Commit b2cc6298 authored by GuanHua's avatar GuanHua

feat: 开票管理-自定义上传组件

parent cb025f91
......@@ -609,7 +609,7 @@ const BalancedRoute = {
},
{
"path": "/memberCenter/balance/invoice/detail",
"component": "@/pages/balance/invoice/srm/inquire/detail",
"component": "@/pages/balance/invoice/srm/invoiceDetail",
"relationParentCode": "balance",
"hideInMenu": true,
"name": "发票详情",
......@@ -634,7 +634,7 @@ const BalancedRoute = {
},
{
"path": "/memberCenter/balance/invoiceJoint/detail",
"component": "@/pages/balance/invoice/srm/joint/detail",
"component": "@/pages/balance/invoice/srm/invoiceDetail",
"relationParentCode": "balance",
"hideInMenu": true,
"name": "发票详情",
......
......@@ -7,16 +7,21 @@
background: #EBF7F2;
border-radius: 4px;
&__active {
color: #4787F0;
background: #ECF2FE;
}
&__success {
color: #00B37A;
background: #EBF7F2;
}
&__warning {
color: #FF991F;
background: #FFFAE6;
}
&__default {
color: #606266;
background: #F4F5F7;
......@@ -26,14 +31,14 @@
color: #E63F3B;
background: #FFEBE6;
}
&__primary {
color: #3F7ED2;
background: #F0F8FF;
}
&__nobility {
color: #6554C0;
background: #EAE6FF;
}
}
\ No newline at end of file
}
......@@ -9,10 +9,10 @@ import React from 'react';
import classNames from 'classnames';
import styles from './index.less';
export const STATUS_TYPE = ['success', 'warning', 'default', 'danger', 'primary', 'nobility']
export const STATUS_TYPE = ['success', 'warning', 'default', 'danger', 'primary', 'nobility', 'active']
export type StatusTagProps = {
type: 'success' | 'warning' | 'default' | 'danger' | 'primary' | 'nobility';
type: 'success' | 'warning' | 'default' | 'danger' | 'primary' | 'nobility' | 'active';
title: React.ReactNode;
style?: React.CSSProperties,
};
......
......@@ -48,6 +48,13 @@
.textOverflow();
}
}
.delete_btn {
margin-left: 8px;
font-size: 12px;
cursor: pointer;
color: #909399;
}
}
// &:hover {
// background-color: @secondary-color;
......
......@@ -5,6 +5,8 @@ import { UPLOAD_TYPE } from '@/constants';
import { Upload, Progress, Button, message } from 'antd';
import { CloudUploadOutlined, DeleteOutlined } from '@ant-design/icons';
import pdfIcon from '@/assets/imgs/pdf_icon.png';
import photoIcon from '@/assets/imgs/file_photo.png'
import othersIcon from '@/assets/imgs/file_others.png'
import { getAuth } from '@/utils/auth';
import styles from './UploadFiles.less';
import { getIntl } from 'umi';
......@@ -13,6 +15,7 @@ type PickProps = "headers" | "action" | "accept" | "beforeUpload" | "onChange" |
interface PickUploadProps extends Pick<UploadProps, PickProps> {
containerStyle?: React.CSSProperties,
btnClassName?: string,
/**
* 表示当前上传组件的order值, 越大越后, 即flex-order
*/
......@@ -57,6 +60,7 @@ const UploadFiles: React.FC<PickUploadProps> = (props: PickUploadProps) => {
renderUploadChild,
maxCount,
multiple,
btnClassName,
} = props;
const hasFileListProps = "fileList" in props;
const hasMaxCount = typeof maxCount !== 'undefined' ? { maxCount } : {};
......@@ -128,6 +132,20 @@ const UploadFiles: React.FC<PickUploadProps> = (props: PickUploadProps) => {
setFiles(newFileList);
}
};
const getIconByName = (name: string) => {
if (name && typeof name === 'string') {
const tempList = name.split('.')
const fileType = tempList[tempList.length - 1]
if (fileType.indexOf('pdf') > -1) {
return pdfIcon
} else {
return photoIcon
}
}
return othersIcon
}
const renderFileItem = () => {
return (
<div className={filesContainerCs} style={{ order: 1 }}>
......@@ -144,7 +162,7 @@ const UploadFiles: React.FC<PickUploadProps> = (props: PickUploadProps) => {
}
<div className={styles.renderFileItem} >
<div className={styles['fileItem-left']}>
<img className={styles.img} src={pdfIcon} />
<img className={styles.img} src={getIconByName(_item.name)} />
<a
className={cx({ [styles.error]: _item.status === 'error' || !_item.url })}
href={_item.url}
......@@ -156,7 +174,7 @@ const UploadFiles: React.FC<PickUploadProps> = (props: PickUploadProps) => {
</div>
{
!disable && (
<DeleteOutlined onClick={() => handleRemove(_item)} />
<DeleteOutlined className={styles.delete_btn} onClick={() => handleRemove(_item)} />
)
}
</div>
......@@ -187,7 +205,7 @@ const UploadFiles: React.FC<PickUploadProps> = (props: PickUploadProps) => {
{renderUploadChild?.(files)}
{
typeof children !== 'undefined' ? children : (
<Button type={mode} icon={<CloudUploadOutlined />}>
<Button className={btnClassName} type={mode} icon={<CloudUploadOutlined />}>
{buttonText}
</Button>
)
......
......@@ -54,6 +54,7 @@ export default {
'balance.accountsReceivable.invoice.columns.invoiceStatus':'Invoice status',
'balance.accountsReceivable.invoice.columns.invoiceStatus.0':'Not invoiced',
'balance.accountsReceivable.invoice.columns.invoiceStatus.1':'Invoice has been issued',
'balance.accountsReceivable.invoice.columns.invoiceStatus.2': 'Invoicing',
'balance.accountsReceivable.invoice.columns.status':'Payment Status',
'balance.accountsReceivable.invoice.columns.status.1':'Unpaid',
'balance.accountsReceivable.invoice.columns.status.2':'paid',
......
......@@ -54,6 +54,7 @@ export default {
'balance.accountsReceivable.invoice.columns.invoiceStatus': '개표 상태',
'balance.accountsReceivable.invoice.columns.invoiceStatus.0': '미개표',
'balance.accountsReceivable.invoice.columns.invoiceStatus.1': '개표됨',
'balance.accountsReceivable.invoice.columns.invoiceStatus.2': '송장 발행',
'balance.accountsReceivable.invoice.columns.status': '지불 상태',
'balance.accountsReceivable.invoice.columns.status.1': '미지급',
'balance.accountsReceivable.invoice.columns.status.2': '지불됨',
......
......@@ -54,6 +54,7 @@ export default {
'balance.accountsReceivable.invoice.columns.invoiceStatus': '开票状态',
'balance.accountsReceivable.invoice.columns.invoiceStatus.0': '未开票',
'balance.accountsReceivable.invoice.columns.invoiceStatus.1': '已开票',
'balance.accountsReceivable.invoice.columns.invoiceStatus.2': '开票中',
'balance.accountsReceivable.invoice.columns.status': '支付状态',
'balance.accountsReceivable.invoice.columns.status.1': '未支付',
'balance.accountsReceivable.invoice.columns.status.2': '已支付',
......
.status_tag {
display: flex;
align-items: center;
.circle {
width: 6px;
height: 6px;
border-radius: 50%;
margin-right: 8px;
}
& > span {
font-size: 12px;
font-weight: 400;
color: #303133;
}
}
/*
* @Description: 状态 tag
*/
import React from 'react';
import classNames from 'classnames';
import styles from './index.less';
export const STATUS_TYPE = ['success', 'warning', 'default', 'danger', 'primary', 'nobility']
export type StatusTagProps = {
/**
* 状态对应颜色
*/
colorMap: {
[key: number]: string,
},
/** 状态 */
status: number,
title: React.ReactNode;
style?: React.CSSProperties,
};
const StatusTag: React.FC<StatusTagProps> = ({ colorMap, status, title, style }) => (
<div className={styles.status_tag} style={style}>
<div className={classNames(styles.circle)} style={{ backgroundColor: colorMap[status] }}></div>
<span>{title}</span>
</div>
);
export default StatusTag;
.upload_invoice {
.upload_btn {
min-width: 80px;
border: none;
background-color: #F4F5F7;
font-size: 12px;
color: #252D37;
}
.upload_file_list {
display: flex;
flex-direction: column;
margin-bottom: 8px;
&_item {
height: 32px;
display: flex;
align-items: center;
.file_type_icon {
margin-right: 8px;
width: 16px;
height: 16px;
}
.file_name {
font-size: 12px;
color: #00A98F;
line-height: 16px;
}
.delete_btn {
margin-left: 8px;
font-size: 12px;
cursor: pointer;
color: #909399;
}
}
}
}
import React from 'react'
import UploadFiles from '@/components/UploadFiles/UploadFiles'
import styles from './index.less'
import { UploadFile, UploadChangeParam } from 'antd/lib/upload/interface'
interface UploadInvoiceProps {
path: string
name: string
value: string[],
props: {
readOnly: boolean
},
mutators: {
change: (params: any) => void
},
}
const UploadInvoice:React.FC<UploadInvoiceProps> & { isFieldComponent: boolean } = (props) => {
const { value, mutators } = props
const handleFilesChange = (info: UploadChangeParam) => {
if (info) {
const fileList = info.fileList;
const urlLIst = fileList.map((file) => file.url)
console.log(urlLIst, 'urlLIst')
mutators.change([...urlLIst])
}
}
const handleFileRemove = (fileItem: UploadFile) => {
if (value && fileItem.url) {
const filterUrlList = value.filter((imgUrl) => imgUrl !== fileItem.url)
console.log(filterUrlList, 'filterUrlList')
mutators.change([...filterUrlList])
}
}
return (
<div className={styles.upload_invoice}>
{/* {
(value && value.length > 0) && (
<div className={styles.upload_file_list}>
{
value.map((item) => (
<div className={styles.upload_file_list_item}>
<img className={styles.file_type_icon} src={getIconByName(item)} />
<span className={styles.file_name}>{item}</span>
{
!props.props.readOnly && <DeleteOutlined onClick={() => handleDeleteItem(item)} className={styles.delete_btn} />
}
</div>
))
}
</div>
)
} */}
<UploadFiles
btnClassName={styles.upload_btn}
buttonText='上传'
onChange={handleFilesChange}
onRemove={handleFileRemove}
/>
</div>
)
}
UploadInvoice.isFieldComponent = true
export default UploadInvoice
......@@ -12,15 +12,13 @@ import StandardTable from '@/components/StandardTable';
import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilterSearch';
import { useAsyncSelect } from '@/formSchema/effects/useAsyncSelect';
import { schema } from './schema';
// import InvoiceCreate from '../../components/InvoiceCreate'
// import StatusTag from '../../components/StatusTag';
import StatusTag, { STATUS_TYPE } from '@/components/StatusTag';
import StatusTag from '../components/StatusTag';
import { fetchInvoiceOptions } from '../../../common';
import useSetSearchValueInTable from '@/hooks/useSetSearchValueInTable';
import { numFormat, priceFormat } from '@/utils/numberFomat';
import {
getSettleAccountsMemberSettlementAccountStatementInvoiceListStatus,
getSettleAccountsMemberSettlementAccountStatementCoordinationInvoiceList,
getSettleAccountsMemberSettlementAccountStatementInvoiceList,
} from '@/services/SettleV2Api';
import AuthButton from '@/components/AuthButton';
import './index.less';
......@@ -43,7 +41,7 @@ const InvoiceInquire: React.FC = () => {
...searchData,
orderByCode: 1,
};
const { data } = await getSettleAccountsMemberSettlementAccountStatementCoordinationInvoiceList(
const { data } = await getSettleAccountsMemberSettlementAccountStatementInvoiceList(
searchParams,
);
return data;
......@@ -179,12 +177,16 @@ const InvoiceInquire: React.FC = () => {
onFilter: (value: number, record: any) => record.invoiceStatus == value,
render: (text, record) => {
return (
<div>
<StatusTag
title={record.examineStatusName}
type={record.examineStatus === 0 ? 'warning' : 'success'}
/>
</div>
<StatusTag
title={record.examineStatusName}
status={record.examineStatus}
colorMap={{
0: '#ACAFB3',
1: '#4787F0',
2: '#00A98F',
3: '#E34D59',
}}
/>
);
},
},
......
import React from 'react'
import styels from './index.less'
const InvoiceInquireDetail: React.FC = () => {
const InvoiceDetail: React.FC = () => {
return (
<div>
InvoiceInquireDetail
InvoiceDetail
</div>
)
}
export default InvoiceInquireDetail
export default InvoiceDetail
import React from 'react'
const InvoiceJointDetail: React.FC = () => {
return (
<div>
InvoiceJointDetail
</div>
)
}
export default InvoiceJointDetail
......@@ -12,7 +12,7 @@ import StandardTable from '@/components/StandardTable';
import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilterSearch';
import { useAsyncSelect } from '@/formSchema/effects/useAsyncSelect';
import { schema } from './schema';
import StatusTag, { STATUS_TYPE } from '@/components/StatusTag';
import StatusTag from '../components/StatusTag';
import { fetchInvoiceOptions } from '../../../common';
import useSetSearchValueInTable from '@/hooks/useSetSearchValueInTable';
import { numFormat, priceFormat } from '@/utils/numberFomat';
......@@ -151,12 +151,6 @@ const InvoiceJoint: React.FC = () => {
filters: [
{
text: intl.formatMessage({
id: 'balance.accountsReceivable.invoice.columns.examineStatus.0',
}),
value: 0,
},
{
text: intl.formatMessage({
id: 'balance.accountsReceivable.invoice.columns.examineStatus.1',
}),
value: 1,
......@@ -177,12 +171,16 @@ const InvoiceJoint: React.FC = () => {
onFilter: (value: number, record: any) => record.invoiceStatus == value,
render: (text, record) => {
return (
<div>
<StatusTag
title={record.examineStatusName}
type={record.examineStatus === 0 ? 'warning' : 'success'}
/>
</div>
<StatusTag
title={record.examineStatusName}
status={record.examineStatus}
colorMap={{
0: '#ACAFB3',
1: '#4787F0',
2: '#00A98F',
3: '#E34D59',
}}
/>
);
},
},
......@@ -193,7 +191,7 @@ const InvoiceJoint: React.FC = () => {
render: (_, record) => {
return (
<Link
to={`/memberCenter/balance/invoice/detail?id=${record.reconciliationId}`}
to={`/memberCenter/balance/invoiceJoint/detail?id=${record.reconciliationId}`}
>
{intl.formatMessage({
id: 'balance.accountsReceivable.invoice.columns.operation.1',
......
import React, { useEffect, useState } from 'react';
import { useIntl } from 'umi';
import { history, useIntl } from 'umi';
import { Button, message } from 'antd';
import { FormDetailContext } from '@/formSchema/context';
import { useFormDetail } from '@/formSchema/effects/useFormDetail';
......@@ -7,86 +7,76 @@ import FormDetailHeader from '@/components/FormDetailHeader';
import TableModal from '@/components/TableModal';
import AuthButton from '@/components/AuthButton';
import { LinkOutlined, PlusOutlined, SaveOutlined } from '@ant-design/icons';
import { createFormActions } from '@formily/antd';
import { createFormActions, FormEffectHooks } from '@formily/antd';
import { increaseSchema } from './schema';
import styles from './index.less';
import FormDetailWrapper from '@/components/FormDetailWrapper';
import {
getSettleAccountsMemberSettlementAccountStatementAddPageInvoicingProcess,
getSettleAccountsMemberSettlementAccountStatementInvoiceReconciliationRows,
getSettleAccountsMemberSettlementPageInvoicingProcessList,
getSettleAccountsMemberSettlementAccountStatementDetail,
postSettleAccountsMemberSettlementAccountStatementAddOrUpdateInvoice,
} from '@/services/SettleV2Api'
import NiceForm from '@/components/NiceForm';
import { formKeys, reconciliationColumn, statementsColumn } from './contants'
import { InvoiceDetailType } from './types';
import { InvoiceDetailType, InvoiceFromValuesType } from './types';
import { usePageStatus } from '@/hooks/usePageStatus';
import { useInvoiceDetailTable } from './model/useInvoiceDetailTable';
import moment from 'moment';
import UploadInvoice from '../components/UploadInvoice'
const { onFieldValueChange$ } = FormEffectHooks
const addSchemaAction = createFormActions();
const mock = [
{
"reconciliationNo": "RE2022012000087",
"reconciliationId": null,
"sourceContractId": 0,
"orderId": 6291,
"orderNo": "DEF45MU81",
"orderStatus": "已完成",
"orderType": 12,
"productId": 88,
"expectPayTime": "2022-02-15",
"deliveryBatch": "1",
"deliveryNo": "FH27FNKPV",
"receiveNo": "SHZ3O460Y",
"productNo": "232d",
"productName": "32423",
"spec": "224",
"category": "农业挖掘机",
"brand": "品牌1",
"unit": "台",
"taxRate": 6,
"billType": 1,
"billTypeName": "订单",
"billDate": "2022-01-19",
"billAmount": 14000,
"price": 100,
"reconciliationQuantity": 28,
"reconciliationMoneyAmount": 900,
"currentReconciliationQuantity": 28,
"currentMoney": 8400,
"id": 2402
}
]
const AddInvoice: React.FC = () => {
const intl = useIntl();
const { id } = usePageStatus()
const { reconciliationId, id } = usePageStatus()
const [btnLoading, setBtnLoading] = useState(false);
const [formLoading, setFormLoading] = useState(false);
const { formContext } = useFormDetail();
const [initFormValue, setInitFormValue] = useState<any>({
rows: mock
const [initFormValue] = useState<any>({
rows: [],
});
const [invoiceDrawerVisible, setInvoiceDrawerVisible] = useState<boolean>(false); // 选择单据
const [statementsDrawerVisible, setStatementsDrawerVisible] = useState<boolean>(false); // 选择对账单抽屉
const [reconciliation, setReconciliation] = useState<InvoiceDetailType>()
const [invoiceDetail, setInvoiceDetail] = useState<InvoiceDetailType>()
const { invoiceDetailColumns, invoiceDetailComponents } = useInvoiceDetailTable(addSchemaAction)
useEffect(() => {
if (id) {
fetchInvoiceDetail()
if (reconciliationId) {
initFormData()
}
}, [])
const initFormData = async () => {
const detailInfo = await fetchInvoiceDetail(reconciliationId)
if (detailInfo) {
// 设置表单数据
Object.keys(detailInfo).forEach((key) => {
if (formKeys.includes(key)) {
addSchemaAction.setFieldValue(key, detailInfo[key])
}
})
if (detailInfo?.returnResource) {
addSchemaAction.setFieldState('returnResource', state => {
state.visible = true
})
}
// 如果是待开票跳转过来新增
if (reconciliationId) {
addSchemaAction.setFieldState('reconciliationNo', state => {
state.props.readOnly = true
state.props["x-rules"] = undefined
state.props["x-component-props"] = undefined
})
}
setInvoiceDrawerVisible(false)
}
}
const providerValue = {
schemaActions: addSchemaAction,
formContext,
};
const handleSelectNo = () => {};
/**
* 获取发票详情
*/
......@@ -111,11 +101,11 @@ const AddInvoice: React.FC = () => {
}
// 选择单据号按钮
const SelectNoBtn = (
const SelectNoBtn = !reconciliationId ? (
<Button type="primary" className={styles.select_btn} onClick={handleSelectReconciliationClick}>
<LinkOutlined className={styles.select_icon} />
</Button>
);
) : null
const handleSelectStatementsClick = () => {
const reconciliationNo = addSchemaAction.getFieldValue('reconciliationNo')
......@@ -136,9 +126,24 @@ const AddInvoice: React.FC = () => {
const handleStatementsModalConfirm = (selectRow: number[] | string[], selectedRows: { [key: string]: any }[]) => {
if (selectedRows && selectedRows.length > 0) {
console.log(selectedRows, 'selectedRows')
const list = addSchemaAction.getFieldValue('rows') || []
addSchemaAction.setFieldValue('rows', [...selectedRows, ...list])
// 对选择的账单明细数据进行处理
const selectList = selectedRows.map((item) => {
return {
...item,
reconciliationId: addSchemaAction.getFieldValue('reconciliationId'),
reconciliationRowId: item.id,
name: item.productName,
priceNoTax: (item.price / (1 + (item.taxRate / 100))).toFixed(2), // 单价(不含税)
taxMoneyAmount: ((item.price * item.currentReconciliationQuantity) / (1 + (item.taxRate / 100)) * (item.taxRate / 100)).toFixed(2), // 税额
currentQuantity: item.currentReconciliationQuantity, // 本次对账数量
currentMoney: item.currentMoney, // 本次对账金额(含税)
currentNumber: item.currentReconciliationQuantity, // 本次开票数量
currentMoneyAmount: item.currentMoney, // 本次开票金额(含税)
currentMoneyNoTax: ((item.price * item.currentReconciliationQuantity) / (1 + (item.taxRate / 100))).toFixed(2), // 本次开票金额(不含税)
}
})
addSchemaAction.setFieldValue('rows', [...selectList, ...list])
setStatementsDrawerVisible(false)
} else {
message.info('请先选择对账单')
......@@ -151,15 +156,24 @@ const AddInvoice: React.FC = () => {
const handleReconciliationModalConfirm = async (_: number[] | string[], selectedRows: { [key: string]: any }[]) => {
const selectedItem = selectedRows[0]
const detailInfo = await fetchInvoiceDetail(selectedItem.reconciliationId)
if (detailInfo) {
setReconciliation(detailInfo)
// 设置表单数据
Object.keys(detailInfo).forEach((key) => {
if (selectedItem) {
const detailInfo = await fetchInvoiceDetail(selectedItem.reconciliationId)
// 拼接发票数据,覆盖单据数据
const info = {
...detailInfo,
...selectedItem
}
// 如果手工新增,则显示选择单据按钮,单据号、单据摘要、单据类型、单据时间从选择的单据中获取
Object.keys(info).forEach((key) => {
if (formKeys.includes(key)) {
addSchemaAction.setFieldValue(key, detailInfo[key])
addSchemaAction.setFieldValue(key, info[key])
}
})
if (detailInfo?.returnResource) {
addSchemaAction.setFieldState('returnResource', state => {
state.visible = true
})
}
setInvoiceDrawerVisible(false)
} else {
message.info('请选择单据')
......@@ -200,6 +214,23 @@ const AddInvoice: React.FC = () => {
return data;
}
const handleSubmit = async (values: InvoiceFromValuesType) => {
try {
// 格式化开票日期
values['invoiceDate'] = moment(values['invoiceDate']).format('YYYY-MM-DD HH:mm:ss')
setBtnLoading(true)
const res = await postSettleAccountsMemberSettlementAccountStatementAddOrUpdateInvoice(values)
if (res.code === 1000) {
message.destroy()
message.success('开票成功')
history.push('/memberCenter/balance/invoice/manage')
}
setBtnLoading(false)
} catch (error) {
setBtnLoading(false)
}
}
return (
<div className={styles['mian']}>
<FormDetailContext.Provider value={providerValue}>
......@@ -241,13 +272,15 @@ const AddInvoice: React.FC = () => {
<FormDetailWrapper>
<div className={styles.restContainer}>
<NiceForm
loading={formLoading}
loading={btnLoading}
previewPlaceholder=" "
value={initFormValue}
actions={addSchemaAction}
schema={increaseSchema}
// onSubmit={handleSubmit}
components={{}}
onSubmit={handleSubmit}
components={{
UploadInvoice,
}}
effects={($, ctx) => {
formContext.useAttachmentChangeForContext(ctx)
}}
......
......@@ -5,7 +5,6 @@ const intl = getIntl()
export const formKeys = [
'reconciliationId',
'reconciliationNo',
'payer',
'reconciliationAbstract',
'createTime',
'reconciliationTypeName',
......@@ -18,8 +17,8 @@ export const formKeys = [
'invoiceTitle',
'address',
'taxNo',
'payer',
'tel',
]
export const reconciliationColumn = [
......@@ -257,7 +256,8 @@ export const invoiceDetailColumn = [
id: 'balance.invoice.columns.price.not',
defaultMessage: '单价(不含税)'
}),
render: (_, record) => `${(record.price / (1 + (record.taxRate / 100))).toFixed(2)}`
dataIndex: 'priceNoTax',
// render: (_, record) => `${(record.price / (1 + (record.taxRate / 100))).toFixed(2)}`
},
{
title: intl.formatMessage({
......@@ -266,35 +266,38 @@ export const invoiceDetailColumn = [
}),
editable: true,
formItem: 'number',
dataIndex: 'currentReconciliationQuantity',
dataIndex: 'currentNumber',
},
{
title: intl.formatMessage({
id: 'balance.invoice.columns.moneyAmount',
defaultMessage: '金额(含税)'
}),
dataIndex: 'currentMoney',
render: (_, record) => `${(record.price * record.currentReconciliationQuantity).toFixed(2)}`
dataIndex: 'currentMoneyAmount',
// render: (_, record) => `${(record.price * record.currentReconciliationQuantity).toFixed(2)}`
},
{
title: intl.formatMessage({
id: 'balance.invoice.columns.moneyAmount.not',
defaultMessage: '金额(不含税)'
}),
render: (_, record) => `${((record.price * record.currentReconciliationQuantity) / (1 + (record.taxRate / 100))).toFixed(2)}`
dataIndex: 'currentMoneyNoTax',
// render: (_, record) => `${((record.price * record.currentReconciliationQuantity) / (1 + (record.taxRate / 100))).toFixed(2)}`
},
{
title: intl.formatMessage({
id: 'balance.invoice.columns.taxAmount',
defaultMessage: '税额'
}),
render: (_, record) => `${((record.price * record.currentReconciliationQuantity) / (1 + (record.taxRate / 100)) * (record.taxRate / 100)).toFixed(2)}`
dataIndex: 'taxMoneyAmount',
// render: (_, record) => `${((record.price * record.currentReconciliationQuantity) / (1 + (record.taxRate / 100)) * (record.taxRate / 100)).toFixed(2)}`
},
{
title: intl.formatMessage({
id: 'balance.accountsReceivable.invoice.columns.operation',
defaultMessage: '操作'
}),
width: 80,
action: 'delete',
},
]
......@@ -68,9 +68,25 @@
border: none;
}
.ant-picker {
border-radius: 4px;
background-color: #F5F6F7!important;
border: none;
&:focus {
box-shadow: none;
}
}
.ant-picker-focused {
border: none;
box-shadow: none;
}
.ant-input {
border: none;
box-shadow: none;
background-color: #F5F6F7!important;
&:focus, &:active {
border: none!important;
......
......@@ -12,10 +12,10 @@ import StandardTable from '@/components/StandardTable';
import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilterSearch';
import { useAsyncSelect } from '@/formSchema/effects/useAsyncSelect';
import { schema } from './schema';
import StatusTag from '@/components/StatusTag';
import { fetchOptions } from '../../../common';
import useSetSearchValueInTable from '@/hooks/useSetSearchValueInTable';
import { priceFormat } from '@/utils/numberFomat';
import StatusTag from '../components/StatusTag'
import {
getSettleAccountsMemberSettlementAccountStatementInvoiceList,
} from '@/services/SettleV2Api';
......@@ -174,14 +174,18 @@ const InvoiceManage: React.FC = () => {
},
],
onFilter: (value: number, record: any) => record.invoiceStatus == value,
render: (text, record) => {
render: (_, record) => {
return (
<div>
<StatusTag
title={record.examineStatusName}
type={record.examineStatus === 0 ? 'warning' : 'success'}
/>
</div>
<StatusTag
title={record.examineStatusName}
status={record.examineStatus}
colorMap={{
0: '#ACAFB3',
1: '#4787F0',
2: '#00A98F',
3: '#E34D59',
}}
/>
);
},
},
......
import { useState } from 'react'
import { ISchemaFormActions, ISchemaFormAsyncActions } from '@formily/antd';
import { invoiceDetailColumn } from '../contants';
import ProductTableCell, { ProductEditableRow } from '../../components/productTableCell';
import ProductTableCell, { ProductEditableRow } from '../../components/ProductTableCell';
import { getIntl } from 'umi';
import { Button } from 'antd';
const intl = getIntl();
......@@ -34,36 +34,36 @@ export const useInvoiceDetailTable = (ctx: ISchemaFormActions | ISchemaFormAsync
return new Promise((resolve) => {
const newData = [...ctx.getFieldValue('rows')];
const index = newData.findIndex(item => row.id === item.id);
const item = newData[index];
newData[index] = row
const item = {...row};
const count = row.currentNumber || 0
item['taxMoneyAmount'] = ((item.price * count) / (1 + (item.taxRate / 100)) * (item.taxRate / 100)).toFixed(2) // 税额
item['currentMoneyAmount'] = (item.price * count).toFixed(2) // 本次开票金额(含税)
item['currentMoneyNoTax'] = ((item.price * count) / (1 + (item.taxRate / 100))).toFixed(2) // 本次开票金额(不含税)
newData[index] = item
ctx.setFieldValue('rows', newData)
resolve({ item, newData })
})
};
const handleDelete = (row) => {
let newData = [...ctx.getFieldValue('rows')];
newData = newData.filter((item) => item.id !== row.id)
ctx.setFieldValue('rows', newData)
}
const invoiceMergeColumns = invoiceDetailColumn.map(col => {
if (!col.editable) {
return col;
}
if (col.action && col.action === 'delete') {
return {
...col,
onCell: record => ({
record,
editable: ctx.getFormState().editable === false ? false : col.editable,
dataIndex: col.dataIndex,
title: col.title,
render: () => <Button type='link'>删除</Button>,
handleDelete,
}),
render: (_, row) => <Button type='link' onClick={() => handleDelete(row)}>{intl.formatMessage({ id: 'common.button.delete' })}</Button>,
}
}
if (!col.editable) {
return col;
}
return {
...col,
onCell: record => ({
......
......@@ -2,6 +2,7 @@ import { getIntl } from 'umi'
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { ISchema, createFormActions } from '@formily/antd';
import moment from 'moment';
const intl = getIntl()
/**
* 开票管理列表页schema
......@@ -283,7 +284,7 @@ const billInfo: ISchema = {
"x-rules": [
{
required: true,
message: getIntl().formatMessage({ id: 'balance.invoice.reconciliationNo.required', defaultMessage: '请输入发票代码' }),
message: getIntl().formatMessage({ id: 'balance.invoice.code.required', defaultMessage: '请输入发票代码' }),
},
{
limitByte: true,
......@@ -297,12 +298,15 @@ const billInfo: ISchema = {
title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.invoiceDate', defaultMessage: '开票日期' }),
"x-component": "date",
"x-component-props": {
style: { width: "100%" }
style: { width: "100%" },
disabledDate: current => {
return current && current < moment().startOf('day')
},
},
"x-rules": [
{
required: true,
message: getIntl().formatMessage({ id: 'balance.invoice.reconciliationNo.required', defaultMessage: '请选择开票日期' }),
message: getIntl().formatMessage({ id: 'balance.invoice.invoiceDate.required', defaultMessage: '请选择开票日期' }),
},
{
limitByte: true,
......@@ -320,19 +324,22 @@ const billInfo: ISchema = {
"x-rules": [
{
required: true,
message: getIntl().formatMessage({ id: 'balance.invoice.reconciliationNo.required', defaultMessage: '请输入发票号码' }),
message: getIntl().formatMessage({ id: 'balance.invoice.number.required', defaultMessage: '请输入发票号码' }),
}
],
},
remark: {
type: 'string',
title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.remark', defaultMessage: '备注' }),
maxLength: 100,
"x-component-props": {
placeholder: '最长100个文字',
maxLength: 100,
}
},
urlImgs: {
type: 'string',
"x-component": "UploadInvoice",
title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.urlImgs', defaultMessage: '发票图片' }),
},
},
......@@ -353,13 +360,18 @@ const invoiceDetails: ISchema = {
rows: {
type: 'array',
"x-component": 'MultTable',
required: true,
"x-component-props": {
rowKey: 'id',
columns: "{{invoiceDetailColumns}}",
components: "{{invoiceDetailComponents}}",
prefix: "{{SelectStatementsButton}}",
},
"x-rules": [
{
required: true,
message: getIntl().formatMessage({ id: 'balance.invoice.details.rows.required', defaultMessage: '请选择对账单' }),
},
],
},
}
}
......
......@@ -89,3 +89,195 @@ export interface InvoiceDetailType {
*/
returnResource: string
}
export interface InvoiceRowsType {
/**
* 开票明细id(新增为空,修改不为空)
*/
id?: number
/**
* 开票id
*/
invoiceProveId: number
/**
* 对账单id
*/
reconciliationId: number
/**
* 对账单明细id
*/
reconciliationRowId: number
/**
* 订单编号
*/
orderNo: string
/**
* 发货单号
*/
deliveryNo: string
/**
* 收货单号
*/
receiveNo: string
/**
* 物料编码
*/
productNo: string
/**
* 物料名称
*/
name: string,
productName: string,
/**
* 商品规格
*/
spec?: string
/**
* 商品品类
*/
category?: string
/**
* 商品品牌
*/
brand?: string
/**
* 单位
*/
unit?: string
/**
* 税率(百分比的分子部分)
*/
taxRate: number
/**
* 单价(含税)
*/
price: number
/**
* 单价(不含税)
*/
priceNoTax: number
/**
* 税额
*/
taxMoneyAmount: number
/**
* 本次对账数量
*/
currentQuantity: number
currentReconciliationQuantity: number,
/**
* 本次对账金额(含税)
*/
currentMoney: number
/**
* 本次开票数量
*/
currentNumber: number
/**
* 本次开票金额(含税)
*/
currentMoneyAmount: number
/**
* 本次开票金额(不含税)
*/
currentMoneyNoTax: number
}
/**
* 新增开票表单类型
*/
export interface InvoiceFromValuesType {
/**
* 对账单开票明细列表 ,InvoiceReconciliationRowVO
*/
rows: InvoiceRowsType[]
/**
* 开票id
*/
id?: number
/**
* 对账单id
*/
reconciliationId: number
/**
* 对账单号
*/
reconciliationNo: string
/**
* 对账单摘要
*/
reconciliationAbstract?: string
/**
* 对账单类型
*/
reconciliationType: number
/**
* 对账单类型名称
*/
reconciliationTypeName?: string
/**
* 单据时间
*/
createTime: string
/**
* 付款方
*/
payer?: string
/**
* 发票种类:1.增值税普通发票(默认)2.增值税专用发票
*/
kind?: number
/**
* 发票类型:1.企业(默认)2.个人
*/
type?: number
/**
* 发票抬头
*/
invoiceTitle?: string
/**
* 纳税号
*/
taxNo?: string
/**
* 开户行
*/
bankOfDeposit?: string
/**
* 账号
*/
account?: string
/**
* 地址
*/
address?: string
/**
* 电话
*/
tel?: string
/**
* 发票号码
*/
number: string
/**
* 发票代码
*/
code: string
/**
* 开票日期
*/
invoiceDate: string
/**
* 备注
*/
remark?: string
/**
* 发票图片 ,String
*/
urlImgs?: string[]
/**
* 退回原因
*/
returnResource?: string
}
......@@ -152,14 +152,20 @@ const SettlementList: React.FC = () => {
}),
value: 1,
},
{
text: intl.formatMessage({
id: 'balance.accountsReceivable.invoice.columns.invoiceStatus.2',
}),
value: 2,
},
],
onFilter: (value: number, record: any) => record.invoiceStatus == value,
render: (text, record) => {
render: (_, record) => {
return (
<div>
<StatusTag
title={record.invoiceStatusName}
type={record.invoiceStatus === 0 ? 'warning' : 'success'}
type={{ 0: 'warning', 1: 'success', 2: 'active'}[record.invoiceStatus]}
/>
</div>
);
......@@ -174,8 +180,8 @@ const SettlementList: React.FC = () => {
<Link
to={
record.invoiceStatus === 1
? `/memberCenter/balance/invoice/inquire?id=${record.reconciliationId}`
: `/memberCenter/balance/invoice/add?id=${record.reconciliationId}`
? `/memberCenter/balance/invoice/inquire?reconciliationId=${record.reconciliationId}`
: `/memberCenter/balance/invoice/add?reconciliationId=${record.reconciliationId}`
}
>
{record.invoiceStatus === 1
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment