Commit fa87b7a24a4dab45a1a7b577f64f3e9bb249dd3b

Authored by 柏杨
2 parents d90ecca7 9cb7666a

Merge branch 'feature-installment2' into 'master'

Feature installment2



See merge request !61
src/pages/Order/OrderList/CheckModal.tsx
... ... @@ -70,6 +70,8 @@ export default ({
70 70  
71 71 const [afterSalesInfo, setAfterSalesInfo] = useState<any>();
72 72 const [prepaidProofImages, setPrepaidProofImages] = useState<any[]>([]);
  73 + const [partialPaymentReceiptsImages, setPartialPaymentReceiptsImages] =
  74 + useState<any[]>([]);
73 75 /**
74 76 * 审核类型
75 77 */
... ... @@ -129,6 +131,7 @@ export default ({
129 131 }
130 132 getOrderAfterSalesInfo();
131 133  
  134 + // 常规回款凭证
132 135 let paymentReceiptsImagesList: any[] = [];
133 136 subOrders?.forEach((item: any) => {
134 137 if (item.paymentReceiptAnnexList) {
... ... @@ -139,6 +142,22 @@ export default ({
139 142 paymentReceiptsImagesList = [...new Set(paymentReceiptsImagesList)];
140 143 setPymentReceiptsImages(paymentReceiptsImagesList);
141 144  
  145 + // 分期付款凭证从 subOrderInformationLists 获取
  146 + let partialPaymentImages: any[] = [];
  147 + if (
  148 + checkType(CHECK_TYPE.PARTIAL_PAYMENT_RECEIPTS_AUDIT) &&
  149 + data?.subOrderInformationLists
  150 + ) {
  151 + data.subOrderInformationLists.forEach((subOrder: any) => {
  152 + if (subOrder.paymentReceiptAnnexPartialList) {
  153 + partialPaymentImages.push(...subOrder.paymentReceiptAnnexPartialList);
  154 + }
  155 + });
  156 + }
  157 + // 去重
  158 + partialPaymentImages = [...new Set(partialPaymentImages)];
  159 + setPartialPaymentReceiptsImages(partialPaymentImages);
  160 +
142 161 //预存审核的凭证
143 162 let proofImages: any[] = [];
144 163 subOrders?.forEach((item) => {
... ... @@ -403,7 +422,10 @@ export default ({
403 422 if (checkType(CHECK_TYPE.URGENT_INVOICE_AUDITING)) {
404 423 type = 'urgent_invoice_audit';
405 424 }
406   - if (checkType(CHECK_TYPE.PAYMENT_RECEIPTS_AUDIT)) {
  425 + if (
  426 + checkType(CHECK_TYPE.PAYMENT_RECEIPTS_AUDIT) ||
  427 + checkType(CHECK_TYPE.PARTIAL_PAYMENT_RECEIPTS_AUDIT)
  428 + ) {
407 429 type = 'payment_receipt_audit';
408 430 }
409 431 if (checkType(CHECK_TYPE.CONFIRM_REISSUE)) {
... ... @@ -585,6 +607,18 @@ export default ({
585 607 });
586 608 }
587 609  
  610 + // 分期回款审核处理
  611 + if (checkType(CHECK_TYPE.PARTIAL_PAYMENT_RECEIPTS_AUDIT)) {
  612 + let type = computeType();
  613 + return doCheck({
  614 + ...values,
  615 + pass: true,
  616 + subOrderIds: subOrderIds,
  617 + type: type,
  618 + notes: form.getFieldValue('name'),
  619 + });
  620 + }
  621 +
588 622 let type = '';
589 623 type = computeType();
590 624 doCheck({
... ... @@ -621,7 +655,6 @@ export default ({
621 655 <span className="text-sm">回款凭证</span>
622 656 </Divider>
623 657 <Image.PreviewGroup
624   - className="mr-10"
625 658 preview={{
626 659 onChange: (current, prev) =>
627 660 console.log(`current index: ${current}, prev index: ${prev}`),
... ... @@ -639,13 +672,54 @@ export default ({
639 672 ''
640 673 )}
641 674  
  675 + {checkType(CHECK_TYPE.PARTIAL_PAYMENT_RECEIPTS_AUDIT) ? (
  676 + <>
  677 + <Row gutter={[16, 16]}>
  678 + <Col span={24}>
  679 + <div className="mb-2">
  680 + <span className="font-semibold">回款类型:</span>
  681 + <span>分期付款</span>
  682 + </div>
  683 + </Col>
  684 + <Col span={24}>
  685 + <div className="mb-2">
  686 + <span className="font-semibold">回款金额:</span>
  687 + <span>{data?.installmentMoney || 0} 元</span>
  688 + </div>
  689 + </Col>
  690 + <Col span={24}>
  691 + <div className="mb-2 font-semibold">附件凭证:</div>
  692 + <div>
  693 + <Image.PreviewGroup
  694 + preview={{
  695 + onChange: (current, prev) =>
  696 + console.log(
  697 + `current index: ${current}, prev index: ${prev}`,
  698 + ),
  699 + }}
  700 + >
  701 + {partialPaymentReceiptsImages.map((url, index) => (
  702 + <span key={`img-${index}`}>
  703 + <Image width={120} src={url} />{' '}
  704 + <Divider type="vertical" />
  705 + </span>
  706 + ))}
  707 + </Image.PreviewGroup>
  708 + </div>
  709 + </Col>
  710 + </Row>
  711 + <Divider></Divider>
  712 + </>
  713 + ) : (
  714 + ''
  715 + )}
  716 +
642 717 {checkType(CHECK_TYPE.PREPAID_AUDIT) && (
643 718 <>
644 719 <Divider orientation="center">
645 720 <span className="text-sm">凭证</span>
646 721 </Divider>
647 722 <Image.PreviewGroup
648   - className="mr-10"
649 723 preview={{
650 724 onChange: (current, prev) =>
651 725 console.log(`current index: ${current}, prev index: ${prev}`),
... ...
src/pages/Order/OrderList/HirePurchaseUploadPayBillModal.tsx 0 → 100644
  1 +import { RESPONSE_CODE } from '@/constants/enum';
  2 +import {
  3 + postServiceOrderFileProcess,
  4 + postServiceOrderHirePurchase,
  5 +} from '@/services';
  6 +import { transImageFile } from '@/utils';
  7 +import { PlusOutlined } from '@ant-design/icons';
  8 +import { Button, Form, Input, Modal, Upload, message } from 'antd';
  9 +import { RcFile } from 'antd/lib/upload';
  10 +import { UploadFile, UploadProps } from 'antd/lib/upload/interface';
  11 +import { cloneDeep } from 'lodash';
  12 +import { useEffect, useRef, useState } from 'react';
  13 +import { COMFIR_RECEIPT_IMAGES_NUMBER } from '../constant';
  14 +
  15 +interface HirePurchaseUploadPayBillModalProps {
  16 + visible: boolean;
  17 + onCancel: () => void;
  18 + onOk: () => void;
  19 + orderAmount?: number;
  20 + paidAmount?: number;
  21 + record?: any;
  22 + subOrders?: any[];
  23 +}
  24 +
  25 +const HirePurchaseUploadPayBillModal: React.FC<
  26 + HirePurchaseUploadPayBillModalProps
  27 +> = ({
  28 + visible,
  29 + onCancel,
  30 + onOk,
  31 + orderAmount = 100000.0,
  32 + paidAmount = 0,
  33 + record,
  34 + subOrders = [],
  35 +}) => {
  36 + // 订单总金额
  37 + const totalPayment = record?.totalPayment || orderAmount;
  38 + // 已回款金额
  39 + const installedMoney = record?.installmentMoneyAudit || paidAmount;
  40 + // 待回款金额
  41 + const remainingMoney = totalPayment - installedMoney;
  42 + const [form] = Form.useForm();
  43 + const [fileList, setFileList] = useState<UploadFile[]>([]);
  44 + const [paymentType] = useState<string>('INSTALLMENT');
  45 + const [previewOpen, setPreviewOpen] = useState(false);
  46 + const [previewImage, setPreviewImage] = useState('');
  47 + const [previewTitle, setPreviewTitle] = useState('');
  48 +
  49 + const fileListObj = useRef<UploadFile[]>([]);
  50 +
  51 + const getBase64 = (file: RcFile): Promise<string> =>
  52 + new Promise((resolve, reject) => {
  53 + const reader = new FileReader();
  54 + reader.readAsDataURL(file);
  55 + reader.onload = () => resolve(reader.result as string);
  56 + reader.onerror = (error) => reject(error);
  57 + });
  58 +
  59 + const handleCancel = () => setPreviewOpen(false);
  60 +
  61 + const uploadButton = (
  62 + <div>
  63 + <PlusOutlined />
  64 + <div style={{ marginTop: 8 }}>上传凭证</div>
  65 + </div>
  66 + );
  67 +
  68 + // const handleTypeChange = (e: any) => {
  69 + // const newType = e.target.value;
  70 + // setPaymentType(newType);
  71 +
  72 + // // 如果选择全部回款,自动填入待回款金额
  73 + // if (newType === 'FULL') {
  74 + // form.setFieldsValue({
  75 + // amount: remainingMoney.toFixed(2),
  76 + // });
  77 + // }
  78 + // };
  79 +
  80 + // 验证回款金额不能超过待回款金额
  81 + const validateAmount = (_: any, value: string) => {
  82 + // Check if the value is a valid number
  83 + if (isNaN(value)) return Promise.reject('请输入有效的数字');
  84 +
  85 + // Check if the value has more than 2 decimal places
  86 + const decimalCount = (value.match(/\.\d+/) || [''])[0].length - 1;
  87 + if (decimalCount > 2) {
  88 + return Promise.reject('最多只能输入两位小数');
  89 + }
  90 +
  91 + const amount = parseFloat(value);
  92 + if (amount <= 0) return Promise.reject('回款金额必须大于0');
  93 + if (amount > remainingMoney)
  94 + return Promise.reject(
  95 + `回款金额不能超过待回款金额 ${remainingMoney.toFixed(2)}元`,
  96 + );
  97 +
  98 + return Promise.resolve();
  99 + };
  100 +
  101 + const handleBeforeUpload = (file: any) => {
  102 + setFileList([...fileList, file]);
  103 + return false;
  104 + };
  105 +
  106 + /** 粘贴快捷键的回调 */
  107 + const onPaste = async (e: any) => {
  108 + /** 获取剪切板的数据clipboardData */
  109 + let clipboardData = e.clipboardData,
  110 + i = 0,
  111 + items,
  112 + item,
  113 + types;
  114 +
  115 + /** 为空判断 */
  116 + if (clipboardData) {
  117 + items = clipboardData.items;
  118 + if (!items) {
  119 + message.info('您的剪贴板中没有照片');
  120 + return;
  121 + }
  122 +
  123 + item = items[0];
  124 + types = clipboardData.types || [];
  125 + /** 遍历剪切板的数据 */
  126 + for (; i < types.length; i++) {
  127 + if (types[i] === 'Files') {
  128 + item = items[i];
  129 + break;
  130 + }
  131 + }
  132 +
  133 + /** 判断文件是否为图片 */
  134 + if (item && item.kind === 'file' && item.type.match(/^image\//i)) {
  135 + const imgItem = item.getAsFile();
  136 + const newFileList = cloneDeep(fileListObj.current);
  137 + let filteredArray = newFileList.filter(
  138 + (obj) => obj.status !== 'removed',
  139 + ); //过滤掉状态为已删除的照片
  140 + const listItem = {
  141 + ...imgItem,
  142 + status: 'done',
  143 + url: await getBase64(imgItem),
  144 + originFileObj: imgItem,
  145 + };
  146 +
  147 + if (filteredArray.length >= COMFIR_RECEIPT_IMAGES_NUMBER) {
  148 + message.info('上传凭证数量不能超过3');
  149 + return;
  150 + }
  151 + fileListObj.current = filteredArray;
  152 + filteredArray.push(listItem);
  153 + setFileList(filteredArray);
  154 + return;
  155 + }
  156 + }
  157 +
  158 + message.info('您的剪贴板中没有照片');
  159 + };
  160 +
  161 + const handleChange: UploadProps['onChange'] = ({ fileList: newFileList }) => {
  162 + fileListObj.current = newFileList;
  163 + setFileList(newFileList);
  164 + };
  165 +
  166 + const handlePreview = async (file: UploadFile) => {
  167 + if (!file.url && !file.preview) {
  168 + file.preview = await getBase64(file.originFileObj as RcFile);
  169 + }
  170 + setPreviewImage(file.url || (file.preview as string));
  171 + setPreviewOpen(true);
  172 + setPreviewTitle(
  173 + file.name ||
  174 + file.originFileObj?.name ||
  175 + file.url!.substring(file.url!.lastIndexOf('/') + 1),
  176 + );
  177 + };
  178 +
  179 + const props: UploadProps = {
  180 + onRemove: (file) => {
  181 + const index = fileList.indexOf(file);
  182 + const newFileList = fileList.slice();
  183 + newFileList.splice(index, 1);
  184 + setFileList(newFileList);
  185 + },
  186 + beforeUpload: handleBeforeUpload,
  187 + listType: 'picture-card',
  188 + onPreview: handlePreview,
  189 + fileList,
  190 + onChange: handleChange,
  191 + accept: 'image/png, image/jpeg, image/png',
  192 + name: 'files',
  193 + headers: { Authorization: localStorage.getItem('token') },
  194 + };
  195 +
  196 + useEffect(() => {
  197 + document.addEventListener('paste', onPaste);
  198 + return () => {
  199 + document.removeEventListener('paste', onPaste);
  200 + };
  201 + }, []);
  202 +
  203 + const handleOk = async () => {
  204 + try {
  205 + const values = await form.validateFields();
  206 +
  207 + if (fileList.length <= 0) {
  208 + message.error('请上传至少一张凭证');
  209 + return;
  210 + }
  211 +
  212 + message.open({
  213 + type: 'loading',
  214 + content: '正在上传凭证...',
  215 + duration: 0,
  216 + });
  217 +
  218 + // 附件处理
  219 + let formData = new FormData();
  220 + for (let file of fileList) {
  221 + if (file.originFileObj) {
  222 + formData.append('files', file.originFileObj as RcFile);
  223 + } else {
  224 + // 有url的话取url(源文件),没url取thumbUrl。有url的时候thumbUrl是略缩图
  225 + if (file?.url === undefined || file?.url === null) {
  226 + formData.append(
  227 + 'files',
  228 + transImageFile(file?.thumbUrl),
  229 + file?.originFileObj?.name,
  230 + );
  231 + } else {
  232 + formData.append(
  233 + 'files',
  234 + transImageFile(file?.url),
  235 + file?.originFileObj?.name,
  236 + );
  237 + }
  238 + }
  239 + }
  240 +
  241 + let res = await postServiceOrderFileProcess({
  242 + data: formData,
  243 + });
  244 +
  245 + message.destroy();
  246 +
  247 + if (res.result === RESPONSE_CODE.SUCCESS) {
  248 + let fileUrls = res?.data?.map((item) => {
  249 + return { url: item };
  250 + });
  251 +
  252 + // 分期付款提交
  253 + const installmentMoney = values.amount;
  254 + const installmentComment = values.remarks;
  255 +
  256 + // 获取子订单IDs
  257 + const subOrderIds =
  258 + subOrders?.map((item: any) => {
  259 + return item.id;
  260 + }) || [];
  261 +
  262 + const data = await postServiceOrderHirePurchase({
  263 + data: {
  264 + subOrderIds: subOrderIds,
  265 + filePaths: fileUrls,
  266 + installmentMoney: installmentMoney,
  267 + installmentComment: installmentComment,
  268 + },
  269 + });
  270 +
  271 + if (data.result === RESPONSE_CODE.SUCCESS) {
  272 + message.success(data.message || '提交成功');
  273 + onOk();
  274 + } else {
  275 + message.error(data.message || '提交失败');
  276 + }
  277 + } else {
  278 + message.error(res.message || '上传失败');
  279 + }
  280 + } catch (error) {
  281 + console.error('Validate Failed:', error);
  282 + message.error('提交失败');
  283 + }
  284 + };
  285 +
  286 + return (
  287 + <>
  288 + <Modal
  289 + title="回款"
  290 + open={visible}
  291 + onCancel={onCancel}
  292 + footer={[
  293 + <Button key="cancel" onClick={onCancel}>
  294 + 取消
  295 + </Button>,
  296 + <Button key="submit" type="primary" onClick={handleOk}>
  297 + 确认
  298 + </Button>,
  299 + ]}
  300 + width={500}
  301 + >
  302 + <Form form={form} layout="vertical">
  303 + <div style={{ marginBottom: 16 }}>
  304 + <div
  305 + style={{
  306 + display: 'flex',
  307 + justifyContent: 'space-between',
  308 + marginBottom: 8,
  309 + }}
  310 + >
  311 + <span>订单总金额:</span>
  312 + <span>{totalPayment.toFixed(2)}元</span>
  313 + </div>
  314 + <div
  315 + style={{
  316 + display: 'flex',
  317 + justifyContent: 'space-between',
  318 + marginBottom: 8,
  319 + }}
  320 + >
  321 + <span>已回款金额:</span>
  322 + <span>{installedMoney.toFixed(2)}元</span>
  323 + </div>
  324 + <div
  325 + style={{
  326 + display: 'flex',
  327 + justifyContent: 'space-between',
  328 + marginBottom: 8,
  329 + }}
  330 + >
  331 + <span>待回款金额:</span>
  332 + <span>{remainingMoney.toFixed(2)}元</span>
  333 + </div>
  334 + </div>
  335 + <Form.Item
  336 + label="回款金额"
  337 + name="amount"
  338 + rules={[
  339 + { required: true, message: '请输入回款金额' },
  340 + { validator: validateAmount },
  341 + ]}
  342 + >
  343 + <Input
  344 + placeholder="请输入回款金额"
  345 + suffix="元"
  346 + disabled={paymentType === 'FULL'}
  347 + />
  348 + </Form.Item>
  349 +
  350 + <div className="pb-4 text-xs decoration-gray-50">可复制照片粘贴</div>
  351 + <Form.Item
  352 + label="附件凭证"
  353 + name="attachments"
  354 + rules={[{ required: true, message: '请上传回款凭证' }]}
  355 + >
  356 + <Upload {...props}>
  357 + {fileList.length < COMFIR_RECEIPT_IMAGES_NUMBER
  358 + ? uploadButton
  359 + : ''}
  360 + </Upload>
  361 + </Form.Item>
  362 + </Form>
  363 + </Modal>
  364 +
  365 + <Modal
  366 + open={previewOpen}
  367 + title={previewTitle}
  368 + footer={null}
  369 + onCancel={handleCancel}
  370 + >
  371 + <img alt="图片预览" style={{ width: '100%' }} src={previewImage} />
  372 + </Modal>
  373 + </>
  374 + );
  375 +};
  376 +
  377 +export default HirePurchaseUploadPayBillModal;
... ...
src/pages/Order/OrderList/ImagesViewerModal.tsx
... ... @@ -3,7 +3,7 @@ import { Button, Divider, Image, Modal } from &#39;antd&#39;;
3 3 import { useEffect, useState } from 'react';
4 4 export default ({ setVisible, optType, onClose, orderRow }) => {
5 5 const [images, setImages] = useState<any[]>([]);
6   - const [title, setTitle] = useState('收凭证');
  6 + const [title, setTitle] = useState('收凭证');
7 7 const handleOk = () => {
8 8 onClose();
9 9 setVisible(false);
... ...
src/pages/Order/OrderList/OrderDrawer.tsx
... ... @@ -75,6 +75,8 @@ export default ({ onClose, data, subOrders, orderOptType }) =&gt; {
75 75 const [kingdeeCstomerModalVisible, setKingdeeCstomerModalVisible] =
76 76 useState(false);
77 77 const [paymentMethod, setPaymentMethod] = useState('');
  78 + const [paymentMethodDisabled, setPaymentMethodDisabled] = useState(false);
  79 + const [paymentChannelDisabled, setPaymentChannelDisabled] = useState(false);
78 80 const [customerRequestCount, setCustomerRequestCount] = useState(0);
79 81 const [
80 82 productParametersDisabledFlagList,
... ... @@ -307,6 +309,23 @@ export default ({ onClose, data, subOrders, orderOptType }) =&gt; {
307 309  
308 310 copyData.customerNameString = copyData.customerName;
309 311  
  312 + // // 清空支付方式和支付渠道
  313 + // if (
  314 + // copyData.paymentChannel === 'TAOBAO' ||
  315 + // [
  316 + // 'UNPAID',
  317 + // 'TAOBAO_ORDER_HAS_BEEN_PAID',
  318 + // 'OFFICIAL_WEBSITE_ORDER_HAS_BEEN_PAID',
  319 + // 'WITHHOLDING_ADVANCE_DEPOSIT',
  320 + // 'PLATFORM_SETTLEMENT',
  321 + // 'PAYMENT_RECEIPT',
  322 + // 'PREPAID_NO_NEED_SEND',
  323 + // ].includes(copyData.paymentMethod)
  324 + // ) {
  325 + // copyData.paymentMethod = '';
  326 + // copyData.paymentChannel = '';
  327 + // }
  328 +
310 329 setPaymentMethod(copyData.paymentMethod);
311 330  
312 331 //子订单数据处理:子订单在表单中的命名为list
... ... @@ -418,6 +437,30 @@ export default ({ onClose, data, subOrders, orderOptType }) =&gt; {
418 437 if (optType('add')) {
419 438 form.resetFields(['list']);
420 439 }
  440 +
  441 + // 如果是复制操作,检查销售代码是否为淘宝相关代码
  442 + if (optType('copy')) {
  443 + const salesCode = data?.salesCode;
  444 + const isTaobaoSalesCode = [
  445 + 'TB',
  446 + 'TBC',
  447 + 'HCTB',
  448 + '淘宝',
  449 + 'TAOBAO',
  450 + ].includes(salesCode);
  451 +
  452 + if (isTaobaoSalesCode) {
  453 + // 锁定支付渠道和支付方式,但保留原有值
  454 + setPaymentChannelDisabled(true);
  455 + setPaymentMethodDisabled(true);
  456 +
  457 + // 确保控制台日志
  458 + console.log('复制淘宝订单,锁定支付渠道和支付方式:', {
  459 + paymentChannel: data?.paymentChannel,
  460 + paymentMethod: data?.paymentMethod,
  461 + });
  462 + }
  463 + }
421 464 }, [data]);
422 465  
423 466 /**
... ... @@ -954,9 +997,11 @@ export default ({ onClose, data, subOrders, orderOptType }) =&gt; {
954 997 if (typeof values.erpCustomerId !== 'string') {
955 998 values.erpCustomerId = values.erpCustomerId?.id;
956 999 }
  1000 +
957 1001 values.province = province;
958 1002 values.city = city;
959 1003 values.district = district;
  1004 +
960 1005 // Handle the prepaidUid and privatePocket values for API submission
961 1006 if (
962 1007 values.paymentMethod === 'WITHHOLDING_ADVANCE_DEPOSIT' &&
... ... @@ -1127,8 +1172,67 @@ export default ({ onClose, data, subOrders, orderOptType }) =&gt; {
1127 1172 placeholder="请输入销售代表"
1128 1173 rules={[{ required: true, message: '销售代表必填' }]}
1129 1174 options={salesCodeOptions}
1130   - onChange={(_, option) => {
  1175 + onChange={(value, option) => {
1131 1176 autoFillSalesInfo(option);
  1177 +
  1178 + // 检查是否是特殊的淘宝销售代码
  1179 + const isTaobaoSalesCode = [
  1180 + 'TB',
  1181 + 'TBC',
  1182 + 'HCTB',
  1183 + '淘宝',
  1184 + 'TAOBAO',
  1185 + ].includes(value);
  1186 +
  1187 + // 如果是复制操作且是淘宝销售代码,锁定支付方式和支付渠道,不清空值
  1188 + if (optType('copy') && isTaobaoSalesCode) {
  1189 + // 保留当前的支付渠道和支付方式值,只锁定选择器
  1190 + setPaymentChannelDisabled(true);
  1191 + setPaymentMethodDisabled(true);
  1192 +
  1193 + // 如果当前没有值,则设置默认值
  1194 + const currentPaymentChannel =
  1195 + form.getFieldValue('paymentChannel');
  1196 + if (!currentPaymentChannel) {
  1197 + form.setFieldsValue({ paymentChannel: 'TAOBAO' });
  1198 + }
  1199 +
  1200 + const currentPaymentMethod = form.getFieldValue('paymentMethod');
  1201 + if (!currentPaymentMethod) {
  1202 + form.setFieldsValue({ paymentMethod: 'PAYMENT_IN_ADVANCE' });
  1203 + setPaymentMethod('PAYMENT_IN_ADVANCE');
  1204 + }
  1205 + } else if (!optType('copy')) {
  1206 + // 非复制操作时,清空支付渠道和支付方式
  1207 + form.setFieldsValue({
  1208 + paymentChannel: undefined,
  1209 + paymentMethod: undefined,
  1210 + });
  1211 +
  1212 + // 重置支付渠道和支付方式的禁用状态
  1213 + setPaymentChannelDisabled(false);
  1214 + setPaymentMethodDisabled(false);
  1215 +
  1216 + if (isTaobaoSalesCode) {
  1217 + // 设置支付渠道为淘宝并锁定
  1218 + form.setFieldsValue({ paymentChannel: 'TAOBAO' });
  1219 + setPaymentChannelDisabled(true);
  1220 +
  1221 + // 支付方式默认锁定为预付
  1222 + form.setFieldsValue({ paymentMethod: 'PAYMENT_IN_ADVANCE' });
  1223 + setPaymentMethod('PAYMENT_IN_ADVANCE');
  1224 + setPaymentMethodDisabled(true);
  1225 + } else {
  1226 + // 如果不是淘宝销售代码,解除锁定
  1227 + setPaymentChannelDisabled(false);
  1228 + // 只有当前支付渠道不是扣预存时才解除付款方式的锁定
  1229 + const currentPaymentChannel =
  1230 + form.getFieldValue('paymentChannel');
  1231 + if (currentPaymentChannel !== 'BALANCE') {
  1232 + setPaymentMethodDisabled(false);
  1233 + }
  1234 + }
  1235 + }
1132 1236 }}
1133 1237 disabled={optType('after-sales-check')}
1134 1238 />
... ... @@ -1798,9 +1902,37 @@ export default ({ onClose, data, subOrders, orderOptType }) =&gt; {
1798 1902 width="lg"
1799 1903 key="paymentChannel"
1800 1904 label="支付渠道"
1801   - options={enumToSelect(PAYMENT_CHANNEL_OPTIONS)}
  1905 + options={enumToSelect(PAYMENT_CHANNEL_OPTIONS).map((option) => {
  1906 + // 将淘宝选项设置为禁用状态,使其无法手动选择
  1907 + if (option.value === 'TAOBAO') {
  1908 + return { ...option, disabled: true };
  1909 + }
  1910 + return option;
  1911 + })}
1802 1912 rules={[{ required: true, message: '支付渠道必填' }]}
1803   - disabled={optType('after-sales-check')}
  1913 + disabled={optType('after-sales-check') || paymentChannelDisabled}
  1914 + fieldProps={{
  1915 + style: paymentChannelDisabled ? { backgroundColor: '#f5f5f5' } : {},
  1916 + }}
  1917 + onChange={(val: any) => {
  1918 + // 根据支付渠道设置不同的支付方式
  1919 + if (val === 'BALANCE') {
  1920 + // 支付渠道为扣预存时,支付方式设置为扣预存
  1921 + setPaymentMethodDisabled(true);
  1922 + form.setFieldsValue({
  1923 + paymentMethod: 'WITHHOLDING_ADVANCE_DEPOSIT',
  1924 + });
  1925 + setPaymentMethod('WITHHOLDING_ADVANCE_DEPOSIT');
  1926 + } else if (val === 'TAOBAO') {
  1927 + // 支付渠道为淘宝时,支付方式设置为预付
  1928 + setPaymentMethodDisabled(true);
  1929 + form.setFieldsValue({ paymentMethod: 'PAYMENT_IN_ADVANCE' });
  1930 + setPaymentMethod('PAYMENT_IN_ADVANCE');
  1931 + } else {
  1932 + // 支付渠道修改为其他的去除锁定状态
  1933 + setPaymentMethodDisabled(false);
  1934 + }
  1935 + }}
1804 1936 />
1805 1937 <ProFormSelect
1806 1938 placeholder="请输入支付方式"
... ... @@ -1811,9 +1943,44 @@ export default ({ onClose, data, subOrders, orderOptType }) =&gt; {
1811 1943 onChange={(val: any) => {
1812 1944 setPaymentMethod(val);
1813 1945 }}
1814   - options={enumToSelect(PAYMENT_METHOD_OPTIONS_4_ADD)}
  1946 + options={[
  1947 + // 默认可选项
  1948 + ...enumToSelect(PAYMENT_METHOD_OPTIONS_4_ADD),
  1949 + // 强制禁用项
  1950 + { label: '未付款', value: 'UNPAID', disabled: true },
  1951 + {
  1952 + label: '淘宝订单已付款',
  1953 + value: 'TAOBAO_ORDER_HAS_BEEN_PAID',
  1954 + disabled: true,
  1955 + },
  1956 + {
  1957 + label: '官网已付',
  1958 + value: 'OFFICIAL_WEBSITE_ORDER_HAS_BEEN_PAID',
  1959 + disabled: true,
  1960 + },
  1961 + {
  1962 + label: '淘宝',
  1963 + value: 'PAYMENT_IN_ADVANCE',
  1964 + disabled: true,
  1965 + },
  1966 + {
  1967 + label: '预付',
  1968 + value: 'WITHHOLDING_ADVANCE_DEPOSIT',
  1969 + disabled: true,
  1970 + },
  1971 + { label: '平台结算', value: 'PLATFORM_SETTLEMENT', disabled: true },
  1972 + { label: '已回款', value: 'PAYMENT_RECEIPT', disabled: true },
  1973 + {
  1974 + label: '预存款无需发货',
  1975 + value: 'PREPAID_NO_NEED_SEND',
  1976 + disabled: true,
  1977 + },
  1978 + ]}
1815 1979 rules={[{ required: true, message: '支付方式必填' }]}
1816   - disabled={optType('after-sales-check')}
  1980 + disabled={optType('after-sales-check') || paymentMethodDisabled}
  1981 + fieldProps={{
  1982 + style: paymentMethodDisabled ? { backgroundColor: '#f5f5f5' } : {},
  1983 + }}
1817 1984 />
1818 1985 {/* 隐藏字段用于存储真实UID和privatePocket标志 */}
1819 1986 <ProFormText name="realPrepaidUid" hidden />
... ...
src/pages/Order/OrderList/OrderList.tsx
... ... @@ -2,6 +2,7 @@ import ButtonConfirm from &#39;@/components/ButtomConfirm&#39;;
2 2 import { RESPONSE_CODE } from '@/constants/enum';
3 3 import ImportExpressBillModal from '@/pages/Order/OrderList/ImportExpressBillModal';
4 4 import InvoicingDrawerForm from '@/pages/Order/OrderList/InvoicingDrawerForm';
  5 +import PaymentRecordModal from '@/pages/Order/OrderList/PaymentRecordModal';
5 6 import ReissueModal from '@/pages/Order/OrderList/ReissueModal';
6 7 import ReissueModal_old from '@/pages/Order/OrderList/ReissueModal_old';
7 8 import {
... ... @@ -115,6 +116,7 @@ import FinancialDrawer from &#39;./FinancialDrawer&#39;;
115 116 import FinancialEditDrawer from './FinancialEditDrawer';
116 117 import FinancialMergeDrawer from './FinancialMergeDrawer';
117 118 import FinancialReceiptsModal from './FinancialReceiptsModal';
  119 +import HirePurchaseUploadPayBillModal from './HirePurchaseUploadPayBillModal';
118 120 import HistoryModal from './HistoryModal';
119 121 import ImagesViewerModal from './ImagesViewerModal';
120 122 import ImportModal from './ImportModal';
... ... @@ -147,6 +149,12 @@ const OrderList = ({ paramsNew, searchShow, toolbarShow }) =&gt; {
147 149 const [uploadPayBillModalVisible, setUploadPayBillModalVisible] =
148 150 useState<boolean>(false);
149 151 const [
  152 + hirePurchaseUploadPayBillModalVisible,
  153 + setHirePurchaseUploadPayBillModalVisible,
  154 + ] = useState<boolean>(false);
  155 + const [paymentRecordModalVisible, setPaymentRecordModalVisible] =
  156 + useState<boolean>(false);
  157 + const [
150 158 feedbackRegistrationModalVisible,
151 159 setFeedbackRegistrationModalVisible,
152 160 ] = useState<boolean>(false);
... ... @@ -236,6 +244,22 @@ const OrderList = ({ paramsNew, searchShow, toolbarShow }) =&gt; {
236 244 }, [selectedSubOrderKeys]);
237 245 const [procureNotes, setProcureNotes] = useState<string>('');
238 246 console.log(JSON.stringify(userInfo));
  247 +
  248 + // 付款状态枚举映射
  249 + const getPaymentStatusText = (status: string | undefined): string => {
  250 + if (!status) return '无';
  251 + switch (status) {
  252 + case 'WAIT_PAYMENT':
  253 + return '待付款';
  254 + case 'PARTIAL_PAYMENT':
  255 + return '部分付款';
  256 + case 'COMPLETE_PAYMENT':
  257 + return '已付款';
  258 + default:
  259 + return status;
  260 + }
  261 + };
  262 +
239 263 const triggerRecordOptNode = async (id) => {
240 264 const res = await postServiceOrderGetCurrentOptNode({
241 265 query: {
... ... @@ -1059,6 +1083,15 @@ const OrderList = ({ paramsNew, searchShow, toolbarShow }) =&gt; {
1059 1083 )}
1060 1084 </span>
1061 1085 </div>
  1086 + {/* 回款状态 */}
  1087 + <div className="overflow-hidden overflow-ellipsis whitespace-no-wrap">
  1088 + <span className="text-slate-700">
  1089 + {enumValueToLabel(
  1090 + optRecord.paymentReceiptStatus,
  1091 + PAYMENT_RECEIPTS_STATUS_OPTIONS,
  1092 + )}
  1093 + </span>
  1094 + </div>
1062 1095 {/* 回款审核状态 */}
1063 1096 {optRecord.paymentReceiptStatus !== null ? (
1064 1097 <div className="overflow-hidden overflow-ellipsis whitespace-no-wrap">
... ... @@ -1440,20 +1473,6 @@ const OrderList = ({ paramsNew, searchShow, toolbarShow }) =&gt; {
1440 1473 }}
1441 1474 />
1442 1475 )}
1443   - {optRecord.paths?.includes('uploadPaymentReceiptBill') ? (
1444   - <Button
1445   - className="p-0"
1446   - type="link"
1447   - onClick={() => {
1448   - createOptObject(optRecord.id, record.id);
1449   - setUploadPayBillModalVisible(true);
1450   - }}
1451   - >
1452   - 回款
1453   - </Button>
1454   - ) : (
1455   - ''
1456   - )}
1457 1476  
1458 1477 {optRecord.paths?.includes('confirmReissue_old') ? (
1459 1478 <Button
... ... @@ -1522,22 +1541,6 @@ const OrderList = ({ paramsNew, searchShow, toolbarShow }) =&gt; {
1522 1541 ''
1523 1542 )}
1524 1543  
1525   - {optRecord.paths?.includes('auditPaymentReceipt') ? (
1526   - <Button
1527   - className="p-0"
1528   - type="link"
1529   - onClick={() => {
1530   - createOptObject(optRecord.id, record.id);
1531   - setCheckVisible(true);
1532   - setOrderCheckType(CHECK_TYPE.PAYMENT_RECEIPTS_AUDIT);
1533   - }}
1534   - >
1535   - 回款审核
1536   - </Button>
1537   - ) : (
1538   - ''
1539   - )}
1540   -
1541 1544 {optRecord.paths?.includes('modifiedAuditRequest') ? (
1542 1545 <Button
1543 1546 className="p-0"
... ... @@ -1623,7 +1626,7 @@ const OrderList = ({ paramsNew, searchShow, toolbarShow }) =&gt; {
1623 1626 ) : (
1624 1627 ''
1625 1628 )}
1626   - {optRecord.paths?.includes('saleCancelInvoicing') ? (
  1629 + {/* {optRecord.paths?.includes('saleCancelInvoicing') ? (
1627 1630 <ButtonConfirm
1628 1631 className="p-0"
1629 1632 title="确认取消申请开票?"
... ... @@ -1643,7 +1646,7 @@ const OrderList = ({ paramsNew, searchShow, toolbarShow }) =&gt; {
1643 1646 />
1644 1647 ) : (
1645 1648 ''
1646   - )}
  1649 + )} */}
1647 1650 {optRecord.paths?.includes('noNeedInvoicingEdit') ? (
1648 1651 <Button
1649 1652 className="p-0"
... ... @@ -1841,7 +1844,7 @@ const OrderList = ({ paramsNew, searchShow, toolbarShow }) =&gt; {
1841 1844 ''
1842 1845 )}
1843 1846  
1844   - {optRecord.paths?.includes('invoicing') ? (
  1847 + {/* {optRecord.paths?.includes('invoicing') ? (
1845 1848 <Button
1846 1849 className="p-0"
1847 1850 type="link"
... ... @@ -1856,9 +1859,9 @@ const OrderList = ({ paramsNew, searchShow, toolbarShow }) =&gt; {
1856 1859 </Button>
1857 1860 ) : (
1858 1861 ''
1859   - )}
  1862 + )} */}
1860 1863  
1861   - {optRecord.paths?.includes('applyInvoicing') ? (
  1864 + {/* {optRecord.paths?.includes('applyInvoicing') ? (
1862 1865 <Button
1863 1866 className="p-0"
1864 1867 type="link"
... ... @@ -1873,7 +1876,7 @@ const OrderList = ({ paramsNew, searchShow, toolbarShow }) =&gt; {
1873 1876 </Button>
1874 1877 ) : (
1875 1878 ''
1876   - )}
  1879 + )} */}
1877 1880  
1878 1881 {optRecord.paths?.includes('applyInvoicing_old') ? (
1879 1882 <Button
... ... @@ -2736,6 +2739,42 @@ const OrderList = ({ paramsNew, searchShow, toolbarShow }) =&gt; {
2736 2739  
2737 2740 {roleCode === 'finance' ? <Divider type="vertical" /> : ''}
2738 2741  
  2742 + {/* 添加付款审核状态 */}
  2743 + <div>
  2744 + <span className="text-[#8C8C8C]">付款状态:</span>
  2745 + <span className="text-slate-700">
  2746 + {getPaymentStatusText(record.paymentAuditStatus)}
  2747 + </span>
  2748 + </div>
  2749 + <Divider type="vertical" />
  2750 +
  2751 + {/* 添加已回款金额 */}
  2752 + <div>
  2753 + <span className="text-[#8C8C8C]">已回款金额:¥</span>
  2754 + <span className="text-slate-700">
  2755 + {record.payedMoney || '0.00'}
  2756 + </span>
  2757 + </div>
  2758 + <Divider type="vertical" />
  2759 +
  2760 + {/* 添加未回款金额 */}
  2761 + <div>
  2762 + <span className="text-[#8C8C8C]">未回款金额:¥</span>
  2763 + <span className="text-slate-700">
  2764 + {record.unPayedMoney || '0.00'}
  2765 + </span>
  2766 + </div>
  2767 + <Divider type="vertical" />
  2768 +
  2769 + {/* 添加发票核销金额 */}
  2770 + <div>
  2771 + <span className="text-[#8C8C8C]">发票核销金额:¥</span>
  2772 + <span className="text-slate-700">
  2773 + {record.invoiceMoney || '0.00'}
  2774 + </span>
  2775 + </div>
  2776 + <Divider type="vertical" />
  2777 +
2739 2778 <div title={record.notes}>
2740 2779 <div
2741 2780 className="max-w-[850px] whitespace-normal overflow-hidden overflow-ellipsis hover:cursor-pointer"
... ... @@ -2957,6 +2996,55 @@ const OrderList = ({ paramsNew, searchShow, toolbarShow }) =&gt; {
2957 2996 ) : (
2958 2997 ''
2959 2998 )}
  2999 + {record.paths?.includes('updateHirePurchase') ? (
  3000 + <Button
  3001 + className="p-0"
  3002 + type="link"
  3003 + onClick={() => {
  3004 + createOptObject(record.id, record.id);
  3005 + setHirePurchaseUploadPayBillModalVisible(true);
  3006 + }}
  3007 + >
  3008 + 回款
  3009 + </Button>
  3010 + ) : (
  3011 + ''
  3012 + )}
  3013 +
  3014 + {record.paths?.includes('refundHistory') ? (
  3015 + <Button
  3016 + className="p-0"
  3017 + type="link"
  3018 + onClick={() => {
  3019 + createOptObject(record.id, record.id);
  3020 + setPaymentRecordModalVisible(true);
  3021 + }}
  3022 + >
  3023 + 付款记录
  3024 + </Button>
  3025 + ) : (
  3026 + ''
  3027 + )}
  3028 +
  3029 + {/* 输出日志以检查权限和支付方式 */}
  3030 + {console.log('Order info:', record.id, record.paths)}
  3031 + {record.paths?.includes('auditPartialPaymentReceipt') ? (
  3032 + <Button
  3033 + className="p-0"
  3034 + type="link"
  3035 + onClick={() => {
  3036 + createOptObject(null, record.id);
  3037 + setCheckVisible(true);
  3038 + setOrderCheckType(
  3039 + CHECK_TYPE.PARTIAL_PAYMENT_RECEIPTS_AUDIT,
  3040 + );
  3041 + }}
  3042 + >
  3043 + 回款审核
  3044 + </Button>
  3045 + ) : (
  3046 + ''
  3047 + )}
2960 3048  
2961 3049 {record.paths?.includes('modifiedAuditRequest') ? (
2962 3050 <Button
... ... @@ -2990,6 +3078,8 @@ const OrderList = ({ paramsNew, searchShow, toolbarShow }) =&gt; {
2990 3078 ''
2991 3079 )}
2992 3080  
  3081 + {/* 第二个回款审核(分期)按钮已被移除,使用上面的带权限检查的按钮 */}
  3082 +
2993 3083 {record.paths?.includes('modifiedLeaderAuditRequest') ? (
2994 3084 <Button
2995 3085 className="p-0"
... ... @@ -3135,6 +3225,36 @@ const OrderList = ({ paramsNew, searchShow, toolbarShow }) =&gt; {
3135 3225 ) : (
3136 3226 ''
3137 3227 )}
  3228 + {record.paths?.includes('saleCancelInvoicing') ? (
  3229 + <ButtonConfirm
  3230 + className="p-0"
  3231 + title="确认取消申请开票?"
  3232 + text="取消申请(新)"
  3233 + onConfirm={async () => {
  3234 + let selectedSubOrders = subOrderSelectedMap.get(
  3235 + record.id,
  3236 + );
  3237 + if (selectedSubOrders === undefined) {
  3238 + selectedSubOrders = record.subOrderInformationLists;
  3239 + }
  3240 + let subOrderIds = selectedSubOrders.map(
  3241 + (item) => item.id,
  3242 + );
  3243 + let res = await postServiceInvoiceCancelApply({
  3244 + data: {
  3245 + subOrderIds: subOrderIds,
  3246 + },
  3247 + });
  3248 +
  3249 + if (res && res.result === RESPONSE_CODE.SUCCESS) {
  3250 + message.success(res.message);
  3251 + refreshTable();
  3252 + }
  3253 + }}
  3254 + />
  3255 + ) : (
  3256 + ''
  3257 + )}
3138 3258  
3139 3259 {record.paths?.includes('leaderAudit') ? (
3140 3260 <Button
... ... @@ -5302,6 +5422,38 @@ const OrderList = ({ paramsNew, searchShow, toolbarShow }) =&gt; {
5302 5422 }}
5303 5423 />
5304 5424 )}
  5425 +
  5426 + {hirePurchaseUploadPayBillModalVisible && data && currentOptMainId && (
  5427 + <HirePurchaseUploadPayBillModal
  5428 + visible={hirePurchaseUploadPayBillModalVisible}
  5429 + onCancel={() => {
  5430 + setHirePurchaseUploadPayBillModalVisible(false);
  5431 + clearOptObject();
  5432 + }}
  5433 + onOk={() => {
  5434 + setHirePurchaseUploadPayBillModalVisible(false);
  5435 + message.success('回款凭证上传成功');
  5436 + refreshTable();
  5437 + }}
  5438 + record={data.find((item) => item.id === currentOptMainId) || {}}
  5439 + subOrders={
  5440 + data.find((item) => item.id === currentOptMainId)
  5441 + ?.subOrderInformationLists || []
  5442 + }
  5443 + />
  5444 + )}
  5445 +
  5446 + {paymentRecordModalVisible && currentOptMainId && (
  5447 + <PaymentRecordModal
  5448 + visible={paymentRecordModalVisible}
  5449 + mainOrderId={currentOptMainId}
  5450 + onClose={() => {
  5451 + setPaymentRecordModalVisible(false);
  5452 + clearOptObject();
  5453 + }}
  5454 + />
  5455 + )}
  5456 +
5305 5457 {feedbackRegistrationModalVisible && (
5306 5458 <FeedbackRegistrationModal
5307 5459 setVisible={(val: boolean) => {
... ...
src/pages/Order/OrderList/PaymentRecordModal.tsx 0 → 100644
  1 +import { postServiceOrderRefundHistory } from '@/services';
  2 +import { Button, Empty, Image, Modal } from 'antd';
  3 +import React, { useEffect, useState } from 'react';
  4 +
  5 +interface PaymentRecordModalProps {
  6 + visible: boolean;
  7 + mainOrderId: number;
  8 + onClose: () => void;
  9 +}
  10 +
  11 +interface PaymentRecord {
  12 + id: number;
  13 + mainOrderId: number;
  14 + refundMoney: number;
  15 + createTime: string;
  16 + annex: string;
  17 + isAudit: number;
  18 + isDel: number;
  19 + updateTime: string | null;
  20 + paymentReceiptAnnexPartial: string | null;
  21 +}
  22 +
  23 +const PaymentRecordModal: React.FC<PaymentRecordModalProps> = ({
  24 + visible,
  25 + mainOrderId,
  26 + onClose,
  27 +}) => {
  28 + const [paymentRecords, setPaymentRecords] = useState<PaymentRecord[]>([]);
  29 +
  30 + const fetchPaymentRecords = async () => {
  31 + if (!mainOrderId) return;
  32 +
  33 + try {
  34 + const response = await postServiceOrderRefundHistory({
  35 + data: { mainOrderId },
  36 + });
  37 +
  38 + if (response.result === 0 && response.data) {
  39 + setPaymentRecords(response.data);
  40 + } else {
  41 + setPaymentRecords([]);
  42 + }
  43 + } catch (error) {
  44 + console.error('Failed to fetch payment records:', error);
  45 + setPaymentRecords([]);
  46 + }
  47 + };
  48 +
  49 + useEffect(() => {
  50 + if (visible && mainOrderId) {
  51 + fetchPaymentRecords();
  52 + }
  53 + }, [visible, mainOrderId]);
  54 +
  55 + const parseAnnex = (annexString: string): string[] => {
  56 + try {
  57 + const parsed = JSON.parse(annexString);
  58 + return parsed.map((item: { url: string }) => item.url);
  59 + } catch (e) {
  60 + console.error('Failed to parse annex:', e);
  61 + return [];
  62 + }
  63 + };
  64 +
  65 + return (
  66 + <Modal
  67 + title="付款记录"
  68 + open={visible}
  69 + onCancel={onClose}
  70 + footer={[
  71 + <Button key="close" onClick={onClose}>
  72 + 关闭
  73 + </Button>,
  74 + ]}
  75 + width={500}
  76 + >
  77 + <div className="payment-record-container">
  78 + {paymentRecords.length > 0 ? (
  79 + paymentRecords.map((record, index) => {
  80 + const imageUrls = record.annex ? parseAnnex(record.annex) : [];
  81 +
  82 + return (
  83 + <div key={record.id} className="payment-record-item">
  84 + <div className="payment-record-header">
  85 + {index < paymentRecords.length - 1 && (
  86 + <div className="payment-record-line" />
  87 + )}
  88 + <div className="payment-record-circle" />
  89 + </div>
  90 + <div className="payment-record-content">
  91 + <div className="payment-record-info">
  92 + <p>
  93 + <strong>提交时间:</strong> {record.createTime}
  94 + </p>
  95 + <p>
  96 + <strong>付款金额:</strong>{' '}
  97 + {record.refundMoney.toFixed(2)}
  98 + </p>
  99 + {imageUrls.length > 0 && (
  100 + <p>
  101 + <strong>付款凭证:</strong>
  102 + </p>
  103 + )}
  104 + </div>
  105 + {imageUrls.length > 0 && (
  106 + <div className="payment-record-images">
  107 + <Image.PreviewGroup>
  108 + {imageUrls.map((url, imgIndex) => (
  109 + <Image
  110 + key={imgIndex}
  111 + width={120}
  112 + src={url}
  113 + className="payment-record-image"
  114 + />
  115 + ))}
  116 + </Image.PreviewGroup>
  117 + </div>
  118 + )}
  119 + </div>
  120 + </div>
  121 + );
  122 + })
  123 + ) : (
  124 + <Empty description="暂无付款记录" className="payment-record-empty" />
  125 + )}
  126 + </div>
  127 + </Modal>
  128 + );
  129 +};
  130 +
  131 +export default PaymentRecordModal;
... ...
src/pages/Order/OrderList/UploadPayBillModal.tsx
... ... @@ -216,10 +216,24 @@ export default ({ setVisible, subOrders, mainOrder, onClose }) =&gt; {
216 216 }}
217 217 onOpenChange={setVisible}
218 218 >
219   - <div className="pb-4 text-xs decoration-gray-50">可复制照片粘贴</div>
220   - <Upload {...props}>
221   - {fileList.length < COMFIR_RECEIPT_IMAGES_NUMBER ? uploadButton : ''}
222   - </Upload>
  219 + <div className="pb-4 text-base font-medium">
  220 + 付款金额:¥{mainOrder?.totalPayment?.toLocaleString() || '0.00'}
  221 + </div>
  222 + <div className="flex items-start pb-4 text-base font-medium">
  223 + <div>付款凭证:</div>
  224 +
  225 + <div className="flex flex-col items-start ml-2">
  226 + <div className="mb-1 text-xs decoration-gray-50">
  227 + 可复制照片粘贴
  228 + </div>
  229 +
  230 + <Upload {...props}>
  231 + {fileList.length < COMFIR_RECEIPT_IMAGES_NUMBER
  232 + ? uploadButton
  233 + : null}
  234 + </Upload>
  235 + </div>
  236 + </div>
223 237 </ModalForm>
224 238  
225 239 <Modal
... ...
src/pages/Order/OrderList/index.css
... ... @@ -2,6 +2,14 @@
2 2 margin-inline: 0 !important;
3 3 }
4 4  
  5 +.order-page-container .ant-table-cell {
  6 + word-break: break-word;
  7 + white-space: normal !important;
  8 + overflow: hidden;
  9 + max-width: 500px;
  10 + box-sizing: border-box;
  11 +}
  12 +
5 13 .order-page-container td {
6 14 font-family: 'San Francisco', 'Helvetica Neue', Helvetica, Arial,
7 15 'Microsoft YaHei', 'PingFang SC', 'Hiragino Sans GB', 'Heiti SC',
... ... @@ -53,6 +61,8 @@
53 61 .order-page-container .ant-table-thead .ant-table-cell {
54 62 background-color: #fff !important;
55 63 border-radius: 8px !important;
  64 + overflow: hidden;
  65 + white-space: normal !important;
56 66 }
57 67  
58 68 #sub-table tbody td {
... ... @@ -98,3 +108,78 @@
98 108  
99 109 /* 设置行与行之间分割线的颜色 */
100 110 }
  111 +
  112 +/* 付款记录样式 */
  113 +.payment-record-container {
  114 + padding: 10px 0;
  115 +}
  116 +
  117 +.payment-record-item {
  118 + position: relative;
  119 + display: flex;
  120 + margin-bottom: 16px;
  121 +}
  122 +
  123 +.payment-record-header {
  124 + position: relative;
  125 + width: 24px;
  126 + margin-right: 12px;
  127 +}
  128 +
  129 +.payment-record-line {
  130 + position: absolute;
  131 + top: 0;
  132 + bottom: 0;
  133 + left: 50%;
  134 + width: 1px;
  135 + background-color: #e8e8e8;
  136 + transform: translateX(-50%);
  137 + z-index: 1;
  138 +}
  139 +
  140 +.payment-record-circle {
  141 + position: absolute;
  142 + top: 12px;
  143 + left: 50%;
  144 + width: 12px;
  145 + height: 12px;
  146 + background-color: #d4b106;
  147 + border-radius: 50%;
  148 + transform: translateX(-50%);
  149 + z-index: 2;
  150 +}
  151 +
  152 +.payment-record-content {
  153 + flex: 1;
  154 + background-color: #f5f5f5;
  155 + border-radius: 8px;
  156 + padding: 12px 16px;
  157 +}
  158 +
  159 +.payment-record-info p {
  160 + margin-bottom: 8px;
  161 +}
  162 +
  163 +.payment-record-images {
  164 + display: flex;
  165 + flex-wrap: wrap;
  166 + gap: 8px;
  167 + margin-top: 8px;
  168 +}
  169 +
  170 +.payment-record-image {
  171 + border: 1px solid #e8e8e8;
  172 + border-radius: 4px;
  173 +}
  174 +
  175 +.payment-record-divider {
  176 + height: 1px;
  177 + background-color: #e8e8e8;
  178 + margin: 16px 0;
  179 +}
  180 +
  181 +.payment-record-empty {
  182 + text-align: center;
  183 + color: #999;
  184 + padding: 20px 0;
  185 +}
... ...
src/pages/Order/OrderList/index.less
... ... @@ -106,3 +106,78 @@
106 106 // .order-tooltip .ant-tooltip-inner{
107 107 // color: black !important;
108 108 // }
  109 +
  110 +/* 付款记录样式 */
  111 +.payment-record-container {
  112 + padding: 10px 0;
  113 +}
  114 +
  115 +.payment-record-item {
  116 + position: relative;
  117 + display: flex;
  118 + margin-bottom: 16px;
  119 +}
  120 +
  121 +.payment-record-header {
  122 + position: relative;
  123 + width: 24px;
  124 + margin-right: 12px;
  125 +}
  126 +
  127 +.payment-record-line {
  128 + position: absolute;
  129 + top: 0;
  130 + bottom: 0;
  131 + left: 50%;
  132 + width: 1px;
  133 + background-color: #e8e8e8;
  134 + transform: translateX(-50%);
  135 + z-index: 1;
  136 +}
  137 +
  138 +.payment-record-circle {
  139 + position: absolute;
  140 + top: 12px;
  141 + left: 50%;
  142 + width: 12px;
  143 + height: 12px;
  144 + background-color: #d4b106;
  145 + border-radius: 50%;
  146 + transform: translateX(-50%);
  147 + z-index: 2;
  148 +}
  149 +
  150 +.payment-record-content {
  151 + flex: 1;
  152 + background-color: #f5f5f5;
  153 + border-radius: 8px;
  154 + padding: 12px 16px;
  155 +}
  156 +
  157 +.payment-record-info p {
  158 + margin-bottom: 8px;
  159 +}
  160 +
  161 +.payment-record-images {
  162 + display: flex;
  163 + flex-wrap: wrap;
  164 + gap: 8px;
  165 + margin-top: 8px;
  166 +}
  167 +
  168 +.payment-record-image {
  169 + border: 1px solid #e8e8e8;
  170 + border-radius: 4px;
  171 +}
  172 +
  173 +.payment-record-divider {
  174 + height: 1px;
  175 + background-color: #e8e8e8;
  176 + margin: 16px 0;
  177 +}
  178 +
  179 +.payment-record-empty {
  180 + text-align: center;
  181 + color: #999;
  182 + padding: 20px 0;
  183 +}
... ...
src/pages/Order/constant.ts
... ... @@ -7,11 +7,13 @@ import { getReceivingCompanyOptions, isSupplier } from &#39;@/utils/order&#39;;
7 7 export const COMFIR_RECEIPT_IMAGES_NUMBER = 3;
8 8  
9 9 export const PAYMENT_CHANNEL_OPTIONS = {
10   - ALIPAY: '支付宝',
11   - WECHAT: '微信',
12 10 BANK_TRANSFER: '银行转账',
13   - BALANCE: '预存款',
14   - OFFLINE: '线下付款',
  11 + WECHAT: '微信支付',
  12 + ALIPAY: '支付宝支付',
  13 + BALANCE: '扣预存',
  14 + PLATFORM: '平台结算',
  15 + OFFLINE: '线下支付',
  16 + TAOBAO: '淘宝已付',
15 17 };
16 18  
17 19 export const RECEIPTS_RECORD_TYPES = {
... ... @@ -26,7 +28,7 @@ export const PAYMENT_METHOD_OPTIONS = {
26 28 TAOBAO_ORDER_HAS_BEEN_PAID: '淘宝订单已付款',
27 29 OFFICIAL_WEBSITE_ORDER_HAS_BEEN_PAID: '官网订单已付款',
28 30 PAYMENT_IN_ADVANCE: '预付款',
29   - WITHHOLDING_ADVANCE_DEPOSIT: '扣预存',
  31 + WITHHOLDING_ADVANCE_DEPOSIT: '预付',
30 32 PLATFORM_SETTLEMENT: '平台结算',
31 33 CASH_ON_DELIVERY: '货到付款',
32 34 HIRE_PURCHASE: '分期付款',
... ... @@ -35,15 +37,9 @@ export const PAYMENT_METHOD_OPTIONS = {
35 37 };
36 38  
37 39 export const PAYMENT_METHOD_OPTIONS_4_ADD = {
38   - UNPAID: '未付款',
39   - TAOBAO_ORDER_HAS_BEEN_PAID: '淘宝订单已付款',
40   - OFFICIAL_WEBSITE_ORDER_HAS_BEEN_PAID: '官网订单已付款',
41   - PAYMENT_IN_ADVANCE: '预付款',
42   - WITHHOLDING_ADVANCE_DEPOSIT: '扣预存',
43   - PLATFORM_SETTLEMENT: '平台结算',
  40 + PAYMENT_IN_ADVANCE: '预付',
44 41 CASH_ON_DELIVERY: '货到付款',
45 42 HIRE_PURCHASE: '分期付款',
46   - PREPAID_NO_NEED_SEND: '预存款无需发货',
47 43 };
48 44  
49 45 export const PRODUCT_BELONG_DEPARTMENT_OPTIONS = {
... ... @@ -125,6 +121,7 @@ export const CHECK_TYPE = {
125 121 URGENT_INVOICE_AUDITING: 'URGENT_INVOICE_AUDITING',
126 122 URGENT_INVOICE_AUDITING_OLD: 'URGENT_INVOICE_AUDITING_OLD',
127 123 PAYMENT_RECEIPTS_AUDIT: 'PAYMENT_RECEIPTS_AUDIT',
  124 + PARTIAL_PAYMENT_RECEIPTS_AUDIT: 'PARTIAL_PAYMENT_RECEIPTS_AUDIT',
128 125 CONFIRM_REISSUE: 'CONFIRM_REISSUE',
129 126 CONFIRM_REISSUE_OLD: 'CONFIRM_REISSUE_OLD',
130 127 PREPAID_AUDIT: 'PREPAID_AUDIT',
... ... @@ -193,9 +190,11 @@ export const POST_AUDIT_OPTIONS = {
193 190 };
194 191  
195 192 export const PAYMENT_RECEIPTS_STATUS_OPTIONS = {
196   - WAIT_AUDIT: '回款待审核',
197   - AUDIT_PASS: '回款已审核',
198   - AUDIT_NOTPASS: '回款审核失败',
  193 + WAIT_AUDIT: '审核中',
  194 + AUDIT_PASS: '审核通过',
  195 + AUDIT_NOTPASS: '未通过',
  196 + NOT_RECEIVED: '待提交',
  197 + PARTIAL_RECEIVED: '待提交',
199 198 };
200 199  
201 200 export const ORDER_STATUS_OPTIONS = {
... ...
src/services/definition.ts
... ... @@ -1556,32 +1556,6 @@ export interface ExchangeRecordsRequestDto {
1556 1556 total?: number;
1557 1557 }
1558 1558  
1559   -export interface File {
1560   - absolute?: boolean;
1561   - absoluteFile?: File;
1562   - absolutePath?: string;
1563   - canonicalFile?: File;
1564   - canonicalPath?: string;
1565   - directory?: boolean;
1566   - executable?: boolean;
1567   - file?: boolean;
1568   - /** @format int64 */
1569   - freeSpace?: number;
1570   - hidden?: boolean;
1571   - /** @format int64 */
1572   - lastModified?: number;
1573   - name?: string;
1574   - parent?: string;
1575   - parentFile?: File;
1576   - path?: string;
1577   - readable?: boolean;
1578   - /** @format int64 */
1579   - totalSpace?: number;
1580   - /** @format int64 */
1581   - usableSpace?: number;
1582   - writable?: boolean;
1583   -}
1584   -
1585 1559 export interface FilePathDto {
1586 1560 url?: string;
1587 1561 }
... ... @@ -1613,6 +1587,29 @@ export interface GroupExchangeRecordsRequestDto {
1613 1587  
1614 1588 export type InputStream = any;
1615 1589  
  1590 +export interface InstallmentPaymentDTO {
  1591 + /**
  1592 + * @description
  1593 + * 回款单
  1594 + */
  1595 + filePaths?: Array<FilePathDto>;
  1596 + /**
  1597 + * @description
  1598 + * 分期付款备注
  1599 + */
  1600 + installmentComment?: string;
  1601 + /**
  1602 + * @description
  1603 + * 分期付款金额
  1604 + */
  1605 + installmentMoney?: number;
  1606 + /**
  1607 + * @description
  1608 + * 子订单id
  1609 + */
  1610 + subOrderIds?: Array<number>;
  1611 +}
  1612 +
1616 1613 export interface InventoryMaterialStockReq {
1617 1614 auxPropId?: string;
1618 1615 isShowStockPosition?: boolean;
... ... @@ -4282,7 +4279,7 @@ export interface ResetPwdVO {
4282 4279  
4283 4280 export interface Resource {
4284 4281 description?: string;
4285   - file?: File;
  4282 + file?: TsgFile;
4286 4283 filename?: string;
4287 4284 inputStream?: InputStream;
4288 4285 open?: boolean;
... ... @@ -4403,6 +4400,7 @@ export interface SubOrder {
4403 4400 paymentChannel?: string;
4404 4401 paymentMethod?: string;
4405 4402 paymentReceiptAnnex?: string;
  4403 + paymentReceiptAnnexPartial?: string;
4406 4404 paymentReceiptNotes?: string;
4407 4405 paymentReceiptStatus?: string;
4408 4406 paymentStatus?: string;
... ... @@ -4904,6 +4902,11 @@ export interface UserPrivatePocketBalanceUpdateRequest {
4904 4902 * @format int32
4905 4903 */
4906 4904 uid?: number;
  4905 + /**
  4906 + * @description
  4907 + * 修改人
  4908 + */
  4909 + updateBy?: string;
4907 4910 }
4908 4911  
4909 4912 export interface UserPrivatePocketDeleteRequest {
... ... @@ -5138,6 +5141,32 @@ export interface CompanyInfo {
5138 5141 taxIdIsNotNull?: boolean;
5139 5142 }
5140 5143  
  5144 +export interface TsgFile {
  5145 + absolute?: boolean;
  5146 + absoluteFile?: TsgFile;
  5147 + absolutePath?: string;
  5148 + canonicalFile?: TsgFile;
  5149 + canonicalPath?: string;
  5150 + directory?: boolean;
  5151 + executable?: boolean;
  5152 + file?: boolean;
  5153 + /** @format int64 */
  5154 + freeSpace?: number;
  5155 + hidden?: boolean;
  5156 + /** @format int64 */
  5157 + lastModified?: number;
  5158 + name?: string;
  5159 + parent?: string;
  5160 + parentFile?: TsgFile;
  5161 + path?: string;
  5162 + readable?: boolean;
  5163 + /** @format int64 */
  5164 + totalSpace?: number;
  5165 + /** @format int64 */
  5166 + usableSpace?: number;
  5167 + writable?: boolean;
  5168 +}
  5169 +
5141 5170 export interface InvoiceDetail {
5142 5171 createByName?: string;
5143 5172 /** @format date-time */
... ...
src/services/request.ts
... ... @@ -60,6 +60,7 @@ import type {
60 60 ExchangeRecordsRequestDto,
61 61 FeedbackRegistrationDTO,
62 62 GroupExchangeRecordsRequestDto,
  63 + InstallmentPaymentDTO,
63 64 InventoryMaterialStockReq,
64 65 InvoiceBatchDownloadDto,
65 66 InvoiceDto,
... ... @@ -23367,6 +23368,77 @@ export const postServiceOrderGetReissueInfo = /* #__PURE__ */ (() =&gt; {
23367 23368 return request;
23368 23369 })();
23369 23370  
  23371 +/** @description request parameter type for postServiceOrderHirePurchase */
  23372 +export interface PostServiceOrderHirePurchaseOption {
  23373 + /**
  23374 + * @description
  23375 + * dto
  23376 + */
  23377 + body: {
  23378 + /**
  23379 + @description
  23380 + dto */
  23381 + dto: InstallmentPaymentDTO;
  23382 + };
  23383 +}
  23384 +
  23385 +/** @description response type for postServiceOrderHirePurchase */
  23386 +export interface PostServiceOrderHirePurchaseResponse {
  23387 + /**
  23388 + * @description
  23389 + * OK
  23390 + */
  23391 + 200: ServerResult;
  23392 + /**
  23393 + * @description
  23394 + * Created
  23395 + */
  23396 + 201: any;
  23397 + /**
  23398 + * @description
  23399 + * Unauthorized
  23400 + */
  23401 + 401: any;
  23402 + /**
  23403 + * @description
  23404 + * Forbidden
  23405 + */
  23406 + 403: any;
  23407 + /**
  23408 + * @description
  23409 + * Not Found
  23410 + */
  23411 + 404: any;
  23412 +}
  23413 +
  23414 +export type PostServiceOrderHirePurchaseResponseSuccess =
  23415 + PostServiceOrderHirePurchaseResponse[200];
  23416 +/**
  23417 + * @description
  23418 + * 分期付款
  23419 + * @tags 内部订单
  23420 + * @produces *
  23421 + * @consumes application/json
  23422 + */
  23423 +export const postServiceOrderHirePurchase = /* #__PURE__ */ (() => {
  23424 + const method = 'post';
  23425 + const url = '/service/order/hirePurchase';
  23426 + function request(
  23427 + option: PostServiceOrderHirePurchaseOption,
  23428 + ): Promise<PostServiceOrderHirePurchaseResponseSuccess> {
  23429 + return requester(request.url, {
  23430 + method: request.method,
  23431 + ...option,
  23432 + }) as unknown as Promise<PostServiceOrderHirePurchaseResponseSuccess>;
  23433 + }
  23434 +
  23435 + /** http method */
  23436 + request.method = method;
  23437 + /** request url */
  23438 + request.url = url;
  23439 + return request;
  23440 +})();
  23441 +
23370 23442 /** @description request parameter type for postServiceOrderImportExcel */
23371 23443 export interface PostServiceOrderImportExcelOption {
23372 23444 /**
... ... @@ -25818,6 +25890,77 @@ export const postServiceOrderQuerySupplier = /* #__PURE__ */ (() =&gt; {
25818 25890 return request;
25819 25891 })();
25820 25892  
  25893 +/** @description request parameter type for postServiceOrderRefundHistory */
  25894 +export interface PostServiceOrderRefundHistoryOption {
  25895 + /**
  25896 + * @description
  25897 + * mainOrderId
  25898 + */
  25899 + body: {
  25900 + /**
  25901 + @description
  25902 + mainOrderId */
  25903 + mainOrderId: number;
  25904 + };
  25905 +}
  25906 +
  25907 +/** @description response type for postServiceOrderRefundHistory */
  25908 +export interface PostServiceOrderRefundHistoryResponse {
  25909 + /**
  25910 + * @description
  25911 + * OK
  25912 + */
  25913 + 200: ServerResult;
  25914 + /**
  25915 + * @description
  25916 + * Created
  25917 + */
  25918 + 201: any;
  25919 + /**
  25920 + * @description
  25921 + * Unauthorized
  25922 + */
  25923 + 401: any;
  25924 + /**
  25925 + * @description
  25926 + * Forbidden
  25927 + */
  25928 + 403: any;
  25929 + /**
  25930 + * @description
  25931 + * Not Found
  25932 + */
  25933 + 404: any;
  25934 +}
  25935 +
  25936 +export type PostServiceOrderRefundHistoryResponseSuccess =
  25937 + PostServiceOrderRefundHistoryResponse[200];
  25938 +/**
  25939 + * @description
  25940 + * 根据主订单ID查询退款历史记录
  25941 + * @tags 内部订单
  25942 + * @produces *
  25943 + * @consumes application/json
  25944 + */
  25945 +export const postServiceOrderRefundHistory = /* #__PURE__ */ (() => {
  25946 + const method = 'post';
  25947 + const url = '/service/order/refundHistory';
  25948 + function request(
  25949 + option: PostServiceOrderRefundHistoryOption,
  25950 + ): Promise<PostServiceOrderRefundHistoryResponseSuccess> {
  25951 + return requester(request.url, {
  25952 + method: request.method,
  25953 + ...option,
  25954 + }) as unknown as Promise<PostServiceOrderRefundHistoryResponseSuccess>;
  25955 + }
  25956 +
  25957 + /** http method */
  25958 + request.method = method;
  25959 + /** request url */
  25960 + request.url = url;
  25961 + return request;
  25962 +})();
  25963 +
25821 25964 /** @description request parameter type for postServiceOrderRemindShipping */
25822 25965 export interface PostServiceOrderRemindShippingOption {
25823 25966 /**
... ...