Commit 100628a37e1f9ec42aef37eb2a97b85dcc875a33

Authored by zhongnanhuang
1 parent 349f730f

feat: update 发票对账

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 }) =&gt; { @@ -226,11 +245,11 @@ export default ({ invoiceId, setVisible, onClose }) =&gt; {
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 }) =&gt; { @@ -14,17 +14,17 @@ export default ({ setVisible, onClose }) =&gt; {
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 }) =&gt; { @@ -34,6 +34,7 @@ export default ({ setVisible, onClose }) =&gt; {
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 }) =&gt; { @@ -53,32 +54,45 @@ export default ({ setVisible, onClose }) =&gt; {
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 }) =&gt; { @@ -36,7 +36,7 @@ export default ({ invoiceId, setVisible, onClose }) =&gt; {
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,