Commit 100628a37e1f9ec42aef37eb2a97b85dcc875a33
1 parent
349f730f
feat: update 发票对账
Showing
5 changed files
with
112 additions
and
40 deletions
src/pages/Invoice/components/BankChooseModal.tsx
@@ -5,7 +5,7 @@ import { | @@ -5,7 +5,7 @@ import { | ||
5 | postServiceBankStatementQueryBankStatement, | 5 | postServiceBankStatementQueryBankStatement, |
6 | postServiceInvoiceInvoiceWriteOff, | 6 | postServiceInvoiceInvoiceWriteOff, |
7 | } from '@/services'; | 7 | } from '@/services'; |
8 | -import { enumValueToLabel, formatDateTime } from '@/utils'; | 8 | +import { FloatAdd, FloatSub, enumValueToLabel, formatDateTime } from '@/utils'; |
9 | import { formatDate } from '@/utils/time'; | 9 | import { formatDate } from '@/utils/time'; |
10 | 10 | ||
11 | import { ActionType, ProCard, ProTable } from '@ant-design/pro-components'; | 11 | import { ActionType, ProCard, ProTable } from '@ant-design/pro-components'; |
@@ -18,6 +18,7 @@ export default ({ invoiceId, setVisible, onClose }) => { | @@ -18,6 +18,7 @@ export default ({ invoiceId, setVisible, onClose }) => { | ||
18 | const [selectedStatementIdSet, setSelectedStatementIdSet] = useState( | 18 | const [selectedStatementIdSet, setSelectedStatementIdSet] = useState( |
19 | new Set(), | 19 | new Set(), |
20 | ); | 20 | ); |
21 | + const [totalAmount, setTotalAmount] = useState(0); | ||
21 | 22 | ||
22 | // 添加元素到Set | 23 | // 添加元素到Set |
23 | const addElement = (element) => { | 24 | const addElement = (element) => { |
@@ -128,6 +129,8 @@ export default ({ invoiceId, setVisible, onClose }) => { | @@ -128,6 +129,8 @@ export default ({ invoiceId, setVisible, onClose }) => { | ||
128 | key="choose" | 129 | key="choose" |
129 | type="link" | 130 | type="link" |
130 | onClick={() => { | 131 | onClick={() => { |
132 | + let amount = record.loanAmount || record.transactionAmount || 0; | ||
133 | + | ||
131 | //已经选中,取消选中 | 134 | //已经选中,取消选中 |
132 | if (selectedStatementIdSet.has(record.id)) { | 135 | if (selectedStatementIdSet.has(record.id)) { |
133 | setSelectedStatement( | 136 | setSelectedStatement( |
@@ -136,12 +139,14 @@ export default ({ invoiceId, setVisible, onClose }) => { | @@ -136,12 +139,14 @@ export default ({ invoiceId, setVisible, onClose }) => { | ||
136 | }), | 139 | }), |
137 | ); | 140 | ); |
138 | removeElement(record.id); | 141 | removeElement(record.id); |
142 | + setTotalAmount(parseFloat(FloatSub(totalAmount, amount))); | ||
139 | } else { | 143 | } else { |
140 | //添加到已选中区域中 | 144 | //添加到已选中区域中 |
141 | let newSelectedStatement = [...selectedStatement]; | 145 | let newSelectedStatement = [...selectedStatement]; |
142 | newSelectedStatement.push(record); | 146 | newSelectedStatement.push(record); |
143 | setSelectedStatement(newSelectedStatement); | 147 | setSelectedStatement(newSelectedStatement); |
144 | addElement(record.id); | 148 | addElement(record.id); |
149 | + setTotalAmount(FloatAdd(totalAmount, amount)); | ||
145 | } | 150 | } |
146 | }} | 151 | }} |
147 | > | 152 | > |
@@ -167,22 +172,36 @@ export default ({ invoiceId, setVisible, onClose }) => { | @@ -167,22 +172,36 @@ export default ({ invoiceId, setVisible, onClose }) => { | ||
167 | }; | 172 | }; |
168 | 173 | ||
169 | const showSelectedStatement = () => { | 174 | const showSelectedStatement = () => { |
170 | - console.log('show'); | ||
171 | - console.log(selectedStatement); | ||
172 | let i = 0; | 175 | let i = 0; |
173 | 176 | ||
174 | let tags = selectedStatement.map((item) => { | 177 | let tags = selectedStatement.map((item) => { |
178 | + console.log(item); | ||
179 | + let tagText = item.id; | ||
180 | + | ||
181 | + if (item.payeePayerName) { | ||
182 | + tagText += ' ' + item.payeePayerName + ' '; | ||
183 | + } | ||
184 | + | ||
185 | + if (item.loanAmount) { | ||
186 | + tagText += item.loanAmount + ' '; | ||
187 | + } | ||
188 | + | ||
189 | + if (item.transactionAmount) { | ||
190 | + tagText += item.transactionAmount; | ||
191 | + } | ||
192 | + | ||
175 | return ( | 193 | return ( |
176 | <Tag | 194 | <Tag |
177 | key={i++} | 195 | key={i++} |
178 | closable={true} | 196 | closable={true} |
179 | style={{ userSelect: 'none' }} | 197 | style={{ userSelect: 'none' }} |
198 | + color="blue" | ||
180 | onClose={(e) => { | 199 | onClose={(e) => { |
181 | e.preventDefault(); //需要加上这句代码,不然删除tag时,当前tag的下一个tag会被设置ant-tag-hidden | 200 | e.preventDefault(); //需要加上这句代码,不然删除tag时,当前tag的下一个tag会被设置ant-tag-hidden |
182 | removeSelectedStatement(item); | 201 | removeSelectedStatement(item); |
183 | }} | 202 | }} |
184 | > | 203 | > |
185 | - <span>{item.id}</span> | 204 | + <span>{tagText}</span> |
186 | </Tag> | 205 | </Tag> |
187 | ); | 206 | ); |
188 | }); | 207 | }); |
@@ -226,11 +245,11 @@ export default ({ invoiceId, setVisible, onClose }) => { | @@ -226,11 +245,11 @@ export default ({ invoiceId, setVisible, onClose }) => { | ||
226 | }} | 245 | }} |
227 | > | 246 | > |
228 | <Divider orientation="left" plain> | 247 | <Divider orientation="left" plain> |
229 | - 已选中 | 248 | + 已选中(合计:¥{totalAmount}) |
230 | </Divider> | 249 | </Divider> |
231 | <ProCard className="mb-[16px]" bordered style={{}}> | 250 | <ProCard className="mb-[16px]" bordered style={{}}> |
232 | - <Flex> | ||
233 | - <div>{showSelectedStatement()}</div> | 251 | + <Flex wrap="wrap" gap="small"> |
252 | + {showSelectedStatement()} | ||
234 | </Flex> | 253 | </Flex> |
235 | </ProCard> | 254 | </ProCard> |
236 | 255 |
src/pages/Invoice/components/BankImportModal.tsx
1 | import { RESPONSE_CODE } from '@/constants/enum'; | 1 | import { RESPONSE_CODE } from '@/constants/enum'; |
2 | -import { postServiceBankStatementImportBankStatementForm } from '@/services'; | 2 | + |
3 | import { UploadOutlined } from '@ant-design/icons'; | 3 | import { UploadOutlined } from '@ant-design/icons'; |
4 | import { ModalForm } from '@ant-design/pro-components'; | 4 | import { ModalForm } from '@ant-design/pro-components'; |
5 | import { Button, Form, Upload, UploadFile, UploadProps, message } from 'antd'; | 5 | import { Button, Form, Upload, UploadFile, UploadProps, message } from 'antd'; |
@@ -14,17 +14,17 @@ export default ({ setVisible, onClose }) => { | @@ -14,17 +14,17 @@ export default ({ setVisible, onClose }) => { | ||
14 | const handleChange: UploadProps['onChange'] = ({ fileList: newFileList }) => | 14 | const handleChange: UploadProps['onChange'] = ({ fileList: newFileList }) => |
15 | setFileList(newFileList); | 15 | setFileList(newFileList); |
16 | 16 | ||
17 | - const [messageApi] = message.useMessage(); | 17 | + // const [messageApi] = message.useMessage(); |
18 | const [uploadLoading, setUploading] = useState(false); | 18 | const [uploadLoading, setUploading] = useState(false); |
19 | console.log(uploadLoading); | 19 | console.log(uploadLoading); |
20 | 20 | ||
21 | - const exportLoading = (content: string) => { | ||
22 | - messageApi.open({ | ||
23 | - type: 'loading', | ||
24 | - content: content, | ||
25 | - duration: 0, | ||
26 | - }); | ||
27 | - }; | 21 | + // const exportLoading = (content: string) => { |
22 | + // messageApi.open({ | ||
23 | + // type: 'loading', | ||
24 | + // content: content, | ||
25 | + // duration: 0, | ||
26 | + // }); | ||
27 | + // }; | ||
28 | 28 | ||
29 | const downloadImportTemplate = async () => { | 29 | const downloadImportTemplate = async () => { |
30 | axios({ | 30 | axios({ |
@@ -34,6 +34,7 @@ export default ({ setVisible, onClose }) => { | @@ -34,6 +34,7 @@ export default ({ setVisible, onClose }) => { | ||
34 | headers: { Authorization: localStorage.getItem('token') }, | 34 | headers: { Authorization: localStorage.getItem('token') }, |
35 | }) | 35 | }) |
36 | .then((response) => { | 36 | .then((response) => { |
37 | + console.log(response); | ||
37 | // 创建一个新的 Blob 对象,它包含了服务器响应的数据(即你的 Excel 文件) | 38 | // 创建一个新的 Blob 对象,它包含了服务器响应的数据(即你的 Excel 文件) |
38 | const blob = new Blob([response.data]); // Excel 的 MIME 类型 | 39 | const blob = new Blob([response.data]); // Excel 的 MIME 类型 |
39 | const downloadUrl = window.URL.createObjectURL(blob); | 40 | const downloadUrl = window.URL.createObjectURL(blob); |
@@ -53,32 +54,45 @@ export default ({ setVisible, onClose }) => { | @@ -53,32 +54,45 @@ export default ({ setVisible, onClose }) => { | ||
53 | const handleUpload = async () => { | 54 | const handleUpload = async () => { |
54 | const formData = new FormData(); | 55 | const formData = new FormData(); |
55 | fileList.forEach((file) => { | 56 | fileList.forEach((file) => { |
56 | - //originFileObj二进制文件 | ||
57 | formData.append('file', file.originFileObj as RcFile); | 57 | formData.append('file', file.originFileObj as RcFile); |
58 | }); | 58 | }); |
59 | - // console.log(fileList[0] as RcFile) | ||
60 | - // formData.append('file', fileList[0] as RcFile); | ||
61 | setUploading(true); | 59 | setUploading(true); |
62 | - // You can use any AJAX library you like | ||
63 | - const res = await postServiceBankStatementImportBankStatementForm({ | ||
64 | - data: formData, | 60 | + |
61 | + axios({ | ||
62 | + url: '/api/service/bankStatement/importBankStatementForm', | ||
63 | + method: 'post', | ||
64 | + responseType: 'blob', | ||
65 | headers: { | 65 | headers: { |
66 | + Authorization: localStorage.getItem('token'), | ||
66 | 'Content-Type': | 67 | 'Content-Type': |
67 | 'multipart/form-data; boundary=----WebKitFormBoundarynl6gT1BKdPWIejNq', | 68 | 'multipart/form-data; boundary=----WebKitFormBoundarynl6gT1BKdPWIejNq', |
68 | }, | 69 | }, |
69 | - }); | ||
70 | - | ||
71 | - if (res.result === RESPONSE_CODE.SUCCESS) { | ||
72 | - message.success(res.message); | ||
73 | - onClose(); | ||
74 | - } else { | ||
75 | - if (res.message === '表格中没有数据') { | ||
76 | - setUploading(false); | ||
77 | - return; | ||
78 | - } | ||
79 | - //存在错误信息,下载错误信息模板 | ||
80 | - exportLoading('正在下载错误信息...'); | ||
81 | - } | 70 | + data: formData, |
71 | + }) | ||
72 | + .then((response) => { | ||
73 | + if (response.data?.result === RESPONSE_CODE.SUCCESS) { | ||
74 | + message.success(response.data?.message); | ||
75 | + } else { | ||
76 | + if (response.data?.message) { | ||
77 | + message.error(response.data?.message); | ||
78 | + } else { | ||
79 | + // 创建一个新的 Blob 对象,它包含了服务器响应的数据(即你的 Excel 文件) | ||
80 | + const blob = new Blob([response.data]); // Excel 的 MIME 类型 | ||
81 | + const downloadUrl = window.URL.createObjectURL(blob); | ||
82 | + const a = document.createElement('a'); | ||
83 | + a.href = downloadUrl; | ||
84 | + a.download = '银行流水导入模板.xlsx'; // 你可以为文件命名 | ||
85 | + document.body.appendChild(a); | ||
86 | + a.click(); // 模拟点击操作来下载文件 | ||
87 | + URL.revokeObjectURL(downloadUrl); // 释放掉 blob 对象所占用的内存 | ||
88 | + document.body.removeChild(a); | ||
89 | + } | ||
90 | + } | ||
91 | + }) | ||
92 | + .catch((error) => { | ||
93 | + // 处理错误 | ||
94 | + message.error('系统出现异常了,请联系管理员', error); | ||
95 | + }); | ||
82 | 96 | ||
83 | setUploading(false); | 97 | setUploading(false); |
84 | }; | 98 | }; |
src/pages/Invoice/components/InvoiceVerificationModal.tsx
@@ -36,7 +36,7 @@ export default ({ invoiceId, setVisible, onClose }) => { | @@ -36,7 +36,7 @@ export default ({ invoiceId, setVisible, onClose }) => { | ||
36 | data: { invoiceId: invoiceId }, | 36 | data: { invoiceId: invoiceId }, |
37 | }); | 37 | }); |
38 | if (res && res.data) { | 38 | if (res && res.data) { |
39 | - setInvoiceInfo(res.data.queryInvoiceResponseDto); | 39 | + setInvoiceInfo(res.data); |
40 | setRelationOrderIds(res.data.mainOrderIds); | 40 | setRelationOrderIds(res.data.mainOrderIds); |
41 | setRelationBankStatements(res.data.bankStatementResponseDtos); | 41 | setRelationBankStatements(res.data.bankStatementResponseDtos); |
42 | } | 42 | } |
src/pages/Invoice/constant.tsx
@@ -131,11 +131,12 @@ export const INVOICE_COLUMNS = [ | @@ -131,11 +131,12 @@ export const INVOICE_COLUMNS = [ | ||
131 | export const BANK_STATEMENT_COLUMNS = [ | 131 | export const BANK_STATEMENT_COLUMNS = [ |
132 | { | 132 | { |
133 | dataIndex: 'id', | 133 | dataIndex: 'id', |
134 | - title: '主键ID', | 134 | + title: '编号', |
135 | valueType: 'text', | 135 | valueType: 'text', |
136 | - width: 100, | ||
137 | - hideInTable: true, | ||
138 | - hideInSearch: true, | 136 | + width: 160, |
137 | + copyable: true, | ||
138 | + // hideInTable: true, | ||
139 | + // hideInSearch: true, | ||
139 | editable: false, | 140 | editable: false, |
140 | }, | 141 | }, |
141 | { | 142 | { |
src/utils/index.ts
@@ -224,7 +224,45 @@ function splitByFirstTwoDashes(str: string) { | @@ -224,7 +224,45 @@ function splitByFirstTwoDashes(str: string) { | ||
224 | ]; | 224 | ]; |
225 | } | 225 | } |
226 | 226 | ||
227 | +//浮点数加法运算 | ||
228 | +function FloatAdd(arg1: any, arg2: any) { | ||
229 | + let r1, r2, m; | ||
230 | + try { | ||
231 | + r1 = arg1.toString().split('.')[1].length; | ||
232 | + } catch (e) { | ||
233 | + r1 = 0; | ||
234 | + } | ||
235 | + try { | ||
236 | + r2 = arg2.toString().split('.')[1].length; | ||
237 | + } catch (e) { | ||
238 | + r2 = 0; | ||
239 | + } | ||
240 | + m = Math.pow(10, Math.max(r1, r2)); | ||
241 | + return (arg1 * m + arg2 * m) / m; | ||
242 | +} | ||
243 | + | ||
244 | +//浮点数减法运算 | ||
245 | +function FloatSub(arg1: any, arg2: any) { | ||
246 | + let r1, r2, m, n; | ||
247 | + try { | ||
248 | + r1 = arg1.toString().split('.')[1].length; | ||
249 | + } catch (e) { | ||
250 | + r1 = 0; | ||
251 | + } | ||
252 | + try { | ||
253 | + r2 = arg2.toString().split('.')[1].length; | ||
254 | + } catch (e) { | ||
255 | + r2 = 0; | ||
256 | + } | ||
257 | + m = Math.pow(10, Math.max(r1, r2)); | ||
258 | + //动态控制精度长度 | ||
259 | + n = (r1 = r2) ? r1 : r2; | ||
260 | + return ((arg1 * m - arg2 * m) / m).toFixed(n); | ||
261 | +} | ||
262 | + | ||
227 | export { | 263 | export { |
264 | + FloatAdd, | ||
265 | + FloatSub, | ||
228 | appendFormData, | 266 | appendFormData, |
229 | blobToFile, | 267 | blobToFile, |
230 | copyToClipboard, | 268 | copyToClipboard, |