Commit 37038e0f92ab70367e33bd53bde61ee7d733d9d8

Authored by boyang
1 parent a9848f98

订单预警页面

Showing 60 changed files with 4266 additions and 195 deletions

Too many changes to show.

To preserve performance only 60 of 120 files are displayed.

.umirc.ts
... ... @@ -41,8 +41,24 @@ export default defineConfig({
41 41 {
42 42 name: '订单管理',
43 43 path: '/order',
44   - component: './Order',
45 44 icon: 'ProfileOutlined',
  45 + routes: [
  46 + {
  47 + name: '订单列表',
  48 + path: 'order',
  49 + component: './Order/Order',
  50 + },
  51 + {
  52 + name: '订单预警',
  53 + path: 'OrderWarning',
  54 + component: './Order/OrderWarning',
  55 + },
  56 + {
  57 + name: '预警白名单',
  58 + path: 'WarningWhitelist',
  59 + component: './Order/WarningWhitelist',
  60 + },
  61 + ],
46 62 },
47 63 {
48 64 name: '订单报表',
... ...
src/components/UserHeader/index.tsx
1 1 import { RESPONSE_CODE } from '@/constants/enum';
2   -import MessageListDrawer from '@/pages/Order/components/MessageListDrawer';
  2 +import MessageListDrawer from '@/pages/Order/Order/components/MessageListDrawer';
3 3 import { postOrderErpMessageGetUnreadNum } from '@/services';
4 4 import { getUserInfo } from '@/utils';
5 5 import { BellOutlined, EllipsisOutlined } from '@ant-design/icons';
... ...
src/pages/Order/components/AfterSalesDrawer.tsx renamed to src/pages/Order/Order/components/AfterSalesDrawer.tsx
... ... @@ -9,7 +9,7 @@ import {
9 9 ProFormUploadDragger,
10 10 } from '@ant-design/pro-components';
11 11 import { Form, message } from 'antd';
12   -import { AFTE_SALES_PLAN_OPTIONS } from '../constant';
  12 +import { AFTE_SALES_PLAN_OPTIONS } from '../../constant';
13 13 export default ({ setVisible, mainOrder, subOrders, onClose }) => {
14 14 let subOrderIds = subOrders?.map((item: { id: any }) => {
15 15 return item.id;
... ...
src/pages/Order/components/ApplyForInvoicingModal.tsx renamed to src/pages/Order/Order/components/ApplyForInvoicingModal.tsx
... ... @@ -10,7 +10,7 @@ import {
10 10 } from '@ant-design/pro-components';
11 11 import { Form, message } from 'antd';
12 12 import { useEffect, useState } from 'react';
13   -import { PAYEE_OPTIONS } from '../constant';
  13 +import { PAYEE_OPTIONS } from '../../constant';
14 14 export default ({
15 15 setCheckVisible,
16 16 isEdit,
... ...
src/pages/Order/components/AttachmentModal.tsx renamed to src/pages/Order/Order/components/AttachmentModal.tsx
src/pages/Order/components/BaseModal.tsx renamed to src/pages/Order/Order/components/BaseModal.tsx
src/pages/Order/components/CheckModal.tsx renamed to src/pages/Order/Order/components/CheckModal.tsx
... ... @@ -32,9 +32,9 @@ import {
32 32 AFTE_SALES_PLAN_OPTIONS,
33 33 CHECK_TYPE,
34 34 COMFIR_RECEIPT_IMAGES_NUMBER,
35   -} from '../constant';
  35 +} from '../../constant';
36 36 // import { cloneDeep } from 'lodash';
37   -import InvoiceSubOrderInfoTable from '@/pages/Order/components/InvoiceSubOrderInfoTable';
  37 +import InvoiceSubOrderInfoTable from '@/pages/Order/Order/components/InvoiceSubOrderInfoTable';
38 38 import { enumValueToLabel, transImageFile } from '@/utils';
39 39 import { PlusOutlined } from '@ant-design/icons';
40 40 import { cloneDeep } from 'lodash';
... ... @@ -235,8 +235,8 @@ export default ({
235 235 setPreviewOpen(true);
236 236 setPreviewTitle(
237 237 file.name ||
238   - file.originFileObj?.name ||
239   - file.url!.substring(file.url!.lastIndexOf('/') + 1),
  238 + file.originFileObj?.name ||
  239 + file.url!.substring(file.url!.lastIndexOf('/') + 1),
240 240 );
241 241 };
242 242  
... ...
src/pages/Order/components/ConfirmReceiptModal.tsx renamed to src/pages/Order/Order/components/ConfirmReceiptModal.tsx
... ... @@ -5,7 +5,7 @@ import { Button, Modal, Upload, message } from 'antd';
5 5 import { RcFile, UploadFile, UploadProps } from 'antd/es/upload';
6 6 import { cloneDeep } from 'lodash';
7 7 import { useEffect, useRef, useState } from 'react';
8   -import { COMFIR_RECEIPT_IMAGES_NUMBER } from '../constant';
  8 +import { COMFIR_RECEIPT_IMAGES_NUMBER } from '../../constant';
9 9 export default ({ data, onClose }) => {
10 10 const subIds = data?.map((item) => {
11 11 return item.id;
... ... @@ -107,8 +107,8 @@ export default ({ data, onClose }) => {
107 107 setPreviewOpen(true);
108 108 setPreviewTitle(
109 109 file.name ||
110   - file.originFileObj?.name ||
111   - file.url!.substring(file.url!.lastIndexOf('/') + 1),
  110 + file.originFileObj?.name ||
  111 + file.url!.substring(file.url!.lastIndexOf('/') + 1),
112 112 );
113 113 };
114 114  
... ...
src/pages/Order/components/DeliverInfoDrawer.tsx renamed to src/pages/Order/Order/components/DeliverInfoDrawer.tsx
... ... @@ -3,7 +3,7 @@ import { enumValueToLabel } from '@/utils';
3 3 import { getReceivingCompanyOptions } from '@/utils/order';
4 4 import { Col, Drawer, Row } from 'antd';
5 5 import { useEffect, useState } from 'react';
6   -import { PAYEE_OPTIONS } from '../constant';
  6 +import { PAYEE_OPTIONS } from '../../constant';
7 7  
8 8 export default ({ data, onClose }) => {
9 9 const [province, setProvince] = useState('');
... ...
src/pages/Order/components/DeliverModal.tsx renamed to src/pages/Order/Order/components/DeliverModal.tsx
... ... @@ -25,7 +25,7 @@ import {
25 25 } from 'antd';
26 26 import { cloneDeep } from 'lodash';
27 27 import { useEffect, useRef, useState } from 'react';
28   -import { CHECK_TYPE, LOGISTICS_STATUS_OPTIONS } from '../constant';
  28 +import { CHECK_TYPE, LOGISTICS_STATUS_OPTIONS } from '../../constant';
29 29  
30 30 const DeliverModal = ({
31 31 data: propsData,
... ... @@ -260,7 +260,7 @@ const DeliverModal = ({
260 260 serialNumber: item.serialNumber,
261 261 packageNumber:
262 262 item.packageNumber === null ||
263   - item.packageNumber === undefined
  263 + item.packageNumber === undefined
264 264 ? 1
265 265 : item.packageNumber,
266 266 logisticsNotes: item.logisticsNotes,
... ...
src/pages/Order/components/FinancialDrawer.tsx renamed to src/pages/Order/Order/components/FinancialDrawer.tsx
... ... @@ -15,7 +15,7 @@ import {
15 15 } from '@ant-design/pro-components';
16 16 import { Button, Form, message } from 'antd';
17 17 import { useEffect, useState } from 'react';
18   -import { INVOCING_STATUS_OPTIONS_OLD, PAYEE_OPTIONS } from '../constant';
  18 +import { INVOCING_STATUS_OPTIONS_OLD, PAYEE_OPTIONS } from '../../constant';
19 19  
20 20 export default ({
21 21 mainOrder,
... ... @@ -144,107 +144,107 @@ export default ({
144 144  
145 145 {invoicingStatus !== 'UN_INVOICE'
146 146 ? [
147   - <ProFormDatePicker
148   - key="invoicingTime"
149   - width="lg"
150   - name="invoicingTime"
151   - label="开票时间"
152   - disabled={isEdit}
153   - rules={[
154   - { required: !isEdit ? true : false, message: '这是必填项' },
155   - ]}
156   - initialValue={subOrders[0]?.invoicingTime}
157   - />,
158   - <ProFormText
159   - key="purchaser"
160   - width="lg"
161   - name="purchaser"
162   - label="抬头名称"
163   - disabled={isEdit}
164   - rules={[
165   - { required: !isEdit ? true : false, message: '这是必填项' },
166   - ]}
167   - initialValue={subOrders[0]?.purchaser}
168   - />,
169   - <ProFormDatePicker
170   - key="financialReceiptIssuanceTime"
171   - width="lg"
172   - name="financialReceiptIssuanceTime"
173   - label="开收据时间"
174   - initialValue={subOrders[0]?.financialReceiptIssuanceTime}
175   - />,
176   - <ProFormDatePicker
177   - key="collectMoneyTime"
178   - width="lg"
179   - name="collectMoneyTime"
180   - label="收款时间"
181   - initialValue={subOrders[0]?.collectMoneyTime}
182   - />,
183   - <ProFormText
184   - width="lg"
185   - key="invoiceNumber"
186   - name="invoiceNumber"
187   - label="发票号码"
188   - initialValue={subOrders[0]?.invoiceNumber}
189   - rules={[{ required: true, message: '发票号码必填' }]}
190   - />,
191   - <div
192   - key="salesChooseReceivingCompany"
193   - hidden={subOrders[0].receivingCompany === null}
  147 + <ProFormDatePicker
  148 + key="invoicingTime"
  149 + width="lg"
  150 + name="invoicingTime"
  151 + label="开票时间"
  152 + disabled={isEdit}
  153 + rules={[
  154 + { required: !isEdit ? true : false, message: '这是必填项' },
  155 + ]}
  156 + initialValue={subOrders[0]?.invoicingTime}
  157 + />,
  158 + <ProFormText
  159 + key="purchaser"
  160 + width="lg"
  161 + name="purchaser"
  162 + label="抬头名称"
  163 + disabled={isEdit}
  164 + rules={[
  165 + { required: !isEdit ? true : false, message: '这是必填项' },
  166 + ]}
  167 + initialValue={subOrders[0]?.purchaser}
  168 + />,
  169 + <ProFormDatePicker
  170 + key="financialReceiptIssuanceTime"
  171 + width="lg"
  172 + name="financialReceiptIssuanceTime"
  173 + label="开收据时间"
  174 + initialValue={subOrders[0]?.financialReceiptIssuanceTime}
  175 + />,
  176 + <ProFormDatePicker
  177 + key="collectMoneyTime"
  178 + width="lg"
  179 + name="collectMoneyTime"
  180 + label="收款时间"
  181 + initialValue={subOrders[0]?.collectMoneyTime}
  182 + />,
  183 + <ProFormText
  184 + width="lg"
  185 + key="invoiceNumber"
  186 + name="invoiceNumber"
  187 + label="发票号码"
  188 + initialValue={subOrders[0]?.invoiceNumber}
  189 + rules={[{ required: true, message: '发票号码必填' }]}
  190 + />,
  191 + <div
  192 + key="salesChooseReceivingCompany"
  193 + hidden={subOrders[0].receivingCompany === null}
  194 + >
  195 + <span className={'pl-2 text-xs text-gray-400'}>
  196 + 销售申请开票时选择了:
  197 + {enumValueToLabel(
  198 + subOrders[0].receivingCompany,
  199 + getReceivingCompanyOptions(PAYEE_OPTIONS),
  200 + )}
  201 + </span>
  202 + <span
  203 + hidden={subOrders[0].receivingCompany === 'ANY'}
  204 + className={
  205 + 'pl-2 text-xs text-[#1677ff] cursor-pointer hover:text-[#64abf7]'
  206 + }
  207 + onClick={() => {
  208 + chooseReceivingCompany(subOrders[0].receivingCompany);
  209 + }}
194 210 >
195   - <span className={'pl-2 text-xs text-gray-400'}>
196   - 销售申请开票时选择了:
197   - {enumValueToLabel(
198   - subOrders[0].receivingCompany,
199   - getReceivingCompanyOptions(PAYEE_OPTIONS),
200   - )}
201   - </span>
202   - <span
203   - hidden={subOrders[0].receivingCompany === 'ANY'}
204   - className={
205   - 'pl-2 text-xs text-[#1677ff] cursor-pointer hover:text-[#64abf7]'
206   - }
207   - onClick={() => {
208   - chooseReceivingCompany(subOrders[0].receivingCompany);
209   - }}
210   - >
211   - 选择
212   - </span>
213   - </div>,
214   - <ProFormSelect
215   - key="payee"
216   - placeholder="选择收款单位"
217   - name="payee"
218   - width="lg"
219   - showSearch
220   - label="收款单位"
221   - options={enumToSelect(PAYEE_OPTIONS)}
222   - initialValue={subOrders[0]?.payee}
223   - rules={[{ required: true, message: '收款单位必填' }]}
224   - />,
  211 + 选择
  212 + </span>
  213 + </div>,
  214 + <ProFormSelect
  215 + key="payee"
  216 + placeholder="选择收款单位"
  217 + name="payee"
  218 + width="lg"
  219 + showSearch
  220 + label="收款单位"
  221 + options={enumToSelect(PAYEE_OPTIONS)}
  222 + initialValue={subOrders[0]?.payee}
  223 + rules={[{ required: true, message: '收款单位必填' }]}
  224 + />,
225 225  
226   - <div id="total-payment" key="money">
227   - <ProFormDigit
228   - key="money"
229   - name="money"
230   - width="lg"
231   - label="金额"
232   - rules={[{ required: true, message: '金额必填' }]}
233   - tooltip="点击计算,合计所有子订单对应主订单总额"
234   - fieldProps={{
235   - addonAfter: (
236   - <Button
237   - className="rounded-l-none"
238   - type="primary"
239   - onClick={computeTotalPayment}
240   - >
241   - 计算
242   - </Button>
243   - ),
244   - }}
245   - />
246   - </div>,
247   - ]
  226 + <div id="total-payment" key="money">
  227 + <ProFormDigit
  228 + key="money"
  229 + name="money"
  230 + width="lg"
  231 + label="金额"
  232 + rules={[{ required: true, message: '金额必填' }]}
  233 + tooltip="点击计算,合计所有子订单对应主订单总额"
  234 + fieldProps={{
  235 + addonAfter: (
  236 + <Button
  237 + className="rounded-l-none"
  238 + type="primary"
  239 + onClick={computeTotalPayment}
  240 + >
  241 + 计算
  242 + </Button>
  243 + ),
  244 + }}
  245 + />
  246 + </div>,
  247 + ]
248 248 : ''}
249 249  
250 250 <ProFormSelect
... ...
src/pages/Order/components/FinancialEditDrawer.tsx renamed to src/pages/Order/Order/components/FinancialEditDrawer.tsx
... ... @@ -9,7 +9,7 @@ import {
9 9 } from '@ant-design/pro-components';
10 10 import { Form, message } from 'antd';
11 11 import { useEffect, useState } from 'react';
12   -import { INVOCING_STATUS_OPTIONS_OLD } from '../constant';
  12 +import { INVOCING_STATUS_OPTIONS_OLD } from '../../constant';
13 13  
14 14 export default ({ mainOrder, subOrders, setVisible, isMainOrder, onClose }) => {
15 15 const [invoicingStatus, setInvoicingStatus] = useState('');
... ... @@ -130,24 +130,24 @@ export default ({ mainOrder, subOrders, setVisible, isMainOrder, onClose }) =&gt; {
130 130 width="lg"
131 131 name="financialReceiptIssuanceTime"
132 132 label="开收据时间"
133   - // rules={[
134   - // {
135   - // required: !isMainOrder && invoicingStatus === 'UN_INVOICE',
136   - // message: '开收据时间必填',
137   - // },
138   - // ]}
  133 + // rules={[
  134 + // {
  135 + // required: !isMainOrder && invoicingStatus === 'UN_INVOICE',
  136 + // message: '开收据时间必填',
  137 + // },
  138 + // ]}
139 139 />
140 140 <ProFormDatePicker
141 141 key="collectMoneyTime"
142 142 width="lg"
143 143 name="collectMoneyTime"
144 144 label="收款时间"
145   - // rules={[
146   - // {
147   - // required: !isMainOrder && invoicingStatus === 'UN_INVOICE',
148   - // message: '收款时间必填',
149   - // },
150   - // ]}
  145 + // rules={[
  146 + // {
  147 + // required: !isMainOrder && invoicingStatus === 'UN_INVOICE',
  148 + // message: '收款时间必填',
  149 + // },
  150 + // ]}
151 151 />
152 152 </DrawerForm>
153 153 );
... ...
src/pages/Order/components/FinancialMergeDrawer.tsx renamed to src/pages/Order/Order/components/FinancialMergeDrawer.tsx
... ... @@ -9,7 +9,7 @@ import {
9 9 ProFormTextArea,
10 10 } from '@ant-design/pro-components';
11 11 import { Form, message } from 'antd';
12   -import { PAYEE_OPTIONS } from '../constant';
  12 +import { PAYEE_OPTIONS } from '../../constant';
13 13  
14 14 export default ({ dataList, setVisible, onClose }) => {
15 15 // let subOrderIds = dataList?.map((item) => {
... ...
src/pages/Order/components/FinancialReceiptsModal.tsx renamed to src/pages/Order/Order/components/FinancialReceiptsModal.tsx
src/pages/Order/components/HistoryModal.tsx renamed to src/pages/Order/Order/components/HistoryModal.tsx
src/pages/Order/components/ImagesViewerModal.tsx renamed to src/pages/Order/Order/components/ImagesViewerModal.tsx
src/pages/Order/components/ImportExpressBillModal.tsx renamed to src/pages/Order/Order/components/ImportExpressBillModal.tsx
src/pages/Order/components/ImportModal.tsx renamed to src/pages/Order/Order/components/ImportModal.tsx
src/pages/Order/components/InvoiceSubOrderInfoTable.tsx renamed to src/pages/Order/Order/components/InvoiceSubOrderInfoTable.tsx
src/pages/Order/components/InvoicingDrawerForm.tsx renamed to src/pages/Order/Order/components/InvoicingDrawerForm.tsx
src/pages/Order/components/KingdeeCustomerModal.tsx renamed to src/pages/Order/Order/components/KingdeeCustomerModal.tsx
src/pages/Order/components/LazySelect.tsx renamed to src/pages/Order/Order/components/LazySelect.tsx
src/pages/Order/components/MessageListDrawer.tsx renamed to src/pages/Order/Order/components/MessageListDrawer.tsx
src/pages/Order/components/ModifiedDiffModal.tsx renamed to src/pages/Order/Order/components/ModifiedDiffModal.tsx
... ... @@ -9,7 +9,7 @@ import {
9 9 PAYMENT_METHOD_OPTIONS,
10 10 PRODUCT_BELONG_DEPARTMENT_OPTIONS,
11 11 SHIPPING_WAREHOUSE_OPTIONS,
12   -} from '../constant';
  12 +} from '../../constant';
13 13 import '../table.less';
14 14  
15 15 export default ({ setVisible, subOrders, mainOrder, onClose }) => {
... ... @@ -106,7 +106,7 @@ export default ({ setVisible, subOrders, mainOrder, onClose }) =&gt; {
106 106 onClick={() => {
107 107 window.open(
108 108 '/previewApi/onlinePreview?url=' +
109   - encodeURIComponent(Base64.encode(item)),
  109 + encodeURIComponent(Base64.encode(item)),
110 110 );
111 111 }}
112 112 >
... ...
src/pages/Order/components/OrderDrawer copy.tsx renamed to src/pages/Order/Order/components/OrderDrawer copy.tsx
src/pages/Order/components/OrderDrawer.tsx renamed to src/pages/Order/Order/components/OrderDrawer.tsx
... ... @@ -51,7 +51,7 @@ import {
51 51 PAYMENT_METHOD_OPTIONS,
52 52 PRODUCT_BELONG_DEPARTMENT_OPTIONS,
53 53 SHIPPING_WAREHOUSE_OPTIONS,
54   -} from '../constant';
  54 +} from '../../constant';
55 55 import KingdeeCustomerModal from './KingdeeCustomerModal';
56 56  
57 57 export default ({ onClose, data, subOrders, orderOptType }) => {
... ... @@ -556,9 +556,9 @@ export default ({ onClose, data, subOrders, orderOptType }) =&gt; {
556 556 form.setFieldValue(
557 557 'customerShippingAddress',
558 558 getDefaultString(option.province) +
559   - getDefaultString(option.city) +
560   - getDefaultString(option.district) +
561   - getDefaultString(option.detail),
  559 + getDefaultString(option.city) +
  560 + getDefaultString(option.district) +
  561 + getDefaultString(option.detail),
562 562 );
563 563 form.setFieldValue('customerNameString', option.realName);
564 564  
... ... @@ -641,11 +641,11 @@ export default ({ onClose, data, subOrders, orderOptType }) =&gt; {
641 641  
642 642 message.error(
643 643 '用户余额不足,当前预减的金额为:' +
644   - data.subPrice +
645   - ',当前账号余额为:' +
646   - data.nowMoney +
647   - ',当前账号可赊账额度为:' +
648   - data.creditLimit,
  644 + data.subPrice +
  645 + ',当前账号余额为:' +
  646 + data.nowMoney +
  647 + ',当前账号可赊账额度为:' +
  648 + data.creditLimit,
649 649 );
650 650 return false;
651 651 }
... ... @@ -1110,7 +1110,7 @@ export default ({ onClose, data, subOrders, orderOptType }) =&gt; {
1110 1110 },
1111 1111 }}
1112 1112 debounceTime={1000}
1113   - request={async (value, {}) => {
  1113 + request={async (value, { }) => {
1114 1114 const keywords = value.keyWords;
1115 1115 if (keywords === '') {
1116 1116 return [];
... ... @@ -1865,7 +1865,7 @@ export default ({ onClose, data, subOrders, orderOptType }) =&gt; {
1865 1865 placeholder="请输入商品参数"
1866 1866 disabled={
1867 1867 productParametersDisabledFlagList[listMeta.index] !==
1868   - false || optType('after-sales-check')
  1868 + false || optType('after-sales-check')
1869 1869 }
1870 1870 />,
1871 1871 <ProFormDigit
... ... @@ -1918,7 +1918,7 @@ export default ({ onClose, data, subOrders, orderOptType }) =&gt; {
1918 1918 placeholder="请输入商品单位"
1919 1919 disabled={
1920 1920 productParametersDisabledFlagList[listMeta.index] !==
1921   - false || optType('after-sales-check')
  1921 + false || optType('after-sales-check')
1922 1922 }
1923 1923 rules={[{ required: true, message: '商品单位必填' }]}
1924 1924 />,
... ...
src/pages/Order/components/OrderNotesEditModal.tsx renamed to src/pages/Order/Order/components/OrderNotesEditModal.tsx
src/pages/Order/components/OtherInfoModal.tsx renamed to src/pages/Order/Order/components/OtherInfoModal.tsx
src/pages/Order/components/ProcureCheckModal.tsx renamed to src/pages/Order/Order/components/ProcureCheckModal.tsx
src/pages/Order/components/ProcureConvertModal.tsx renamed to src/pages/Order/Order/components/ProcureConvertModal.tsx
src/pages/Order/components/ProcureNotesEditModal.tsx renamed to src/pages/Order/Order/components/ProcureNotesEditModal.tsx
src/pages/Order/components/ProductionTimeModal.tsx renamed to src/pages/Order/Order/components/ProductionTimeModal.tsx
src/pages/Order/components/ReissueModal.tsx renamed to src/pages/Order/Order/components/ReissueModal.tsx
src/pages/Order/components/ReissueModal_old.tsx renamed to src/pages/Order/Order/components/ReissueModal_old.tsx
src/pages/Order/components/ShippingWarehouseChangeModal.tsx renamed to src/pages/Order/Order/components/ShippingWarehouseChangeModal.tsx
... ... @@ -3,7 +3,7 @@ import { postServiceOrderShippingWarehouseChange } from &#39;@/services&#39;;
3 3 import { enumToSelect } from '@/utils';
4 4 import { ModalForm, ProFormSelect } from '@ant-design/pro-components';
5 5 import { Form, message } from 'antd';
6   -import { SHIPPING_WAREHOUSE_OPTIONS } from '../constant';
  6 +import { SHIPPING_WAREHOUSE_OPTIONS } from '../../constant';
7 7  
8 8 export default ({
9 9 setVisible,
... ...
src/pages/Order/components/UploadPayBillModal.tsx renamed to src/pages/Order/Order/components/UploadPayBillModal.tsx
... ... @@ -3,7 +3,7 @@ import { Form, Modal, Upload, UploadFile, UploadProps, message } from &#39;antd&#39;;
3 3 import { RcFile } from 'antd/lib/upload';
4 4 import { cloneDeep } from 'lodash';
5 5 import { useEffect, useRef, useState } from 'react';
6   -import { COMFIR_RECEIPT_IMAGES_NUMBER } from '../constant';
  6 +import { COMFIR_RECEIPT_IMAGES_NUMBER } from '../../constant';
7 7 import { PlusOutlined } from '@ant-design/icons';
8 8 import { transImageFile } from '@/utils';
9 9 import { postServiceOrderFileProcess, postServiceOrderUploadPaymentReceipt } from '@/services';
... ...
src/pages/Order/hooks.ts renamed to src/pages/Order/Order/hooks.ts
src/pages/Order/index.less renamed to src/pages/Order/Order/index.less
src/pages/Order/index.tsx renamed to src/pages/Order/Order/index.tsx
1 1 import ButtonConfirm from '@/components/ButtomConfirm';
2 2 import { RESPONSE_CODE } from '@/constants/enum';
3   -import ImportExpressBillModal from '@/pages/Order/components/ImportExpressBillModal';
4   -import InvoicingDrawerForm from '@/pages/Order/components/InvoicingDrawerForm';
5   -import ReissueModal from '@/pages/Order/components/ReissueModal';
6   -import ReissueModal_old from '@/pages/Order/components/ReissueModal_old';
  3 +import ImportExpressBillModal from '@/pages/Order/Order/components/ImportExpressBillModal';
  4 +import InvoicingDrawerForm from '@/pages/Order/Order/components/InvoicingDrawerForm';
  5 +import ReissueModal from '@/pages/Order/Order/components/ReissueModal';
  6 +import ReissueModal_old from '@/pages/Order/Order/components/ReissueModal_old';
7 7 import {
8 8 postKingdeeRepSalBillOutbound,
9 9 postKingdeeRepSalOrderSave,
... ... @@ -78,7 +78,7 @@ import {
78 78 import Base64 from 'base-64';
79 79 import { cloneDeep } from 'lodash';
80 80 import React, { Key, useEffect, useMemo, useRef, useState } from 'react';
81   -import OrderPrintModal from '../OrderPrint/OrderPrintModal';
  81 +import OrderPrintModal from '../../OrderPrint/OrderPrintModal';
82 82 import AfterSalesDrawer from './components/AfterSalesDrawer';
83 83 import ApplyForInvoicingModal from './components/ApplyForInvoicingModal';
84 84 import AttachmentModal from './components/AttachmentModal';
... ... @@ -119,7 +119,7 @@ import {
119 119 TAGS_COLOR,
120 120 getInvoicingType,
121 121 getNeedInvoicing,
122   -} from './constant';
  122 +} from '../constant';
123 123 import './index.less';
124 124 import { OrderListItemType, OrderType } from './type.d';
125 125  
... ... @@ -830,7 +830,7 @@ const OrderPage = () =&gt; {
830 830 onConfirm={() => {
831 831 window.open(
832 832 '/previewApi/onlinePreview?url=' +
833   - encodeURIComponent(Base64.encode(item.url)),
  833 + encodeURIComponent(Base64.encode(item.url)),
834 834 );
835 835 }}
836 836 onCancel={() => {
... ... @@ -902,7 +902,7 @@ const OrderPage = () =&gt; {
902 902 </span>
903 903 {(roleCode === 'salesRepresentative' ||
904 904 roleCode === 'salesManager') &&
905   - !optRecord.isCurrentUserOrder ? (
  905 + !optRecord.isCurrentUserOrder ? (
906 906 <span className="text-[#f44e4e]">(非本账号订单)</span>
907 907 ) : (
908 908 ''
... ... @@ -1086,13 +1086,13 @@ const OrderPage = () =&gt; {
1086 1086 <Tooltip
1087 1087 title={
1088 1088 optRecord.invoicingUrgentCause !== null &&
1089   - optRecord.afterInvoicingStatus ===
  1089 + optRecord.afterInvoicingStatus ===
1090 1090 'URGENT_INVOICE_AUDITING'
1091 1091 ? optRecord.invoicingUrgentCause
1092 1092 : enumValueToLabel(
1093   - optRecord.afterInvoicingStatus,
1094   - AFTER_INVOICING_STATUS,
1095   - )
  1093 + optRecord.afterInvoicingStatus,
  1094 + AFTER_INVOICING_STATUS,
  1095 + )
1096 1096 }
1097 1097 >
1098 1098 <Tag
... ... @@ -1123,7 +1123,7 @@ const OrderPage = () =&gt; {
1123 1123 )}
1124 1124  
1125 1125 {(roleCode === 'warehouseKeeper' || roleCode === 'admin') &&
1126   - optRecord.shippingWarehouse !== null ? (
  1126 + optRecord.shippingWarehouse !== null ? (
1127 1127 <div
1128 1128 className="overflow-hidden whitespace-no-wrap overflow-ellipsis"
1129 1129 title={enumValueToLabel(
... ... @@ -1145,7 +1145,7 @@ const OrderPage = () =&gt; {
1145 1145 {/* 生产时间 */}
1146 1146 <div className="overflow-hidden whitespace-no-wrap overflow-ellipsis">
1147 1147 {optRecord.productionStartTime !== null ||
1148   - optRecord.productionEndTime !== null ? (
  1148 + optRecord.productionEndTime !== null ? (
1149 1149 <MyToolTip
1150 1150 title={
1151 1151 formatdate(optRecord.productionStartTime) +
... ... @@ -1175,7 +1175,7 @@ const OrderPage = () =&gt; {
1175 1175 <Tag
1176 1176 color={
1177 1177 optRecord.invoicingTime === null ||
1178   - optRecord.invoicingTime === undefined
  1178 + optRecord.invoicingTime === undefined
1179 1179 ? TAGS_COLOR.get(optRecord.invoicingStatus)
1180 1180 : 'success'
1181 1181 }
... ... @@ -1203,7 +1203,7 @@ const OrderPage = () =&gt; {
1203 1203  
1204 1204 {/**采购是否已下单状态 */}
1205 1205 {optRecord.procureOrderStatus !== null &&
1206   - optRecord.procureOrderStatus !== undefined ? (
  1206 + optRecord.procureOrderStatus !== undefined ? (
1207 1207 <div className="overflow-hidden whitespace-no-wrap overflow-ellipsis">
1208 1208 <Tag color="success">
1209 1209 {enumValueToLabel(
... ... @@ -1219,21 +1219,21 @@ const OrderPage = () =&gt; {
1219 1219 {/* 物流信息 */}
1220 1220 <div className="overflow-hidden whitespace-no-wrap overflow-ellipsis">
1221 1221 {optRecord.orderStatus === 'CONFIRM_RECEIPT' ||
1222   - optRecord.orderStatus === 'AFTER_SALES_COMPLETION' ||
1223   - optRecord.orderStatus === 'IN_AFTER_SALES' ||
1224   - optRecord.orderStatus === 'SHIPPED' ? (
  1222 + optRecord.orderStatus === 'AFTER_SALES_COMPLETION' ||
  1223 + optRecord.orderStatus === 'IN_AFTER_SALES' ||
  1224 + optRecord.orderStatus === 'SHIPPED' ? (
1225 1225 <MyToolTip
1226 1226 title={
1227 1227 optRecord.serialNumber === undefined
1228 1228 ? '暂无物流信息'
1229 1229 : enumValueToLabel(
1230   - optRecord.logisticsMethod,
1231   - LOGISTICS_STATUS_OPTIONS,
1232   - ) +
1233   - ' ' +
1234   - optRecord.serialNumber +
1235   - ' ' +
1236   - optRecord.logisticsNotes
  1230 + optRecord.logisticsMethod,
  1231 + LOGISTICS_STATUS_OPTIONS,
  1232 + ) +
  1233 + ' ' +
  1234 + optRecord.serialNumber +
  1235 + ' ' +
  1236 + optRecord.logisticsNotes
1237 1237 }
1238 1238 content={
1239 1239 <Button type="link" size="small" style={{ padding: 0 }}>
... ... @@ -1247,7 +1247,7 @@ const OrderPage = () =&gt; {
1247 1247  
1248 1248 {/* 修改审核状态 */}
1249 1249 {optRecord.modifiedAuditStatus !== null &&
1250   - optRecord.modifiedAuditStatus !== 'AUDIT_FAILURE' ? (
  1250 + optRecord.modifiedAuditStatus !== 'AUDIT_FAILURE' ? (
1251 1251 <div className="overflow-hidden whitespace-no-wrap overflow-ellipsis">
1252 1252 <Tooltip
1253 1253 title={recordOptNode ? recordOptNode : <Spin />}
... ... @@ -1687,7 +1687,7 @@ const OrderPage = () =&gt; {
1687 1687 )}
1688 1688  
1689 1689 {optRecord.paths?.includes('queryAnnex') &&
1690   - optRecord.listAnnex?.length > 0 ? (
  1690 + optRecord.listAnnex?.length > 0 ? (
1691 1691 <Button
1692 1692 className="p-0"
1693 1693 type="link"
... ... @@ -2121,7 +2121,7 @@ const OrderPage = () =&gt; {
2121 2121 </Flex>
2122 2122  
2123 2123 {(isProcure() || isWarehousekeeper() || isSales() || isAdmin()) &&
2124   - !isSupplier() ? (
  2124 + !isSupplier() ? (
2125 2125 <div className="pt-2">
2126 2126 <Flex title={optRecord.supplierName}>
2127 2127 <div>
... ... @@ -2196,7 +2196,7 @@ const OrderPage = () =&gt; {
2196 2196 <span className="text-[#8C8C8C]">
2197 2197 申请开票备注:
2198 2198 {optRecord.applyInvoicingNotes === undefined ||
2199   - optRecord.applyInvoicingNotes === null
  2199 + optRecord.applyInvoicingNotes === null
2200 2200 ? '暂无备注'
2201 2201 : optRecord.applyInvoicingNotes}
2202 2202 </span>
... ... @@ -2224,7 +2224,7 @@ const OrderPage = () =&gt; {
2224 2224 <span className="text-[#8C8C8C] mr-3">
2225 2225 财务审核备注:
2226 2226 {optRecord.checkNotes === undefined ||
2227   - optRecord.checkNotes === null
  2227 + optRecord.checkNotes === null
2228 2228 ? '暂无备注'
2229 2229 : optRecord.checkNotes}
2230 2230 </span>
... ... @@ -2248,7 +2248,7 @@ const OrderPage = () =&gt; {
2248 2248 <span className="text-[#8C8C8C]">
2249 2249 重新开票备注:
2250 2250 {optRecord.reissueNotes === undefined ||
2251   - optRecord.reissueNotes === null
  2251 + optRecord.reissueNotes === null
2252 2252 ? '暂无备注'
2253 2253 : optRecord.reissueNotes}
2254 2254 </span>
... ... @@ -2552,9 +2552,9 @@ const OrderPage = () =&gt; {
2552 2552 <span className="text-slate-700">
2553 2553 {record.receivingCompany !== null
2554 2554 ? enumValueToLabel(
2555   - record.receivingCompany,
2556   - getReceivingCompanyOptions(PAYEE_OPTIONS),
2557   - )
  2555 + record.receivingCompany,
  2556 + getReceivingCompanyOptions(PAYEE_OPTIONS),
  2557 + )
2558 2558 : '暂无'}
2559 2559 </span>
2560 2560 </div>
... ... @@ -3346,9 +3346,9 @@ const OrderPage = () =&gt; {
3346 3346 for (let i = 0; i < selectedSubOrders.length; i++) {
3347 3347 if (
3348 3348 selectedSubOrders[i].invoicingStatus ===
3349   - 'UN_INVOICE' ||
  3349 + 'UN_INVOICE' ||
3350 3350 selectedSubOrders[i].afterInvoicingStatus ===
3351   - 'APPLY_FOR_INVOICING'
  3351 + 'APPLY_FOR_INVOICING'
3352 3352 ) {
3353 3353 message.error(
3354 3354 '请选择需要开票且未申请开票的子订单进行申请',
... ... @@ -3383,9 +3383,9 @@ const OrderPage = () =&gt; {
3383 3383 for (let i = 0; i < selectedSubOrders.length; i++) {
3384 3384 if (
3385 3385 selectedSubOrders[i].invoicingStatus ===
3386   - 'UN_INVOICE' ||
  3386 + 'UN_INVOICE' ||
3387 3387 selectedSubOrders[i].afterInvoicingStatus ===
3388   - 'APPLY_FOR_INVOICING'
  3388 + 'APPLY_FOR_INVOICING'
3389 3389 ) {
3390 3390 message.error(
3391 3391 '请选择需要开票且未申请开票的子订单进行申请',
... ... @@ -3576,13 +3576,13 @@ const OrderPage = () =&gt; {
3576 3576 if (
3577 3577 selectedSubOrders[i].orderStatus !== 'AUDITED' &&
3578 3578 selectedSubOrders[i].orderStatus !==
3579   - 'PROCURE_PROCESS' &&
  3579 + 'PROCURE_PROCESS' &&
3580 3580 selectedSubOrders[i].orderStatus !==
3581   - 'PROCURE_PROCESS_FOR_MINE' &&
  3581 + 'PROCURE_PROCESS_FOR_MINE' &&
3582 3582 selectedSubOrders[i].orderStatus !==
3583   - 'PROCURE_WAIT_SHIP' &&
  3583 + 'PROCURE_WAIT_SHIP' &&
3584 3584 selectedSubOrders[i].orderStatus !==
3585   - 'SUPPLIER_WAIT_SHIP' &&
  3585 + 'SUPPLIER_WAIT_SHIP' &&
3586 3586 selectedSubOrders[i].orderStatus !== 'WAIT_SHIP'
3587 3587 ) {
3588 3588 message.error(
... ... @@ -3668,9 +3668,9 @@ const OrderPage = () =&gt; {
3668 3668 if (
3669 3669 selectedSubOrders[i].orderStatus !== 'UNAUDITED' &&
3670 3670 selectedSubOrders[i].orderStatus !==
3671   - 'FINANCE_PROCESS' &&
  3671 + 'FINANCE_PROCESS' &&
3672 3672 selectedSubOrders[i].orderStatus !==
3673   - 'LEADER_AUDITED'
  3673 + 'LEADER_AUDITED'
3674 3674 ) {
3675 3675 message.error(
3676 3676 '请选择[未审核]、[财务待审核]、[领导已审核]的子订单进行审核',
... ... @@ -3738,9 +3738,9 @@ const OrderPage = () =&gt; {
3738 3738 for (let i = 0; i < selectedSubOrders.length; i++) {
3739 3739 if (
3740 3740 selectedSubOrders[i].orderStatus !==
3741   - 'CONFIRM_RECEIPT' &&
  3741 + 'CONFIRM_RECEIPT' &&
3742 3742 selectedSubOrders[i].orderStatus !==
3743   - 'AFTER_SALES_FAILURE'
  3743 + 'AFTER_SALES_FAILURE'
3744 3744 ) {
3745 3745 message.error('请选择确认收货状态的子订单进行售后');
3746 3746 return;
... ... @@ -4203,7 +4203,7 @@ const OrderPage = () =&gt; {
4203 4203  
4204 4204 const exportMenuProps = {
4205 4205 items: exportItems,
4206   - onClick: () => {},
  4206 + onClick: () => { },
4207 4207 };
4208 4208  
4209 4209 //导出按钮配置
... ... @@ -4249,7 +4249,7 @@ const OrderPage = () =&gt; {
4249 4249  
4250 4250 const auditProps = {
4251 4251 items: auditItems,
4252   - onClick: () => {},
  4252 + onClick: () => { },
4253 4253 };
4254 4254  
4255 4255 if (rolePath?.includes('leaderMergeAudit')) {
... ... @@ -4370,8 +4370,8 @@ const OrderPage = () =&gt; {
4370 4370 if (errorIds.size > 0) {
4371 4371 message.error(
4372 4372 '订单号为:' +
4373   - [...errorIds.values()].join(',') +
4374   - '的订单存在不是[申请开票]或者[部分开票]状态的子订单,请检查!',
  4373 + [...errorIds.values()].join(',') +
  4374 + '的订单存在不是[申请开票]或者[部分开票]状态的子订单,请检查!',
4375 4375 );
4376 4376 return;
4377 4377 }
... ...
src/pages/Order/table.less renamed to src/pages/Order/Order/table.less
src/pages/Order/type.d.ts renamed to src/pages/Order/Order/type.d.ts
src/pages/Order/OrderWarning/components/AfterSalesDrawer.tsx 0 → 100644
  1 +import { RESPONSE_CODE } from '@/constants/enum';
  2 +import { postServiceOrderApplyAfterSales } from '@/services';
  3 +import { enumToSelect } from '@/utils';
  4 +import {
  5 + DrawerForm,
  6 + ProFormDigit,
  7 + ProFormSelect,
  8 + ProFormTextArea,
  9 + ProFormUploadDragger,
  10 +} from '@ant-design/pro-components';
  11 +import { Form, message } from 'antd';
  12 +import { AFTE_SALES_PLAN_OPTIONS } from '../../constant';
  13 +export default ({ setVisible, mainOrder, subOrders, onClose }) => {
  14 + let subOrderIds = subOrders?.map((item: { id: any }) => {
  15 + return item.id;
  16 + });
  17 +
  18 + let mainOrderId = mainOrder.id;
  19 + const [form] = Form.useForm<{
  20 + afterSalesNotes: string;
  21 + afterSalesPlan: string;
  22 + ids: [];
  23 + totalPayment: number;
  24 + filePaths: any[];
  25 + }>();
  26 +
  27 + return (
  28 + <DrawerForm<{
  29 + afterSalesNotes: string;
  30 + afterSalesPlan: string;
  31 + subOrderIds: [];
  32 + totalPayment: number;
  33 + mainId: number;
  34 + filePaths: any[];
  35 + }>
  36 + title="申请售后"
  37 + open
  38 + resize={{
  39 + onResize() {
  40 + console.log('resize!');
  41 + },
  42 + maxWidth: window.innerWidth * 0.8,
  43 + minWidth: 500,
  44 + }}
  45 + form={form}
  46 + autoFocusFirstInput
  47 + drawerProps={{
  48 + destroyOnClose: true,
  49 + onClose: () => {
  50 + setVisible(false);
  51 + },
  52 + }}
  53 + onFinish={async (values) => {
  54 + values.subOrderIds = subOrderIds;
  55 + values.mainId = mainOrderId;
  56 + values.filePaths = values.filePaths?.map((file) => {
  57 + return { url: file.response.data[0] };
  58 + });
  59 + let res = await postServiceOrderApplyAfterSales({ data: values });
  60 + if (res?.result === RESPONSE_CODE.SUCCESS) {
  61 + message.success(res.message);
  62 + onClose();
  63 + }
  64 + }}
  65 + >
  66 + <ProFormSelect
  67 + key="key"
  68 + label="售后方案"
  69 + width="lg"
  70 + showSearch
  71 + name="afterSalesPlan"
  72 + options={enumToSelect(AFTE_SALES_PLAN_OPTIONS)}
  73 + placeholder="请搜索"
  74 + rules={[{ required: true, message: '售后方案必填' }]}
  75 + ></ProFormSelect>
  76 + <ProFormDigit
  77 + width="lg"
  78 + name="totalPayment"
  79 + label="总金额调整"
  80 + min={0}
  81 + initialValue={mainOrder.totalPayment}
  82 + rules={[{ required: true, message: '总金额必填' }]}
  83 + />
  84 + <ProFormTextArea
  85 + width="lg"
  86 + label="售后原因"
  87 + name="afterSalesNotes"
  88 + rules={[{ required: true, message: '售后原因必填' }]}
  89 + />
  90 + <ProFormUploadDragger
  91 + key="filePaths"
  92 + label="附件"
  93 + name="filePaths"
  94 + action="/api/service/order/fileProcess"
  95 + fieldProps={{
  96 + headers: { Authorization: localStorage.getItem('token') },
  97 + }}
  98 + />
  99 + </DrawerForm>
  100 + );
  101 +};
... ...
src/pages/Order/OrderWarning/components/ApplyForInvoicingModal.tsx 0 → 100644
  1 +import { RESPONSE_CODE } from '@/constants/enum';
  2 +import { postServiceOrderApplyInvoicing } from '@/services';
  3 +import { enumToSelect, getAliYunOSSFileNameFromUrl } from '@/utils';
  4 +import {
  5 + ModalForm,
  6 + ProFormSelect,
  7 + ProFormText,
  8 + ProFormTextArea,
  9 + ProFormUploadDragger,
  10 +} from '@ant-design/pro-components';
  11 +import { Form, message } from 'antd';
  12 +import { useEffect, useState } from 'react';
  13 +import { PAYEE_OPTIONS } from '../../constant';
  14 +export default ({
  15 + setCheckVisible,
  16 + isEdit,
  17 + subOrders,
  18 + isMainOrder,
  19 + totalPayment,
  20 + onClose,
  21 +}) => {
  22 + const [isUrgent, setIsUrgent] = useState('');
  23 + let sumPrice = totalPayment;
  24 +
  25 + let ids = subOrders?.map((item) => {
  26 + return item.id;
  27 + });
  28 +
  29 + let mainIdSet = new Set();
  30 + subOrders?.forEach((item: { mainOrderId: unknown }) => {
  31 + mainIdSet.add(item.mainOrderId);
  32 + });
  33 +
  34 + let mainIds = Array.from(mainIdSet).join(',');
  35 +
  36 + let newListAnnex = [];
  37 +
  38 + //回显,子订单可以编辑备注跟附件
  39 + if (isEdit) {
  40 + newListAnnex = subOrders.afterAnnexList?.map((path) => {
  41 + let i = 0;
  42 + return {
  43 + uid: i++,
  44 + name: getAliYunOSSFileNameFromUrl(path),
  45 + status: 'uploaded',
  46 + url: path,
  47 + response: { data: [path] },
  48 + };
  49 + });
  50 + subOrders.filePaths = newListAnnex;
  51 + }
  52 +
  53 + const [form] = Form.useForm<{
  54 + applyInvoicingNotes: string;
  55 + filePaths: any;
  56 + subIds: any[];
  57 + afterInvoicingUpdate: boolean;
  58 + receivingCompany: string;
  59 + isUrgent: boolean;
  60 + deadline: string;
  61 + }>();
  62 +
  63 + useEffect(() => {
  64 + //显示拼接的主订单id
  65 + form.setFieldValue('applyInvoicingNotes', mainIds);
  66 + }, []);
  67 +
  68 + return (
  69 + <ModalForm<{
  70 + applyInvoicingNotes: string;
  71 + filePaths: any;
  72 + subIds: any[];
  73 + afterInvoicingUpdate: boolean;
  74 + }>
  75 + width={500}
  76 + open
  77 + title={isEdit ? '修改信息' : '申请开票'}
  78 + initialValues={subOrders}
  79 + form={form}
  80 + autoFocusFirstInput
  81 + modalProps={{
  82 + okText: '确认',
  83 + cancelText: '取消',
  84 + destroyOnClose: true,
  85 + onCancel: () => {
  86 + setCheckVisible(false);
  87 + },
  88 + }}
  89 + submitter={{
  90 + render: (props, defaultDoms) => {
  91 + return defaultDoms;
  92 + },
  93 + }}
  94 + submitTimeout={2000}
  95 + onFinish={async (values) => {
  96 + values.subIds = ids;
  97 + //附件处理
  98 + values.filePaths = values.filePaths?.map((item) => {
  99 + return { url: item.response.data[0] };
  100 + });
  101 +
  102 + if (isEdit) {
  103 + values.afterInvoicingUpdate = true;
  104 + } else {
  105 + values.afterInvoicingUpdate = false;
  106 + }
  107 +
  108 + const res = await postServiceOrderApplyInvoicing({ data: values });
  109 +
  110 + if (res.result === RESPONSE_CODE.SUCCESS) {
  111 + message.success(res.message);
  112 + onClose();
  113 + }
  114 + }}
  115 + onOpenChange={setCheckVisible}
  116 + >
  117 + {isMainOrder ? (
  118 + <div className="mb-[24px]">
  119 + <span>选中子订单金额之和:</span>
  120 + <span className="text-red-500">{sumPrice}¥</span>
  121 + </div>
  122 + ) : (
  123 + ''
  124 + )}
  125 +
  126 + <div className="mb-1">
  127 + 如果需要合并订单,请将需要合并的订单id写在备注中,id之间用英文逗号隔开。
  128 + </div>
  129 + <ProFormTextArea
  130 + width="lg"
  131 + name="applyInvoicingNotes"
  132 + key="applyInvoicingNotes"
  133 + placeholder="请输入备注"
  134 + onMetaChange={(val) => {
  135 + console.log(val);
  136 + }}
  137 + proFieldProps={{
  138 + onchange: () => {
  139 + message.info('change');
  140 + },
  141 + }}
  142 + />
  143 + <ProFormText
  144 + width="lg"
  145 + name="purchaser"
  146 + label="抬头名称"
  147 + key="purchaser"
  148 + placeholder="请输入抬头名称"
  149 + rules={[{ required: true, message: '抬头名称必填' }]}
  150 + />
  151 + <ProFormSelect
  152 + placeholder="选择收款单位"
  153 + name="receivingCompany"
  154 + width="lg"
  155 + key="receivingCompany"
  156 + label={
  157 + <div>
  158 + <span>开票收款单位</span>
  159 + <span className="pl-2 text-xs text-gray-400">
  160 + 财务开票将依据这个字段,选择对应的公司开票(若对[收款单位]没有要求,请任意选择一个)
  161 + </span>
  162 + </div>
  163 + }
  164 + options={enumToSelect(PAYEE_OPTIONS)}
  165 + rules={[{ required: true, message: '开票收款单位必填' }]}
  166 + />
  167 + <ProFormSelect
  168 + placeholder="选择是否加急"
  169 + name="isUrgent"
  170 + width="lg"
  171 + key="isUrgent"
  172 + label="是否加急"
  173 + options={[
  174 + { label: '是', value: 'true' },
  175 + { label: '否', value: 'false' },
  176 + ]}
  177 + rules={[{ required: true, message: '是否加急必填' }]}
  178 + onChange={(val: any) => {
  179 + setIsUrgent(val);
  180 + }}
  181 + />
  182 +
  183 + {/* <ProFormDatePicker
  184 + key="deadline"
  185 + label="期望开票时间"
  186 + name="deadline"
  187 + rules={[{ required: isUrgent === 'true', message: '期望开票时间必填' }]}
  188 + hidden={isUrgent !== 'true'}
  189 + /> */}
  190 +
  191 + <ProFormTextArea
  192 + key="invoicingUrgentCause"
  193 + label="加急开票原因"
  194 + name="invoicingUrgentCause"
  195 + rules={[{ required: isUrgent === 'true', message: '加急开票原因' }]}
  196 + hidden={isUrgent !== 'true'}
  197 + />
  198 +
  199 + <ProFormUploadDragger
  200 + key="2"
  201 + label={
  202 + <div>
  203 + <span>开票明细确认表</span>
  204 + <span className="pl-2 text-xs text-gray-400">
  205 + 如果开票信息有变更,如开票内容跟下单内容不一致、下单抬头和付款抬头不一致,请上传开票明细确认表。
  206 + </span>
  207 + </div>
  208 + }
  209 + name="filePaths"
  210 + action="/api/service/order/fileProcess"
  211 + fieldProps={{
  212 + headers: { Authorization: localStorage.getItem('token') },
  213 + }}
  214 + />
  215 + </ModalForm>
  216 + );
  217 +};
... ...
src/pages/Order/OrderWarning/components/AttachmentModal.tsx 0 → 100644
  1 +import { getAliYunOSSFileNameFromUrl, isImageName } from '@/utils';
  2 +import { ModalForm } from '@ant-design/pro-components';
  3 +import { Button, Card, Divider, Empty, Form, Image, List, message } from 'antd';
  4 +import Base64 from 'base-64';
  5 +import { cloneDeep } from 'lodash';
  6 +import React, { useEffect, useState } from 'react';
  7 +
  8 +export default ({ data, onClose }) => {
  9 + let newData = cloneDeep(data);
  10 + const [fileList, setFileList] = useState<[]>([]);
  11 + console.log(fileList);
  12 + const [form] = Form.useForm<{
  13 + subOrderId: '';
  14 + listAnnex: [];
  15 + }>();
  16 +
  17 + let newListAnnex = newData.listAnnex?.map((path) => {
  18 + let i = 0;
  19 + return {
  20 + uid: i++,
  21 + name: getAliYunOSSFileNameFromUrl(path),
  22 + status: 'uploaded',
  23 + url: path,
  24 + response: { data: [path] },
  25 + };
  26 + });
  27 + newData.listAnnex = newListAnnex;
  28 +
  29 + //将图片和其他文件区分开
  30 + let images: any[] = [];
  31 + let otherAnnex: any[] = [];
  32 + newListAnnex.forEach((item: any) => {
  33 + if (isImageName(item.name)) {
  34 + images.push(item);
  35 + } else {
  36 + otherAnnex.push(item);
  37 + }
  38 + });
  39 +
  40 + useEffect(() => {
  41 + setFileList(newData.listAnnex);
  42 + }, []);
  43 +
  44 + return (
  45 + <ModalForm
  46 + width={800}
  47 + open
  48 + title="查看附件"
  49 + initialValues={newData}
  50 + form={form}
  51 + modalProps={{
  52 + onCancel: onClose,
  53 + }}
  54 + submitter={{
  55 + render: () => {
  56 + return [
  57 + <Button
  58 + key="back"
  59 + onClick={() => {
  60 + onClose();
  61 + }}
  62 + >
  63 + 返回
  64 + </Button>,
  65 + ];
  66 + },
  67 + }}
  68 + >
  69 + {newListAnnex?.length <= 0 ? (
  70 + <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
  71 + ) : (
  72 + // <ProFormUploadDragger
  73 + // name="listAnnex"
  74 + // action="/api/service/order/fileProcess"
  75 + // disabled
  76 + // fieldProps={{
  77 + // headers: { Authorization: localStorage.getItem('token') },
  78 + // // onRemove: (file) => {
  79 + // // const index = fileList[listMeta.index].indexOf(file);
  80 + // // console.log(index);
  81 + // // const newFileList = fileList.slice();
  82 + // // newFileList.splice(index, 1);
  83 + // // setFileList(newFileList);
  84 + // // },
  85 + // // beforeUpload: (file) => {
  86 + // // fileList[listMeta.index] = [...fileList[listMeta.index], file as RcFile];
  87 + // // setFileList(fileList);
  88 + // // return true;
  89 + // // },
  90 + // fileList,
  91 + // // defaultFileList: itemFileList
  92 + // }}
  93 + // />
  94 + <>
  95 + <Card>
  96 + <Image.PreviewGroup
  97 + className="mr-10"
  98 + preview={{
  99 + onChange: (current, prev) =>
  100 + console.log(`current index: ${current}, prev index: ${prev}`),
  101 + }}
  102 + >
  103 + {images.map((item, index) => (
  104 + <React.Fragment key={index}>
  105 + <Image
  106 + className="max-h-[200px] max-w-[200px]"
  107 + src={item.url}
  108 + title={item.name}
  109 + />{' '}
  110 + <Divider type="vertical" />
  111 + </React.Fragment>
  112 + ))}
  113 + </Image.PreviewGroup>
  114 + </Card>
  115 + <Divider />
  116 +
  117 + <div>
  118 + <List
  119 + size="small"
  120 + header={<div>其他类型文件</div>}
  121 + bordered
  122 + dataSource={otherAnnex}
  123 + renderItem={(item) => (
  124 + <List.Item
  125 + actions={[
  126 + <Button
  127 + type="link"
  128 + key="key"
  129 + href={item.url}
  130 + target="blank"
  131 + className="py-1"
  132 + >
  133 + 下载
  134 + </Button>,
  135 + <Button
  136 + type="link"
  137 + key="key"
  138 + className="py-1"
  139 + onClick={() => {
  140 + message.info(item.url);
  141 + window.open(
  142 + '/previewApi/onlinePreview?url=' +
  143 + encodeURIComponent(Base64.encode(item.url)),
  144 + );
  145 + }}
  146 + >
  147 + 预览
  148 + </Button>,
  149 + ]}
  150 + >
  151 + <div>
  152 + <span>{item.name}</span>
  153 + </div>
  154 + </List.Item>
  155 + )}
  156 + />
  157 + </div>
  158 + </>
  159 + )}
  160 + </ModalForm>
  161 + );
  162 +};
... ...
src/pages/Order/OrderWarning/components/BaseModal.tsx 0 → 100644
  1 +import { ModalForm } from '@ant-design/pro-components';
  2 +import { Form } from 'antd';
  3 +
  4 +// import { cloneDeep } from 'lodash';
  5 +export default ({ setVisible, onClose }) => {
  6 + const [form] = Form.useForm<{ name: string; company: string }>();
  7 +
  8 + return (
  9 + <>
  10 + <ModalForm<{
  11 + name: string;
  12 + company: string;
  13 + }>
  14 + width={500}
  15 + open
  16 + title="标题"
  17 + form={form}
  18 + autoFocusFirstInput
  19 + modalProps={{
  20 + okText: '通过',
  21 + cancelText: '取消',
  22 + destroyOnClose: true,
  23 + onCancel: () => {
  24 + setVisible(false);
  25 + },
  26 + }}
  27 + onFinish={async (values) => {
  28 + console.log(values);
  29 + onClose();
  30 + }}
  31 + onOpenChange={setVisible}
  32 + ></ModalForm>
  33 + </>
  34 + );
  35 +};
... ...
src/pages/Order/OrderWarning/components/CheckModal.tsx 0 → 100644
  1 +import { RESPONSE_CODE } from '@/constants/enum';
  2 +import {
  3 + postPrepaidAudit,
  4 + postServiceOrderAfterSalesCheck,
  5 + postServiceOrderAudit,
  6 + postServiceOrderFileProcess,
  7 + postServiceOrderFinanceCheckOrder,
  8 + postServiceOrderLeaderAudit,
  9 + postServiceOrderToProcureAudit,
  10 +} from '@/services';
  11 +import {
  12 + ModalForm,
  13 + ProFormTextArea,
  14 + ProList,
  15 +} from '@ant-design/pro-components';
  16 +import {
  17 + Button,
  18 + Col,
  19 + Divider,
  20 + Form,
  21 + Image,
  22 + Modal,
  23 + Row,
  24 + Space,
  25 + Tag,
  26 + UploadFile,
  27 + message,
  28 +} from 'antd';
  29 +import Upload, { RcFile, UploadProps } from 'antd/es/upload';
  30 +import { useEffect, useRef, useState } from 'react';
  31 +import {
  32 + AFTE_SALES_PLAN_OPTIONS,
  33 + CHECK_TYPE,
  34 + COMFIR_RECEIPT_IMAGES_NUMBER,
  35 +} from '../../constant';
  36 +// import { cloneDeep } from 'lodash';
  37 +import InvoiceSubOrderInfoTable from '@/pages/Order/Order/components/InvoiceSubOrderInfoTable';
  38 +import { enumValueToLabel, transImageFile } from '@/utils';
  39 +import { PlusOutlined } from '@ant-design/icons';
  40 +import { cloneDeep } from 'lodash';
  41 +
  42 +export default ({
  43 + setCheckVisible,
  44 + data,
  45 + subOrders,
  46 + orderCheckType,
  47 + openOrderDrawer,
  48 + onClose,
  49 +}) => {
  50 + const [previewOpen, setPreviewOpen] = useState(false);
  51 + const [aPopoverTitle, setAPopoverTitle] = useState('审核');
  52 + const [previewImage, setPreviewImage] = useState('');
  53 + const [previewTitle, setPreviewTitle] = useState('');
  54 + const [paymentReceiptsImages, setPymentReceiptsImages] = useState<any[]>([]);
  55 + const fileListObj = useRef<UploadFile[]>([]); //使用引用类型,使得在useEffect里面设置监听事件后,不用更新监听事件也能保持obj与外界一致
  56 + const getBase64 = (file: RcFile): Promise<string> =>
  57 + new Promise((resolve, reject) => {
  58 + const reader = new FileReader();
  59 + reader.readAsDataURL(file);
  60 + reader.onload = () => resolve(reader.result as string);
  61 + reader.onerror = (error) => reject(error);
  62 + });
  63 + const [fileList, setFileList] = useState<UploadFile[]>([]);
  64 + const handleCancel = () => setPreviewOpen(false);
  65 + const [messageApi, contextHolder] = message.useMessage();
  66 + const [form] = Form.useForm<{ name: string; company: string }>();
  67 + let subOrderIds: any[] = subOrders?.map((subOrder) => subOrder.id);
  68 + const [mainOrderId] = useState(data.id);
  69 +
  70 + const [afterSalesInfo, setAfterSalesInfo] = useState<any>();
  71 + const [prepaidProofImages, setPrepaidProofImages] = useState<any[]>([]);
  72 + /**
  73 + * 审核类型
  74 + */
  75 + function checkType(check: string) {
  76 + if (orderCheckType === check) {
  77 + return true;
  78 + }
  79 + return false;
  80 + }
  81 +
  82 + const getOrderAfterSalesInfo = async () => {
  83 + // let res = await postServiceOrderQueryAfterSalesInfoSnapshot({
  84 + // data: { subOrderIds: subOrderIds },
  85 + // });
  86 +
  87 + //附件
  88 + let annex = subOrders[0].afterSalesAnnexList;
  89 + let index = 1;
  90 + let annexLinks = annex?.map((f) => {
  91 + return (
  92 + <Button className="p-0 pr-1" type="link" key="key" href={f}>
  93 + {'附件' + index++}
  94 + </Button>
  95 + );
  96 + });
  97 +
  98 + console.log(annexLinks);
  99 +
  100 + setAfterSalesInfo(
  101 + <div className="my-5">
  102 + <Row gutter={[16, 24]}>
  103 + <Col span={6}>
  104 + <span className="text-[#333333]">售后方案</span>
  105 + </Col>
  106 + <Col span={18}>
  107 + {enumValueToLabel(
  108 + subOrders[0]?.afterSalesPlan,
  109 + AFTE_SALES_PLAN_OPTIONS,
  110 + )}
  111 + </Col>
  112 + <Col span={6}>
  113 + <span className="className='text-[#333333]'">售后原因</span>
  114 + </Col>
  115 + <Col span={18}>{subOrders[0]?.afterSalesNotes}</Col>
  116 + <Col span={6}>
  117 + <span className="className='text-[#333333]'">附件</span>
  118 + </Col>
  119 + <Col span={18}>{annexLinks}</Col>
  120 + </Row>
  121 + </div>,
  122 + );
  123 + };
  124 +
  125 + useEffect(() => {
  126 + if (checkType(CHECK_TYPE.CONFIRM_DELIVER)) {
  127 + setAPopoverTitle('确认发货');
  128 + }
  129 + getOrderAfterSalesInfo();
  130 +
  131 + let paymentReceiptsImagesList: any[] = [];
  132 + subOrders?.forEach((item: any) => {
  133 + if (item.paymentReceiptAnnexList) {
  134 + paymentReceiptsImagesList.push(...item.paymentReceiptAnnexList);
  135 + }
  136 + });
  137 + //去重
  138 + paymentReceiptsImagesList = [...new Set(paymentReceiptsImagesList)];
  139 + setPymentReceiptsImages(paymentReceiptsImagesList);
  140 +
  141 + //预存审核的凭证
  142 + let proofImages: any[] = [];
  143 + subOrders?.forEach((item) => {
  144 + let images = item.proofImages;
  145 + if (images !== null && images !== undefined) {
  146 + proofImages.push(...images);
  147 + }
  148 + });
  149 + setPrepaidProofImages(proofImages);
  150 + }, []);
  151 +
  152 + const handleChange: UploadProps['onChange'] = ({ fileList: newFileList }) => {
  153 + //fileListObj得在change里变化,change的参数是已经处理过的file数组
  154 + //beforeUpload中的参数file是未处理过,还需要Base64拿到文件数据处理
  155 + fileListObj.current = newFileList;
  156 + setFileList(newFileList);
  157 + };
  158 +
  159 + /** 粘贴快捷键的回调 */
  160 + const onPaste = async (e: any) => {
  161 + /** 获取剪切板的数据clipboardData */
  162 + let clipboardData = e.clipboardData,
  163 + i = 0,
  164 + items,
  165 + item,
  166 + types;
  167 +
  168 + /** 为空判断 */
  169 + if (clipboardData) {
  170 + items = clipboardData.items;
  171 + if (!items) {
  172 + message.info('您的剪贴板中没有照片');
  173 + return;
  174 + }
  175 +
  176 + item = items[0];
  177 + types = clipboardData.types || [];
  178 + /** 遍历剪切板的数据 */
  179 + for (; i < types.length; i++) {
  180 + if (types[i] === 'Files') {
  181 + item = items[i];
  182 + break;
  183 + }
  184 + }
  185 +
  186 + /** 判断文件是否为图片 */
  187 + if (item && item.kind === 'file' && item.type.match(/^image\//i)) {
  188 + const imgItem = item.getAsFile();
  189 + const newFileList = cloneDeep(fileListObj.current);
  190 + let filteredArray = newFileList.filter(
  191 + (obj) => obj.status !== 'removed',
  192 + ); //过滤掉状态为已删除的照片
  193 + const listItem = {
  194 + ...imgItem,
  195 + status: 'done',
  196 + url: await getBase64(imgItem),
  197 + originFileObj: imgItem,
  198 + };
  199 +
  200 + if (filteredArray.length >= COMFIR_RECEIPT_IMAGES_NUMBER) {
  201 + message.info('发货照片数量不能超过3');
  202 + return;
  203 + }
  204 + fileListObj.current = filteredArray;
  205 + filteredArray.push(listItem);
  206 + setFileList(filteredArray);
  207 + return;
  208 + }
  209 + }
  210 +
  211 + message.info('您的剪贴板中没有照片');
  212 + };
  213 + useEffect(() => {
  214 + //回显售后信息
  215 + // if (checkType(CHECK_TYPE.AFTER_SALES)) {
  216 + // getOrderAfterSalesInfo();
  217 + // }
  218 +
  219 + document.addEventListener('paste', onPaste);
  220 + return () => {
  221 + document.removeEventListener('paste', onPaste);
  222 + };
  223 + }, []);
  224 + const uploadButton = (
  225 + <div>
  226 + <PlusOutlined />
  227 + <div style={{ marginTop: 8 }}>上传凭证</div>
  228 + </div>
  229 + );
  230 + const handlePreview = async (file: UploadFile) => {
  231 + if (!file.url && !file.preview) {
  232 + file.preview = await getBase64(file.originFileObj as RcFile);
  233 + }
  234 + setPreviewImage(file.url || (file.preview as string));
  235 + setPreviewOpen(true);
  236 + setPreviewTitle(
  237 + file.name ||
  238 + file.originFileObj?.name ||
  239 + file.url!.substring(file.url!.lastIndexOf('/') + 1),
  240 + );
  241 + };
  242 +
  243 + const handleBeforeUpload = (file: any) => {
  244 + setFileList([...fileList, file]);
  245 + return false;
  246 + };
  247 +
  248 + const props: UploadProps = {
  249 + onRemove: (file) => {
  250 + const index = fileList.indexOf(file);
  251 + const newFileList = fileList.slice();
  252 + newFileList.splice(index, 1);
  253 + setFileList(newFileList);
  254 + },
  255 + beforeUpload: handleBeforeUpload,
  256 + listType: 'picture-card',
  257 + onPreview: handlePreview,
  258 + fileList,
  259 + onChange: handleChange,
  260 + accept: 'image/png, image/jpeg, image/png',
  261 + // action: '/api/service/order/fileProcess',
  262 + name: 'files',
  263 + headers: { Authorization: localStorage.getItem('token') },
  264 + };
  265 +
  266 + //仓库审核
  267 + async function doCheck(body: object) {
  268 + const data = await postServiceOrderAudit({
  269 + data: body,
  270 + });
  271 + if (data.result === RESPONSE_CODE.SUCCESS) {
  272 + message.success(data.message);
  273 + onClose();
  274 + }
  275 + }
  276 +
  277 + /**
  278 + *
  279 + * @param body 财务审核
  280 + */
  281 + async function doFinancailCheck(values: any, isAgree: boolean) {
  282 + if (fileList.length <= 0) {
  283 + message.error('凭证不能为空');
  284 + return;
  285 + }
  286 + messageApi.open({
  287 + type: 'loading',
  288 + content: '正在上传图片...',
  289 + duration: 0,
  290 + });
  291 + //附件处理
  292 + let formData = new FormData();
  293 + //附件处理
  294 + for (let file of fileList) {
  295 + if (file.originFileObj) {
  296 + formData.append('files', file.originFileObj as RcFile);
  297 + } else {
  298 + //有url的话取url(源文件),没url取thumbUrl。有url的时候thumbUrl是略缩图
  299 + if (file?.url === undefined || file?.url === null) {
  300 + formData.append(
  301 + 'files',
  302 + transImageFile(file?.thumbUrl),
  303 + file?.originFileObj?.name,
  304 + );
  305 + } else {
  306 + formData.append(
  307 + 'files',
  308 + transImageFile(file?.url),
  309 + file?.originFileObj?.name,
  310 + );
  311 + }
  312 + }
  313 + }
  314 + let res = await postServiceOrderFileProcess({
  315 + data: formData,
  316 + });
  317 + messageApi.destroy();
  318 + if (res.result === RESPONSE_CODE.SUCCESS) {
  319 + message.success('上传成功!');
  320 +
  321 + let fileUrls = res?.data?.map((item) => {
  322 + return { url: item };
  323 + });
  324 + //财务审核
  325 + const data = await postServiceOrderFinanceCheckOrder({
  326 + data: {
  327 + checkNotes: values.name,
  328 + ids: subOrderIds,
  329 + checkPassOrReject: isAgree,
  330 + invoicingCheckAnnex: fileUrls,
  331 + },
  332 + });
  333 + if (data.result === RESPONSE_CODE.SUCCESS) {
  334 + message.success(data.message);
  335 + onClose();
  336 + }
  337 + } else {
  338 + message.success('上传失败');
  339 + }
  340 + }
  341 +
  342 + /**
  343 + *
  344 + * @param body 售后审核
  345 + */
  346 + async function doAfterSalesCheck(body: object) {
  347 + const data = await postServiceOrderAfterSalesCheck({
  348 + data: body,
  349 + });
  350 + if (data.result === RESPONSE_CODE.SUCCESS) {
  351 + message.success(data.message);
  352 + onClose();
  353 + }
  354 + }
  355 +
  356 + /**
  357 + *
  358 + * @param body 领导审核
  359 + */
  360 + async function doLeaderCheck(body: object) {
  361 + const data = await postServiceOrderLeaderAudit({
  362 + data: body,
  363 + });
  364 + if (data.result === RESPONSE_CODE.SUCCESS) {
  365 + message.success(data.message);
  366 + onClose();
  367 + }
  368 + }
  369 +
  370 + /**
  371 + * 预存审核
  372 + * @param body
  373 + */
  374 + async function doPrepaidAudit(body: any) {
  375 + const data = await postPrepaidAudit({
  376 + data: body,
  377 + });
  378 + if (data.result === RESPONSE_CODE.SUCCESS) {
  379 + message.success(data.message);
  380 + onClose();
  381 + }
  382 + }
  383 +
  384 + function computeType() {
  385 + let type: string = '';
  386 + if (checkType(CHECK_TYPE.CONFIRM_DELIVER)) {
  387 + type = 'confirm_deliver';
  388 + }
  389 + if (checkType(CHECK_TYPE.WEARHOUSE_KEEPER)) {
  390 + type = 'warehouse_audit';
  391 + }
  392 + if (checkType(CHECK_TYPE.WAITING_FOR_POST_AUDIT)) {
  393 + type = 'post_audit';
  394 + }
  395 + if (checkType(CHECK_TYPE.NODE_OPERATING_AUDIT)) {
  396 + type = 'node_operating_audit';
  397 + }
  398 + if (checkType(CHECK_TYPE.MODIFY_LEADER_AUDIT)) {
  399 + type = 'modify_leader_audit';
  400 + }
  401 + if (checkType(CHECK_TYPE.URGENT_INVOICE_AUDITING)) {
  402 + type = 'urgent_invoice_audit';
  403 + }
  404 + if (checkType(CHECK_TYPE.PAYMENT_RECEIPTS_AUDIT)) {
  405 + type = 'payment_receipt_audit';
  406 + }
  407 + if (checkType(CHECK_TYPE.CONFIRM_REISSUE)) {
  408 + type = 'confirm_reissue';
  409 + }
  410 + if (checkType(CHECK_TYPE.CREDIT_AUDIT)) {
  411 + type = 'credit_audit';
  412 + }
  413 + if (checkType(CHECK_TYPE.URGENT_INVOICE_AUDITING_OLD)) {
  414 + type = 'urgent_invoice_audit_old';
  415 + }
  416 + if (checkType(CHECK_TYPE.CONFIRM_REISSUE_OLD)) {
  417 + type = 'confirm_reissue_old';
  418 + }
  419 + return type;
  420 + }
  421 +
  422 + return (
  423 + <>
  424 + <ModalForm<{
  425 + name: string;
  426 + company: string;
  427 + }>
  428 + width={500}
  429 + open
  430 + title={aPopoverTitle}
  431 + form={form}
  432 + autoFocusFirstInput
  433 + modalProps={{
  434 + okText: '通过',
  435 + cancelText: '驳回',
  436 + destroyOnClose: true,
  437 + onCancel: () => {
  438 + setCheckVisible(false);
  439 + },
  440 + }}
  441 + submitter={{
  442 + render: (props, defaultDoms) => {
  443 + let myDoms = [];
  444 + if (!checkType(CHECK_TYPE.CONFIRM_DELIVER)) {
  445 + myDoms.push(
  446 + <Button
  447 + key="驳回"
  448 + onClick={async () => {
  449 + if (checkType(CHECK_TYPE.AFTER_SALES)) {
  450 + doAfterSalesCheck({
  451 + applyType: 'after-sales',
  452 + isAfterSalesSuccess: false,
  453 + subOrderIds: subOrderIds,
  454 + mainId: mainOrderId,
  455 + afterSalesRejectionNotes: form.getFieldValue('name'),
  456 + });
  457 + return;
  458 + }
  459 +
  460 + if (checkType(CHECK_TYPE.FINALCIAL)) {
  461 + let values = { name: form.getFieldValue('name') };
  462 + doFinancailCheck(values, false);
  463 + return;
  464 + }
  465 +
  466 + if (checkType(CHECK_TYPE.LEADER_AUDIT)) {
  467 + doLeaderCheck({
  468 + pass: false,
  469 + subOrderIds: subOrderIds,
  470 + reason: form.getFieldValue('name'),
  471 + });
  472 + return;
  473 + }
  474 +
  475 + if (checkType(CHECK_TYPE.MODIFY_APPLY_WAIT_FOR_AUDIT)) {
  476 + doAfterSalesCheck({
  477 + applyType: 'order-change-normal',
  478 + isAfterSalesSuccess: false,
  479 + subOrderIds: subOrderIds,
  480 + mainId: mainOrderId,
  481 + afterSalesRejectionNotes: form.getFieldValue('name'),
  482 + });
  483 + return;
  484 + }
  485 +
  486 + //预存审核,先暂时共用同一个审核弹窗
  487 + if (checkType(CHECK_TYPE.PREPAID_AUDIT)) {
  488 + return doPrepaidAudit({
  489 + pass: false,
  490 + ids: subOrderIds,
  491 + auditNotes: form.getFieldValue('name'),
  492 + });
  493 + }
  494 +
  495 + let type = '';
  496 + type = computeType();
  497 + console.log('type:' + type);
  498 + doCheck({
  499 + pass: false,
  500 + subOrderIds: subOrderIds,
  501 + type: type,
  502 + notes: form.getFieldValue('name'),
  503 + });
  504 + }}
  505 + >
  506 + 驳回
  507 + </Button>,
  508 + );
  509 + }
  510 +
  511 + //如果是仓库审核,那么显示这个外部采购
  512 + if (checkType(CHECK_TYPE.WEARHOUSE_KEEPER)) {
  513 + myDoms.push(
  514 + <Button
  515 + key="外部采购"
  516 + onClick={async () => {
  517 + let res = await postServiceOrderToProcureAudit({
  518 + data: {
  519 + subOrderIds: subOrderIds,
  520 + },
  521 + });
  522 +
  523 + if (res && res.result === RESPONSE_CODE.SUCCESS) {
  524 + message.success(res.message);
  525 + onClose();
  526 + }
  527 + }}
  528 + >
  529 + 外部采购
  530 + </Button>,
  531 + );
  532 + }
  533 +
  534 + //确认
  535 + myDoms.push(defaultDoms[1]);
  536 + return myDoms;
  537 + },
  538 + }}
  539 + submitTimeout={2000}
  540 + onFinish={async (values) => {
  541 + if (checkType(CHECK_TYPE.AFTER_SALES)) {
  542 + //审核通过
  543 + return doAfterSalesCheck({
  544 + applyType: 'after-sales',
  545 + isAfterSalesSuccess: true,
  546 + subOrderIds: subOrderIds,
  547 + mainId: mainOrderId,
  548 + afterSalesRejectionNotes: values.name,
  549 + });
  550 + }
  551 + console.log('h');
  552 + if (checkType(CHECK_TYPE.FINALCIAL)) {
  553 + doFinancailCheck(values, true);
  554 + return;
  555 + }
  556 +
  557 + if (checkType(CHECK_TYPE.LEADER_AUDIT)) {
  558 + doLeaderCheck({
  559 + pass: true,
  560 + subOrderIds: subOrderIds,
  561 + reason: values.name,
  562 + });
  563 + return;
  564 + }
  565 +
  566 + if (checkType(CHECK_TYPE.MODIFY_APPLY_WAIT_FOR_AUDIT)) {
  567 + //审核通过
  568 + return doAfterSalesCheck({
  569 + applyType: 'order-change-normal',
  570 + isAfterSalesSuccess: true,
  571 + subOrderIds: subOrderIds,
  572 + mainId: mainOrderId,
  573 + afterSalesRejectionNotes: values.name,
  574 + });
  575 + }
  576 +
  577 + //预存审核,先暂时共用同一个审核弹窗
  578 + if (checkType(CHECK_TYPE.PREPAID_AUDIT)) {
  579 + return doPrepaidAudit({
  580 + pass: true,
  581 + ids: subOrderIds,
  582 + auditNotes: form.getFieldValue('name'),
  583 + });
  584 + }
  585 +
  586 + let type = '';
  587 + type = computeType();
  588 + doCheck({
  589 + pass: true,
  590 + subOrderIds: subOrderIds,
  591 + type: type,
  592 + notes: form.getFieldValue('name'),
  593 + });
  594 + }}
  595 + onOpenChange={setCheckVisible}
  596 + >
  597 + {checkType(CHECK_TYPE.AFTER_SALES) ? (
  598 + <>
  599 + {afterSalesInfo}
  600 + <Button
  601 + className="px-0"
  602 + type="link"
  603 + onClick={() => {
  604 + console.log(data);
  605 + openOrderDrawer('after-sales-check', mainOrderId);
  606 + }}
  607 + >
  608 + 查看旧订单
  609 + </Button>
  610 + </>
  611 + ) : (
  612 + ''
  613 + )}
  614 +
  615 + {checkType(CHECK_TYPE.PAYMENT_RECEIPTS_AUDIT) ? (
  616 + <>
  617 + <Divider orientation="center">
  618 + <span className="text-sm">回款凭证</span>
  619 + </Divider>
  620 + <Image.PreviewGroup
  621 + className="mr-10"
  622 + preview={{
  623 + onChange: (current, prev) =>
  624 + console.log(`current index: ${current}, prev index: ${prev}`),
  625 + }}
  626 + >
  627 + {paymentReceiptsImages.map((url) => (
  628 + <>
  629 + <Image width={120} src={url} /> <Divider type="vertical" />
  630 + </>
  631 + ))}
  632 + </Image.PreviewGroup>
  633 + <Divider></Divider>
  634 + </>
  635 + ) : (
  636 + ''
  637 + )}
  638 +
  639 + {checkType(CHECK_TYPE.PREPAID_AUDIT) && (
  640 + <>
  641 + <Divider orientation="center">
  642 + <span className="text-sm">凭证</span>
  643 + </Divider>
  644 + <Image.PreviewGroup
  645 + className="mr-10"
  646 + preview={{
  647 + onChange: (current, prev) =>
  648 + console.log(`current index: ${current}, prev index: ${prev}`),
  649 + }}
  650 + >
  651 + {prepaidProofImages.map((url) => (
  652 + <>
  653 + <Image width={120} src={url} /> <Divider type="vertical" />
  654 + </>
  655 + ))}
  656 + </Image.PreviewGroup>
  657 + <Divider></Divider>
  658 + </>
  659 + )}
  660 +
  661 + {checkType('prepaidAudit') ? (
  662 + <div>请特别注意手机号码和充值金额。</div>
  663 + ) : (
  664 + <div>请特别注意订单总金额与订单金额。</div>
  665 + )}
  666 + {!checkType(CHECK_TYPE.CONFIRM_DELIVER) ? (
  667 + <ProFormTextArea
  668 + width="lg"
  669 + name="name"
  670 + placeholder="若驳回,请填写驳回理由"
  671 + />
  672 + ) : (
  673 + <></>
  674 + )}
  675 + {checkType(CHECK_TYPE.FINALCIAL) ? (
  676 + <>
  677 + <div className="pb-4 text-xs decoration-gray-50">
  678 + 可复制照片粘贴
  679 + </div>
  680 + <Upload {...props}>
  681 + {fileList.length < COMFIR_RECEIPT_IMAGES_NUMBER
  682 + ? uploadButton
  683 + : ''}
  684 + </Upload>
  685 + </>
  686 + ) : (
  687 + ''
  688 + )}
  689 + {checkType(CHECK_TYPE.CONFIRM_REISSUE) && (
  690 + <>
  691 + <InvoiceSubOrderInfoTable
  692 + subOrderIds={subOrderIds}
  693 + ></InvoiceSubOrderInfoTable>
  694 + </>
  695 + )}
  696 + {checkType(CHECK_TYPE.URGENT_INVOICE_AUDITING) ? (
  697 + <>
  698 + <ProList
  699 + rowKey="id"
  700 + headerTitle="发票信息"
  701 + metas={{
  702 + title: {
  703 + dataIndex: 'name',
  704 + },
  705 + avatar: {
  706 + dataIndex: 'image',
  707 + editable: false,
  708 + },
  709 + description: {
  710 + dataIndex: 'desc',
  711 + },
  712 + subTitle: {
  713 + render: () => {
  714 + return (
  715 + <Space size={0}>
  716 + <Tag color="blue">Ant Design</Tag>
  717 + <Tag color="#5BD8A6">TechUI</Tag>
  718 + </Space>
  719 + );
  720 + },
  721 + },
  722 + actions: {
  723 + render: (text, row, index, action) => [
  724 + <a
  725 + onClick={() => {
  726 + action?.startEditable(row.id);
  727 + }}
  728 + key="link"
  729 + >
  730 + 编辑
  731 + </a>,
  732 + ],
  733 + },
  734 + }}
  735 + ></ProList>
  736 + </>
  737 + ) : (
  738 + ''
  739 + )}
  740 + </ModalForm>
  741 +
  742 + <Modal
  743 + open={previewOpen}
  744 + title={previewTitle}
  745 + footer={null}
  746 + onCancel={handleCancel}
  747 + >
  748 + <img alt="图片预览" style={{ width: '100%' }} src={previewImage} />
  749 + </Modal>
  750 + {contextHolder}
  751 + </>
  752 + );
  753 +};
... ...
src/pages/Order/OrderWarning/components/ConfirmReceiptModal.tsx 0 → 100644
  1 +import { RESPONSE_CODE } from '@/constants/enum';
  2 +import { postServiceOrderConfirmReceipt } from '@/services';
  3 +import { PlusOutlined } from '@ant-design/icons';
  4 +import { Button, Modal, Upload, message } from 'antd';
  5 +import { RcFile, UploadFile, UploadProps } from 'antd/es/upload';
  6 +import { cloneDeep } from 'lodash';
  7 +import { useEffect, useRef, useState } from 'react';
  8 +import { COMFIR_RECEIPT_IMAGES_NUMBER } from '../../constant';
  9 +export default ({ data, onClose }) => {
  10 + const subIds = data?.map((item) => {
  11 + return item.id;
  12 + });
  13 + // const [form] = Form.useForm<{ name: string; company: string }>();
  14 + const [previewOpen, setPreviewOpen] = useState(false);
  15 + const [previewImage, setPreviewImage] = useState('');
  16 + const [previewTitle, setPreviewTitle] = useState('');
  17 + const fileListObj = useRef<UploadFile[]>([]); //使用引用类型,使得在useEffect里面设置监听事件后,不用更新监听事件也能保持obj与外界一致
  18 + const getBase64 = (file: RcFile): Promise<string> =>
  19 + new Promise((resolve, reject) => {
  20 + const reader = new FileReader();
  21 + reader.readAsDataURL(file);
  22 + reader.onload = () => resolve(reader.result as string);
  23 + reader.onerror = (error) => reject(error);
  24 + });
  25 + const [fileList, setFileList] = useState<UploadFile[]>([]);
  26 + const [uploading, setUploading] = useState(false);
  27 + const handleCancel = () => setPreviewOpen(false);
  28 +
  29 + const handleChange: UploadProps['onChange'] = ({ fileList: newFileList }) => {
  30 + //fileListObj得在change里变化,change的参数是已经处理过的file数组
  31 + //beforeUpload中的参数file是未处理过,还需要Base64拿到文件数据处理
  32 + fileListObj.current = newFileList;
  33 + setFileList(newFileList);
  34 + };
  35 +
  36 + /** 粘贴快捷键的回调 */
  37 + const onPaste = async (e: any) => {
  38 + /** 获取剪切板的数据clipboardData */
  39 + let clipboardData = e.clipboardData,
  40 + i = 0,
  41 + items,
  42 + item,
  43 + types;
  44 +
  45 + /** 为空判断 */
  46 + if (clipboardData) {
  47 + items = clipboardData.items;
  48 + if (!items) {
  49 + message.info('您的剪贴板中没有照片');
  50 + return;
  51 + }
  52 +
  53 + item = items[0];
  54 + types = clipboardData.types || [];
  55 + /** 遍历剪切板的数据 */
  56 + for (; i < types.length; i++) {
  57 + if (types[i] === 'Files') {
  58 + item = items[i];
  59 + break;
  60 + }
  61 + }
  62 +
  63 + /** 判断文件是否为图片 */
  64 + if (item && item.kind === 'file' && item.type.match(/^image\//i)) {
  65 + const imgItem = item.getAsFile();
  66 + const newFileList = cloneDeep(fileListObj.current);
  67 + let filteredArray = newFileList.filter(
  68 + (obj) => obj.status !== 'removed',
  69 + ); //过滤掉状态为已删除的照片
  70 + const listItem = {
  71 + ...imgItem,
  72 + status: 'done',
  73 + url: await getBase64(imgItem),
  74 + originFileObj: imgItem,
  75 + };
  76 +
  77 + if (filteredArray.length >= COMFIR_RECEIPT_IMAGES_NUMBER) {
  78 + message.info('发货凭证照片数量不能超过3');
  79 + return;
  80 + }
  81 + fileListObj.current = filteredArray;
  82 + filteredArray.push(listItem);
  83 + setFileList(filteredArray);
  84 + return;
  85 + }
  86 + }
  87 +
  88 + message.info('您的剪贴板中没有照片');
  89 + };
  90 + useEffect(() => {
  91 + document.addEventListener('paste', onPaste);
  92 + return () => {
  93 + document.removeEventListener('paste', onPaste);
  94 + };
  95 + }, []);
  96 + const uploadButton = (
  97 + <div>
  98 + <PlusOutlined />
  99 + <div style={{ marginTop: 8 }}>上传凭证</div>
  100 + </div>
  101 + );
  102 + const handlePreview = async (file: UploadFile) => {
  103 + if (!file.url && !file.preview) {
  104 + file.preview = await getBase64(file.originFileObj as RcFile);
  105 + }
  106 + setPreviewImage(file.url || (file.preview as string));
  107 + setPreviewOpen(true);
  108 + setPreviewTitle(
  109 + file.name ||
  110 + file.originFileObj?.name ||
  111 + file.url!.substring(file.url!.lastIndexOf('/') + 1),
  112 + );
  113 + };
  114 +
  115 + const handleUpload = async () => {
  116 + const formData = new FormData();
  117 + fileList.forEach((file) => {
  118 + //originFileObj二进制文件
  119 + formData.append('files', file.originFileObj as RcFile);
  120 + });
  121 + // console.log(fileList[0] as RcFile)
  122 + // formData.append('file', fileList[0] as RcFile);
  123 + formData.append('subIds', subIds);
  124 + setUploading(true);
  125 + // You can use any AJAX library you like
  126 + const res = await postServiceOrderConfirmReceipt({
  127 + data: formData,
  128 + headers: {
  129 + 'Content-Type':
  130 + 'multipart/form-data; boundary=----WebKitFormBoundarynl6gT1BKdPWIejNq',
  131 + },
  132 + });
  133 +
  134 + if (res.result === RESPONSE_CODE.SUCCESS) {
  135 + message.success(res.message);
  136 + onClose();
  137 + }
  138 +
  139 + setUploading(false);
  140 + };
  141 +
  142 + const props: UploadProps = {
  143 + onRemove: (file) => {
  144 + const index = fileList.indexOf(file);
  145 + const newFileList = fileList.slice();
  146 + newFileList.splice(index, 1);
  147 + setFileList(newFileList);
  148 + },
  149 + beforeUpload: (file) => {
  150 + setFileList([...fileList, file]);
  151 + return false;
  152 + },
  153 + listType: 'picture-card',
  154 + onPreview: handlePreview,
  155 + fileList,
  156 + onChange: handleChange,
  157 + accept: 'image/png, image/jpeg, image/png',
  158 + };
  159 +
  160 + return (
  161 + <>
  162 + <Modal
  163 + width={500}
  164 + open
  165 + title="确认收货"
  166 + footer={[
  167 + <Button key="cancel" onClick={onClose}>
  168 + 取消
  169 + </Button>,
  170 + <Button
  171 + type="primary"
  172 + key="ok"
  173 + onClick={handleUpload}
  174 + disabled={fileList.length === 0}
  175 + loading={uploading}
  176 + >
  177 + {uploading ? '上传中' : '提交'}
  178 + </Button>,
  179 + ]}
  180 + onCancel={async () => {
  181 + onClose();
  182 + }}
  183 + >
  184 + <div className="pt-4 font-semibold">请将买家确认收货的凭证照片上传</div>
  185 + <div className="pb-4 text-xs decoration-gray-50">可复制照片粘贴</div>
  186 + <Upload {...props}>
  187 + {fileList.length < COMFIR_RECEIPT_IMAGES_NUMBER ? uploadButton : ''}
  188 + </Upload>
  189 + </Modal>
  190 + <Modal
  191 + open={previewOpen}
  192 + title={previewTitle}
  193 + footer={null}
  194 + onCancel={handleCancel}
  195 + >
  196 + <img alt="图片预览" style={{ width: '100%' }} src={previewImage} />
  197 + </Modal>
  198 + </>
  199 + );
  200 +};
... ...
src/pages/Order/OrderWarning/components/DeliverInfoDrawer.tsx 0 → 100644
  1 +import { postDistrictSelOrderProvince } from '@/services';
  2 +import { enumValueToLabel } from '@/utils';
  3 +import { getReceivingCompanyOptions } from '@/utils/order';
  4 +import { Col, Drawer, Row } from 'antd';
  5 +import { useEffect, useState } from 'react';
  6 +import { PAYEE_OPTIONS } from '../../constant';
  7 +
  8 +export default ({ data, onClose }) => {
  9 + const [province, setProvince] = useState('');
  10 + const [city, setCity] = useState('');
  11 + const [district, setDistrict] = useState('');
  12 +
  13 + useEffect(() => {
  14 + const fetchData = async () => {
  15 + if (data.id !== undefined) {
  16 + const resp = await postDistrictSelOrderProvince({
  17 + data: data.id,
  18 + });
  19 + if (resp && resp.data) {
  20 + if (resp.data.province) {
  21 + setProvince(resp.data.province);
  22 + }
  23 + if (resp.data.city) {
  24 + setCity(resp.data.city);
  25 + }
  26 + if (resp.data.district) {
  27 + setDistrict(resp.data.district);
  28 + }
  29 + }
  30 + }
  31 + };
  32 +
  33 + fetchData();
  34 + }, [data.id]);
  35 + return (
  36 + <>
  37 + <Drawer
  38 + width={500}
  39 + title="基本信息"
  40 + placement="right"
  41 + onClose={onClose}
  42 + open
  43 + >
  44 + <Row gutter={[16, 24]}>
  45 + <Col span={6}>
  46 + <span className="text-[#333333]">收货人</span>
  47 + </Col>
  48 + <Col span={18}>{data.customerName}</Col>
  49 + <Col span={6}>
  50 + <span className="className='text-[#333333]'">联系方式</span>
  51 + </Col>
  52 + <Col span={18}>{data.customerContactNumber}</Col>
  53 + <Col span={6}>
  54 + <span className="className='text-[#333333]'">省市区</span>
  55 + </Col>
  56 + <Col span={18}>
  57 + {province}&nbsp;{city}&nbsp;{district}
  58 + </Col>
  59 + <Col span={6}>
  60 + <span className="className='text-[#333333]'">收货地址</span>
  61 + </Col>
  62 + <Col span={18}>{data.customerShippingAddress}</Col>
  63 + <Col span={6}>
  64 + <span className="className='text-[#333333]'">课题组老师</span>
  65 + </Col>
  66 + <Col span={18}>{data.institutionContactName}</Col>
  67 + <Col span={6}>
  68 + <span className="className='text-[#333333]'">单位名称</span>
  69 + </Col>
  70 + <Col span={18}>{data.institution}</Col>
  71 + <Col span={6}>
  72 + <span className="className='text-[#333333]'">开户银行</span>
  73 + </Col>
  74 + <Col span={18}>{data.bank}</Col>
  75 +
  76 + <Col span={6}>
  77 + <span className="className='text-[#333333]'">开票收款单位</span>
  78 + </Col>
  79 + <Col span={18}>
  80 + {enumValueToLabel(
  81 + data.receivingCompany,
  82 + getReceivingCompanyOptions(PAYEE_OPTIONS),
  83 + )}
  84 + </Col>
  85 +
  86 + <Col span={6}>
  87 + <span className="className='text-[#333333]'">银行账号</span>
  88 + </Col>
  89 + <Col span={18}>{data.bankAccountNumber}</Col>
  90 + <Col span={6}>
  91 + <span className="className='text-[#333333]'">开票识别号</span>
  92 + </Col>
  93 + <Col span={18}>{data.invoiceIdentificationNumber}</Col>
  94 + </Row>
  95 + </Drawer>
  96 + </>
  97 + );
  98 +};
... ...
src/pages/Order/OrderWarning/components/DeliverModal.tsx 0 → 100644
  1 +import { RESPONSE_CODE } from '@/constants/enum';
  2 +import {
  3 + postServiceOrderProcureSend,
  4 + postServiceOrderSendProduct,
  5 + postServiceOrderSupplierSendOrder,
  6 +} from '@/services';
  7 +import { enumToSelect } from '@/utils';
  8 +import {
  9 + ProColumns,
  10 + ProForm,
  11 + ProFormSelect,
  12 + ProFormText,
  13 + ProTable,
  14 +} from '@ant-design/pro-components';
  15 +import {
  16 + Button,
  17 + Col,
  18 + Flex,
  19 + Input,
  20 + InputNumber,
  21 + Modal,
  22 + Row,
  23 + Select,
  24 + message,
  25 +} from 'antd';
  26 +import { cloneDeep } from 'lodash';
  27 +import { useEffect, useRef, useState } from 'react';
  28 +import { CHECK_TYPE, LOGISTICS_STATUS_OPTIONS } from '../../constant';
  29 +
  30 +const DeliverModal = ({
  31 + data: propsData,
  32 + isSendProduct,
  33 + setVisible,
  34 + sendType,
  35 + onClose,
  36 +}) => {
  37 + const [data, setData] = useState(propsData || {});
  38 + const form = useRef();
  39 +
  40 + /**
  41 + * 是供应商发货还是普通发货
  42 + * @param typeString
  43 + * @returns
  44 + */
  45 + function optType(typeString: string) {
  46 + if (sendType === typeString) {
  47 + return true;
  48 + }
  49 +
  50 + return false;
  51 + }
  52 +
  53 + useEffect(() => {
  54 + setData(propsData);
  55 + }, [propsData]);
  56 +
  57 + const handleChange = (key: string, index: number, obj: any) => {
  58 + const newData = cloneDeep(data);
  59 + if (typeof obj !== 'object') {
  60 + newData[index][key] = obj;
  61 + } else {
  62 + newData[index][key] = obj.target?.value;
  63 + }
  64 + setData(newData);
  65 + };
  66 + const columns: ProColumns<any>[] = [
  67 + {
  68 + title: 'ID',
  69 + dataIndex: 'id',
  70 + width: 120,
  71 + render: (_, record) => <Input value={record.id} disabled />,
  72 + },
  73 + {
  74 + title: '商品编号',
  75 + dataIndex: 'productCode',
  76 + width: 120,
  77 + render: (_, record) => <Input value={record.productCode} disabled />,
  78 + },
  79 + {
  80 + title: '商品名称',
  81 + dataIndex: 'productName',
  82 + width: 120,
  83 + render: (_, record) => <Input value={record.productName} disabled />,
  84 + },
  85 + {
  86 + title: '商品参数',
  87 + dataIndex: 'parameters',
  88 + width: 80,
  89 + render: (_, record) => <Input value={record.parameters} disabled />,
  90 + },
  91 + {
  92 + title: '商品数量',
  93 + dataIndex: 'status',
  94 + render: (_, record) => <InputNumber value={record.quantity} disabled />,
  95 + },
  96 + {
  97 + title: '包裹数量',
  98 + dataIndex: 'packageNumber',
  99 + render: (_, record, index) => (
  100 + <InputNumber
  101 + min={1}
  102 + value={record.packageNumber}
  103 + defaultValue={1}
  104 + onChange={(value) => handleChange('packageNumber', index, value)}
  105 + />
  106 + ),
  107 + },
  108 + {
  109 + title: '物流方式',
  110 + key: 'logisticsMethod',
  111 + render: (_, record, index) => (
  112 + <Select
  113 + style={{ minWidth: 150 }}
  114 + placeholder="请输入物流方式"
  115 + value={record.logisticsMethod}
  116 + options={enumToSelect(LOGISTICS_STATUS_OPTIONS)}
  117 + onChange={(value) => {
  118 + handleChange('logisticsMethod', index, value); //修改时更改record数据
  119 + if (value === 'OTHER_LOGISTICS') {
  120 + message.info(
  121 + '您选择的是[其他物流方式],请将该物流方式写在备注中',
  122 + );
  123 + }
  124 + }}
  125 + />
  126 + ),
  127 + },
  128 + {
  129 + title: '物流单号',
  130 + key: 'serialNumber',
  131 + render: (_, record, index) => (
  132 + <Input
  133 + placeholder="请输入物流单号"
  134 + value={record.serialNumber}
  135 + onChange={(value) => {
  136 + handleChange('serialNumber', index, value);
  137 + }}
  138 + />
  139 + ),
  140 + },
  141 + {
  142 + title: '物流备注',
  143 + dataIndex: 'packageNumber',
  144 + render: (_, record, index) => (
  145 + <Input.TextArea
  146 + value={record.logisticsNotes}
  147 + onChange={(value) => handleChange('logisticsNotes', index, value)}
  148 + />
  149 + ),
  150 + },
  151 + ];
  152 +
  153 + return (
  154 + <Modal
  155 + open
  156 + width={1000}
  157 + title={isSendProduct ? '发货' : '修改发货信息'}
  158 + onOk={async () => {
  159 + //请求体封装
  160 + let list = data.map((item) => {
  161 + return {
  162 + id: item.id,
  163 + logisticsMethod: item.logisticsMethod,
  164 + serialNumber: item.serialNumber,
  165 + packageNumber:
  166 + item.packageNumber === null || item.packageNumber === undefined
  167 + ? 1
  168 + : item.packageNumber,
  169 + logisticsNotes: item.logisticsNotes,
  170 + };
  171 + });
  172 +
  173 + for (let item of list) {
  174 + let method = item.logisticsMethod;
  175 + let notes = item.logisticsNotes;
  176 + if (
  177 + method === 'OTHER_LOGISTICS' &&
  178 + (notes === '' || notes === undefined)
  179 + ) {
  180 + message.error(
  181 + '请检查:物流方式为[其他物流方式]的记录中,物流备注不能为空!请将实际的物流方式填写在备注中!',
  182 + );
  183 + return;
  184 + }
  185 + }
  186 + let body = { id: data[0].mainOrderId, list: list, flag: false };
  187 + if (isSendProduct) {
  188 + body.flag = true;
  189 + }
  190 + //发货请求
  191 + let res;
  192 + if (optType(CHECK_TYPE.SUPPLIER)) {
  193 + res = await postServiceOrderSupplierSendOrder({ data: body });
  194 + } else if (optType(CHECK_TYPE.PROCURE)) {
  195 + res = await postServiceOrderProcureSend({ data: body });
  196 + } else {
  197 + res = await postServiceOrderSendProduct({ data: body });
  198 + }
  199 +
  200 + if (res.result === RESPONSE_CODE.SUCCESS) {
  201 + message.success(res.message);
  202 + onClose();
  203 + }
  204 + }}
  205 + onCancel={() => {
  206 + setVisible(false);
  207 + }}
  208 + footer={[
  209 + <Button
  210 + key="back"
  211 + onClick={() => {
  212 + setVisible(false);
  213 + }}
  214 + >
  215 + 取消
  216 + </Button>,
  217 + <Button
  218 + key="selfDeliver"
  219 + type="primary"
  220 + onClick={async () => {
  221 + //请求体封装
  222 + let list = data.map((item) => {
  223 + return {
  224 + id: item.id,
  225 + deliverType: 'SELF_DELIVER',
  226 + };
  227 + });
  228 +
  229 + let body = { id: data[0].mainOrderId, list: list, flag: false };
  230 + if (isSendProduct) {
  231 + body.flag = true;
  232 + }
  233 + //发货请求
  234 + let res;
  235 + if (optType(CHECK_TYPE.SUPPLIER)) {
  236 + res = await postServiceOrderSupplierSendOrder({ data: body });
  237 + } else if (optType(CHECK_TYPE.PROCURE)) {
  238 + res = await postServiceOrderProcureSend({ data: body });
  239 + } else {
  240 + res = await postServiceOrderSendProduct({ data: body });
  241 + }
  242 +
  243 + if (res.result === RESPONSE_CODE.SUCCESS) {
  244 + message.success(res.message);
  245 + onClose();
  246 + }
  247 + }}
  248 + >
  249 + 自行派送
  250 + </Button>,
  251 + <Button
  252 + key="submit"
  253 + type="primary"
  254 + onClick={async () => {
  255 + //请求体封装
  256 + let list = data.map((item) => {
  257 + return {
  258 + id: item.id,
  259 + logisticsMethod: item.logisticsMethod,
  260 + serialNumber: item.serialNumber,
  261 + packageNumber:
  262 + item.packageNumber === null ||
  263 + item.packageNumber === undefined
  264 + ? 1
  265 + : item.packageNumber,
  266 + logisticsNotes: item.logisticsNotes,
  267 + };
  268 + });
  269 +
  270 + for (let item of list) {
  271 + let method = item.logisticsMethod;
  272 + let notes = item.logisticsNotes;
  273 + if (
  274 + method === 'OTHER_LOGISTICS' &&
  275 + (notes === '' || notes === undefined)
  276 + ) {
  277 + message.error(
  278 + '请检查:物流方式为[其他物流方式]的记录中,物流备注不能为空!请将实际的物流方式填写在备注中!',
  279 + );
  280 + return;
  281 + }
  282 + }
  283 + let body = { id: data[0].mainOrderId, list: list, flag: false };
  284 + if (isSendProduct) {
  285 + body.flag = true;
  286 + }
  287 + //发货请求
  288 + let res;
  289 + if (optType(CHECK_TYPE.SUPPLIER)) {
  290 + res = await postServiceOrderSupplierSendOrder({ data: body });
  291 + } else if (optType(CHECK_TYPE.PROCURE)) {
  292 + res = await postServiceOrderProcureSend({ data: body });
  293 + } else {
  294 + res = await postServiceOrderSendProduct({ data: body });
  295 + }
  296 +
  297 + if (res.result === RESPONSE_CODE.SUCCESS) {
  298 + message.success(res.message);
  299 + onClose();
  300 + }
  301 + }}
  302 + >
  303 + 确认
  304 + </Button>,
  305 + ]}
  306 + >
  307 + <Flex vertical>
  308 + <strong>将物流方式和物流单号更新到下方所有订单</strong>
  309 + <span className="text-[red] py-1">
  310 + 选择【其他物流方式】时,需要将对应的物流方式填写在备注中。例如:如果发圆通快递,系统上没有这个选项,就需要选【其他物流方式】,然后把“圆通快递”填在备注上。
  311 + </span>
  312 + </Flex>
  313 +
  314 + <ProForm
  315 + layout="inline"
  316 + submitter={false}
  317 + className="mb-8"
  318 + formRef={form}
  319 + >
  320 + <Row gutter={[0, 6]}>
  321 + <Col>
  322 + <ProFormSelect
  323 + placeholder="请输入物流方式"
  324 + name="logisticsMethod"
  325 + width="sm"
  326 + label="物流方式"
  327 + options={enumToSelect(LOGISTICS_STATUS_OPTIONS)}
  328 + />
  329 + <ProFormText name="logisticsNotes" label="物流备注"></ProFormText>
  330 + </Col>
  331 + <Col>
  332 + <ProFormText name="serialNumber" label="物流单号"></ProFormText>
  333 + </Col>
  334 + </Row>
  335 +
  336 + <Button
  337 + type="primary"
  338 + onClick={() => {
  339 + const values = form.current.getFieldsValue();
  340 + if (values.logisticsMethod === 'OTHER_LOGISTICS') {
  341 + message.info(
  342 + '自动填充成功!您选择的是其他物流方式,请将物流方式写在物流备注中!',
  343 + );
  344 + }
  345 + let newData = cloneDeep(data);
  346 + newData = newData.map((item) => ({
  347 + ...item,
  348 + logisticsMethod: values.logisticsMethod,
  349 + serialNumber: values.serialNumber,
  350 + logisticsNotes: values.logisticsNotes,
  351 + }));
  352 + setData(newData);
  353 + }}
  354 + >
  355 + 批量更新
  356 + </Button>
  357 + </ProForm>
  358 + <ProTable<any>
  359 + className="px-0"
  360 + dataSource={data}
  361 + rowKey="id"
  362 + pagination={false}
  363 + columns={columns}
  364 + search={false}
  365 + dateFormatter="string"
  366 + options={false}
  367 + scroll={{ x: 1400 }}
  368 + />
  369 + </Modal>
  370 + );
  371 +};
  372 +
  373 +export default DeliverModal;
... ...
src/pages/Order/OrderWarning/components/FinancialDrawer.tsx 0 → 100644
  1 +import { RESPONSE_CODE } from '@/constants/enum';
  2 +import {
  3 + postServiceOrderEditOrder,
  4 + postServiceOrderInvoicing,
  5 +} from '@/services';
  6 +import { FloatAdd, enumToSelect, enumValueToLabel } from '@/utils';
  7 +import { getReceivingCompanyOptions } from '@/utils/order';
  8 +import {
  9 + DrawerForm,
  10 + ProFormDatePicker,
  11 + ProFormDigit,
  12 + ProFormSelect,
  13 + ProFormText,
  14 + ProFormTextArea,
  15 +} from '@ant-design/pro-components';
  16 +import { Button, Form, message } from 'antd';
  17 +import { useEffect, useState } from 'react';
  18 +import { INVOCING_STATUS_OPTIONS_OLD, PAYEE_OPTIONS } from '../../constant';
  19 +
  20 +export default ({
  21 + mainOrder,
  22 + subOrders,
  23 + isEdit,
  24 + isMainOrder,
  25 + cancel,
  26 + onClose,
  27 +}) => {
  28 + const [invoicingStatus, setInvoicingStatus] = useState('');
  29 + const subIds = subOrders.map((item) => item.id);
  30 + useEffect(() => {
  31 + // 在组件挂载或数据变化时,更新组件状态
  32 + if (mainOrder) {
  33 + setInvoicingStatus(subOrders[0]?.invoicingStatus);
  34 + }
  35 + }, [mainOrder]);
  36 + useEffect(() => {
  37 + console.log(JSON.stringify(subOrders));
  38 + }, []);
  39 +
  40 + const [form] = Form.useForm<{ name: string; company: string }>();
  41 +
  42 + /**
  43 + * 自动选择收款公司
  44 + * @param receivingCompany
  45 + */
  46 + function chooseReceivingCompany(receivingCompany: any) {
  47 + form.setFieldValue('payee', receivingCompany);
  48 + }
  49 +
  50 + /**
  51 + * 计算选中子订单的主订单金额之和
  52 + */
  53 + function computeTotalPayment() {
  54 + let distinctMap = new Map();
  55 +
  56 + subOrders?.forEach((item: any) => {
  57 + distinctMap.set(item.mainOrderId, item.totalPayment);
  58 + });
  59 +
  60 + let sum = 0;
  61 + for (let p of distinctMap.values()) {
  62 + sum = FloatAdd(p, sum);
  63 + }
  64 +
  65 + form.setFieldValue('money', sum);
  66 + }
  67 +
  68 + return (
  69 + <DrawerForm<{
  70 + name: string;
  71 + company: string;
  72 + }>
  73 + open
  74 + title="财务信息"
  75 + resize={{
  76 + onResize() {
  77 + console.log('resize!');
  78 + },
  79 + maxWidth: window.innerWidth * 0.8,
  80 + minWidth: 400,
  81 + }}
  82 + initialValues={mainOrder}
  83 + form={form}
  84 + autoFocusFirstInput
  85 + drawerProps={{
  86 + destroyOnClose: true,
  87 + }}
  88 + submitTimeout={2000}
  89 + onFinish={async (values) => {
  90 + let res;
  91 + let body = values;
  92 + body.subIds = subIds;
  93 + if (isEdit) {
  94 + res = await postServiceOrderEditOrder({ data: body });
  95 + } else {
  96 + res = await postServiceOrderInvoicing({ data: body });
  97 + }
  98 + if (res.result === RESPONSE_CODE.SUCCESS) {
  99 + message.success(res.message);
  100 + onClose();
  101 + }
  102 + }}
  103 + onOpenChange={(val) => {
  104 + return !val && cancel();
  105 + }}
  106 + >
  107 + {isMainOrder ? (
  108 + <ProFormSelect
  109 + placeholder="选择是否需要开票"
  110 + name="invoicingStatus"
  111 + width="lg"
  112 + label="是否需要开票"
  113 + options={enumToSelect(INVOCING_STATUS_OPTIONS_OLD)}
  114 + onChange={setInvoicingStatus}
  115 + initialValue={subOrders[0]?.invoicingStatus}
  116 + // disabled={mainInfoDisbled}
  117 + rules={[{ required: true, message: '是否需要开票必填' }]}
  118 + />
  119 + ) : (
  120 + ''
  121 + )}
  122 +
  123 + <ProFormTextArea
  124 + width="lg"
  125 + name="invoiceIdentificationNumber"
  126 + label="开票信息"
  127 + placeholder="请输入开票信息"
  128 + disabled
  129 + />
  130 + <ProFormText
  131 + width="lg"
  132 + name="bank"
  133 + label="开户银行"
  134 + placeholder="请输入开户银行"
  135 + disabled
  136 + />
  137 + <ProFormText
  138 + width="lg"
  139 + name="bankAccountNumber"
  140 + label="开户银行账号"
  141 + placeholder="请输入开户银行账号"
  142 + disabled
  143 + />
  144 +
  145 + {invoicingStatus !== 'UN_INVOICE'
  146 + ? [
  147 + <ProFormDatePicker
  148 + key="invoicingTime"
  149 + width="lg"
  150 + name="invoicingTime"
  151 + label="开票时间"
  152 + disabled={isEdit}
  153 + rules={[
  154 + { required: !isEdit ? true : false, message: '这是必填项' },
  155 + ]}
  156 + initialValue={subOrders[0]?.invoicingTime}
  157 + />,
  158 + <ProFormText
  159 + key="purchaser"
  160 + width="lg"
  161 + name="purchaser"
  162 + label="抬头名称"
  163 + disabled={isEdit}
  164 + rules={[
  165 + { required: !isEdit ? true : false, message: '这是必填项' },
  166 + ]}
  167 + initialValue={subOrders[0]?.purchaser}
  168 + />,
  169 + <ProFormDatePicker
  170 + key="financialReceiptIssuanceTime"
  171 + width="lg"
  172 + name="financialReceiptIssuanceTime"
  173 + label="开收据时间"
  174 + initialValue={subOrders[0]?.financialReceiptIssuanceTime}
  175 + />,
  176 + <ProFormDatePicker
  177 + key="collectMoneyTime"
  178 + width="lg"
  179 + name="collectMoneyTime"
  180 + label="收款时间"
  181 + initialValue={subOrders[0]?.collectMoneyTime}
  182 + />,
  183 + <ProFormText
  184 + width="lg"
  185 + key="invoiceNumber"
  186 + name="invoiceNumber"
  187 + label="发票号码"
  188 + initialValue={subOrders[0]?.invoiceNumber}
  189 + rules={[{ required: true, message: '发票号码必填' }]}
  190 + />,
  191 + <div
  192 + key="salesChooseReceivingCompany"
  193 + hidden={subOrders[0].receivingCompany === null}
  194 + >
  195 + <span className={'pl-2 text-xs text-gray-400'}>
  196 + 销售申请开票时选择了:
  197 + {enumValueToLabel(
  198 + subOrders[0].receivingCompany,
  199 + getReceivingCompanyOptions(PAYEE_OPTIONS),
  200 + )}
  201 + </span>
  202 + <span
  203 + hidden={subOrders[0].receivingCompany === 'ANY'}
  204 + className={
  205 + 'pl-2 text-xs text-[#1677ff] cursor-pointer hover:text-[#64abf7]'
  206 + }
  207 + onClick={() => {
  208 + chooseReceivingCompany(subOrders[0].receivingCompany);
  209 + }}
  210 + >
  211 + 选择
  212 + </span>
  213 + </div>,
  214 + <ProFormSelect
  215 + key="payee"
  216 + placeholder="选择收款单位"
  217 + name="payee"
  218 + width="lg"
  219 + showSearch
  220 + label="收款单位"
  221 + options={enumToSelect(PAYEE_OPTIONS)}
  222 + initialValue={subOrders[0]?.payee}
  223 + rules={[{ required: true, message: '收款单位必填' }]}
  224 + />,
  225 +
  226 + <div id="total-payment" key="money">
  227 + <ProFormDigit
  228 + key="money"
  229 + name="money"
  230 + width="lg"
  231 + label="金额"
  232 + rules={[{ required: true, message: '金额必填' }]}
  233 + tooltip="点击计算,合计所有子订单对应主订单总额"
  234 + fieldProps={{
  235 + addonAfter: (
  236 + <Button
  237 + className="rounded-l-none"
  238 + type="primary"
  239 + onClick={computeTotalPayment}
  240 + >
  241 + 计算
  242 + </Button>
  243 + ),
  244 + }}
  245 + />
  246 + </div>,
  247 + ]
  248 + : ''}
  249 +
  250 + <ProFormSelect
  251 + placeholder="是否完全开票"
  252 + name="afterInvoicingStatus"
  253 + width="lg"
  254 + label="是否完全开票"
  255 + options={[
  256 + { label: '完全开票', value: 'COMPLETE_INVOICING' },
  257 + { label: '部分开票', value: 'PARTIAL_INVOICING' },
  258 + ]}
  259 + // disabled={mainInfoDisbled}
  260 + initialValue={
  261 + subOrders[0]?.afterInvoicingStatus === 'APPLY_FOR_INVOICING'
  262 + ? 'COMPLETE_INVOICING'
  263 + : subOrders[0]?.afterInvoicingStatus
  264 + }
  265 + rules={[{ required: true, message: '是否完全开票必填' }]}
  266 + />
  267 + <ProFormTextArea
  268 + width="lg"
  269 + name="invoicingNotes"
  270 + label="备注"
  271 + initialValue={subOrders[0]?.invoicingNotes}
  272 + />
  273 + </DrawerForm>
  274 + );
  275 +};
... ...
src/pages/Order/OrderWarning/components/FinancialEditDrawer.tsx 0 → 100644
  1 +import { RESPONSE_CODE } from '@/constants/enum';
  2 +import { postServiceOrderNoNeedInvoicingEdit } from '@/services';
  3 +import { enumToSelect } from '@/utils';
  4 +import {
  5 + DrawerForm,
  6 + ProFormDatePicker,
  7 + ProFormSelect,
  8 + ProFormText,
  9 +} from '@ant-design/pro-components';
  10 +import { Form, message } from 'antd';
  11 +import { useEffect, useState } from 'react';
  12 +import { INVOCING_STATUS_OPTIONS_OLD } from '../../constant';
  13 +
  14 +export default ({ mainOrder, subOrders, setVisible, isMainOrder, onClose }) => {
  15 + const [invoicingStatus, setInvoicingStatus] = useState('');
  16 + useEffect(() => {
  17 + setInvoicingStatus(subOrders[0]?.invoicingStatus);
  18 + }, []);
  19 + const subOrderIds = subOrders?.map((subOrder) => {
  20 + return subOrder?.id;
  21 + });
  22 + const mainOrderId = mainOrder.id;
  23 + const [form] = Form.useForm<{
  24 + collectMoneyTime: string;
  25 + subIds: [];
  26 + financialReceiptIssuanceTime: string;
  27 + }>();
  28 +
  29 + //回显开收据时间和收款时间
  30 + if (!isMainOrder) {
  31 + form.setFieldValue('collectMoneyTime', subOrders[0].collectMoneyTime);
  32 + form.setFieldValue(
  33 + 'financialReceiptIssuanceTime',
  34 + subOrders[0].financialReceiptIssuanceTime,
  35 + );
  36 + }
  37 +
  38 + return (
  39 + <DrawerForm<{
  40 + collectMoneyTime: string;
  41 + financialReceiptIssuanceTime: string;
  42 + subIds: [];
  43 + }>
  44 + open
  45 + title={isMainOrder ? '编辑开票信息' : '编辑收款时间'}
  46 + resize={{
  47 + onResize() {
  48 + console.log('resize!');
  49 + },
  50 + maxWidth: window.innerWidth * 0.8,
  51 + minWidth: 400,
  52 + }}
  53 + initialValues={mainOrder}
  54 + form={form}
  55 + autoFocusFirstInput
  56 + drawerProps={{
  57 + destroyOnClose: true,
  58 + }}
  59 + submitTimeout={2000}
  60 + onFinish={async (values) => {
  61 + let body = {
  62 + ...values,
  63 + mainOrderId: mainOrderId,
  64 + subIds: subOrderIds,
  65 + };
  66 +
  67 + if (!isMainOrder) {
  68 + body.invoicingStatus = 'UN_INVOICE';
  69 + }
  70 +
  71 + let res = await postServiceOrderNoNeedInvoicingEdit({
  72 + data: body,
  73 + });
  74 + if (res.result === RESPONSE_CODE.SUCCESS) {
  75 + message.success(res.message);
  76 + onClose();
  77 + }
  78 + }}
  79 + onOpenChange={(val) => {
  80 + return !val && setVisible(val);
  81 + }}
  82 + >
  83 + {isMainOrder ? (
  84 + <ProFormSelect
  85 + placeholder="选择是否需要开票"
  86 + name="invoicingStatus"
  87 + width="lg"
  88 + label="是否需要开票"
  89 + options={enumToSelect(INVOCING_STATUS_OPTIONS_OLD)}
  90 + onChange={setInvoicingStatus}
  91 + initialValue={subOrders[0]?.invoicingStatus}
  92 + // disabled={mainInfoDisbled}
  93 + rules={[{ required: true, message: '是否需要开票必填' }]}
  94 + />
  95 + ) : (
  96 + ''
  97 + )}
  98 +
  99 + {invoicingStatus !== 'UN_INVOICE' ? (
  100 + <>
  101 + <ProFormText
  102 + key="invoiceIdentificationNumber"
  103 + width="lg"
  104 + name="invoiceIdentificationNumber"
  105 + label="开票信息"
  106 + placeholder="请输入开票信息"
  107 + rules={[{ required: true, message: '开票信息必填' }]}
  108 + />
  109 + <ProFormText
  110 + key="bank"
  111 + width="lg"
  112 + name="bank"
  113 + label="开户银行"
  114 + placeholder="请输入开户银行"
  115 + />
  116 + <ProFormText
  117 + key="bankAccountNumber"
  118 + width="lg"
  119 + name="bankAccountNumber"
  120 + label="开户银行账号"
  121 + placeholder="请输入开户银行账号"
  122 + />
  123 + </>
  124 + ) : (
  125 + ''
  126 + )}
  127 +
  128 + <ProFormDatePicker
  129 + key="financialReceiptIssuanceTime"
  130 + width="lg"
  131 + name="financialReceiptIssuanceTime"
  132 + label="开收据时间"
  133 + // rules={[
  134 + // {
  135 + // required: !isMainOrder && invoicingStatus === 'UN_INVOICE',
  136 + // message: '开收据时间必填',
  137 + // },
  138 + // ]}
  139 + />
  140 + <ProFormDatePicker
  141 + key="collectMoneyTime"
  142 + width="lg"
  143 + name="collectMoneyTime"
  144 + label="收款时间"
  145 + // rules={[
  146 + // {
  147 + // required: !isMainOrder && invoicingStatus === 'UN_INVOICE',
  148 + // message: '收款时间必填',
  149 + // },
  150 + // ]}
  151 + />
  152 + </DrawerForm>
  153 + );
  154 +};
... ...
src/pages/Order/OrderWarning/components/FinancialMergeDrawer.tsx 0 → 100644
  1 +import { RESPONSE_CODE } from '@/constants/enum';
  2 +import { enumToSelect } from '@/utils';
  3 +import {
  4 + DrawerForm,
  5 + ProFormDatePicker,
  6 + ProFormDigit,
  7 + ProFormSelect,
  8 + ProFormText,
  9 + ProFormTextArea,
  10 +} from '@ant-design/pro-components';
  11 +import { Form, message } from 'antd';
  12 +import { PAYEE_OPTIONS } from '../../constant';
  13 +
  14 +export default ({ dataList, setVisible, onClose }) => {
  15 + // let subOrderIds = dataList?.map((item) => {
  16 + // return item.id;
  17 + // });
  18 + let firstMainOrder = dataList[0];
  19 + let bank = firstMainOrder?.bank;
  20 + let bankAccountNumber = firstMainOrder?.bankAccountNumber;
  21 + let invoiceIdentificationNumber = firstMainOrder?.invoiceIdentificationNumber;
  22 +
  23 + const [form] = Form.useForm<{
  24 + invoicingTime: string;
  25 + financialReceiptIssuanceTime: string;
  26 + invoicingNotes: string;
  27 + afterInvoicingStatus: string;
  28 + collectMoneyTime: string;
  29 + }>();
  30 + return (
  31 + <DrawerForm
  32 + open
  33 + title="合并开票"
  34 + resize={{
  35 + onResize() {
  36 + console.log('resize!');
  37 + },
  38 + maxWidth: window.innerWidth * 0.8,
  39 + minWidth: 400,
  40 + }}
  41 + form={form}
  42 + autoFocusFirstInput
  43 + drawerProps={{
  44 + destroyOnClose: true,
  45 + }}
  46 + submitTimeout={2000}
  47 + onFinish={async (values) => {
  48 + console.log(values);
  49 + let res;
  50 + let body = values;
  51 + body.subIds = subIds;
  52 + body.mainOrderId = mainOrder.id;
  53 + body.mainorderOrSubOrderInvoicing = isMainOrder;
  54 + if (isEdit) {
  55 + res = await postServiceOrderEditOrder({ data: body });
  56 + } else {
  57 + res = await postServiceOrderInvoicing({ data: body });
  58 + }
  59 + if (res.result === RESPONSE_CODE.SUCCESS) {
  60 + message.success(res.message);
  61 + onClose();
  62 + }
  63 + }}
  64 + onOpenChange={(val) => {
  65 + return !val && setVisible();
  66 + }}
  67 + >
  68 + <ProFormText
  69 + width="lg"
  70 + name="invoiceIdentificationNumber"
  71 + label="开票信息"
  72 + placeholder="请输入开票信息"
  73 + initialValue={invoiceIdentificationNumber}
  74 + disabled
  75 + />
  76 + <ProFormText
  77 + width="lg"
  78 + name="bank"
  79 + label="开户银行"
  80 + placeholder="请输入开户银行"
  81 + initialValue={bank}
  82 + disabled
  83 + />
  84 + <ProFormText
  85 + width="lg"
  86 + name="bankAccountNumber"
  87 + label="开户银行账号"
  88 + placeholder="请输入开户银行账号"
  89 + initialValue={bankAccountNumber}
  90 + disabled
  91 + />
  92 +
  93 + <ProFormDatePicker
  94 + key="invoicingTime"
  95 + width="lg"
  96 + name="invoicingTime"
  97 + label="开票时间"
  98 + rules={[{ required: true, message: '这是必填项' }]}
  99 + />
  100 + <ProFormDatePicker
  101 + key="financialReceiptIssuanceTime"
  102 + width="lg"
  103 + name="financialReceiptIssuanceTime"
  104 + label="开收据时间"
  105 + />
  106 + <ProFormDatePicker
  107 + key="collectMoneyTime"
  108 + width="lg"
  109 + name="collectMoneyTime"
  110 + label="收款时间"
  111 + />
  112 + <ProFormText
  113 + width="lg"
  114 + key="invoiceNumber"
  115 + name="invoiceNumber"
  116 + label="发票号码"
  117 + rules={[{ required: true, message: '发票号码必填' }]}
  118 + />
  119 + <ProFormSelect
  120 + key="payee"
  121 + placeholder="选择收款单位"
  122 + name="payee"
  123 + width="lg"
  124 + label="收款单位"
  125 + options={enumToSelect(PAYEE_OPTIONS)}
  126 + rules={[{ required: true, message: '收款单位必填' }]}
  127 + />
  128 +
  129 + <ProFormDigit
  130 + key="money"
  131 + name="money"
  132 + width="lg"
  133 + label="金额"
  134 + rules={[{ required: true, message: '金额必填' }]}
  135 + />
  136 + <ProFormSelect
  137 + placeholder="是否完全开票"
  138 + name="afterInvoicingStatus"
  139 + width="lg"
  140 + label="是否完全开票"
  141 + options={[
  142 + { label: '完全开票', value: 'COMPLETE_INVOICING' },
  143 + { label: '部分开票', value: 'PARTIAL_INVOICING' },
  144 + ]}
  145 + initialValue={'COMPLETE_INVOICING'}
  146 + />
  147 + <ProFormTextArea width="lg" name="invoicingNotes" label="备注" />
  148 + </DrawerForm>
  149 + );
  150 +};
... ...
src/pages/Order/OrderWarning/components/FinancialReceiptsModal.tsx 0 → 100644
  1 +import { postServiceOrderUpdateHirePurchase } from '@/services';
  2 +import {
  3 + EditableProTable,
  4 + ModalForm,
  5 + ProColumns,
  6 + ProForm,
  7 +} from '@ant-design/pro-components';
  8 +import { Form } from 'antd';
  9 +import { useState } from 'react';
  10 +
  11 +// import { cloneDeep } from 'lodash';
  12 +export default ({ setVisible, datas, onClose }) => {
  13 + const [form] = Form.useForm<{ name: string; company: string }>();
  14 + type DataSourceType = {
  15 + id: React.Key;
  16 + hirePurchaseMethod?: string;
  17 + hirePurchaseMethodName?: string;
  18 + money?: number;
  19 + updateTime?: string;
  20 + notes?: string;
  21 + };
  22 + const defaultData: DataSourceType[] = [
  23 + {
  24 + id: 1,
  25 + hirePurchaseMethod: 'ADVANCE_CHARGE',
  26 + hirePurchaseMethodName: '预付款',
  27 + money: undefined,
  28 + updateTime: undefined,
  29 + notes: undefined,
  30 + },
  31 + {
  32 + id: 2,
  33 + hirePurchaseMethod: 'PAYMENT_FOR_SHIPMENT',
  34 + hirePurchaseMethodName: '发货款',
  35 + money: undefined,
  36 + updateTime: undefined,
  37 + notes: undefined,
  38 + },
  39 + {
  40 + id: 3,
  41 + hirePurchaseMethod: 'ACCEPTANCE_PAYMENT',
  42 + hirePurchaseMethodName: '验收款',
  43 + money: undefined,
  44 + updateTime: undefined,
  45 + notes: undefined,
  46 + },
  47 + {
  48 + id: 4,
  49 + hirePurchaseMethod: 'BALANCE_PAYMENT',
  50 + hirePurchaseMethodName: '尾款',
  51 + money: undefined,
  52 + updateTime: undefined,
  53 + notes: undefined,
  54 + },
  55 + ];
  56 + const [editableKeys, setEditableRowKeys] = useState<React.Key[]>(() =>
  57 + // defaultData.map((item) => item.id),
  58 + [1, 2, 3, 4],
  59 + );
  60 + const columns: ProColumns<DataSourceType>[] = [
  61 + {
  62 + title: '款项',
  63 + dataIndex: 'hirePurchaseMethodName',
  64 + editable: false,
  65 + width: '10%',
  66 + },
  67 + {
  68 + title: '已收金额',
  69 + dataIndex: 'money',
  70 + valueType: 'digit',
  71 + width: '15%',
  72 + },
  73 + {
  74 + title: '收款时间',
  75 + dataIndex: 'updateTime',
  76 + valueType: 'dateTime',
  77 + width: '25%',
  78 + },
  79 + {
  80 + title: '备注',
  81 + dataIndex: 'receiptsNotes',
  82 + },
  83 + ];
  84 + return (
  85 + <>
  86 + <ModalForm<{
  87 + name: string;
  88 + company: string;
  89 + }>
  90 + width={1100}
  91 + open
  92 + title="收款记录"
  93 + form={form}
  94 + autoFocusFirstInput
  95 + modalProps={{
  96 + okText: '保存',
  97 + cancelText: '取消',
  98 + destroyOnClose: true,
  99 + onCancel: () => {
  100 + setVisible(false);
  101 + },
  102 + }}
  103 + onFinish={async (values) => {
  104 + let res = await postServiceOrderUpdateHirePurchase({
  105 + data: {
  106 + mainOrderId: datas[0].id,
  107 + list: values.dataSource,
  108 + },
  109 + });
  110 + console.log(res);
  111 + onClose();
  112 + }}
  113 + onOpenChange={setVisible}
  114 + >
  115 + <ProForm.Item
  116 + label=""
  117 + name="dataSource"
  118 + initialValue={defaultData}
  119 + trigger="onValuesChange"
  120 + >
  121 + <EditableProTable<DataSourceType>
  122 + rowKey="id"
  123 + toolBarRender={false}
  124 + columns={columns}
  125 + recordCreatorProps={{
  126 + newRecordType: 'dataSource',
  127 + position: 'top',
  128 + record: () => ({
  129 + id: Date.now(),
  130 + addonBefore: 'ccccccc',
  131 + decs: 'testdesc',
  132 + }),
  133 + style: {
  134 + display: 'none',
  135 + },
  136 + }}
  137 + editable={{
  138 + type: 'multiple',
  139 + editableKeys,
  140 + onChange: setEditableRowKeys,
  141 + actionRender: (row, _, dom) => {
  142 + return [dom.delete];
  143 + },
  144 + }}
  145 + />
  146 + </ProForm.Item>
  147 +
  148 + {/* <ProForm.Group>
  149 + <ProFormText
  150 + width="sm"
  151 + name="name1"
  152 + label="款项"
  153 + tooltip="最长为 24 位"
  154 + initialValue={"预付款"}
  155 + disabled
  156 + placeholder="请输入名称"
  157 + />
  158 +
  159 + <ProFormText
  160 + width="sm"
  161 + name="company"
  162 + label="收款时间"
  163 + placeholder="请输入名称"
  164 + />
  165 +
  166 + <ProFormText
  167 + width="sm"
  168 + name="price"
  169 + label="收款金额"
  170 + placeholder="请输入名称"
  171 + />
  172 +
  173 + <ProFormText
  174 + width="sm"
  175 + name="notes"
  176 + label="备注"
  177 + placeholder="请输入名称"
  178 + />
  179 + </ProForm.Group>
  180 +
  181 + <ProForm.Group>
  182 + <ProFormText
  183 + width="sm"
  184 + name="name2"
  185 + initialValue={"发货款"}
  186 + disabled
  187 + tooltip="最长为 24 位"
  188 + placeholder="请输入名称"
  189 + />
  190 +
  191 + <ProFormText
  192 + width="sm"
  193 + name="company"
  194 + placeholder="请输入名称"
  195 + />
  196 +
  197 + <ProFormText
  198 + width="sm"
  199 + name="price"
  200 + placeholder="请输入名称"
  201 + />
  202 +
  203 + <ProFormText
  204 + width="sm"
  205 + name="notes"
  206 + placeholder="请输入名称"
  207 + />
  208 + </ProForm.Group>
  209 +
  210 + <ProForm.Group>
  211 + <ProFormText
  212 + width="sm"
  213 + name="name3"
  214 + initialValue={"验收款"}
  215 + disabled
  216 + tooltip="最长为 24 位"
  217 + placeholder="请输入名称"
  218 + />
  219 +
  220 + <ProFormText
  221 + width="sm"
  222 + name="company"
  223 + placeholder="请输入名称"
  224 + />
  225 +
  226 + <ProFormText
  227 + width="sm"
  228 + name="price"
  229 + placeholder="请输入名称"
  230 + />
  231 +
  232 + <ProFormText
  233 + width="sm"
  234 + name="notes"
  235 + placeholder="请输入名称"
  236 + />
  237 + </ProForm.Group>
  238 +
  239 + <ProForm.Group>
  240 + <ProFormText
  241 + width="sm"
  242 + name="name4"
  243 + disabled
  244 + initialValue={"尾款"}
  245 + tooltip="最长为 24 位"
  246 + placeholder="请输入名称"
  247 + />
  248 +
  249 + <ProFormText
  250 + width="sm"
  251 + name="company"
  252 + placeholder="请输入名称"
  253 + />
  254 +
  255 + <ProFormText
  256 + width="sm"
  257 + name="price"
  258 + placeholder="请输入名称"
  259 + />
  260 +
  261 + <ProFormText
  262 + width="sm"
  263 + name="notes"
  264 + placeholder="请输入名称"
  265 + />
  266 + </ProForm.Group> */}
  267 + </ModalForm>
  268 + </>
  269 + );
  270 +};
... ...
src/pages/Order/OrderWarning/components/HistoryModal.tsx 0 → 100644
  1 +import { postServiceOrderQueryHistoryOrderRecord } from '@/services';
  2 +import { formatDateTime } from '@/utils';
  3 +import { Button, Col, Empty, Flex, Modal, Row, Spin } from 'antd';
  4 +import { useEffect, useState } from 'react';
  5 +
  6 +export default ({ subOrders, isCancelledOrder, onClose }) => {
  7 + let subOrderIds = subOrders?.map((subOrder: any) => {
  8 + return subOrder.id;
  9 + });
  10 +
  11 + const [data, setData] = useState([]);
  12 + const [loading, setLoading] = useState(true);
  13 + let i = 0;
  14 +
  15 + const handleOk = () => {
  16 + onClose();
  17 + };
  18 +
  19 + /**
  20 + * 获取历史记录
  21 + */
  22 + const getHistory = async () => {
  23 + let res = await postServiceOrderQueryHistoryOrderRecord({
  24 + data: { ids: subOrderIds, isDeleteQueryOrder: isCancelledOrder },
  25 + });
  26 + setData(res.data);
  27 + setLoading(false);
  28 + };
  29 +
  30 + const getRecord = (history: any) => {
  31 + let record = [];
  32 + record.push(
  33 + <span className="pr-2 text-[#5E5E5E]">
  34 + {formatDateTime(history.createTime)}
  35 + </span>,
  36 + );
  37 +
  38 + record.push(<span className="text-[#3b83e5]">{history.createByName}</span>);
  39 +
  40 + record.push(<span>进行了</span>);
  41 +
  42 + // let label = enumValueToLabel(history.status, ORDER_STATUS_OPTIONS);
  43 +
  44 + // if (
  45 + // history.record !== 'INVOICING' && history.record !== 'order-change-normal' && history.record !== 'order-change-normal-CHECK' &&
  46 + // history.record?.indexOf(':') === -1 &&
  47 + // label !== undefined &&
  48 + // label !== ''
  49 + // ) {
  50 + // record.push(
  51 + // <>
  52 + // <span>,订单状态为:</span>
  53 + // <span className="text-[#3b83e5]">{label}</span>
  54 + // </>,
  55 + // );
  56 + // }
  57 +
  58 + if (history.record?.indexOf(':') !== -1) {
  59 + let values = history.record?.split(':');
  60 + let type = values[0];
  61 + let target = values[1];
  62 + if (target === 'null') {
  63 + target = '未指定';
  64 + }
  65 + //采购转发
  66 + if (type === 'PROCURE_CONVERT_PROCURE') {
  67 + record.push(
  68 + <>
  69 + <span>采购转发,{history.createByName}将订单转发给了</span>
  70 + <span className="text-[#3b83e5]">{target}</span>
  71 + </>,
  72 + );
  73 + }
  74 + } else {
  75 + record.push(
  76 + <span className="text-[#3b83e5]">
  77 + {history.recordText +
  78 + (history.record === 'INVOICING'
  79 + ? '(开票号码:' + history.invoiceNumber + ')'
  80 + : '')}
  81 + </span>,
  82 + );
  83 + }
  84 +
  85 + if (history.notes !== null) {
  86 + record.push(<span className="pl-1">{'备注:' + history.notes}</span>);
  87 + }
  88 +
  89 + if (history.description !== null) {
  90 + record.push(
  91 + <span className="pl-1">{'描述:' + history.description}</span>,
  92 + );
  93 + }
  94 +
  95 + return record;
  96 + };
  97 +
  98 + useEffect(() => {
  99 + getHistory();
  100 + }, []);
  101 +
  102 + const handleCancel = () => {
  103 + onClose();
  104 + };
  105 +
  106 + return (
  107 + <>
  108 + <Modal
  109 + title="订单历史记录"
  110 + open
  111 + width={650}
  112 + onOk={handleOk}
  113 + onCancel={handleCancel}
  114 + footer={() => (
  115 + <>
  116 + <Button onClick={handleCancel}>返回</Button>
  117 + </>
  118 + )}
  119 + >
  120 + <Spin tip="加载中" spinning={loading}>
  121 + <Row className="max-h-[500px] overflow-auto" gutter={[0, 14]}>
  122 + {data.map((item) => {
  123 + return (
  124 + <Col span={24} key={i}>
  125 + <Flex vertical>
  126 + <div>
  127 + <span className="py-2 text-[#5E5E5E]">
  128 + {'商品' + ++i}
  129 + </span>
  130 + <span className="text-[#8C8C8C]">
  131 + -【{item.productName}】
  132 + </span>
  133 + </div>
  134 +
  135 + <Flex vertical>
  136 + {item.historySubOrderRecordDto?.map((history) => {
  137 + return (
  138 + <div className="py-1" key={history.id}>
  139 + {getRecord(history)}
  140 + </div>
  141 + );
  142 + })}
  143 + </Flex>
  144 + </Flex>
  145 + </Col>
  146 + );
  147 + })}
  148 + </Row>
  149 + {data?.length <= 0 ? (
  150 + <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
  151 + ) : (
  152 + ''
  153 + )}
  154 + </Spin>
  155 + </Modal>
  156 + </>
  157 + );
  158 +};
... ...
src/pages/Order/OrderWarning/components/ImagesViewerModal.tsx 0 → 100644
  1 +import { postServiceOrderViewImages } from '@/services';
  2 +import { Button, Divider, Image, Modal } from 'antd';
  3 +import { useEffect, useState } from 'react';
  4 +export default ({ setVisible, optType, onClose, orderRow }) => {
  5 + const [images, setImages] = useState<any[]>([]);
  6 + const [title, setTitle] = useState("收货凭证");
  7 + const handleOk = () => {
  8 + onClose();
  9 + setVisible(false);
  10 + };
  11 +
  12 + const handleCancel = () => {
  13 + onClose();
  14 + setVisible(false);
  15 + };
  16 +
  17 + async function getImages() {
  18 + const res = await postServiceOrderViewImages({
  19 + data: { subId: orderRow.id },
  20 + });
  21 + const images = res.data;
  22 + setImages(images);
  23 + }
  24 + useEffect(() => {
  25 + if (optType === 'shippingReceipt') {
  26 + setTitle("收货凭证");
  27 + getImages();
  28 + } else if (optType === 'paymentReceipt') {
  29 + let paymentReceiptsImagesList: any[] = [];
  30 + if (orderRow.paymentReceiptAnnexList) {
  31 + paymentReceiptsImagesList.push(...orderRow.paymentReceiptAnnexList);
  32 + }
  33 + //去重
  34 + paymentReceiptsImagesList = [...new Set(paymentReceiptsImagesList)];
  35 + setImages(paymentReceiptsImagesList);
  36 + }
  37 +
  38 + }, []);
  39 +
  40 + return (
  41 + <>
  42 + <Modal
  43 + title={title}
  44 + open
  45 + onOk={handleOk}
  46 + onCancel={handleCancel}
  47 + footer={[
  48 + <Button key="back" onClick={handleCancel}>
  49 + 返回
  50 + </Button>,
  51 + ]}
  52 + >
  53 + <Image.PreviewGroup
  54 + className="mr-10"
  55 + preview={{
  56 + onChange: (current, prev) =>
  57 + console.log(`current index: ${current}, prev index: ${prev}`),
  58 + }}
  59 + >
  60 + {images.map((url) => (
  61 + <>
  62 + <Image width={120} src={url} /> <Divider type="vertical" />
  63 + </>
  64 + ))}
  65 + </Image.PreviewGroup>
  66 + </Modal>
  67 + </>
  68 + );
  69 +};
... ...
src/pages/Order/OrderWarning/components/ImportExpressBillModal.tsx 0 → 100644
  1 +import { RESPONSE_CODE } from '@/constants/enum';
  2 +import { postOrderImportImportWeightAndVolume } from '@/services';
  3 +import { ModalForm, ProFormUploadDragger } from '@ant-design/pro-components';
  4 +import { Button, Form, message } from 'antd';
  5 +
  6 +export default () => {
  7 + const [form] = Form.useForm();
  8 + const [messageApi, contextHolder] = message.useMessage();
  9 + return (
  10 + <>
  11 + <ModalForm
  12 + title="导入重量、体积"
  13 + trigger={<Button type="primary">导入重量、体积</Button>}
  14 + form={form}
  15 + autoFocusFirstInput
  16 + modalProps={{
  17 + destroyOnClose: true,
  18 + }}
  19 + submitTimeout={2000}
  20 + onFinish={async (values) => {
  21 + console.log(values);
  22 + const formData = new FormData();
  23 + formData.append('file', values.express[0].originFileObj);
  24 + messageApi.open({
  25 + type: 'loading',
  26 + content: '正在导入...',
  27 + duration: 0,
  28 + });
  29 + const res = await postOrderImportImportWeightAndVolume({
  30 + data: formData,
  31 + headers: {
  32 + 'Content-Type':
  33 + 'multipart/form-data; boundary=----WebKitFormBoundarynl6gT1BKdPWIejNq',
  34 + },
  35 + });
  36 + if (res.result === RESPONSE_CODE.SUCCESS) {
  37 + message.error('导入成功');
  38 + } else {
  39 + message.error('导入失败');
  40 + }
  41 + messageApi.destroy();
  42 + return true;
  43 + }}
  44 + >
  45 + <ProFormUploadDragger max={1} label="上传快递单" name="express" />
  46 + </ModalForm>
  47 + {contextHolder}
  48 + </>
  49 + );
  50 +};
... ...
src/pages/Order/OrderWarning/components/ImportModal.tsx 0 → 100644
  1 +import { RESPONSE_CODE } from '@/constants/enum';
  2 +import { postServiceOrderImportExcel } from '@/services';
  3 +import { orderExport } from '@/services/order';
  4 +import { UploadOutlined } from '@ant-design/icons';
  5 +import { Button, Modal, Upload, message } from 'antd';
  6 +import { RcFile, UploadFile, UploadProps } from 'antd/es/upload';
  7 +import { useState } from 'react';
  8 +export default ({ onClose }) => {
  9 + // const [form] = Form.useForm<{ name: string; company: string }>();
  10 + const [messageApi, contextHolder] = message.useMessage();
  11 + const [fileList, setFileList] = useState<UploadFile[]>([]);
  12 + const [uploading, setUploading] = useState(false);
  13 + const handleChange: UploadProps['onChange'] = ({ fileList: newFileList }) =>
  14 + setFileList(newFileList);
  15 +
  16 + const exportLoading = (content: string) => {
  17 + messageApi.open({
  18 + type: 'loading',
  19 + content: content,
  20 + duration: 0,
  21 + });
  22 + };
  23 +
  24 + const exportLoadingDestory = () => {
  25 + messageApi.destroy();
  26 + };
  27 + const downloadTemplate = async () => {
  28 + exportLoading('正在下载模板...');
  29 + orderExport(
  30 + '/api/service/order/exportTemplate',
  31 + '订单.xlsx',
  32 + 'post',
  33 + {},
  34 + exportLoadingDestory,
  35 + );
  36 + };
  37 +
  38 + const handleUpload = async () => {
  39 + const formData = new FormData();
  40 + fileList.forEach((file) => {
  41 + //originFileObj二进制文件
  42 + formData.append('file', file.originFileObj as RcFile);
  43 + });
  44 + // console.log(fileList[0] as RcFile)
  45 + // formData.append('file', fileList[0] as RcFile);
  46 + setUploading(true);
  47 + // You can use any AJAX library you like
  48 + const res = await postServiceOrderImportExcel({
  49 + data: formData,
  50 + headers: {
  51 + 'Content-Type':
  52 + 'multipart/form-data; boundary=----WebKitFormBoundarynl6gT1BKdPWIejNq',
  53 + },
  54 + });
  55 +
  56 + if (res.result === RESPONSE_CODE.SUCCESS) {
  57 + message.success(res.message);
  58 + onClose();
  59 + } else {
  60 + if (res.message === '表格中没有数据') {
  61 + setUploading(false);
  62 + return;
  63 + }
  64 + //存在错误信息,下载错误信息模板
  65 + exportLoading('正在下载错误信息...');
  66 + orderExport(
  67 + '/api/service/order/errorExcelInformation',
  68 + '订单.xlsx',
  69 + 'post',
  70 + formData,
  71 + exportLoadingDestory,
  72 + );
  73 + }
  74 +
  75 + setUploading(false);
  76 + };
  77 +
  78 + const props: UploadProps = {
  79 + onRemove: (file) => {
  80 + const index = fileList.indexOf(file);
  81 + const newFileList = fileList.slice();
  82 + newFileList.splice(index, 1);
  83 + setFileList(newFileList);
  84 + },
  85 + beforeUpload: (file) => {
  86 + setFileList([...fileList, file]);
  87 +
  88 + return false;
  89 + },
  90 + fileList,
  91 + onChange: handleChange,
  92 + accept: '.xlsx',
  93 + };
  94 +
  95 + return (
  96 + <>
  97 + <Modal
  98 + width={500}
  99 + open
  100 + title="批量发货"
  101 + footer={[
  102 + <Button key="cancel" onClick={onClose}>
  103 + 取消
  104 + </Button>,
  105 + <Button
  106 + type="primary"
  107 + key="ok"
  108 + onClick={handleUpload}
  109 + disabled={fileList.length === 0}
  110 + loading={uploading}
  111 + >
  112 + {uploading ? '上传中' : '提交'}
  113 + </Button>,
  114 + ]}
  115 + onCancel={async () => {
  116 + onClose();
  117 + }}
  118 + >
  119 + <div className="py-4 font-semibold">
  120 + 导入发货信息
  121 + <Button type="link" onClick={downloadTemplate}>
  122 + 下载模板
  123 + </Button>
  124 + </div>
  125 + <Upload {...props}>
  126 + <Button icon={<UploadOutlined />} disabled={fileList.length > 0}>
  127 + 点击选择文件
  128 + </Button>
  129 + </Upload>
  130 + </Modal>
  131 + {contextHolder}
  132 + </>
  133 + );
  134 +};
... ...
src/pages/Order/OrderWarning/components/InvoiceSubOrderInfoTable.tsx 0 → 100644
  1 +import { postServiceOrderGetReissueInfo } from '@/services';
  2 +import type { ProColumns } from '@ant-design/pro-components';
  3 +import { ProTable } from '@ant-design/pro-components';
  4 +import { Button, Divider } from 'antd';
  5 +import { useEffect, useState } from 'react';
  6 +
  7 +const columns: ProColumns[] = [
  8 + {
  9 + title: '发票号码',
  10 + width: 80,
  11 + dataIndex: 'invoiceNumber',
  12 + render: (_) => _,
  13 + },
  14 + {
  15 + title: '关联订单',
  16 + dataIndex: 'subOrderIds',
  17 + render: (_, { subOrderIds }) => {
  18 + console.log(JSON.stringify(_));
  19 + console.log(JSON.stringify(subOrderIds));
  20 + return (
  21 + <>
  22 + {subOrderIds.map((subOrderId, index) => {
  23 + return (
  24 + <>
  25 + <Button
  26 + key={index}
  27 + className="pl-1 pr-0"
  28 + type="link"
  29 + target="_blank"
  30 + href={'/order?id=' + subOrderId}
  31 + >
  32 + {subOrderId}
  33 + </Button>
  34 + <Divider type="vertical" />
  35 + </>
  36 + );
  37 + })}
  38 + </>
  39 + );
  40 + },
  41 + },
  42 +];
  43 +
  44 +export default ({ subOrderIds }) => {
  45 + const [reissueInfos, setReissueInfos] = useState([]);
  46 + useEffect(() => {
  47 + console.log('info');
  48 + const getReissueInfo = async () => {
  49 + let res = await postServiceOrderGetReissueInfo({
  50 + data: subOrderIds,
  51 + });
  52 + setReissueInfos(res.data);
  53 + };
  54 + getReissueInfo();
  55 + }, []);
  56 + return (
  57 + <ProTable
  58 + dataSource={reissueInfos}
  59 + rowKey="key"
  60 + pagination={false}
  61 + size={'small'}
  62 + //设置左右下边距为0
  63 + options={false}
  64 + columns={columns}
  65 + search={false}
  66 + dateFormatter="string"
  67 + headerTitle="发票信息"
  68 + />
  69 + );
  70 +};
... ...
src/pages/Order/OrderWarning/components/InvoicingDrawerForm.tsx 0 → 100644
  1 +// import { PlusOutlined } from '@ant-design/icons';
  2 +import InvoiceModal from '@/pages/Invoice/InvoiceVerification/components/InvoiceModal';
  3 +import {
  4 + postServiceConstGetPayeeEnum,
  5 + postServiceConstInitInvoiceDetailNames,
  6 + postServiceConstInvoiceType,
  7 + postServiceConstInvoicingType,
  8 + postServiceConstListInvoiceDetailNames,
  9 + postServiceInvoiceApplyInvoice,
  10 + postServiceInvoiceQueryCompanyInfo,
  11 + postServiceInvoiceWaitReissueInvoices,
  12 +} from '@/services';
  13 +import { FloatAdd, FloatSub, enum2ReverseSelect, enumToSelect } from '@/utils';
  14 +import { convertCurrency } from '@/utils/numberUtil';
  15 +import {
  16 + DrawerForm,
  17 + FormListActionType,
  18 + ProCard,
  19 + ProFormDigit,
  20 + ProFormGroup,
  21 + ProFormInstance,
  22 + ProFormList,
  23 + ProFormMoney,
  24 + ProFormSelect,
  25 + ProFormText,
  26 + ProFormTextArea,
  27 +} from '@ant-design/pro-components';
  28 +import { Button, Divider, Form, Space, Tooltip, message } from 'antd';
  29 +import { useEffect, useRef, useState } from 'react';
  30 +
  31 +export default ({ dataList, setVisible, mainOrder, onClose }) => {
  32 + // let subOrderIds = dataList?.map((item) => {
  33 + // return item.id;
  34 + // })
  35 + const [form] = Form.useForm();
  36 + const [projectOptions] = useState();
  37 + const [dataListCopy] = useState(dataList);
  38 + const listActionRef = useRef<FormListActionType>();
  39 + const formRef = useRef<ProFormInstance>();
  40 + useEffect(() => {
  41 + const initOptions = async () => {
  42 + const res = await postServiceConstInitInvoiceDetailNames({
  43 + data: dataListCopy.map((item) => {
  44 + return item.productName;
  45 + }),
  46 + });
  47 + const options = res.data;
  48 + const datas = dataListCopy.map((item) => {
  49 + return {
  50 + ...item,
  51 + projectName: options[item.productName],
  52 + };
  53 + });
  54 + const initialValue = datas.map((item) => {
  55 + return {
  56 + productName: item.productName,
  57 + projectName: item.projectName,
  58 + subOrderId: item.id,
  59 + specification: item.parameters,
  60 + unit: item.unit,
  61 + quantity: item.quantity,
  62 + price: item.productPrice,
  63 + totalPrice: item.subOrderPayment,
  64 + };
  65 + });
  66 + form.setFieldValue('invoiceDetails', initialValue);
  67 + form.setFieldValue('contacts', mainOrder.customerName);
  68 + };
  69 + initOptions();
  70 + }, []);
  71 +
  72 + useEffect(() => {}, [projectOptions]);
  73 +
  74 + function copyToClipboard(text: string) {
  75 + // 创建一个临时的textarea元素
  76 + const textarea = document.createElement('textarea');
  77 + textarea.value = text;
  78 +
  79 + // 将textarea元素添加到DOM中
  80 + document.body.appendChild(textarea);
  81 +
  82 + // 选中textarea中的文本
  83 + textarea.select();
  84 +
  85 + try {
  86 + // 尝试执行复制命令
  87 + document.execCommand('copy');
  88 + return true;
  89 + } catch (err) {
  90 + return false;
  91 + } finally {
  92 + // 移除临时的textarea元素
  93 + document.body.removeChild(textarea);
  94 + }
  95 + }
  96 +
  97 + useEffect(() => {}, []);
  98 + return (
  99 + <DrawerForm
  100 + open
  101 + title="申请开票"
  102 + resize={{
  103 + maxWidth: window.innerWidth * 0.8,
  104 + minWidth: 500,
  105 + }}
  106 + form={form}
  107 + formRef={formRef}
  108 + autoFocusFirstInput
  109 + drawerProps={{
  110 + destroyOnClose: true,
  111 + }}
  112 + submitter={{
  113 + render: (props, defaultDoms) => {
  114 + return [
  115 + <InvoiceModal
  116 + key={'invoicePreview'}
  117 + button={<Button type="primary"> 发票预览 </Button>}
  118 + getRecord={() => {
  119 + const totalPrice = form
  120 + .getFieldValue('invoiceDetails')
  121 + .reduce((accumulator, currentValue) => {
  122 + return FloatAdd(accumulator, currentValue.totalPrice);
  123 + }, 0);
  124 + const partyBName = form.getFieldValue('partyBName');
  125 + const openBank = form.getFieldValue('openBank');
  126 + const bankAccount = form.getFieldValue('bankAccount');
  127 + const bankCode = form.getFieldValue('bankCode');
  128 + return {
  129 + ...form.getFieldsValue(),
  130 + totalPrice: totalPrice,
  131 + totalPriceText: convertCurrency(totalPrice),
  132 + comment:
  133 + '开户名称: ' +
  134 + partyBName +
  135 + '\n' +
  136 + '开户行: ' +
  137 + openBank +
  138 + '\n' +
  139 + '账号: ' +
  140 + bankAccount +
  141 + '\n' +
  142 + '银行联行号: ' +
  143 + bankCode,
  144 + };
  145 + }}
  146 + />,
  147 + ...defaultDoms,
  148 + ];
  149 + },
  150 + }}
  151 + submitTimeout={2000}
  152 + onFinish={async (values) => {
  153 + postServiceInvoiceApplyInvoice({
  154 + data: {
  155 + ...values,
  156 + subOrderIds: dataListCopy.map((item) => {
  157 + return item.id;
  158 + }),
  159 + },
  160 + });
  161 + onClose();
  162 + }}
  163 + onOpenChange={(val) => {
  164 + return !val && setVisible();
  165 + }}
  166 + >
  167 + <ProFormList
  168 + name="subOrderIdObjs"
  169 + readonly={true}
  170 + label="开票订单"
  171 + initialValue={dataListCopy.map((item) => {
  172 + return {
  173 + value: item.id,
  174 + };
  175 + })}
  176 + deleteIconProps={false}
  177 + copyIconProps={false}
  178 + >
  179 + <ProFormGroup key="group">
  180 + <ProFormText readonly={true} name="value" label="" />
  181 + </ProFormGroup>
  182 + </ProFormList>
  183 + <ProFormSelect
  184 + name="ReissueInvoiceRecordIds"
  185 + label="重开的发票"
  186 + fieldProps={{
  187 + mode: 'multiple',
  188 + }}
  189 + placeholder="请选择重开发票"
  190 + request={async () => {
  191 + let reissueIds = dataListCopy.map((item) => {
  192 + return item.id;
  193 + });
  194 + let res = await postServiceInvoiceWaitReissueInvoices({
  195 + data: reissueIds,
  196 + });
  197 + return enum2ReverseSelect(res.data);
  198 + }}
  199 + />
  200 + <ProFormSelect
  201 + key="key"
  202 + label="购方名称"
  203 + width="lg"
  204 + showSearch
  205 + name="partyAName"
  206 + placeholder="请搜索购方"
  207 + rules={[{ required: true, message: '购方名称必填' }]}
  208 + onChange={(_, option) => {
  209 + form.setFieldValue('partyATaxid', option.taxId);
  210 + }}
  211 + fieldProps={{
  212 + optionItemRender(item) {
  213 + if (item.type === 'add') {
  214 + return <>{item.name}</>;
  215 + }
  216 + return (
  217 + <>
  218 + {item.name}
  219 + <Divider type="vertical" />
  220 + {item.taxId}
  221 + </>
  222 + );
  223 + },
  224 + }}
  225 + debounceTime={1000}
  226 + request={async (value) => {
  227 + const keywords = value.keyWords;
  228 + const res = await postServiceInvoiceQueryCompanyInfo({
  229 + data: {
  230 + nameLike: keywords,
  231 + taxIdIsNotNull: true,
  232 + },
  233 + });
  234 + let options = res?.data?.map((company) => {
  235 + return {
  236 + ...company,
  237 + label: company.name,
  238 + value: company.name,
  239 + key: company.id,
  240 + };
  241 + });
  242 +
  243 + //第一个商品默认为要新增的商品
  244 + if (keywords.trim() !== '') {
  245 + options.unshift({
  246 + name: keywords,
  247 + type: 'add',
  248 + label: keywords,
  249 + value: keywords,
  250 + key: keywords,
  251 + });
  252 + }
  253 + return options;
  254 + }}
  255 + />
  256 + <ProFormText
  257 + width="md"
  258 + name="partyATaxid"
  259 + label="购方税号"
  260 + rules={[{ required: true, message: '购方税号必填' }]}
  261 + placeholder="请输入名称"
  262 + />
  263 + <ProFormText
  264 + width="md"
  265 + name="partyAOpenBank"
  266 + label="开户银行"
  267 + placeholder="请输入名称"
  268 + />
  269 + <ProFormText
  270 + width="md"
  271 + name="partyABankAccount"
  272 + label="开户行账号"
  273 + placeholder="请输入名称"
  274 + />
  275 + <ProFormText
  276 + name="contacts"
  277 + label="联系人"
  278 + rules={[{ required: true, message: '请选择银行联行号!' }]}
  279 + />
  280 + <ProFormSelect
  281 + name="invoicingType"
  282 + label="开具类型"
  283 + request={async () => {
  284 + let invoicingTypeRet = await postServiceConstInvoicingType();
  285 + let options = enumToSelect(invoicingTypeRet.data);
  286 + return options;
  287 + }}
  288 + placeholder="请选择开具类型"
  289 + rules={[{ required: true, message: '请选择开具类型!' }]}
  290 + />
  291 + <ProFormSelect
  292 + name="type"
  293 + label="开票类型"
  294 + placeholder="请选择开票类型"
  295 + rules={[{ required: true, message: '请选择开票类型!' }]}
  296 + request={async () => {
  297 + let invoiceTypeRet = await postServiceConstInvoiceType();
  298 + let options = enumToSelect(invoiceTypeRet.data);
  299 + return options;
  300 + }}
  301 + />
  302 + <ProFormSelect
  303 + name="partyB"
  304 + label="开票收款单位"
  305 + request={async () => {
  306 + const res = await postServiceConstGetPayeeEnum();
  307 + let options = res?.data?.map((payee: any) => {
  308 + return {
  309 + ...payee,
  310 + label: payee.payeeName,
  311 + value: payee.name,
  312 + };
  313 + });
  314 + return options;
  315 + }}
  316 + onChange={(_, option) => {
  317 + if (option) {
  318 + form.setFieldsValue({
  319 + partyBName: option.payeeName,
  320 + partyBTaxid: option.taxId,
  321 + bankAccount: option.bankAccount,
  322 + openBank: option.openBank,
  323 + bankCode: option.bankCode,
  324 + });
  325 + }
  326 + }}
  327 + placeholder="请选择收款单位"
  328 + rules={[{ required: true, message: '请选择收款单位!' }]}
  329 + />
  330 + <ProFormText
  331 + name="partyBName"
  332 + label="开票收款单位名称"
  333 + hidden
  334 + rules={[{ required: true, message: '请选择收款单位!' }]}
  335 + />
  336 + <ProFormText
  337 + name="partyBTaxid"
  338 + label="开票收款单位税号"
  339 + hidden
  340 + rules={[{ required: true, message: '请选择收款单位!' }]}
  341 + />
  342 + <ProFormText
  343 + name="bankAccount"
  344 + label="账号"
  345 + hidden
  346 + rules={[{ required: true, message: '请选择账号!' }]}
  347 + />
  348 + <ProFormText
  349 + name="openBank"
  350 + label="开户行"
  351 + hidden
  352 + rules={[{ required: true, message: '请选择开户行!' }]}
  353 + />
  354 + <ProFormText
  355 + name="bankCode"
  356 + label="银行联行号"
  357 + hidden
  358 + rules={[{ required: true, message: '请选择银行联行号!' }]}
  359 + />
  360 + <ProFormSelect
  361 + name="isUrgent"
  362 + label="是否加急"
  363 + valueEnum={{
  364 + true: '是',
  365 + false: '否',
  366 + }}
  367 + placeholder="请选择是否加急"
  368 + rules={[{ required: true, message: '请选择是否加急!' }]}
  369 + />
  370 + <ProFormMoney
  371 + label="开票金额"
  372 + name="price"
  373 + locale="zh-CN"
  374 + disabled={true}
  375 + rules={[{ required: true, message: '请填写开票金额!' }]}
  376 + initialValue={dataListCopy.reduce((accumulator, currentValue) => {
  377 + return accumulator + currentValue.subOrderPayment;
  378 + }, 0)}
  379 + />
  380 + <ProFormList
  381 + name="invoiceDetails"
  382 + label="开票明细"
  383 + actionRef={listActionRef}
  384 + actionGuard={{
  385 + beforeRemoveRow: async (index) => {
  386 + const list = listActionRef.current?.getList();
  387 + const totalPrice = list[index].totalPrice;
  388 + form.setFieldValue(
  389 + 'price',
  390 + FloatSub(form.getFieldValue('price'), totalPrice),
  391 + );
  392 + return true;
  393 + },
  394 + }}
  395 + rules={[
  396 + {
  397 + required: true,
  398 + validator: async (_, value) => {
  399 + if (value && value.length > 0) {
  400 + return;
  401 + }
  402 + throw new Error('至少要有一项!');
  403 + },
  404 + },
  405 + ]}
  406 + itemRender={(doms, listMeta) => {
  407 + return (
  408 + <ProCard
  409 + bordered
  410 + extra={doms.action}
  411 + title={'明细' + (listMeta.index + 1)}
  412 + style={{
  413 + marginBlockEnd: 8,
  414 + }}
  415 + >
  416 + <Tooltip title="点击复制商品名称">
  417 + <Space
  418 + className="hover:cursor-pointer"
  419 + style={{
  420 + margin: 16,
  421 + marginTop: 4,
  422 + marginLeft: 0,
  423 + fontSize: 15,
  424 + }}
  425 + onClick={() => {
  426 + copyToClipboard(listMeta.record.productName);
  427 + message.info('商品名称复制成功!');
  428 + }}
  429 + >
  430 + 商品名称:{listMeta.record.productName}
  431 + </Space>
  432 + </Tooltip>
  433 + <ProFormSelect
  434 + key={'projectName' + listMeta.index}
  435 + width="md"
  436 + showSearch
  437 + name="projectName"
  438 + rules={[{ required: true, message: '请输入开票项目名称!' }]}
  439 + request={async (value) => {
  440 + const keywords = value.keyWords;
  441 + const res = await postServiceConstListInvoiceDetailNames({
  442 + data: {
  443 + nameLike: keywords,
  444 + },
  445 + });
  446 + let options = res?.data?.map((c: any) => {
  447 + return {
  448 + ...c,
  449 + label:
  450 + '*' +
  451 + c.productAndServiceCatagoryAbbreviation +
  452 + '*' +
  453 + c.name,
  454 + value:
  455 + '*' +
  456 + c.productAndServiceCatagoryAbbreviation +
  457 + '*' +
  458 + c?.name,
  459 + key: c.id,
  460 + };
  461 + });
  462 + return options;
  463 + }}
  464 + fieldProps={{
  465 + filterOption() {
  466 + return true;
  467 + },
  468 + }}
  469 + onChange={(_, option) => {
  470 + let index = listMeta.index;
  471 + let copyList = form.getFieldValue('invoiceDetails');
  472 + let currentData = copyList[index];
  473 + currentData.projectName =
  474 + '*' +
  475 + option.productAndServiceCatagoryAbbreviation +
  476 + '*' +
  477 + option.name;
  478 + form.setFieldValue('invoiceDetails', copyList);
  479 + }}
  480 + debounceTime={1000}
  481 + label="项目名称"
  482 + initialValue={listMeta.record.projectName}
  483 + placeholder="请输入名称"
  484 + />
  485 + <ProFormText
  486 + key={'specification' + listMeta.index}
  487 + name="specification"
  488 + label="规格型号"
  489 + rules={[
  490 + {
  491 + message: '规格型号不能为空!',
  492 + required: true,
  493 + },
  494 + {
  495 + validator: (_, value) => {
  496 + let len = 0;
  497 + // 判断是否为全角字符
  498 + for (let i = 0; i < value.length; i++) {
  499 + // 获取字符的Unicode值
  500 + const code = value.charCodeAt(i);
  501 + // 判断是否为全角字符
  502 + if (
  503 + (code >= 0xff01 && code <= 0xff5e) ||
  504 + (code >= 0x4e00 && code <= 0x9fff)
  505 + ) {
  506 + len += 2; // 全角字符
  507 + } else {
  508 + len += 1; // 半角字符
  509 + }
  510 + }
  511 + if (len <= 40) {
  512 + return Promise.resolve();
  513 + }
  514 + return Promise.reject(
  515 + new Error('规格型号不能超过40个字符!'),
  516 + );
  517 + },
  518 + },
  519 + ]}
  520 + placeholder="请输入名称"
  521 + />
  522 + <ProFormText
  523 + key={'unit' + listMeta.index}
  524 + name="unit"
  525 + label="单位"
  526 + placeholder="请输入名称"
  527 + />
  528 + <ProFormDigit
  529 + key={'quantity' + listMeta.index}
  530 + label="数量"
  531 + name="quantity"
  532 + rules={[
  533 + {
  534 + validator: (_, value) => {
  535 + if (value === undefined || value > 0) {
  536 + return Promise.resolve();
  537 + }
  538 + return Promise.reject(new Error('数量必须大于0'));
  539 + },
  540 + },
  541 + ]}
  542 + />
  543 + <ProFormDigit
  544 + key={'price' + listMeta.index}
  545 + label="单价"
  546 + name="price"
  547 + rules={[
  548 + {
  549 + validator: (_, value) => {
  550 + if (value === undefined || value > 0) {
  551 + return Promise.resolve();
  552 + }
  553 + return Promise.reject(new Error('单价必须大于0'));
  554 + },
  555 + },
  556 + ]}
  557 + />
  558 + <ProFormMoney
  559 + key={'totalPrice' + listMeta.index}
  560 + label="金额"
  561 + name="totalPrice"
  562 + onChange={() => {
  563 + const invoiceDetails = form.getFieldValue('invoiceDetails');
  564 + console.log('invoiceDetails', invoiceDetails);
  565 + const totalPrice = invoiceDetails.reduce(
  566 + (accumulator, currentValue) => {
  567 + return FloatAdd(accumulator, currentValue.totalPrice);
  568 + },
  569 + 0,
  570 + );
  571 + console.log('totalPrice', totalPrice);
  572 + form.setFieldValue('price', totalPrice);
  573 + }}
  574 + rules={[
  575 + {
  576 + validator: (_, value) => {
  577 + if (value === undefined || value > 0) {
  578 + return Promise.resolve();
  579 + }
  580 + return Promise.reject(new Error('金额必须大于0'));
  581 + },
  582 + },
  583 + ]}
  584 + locale="zh-CN"
  585 + />
  586 + </ProCard>
  587 + );
  588 + }}
  589 + ></ProFormList>
  590 + <ProFormTextArea
  591 + name="applyInvoicingNotes"
  592 + label="备注"
  593 + placeholder="请输入名称"
  594 + />
  595 + </DrawerForm>
  596 + );
  597 +};
... ...
src/pages/Order/OrderWarning/components/KingdeeCustomerModal.tsx 0 → 100644
  1 +import {
  2 + postKingdeeRepCustomerDetail,
  3 + postKingdeeRepCustomerSave,
  4 +} from '@/services';
  5 +import { getTeacherCustomFieldNumber } from '@/utils/kingdee';
  6 +import { CloseCircleOutlined } from '@ant-design/icons';
  7 +import {
  8 + ModalForm,
  9 + ProFormGroup,
  10 + ProFormList,
  11 + ProFormText,
  12 +} from '@ant-design/pro-components';
  13 +import { Form, message } from 'antd';
  14 +
  15 +// import { cloneDeep } from 'lodash';
  16 +export default ({ setVisible, data, onClose }) => {
  17 + const [form] = Form.useForm();
  18 +
  19 + /**
  20 + * 回显客户信息
  21 + * @param id
  22 + */
  23 + async function queryAndShowCustomer(id: any) {
  24 + //查询客户信息
  25 + let res = await postKingdeeRepCustomerDetail({
  26 + data: {
  27 + id: id,
  28 + },
  29 + });
  30 +
  31 + if (res) {
  32 + form.setFieldValue('name', res.name);
  33 + form.setFieldValue('id', res.id);
  34 + form.setFieldValue('contact_persons', res.bomentity);
  35 + let customFiledNumber = await getTeacherCustomFieldNumber();
  36 + form.setFieldValue('teacherName', res.custom_field[customFiledNumber]);
  37 + }
  38 + }
  39 +
  40 + if (data) {
  41 + //修改
  42 + if (data.id) {
  43 + queryAndShowCustomer(data.id);
  44 + } else {
  45 + //新增
  46 + form.setFieldValue('name', data.name);
  47 + form.setFieldValue('contact_persons', [{}]);
  48 + }
  49 + }
  50 + return (
  51 + <>
  52 + <ModalForm
  53 + width={900}
  54 + open
  55 + title="客户信息"
  56 + form={form}
  57 + autoFocusFirstInput
  58 + modalProps={{
  59 + okText: '保存',
  60 + cancelText: '取消',
  61 + destroyOnClose: true,
  62 + onCancel: () => {
  63 + setVisible(false);
  64 + },
  65 + }}
  66 + onFinish={async (values) => {
  67 + //查询客户自定义字段,课题组
  68 + let custom_field_umber = await getTeacherCustomFieldNumber();
  69 +
  70 + if (custom_field_umber) {
  71 + let customFieldObj = {};
  72 + customFieldObj[custom_field_umber] = values.teacherName;
  73 + values.custom_field = customFieldObj;
  74 + }
  75 + let customSaveRes = await postKingdeeRepCustomerSave({
  76 + data: values,
  77 + });
  78 + if (customSaveRes) {
  79 + let id_number_map = customSaveRes.id_number_map;
  80 + let ids = customSaveRes.ids;
  81 + if (id_number_map && ids) {
  82 + message.success('保存成功');
  83 + let id = ids[0];
  84 + onClose(id);
  85 + }
  86 + }
  87 + }}
  88 + onOpenChange={setVisible}
  89 + >
  90 + <ProFormText key="key" name="id" label="id" placeholder="id" hidden />
  91 + <ProFormGroup key="group">
  92 + <ProFormText
  93 + name="name"
  94 + width="md"
  95 + label={
  96 + <>
  97 + <span>客户名称</span>
  98 + <span className="pl-2 text-xs text-gray-400">
  99 + 请按照[单位]-[姓名][手机号]命名,例如:清华大学-张三12345678919
  100 + </span>
  101 + </>
  102 + }
  103 + initialValue={data}
  104 + placeholder="请输入客户名称"
  105 + rules={[
  106 + {
  107 + required: true,
  108 + pattern: new RegExp('^.+-.+$'),
  109 + message:
  110 + '格式错误,若无单位可写:“无-姓名手机号”,例如:无-张三12345678919',
  111 + },
  112 + { required: true, message: '客户名称必填' },
  113 + ]}
  114 + />
  115 + <ProFormText
  116 + name="teacherName"
  117 + width="md"
  118 + label="课题组老师"
  119 + placeholder="请输入课题组老师"
  120 + rules={[
  121 + { required: true, message: '课题组老师必填,若没有请填“无”' },
  122 + ]}
  123 + />
  124 + </ProFormGroup>
  125 +
  126 + <ProFormList
  127 + creatorButtonProps={{ disabled: false }}
  128 + name="contact_persons"
  129 + label="联系人信息"
  130 + actionGuard={{
  131 + beforeRemoveRow: async () => {
  132 + return new Promise((resolve) => {
  133 + let contactPersons = form.getFieldValue('contact_persons');
  134 + if (contactPersons.length === 1) {
  135 + message.error('至少要有一个联系人');
  136 + resolve(false);
  137 + return;
  138 + }
  139 + resolve(true);
  140 + });
  141 + },
  142 + beforeAddRow: (defaultValue) => {
  143 + defaultValue.id = undefined; //复制的时候要把id去掉
  144 + return defaultValue;
  145 + },
  146 + }}
  147 + deleteIconProps={{
  148 + Icon: CloseCircleOutlined,
  149 + tooltipText: '不需要这行了',
  150 + }}
  151 + >
  152 + <ProFormGroup key="group">
  153 + {[
  154 + <ProFormText
  155 + key="key"
  156 + name="id"
  157 + label="id"
  158 + placeholder="id"
  159 + hidden
  160 + />,
  161 + <ProFormText
  162 + key="key"
  163 + name="contact_person"
  164 + label="收货人姓名"
  165 + placeholder="联系人姓名"
  166 + rules={[{ required: true, message: '收货人姓名必填' }]}
  167 + />,
  168 + <ProFormText
  169 + key="key"
  170 + name="mobile"
  171 + label="联系方式"
  172 + placeholder="联系方式"
  173 + rules={[{ required: true, message: '联系方式必填' }]}
  174 + />,
  175 + <ProFormText
  176 + key="key"
  177 + name="contact_address"
  178 + label="收货地址"
  179 + width="md"
  180 + placeholder="请输入收货地址"
  181 + rules={[{ required: true, message: '收货地址必填' }]}
  182 + />,
  183 + ]}
  184 + </ProFormGroup>
  185 + </ProFormList>
  186 + </ModalForm>
  187 + </>
  188 + );
  189 +};
... ...