Commit 768fbcceeccc357770a46a82cde7fd9003bdfa27

Authored by 曾国涛
1 parent ea6f0208

feat(invoice): optimize invoice components and enhance user experience

- 重构Client页面表格组件,文件重命名为AllRecordTable.tsx,优化表格项显示
- 修改发票类型显示名称,增加文本复制功能,提升用户交互体验
- 移除部分不必要组件和代码,简化页面结构,提高代码可维护性- 修正InvoiceModal组件中submitter属性,改进页面提交逻辑- 优化InvoiceRecordDetailModal组件,简化订单号显示方式,增加复制功能
- 调整InvoicingModal和ManualInvoicingModal组件,移除冗余的select和list组件
-增加pageSizeOptions配置,提供分页大小选择,改善数据浏览体验
- 修复Invoice组件中开票日期显示格式问题,统一数据展示样式
- 优化Order组件中的按钮权限判断逻辑,提升页面响应性
- 删除不再使用的enumToSelect函数,精简代码依赖
- 修正InvoicingDrawerForm组件中产品名称复制功能的实现
- 优化表单验证逻辑,增强数据校验的准确性和用户体验

通过这些改动,- 实现导出客户信息为Excel文件的功能。
- 使用useMessage钩子来管理Ant Design消息提示。
- 添加单元格操作按钮,包括查看沟通历史、详情和编辑客户信息。
- 组件使用了editable、columnsState和form等高级特性,以提供更好的用户体验和数据管理。

通过这个提交,我们完成了客户记录的表格展示页面,实现了数据的查询、筛选、导出及一些基本操作,提升了项目的业务功能完备性。"增加客户统计信息和调整客户端表格布局"模块结构以支持核销功能本次更新主要涉及发票相关组件及页面的重构,以支持新的核销功能。具体变更包括:

- 重命名并移动了多个与发票核销相关的组件,以便于在新的`InvoiceVerification`目录中集中管理。
- 对`InvoiceVerificationModal`进行了清理,并更新了相关的导入路径。
- 移除了未使用的常量导入和组件,以简化代码并提高可维护性。- 更新了`index.tsx`中的导入路径,以确保正确引入新的组件和常量。
- 修改了`constant.tsx`中的部分导出,以适应新的核销功能。

此次重构旨在为系统引入核销功能,提高发票管理的灵活性和效率。通过整理和更新代码结构,也使得代码更加清晰,便于后续的维护和开发。```
Showing 44 changed files with 4937 additions and 937 deletions
.umirc.ts
... ... @@ -53,24 +53,40 @@ export default defineConfig({
53 53 },
54 54 {
55 55 name: '发票管理',
56   - path: '/invoiceManage',
57   - component: './Invoice',
58   - icon: 'BookOutlined',
59   - access: 'canReadAdminAndFinance',
60   - },
61   - /*{
62   - name: '发票管理',
63 56 path: '/Invoice',
64 57 icon: 'BookOutlined',
65   - access: 'canReadAdminAndFinance',
66   - routes:[
  58 + access: 'canReadAdminAndFinanceAndSales',
  59 + routes: [
67 60 {
68   - name: '权限管理',
69   - path: 'authrity',
  61 + name: '待开票',
  62 + path: 'waitProcessRecord',
70 63 icon: 'BookOutlined',
71   - component: './Invoice/InvoiceRecord' },
72   - ]
73   - },*/
  64 + access: 'canReadAdminAndFinance',
  65 + component: './Invoice/waitProcessRecord',
  66 + },
  67 + {
  68 + name: '开票记录',
  69 + path: 'invoiceRecord',
  70 + icon: 'BookOutlined',
  71 + access: 'canReadAdminAndFinanceAndSales',
  72 + component: './Invoice/InvoiceRecord',
  73 + },
  74 + {
  75 + name: '发票管理',
  76 + path: 'invoice',
  77 + icon: 'BookOutlined',
  78 + access: 'canReadAdminAndFinance',
  79 + component: './Invoice/Invoice',
  80 + },
  81 + {
  82 + name: '发票核销',
  83 + path: 'invoiceVerification',
  84 + icon: 'BookOutlined',
  85 + access: 'canReadAdminAndFinance',
  86 + component: './Invoice/InvoiceVerification',
  87 + },
  88 + ],
  89 + },
74 90  
75 91 {
76 92 name: '预存管理',
... ...
src/pages/Invoice/components/AddInvoiceDrawerForm.tsx renamed to src/pages/Invoice/Invoice/components/AddInvoiceDrawerForm.tsx
src/pages/Invoice/components/BankChooseModal.tsx renamed to src/pages/Invoice/Invoice/components/BankChooseModal.tsx
... ... @@ -11,7 +11,7 @@ import { formatDate } from '@/utils/time';
11 11 import { ActionType, ProCard, ProTable } from '@ant-design/pro-components';
12 12 import { Button, Divider, Flex, Modal, Tag, message } from 'antd';
13 13 import { useRef, useState } from 'react';
14   -import { BANK_STATEMENT_COLUMNS, INVOICE_STATUS } from '../constant';
  14 +import { BANK_STATEMENT_COLUMNS, INVOICE_STATUS } from '../../constant';
15 15 import '../index.less';
16 16  
17 17 export default ({ loadInvoiceData, invoiceId, setVisible, onClose }) => {
... ...
src/pages/Invoice/components/BankImportModal.tsx renamed to src/pages/Invoice/Invoice/components/BankImportModal.tsx
src/pages/Invoice/components/Invoice.tsx renamed to src/pages/Invoice/Invoice/components/Invoice.tsx
src/pages/Invoice/components/InvoiceDetailImportModal.tsx renamed to src/pages/Invoice/Invoice/components/InvoiceDetailImportModal.tsx
src/pages/Invoice/Invoice/components/InvoiceDetailTable.tsx 0 → 100644
  1 +import InvoiceDetailImportModal from '@/pages/Invoice/Invoice/components/InvoiceDetailImportModal';
  2 +import { InvoiceProjectSelect } from '@/pages/Invoice/Invoice/components/InvoiceProjectSelect';
  3 +import {
  4 + ActionType,
  5 + EditableProTable,
  6 + ProCard,
  7 + ProColumns,
  8 + ProFormField,
  9 +} from '@ant-design/pro-components';
  10 +import { useEffect, useRef, useState } from 'react';
  11 +
  12 +export default ({ recordId, details, updateDetails, readOnly }) => {
  13 + const [editableKeys, setEditableRowKeys] = useState([]);
  14 + const ref = useRef<ActionType>();
  15 + useEffect(() => {
  16 + updateDetails(details);
  17 + }, []);
  18 +
  19 + useEffect(() => {
  20 + setEditableRowKeys(details?.map((item) => item.tid));
  21 + }, [details]);
  22 + const columns: ProColumns[] = [
  23 + {
  24 + title: '项目名称',
  25 + dataIndex: 'projectName',
  26 + width: 200,
  27 + ellipsis: true,
  28 + readonly: readOnly,
  29 + renderFormItem: () => {
  30 + return <InvoiceProjectSelect readOnly={readOnly} />;
  31 + },
  32 + },
  33 + {
  34 + title: '规格型号',
  35 + readonly: readOnly,
  36 + dataIndex: 'specification',
  37 + valueType: 'text',
  38 + ellipsis: true,
  39 + },
  40 + {
  41 + title: '单位',
  42 + readonly: readOnly,
  43 + dataIndex: 'unit',
  44 + valueType: 'text',
  45 + ellipsis: true,
  46 + },
  47 + {
  48 + title: '数量',
  49 + readonly: readOnly,
  50 + dataIndex: 'quantity',
  51 + valueType: 'digit',
  52 + ellipsis: true,
  53 + },
  54 + {
  55 + title: '单价',
  56 + readonly: readOnly,
  57 + dataIndex: 'price',
  58 + valueType: 'digit',
  59 + ellipsis: true,
  60 + },
  61 + {
  62 + title: '金额',
  63 + readonly: readOnly,
  64 + dataIndex: 'totalPrice',
  65 + valueType: 'digit',
  66 + ellipsis: true,
  67 + },
  68 + {
  69 + title: '税率/征收率',
  70 + readonly: true,
  71 + dataIndex: 'taxRate',
  72 + valueType: () => ({
  73 + type: 'percent',
  74 + }),
  75 + ellipsis: true,
  76 + },
  77 + {
  78 + title: '税额',
  79 + readonly: true,
  80 + dataIndex: 'taxPrice',
  81 + valueType: 'digit',
  82 + ellipsis: true,
  83 + },
  84 + {
  85 + title: '操作',
  86 + valueType: 'option',
  87 + width: 100,
  88 + render: () => {
  89 + return null;
  90 + },
  91 + },
  92 + ];
  93 +
  94 + return (
  95 + <>
  96 + <EditableProTable
  97 + columns={columns}
  98 + actionRef={ref}
  99 + rowKey="tid"
  100 + scroll={{
  101 + x: 960,
  102 + }}
  103 + value={details}
  104 + controlled={true}
  105 + recordCreatorProps={
  106 + readOnly
  107 + ? false
  108 + : {
  109 + newRecordType: 'dataSource',
  110 + record: () => ({
  111 + tid: Date.now(),
  112 + }),
  113 + }
  114 + }
  115 + toolBarRender={() => {
  116 + return [
  117 + <InvoiceDetailImportModal key={'import'} recordId={recordId} />,
  118 + ];
  119 + }}
  120 + editable={{
  121 + type: 'multiple',
  122 + editableKeys,
  123 + actionRender: (row, config, defaultDoms) => {
  124 + return [defaultDoms.delete];
  125 + },
  126 +
  127 + onValuesChange: (record, recordList) => {
  128 + //修改recordList中tid为record.tid的元素,将它的specification属性设置为invoiceProject的specification属性
  129 + const records = recordList.map((item) => {
  130 + return item;
  131 + });
  132 + updateDetails(records);
  133 + },
  134 + }}
  135 + />
  136 + {
  137 + <ProCard title="表格数据" headerBordered collapsible defaultCollapsed>
  138 + <ProFormField
  139 + ignoreFormItem
  140 + fieldProps={{
  141 + style: {
  142 + width: '100%',
  143 + },
  144 + }}
  145 + mode="read"
  146 + valueType="jsonCode"
  147 + text={JSON.stringify(details)}
  148 + />
  149 + </ProCard>
  150 + }
  151 + </>
  152 + );
  153 +};
... ...
src/pages/Invoice/components/InvoiceProjectSelect.tsx renamed to src/pages/Invoice/Invoice/components/InvoiceProjectSelect.tsx
src/pages/Invoice/components/InvoiceVerificationModal.tsx renamed to src/pages/Invoice/Invoice/components/InvoiceVerificationModal.tsx
... ... @@ -25,7 +25,7 @@ import {
25 25 message,
26 26 } from 'antd';
27 27 import { useEffect, useRef, useState } from 'react';
28   -import { BANK_STATEMENT_COLUMNS, INVOICE_STATUS } from '../constant';
  28 +import { BANK_STATEMENT_COLUMNS, INVOICE_STATUS } from '../../constant';
29 29 import '../index.less';
30 30 import BankChooseModal from './BankChooseModal';
31 31  
... ...
src/pages/Invoice/index.less renamed to src/pages/Invoice/Invoice/index.less
src/pages/Invoice/Invoice/index.tsx 0 → 100644
  1 +import ButtonConfirm from '@/components/ButtomConfirm';
  2 +import EllipsisDiv from '@/components/Div/EllipsisDiv';
  3 +import AddInvoiceDrawerForm from '@/pages/Invoice/Invoice/components/AddInvoiceDrawerForm';
  4 +import BankImportModal from '@/pages/Invoice/Invoice/components/BankImportModal';
  5 +import InvoiceVerificationModal from '@/pages/Invoice/Invoice/components/InvoiceVerificationModal';
  6 +import { INVOICE_COLUMNS, INVOICE_STATUS } from '@/pages/Invoice/constant';
  7 +import { INVOCING_STATUS, PAYEE_OPTIONS } from '@/pages/Order/constant';
  8 +import {
  9 + postServiceInvoiceDeleteInvoice,
  10 + postServiceInvoiceQueryInvoice,
  11 +} from '@/services';
  12 +import { enumValueToLabel, formatDateTime } from '@/utils';
  13 +import { formatDate } from '@/utils/time';
  14 +import { ActionType, ProTable } from '@ant-design/pro-components';
  15 +import { Button, message } from 'antd';
  16 +import { useRef, useState } from 'react';
  17 +
  18 +const InvoiceRecord = () => {
  19 + const invoiceActionRef = useRef<ActionType>();
  20 + const [bankImportModalVisible, setBankImportModalVisible] = useState(false);
  21 + const [invoiceVerificationVisible, setInvoiceVerificationVisible] =
  22 + useState(false);
  23 + const [invoiceId, setInvoiceId] = useState(undefined);
  24 + const reloadInvoiceTable = () => {
  25 + invoiceActionRef.current?.reload();
  26 + };
  27 +
  28 + const getTableCellText = (target: any) => {
  29 + if (!target) {
  30 + return '';
  31 + }
  32 +
  33 + if (target.props) {
  34 + return target.props.text;
  35 + }
  36 +
  37 + return target;
  38 + };
  39 + /**
  40 + * 加载发票列表表格的各个列格式
  41 + */
  42 + const invoicecColumnsInit = () => {
  43 + let columns = INVOICE_COLUMNS.map((item) => {
  44 + let newItem = { ...item };
  45 + let dataIndex = item.dataIndex;
  46 + let dataType = item.valueType;
  47 +
  48 + newItem.render = (text, record) => {
  49 + let textValue = record[dataIndex];
  50 +
  51 + if (dataType === 'dateRange' || dataType === 'date') {
  52 + textValue = formatDate(textValue);
  53 + }
  54 +
  55 + if (dataType === 'dateTime') {
  56 + textValue = formatDateTime(textValue);
  57 + }
  58 +
  59 + if (dataType === 'money') {
  60 + textValue = '¥' + textValue;
  61 + }
  62 +
  63 + switch (dataIndex) {
  64 + case 'invoiceStatus':
  65 + return (
  66 + <EllipsisDiv
  67 + text={enumValueToLabel(
  68 + getTableCellText(textValue),
  69 + INVOCING_STATUS,
  70 + )}
  71 + />
  72 + );
  73 +
  74 + case 'status':
  75 + return (
  76 + <EllipsisDiv
  77 + text={enumValueToLabel(
  78 + getTableCellText(textValue),
  79 + INVOICE_STATUS,
  80 + )}
  81 + />
  82 + );
  83 +
  84 + case 'payee':
  85 + return (
  86 + <EllipsisDiv
  87 + text={enumValueToLabel(
  88 + getTableCellText(textValue),
  89 + PAYEE_OPTIONS,
  90 + )}
  91 + />
  92 + );
  93 +
  94 + default:
  95 + return <EllipsisDiv text={getTableCellText(textValue)} />;
  96 + }
  97 + };
  98 +
  99 + return newItem;
  100 + });
  101 +
  102 + columns.push({
  103 + title: '操作',
  104 + valueType: 'option',
  105 + key: 'option',
  106 + fixed: 'right',
  107 + width: 120,
  108 + render: (text, record) => {
  109 + let btns = [];
  110 + if (record.path?.includes('writeOff')) {
  111 + btns.push(
  112 + <a
  113 + key="editable"
  114 + onClick={() => {
  115 + setInvoiceVerificationVisible(true);
  116 + setInvoiceId(record.invoiceId);
  117 + }}
  118 + >
  119 + 核销
  120 + </a>,
  121 + );
  122 + }
  123 +
  124 + if (record.path?.includes('queryInvoiceDetails')) {
  125 + btns.push(
  126 + <Button
  127 + className="p-0"
  128 + key="view"
  129 + type="link"
  130 + onClick={() => {
  131 + setInvoiceVerificationVisible(true);
  132 + setInvoiceId(record.invoiceId);
  133 + }}
  134 + >
  135 + 查看
  136 + </Button>,
  137 + );
  138 + }
  139 +
  140 + if (record.path?.includes('deleteInvoice')) {
  141 + btns.push(
  142 + <ButtonConfirm
  143 + key="delete"
  144 + className="p-0"
  145 + title={
  146 + '确认删除发票号码为[ ' + record.invoiceNumber + ' ]的发票吗?'
  147 + }
  148 + text="删除"
  149 + onConfirm={async () => {
  150 + let res = await postServiceInvoiceDeleteInvoice({
  151 + data: { invoiceId: record.invoiceId },
  152 + });
  153 + if (res) {
  154 + message.success(res.message);
  155 + reloadInvoiceTable();
  156 + }
  157 + }}
  158 + />,
  159 + );
  160 + }
  161 + return btns;
  162 + },
  163 + });
  164 +
  165 + return columns;
  166 + };
  167 +
  168 + return (
  169 + <div className="invoice-index">
  170 + <ProTable
  171 + columns={invoicecColumnsInit()}
  172 + actionRef={invoiceActionRef}
  173 + cardBordered
  174 + pagination={{
  175 + pageSize: 10,
  176 + }}
  177 + request={async (params) => {
  178 + const res = await postServiceInvoiceQueryInvoice({
  179 + data: { ...params },
  180 + });
  181 + if (res) {
  182 + return {
  183 + data: res?.data?.data || [],
  184 + total: res?.data?.total || 0,
  185 + };
  186 + }
  187 + }}
  188 + columnsState={{
  189 + persistenceKey: 'pro-table-singe-demos',
  190 + persistenceType: 'localStorage',
  191 + defaultValue: {
  192 + option: { fixed: 'right', disable: true },
  193 + },
  194 + onChange(value) {
  195 + console.log('value: ', value);
  196 + },
  197 + }}
  198 + rowKey="id"
  199 + search={{
  200 + labelWidth: 'auto',
  201 + }}
  202 + options={{
  203 + setting: {
  204 + listsHeight: 400,
  205 + },
  206 + }}
  207 + form={{}}
  208 + dateFormatter="string"
  209 + headerTitle="发票列表"
  210 + scroll={{ x: 1400, y: 360 }}
  211 + toolBarRender={() => [
  212 + <AddInvoiceDrawerForm
  213 + onClose={() => {
  214 + invoiceActionRef.current?.reload();
  215 + }}
  216 + key="add"
  217 + ></AddInvoiceDrawerForm>,
  218 + ]}
  219 + />
  220 +
  221 + {bankImportModalVisible ? (
  222 + <BankImportModal
  223 + setVisible={setBankImportModalVisible}
  224 + onClose={() => {
  225 + setBankImportModalVisible(false);
  226 + invoiceActionRef.current?.reload();
  227 + }}
  228 + ></BankImportModal>
  229 + ) : (
  230 + ''
  231 + )}
  232 +
  233 + {invoiceVerificationVisible ? (
  234 + <InvoiceVerificationModal
  235 + setVisible={setInvoiceVerificationVisible}
  236 + invoiceId={invoiceId}
  237 + onClose={() => {
  238 + invoiceActionRef.current?.reload();
  239 + }}
  240 + ></InvoiceVerificationModal>
  241 + ) : (
  242 + ''
  243 + )}
  244 + </div>
  245 + );
  246 +};
  247 +
  248 +export default InvoiceRecord;
... ...
src/pages/Invoice/InvoiceRecord/components/AddInvoiceDrawerForm.tsx 0 → 100644
  1 +import { RESPONSE_CODE } from '@/constants/enum';
  2 +import { PAYEE_OPTIONS } from '@/pages/Order/constant';
  3 +import {
  4 + postServiceInvoiceAddInvoice,
  5 + postServiceOrderQuerySalesCode,
  6 +} from '@/services';
  7 +import { enumToSelect } from '@/utils';
  8 +import { PlusOutlined } from '@ant-design/icons';
  9 +import {
  10 + DrawerForm,
  11 + ProFormDateTimePicker,
  12 + ProFormGroup,
  13 + ProFormList,
  14 + ProFormMoney,
  15 + ProFormSelect,
  16 + ProFormText,
  17 + ProFormTextArea,
  18 +} from '@ant-design/pro-components';
  19 +import { Button, Form, message } from 'antd';
  20 +import { useEffect, useState } from 'react';
  21 +
  22 +export default ({ onClose }) => {
  23 + const [form] = Form.useForm<{
  24 + invoiceNumber: '';
  25 + invoiceStatus: '';
  26 + purchaser: '';
  27 + payee: '';
  28 + contacts: '';
  29 + sale: '';
  30 + invoicingTime: '';
  31 + notes: '';
  32 + mainOrderIdObjs: [
  33 + {
  34 + mainOrderId: '';
  35 + },
  36 + ];
  37 + money: '';
  38 + }>();
  39 + const [salesCodeOptions, setSalesCodeOptions] = useState([]);
  40 + const getSalesCodeOptions = async () => {
  41 + const res = await postServiceOrderQuerySalesCode();
  42 + let options = res.data?.map((item) => {
  43 + return {
  44 + label: item.userName,
  45 + value: item.userName,
  46 + number: item.number,
  47 + };
  48 + });
  49 + setSalesCodeOptions(options);
  50 + };
  51 + useEffect(() => {
  52 + getSalesCodeOptions();
  53 + }, []);
  54 + return (
  55 + <DrawerForm<{
  56 + invoiceNumber: string;
  57 + invoiceStatus: string;
  58 + purchaser: string;
  59 + payee: string;
  60 + contacts: string;
  61 + sale: string;
  62 + invoicingTime: Date;
  63 + notes: string;
  64 + mainOrderIdObjs: [
  65 + {
  66 + mainOrderId: string;
  67 + },
  68 + ];
  69 + money: string;
  70 + }>
  71 + title="新增开票"
  72 + resize={{
  73 + onResize() {
  74 + console.log('resize!');
  75 + },
  76 + maxWidth: window.innerWidth * 0.8,
  77 + minWidth: 500,
  78 + }}
  79 + form={form}
  80 + trigger={
  81 + <Button type="primary">
  82 + <PlusOutlined />
  83 + 新增
  84 + </Button>
  85 + }
  86 + autoFocusFirstInput
  87 + drawerProps={{
  88 + destroyOnClose: true,
  89 + }}
  90 + submitTimeout={2000}
  91 + onFinish={async (values) => {
  92 + console.log(values);
  93 + const mainOrderIds = values.mainOrderIdObjs.flatMap(
  94 + (item) => item.mainOrderId,
  95 + );
  96 + let attrs = { ...values, mainOrderIds };
  97 + let res = await postServiceInvoiceAddInvoice({
  98 + data: { ...attrs },
  99 + });
  100 + if (res.result === RESPONSE_CODE.SUCCESS) {
  101 + message.success(res.message);
  102 + } else {
  103 + message.error(res.message);
  104 + return false;
  105 + }
  106 + onClose();
  107 + // 不返回不会关闭弹框
  108 + return true;
  109 + }}
  110 + >
  111 + <ProFormText
  112 + name="invoiceNumber"
  113 + width="md"
  114 + label="发票号码"
  115 + placeholder="请输入名称"
  116 + rules={[{ required: true, message: '请输入名称!' }]}
  117 + />
  118 + <ProFormSelect
  119 + name="invoiceStatus"
  120 + label="发票类型"
  121 + valueEnum={{
  122 + SPECIALLY_INVOICED: '专票',
  123 + COMMON_INVOICED: '普票',
  124 + }}
  125 + rules={[{ required: true, message: '请选择发票类型!' }]}
  126 + />
  127 + <ProFormText
  128 + name="purchaser"
  129 + width="md"
  130 + label="购买方"
  131 + placeholder="请输入购买方"
  132 + rules={[{ required: true, message: '请输入购买方!' }]}
  133 + />
  134 + <ProFormSelect
  135 + placeholder="收款单位"
  136 + name="payee"
  137 + width="lg"
  138 + key="payee"
  139 + showSearch
  140 + label="开票收款单位"
  141 + tooltip="财务开票将依据这个字段,选择对应的公司开票"
  142 + options={enumToSelect(PAYEE_OPTIONS)}
  143 + />
  144 + <ProFormText
  145 + name="contacts"
  146 + width="md"
  147 + label="联系人"
  148 + placeholder="请输入联系人"
  149 + rules={[{ required: true, message: '请输入联系人!' }]}
  150 + />
  151 + <ProFormSelect
  152 + name="sale"
  153 + key="sale"
  154 + width="lg"
  155 + showSearch
  156 + label="销售代表"
  157 + placeholder="请选择销售代表"
  158 + options={salesCodeOptions}
  159 + />
  160 + <ProFormDateTimePicker
  161 + name="invoicingTime"
  162 + label="开票时间"
  163 + fieldProps={{
  164 + format: (value) => value.format('YYYY-MM-DD'),
  165 + }}
  166 + rules={[{ required: true, message: '请输入开票时间!' }]}
  167 + />
  168 + <ProFormTextArea name="notes" label="备注" placeholder="请输入名称" />
  169 + <ProFormList
  170 + name="mainOrderIdObjs"
  171 + label="订单号"
  172 + min={1}
  173 + copyIconProps={false}
  174 + deleteIconProps={{
  175 + tooltipText: '删除',
  176 + }}
  177 + initialValue={[
  178 + {
  179 + mainOrderId: '',
  180 + },
  181 + ]}
  182 + >
  183 + <ProFormGroup key="group">
  184 + <ProFormText
  185 + rules={[{ required: true, message: '请输入关联订单!' }]}
  186 + name="mainOrderId"
  187 + />
  188 + </ProFormGroup>
  189 + </ProFormList>
  190 + <ProFormMoney
  191 + label="金额"
  192 + name="money"
  193 + customSymbol="¥"
  194 + min={0}
  195 + rules={[{ required: true, message: '请输入金额!' }]}
  196 + />
  197 + </DrawerForm>
  198 + );
  199 +};
... ...
src/pages/Invoice/InvoiceRecord/components/BankChooseModal.tsx 0 → 100644
  1 +import EllipsisDiv from '@/components/Div/EllipsisDiv';
  2 +import { RESPONSE_CODE } from '@/constants/enum';
  3 +import { INVOCING_STATUS, PAYEE_OPTIONS } from '@/pages/Order/constant';
  4 +import {
  5 + postServiceBankStatementQueryBankStatement,
  6 + postServiceInvoiceInvoiceWriteOff,
  7 +} from '@/services';
  8 +import { FloatAdd, FloatSub, enumValueToLabel, formatDateTime } from '@/utils';
  9 +import { formatDate } from '@/utils/time';
  10 +
  11 +import { ActionType, ProCard, ProTable } from '@ant-design/pro-components';
  12 +import { Button, Divider, Flex, Modal, Tag, message } from 'antd';
  13 +import { useRef, useState } from 'react';
  14 +import { BANK_STATEMENT_COLUMNS, INVOICE_STATUS } from '../../constant';
  15 +import '../index.less';
  16 +
  17 +export default ({ loadInvoiceData, invoiceId, setVisible, onClose }) => {
  18 + const [selectedStatement, setSelectedStatement] = useState([]);
  19 + const [selectedStatementIdSet, setSelectedStatementIdSet] = useState(
  20 + new Set(),
  21 + );
  22 + const [totalAmount, setTotalAmount] = useState(0);
  23 +
  24 + // 添加元素到Set
  25 + const addElement = (element) => {
  26 + setSelectedStatementIdSet((prevSet) => new Set([...prevSet, element]));
  27 + };
  28 +
  29 + // 从Set中删除元素
  30 + const removeElement = (element) => {
  31 + setSelectedStatementIdSet((prevSet) => {
  32 + const newSet = new Set(prevSet);
  33 + newSet.delete(element);
  34 + return newSet;
  35 + });
  36 + };
  37 +
  38 + const [btnLoading, setBtnLoading] = useState(false);
  39 +
  40 + const actionRef = useRef<ActionType>();
  41 + const getTableCellText = (target: any) => {
  42 + if (!target) {
  43 + return '';
  44 + }
  45 +
  46 + if (target.props) {
  47 + return target.props.text;
  48 + }
  49 +
  50 + return target;
  51 + };
  52 +
  53 + /**
  54 + * 加载列表表格的各个列格式
  55 + */
  56 + const bankStatementColumnsInit = () => {
  57 + let columns = BANK_STATEMENT_COLUMNS.map((item) => {
  58 + let newItem = { ...item };
  59 + let dataIndex = item.dataIndex;
  60 + let dataType = item.valueType;
  61 +
  62 + if (item.dataIndex === 'status') {
  63 + newItem.hideInSearch = true;
  64 + }
  65 +
  66 + newItem.render = (text, record) => {
  67 + let textValue = record[dataIndex];
  68 +
  69 + if (dataType === 'date') {
  70 + textValue = formatDate(textValue);
  71 + }
  72 +
  73 + if (dataType === 'dateTime') {
  74 + textValue = formatDateTime(textValue);
  75 + }
  76 +
  77 + if (dataType === 'money') {
  78 + textValue = '¥' + textValue;
  79 + }
  80 +
  81 + switch (dataIndex) {
  82 + case 'invoiceStatus':
  83 + return (
  84 + <EllipsisDiv
  85 + text={enumValueToLabel(
  86 + getTableCellText(textValue),
  87 + INVOCING_STATUS,
  88 + )}
  89 + />
  90 + );
  91 +
  92 + case 'status': {
  93 + //这里状态不显示在筛选条件中,只能筛异常的流水
  94 + return (
  95 + <EllipsisDiv
  96 + text={enumValueToLabel(
  97 + getTableCellText(textValue),
  98 + INVOICE_STATUS,
  99 + )}
  100 + />
  101 + );
  102 + }
  103 + case 'payee':
  104 + return (
  105 + <EllipsisDiv
  106 + text={enumValueToLabel(
  107 + getTableCellText(textValue),
  108 + PAYEE_OPTIONS,
  109 + )}
  110 + />
  111 + );
  112 +
  113 + default:
  114 + return <EllipsisDiv text={getTableCellText(textValue)} />;
  115 + }
  116 + };
  117 +
  118 + return newItem;
  119 + });
  120 +
  121 + columns.push({
  122 + title: '操作',
  123 + valueType: 'option',
  124 + key: 'option',
  125 + fixed: 'right',
  126 + width: 70,
  127 + render: (text, record) => [
  128 + <Button
  129 + className="p-0"
  130 + key="choose"
  131 + type="link"
  132 + onClick={() => {
  133 + let amount = record.loanAmount || record.transactionAmount || 0;
  134 +
  135 + //已经选中,取消选中
  136 + if (selectedStatementIdSet.has(record.id)) {
  137 + setSelectedStatement(
  138 + selectedStatement.filter((item) => {
  139 + return item.id !== record.id;
  140 + }),
  141 + );
  142 + removeElement(record.id);
  143 + setTotalAmount(parseFloat(FloatSub(totalAmount, amount)));
  144 + } else {
  145 + //添加到已选中区域中
  146 + let newSelectedStatement = [...selectedStatement];
  147 + newSelectedStatement.push(record);
  148 + setSelectedStatement(newSelectedStatement);
  149 + addElement(record.id);
  150 + setTotalAmount(FloatAdd(totalAmount, amount));
  151 + }
  152 + }}
  153 + >
  154 + {selectedStatementIdSet.has(record.id) ? '取消选中' : '选中'}
  155 + </Button>,
  156 + ],
  157 + });
  158 +
  159 + return columns;
  160 + };
  161 +
  162 + /**
  163 + * 删除已选中
  164 + * @param record
  165 + */
  166 + const removeSelectedStatement = (record: any) => {
  167 + setSelectedStatement(
  168 + selectedStatement.filter((item) => {
  169 + return item.id !== record.id;
  170 + }),
  171 + );
  172 + removeElement(record.id);
  173 + };
  174 +
  175 + const showSelectedStatement = () => {
  176 + let i = 0;
  177 +
  178 + let tags = selectedStatement.map((item) => {
  179 + let tagText = item.id;
  180 +
  181 + if (item.payeePayerName) {
  182 + tagText += ' ' + item.payeePayerName + ' ';
  183 + }
  184 +
  185 + if (item.loanAmount) {
  186 + tagText += item.loanAmount + ' ';
  187 + }
  188 +
  189 + if (item.transactionAmount) {
  190 + tagText += item.transactionAmount;
  191 + }
  192 +
  193 + return (
  194 + <Tag
  195 + key={i++}
  196 + closable={true}
  197 + style={{ userSelect: 'none' }}
  198 + color="blue"
  199 + onClose={(e) => {
  200 + e.preventDefault(); //需要加上这句代码,不然删除tag时,当前tag的下一个tag会被设置ant-tag-hidden
  201 + removeSelectedStatement(item);
  202 + }}
  203 + >
  204 + <span>{tagText}</span>
  205 + </Tag>
  206 + );
  207 + });
  208 +
  209 + return tags;
  210 + };
  211 +
  212 + return (
  213 + <>
  214 + <Modal
  215 + open
  216 + width="80%"
  217 + title="添加银行流水"
  218 + className="bank-statement-choose"
  219 + onOk={async () => {
  220 + setBtnLoading(true);
  221 + let bankStatementIds = selectedStatement?.map((item) => {
  222 + return item.id;
  223 + });
  224 + let res = await postServiceInvoiceInvoiceWriteOff({
  225 + data: {
  226 + invoiceId: invoiceId,
  227 + bankStatementIds: bankStatementIds,
  228 + },
  229 + });
  230 + setTimeout(() => {
  231 + loadInvoiceData();
  232 + }, 500);
  233 + if (res.result === RESPONSE_CODE.SUCCESS) {
  234 + if (res.data?.length > 0) {
  235 + message.info(res.data);
  236 + } else {
  237 + message.success(res.message);
  238 + }
  239 +
  240 + onClose();
  241 + }
  242 + setBtnLoading(false);
  243 + }}
  244 + okButtonProps={{
  245 + loading: btnLoading,
  246 + }}
  247 + onCancel={() => {
  248 + setVisible(false);
  249 + }}
  250 + >
  251 + <Divider orientation="left" plain>
  252 + 已选中(合计:¥{totalAmount})
  253 + </Divider>
  254 + <ProCard className="mb-[16px]" bordered style={{}}>
  255 + <Flex wrap="wrap" gap="small">
  256 + {showSelectedStatement()}
  257 + </Flex>
  258 + </ProCard>
  259 +
  260 + <ProTable
  261 + columns={bankStatementColumnsInit()}
  262 + actionRef={actionRef}
  263 + cardBordered
  264 + pagination={{
  265 + pageSize: 10,
  266 + }}
  267 + editable={{
  268 + type: 'multiple',
  269 + onSave: async (rowKey, data) => {
  270 + console.log(rowKey, data);
  271 + },
  272 + actionRender: (row, config, defaultDom) => [
  273 + defaultDom.save,
  274 + defaultDom.cancel,
  275 + ],
  276 + }}
  277 + request={async (params) => {
  278 + const res = await postServiceBankStatementQueryBankStatement({
  279 + data: { ...params, status: 'ABNORMAL' },
  280 + });
  281 + if (res) {
  282 + return {
  283 + data: res?.data?.data || [],
  284 + total: res?.data?.total || 0,
  285 + };
  286 + }
  287 + }}
  288 + columnsState={{
  289 + persistenceKey: 'pro-table-singe-demos',
  290 + persistenceType: 'localStorage',
  291 + defaultValue: {
  292 + option: { fixed: 'right', disable: true },
  293 + },
  294 + onChange(value) {
  295 + console.log('value: ', value);
  296 + },
  297 + }}
  298 + rowKey="id"
  299 + search={{
  300 + labelWidth: 'auto',
  301 + }}
  302 + options={{
  303 + setting: {
  304 + listsHeight: 400,
  305 + },
  306 + }}
  307 + form={{}}
  308 + dateFormatter="string"
  309 + headerTitle="银行流水列表"
  310 + scroll={{ x: 1400, y: 360 }}
  311 + toolBarRender={() => []}
  312 + />
  313 + </Modal>
  314 + </>
  315 + );
  316 +};
... ...
src/pages/Invoice/InvoiceRecord/components/BankImportModal.tsx 0 → 100644
  1 +import { RESPONSE_CODE } from '@/constants/enum';
  2 +import { blobToJson } from '@/utils';
  3 +
  4 +import { UploadOutlined } from '@ant-design/icons';
  5 +import { ModalForm } from '@ant-design/pro-components';
  6 +import { Button, Form, Upload, UploadFile, UploadProps, message } from 'antd';
  7 +import { RcFile } from 'antd/es/upload';
  8 +import axios from 'axios';
  9 +import { useState } from 'react';
  10 +
  11 +// import { cloneDeep } from 'lodash';
  12 +export default ({ setVisible, onClose }) => {
  13 + const [form] = Form.useForm<{ name: string; company: string }>();
  14 + const [fileList, setFileList] = useState<UploadFile[]>([]);
  15 + const handleChange: UploadProps['onChange'] = ({ fileList: newFileList }) =>
  16 + setFileList(newFileList);
  17 +
  18 + const [messageApi, contextHolder] = message.useMessage();
  19 + const [uploadLoading, setUploading] = useState(false);
  20 + console.log(uploadLoading);
  21 +
  22 + const exportLoading = (content: string) => {
  23 + messageApi.open({
  24 + type: 'loading',
  25 + content: content,
  26 + duration: 0,
  27 + });
  28 + };
  29 +
  30 + const downloadImportTemplate = async () => {
  31 + exportLoading('正在下载......');
  32 + axios({
  33 + url: '/api/service/bankStatement/exportTemplate',
  34 + method: 'post',
  35 + responseType: 'blob',
  36 + headers: { Authorization: localStorage.getItem('token') },
  37 + })
  38 + .then((response) => {
  39 + // 创建一个新的 Blob 对象,它包含了服务器响应的数据(即你的 Excel 文件)
  40 + const blob = new Blob([response.data]); // Excel 的 MIME 类型
  41 + const downloadUrl = window.URL.createObjectURL(blob);
  42 + const a = document.createElement('a');
  43 + a.href = downloadUrl;
  44 + a.download = '导入模板.xlsx'; // 你可以为文件命名
  45 + document.body.appendChild(a);
  46 + a.click(); // 模拟点击操作来下载文件
  47 + URL.revokeObjectURL(downloadUrl); // 释放掉 blob 对象所占用的内存
  48 + document.body.removeChild(a);
  49 + })
  50 + .catch((error) => {
  51 + // 处理错误
  52 + console.error('导出错误', error);
  53 + })
  54 + .finally(() => {
  55 + messageApi.destroy();
  56 + });
  57 + };
  58 + const handleUpload = async () => {
  59 + exportLoading('正在导入......');
  60 +
  61 + const formData = new FormData();
  62 + fileList.forEach((file) => {
  63 + formData.append('file', file.originFileObj as RcFile);
  64 + });
  65 +
  66 + setUploading(true);
  67 +
  68 + axios({
  69 + url: '/api/service/bankStatement/importBankStatementForm',
  70 + method: 'post',
  71 + responseType: 'blob',
  72 + headers: {
  73 + Authorization: localStorage.getItem('token'),
  74 + 'Content-Type':
  75 + 'multipart/form-data; boundary=----WebKitFormBoundarynl6gT1BKdPWIejNq',
  76 + },
  77 + data: formData,
  78 + })
  79 + .then((response) => {
  80 + let data = response.data;
  81 + if (data.type === 'application/json') {
  82 + blobToJson(data).then((dataJson) => {
  83 + if (dataJson?.result === RESPONSE_CODE.SUCCESS) {
  84 + message.success(dataJson?.message);
  85 + onClose();
  86 + } else {
  87 + message.error(dataJson?.message);
  88 + }
  89 + });
  90 + } else {
  91 + message.error('上传失败,已下载错误信息表格');
  92 + // 创建一个新的 Blob 对象,它包含了服务器响应的数据(即你的 Excel 文件)
  93 + const blob = new Blob([response.data]); // Excel 的 MIME 类型
  94 + const downloadUrl = window.URL.createObjectURL(blob);
  95 + const a = document.createElement('a');
  96 + a.href = downloadUrl;
  97 + a.download = '银行流水导入模板.xlsx'; // 你可以为文件命名
  98 + document.body.appendChild(a);
  99 + a.click(); // 模拟点击操作来下载文件
  100 + URL.revokeObjectURL(downloadUrl); // 释放掉 blob 对象所占用的内存
  101 + document.body.removeChild(a);
  102 + }
  103 + })
  104 + .catch((error) => {
  105 + // 处理错误
  106 + message.error('系统出现异常了,请联系管理员', error);
  107 + })
  108 + .finally(() => {
  109 + setUploading(false);
  110 + messageApi.destroy();
  111 + });
  112 + };
  113 + const props: UploadProps = {
  114 + onRemove: (file) => {
  115 + const index = fileList.indexOf(file);
  116 + const newFileList = fileList.slice();
  117 + newFileList.splice(index, 1);
  118 + setFileList(newFileList);
  119 + },
  120 + beforeUpload: (file) => {
  121 + setFileList([...fileList, file]);
  122 +
  123 + return false;
  124 + },
  125 + fileList,
  126 + onChange: handleChange,
  127 + accept: '.xlsx',
  128 + };
  129 +
  130 + return (
  131 + <>
  132 + <ModalForm<{
  133 + name: string;
  134 + company: string;
  135 + }>
  136 + width={500}
  137 + open
  138 + title="银行流水导入"
  139 + form={form}
  140 + autoFocusFirstInput
  141 + modalProps={{
  142 + okText: '确定',
  143 + cancelText: '取消',
  144 + destroyOnClose: true,
  145 + onCancel: () => {
  146 + setVisible(false);
  147 + },
  148 + }}
  149 + onFinish={async () => {
  150 + handleUpload();
  151 + }}
  152 + onOpenChange={setVisible}
  153 + >
  154 + <div className="py-4 font-semibold">
  155 + 导入银行流水
  156 + <Button type="link" onClick={downloadImportTemplate}>
  157 + 下载导入模板
  158 + </Button>
  159 + </div>
  160 + <Upload {...props}>
  161 + <Button icon={<UploadOutlined />} disabled={fileList.length > 0}>
  162 + 点击选择文件
  163 + </Button>
  164 + </Upload>
  165 + </ModalForm>
  166 +
  167 + {contextHolder}
  168 + </>
  169 + );
  170 +};
... ...
src/pages/Invoice/InvoiceRecord/components/Invoice.tsx 0 → 100644
  1 +import styled from 'styled-components';
  2 +const InvoiceTmpDiv = styled.div`
  3 + font-size: 12px;
  4 + width: 1120px;
  5 + .title {
  6 + font-size: 26px;
  7 + color: #b16363;
  8 + text-align: center;
  9 + line-height: 56px;
  10 + padding-top: 0;
  11 + }
  12 + .extra {
  13 + color: #b15b16;
  14 + .content {
  15 + color: #181818;
  16 + }
  17 + }
  18 + .height84 {
  19 + height: 110px;
  20 + }
  21 + .row {
  22 + border: 2px solid #b16363;
  23 + border-bottom: none;
  24 + color: #b15b16;
  25 + .content {
  26 + color: #181818;
  27 + }
  28 + }
  29 + .last-row {
  30 + .content {
  31 + color: #181818;
  32 + }
  33 + color: #b15b16;
  34 + border-top: 2px solid #b16363;
  35 + }
  36 + .label {
  37 + width: 78px;
  38 + display: inline-block;
  39 + text-align-last: justify;
  40 + text-align: justify;
  41 + }
  42 + .longLabel {
  43 + width: 178px;
  44 + display: inline-block;
  45 + text-align-last: justify;
  46 + text-align: justify;
  47 + }
  48 + .title-label {
  49 + width: 52px;
  50 + }
  51 +`;
  52 +const Row = styled.div`
  53 + .col_1 {
  54 + width: 2.65%;
  55 + borderleft: none;
  56 + }
  57 + .col_4 {
  58 + width: 3.75%;
  59 + }
  60 + .col_9 {
  61 + width: 7.4%;
  62 + }
  63 + .col_2 {
  64 + width: 8.33%;
  65 + }
  66 + .col_3 {
  67 + width: 12.5%;
  68 + }
  69 + .col_5 {
  70 + width: 20.83%;
  71 + }
  72 + .col_6 {
  73 + width: 42.5%;
  74 + }
  75 + .col_7 {
  76 + width: 29.16%;
  77 + }
  78 + .col_8 {
  79 + width: 33.33%;
  80 + }
  81 + .col_14 {
  82 + width: 58.33%;
  83 + }
  84 + .col_15 {
  85 + width: 42.5%;
  86 + }
  87 + .col_17 {
  88 + width: 70.83%;
  89 + }
  90 + .col_18 {
  91 + width: 100%;
  92 + }
  93 + .col_24 {
  94 + width: 100%;
  95 + }
  96 +`;
  97 +const Col = styled.span`
  98 + display: inline-block;
  99 + padding: 8px;
  100 + box-sizing: border-box;
  101 + vertical-align: middle;
  102 + border-left: 2px solid #b16363;
  103 + height: 100%;
  104 + &.no-border {
  105 + border-left: none;
  106 + }
  107 + .text-center {
  108 + text-align: center;
  109 + border-left: none;
  110 + border-right: none;
  111 + }
  112 + &.transparent-border {
  113 + border-left: 2px solid rgba(0, 0, 0, 0);
  114 + }
  115 + &.invoice-number {
  116 + border-left: none;
  117 + color: #b16363;
  118 + padding: 0 0 0 800px;
  119 + font-size: 14px;
  120 + }
  121 +`;
  122 +const UnderLine = styled.div`
  123 + border: 2px solid #b16363;
  124 + width: 325px;
  125 + height: 8px;
  126 + margin: -1% 0 2% 35%;
  127 + border-left: none;
  128 + border-right: none;
  129 +`;
  130 +const InvoiceInfo = styled.span`
  131 + color: black;
  132 +`;
  133 +const TitleDescription = styled.div`
  134 + margin-top: 4.2%;
  135 +`;
  136 +const ProjectContainer = styled.div`
  137 + width: 100%;
  138 + height: 160px;
  139 + border-top: 2px solid #b16363;
  140 + border-right: 2px solid #b16363;
  141 + border-left: 2px solid #b16363;
  142 + overflow: auto;
  143 + .single-project {
  144 + width: 100%;
  145 + height: 30px;
  146 + }
  147 +`;
  148 +export default ({ data }) => {
  149 + return (
  150 + <div>
  151 + <InvoiceTmpDiv>
  152 + <Row>
  153 + <Col className="col_18 invoice-number">
  154 + 发票号码:<InvoiceInfo>{data.invoiceNumber}</InvoiceInfo>
  155 + </Col>
  156 + <Col className="title col_18 no-border">
  157 + 电子发票(
  158 + {data.type === 'SPECIAL_TICKET' ? '增值税专用发票' : '普通发票'})
  159 + </Col>
  160 + <UnderLine className="UnderLine">
  161 + <div></div>
  162 + </UnderLine>
  163 + </Row>
  164 + <Row className="row height84">
  165 + <Col className="col_1 no-border">购买方信息</Col>
  166 + <Col className="col_15">
  167 + <TitleDescription>
  168 + <span className="label">名称</span>:
  169 + <span className="content">{data.partyAName}</span>
  170 + </TitleDescription>
  171 + <TitleDescription>
  172 + <span className="longLabel">统一社会信用代码/纳税人识别号</span>:
  173 + <span className="content">{data.partyATaxid}</span>
  174 + </TitleDescription>
  175 + </Col>
  176 + <Col className="col_1">销售方信息</Col>
  177 + <Col className="col_6">
  178 + <TitleDescription>
  179 + <span className="label">名称</span>:
  180 + <span className="content">{data.partyBName}</span>
  181 + </TitleDescription>
  182 + <TitleDescription>
  183 + <span className="longLabel">统一社会信用代码/纳税人识别号</span>:
  184 + <span className="content">{data.partyBTaxid}</span>
  185 + </TitleDescription>
  186 + </Col>
  187 + </Row>
  188 + <Row className="row">
  189 + <Col className="col_7 no-border">
  190 + <div className="text-center">项目名称</div>
  191 + </Col>
  192 + <Col className="col_5">
  193 + <div className="text-center">规格型号</div>
  194 + </Col>
  195 + <Col className="">
  196 + <div className="text-center">单位</div>
  197 + </Col>
  198 + <Col className="col_2">
  199 + <div className="text-center">数量</div>
  200 + </Col>
  201 + <Col className="col_2">
  202 + <div className="text-center">单价</div>
  203 + </Col>
  204 + <Col className="col_2">
  205 + <div className="text-center">金额</div>
  206 + </Col>
  207 + <Col className="">
  208 + <div className="text-center">税率/征收率</div>
  209 + </Col>
  210 + <Col className="col_2">
  211 + <div className="text-center">税额</div>
  212 + </Col>
  213 + </Row>
  214 + <Row>
  215 + <ProjectContainer>
  216 + {data &&
  217 + data.invoiceDetails?.map((item) => {
  218 + const {
  219 + taxPrice,
  220 + totalPrice,
  221 + specification,
  222 + projectName,
  223 + quantity,
  224 + price,
  225 + taxRate,
  226 + unit,
  227 + } = item;
  228 + return (
  229 + <div className="single-project" key={item.id}>
  230 + <Col
  231 + className="col_7 transparent-border"
  232 + key={'projectName'}
  233 + >
  234 + <div className="text-center">{projectName}</div>
  235 + </Col>
  236 + <Col
  237 + className="col_5 transparent-border"
  238 + key={'specification'}
  239 + >
  240 + <div className="text-center">{specification}</div>
  241 + </Col>
  242 + <Col className=" transparent-border" key={'unit'}>
  243 + <div className="text-center">{unit}</div>
  244 + </Col>
  245 + <Col className="col_2 transparent-border" key={'quantity'}>
  246 + <div className="text-center">{quantity}</div>
  247 + </Col>
  248 + <Col className="col_2 transparent-border" key={'price'}>
  249 + <div className="text-center">{price}</div>
  250 + </Col>
  251 + <Col
  252 + className="col_2 transparent-border"
  253 + key={'totalPrice'}
  254 + >
  255 + <div className="text-center">{totalPrice}</div>
  256 + </Col>
  257 + <Col className=" transparent-border" key={'taxRate'}>
  258 + <div className="text-center">{taxRate}</div>
  259 + </Col>
  260 + <Col className="col_2 transparent-border" key={'taxPrice'}>
  261 + <div className="text-center">{taxPrice}</div>
  262 + </Col>
  263 + </div>
  264 + );
  265 + })}
  266 + </ProjectContainer>
  267 + </Row>
  268 + <Row className="row">
  269 + <Col className="col_15 no-border">
  270 + 价税合计(大写)
  271 + <InvoiceInfo>{data.totalPriceText}</InvoiceInfo>
  272 + </Col>
  273 + <Col className="no-border">
  274 + (小写)<InvoiceInfo>¥{data.totalPrice}</InvoiceInfo>
  275 + </Col>
  276 + </Row>
  277 + <Row className="row height84">
  278 + <Col className="col_1 no-border">备注</Col>
  279 + <Col className="col_7">
  280 + <InvoiceInfo>{data.comment}</InvoiceInfo>
  281 + </Col>
  282 + </Row>
  283 + <Row className="last-row">
  284 + <Col className="col_6 no-border">
  285 + 开票人:<InvoiceInfo>{data.invoicingPerson}</InvoiceInfo>
  286 + </Col>
  287 + </Row>
  288 + </InvoiceTmpDiv>
  289 + </div>
  290 + );
  291 +};
... ...
src/pages/Invoice/InvoiceRecord/components/InvoiceDetailImportModal.tsx 0 → 100644
  1 +import { RESPONSE_CODE } from '@/constants/enum';
  2 +import { postServiceInvoiceImportInvoiceDetails } from '@/services';
  3 +import { ModalForm, ProFormUploadDragger } from '@ant-design/pro-components';
  4 +import { Button, Form, message } from 'antd';
  5 +
  6 +export default ({ recordId }) => {
  7 + const [form] = Form.useForm();
  8 + return (
  9 + <ModalForm
  10 + title="新建表单"
  11 + trigger={<Button type="primary">导入明细</Button>}
  12 + form={form}
  13 + autoFocusFirstInput
  14 + modalProps={{
  15 + destroyOnClose: true,
  16 + onCancel: () => console.log('run'),
  17 + }}
  18 + submitTimeout={2000}
  19 + onFinish={async (values) => {
  20 + const formData = new FormData();
  21 + // console.log(fileList[0] as RcFile)
  22 + // formData.append('file', fileList[0] as RcFile);
  23 + formData.append('invoiceRecordId', recordId);
  24 + formData.append('detailsExcel', values.detailsExcel[0].originFileObj);
  25 + // You can use any AJAX library you like
  26 + const res = await postServiceInvoiceImportInvoiceDetails({
  27 + data: formData,
  28 + headers: {
  29 + 'Content-Type':
  30 + 'multipart/form-data; boundary=----WebKitFormBoundarynl6gT1BKdPWIejNq',
  31 + },
  32 + });
  33 + if (res.result === RESPONSE_CODE.SUCCESS) {
  34 + message.success('导入成功');
  35 + return true;
  36 + }
  37 + }}
  38 + >
  39 + <ProFormUploadDragger name="detailsExcel" label="导入明细表" />
  40 + </ModalForm>
  41 + );
  42 +};
... ...
src/pages/Invoice/components/InvoiceDetailTable.tsx renamed to src/pages/Invoice/InvoiceRecord/components/InvoiceDetailTable.tsx
1   -import InvoiceDetailImportModal from '@/pages/Invoice/components/InvoiceDetailImportModal';
2   -import { InvoiceProjectSelect } from '@/pages/Invoice/components/InvoiceProjectSelect';
  1 +import InvoiceDetailImportModal from '@/pages/Invoice/InvoiceRecord/components/InvoiceDetailImportModal';
  2 +import { InvoiceProjectSelect } from '@/pages/Invoice/InvoiceRecord/components/InvoiceProjectSelect';
3 3 import {
4 4 ActionType,
5 5 EditableProTable,
... ...
src/pages/Invoice/components/InvoiceModal.tsx renamed to src/pages/Invoice/InvoiceRecord/components/InvoiceModal.tsx
1   -import Invoice from '@/pages/Invoice/components/Invoice';
  1 +import Invoice from '@/pages/Invoice/InvoiceRecord/components/Invoice';
2 2 import { postServiceInvoiceGetInvoiceRecord } from '@/services';
3 3 import { ModalForm } from '@ant-design/pro-components';
4 4 import { Form } from 'antd';
... ...
src/pages/Invoice/InvoiceRecord/components/InvoiceProjectSelect.tsx 0 → 100644
  1 +import { postServiceConstListInvoiceDetailNames } from '@/services';
  2 +import { Select, Tooltip } from 'antd';
  3 +import { useState } from 'react';
  4 +
  5 +export const InvoiceProjectSelect = ({ readOnly, value, onChange }) => {
  6 + const [options, setOptions] = useState<any[]>([]);
  7 + // 定义防抖函数
  8 + let timeoutId = null;
  9 + const fetchOptions = async (keywords) => {
  10 + clearTimeout(timeoutId);
  11 + timeoutId = setTimeout(async () => {
  12 + const res = await postServiceConstListInvoiceDetailNames({
  13 + data: {
  14 + nameLike: keywords,
  15 + },
  16 + });
  17 + const data = res.data;
  18 +
  19 + setOptions(
  20 + data.map((item) => {
  21 + console.log(item);
  22 + return {
  23 + key: item.id,
  24 + label:
  25 + '*' +
  26 + item.productAndServiceCatagoryAbbreviation +
  27 + '*' +
  28 + item?.name,
  29 + value:
  30 + '*' +
  31 + item.productAndServiceCatagoryAbbreviation +
  32 + '*' +
  33 + item?.name,
  34 + ...item,
  35 + };
  36 + }),
  37 + );
  38 + // 这里可以放置实际的搜索逻辑,比如发起网络请求等
  39 + }, 500); // 设置延迟时间,单位毫秒
  40 + };
  41 +
  42 + return readOnly ? (
  43 + <Tooltip title={value}>{value}</Tooltip>
  44 + ) : (
  45 + <Select
  46 + key="project"
  47 + /*readonly={readonly}*/
  48 + showSearch
  49 + placeholder="请选择开票项目"
  50 + filterOption={(input, option) => (option?.label ?? '').includes(input)}
  51 + onChange={(e) => {
  52 + onChange(e);
  53 + }}
  54 + defaultValue={value}
  55 + options={options}
  56 + onSearch={(e) => {
  57 + fetchOptions(e);
  58 + }}
  59 + />
  60 + );
  61 +};
... ...
src/pages/Invoice/components/InvoiceRecordDetailModal.tsx renamed to src/pages/Invoice/InvoiceRecord/components/InvoiceRecordDetailModal.tsx
1 1 import { RESPONSE_CODE } from '@/constants/enum';
2   -import InvoiceDetailTable from '@/pages/Invoice/components/InvoiceDetailTable';
  2 +import InvoiceDetailTable from '@/pages/Invoice/InvoiceRecord/components/InvoiceDetailTable';
3 3 import {
4 4 postServiceConstGetPayeeEnum,
5 5 postServiceConstInvoiceType,
... ...
src/pages/Invoice/InvoiceRecord/components/InvoiceVerificationModal.tsx 0 → 100644
  1 +import ButtonConfirm from '@/components/ButtomConfirm';
  2 +import EllipsisDiv from '@/components/Div/EllipsisDiv';
  3 +import { RESPONSE_CODE } from '@/constants/enum';
  4 +import { INVOCING_STATUS, PAYEE_OPTIONS } from '@/pages/Order/constant';
  5 +import {
  6 + postServiceInvoiceCancelInvoiceAndBankStatement,
  7 + postServiceInvoiceQueryInvoiceDetail,
  8 +} from '@/services';
  9 +import { enumValueToLabel, formatDateTime } from '@/utils';
  10 +import { formatDate } from '@/utils/time';
  11 +import { PlusOutlined } from '@ant-design/icons';
  12 +import {
  13 + ActionType,
  14 + ModalForm,
  15 + ProCard,
  16 + ProTable,
  17 +} from '@ant-design/pro-components';
  18 +import {
  19 + Button,
  20 + Descriptions,
  21 + DescriptionsProps,
  22 + Divider,
  23 + Flex,
  24 + Form,
  25 + message,
  26 +} from 'antd';
  27 +import { useEffect, useRef, useState } from 'react';
  28 +import { BANK_STATEMENT_COLUMNS, INVOICE_STATUS } from '../../constant';
  29 +import '../index.less';
  30 +import BankChooseModal from './BankChooseModal';
  31 +
  32 +export default ({ invoiceId, setVisible, onClose }) => {
  33 + const [form] = Form.useForm<{ id: string }>();
  34 + const [bankChooseModalVisible, setBankChooseModalVisible] = useState(false);
  35 + const [invoiceInfo, setInvoiceInfo] = useState({});
  36 + const [relationOrderIds, setRelationOrderIds] = useState([]);
  37 + const [relationBankStatements, setRelationBankStatements] = useState([]);
  38 + const actionRef = useRef<ActionType>();
  39 +
  40 + const loadInvoiceData = async () => {
  41 + let res = await postServiceInvoiceQueryInvoiceDetail({
  42 + data: { invoiceId: invoiceId },
  43 + });
  44 + if (res && res.data) {
  45 + setInvoiceInfo(res.data);
  46 + setRelationOrderIds(res.data.mainOrderIds);
  47 + console.log('bs:' + res.data.bankStatementDtos);
  48 + setRelationBankStatements(res.data.bankStatementDtos);
  49 + }
  50 + };
  51 +
  52 + const showRelationOrders = () => {
  53 + return relationOrderIds?.map((item) => {
  54 + return (
  55 + <>
  56 + <Button
  57 + className="pl-1 pr-0"
  58 + type="link"
  59 + target="_blank"
  60 + href={'/order?id=' + item}
  61 + >
  62 + {item}
  63 + </Button>
  64 + <Divider type="vertical" />
  65 + </>
  66 + );
  67 + });
  68 + };
  69 +
  70 + const items: DescriptionsProps['items'] = [
  71 + {
  72 + key: '1',
  73 + label: '发票号码',
  74 + children: invoiceInfo?.invoiceNumber,
  75 + span: 6,
  76 + },
  77 + {
  78 + key: '2',
  79 + label: '发票类型',
  80 + children: enumValueToLabel(invoiceInfo?.invoiceStatus, INVOCING_STATUS),
  81 + span: 6,
  82 + },
  83 + {
  84 + key: '3',
  85 + label: '状态',
  86 + children: enumValueToLabel(invoiceInfo?.status, INVOICE_STATUS),
  87 + span: 4,
  88 + },
  89 + {
  90 + key: '4',
  91 + label: '购买方',
  92 + children: invoiceInfo?.purchaser,
  93 + span: 8,
  94 + },
  95 + {
  96 + key: '5',
  97 + label: '收款单位',
  98 + children: enumValueToLabel(invoiceInfo?.payee, PAYEE_OPTIONS),
  99 + span: 12,
  100 + },
  101 + {
  102 + key: '6',
  103 + label: '联系人',
  104 + children: invoiceInfo?.contacts,
  105 + span: 4,
  106 + },
  107 + {
  108 + key: '7',
  109 + label: '销售',
  110 + children: invoiceInfo?.sale,
  111 + span: 8,
  112 + },
  113 +
  114 + {
  115 + key: '9',
  116 + label: '开票日期',
  117 + children: formatDate(invoiceInfo?.invoicingTime),
  118 + span: 12,
  119 + },
  120 + {
  121 + key: '10',
  122 + label: '收款时间',
  123 + children: formatDate(invoiceInfo?.collectionTime),
  124 + span: 4,
  125 + },
  126 + {
  127 + key: '8',
  128 + label: '金额',
  129 + children: invoiceInfo?.money,
  130 + span: 10,
  131 + },
  132 + {
  133 + key: '11',
  134 + label: '备注',
  135 + children: invoiceInfo?.notes,
  136 + span: 24,
  137 + },
  138 + ];
  139 +
  140 + const getTableCellText = (target: any) => {
  141 + if (!target) {
  142 + return '';
  143 + }
  144 +
  145 + if (target.props) {
  146 + return target.props.text;
  147 + }
  148 +
  149 + return target;
  150 + };
  151 +
  152 + /**
  153 + * 加载表格的各个列格式
  154 + */
  155 + const bankStatementColumnsInit = () => {
  156 + let columns = BANK_STATEMENT_COLUMNS.map((item) => {
  157 + let newItem = { ...item };
  158 + let dataIndex = item.dataIndex;
  159 + let dataType = item.valueType;
  160 +
  161 + newItem.render = (text, record) => {
  162 + let textValue = record[dataIndex];
  163 +
  164 + if (dataType === 'date') {
  165 + textValue = formatDate(textValue);
  166 + }
  167 +
  168 + if (dataType === 'dateTime') {
  169 + textValue = formatDateTime(textValue);
  170 + }
  171 +
  172 + if (dataType === 'money') {
  173 + textValue = '¥' + textValue;
  174 + }
  175 +
  176 + switch (dataIndex) {
  177 + case 'invoiceStatus':
  178 + return (
  179 + <EllipsisDiv
  180 + text={enumValueToLabel(
  181 + getTableCellText(textValue),
  182 + INVOCING_STATUS,
  183 + )}
  184 + />
  185 + );
  186 +
  187 + case 'status':
  188 + return (
  189 + <EllipsisDiv
  190 + text={enumValueToLabel(
  191 + getTableCellText(textValue),
  192 + INVOICE_STATUS,
  193 + )}
  194 + />
  195 + );
  196 +
  197 + case 'payee':
  198 + return (
  199 + <EllipsisDiv
  200 + text={enumValueToLabel(
  201 + getTableCellText(textValue),
  202 + PAYEE_OPTIONS,
  203 + )}
  204 + />
  205 + );
  206 +
  207 + default:
  208 + return <EllipsisDiv text={getTableCellText(textValue)} />;
  209 + }
  210 + };
  211 +
  212 + return newItem;
  213 + });
  214 +
  215 + columns.push({
  216 + title: '操作',
  217 + valueType: 'option',
  218 + key: 'option',
  219 + fixed: 'right',
  220 + width: 70,
  221 + render: (text, record) => {
  222 + let optBtns = [];
  223 + if (invoiceInfo?.status === 'VERIFIED') {
  224 + return [];
  225 + }
  226 +
  227 + optBtns.push(
  228 + <ButtonConfirm
  229 + key="delete"
  230 + className="p-0"
  231 + title={'确认删除此项吗?'}
  232 + text="删除"
  233 + onConfirm={async () => {
  234 + let res = await postServiceInvoiceCancelInvoiceAndBankStatement({
  235 + data: {
  236 + invoiceId: invoiceId,
  237 + cancelId: [record.id],
  238 + },
  239 + });
  240 + if (res.result === RESPONSE_CODE.SUCCESS) {
  241 + message.success(res.message);
  242 + loadInvoiceData();
  243 + }
  244 + }}
  245 + />,
  246 + );
  247 + return optBtns;
  248 + },
  249 + });
  250 +
  251 + return columns;
  252 + };
  253 +
  254 + useEffect(() => {
  255 + loadInvoiceData();
  256 + }, []);
  257 +
  258 + return (
  259 + <>
  260 + <ModalForm<{
  261 + id: string;
  262 + }>
  263 + className="invoice-detail"
  264 + open
  265 + width="80%"
  266 + title="发票详情"
  267 + form={form}
  268 + autoFocusFirstInput
  269 + modalProps={{
  270 + okText: '确定',
  271 + cancelText: '返回',
  272 + destroyOnClose: true,
  273 + onCancel: () => {
  274 + setVisible(false);
  275 + onClose();
  276 + },
  277 + }}
  278 + submitter={{
  279 + render: (props, defaultDoms) => {
  280 + return [defaultDoms[0]];
  281 + },
  282 + }}
  283 + onFinish={async () => {
  284 + onClose();
  285 + }}
  286 + onOpenChange={setVisible}
  287 + >
  288 + <Divider orientation="left" plain>
  289 + 发票信息
  290 + </Divider>
  291 +
  292 + <Descriptions
  293 + bordered
  294 + column={24}
  295 + size="small"
  296 + title=""
  297 + items={items}
  298 + />
  299 +
  300 + <Divider orientation="left" plain>
  301 + 订单号
  302 + </Divider>
  303 +
  304 + <ProCard bordered style={{}}>
  305 + <Flex>
  306 + <div>{showRelationOrders()}</div>
  307 + </Flex>
  308 + </ProCard>
  309 +
  310 + <Divider plain></Divider>
  311 +
  312 + <ProTable
  313 + columns={bankStatementColumnsInit()}
  314 + actionRef={actionRef}
  315 + cardBordered
  316 + pagination={{
  317 + pageSize: 10,
  318 + }}
  319 + dataSource={relationBankStatements}
  320 + columnsState={{
  321 + persistenceKey: 'pro-table-singe-demos',
  322 + persistenceType: 'localStorage',
  323 + defaultValue: {
  324 + option: { fixed: 'right', disable: true },
  325 + },
  326 + onChange(value) {
  327 + console.log('value: ', value);
  328 + },
  329 + }}
  330 + rowKey="id"
  331 + search={false}
  332 + options={{
  333 + setting: {
  334 + listsHeight: 400,
  335 + },
  336 + reload: false,
  337 + }}
  338 + form={{
  339 + // 由于配置了 transform,提交的参与与定义的不同这里需要转化一下
  340 + syncToUrl: (values, type) => {
  341 + if (type === 'get') {
  342 + return {
  343 + ...values,
  344 + created_at: [values.startTime, values.endTime],
  345 + };
  346 + }
  347 + return values;
  348 + },
  349 + }}
  350 + dateFormatter="string"
  351 + headerTitle="银行流水"
  352 + scroll={{ x: 1400, y: 360 }}
  353 + toolBarRender={() => [
  354 + <Button
  355 + key="button"
  356 + icon={<PlusOutlined />}
  357 + onClick={() => {
  358 + setBankChooseModalVisible(true);
  359 + }}
  360 + hidden={invoiceInfo?.status === 'VERIFIED'}
  361 + type="primary"
  362 + >
  363 + 添加
  364 + </Button>,
  365 + ]}
  366 + />
  367 + </ModalForm>
  368 +
  369 + {bankChooseModalVisible ? (
  370 + <BankChooseModal
  371 + loadInvoiceData={loadInvoiceData}
  372 + setVisible={setBankChooseModalVisible}
  373 + invoiceId={invoiceId}
  374 + onClose={() => {
  375 + setBankChooseModalVisible(false);
  376 + loadInvoiceData();
  377 + actionRef.current?.reload();
  378 + }}
  379 + ></BankChooseModal>
  380 + ) : (
  381 + ''
  382 + )}
  383 + </>
  384 + );
  385 +};
... ...
src/pages/Invoice/components/InvoicingModal.tsx renamed to src/pages/Invoice/InvoiceRecord/components/InvoicingModal.tsx
src/pages/Invoice/components/ManualInvoicingModal.tsx renamed to src/pages/Invoice/InvoiceRecord/components/ManualInvoicingModal.tsx
1 1 import { RESPONSE_CODE } from '@/constants/enum';
2   -import UploadC from '@/pages/Invoice/components/UploadSingleImg';
  2 +import UploadC from '@/pages/Invoice/InvoiceRecord/components/UploadSingleImg';
3 3 import {
4 4 postOrderErpOrderStagesUpload,
5 5 postServiceInvoiceDealInvoicingResult,
... ...
src/pages/Invoice/components/UploadSingleImg.tsx renamed to src/pages/Invoice/InvoiceRecord/components/UploadSingleImg.tsx
src/pages/Invoice/InvoiceRecord/index.tsx
1   -import ButtonConfirm from '@/components/ButtomConfirm';
2   -import EllipsisDiv from '@/components/Div/EllipsisDiv';
3   -import { RESPONSE_CODE } from '@/constants/enum';
4   -import AddInvoiceDrawerForm from '@/pages/Invoice/components/AddInvoiceDrawerForm';
5   -import BankImportModal from '@/pages/Invoice/components/BankImportModal';
6   -import InvoiceModal from '@/pages/Invoice/components/InvoiceModal';
7   -import InvoiceRecordDetailModal from '@/pages/Invoice/components/InvoiceRecordDetailModal';
8   -import InvoiceVerificationModal from '@/pages/Invoice/components/InvoiceVerificationModal';
9   -import InvoicingModal from '@/pages/Invoice/components/InvoicingModal';
10   -import ManualInvoicingModal from '@/pages/Invoice/components/ManualInvoicingModal';
  1 +import InvoiceRecordDetailModal from '@/pages/Invoice/InvoiceRecord/components/InvoiceRecordDetailModal';
  2 +import ManualInvoicingModal from '@/pages/Invoice/InvoiceRecord/components/ManualInvoicingModal';
  3 +import { PAYEE_OPTIONS } from '@/pages/Order/constant';
11 4 import {
12   - BANK_STATEMENT_COLUMNS,
13   - INVOICE_COLUMNS,
14   - INVOICE_STATUS,
15   -} from '@/pages/Invoice/constant';
16   -import { INVOCING_STATUS, PAYEE_OPTIONS } from '@/pages/Order/constant';
17   -import {
18   - postServiceBankStatementDeleteBankStatement,
19 5 postServiceBankStatementEditBankStatement,
20   - postServiceBankStatementQueryBankStatement,
21 6 postServiceConstAfterInvoicingInvoiceRecordStatus,
22   - postServiceConstBeforeInvoicingInvoiceRecordStatus,
23 7 postServiceConstInvoiceType,
24   - postServiceConstInvoicingType,
25   - postServiceInvoiceDeleteInvoice,
26 8 postServiceInvoiceInvoicing,
27   - postServiceInvoiceQueryInvoice,
28 9 postServiceInvoiceQueryInvoiceRecordList,
29 10 postServiceOrderQuerySalesCode,
30 11 } from '@/services';
31 12 import { excelExport } from '@/services/exportRequest';
32   -import {
33   - enumToProTableEnumValue,
34   - enumToSelect,
35   - enumValueToLabel,
36   - formatDateTime,
37   -} from '@/utils';
38   -import { formatDate } from '@/utils/time';
39   -import { PlusOutlined } from '@ant-design/icons';
  13 +import { enumToProTableEnumValue, enumToSelect } from '@/utils';
40 14 import { ActionType, ModalForm, ProTable } from '@ant-design/pro-components';
41   -import { Button, Space, Table, Tabs, message } from 'antd';
  15 +import { Button, message } from 'antd';
42 16 import { useEffect, useRef, useState } from 'react';
43 17  
44 18 const InvoiceRecord = () => {
45   - const invoiceActionRef = useRef<ActionType>();
46   - const bankActionRef = useRef<ActionType>();
47   - const waitDealrecordActionRef = useRef<ActionType>();
48 19 const processedRecordRef = useRef<ActionType>();
49 20 const [invoiceTypeValueEnum, setInvoiceTypeValueEnum] = useState({});
50   - const [invoicingTypeValueEnum, setInvoicingTypeValueEnum] = useState({});
51 21 const [salesCodeValueEnum, setSalesCodeValueEnum] = useState({});
52   - const [bankImportModalVisible, setBankImportModalVisible] = useState(false);
53   - const [invoiceVerificationVisible, setInvoiceVerificationVisible] =
54   - useState(false);
55   - const [invoiceId, setInvoiceId] = useState(undefined);
56 22 const [invoiceRecordDetailVisible, setInvoiceRecordDetailVisible] =
57 23 useState(false);
58 24 const [invoiceRecord, setInvoiceRecord] = useState({});
... ... @@ -69,15 +35,6 @@ const InvoiceRecord = () =&gt; {
69 35  
70 36 useEffect(() => {
71 37 async function extracted() {
72   - let invoicingTypeRet = await postServiceConstInvoicingType();
73   - setInvoicingTypeValueEnum(invoicingTypeRet.data);
74   - }
75   -
76   - extracted().catch(console.error);
77   - }, []);
78   -
79   - useEffect(() => {
80   - async function extracted() {
81 38 const res = await postServiceOrderQuerySalesCode();
82 39 let map = {};
83 40 res.data?.forEach((item) => {
... ... @@ -92,271 +49,6 @@ const InvoiceRecord = () =&gt; {
92 49 extracted().catch(console.error);
93 50 }, []);
94 51  
95   - const reloadInvoiceTable = () => {
96   - invoiceActionRef.current?.reload();
97   - };
98   -
99   - const reloadBankStatementTable = () => {
100   - bankActionRef.current?.reload();
101   - };
102   - const reloadRecordTable = () => {
103   - waitDealrecordActionRef.current?.reload();
104   - processedRecordRef.current?.reload();
105   - };
106   -
107   - const getTableCellText = (target: any) => {
108   - if (!target) {
109   - return '';
110   - }
111   -
112   - if (target.props) {
113   - return target.props.text;
114   - }
115   -
116   - return target;
117   - };
118   -
119   - const waitDealRecordColumns = [
120   - {
121   - dataIndex: 'index',
122   - valueType: 'indexBorder',
123   - hideInSearch: true,
124   - ellipsis: true,
125   - width: 48,
126   - },
127   - {
128   - title: '开票编号',
129   - valueType: 'text',
130   - dataIndex: 'id',
131   - copyable: true,
132   - hideInSearch: true,
133   - ellipsis: true,
134   - width: 100,
135   - },
136   - {
137   - title: '发票状态',
138   - valueType: 'Text',
139   - dataIndex: 'statusText',
140   - ellipsis: true,
141   - hideInSearch: true,
142   - },
143   - {
144   - title: '申请开票时间',
145   - dataIndex: 'createTime',
146   - valueType: 'dateTime',
147   - hideInSearch: true,
148   - ellipsis: true,
149   - },
150   - {
151   - title: '销售代表',
152   - valueType: 'text',
153   - hideInSearch: true,
154   - ellipsis: true,
155   - dataIndex: 'createByName',
156   - },
157   - {
158   - title: '购方名称',
159   - valueType: 'text',
160   - dataIndex: 'partyAName',
161   - hideInSearch: true,
162   - ellipsis: true,
163   - },
164   - {
165   - title: '购方税号',
166   - valueType: 'text',
167   - hideInSearch: true,
168   - dataIndex: 'partyATaxid',
169   - ellipsis: true,
170   - },
171   - {
172   - title: '收款单位',
173   - valueType: 'text',
174   - hideInSearch: true,
175   - dataIndex: 'partyBName',
176   - ellipsis: true,
177   - },
178   - {
179   - title: '开票金额',
180   - valueType: 'money',
181   - dataIndex: 'price',
182   - hideInSearch: true,
183   - ellipsis: true,
184   - },
185   - {
186   - title: '开具类型',
187   - valueType: 'Text',
188   - dataIndex: 'invoicingTypeText',
189   - hideInSearch: true,
190   - ellipsis: true,
191   - },
192   - {
193   - title: '发票类型',
194   - valueType: 'Text',
195   - dataIndex: 'typeText',
196   - hideInSearch: true,
197   - ellipsis: true,
198   - },
199   - {
200   - title: '是否加急',
201   - valueType: 'Text',
202   - dataIndex: 'isUrgentText',
203   - hideInSearch: true,
204   - ellipsis: true,
205   - },
206   - {
207   - title: '申请备注',
208   - valueType: 'text',
209   - dataIndex: 'applyInvoicingNotes',
210   - hideInSearch: true,
211   - ellipsis: true,
212   - },
213   - {
214   - title: '购方名称',
215   - valueType: 'Text',
216   - dataIndex: 'partyANameLike',
217   - hideInTable: true,
218   - },
219   - {
220   - title: '收款单位',
221   - valueType: 'select',
222   - dataIndex: 'partyB',
223   - filters: true,
224   - onFilter: true,
225   - hideInTable: true,
226   - valueEnum: enumToProTableEnumValue(PAYEE_OPTIONS),
227   - },
228   - {
229   - title: '主订单号',
230   - valueType: 'Text',
231   - dataIndex: 'mainOrderId',
232   - hideInTable: true,
233   - },
234   - {
235   - title: '子订单号',
236   - valueType: 'Text',
237   - dataIndex: 'subOrderId',
238   - hideInTable: true,
239   - },
240   - {
241   - title: '销售代表',
242   - valueType: 'select',
243   - dataIndex: 'salesCode',
244   - filters: true,
245   - onFilter: true,
246   - hideInTable: true,
247   - valueEnum: salesCodeValueEnum,
248   - },
249   - {
250   - title: '发票类型',
251   - valueType: 'select',
252   - dataIndex: 'type',
253   - filters: true,
254   - onFilter: true,
255   - hideInTable: true,
256   - valueEnum: enumToProTableEnumValue(invoiceTypeValueEnum),
257   - },
258   - {
259   - title: '开具类型',
260   - valueType: 'select',
261   - dataIndex: 'invoicingType',
262   - filters: true,
263   - onFilter: true,
264   - hideInTable: true,
265   - valueEnum: enumToProTableEnumValue(invoicingTypeValueEnum),
266   - },
267   - {
268   - title: '开票状态',
269   - valueType: 'select',
270   - dataIndex: 'status',
271   - filters: true,
272   - onFilter: true,
273   - hideInTable: true,
274   - request: async () => {
275   - const res = await postServiceConstBeforeInvoicingInvoiceRecordStatus();
276   - return enumToSelect(res.data);
277   - },
278   - },
279   - {
280   - title: '是否加急',
281   - valueType: 'select',
282   - dataIndex: 'isUrgent',
283   - filters: true,
284   - onFilter: true,
285   - hideInTable: true,
286   - valueEnum: {
287   - true: {
288   - text: '是',
289   - status: true,
290   - },
291   - false: {
292   - text: '否',
293   - status: false,
294   - },
295   - },
296   - },
297   - {
298   - title: '申请开票时间',
299   - dataIndex: 'createTime',
300   - valueType: 'dateTimeRange',
301   - width: 200,
302   - hideInTable: true,
303   - search: {
304   - transform: (value) => {
305   - if (value) {
306   - return {
307   - createTimeGe: value[0],
308   - createTimeLe: value[1],
309   - };
310   - }
311   - },
312   - },
313   - },
314   - {
315   - title: '操作',
316   - valueType: 'option',
317   - key: 'option',
318   - render: (text, record) => {
319   - return [
320   - /*<InvoiceRecordDetailModal
321   - key="detail"
322   - id={record.id}
323   - subOrderIds={record.subOrderIds}
324   - onClose={()=>{
325   - waitDealrecordActionRef.current?.reload();
326   - }
327   - }
328   - />*/
329   - <>
330   - {record.paths.includes('DETAIL') && (
331   - <a
332   - key="detail"
333   - onClick={() => {
334   - setInvoiceRecordDetailVisible(true);
335   - setInvoiceRecord(record);
336   - }}
337   - >
338   - 详情
339   - </a>
340   - )}
341   - </>,
342   - <>
343   - {record.paths.includes('PREVIEW') && (
344   - <InvoiceModal key="invoiceModal" recordId={record.id} />
345   - )}
346   - </>,
347   - <>
348   - {record.paths.includes('INVOICING') && (
349   - <ManualInvoicingModal
350   - key={'ManualInvoicingModal'}
351   - record={record}
352   - ></ManualInvoicingModal>
353   - )}
354   - </>,
355   - ];
356   - },
357   - },
358   - ];
359   -
360 52 const processedRecordColumns = [
361 53 {
362 54 dataIndex: 'index',
... ... @@ -527,7 +219,7 @@ const InvoiceRecord = () =&gt; {
527 219 key: 'option',
528 220 render: (text, record) => [
529 221 <>
530   - {record.status === 'SUCCESS' && record.paths.includes('DETAIL') && (
  222 + {record.paths.includes('DETAIL') && (
531 223 <a
532 224 key="detail"
533 225 onClick={() => {
... ... @@ -589,576 +281,91 @@ const InvoiceRecord = () =&gt; {
589 281 ],
590 282 },
591 283 ];
592   - /**
593   - * 加载发票列表表格的各个列格式
594   - */
595   - const invoicecColumnsInit = () => {
596   - let columns = INVOICE_COLUMNS.map((item) => {
597   - let newItem = { ...item };
598   - let dataIndex = item.dataIndex;
599   - let dataType = item.valueType;
600   -
601   - newItem.render = (text, record) => {
602   - let textValue = record[dataIndex];
603   -
604   - if (dataType === 'dateRange' || dataType === 'date') {
605   - textValue = formatDate(textValue);
606   - }
607   -
608   - if (dataType === 'dateTime') {
609   - textValue = formatDateTime(textValue);
610   - }
611   -
612   - if (dataType === 'money') {
613   - textValue = '¥' + textValue;
614   - }
615   -
616   - switch (dataIndex) {
617   - case 'invoiceStatus':
618   - return (
619   - <EllipsisDiv
620   - text={enumValueToLabel(
621   - getTableCellText(textValue),
622   - INVOCING_STATUS,
623   - )}
624   - />
625   - );
626   -
627   - case 'status':
628   - return (
629   - <EllipsisDiv
630   - text={enumValueToLabel(
631   - getTableCellText(textValue),
632   - INVOICE_STATUS,
633   - )}
634   - />
635   - );
636   -
637   - case 'payee':
638   - return (
639   - <EllipsisDiv
640   - text={enumValueToLabel(
641   - getTableCellText(textValue),
642   - PAYEE_OPTIONS,
643   - )}
644   - />
645   - );
646   -
647   - default:
648   - return <EllipsisDiv text={getTableCellText(textValue)} />;
649   - }
650   - };
651   -
652   - return newItem;
653   - });
654   -
655   - columns.push({
656   - title: '操作',
657   - valueType: 'option',
658   - key: 'option',
659   - fixed: 'right',
660   - width: 120,
661   - render: (text, record) => {
662   - let btns = [];
663   - if (record.path?.includes('writeOff')) {
664   - btns.push(
665   - <a
666   - key="editable"
667   - onClick={() => {
668   - setInvoiceVerificationVisible(true);
669   - setInvoiceId(record.invoiceId);
670   - }}
671   - >
672   - 核销
673   - </a>,
674   - );
675   - }
676   -
677   - if (record.path?.includes('queryInvoiceDetails')) {
678   - btns.push(
  284 + return (
  285 + <div className="invoice-index">
  286 + <ProTable
  287 + columns={processedRecordColumns}
  288 + actionRef={processedRecordRef}
  289 + cardBordered
  290 + pagination={{
  291 + showSizeChanger: true, // 显示可以选择每页显示条数的下拉菜单
  292 + pageSizeOptions: ['10', '20', '50', '100'], // 设置可以选择的每页显示条数选项
  293 + }}
  294 + editable={{
  295 + type: 'multiple',
  296 + onSave: async (rowKey, data) => {
  297 + await postServiceBankStatementEditBankStatement({ data: data });
  298 + },
  299 + actionRender: (row, config, defaultDom) => [
  300 + defaultDom.save,
  301 + defaultDom.cancel,
  302 + ],
  303 + }}
  304 + search={{
  305 + labelWidth: 'auto',
  306 + defaultCollapsed: false,
  307 + optionRender: (searchConfig, formProps, dom) => [
  308 + ...dom,
679 309 <Button
680   - className="p-0"
681   - key="view"
682   - type="link"
  310 + key="out"
683 311 onClick={() => {
684   - setInvoiceVerificationVisible(true);
685   - setInvoiceId(record.invoiceId);
686   - }}
687   - >
688   - 查看
689   - </Button>,
690   - );
691   - }
692   -
693   - if (record.path?.includes('deleteInvoice')) {
694   - btns.push(
695   - <ButtonConfirm
696   - key="delete"
697   - className="p-0"
698   - title={
699   - '确认删除发票号码为[ ' + record.invoiceNumber + ' ]的发票吗?'
700   - }
701   - text="删除"
702   - onConfirm={async () => {
703   - let res = await postServiceInvoiceDeleteInvoice({
704   - data: { invoiceId: record.invoiceId },
  312 + const values = searchConfig?.form?.getFieldsValue();
  313 + console.log(values);
  314 + messageApi.open({
  315 + type: 'loading',
  316 + content: '正在导出文件...',
705 317 });
706   - if (res) {
707   - message.success(res.message);
708   - reloadInvoiceTable();
709   - }
710   - }}
711   - />,
712   - );
713   - }
714   - return btns;
715   - },
716   - });
717   -
718   - return columns;
719   - };
720   -
721   - const bankStatemetColumnsInit = () => {
722   - let columns = BANK_STATEMENT_COLUMNS.map((item) => {
723   - let newItem = { ...item };
724   - let dataIndex = item.dataIndex;
725   - let dataType = item.valueType;
726   -
727   - newItem.render = (text, record) => {
728   - let textValue = record[dataIndex];
729   -
730   - if (dataType === 'date') {
731   - textValue = formatDate(textValue);
732   - }
733   -
734   - if (dataType === 'dateTime') {
735   - textValue = formatDateTime(textValue);
736   - }
737   -
738   - if (dataType === 'money') {
739   - if (textValue === null || textValue === undefined) {
740   - textValue = '';
741   - } else {
742   - textValue = '¥' + textValue;
743   - }
744   - }
745   -
746   - switch (dataIndex) {
747   - case 'invoiceStatus':
748   - return (
749   - <EllipsisDiv
750   - text={enumValueToLabel(
751   - getTableCellText(textValue),
752   - INVOCING_STATUS,
753   - )}
754   - />
755   - );
756   -
757   - case 'status':
758   - return (
759   - <EllipsisDiv
760   - text={enumValueToLabel(
761   - getTableCellText(textValue),
762   - INVOICE_STATUS,
763   - )}
764   - />
765   - );
766   -
767   - case 'payee':
768   - return (
769   - <EllipsisDiv
770   - text={enumValueToLabel(
771   - getTableCellText(textValue),
772   - PAYEE_OPTIONS,
773   - )}
774   - />
775   - );
776   -
777   - default:
778   - return <EllipsisDiv text={getTableCellText(textValue)} />;
779   - }
780   - };
781   -
782   - return newItem;
783   - });
784   -
785   - columns.push({
786   - title: '操作',
787   - valueType: 'option',
788   - key: 'option',
789   - fixed: 'right',
790   - width: 120,
791   - render: (text, record, _, action) => {
792   - let btns = [];
793   - if (record.path?.includes('editBankStatement')) {
794   - btns.push(
795   - <a
796   - key="editable"
797   - onClick={() => {
798   - action?.startEditable?.(record.id);
799   - }}
800   - >
801   - 编辑
802   - </a>,
803   - );
804   - }
805   -
806   - if (record.path?.includes('deleteBankStatement')) {
807   - btns.push(
808   - <ButtonConfirm
809   - key="delete"
810   - className="p-0"
811   - title={'是否删除该银行流水记录?'}
812   - text="删除"
813   - onConfirm={async () => {
814   - let res = await postServiceBankStatementDeleteBankStatement({
815   - data: { id: record.id },
816   - });
817   - if (res.result === RESPONSE_CODE.SUCCESS) {
818   - message.success(res.message);
819   - reloadBankStatementTable();
820   - }
821   - }}
822   - />,
823   - );
824   - }
825   - return btns;
826   - },
827   - });
828   -
829   - return columns;
830   - };
831   -
832   - const tabsItems = [
833   - {
834   - key: 1,
835   - label: '待处理',
836   - children: (
837   - <ProTable
838   - columns={waitDealRecordColumns}
839   - actionRef={waitDealrecordActionRef}
840   - cardBordered
841   - pagination={{
842   - showSizeChanger: true, // 显示可以选择每页显示条数的下拉菜单
843   - pageSizeOptions: ['10', '20', '50', '100'], // 设置可以选择的每页显示条数选项
844   - }}
845   - rowSelection={{
846   - selections: [Table.SELECTION_ALL, Table.SELECTION_INVERT],
847   - alwaysShowAlert: true,
848   - }}
849   - tableAlertOptionRender={({ selectedRowKeys, selectedRows }) => {
850   - console.log(selectedRows);
851   - console.log(selectedRowKeys);
852   - return (
853   - <Space size={16}>
854   - <InvoicingModal
855   - reloadRecordTable={reloadRecordTable}
856   - key="button"
857   - selectedRowKeys={selectedRowKeys}
858   - />
859   - </Space>
860   - );
861   - }}
862   - request={async (params) => {
863   - let res = await postServiceInvoiceQueryInvoiceRecordList({
864   - data: {
865   - ...params,
866   - statusIn: [
867   - 'WAITING_FOR_INVOICING',
868   - 'AUDITING',
869   - 'AUDITING_NOT_PASSED',
870   - 'CANCELED',
871   - ],
872   - needBuildDetails: true,
873   - needBuildSubOrders: true,
874   - },
875   - });
876   - return {
877   - data: res?.data?.data,
878   - total: res?.data?.total || 0,
879   - };
880   - }}
881   - columnsState={{
882   - persistenceKey: 'pro-table-singe-demos',
883   - persistenceType: 'localStorage',
884   - defaultValue: {
885   - option: { fixed: 'right', disable: true },
886   - },
887   - onChange(value) {
888   - console.log('value: ', value);
889   - },
890   - }}
891   - rowKey="id"
892   - search={{
893   - labelWidth: 'auto',
894   - }}
895   - options={{
896   - setting: {
897   - listsHeight: 400,
898   - },
899   - }}
900   - form={{}}
901   - dateFormatter="string"
902   - headerTitle="待开票列表"
903   - scroll={{ x: 1400, y: 360 }}
904   - />
905   - ),
906   - },
907   - {
908   - key: 2,
909   - label: '开票记录',
910   - children: (
911   - <ProTable
912   - columns={processedRecordColumns}
913   - actionRef={processedRecordRef}
914   - cardBordered
915   - pagination={{
916   - showSizeChanger: true, // 显示可以选择每页显示条数的下拉菜单
917   - pageSizeOptions: ['10', '20', '50', '100'], // 设置可以选择的每页显示条数选项
918   - }}
919   - editable={{
920   - type: 'multiple',
921   - onSave: async (rowKey, data) => {
922   - await postServiceBankStatementEditBankStatement({ data: data });
923   - },
924   - actionRender: (row, config, defaultDom) => [
925   - defaultDom.save,
926   - defaultDom.cancel,
927   - ],
928   - }}
929   - search={{
930   - labelWidth: 'auto',
931   - defaultCollapsed: false,
932   - optionRender: (searchConfig, formProps, dom) => [
933   - ...dom,
934   - <Button
935   - key="out"
936   - onClick={() => {
937   - const values = searchConfig?.form?.getFieldsValue();
938   - console.log(values);
939   - messageApi.open({
940   - type: 'loading',
941   - content: '正在导出文件...',
942   - });
943   - excelExport(
944   - '/api/service/invoice/exportInvoiceRecords',
945   - {
946   - ...values,
947   - statusIn: ['INVOICING', 'SUCCESS', 'FAIL'],
948   - },
949   - () => {
950   - messageApi.destroy();
951   - },
952   - );
953   - }}
954   - >
955   - 导出
956   - </Button>,
957   - ],
958   - }}
959   - request={async (params) => {
960   - let res = await postServiceInvoiceQueryInvoiceRecordList({
961   - data: {
962   - ...params,
963   - statusIn: ['INVOICING', 'SUCCESS', 'FAIL'],
964   - },
965   - });
966   - return {
967   - data: res?.data?.data,
968   - total: res?.data?.total || 0,
969   - };
970   - }}
971   - columnsState={{
972   - persistenceKey: 'pro-table-singe-demos',
973   - persistenceType: 'localStorage',
974   - defaultValue: {
975   - option: { fixed: 'right', disable: true },
976   - },
977   - onChange(value) {
978   - console.log('value: ', value);
979   - },
980   - }}
981   - rowKey="id"
982   - options={{
983   - setting: {
984   - listsHeight: 400,
985   - },
986   - }}
987   - form={{}}
988   - dateFormatter="string"
989   - headerTitle="待开票列表"
990   - scroll={{ x: 1400, y: 360 }}
991   - toolBarRender={() => []}
992   - />
993   - ),
994   - },
995   - {
996   - key: 3,
997   - label: '发票管理',
998   - children: (
999   - <ProTable
1000   - columns={invoicecColumnsInit()}
1001   - actionRef={invoiceActionRef}
1002   - cardBordered
1003   - pagination={{
1004   - pageSize: 10,
1005   - }}
1006   - request={async (params) => {
1007   - const res = await postServiceInvoiceQueryInvoice({
1008   - data: { ...params },
1009   - });
1010   - if (res) {
1011   - return {
1012   - data: res?.data?.data || [],
1013   - total: res?.data?.total || 0,
1014   - };
1015   - }
1016   - }}
1017   - columnsState={{
1018   - persistenceKey: 'pro-table-singe-demos',
1019   - persistenceType: 'localStorage',
1020   - defaultValue: {
1021   - option: { fixed: 'right', disable: true },
1022   - },
1023   - onChange(value) {
1024   - console.log('value: ', value);
1025   - },
1026   - }}
1027   - rowKey="id"
1028   - search={{
1029   - labelWidth: 'auto',
1030   - }}
1031   - options={{
1032   - setting: {
1033   - listsHeight: 400,
1034   - },
1035   - }}
1036   - form={{}}
1037   - dateFormatter="string"
1038   - headerTitle="发票列表"
1039   - scroll={{ x: 1400, y: 360 }}
1040   - toolBarRender={() => [
1041   - <AddInvoiceDrawerForm
1042   - onClose={() => {
1043   - invoiceActionRef.current?.reload();
1044   - bankActionRef.current?.reload();
1045   - }}
1046   - key="add"
1047   - ></AddInvoiceDrawerForm>,
1048   - ]}
1049   - />
1050   - ),
1051   - },
1052   - {
1053   - key: 4,
1054   - label: '银行流水',
1055   - children: (
1056   - <ProTable
1057   - columns={bankStatemetColumnsInit()}
1058   - actionRef={bankActionRef}
1059   - cardBordered
1060   - pagination={{
1061   - pageSize: 10,
1062   - }}
1063   - editable={{
1064   - type: 'multiple',
1065   - onSave: async (rowKey, data) => {
1066   - await postServiceBankStatementEditBankStatement({ data: data });
1067   - },
1068   - actionRender: (row, config, defaultDom) => [
1069   - defaultDom.save,
1070   - defaultDom.cancel,
1071   - ],
1072   - }}
1073   - request={async (params) => {
1074   - const res = await postServiceBankStatementQueryBankStatement({
1075   - data: { ...params },
1076   - });
1077   - if (res) {
1078   - return {
1079   - data: res?.data?.data || [],
1080   - total: res?.data?.total || 0,
1081   - };
1082   - }
1083   - }}
1084   - columnsState={{
1085   - persistenceKey: 'pro-table-singe-demos',
1086   - persistenceType: 'localStorage',
1087   - defaultValue: {
1088   - option: { fixed: 'right', disable: true },
1089   - },
1090   - onChange(value) {
1091   - console.log('value: ', value);
1092   - },
1093   - }}
1094   - rowKey="id"
1095   - search={{
1096   - labelWidth: 'auto',
1097   - }}
1098   - options={{
1099   - setting: {
1100   - listsHeight: 400,
1101   - },
1102   - }}
1103   - form={{}}
1104   - dateFormatter="string"
1105   - headerTitle="银行流水列表"
1106   - scroll={{ x: 1400, y: 360 }}
1107   - toolBarRender={() => [
1108   - <Button
1109   - key="button"
1110   - icon={<PlusOutlined />}
1111   - onClick={() => {
1112   - setBankImportModalVisible(true);
  318 + excelExport(
  319 + '/api/service/invoice/exportInvoiceRecords',
  320 + {
  321 + ...values,
  322 + statusIn: ['INVOICING', 'SUCCESS', 'FAIL', 'REISSUED'],
  323 + },
  324 + () => {
  325 + messageApi.destroy();
  326 + },
  327 + );
1113 328 }}
1114   - type="primary"
1115 329 >
1116   - 导
  330 + 导
1117 331 </Button>,
1118   - ]}
1119   - />
1120   - ),
1121   - },
1122   - ];
1123   - return (
1124   - <div className="invoice-index">
1125   - <Tabs
1126   - defaultActiveKey="1"
1127   - items={tabsItems}
1128   - onChange={(value) => {
1129   - if (value === 1) {
1130   - invoiceActionRef.current?.reload();
1131   - } else {
1132   - bankActionRef.current?.reload();
1133   - }
  332 + ],
  333 + }}
  334 + request={async (params) => {
  335 + let res = await postServiceInvoiceQueryInvoiceRecordList({
  336 + data: {
  337 + ...params,
  338 + statusIn: ['INVOICING', 'SUCCESS', 'FAIL', 'REISSUED'],
  339 + },
  340 + });
  341 + return {
  342 + data: res?.data?.data,
  343 + total: res?.data?.total || 0,
  344 + };
1134 345 }}
  346 + columnsState={{
  347 + persistenceKey: 'pro-table-singe-demos',
  348 + persistenceType: 'localStorage',
  349 + defaultValue: {
  350 + option: { fixed: 'right', disable: true },
  351 + },
  352 + onChange(value) {
  353 + console.log('value: ', value);
  354 + },
  355 + }}
  356 + rowKey="id"
  357 + options={{
  358 + setting: {
  359 + listsHeight: 400,
  360 + },
  361 + }}
  362 + form={{}}
  363 + dateFormatter="string"
  364 + headerTitle="待开票列表"
  365 + scroll={{ x: 1400, y: 360 }}
  366 + toolBarRender={() => []}
1135 367 />
1136 368  
1137   - {bankImportModalVisible ? (
1138   - <BankImportModal
1139   - setVisible={setBankImportModalVisible}
1140   - onClose={() => {
1141   - setBankImportModalVisible(false);
1142   - invoiceActionRef.current?.reload();
1143   - bankActionRef.current?.reload();
1144   - }}
1145   - ></BankImportModal>
1146   - ) : (
1147   - ''
1148   - )}
1149   -
1150   - {invoiceVerificationVisible ? (
1151   - <InvoiceVerificationModal
1152   - setVisible={setInvoiceVerificationVisible}
1153   - invoiceId={invoiceId}
1154   - onClose={() => {
1155   - invoiceActionRef.current?.reload();
1156   - bankActionRef.current?.reload();
1157   - }}
1158   - ></InvoiceVerificationModal>
1159   - ) : (
1160   - ''
1161   - )}
1162 369 {invoiceRecordDetailVisible ? (
1163 370 <InvoiceRecordDetailModal
1164 371 key="detail"
... ...
src/pages/Invoice/waitProcessRecord/components/AddInvoiceDrawerForm.tsx 0 → 100644
  1 +import { RESPONSE_CODE } from '@/constants/enum';
  2 +import { PAYEE_OPTIONS } from '@/pages/Order/constant';
  3 +import {
  4 + postServiceInvoiceAddInvoice,
  5 + postServiceOrderQuerySalesCode,
  6 +} from '@/services';
  7 +import { enumToSelect } from '@/utils';
  8 +import { PlusOutlined } from '@ant-design/icons';
  9 +import {
  10 + DrawerForm,
  11 + ProFormDateTimePicker,
  12 + ProFormGroup,
  13 + ProFormList,
  14 + ProFormMoney,
  15 + ProFormSelect,
  16 + ProFormText,
  17 + ProFormTextArea,
  18 +} from '@ant-design/pro-components';
  19 +import { Button, Form, message } from 'antd';
  20 +import { useEffect, useState } from 'react';
  21 +
  22 +export default ({ onClose }) => {
  23 + const [form] = Form.useForm<{
  24 + invoiceNumber: '';
  25 + invoiceStatus: '';
  26 + purchaser: '';
  27 + payee: '';
  28 + contacts: '';
  29 + sale: '';
  30 + invoicingTime: '';
  31 + notes: '';
  32 + mainOrderIdObjs: [
  33 + {
  34 + mainOrderId: '';
  35 + },
  36 + ];
  37 + money: '';
  38 + }>();
  39 + const [salesCodeOptions, setSalesCodeOptions] = useState([]);
  40 + const getSalesCodeOptions = async () => {
  41 + const res = await postServiceOrderQuerySalesCode();
  42 + let options = res.data?.map((item) => {
  43 + return {
  44 + label: item.userName,
  45 + value: item.userName,
  46 + number: item.number,
  47 + };
  48 + });
  49 + setSalesCodeOptions(options);
  50 + };
  51 + useEffect(() => {
  52 + getSalesCodeOptions();
  53 + }, []);
  54 + return (
  55 + <DrawerForm<{
  56 + invoiceNumber: string;
  57 + invoiceStatus: string;
  58 + purchaser: string;
  59 + payee: string;
  60 + contacts: string;
  61 + sale: string;
  62 + invoicingTime: Date;
  63 + notes: string;
  64 + mainOrderIdObjs: [
  65 + {
  66 + mainOrderId: string;
  67 + },
  68 + ];
  69 + money: string;
  70 + }>
  71 + title="新增开票"
  72 + resize={{
  73 + onResize() {
  74 + console.log('resize!');
  75 + },
  76 + maxWidth: window.innerWidth * 0.8,
  77 + minWidth: 500,
  78 + }}
  79 + form={form}
  80 + trigger={
  81 + <Button type="primary">
  82 + <PlusOutlined />
  83 + 新增
  84 + </Button>
  85 + }
  86 + autoFocusFirstInput
  87 + drawerProps={{
  88 + destroyOnClose: true,
  89 + }}
  90 + submitTimeout={2000}
  91 + onFinish={async (values) => {
  92 + console.log(values);
  93 + const mainOrderIds = values.mainOrderIdObjs.flatMap(
  94 + (item) => item.mainOrderId,
  95 + );
  96 + let attrs = { ...values, mainOrderIds };
  97 + let res = await postServiceInvoiceAddInvoice({
  98 + data: { ...attrs },
  99 + });
  100 + if (res.result === RESPONSE_CODE.SUCCESS) {
  101 + message.success(res.message);
  102 + } else {
  103 + message.error(res.message);
  104 + return false;
  105 + }
  106 + onClose();
  107 + // 不返回不会关闭弹框
  108 + return true;
  109 + }}
  110 + >
  111 + <ProFormText
  112 + name="invoiceNumber"
  113 + width="md"
  114 + label="发票号码"
  115 + placeholder="请输入名称"
  116 + rules={[{ required: true, message: '请输入名称!' }]}
  117 + />
  118 + <ProFormSelect
  119 + name="invoiceStatus"
  120 + label="发票类型"
  121 + valueEnum={{
  122 + SPECIALLY_INVOICED: '专票',
  123 + COMMON_INVOICED: '普票',
  124 + }}
  125 + rules={[{ required: true, message: '请选择发票类型!' }]}
  126 + />
  127 + <ProFormText
  128 + name="purchaser"
  129 + width="md"
  130 + label="购买方"
  131 + placeholder="请输入购买方"
  132 + rules={[{ required: true, message: '请输入购买方!' }]}
  133 + />
  134 + <ProFormSelect
  135 + placeholder="收款单位"
  136 + name="payee"
  137 + width="lg"
  138 + key="payee"
  139 + showSearch
  140 + label="开票收款单位"
  141 + tooltip="财务开票将依据这个字段,选择对应的公司开票"
  142 + options={enumToSelect(PAYEE_OPTIONS)}
  143 + />
  144 + <ProFormText
  145 + name="contacts"
  146 + width="md"
  147 + label="联系人"
  148 + placeholder="请输入联系人"
  149 + rules={[{ required: true, message: '请输入联系人!' }]}
  150 + />
  151 + <ProFormSelect
  152 + name="sale"
  153 + key="sale"
  154 + width="lg"
  155 + showSearch
  156 + label="销售代表"
  157 + placeholder="请选择销售代表"
  158 + options={salesCodeOptions}
  159 + />
  160 + <ProFormDateTimePicker
  161 + name="invoicingTime"
  162 + label="开票时间"
  163 + fieldProps={{
  164 + format: (value) => value.format('YYYY-MM-DD'),
  165 + }}
  166 + rules={[{ required: true, message: '请输入开票时间!' }]}
  167 + />
  168 + <ProFormTextArea name="notes" label="备注" placeholder="请输入名称" />
  169 + <ProFormList
  170 + name="mainOrderIdObjs"
  171 + label="订单号"
  172 + min={1}
  173 + copyIconProps={false}
  174 + deleteIconProps={{
  175 + tooltipText: '删除',
  176 + }}
  177 + initialValue={[
  178 + {
  179 + mainOrderId: '',
  180 + },
  181 + ]}
  182 + >
  183 + <ProFormGroup key="group">
  184 + <ProFormText
  185 + rules={[{ required: true, message: '请输入关联订单!' }]}
  186 + name="mainOrderId"
  187 + />
  188 + </ProFormGroup>
  189 + </ProFormList>
  190 + <ProFormMoney
  191 + label="金额"
  192 + name="money"
  193 + customSymbol="¥"
  194 + min={0}
  195 + rules={[{ required: true, message: '请输入金额!' }]}
  196 + />
  197 + </DrawerForm>
  198 + );
  199 +};
... ...
src/pages/Invoice/waitProcessRecord/components/BankChooseModal.tsx 0 → 100644
  1 +import EllipsisDiv from '@/components/Div/EllipsisDiv';
  2 +import { RESPONSE_CODE } from '@/constants/enum';
  3 +import { INVOCING_STATUS, PAYEE_OPTIONS } from '@/pages/Order/constant';
  4 +import {
  5 + postServiceBankStatementQueryBankStatement,
  6 + postServiceInvoiceInvoiceWriteOff,
  7 +} from '@/services';
  8 +import { FloatAdd, FloatSub, enumValueToLabel, formatDateTime } from '@/utils';
  9 +import { formatDate } from '@/utils/time';
  10 +
  11 +import { ActionType, ProCard, ProTable } from '@ant-design/pro-components';
  12 +import { Button, Divider, Flex, Modal, Tag, message } from 'antd';
  13 +import { useRef, useState } from 'react';
  14 +import { BANK_STATEMENT_COLUMNS, INVOICE_STATUS } from '../../constant';
  15 +import '../index.less';
  16 +
  17 +export default ({ loadInvoiceData, invoiceId, setVisible, onClose }) => {
  18 + const [selectedStatement, setSelectedStatement] = useState([]);
  19 + const [selectedStatementIdSet, setSelectedStatementIdSet] = useState(
  20 + new Set(),
  21 + );
  22 + const [totalAmount, setTotalAmount] = useState(0);
  23 +
  24 + // 添加元素到Set
  25 + const addElement = (element) => {
  26 + setSelectedStatementIdSet((prevSet) => new Set([...prevSet, element]));
  27 + };
  28 +
  29 + // 从Set中删除元素
  30 + const removeElement = (element) => {
  31 + setSelectedStatementIdSet((prevSet) => {
  32 + const newSet = new Set(prevSet);
  33 + newSet.delete(element);
  34 + return newSet;
  35 + });
  36 + };
  37 +
  38 + const [btnLoading, setBtnLoading] = useState(false);
  39 +
  40 + const actionRef = useRef<ActionType>();
  41 + const getTableCellText = (target: any) => {
  42 + if (!target) {
  43 + return '';
  44 + }
  45 +
  46 + if (target.props) {
  47 + return target.props.text;
  48 + }
  49 +
  50 + return target;
  51 + };
  52 +
  53 + /**
  54 + * 加载列表表格的各个列格式
  55 + */
  56 + const bankStatementColumnsInit = () => {
  57 + let columns = BANK_STATEMENT_COLUMNS.map((item) => {
  58 + let newItem = { ...item };
  59 + let dataIndex = item.dataIndex;
  60 + let dataType = item.valueType;
  61 +
  62 + if (item.dataIndex === 'status') {
  63 + newItem.hideInSearch = true;
  64 + }
  65 +
  66 + newItem.render = (text, record) => {
  67 + let textValue = record[dataIndex];
  68 +
  69 + if (dataType === 'date') {
  70 + textValue = formatDate(textValue);
  71 + }
  72 +
  73 + if (dataType === 'dateTime') {
  74 + textValue = formatDateTime(textValue);
  75 + }
  76 +
  77 + if (dataType === 'money') {
  78 + textValue = '¥' + textValue;
  79 + }
  80 +
  81 + switch (dataIndex) {
  82 + case 'invoiceStatus':
  83 + return (
  84 + <EllipsisDiv
  85 + text={enumValueToLabel(
  86 + getTableCellText(textValue),
  87 + INVOCING_STATUS,
  88 + )}
  89 + />
  90 + );
  91 +
  92 + case 'status': {
  93 + //这里状态不显示在筛选条件中,只能筛异常的流水
  94 + return (
  95 + <EllipsisDiv
  96 + text={enumValueToLabel(
  97 + getTableCellText(textValue),
  98 + INVOICE_STATUS,
  99 + )}
  100 + />
  101 + );
  102 + }
  103 + case 'payee':
  104 + return (
  105 + <EllipsisDiv
  106 + text={enumValueToLabel(
  107 + getTableCellText(textValue),
  108 + PAYEE_OPTIONS,
  109 + )}
  110 + />
  111 + );
  112 +
  113 + default:
  114 + return <EllipsisDiv text={getTableCellText(textValue)} />;
  115 + }
  116 + };
  117 +
  118 + return newItem;
  119 + });
  120 +
  121 + columns.push({
  122 + title: '操作',
  123 + valueType: 'option',
  124 + key: 'option',
  125 + fixed: 'right',
  126 + width: 70,
  127 + render: (text, record) => [
  128 + <Button
  129 + className="p-0"
  130 + key="choose"
  131 + type="link"
  132 + onClick={() => {
  133 + let amount = record.loanAmount || record.transactionAmount || 0;
  134 +
  135 + //已经选中,取消选中
  136 + if (selectedStatementIdSet.has(record.id)) {
  137 + setSelectedStatement(
  138 + selectedStatement.filter((item) => {
  139 + return item.id !== record.id;
  140 + }),
  141 + );
  142 + removeElement(record.id);
  143 + setTotalAmount(parseFloat(FloatSub(totalAmount, amount)));
  144 + } else {
  145 + //添加到已选中区域中
  146 + let newSelectedStatement = [...selectedStatement];
  147 + newSelectedStatement.push(record);
  148 + setSelectedStatement(newSelectedStatement);
  149 + addElement(record.id);
  150 + setTotalAmount(FloatAdd(totalAmount, amount));
  151 + }
  152 + }}
  153 + >
  154 + {selectedStatementIdSet.has(record.id) ? '取消选中' : '选中'}
  155 + </Button>,
  156 + ],
  157 + });
  158 +
  159 + return columns;
  160 + };
  161 +
  162 + /**
  163 + * 删除已选中
  164 + * @param record
  165 + */
  166 + const removeSelectedStatement = (record: any) => {
  167 + setSelectedStatement(
  168 + selectedStatement.filter((item) => {
  169 + return item.id !== record.id;
  170 + }),
  171 + );
  172 + removeElement(record.id);
  173 + };
  174 +
  175 + const showSelectedStatement = () => {
  176 + let i = 0;
  177 +
  178 + let tags = selectedStatement.map((item) => {
  179 + let tagText = item.id;
  180 +
  181 + if (item.payeePayerName) {
  182 + tagText += ' ' + item.payeePayerName + ' ';
  183 + }
  184 +
  185 + if (item.loanAmount) {
  186 + tagText += item.loanAmount + ' ';
  187 + }
  188 +
  189 + if (item.transactionAmount) {
  190 + tagText += item.transactionAmount;
  191 + }
  192 +
  193 + return (
  194 + <Tag
  195 + key={i++}
  196 + closable={true}
  197 + style={{ userSelect: 'none' }}
  198 + color="blue"
  199 + onClose={(e) => {
  200 + e.preventDefault(); //需要加上这句代码,不然删除tag时,当前tag的下一个tag会被设置ant-tag-hidden
  201 + removeSelectedStatement(item);
  202 + }}
  203 + >
  204 + <span>{tagText}</span>
  205 + </Tag>
  206 + );
  207 + });
  208 +
  209 + return tags;
  210 + };
  211 +
  212 + return (
  213 + <>
  214 + <Modal
  215 + open
  216 + width="80%"
  217 + title="添加银行流水"
  218 + className="bank-statement-choose"
  219 + onOk={async () => {
  220 + setBtnLoading(true);
  221 + let bankStatementIds = selectedStatement?.map((item) => {
  222 + return item.id;
  223 + });
  224 + let res = await postServiceInvoiceInvoiceWriteOff({
  225 + data: {
  226 + invoiceId: invoiceId,
  227 + bankStatementIds: bankStatementIds,
  228 + },
  229 + });
  230 + setTimeout(() => {
  231 + loadInvoiceData();
  232 + }, 500);
  233 + if (res.result === RESPONSE_CODE.SUCCESS) {
  234 + if (res.data?.length > 0) {
  235 + message.info(res.data);
  236 + } else {
  237 + message.success(res.message);
  238 + }
  239 +
  240 + onClose();
  241 + }
  242 + setBtnLoading(false);
  243 + }}
  244 + okButtonProps={{
  245 + loading: btnLoading,
  246 + }}
  247 + onCancel={() => {
  248 + setVisible(false);
  249 + }}
  250 + >
  251 + <Divider orientation="left" plain>
  252 + 已选中(合计:¥{totalAmount})
  253 + </Divider>
  254 + <ProCard className="mb-[16px]" bordered style={{}}>
  255 + <Flex wrap="wrap" gap="small">
  256 + {showSelectedStatement()}
  257 + </Flex>
  258 + </ProCard>
  259 +
  260 + <ProTable
  261 + columns={bankStatementColumnsInit()}
  262 + actionRef={actionRef}
  263 + cardBordered
  264 + pagination={{
  265 + pageSize: 10,
  266 + }}
  267 + editable={{
  268 + type: 'multiple',
  269 + onSave: async (rowKey, data) => {
  270 + console.log(rowKey, data);
  271 + },
  272 + actionRender: (row, config, defaultDom) => [
  273 + defaultDom.save,
  274 + defaultDom.cancel,
  275 + ],
  276 + }}
  277 + request={async (params) => {
  278 + const res = await postServiceBankStatementQueryBankStatement({
  279 + data: { ...params, status: 'ABNORMAL' },
  280 + });
  281 + if (res) {
  282 + return {
  283 + data: res?.data?.data || [],
  284 + total: res?.data?.total || 0,
  285 + };
  286 + }
  287 + }}
  288 + columnsState={{
  289 + persistenceKey: 'pro-table-singe-demos',
  290 + persistenceType: 'localStorage',
  291 + defaultValue: {
  292 + option: { fixed: 'right', disable: true },
  293 + },
  294 + onChange(value) {
  295 + console.log('value: ', value);
  296 + },
  297 + }}
  298 + rowKey="id"
  299 + search={{
  300 + labelWidth: 'auto',
  301 + }}
  302 + options={{
  303 + setting: {
  304 + listsHeight: 400,
  305 + },
  306 + }}
  307 + form={{}}
  308 + dateFormatter="string"
  309 + headerTitle="银行流水列表"
  310 + scroll={{ x: 1400, y: 360 }}
  311 + toolBarRender={() => []}
  312 + />
  313 + </Modal>
  314 + </>
  315 + );
  316 +};
... ...
src/pages/Invoice/waitProcessRecord/components/BankImportModal.tsx 0 → 100644
  1 +import { RESPONSE_CODE } from '@/constants/enum';
  2 +import { blobToJson } from '@/utils';
  3 +
  4 +import { UploadOutlined } from '@ant-design/icons';
  5 +import { ModalForm } from '@ant-design/pro-components';
  6 +import { Button, Form, Upload, UploadFile, UploadProps, message } from 'antd';
  7 +import { RcFile } from 'antd/es/upload';
  8 +import axios from 'axios';
  9 +import { useState } from 'react';
  10 +
  11 +// import { cloneDeep } from 'lodash';
  12 +export default ({ setVisible, onClose }) => {
  13 + const [form] = Form.useForm<{ name: string; company: string }>();
  14 + const [fileList, setFileList] = useState<UploadFile[]>([]);
  15 + const handleChange: UploadProps['onChange'] = ({ fileList: newFileList }) =>
  16 + setFileList(newFileList);
  17 +
  18 + const [messageApi, contextHolder] = message.useMessage();
  19 + const [uploadLoading, setUploading] = useState(false);
  20 + console.log(uploadLoading);
  21 +
  22 + const exportLoading = (content: string) => {
  23 + messageApi.open({
  24 + type: 'loading',
  25 + content: content,
  26 + duration: 0,
  27 + });
  28 + };
  29 +
  30 + const downloadImportTemplate = async () => {
  31 + exportLoading('正在下载......');
  32 + axios({
  33 + url: '/api/service/bankStatement/exportTemplate',
  34 + method: 'post',
  35 + responseType: 'blob',
  36 + headers: { Authorization: localStorage.getItem('token') },
  37 + })
  38 + .then((response) => {
  39 + // 创建一个新的 Blob 对象,它包含了服务器响应的数据(即你的 Excel 文件)
  40 + const blob = new Blob([response.data]); // Excel 的 MIME 类型
  41 + const downloadUrl = window.URL.createObjectURL(blob);
  42 + const a = document.createElement('a');
  43 + a.href = downloadUrl;
  44 + a.download = '导入模板.xlsx'; // 你可以为文件命名
  45 + document.body.appendChild(a);
  46 + a.click(); // 模拟点击操作来下载文件
  47 + URL.revokeObjectURL(downloadUrl); // 释放掉 blob 对象所占用的内存
  48 + document.body.removeChild(a);
  49 + })
  50 + .catch((error) => {
  51 + // 处理错误
  52 + console.error('导出错误', error);
  53 + })
  54 + .finally(() => {
  55 + messageApi.destroy();
  56 + });
  57 + };
  58 + const handleUpload = async () => {
  59 + exportLoading('正在导入......');
  60 +
  61 + const formData = new FormData();
  62 + fileList.forEach((file) => {
  63 + formData.append('file', file.originFileObj as RcFile);
  64 + });
  65 +
  66 + setUploading(true);
  67 +
  68 + axios({
  69 + url: '/api/service/bankStatement/importBankStatementForm',
  70 + method: 'post',
  71 + responseType: 'blob',
  72 + headers: {
  73 + Authorization: localStorage.getItem('token'),
  74 + 'Content-Type':
  75 + 'multipart/form-data; boundary=----WebKitFormBoundarynl6gT1BKdPWIejNq',
  76 + },
  77 + data: formData,
  78 + })
  79 + .then((response) => {
  80 + let data = response.data;
  81 + if (data.type === 'application/json') {
  82 + blobToJson(data).then((dataJson) => {
  83 + if (dataJson?.result === RESPONSE_CODE.SUCCESS) {
  84 + message.success(dataJson?.message);
  85 + onClose();
  86 + } else {
  87 + message.error(dataJson?.message);
  88 + }
  89 + });
  90 + } else {
  91 + message.error('上传失败,已下载错误信息表格');
  92 + // 创建一个新的 Blob 对象,它包含了服务器响应的数据(即你的 Excel 文件)
  93 + const blob = new Blob([response.data]); // Excel 的 MIME 类型
  94 + const downloadUrl = window.URL.createObjectURL(blob);
  95 + const a = document.createElement('a');
  96 + a.href = downloadUrl;
  97 + a.download = '银行流水导入模板.xlsx'; // 你可以为文件命名
  98 + document.body.appendChild(a);
  99 + a.click(); // 模拟点击操作来下载文件
  100 + URL.revokeObjectURL(downloadUrl); // 释放掉 blob 对象所占用的内存
  101 + document.body.removeChild(a);
  102 + }
  103 + })
  104 + .catch((error) => {
  105 + // 处理错误
  106 + message.error('系统出现异常了,请联系管理员', error);
  107 + })
  108 + .finally(() => {
  109 + setUploading(false);
  110 + messageApi.destroy();
  111 + });
  112 + };
  113 + const props: UploadProps = {
  114 + onRemove: (file) => {
  115 + const index = fileList.indexOf(file);
  116 + const newFileList = fileList.slice();
  117 + newFileList.splice(index, 1);
  118 + setFileList(newFileList);
  119 + },
  120 + beforeUpload: (file) => {
  121 + setFileList([...fileList, file]);
  122 +
  123 + return false;
  124 + },
  125 + fileList,
  126 + onChange: handleChange,
  127 + accept: '.xlsx',
  128 + };
  129 +
  130 + return (
  131 + <>
  132 + <ModalForm<{
  133 + name: string;
  134 + company: string;
  135 + }>
  136 + width={500}
  137 + open
  138 + title="银行流水导入"
  139 + form={form}
  140 + autoFocusFirstInput
  141 + modalProps={{
  142 + okText: '确定',
  143 + cancelText: '取消',
  144 + destroyOnClose: true,
  145 + onCancel: () => {
  146 + setVisible(false);
  147 + },
  148 + }}
  149 + onFinish={async () => {
  150 + handleUpload();
  151 + }}
  152 + onOpenChange={setVisible}
  153 + >
  154 + <div className="py-4 font-semibold">
  155 + 导入银行流水
  156 + <Button type="link" onClick={downloadImportTemplate}>
  157 + 下载导入模板
  158 + </Button>
  159 + </div>
  160 + <Upload {...props}>
  161 + <Button icon={<UploadOutlined />} disabled={fileList.length > 0}>
  162 + 点击选择文件
  163 + </Button>
  164 + </Upload>
  165 + </ModalForm>
  166 +
  167 + {contextHolder}
  168 + </>
  169 + );
  170 +};
... ...
src/pages/Invoice/waitProcessRecord/components/Invoice.tsx 0 → 100644
  1 +import styled from 'styled-components';
  2 +const InvoiceTmpDiv = styled.div`
  3 + font-size: 12px;
  4 + width: 1120px;
  5 + .title {
  6 + font-size: 26px;
  7 + color: #b16363;
  8 + text-align: center;
  9 + line-height: 56px;
  10 + padding-top: 0;
  11 + }
  12 + .extra {
  13 + color: #b15b16;
  14 + .content {
  15 + color: #181818;
  16 + }
  17 + }
  18 + .height84 {
  19 + height: 110px;
  20 + }
  21 + .row {
  22 + border: 2px solid #b16363;
  23 + border-bottom: none;
  24 + color: #b15b16;
  25 + .content {
  26 + color: #181818;
  27 + }
  28 + }
  29 + .last-row {
  30 + .content {
  31 + color: #181818;
  32 + }
  33 + color: #b15b16;
  34 + border-top: 2px solid #b16363;
  35 + }
  36 + .label {
  37 + width: 78px;
  38 + display: inline-block;
  39 + text-align-last: justify;
  40 + text-align: justify;
  41 + }
  42 + .longLabel {
  43 + width: 178px;
  44 + display: inline-block;
  45 + text-align-last: justify;
  46 + text-align: justify;
  47 + }
  48 + .title-label {
  49 + width: 52px;
  50 + }
  51 +`;
  52 +const Row = styled.div`
  53 + .col_1 {
  54 + width: 2.65%;
  55 + borderleft: none;
  56 + }
  57 + .col_4 {
  58 + width: 3.75%;
  59 + }
  60 + .col_9 {
  61 + width: 7.4%;
  62 + }
  63 + .col_2 {
  64 + width: 8.33%;
  65 + }
  66 + .col_3 {
  67 + width: 12.5%;
  68 + }
  69 + .col_5 {
  70 + width: 20.83%;
  71 + }
  72 + .col_6 {
  73 + width: 42.5%;
  74 + }
  75 + .col_7 {
  76 + width: 29.16%;
  77 + }
  78 + .col_8 {
  79 + width: 33.33%;
  80 + }
  81 + .col_14 {
  82 + width: 58.33%;
  83 + }
  84 + .col_15 {
  85 + width: 42.5%;
  86 + }
  87 + .col_17 {
  88 + width: 70.83%;
  89 + }
  90 + .col_18 {
  91 + width: 100%;
  92 + }
  93 + .col_24 {
  94 + width: 100%;
  95 + }
  96 +`;
  97 +const Col = styled.span`
  98 + display: inline-block;
  99 + padding: 8px;
  100 + box-sizing: border-box;
  101 + vertical-align: middle;
  102 + border-left: 2px solid #b16363;
  103 + height: 100%;
  104 + &.no-border {
  105 + border-left: none;
  106 + }
  107 + .text-center {
  108 + text-align: center;
  109 + border-left: none;
  110 + border-right: none;
  111 + }
  112 + &.transparent-border {
  113 + border-left: 2px solid rgba(0, 0, 0, 0);
  114 + }
  115 + &.invoice-number {
  116 + border-left: none;
  117 + color: #b16363;
  118 + padding: 0 0 0 800px;
  119 + font-size: 14px;
  120 + }
  121 +`;
  122 +const UnderLine = styled.div`
  123 + border: 2px solid #b16363;
  124 + width: 325px;
  125 + height: 8px;
  126 + margin: -1% 0 2% 35%;
  127 + border-left: none;
  128 + border-right: none;
  129 +`;
  130 +const InvoiceInfo = styled.span`
  131 + color: black;
  132 +`;
  133 +const TitleDescription = styled.div`
  134 + margin-top: 4.2%;
  135 +`;
  136 +const ProjectContainer = styled.div`
  137 + width: 100%;
  138 + height: 160px;
  139 + border-top: 2px solid #b16363;
  140 + border-right: 2px solid #b16363;
  141 + border-left: 2px solid #b16363;
  142 + overflow: auto;
  143 + .single-project {
  144 + width: 100%;
  145 + height: 30px;
  146 + }
  147 +`;
  148 +export default ({ data }) => {
  149 + return (
  150 + <div>
  151 + <InvoiceTmpDiv>
  152 + <Row>
  153 + <Col className="col_18 invoice-number">
  154 + 发票号码:<InvoiceInfo>{data.invoiceNumber}</InvoiceInfo>
  155 + </Col>
  156 + <Col className="title col_18 no-border">
  157 + 电子发票(
  158 + {data.type === 'SPECIAL_TICKET' ? '增值税专用发票' : '普通发票'})
  159 + </Col>
  160 + <UnderLine className="UnderLine">
  161 + <div></div>
  162 + </UnderLine>
  163 + </Row>
  164 + <Row className="row height84">
  165 + <Col className="col_1 no-border">购买方信息</Col>
  166 + <Col className="col_15">
  167 + <TitleDescription>
  168 + <span className="label">名称</span>:
  169 + <span className="content">{data.partyAName}</span>
  170 + </TitleDescription>
  171 + <TitleDescription>
  172 + <span className="longLabel">统一社会信用代码/纳税人识别号</span>:
  173 + <span className="content">{data.partyATaxid}</span>
  174 + </TitleDescription>
  175 + </Col>
  176 + <Col className="col_1">销售方信息</Col>
  177 + <Col className="col_6">
  178 + <TitleDescription>
  179 + <span className="label">名称</span>:
  180 + <span className="content">{data.partyBName}</span>
  181 + </TitleDescription>
  182 + <TitleDescription>
  183 + <span className="longLabel">统一社会信用代码/纳税人识别号</span>:
  184 + <span className="content">{data.partyBTaxid}</span>
  185 + </TitleDescription>
  186 + </Col>
  187 + </Row>
  188 + <Row className="row">
  189 + <Col className="col_7 no-border">
  190 + <div className="text-center">项目名称</div>
  191 + </Col>
  192 + <Col className="col_5">
  193 + <div className="text-center">规格型号</div>
  194 + </Col>
  195 + <Col className="">
  196 + <div className="text-center">单位</div>
  197 + </Col>
  198 + <Col className="col_2">
  199 + <div className="text-center">数量</div>
  200 + </Col>
  201 + <Col className="col_2">
  202 + <div className="text-center">单价</div>
  203 + </Col>
  204 + <Col className="col_2">
  205 + <div className="text-center">金额</div>
  206 + </Col>
  207 + <Col className="">
  208 + <div className="text-center">税率/征收率</div>
  209 + </Col>
  210 + <Col className="col_2">
  211 + <div className="text-center">税额</div>
  212 + </Col>
  213 + </Row>
  214 + <Row>
  215 + <ProjectContainer>
  216 + {data &&
  217 + data.invoiceDetails?.map((item) => {
  218 + const {
  219 + taxPrice,
  220 + totalPrice,
  221 + specification,
  222 + projectName,
  223 + quantity,
  224 + price,
  225 + taxRate,
  226 + unit,
  227 + } = item;
  228 + return (
  229 + <div className="single-project" key={item.id}>
  230 + <Col
  231 + className="col_7 transparent-border"
  232 + key={'projectName'}
  233 + >
  234 + <div className="text-center">{projectName}</div>
  235 + </Col>
  236 + <Col
  237 + className="col_5 transparent-border"
  238 + key={'specification'}
  239 + >
  240 + <div className="text-center">{specification}</div>
  241 + </Col>
  242 + <Col className=" transparent-border" key={'unit'}>
  243 + <div className="text-center">{unit}</div>
  244 + </Col>
  245 + <Col className="col_2 transparent-border" key={'quantity'}>
  246 + <div className="text-center">{quantity}</div>
  247 + </Col>
  248 + <Col className="col_2 transparent-border" key={'price'}>
  249 + <div className="text-center">{price}</div>
  250 + </Col>
  251 + <Col
  252 + className="col_2 transparent-border"
  253 + key={'totalPrice'}
  254 + >
  255 + <div className="text-center">{totalPrice}</div>
  256 + </Col>
  257 + <Col className=" transparent-border" key={'taxRate'}>
  258 + <div className="text-center">{taxRate}</div>
  259 + </Col>
  260 + <Col className="col_2 transparent-border" key={'taxPrice'}>
  261 + <div className="text-center">{taxPrice}</div>
  262 + </Col>
  263 + </div>
  264 + );
  265 + })}
  266 + </ProjectContainer>
  267 + </Row>
  268 + <Row className="row">
  269 + <Col className="col_15 no-border">
  270 + 价税合计(大写)
  271 + <InvoiceInfo>{data.totalPriceText}</InvoiceInfo>
  272 + </Col>
  273 + <Col className="no-border">
  274 + (小写)<InvoiceInfo>¥{data.totalPrice}</InvoiceInfo>
  275 + </Col>
  276 + </Row>
  277 + <Row className="row height84">
  278 + <Col className="col_1 no-border">备注</Col>
  279 + <Col className="col_7">
  280 + <InvoiceInfo>{data.comment}</InvoiceInfo>
  281 + </Col>
  282 + </Row>
  283 + <Row className="last-row">
  284 + <Col className="col_6 no-border">
  285 + 开票人:<InvoiceInfo>{data.invoicingPerson}</InvoiceInfo>
  286 + </Col>
  287 + </Row>
  288 + </InvoiceTmpDiv>
  289 + </div>
  290 + );
  291 +};
... ...
src/pages/Invoice/waitProcessRecord/components/InvoiceDetailImportModal.tsx 0 → 100644
  1 +import { RESPONSE_CODE } from '@/constants/enum';
  2 +import { postServiceInvoiceImportInvoiceDetails } from '@/services';
  3 +import { ModalForm, ProFormUploadDragger } from '@ant-design/pro-components';
  4 +import { Button, Form, message } from 'antd';
  5 +
  6 +export default ({ recordId }) => {
  7 + const [form] = Form.useForm();
  8 + return (
  9 + <ModalForm
  10 + title="新建表单"
  11 + trigger={<Button type="primary">导入明细</Button>}
  12 + form={form}
  13 + autoFocusFirstInput
  14 + modalProps={{
  15 + destroyOnClose: true,
  16 + onCancel: () => console.log('run'),
  17 + }}
  18 + submitTimeout={2000}
  19 + onFinish={async (values) => {
  20 + const formData = new FormData();
  21 + // console.log(fileList[0] as RcFile)
  22 + // formData.append('file', fileList[0] as RcFile);
  23 + formData.append('invoiceRecordId', recordId);
  24 + formData.append('detailsExcel', values.detailsExcel[0].originFileObj);
  25 + // You can use any AJAX library you like
  26 + const res = await postServiceInvoiceImportInvoiceDetails({
  27 + data: formData,
  28 + headers: {
  29 + 'Content-Type':
  30 + 'multipart/form-data; boundary=----WebKitFormBoundarynl6gT1BKdPWIejNq',
  31 + },
  32 + });
  33 + if (res.result === RESPONSE_CODE.SUCCESS) {
  34 + message.success('导入成功');
  35 + return true;
  36 + }
  37 + }}
  38 + >
  39 + <ProFormUploadDragger name="detailsExcel" label="导入明细表" />
  40 + </ModalForm>
  41 + );
  42 +};
... ...
src/pages/Invoice/waitProcessRecord/components/InvoiceDetailTable.tsx 0 → 100644
  1 +import InvoiceDetailImportModal from '@/pages/Invoice/waitProcessRecord/components/InvoiceDetailImportModal';
  2 +import { InvoiceProjectSelect } from '@/pages/Invoice/waitProcessRecord/components/InvoiceProjectSelect';
  3 +import {
  4 + ActionType,
  5 + EditableProTable,
  6 + ProCard,
  7 + ProColumns,
  8 + ProFormField,
  9 +} from '@ant-design/pro-components';
  10 +import { useEffect, useRef, useState } from 'react';
  11 +
  12 +export default ({ recordId, details, updateDetails, readOnly }) => {
  13 + const [editableKeys, setEditableRowKeys] = useState([]);
  14 + const ref = useRef<ActionType>();
  15 + useEffect(() => {
  16 + updateDetails(details);
  17 + }, []);
  18 +
  19 + useEffect(() => {
  20 + setEditableRowKeys(details?.map((item) => item.tid));
  21 + }, [details]);
  22 + const columns: ProColumns[] = [
  23 + {
  24 + title: '项目名称',
  25 + dataIndex: 'projectName',
  26 + width: 200,
  27 + ellipsis: true,
  28 + readonly: readOnly,
  29 + renderFormItem: () => {
  30 + return <InvoiceProjectSelect readOnly={readOnly} />;
  31 + },
  32 + },
  33 + {
  34 + title: '规格型号',
  35 + readonly: readOnly,
  36 + dataIndex: 'specification',
  37 + valueType: 'text',
  38 + ellipsis: true,
  39 + },
  40 + {
  41 + title: '单位',
  42 + readonly: readOnly,
  43 + dataIndex: 'unit',
  44 + valueType: 'text',
  45 + ellipsis: true,
  46 + },
  47 + {
  48 + title: '数量',
  49 + readonly: readOnly,
  50 + dataIndex: 'quantity',
  51 + valueType: 'digit',
  52 + ellipsis: true,
  53 + },
  54 + {
  55 + title: '单价',
  56 + readonly: readOnly,
  57 + dataIndex: 'price',
  58 + valueType: 'digit',
  59 + ellipsis: true,
  60 + },
  61 + {
  62 + title: '金额',
  63 + readonly: readOnly,
  64 + dataIndex: 'totalPrice',
  65 + valueType: 'digit',
  66 + ellipsis: true,
  67 + },
  68 + {
  69 + title: '税率/征收率',
  70 + readonly: true,
  71 + dataIndex: 'taxRate',
  72 + valueType: () => ({
  73 + type: 'percent',
  74 + }),
  75 + ellipsis: true,
  76 + },
  77 + {
  78 + title: '税额',
  79 + readonly: true,
  80 + dataIndex: 'taxPrice',
  81 + valueType: 'digit',
  82 + ellipsis: true,
  83 + },
  84 + {
  85 + title: '操作',
  86 + valueType: 'option',
  87 + width: 100,
  88 + render: () => {
  89 + return null;
  90 + },
  91 + },
  92 + ];
  93 +
  94 + return (
  95 + <>
  96 + <EditableProTable
  97 + columns={columns}
  98 + actionRef={ref}
  99 + rowKey="tid"
  100 + scroll={{
  101 + x: 960,
  102 + }}
  103 + value={details}
  104 + controlled={true}
  105 + recordCreatorProps={
  106 + readOnly
  107 + ? false
  108 + : {
  109 + newRecordType: 'dataSource',
  110 + record: () => ({
  111 + tid: Date.now(),
  112 + }),
  113 + }
  114 + }
  115 + toolBarRender={() => {
  116 + return [
  117 + <InvoiceDetailImportModal key={'import'} recordId={recordId} />,
  118 + ];
  119 + }}
  120 + editable={{
  121 + type: 'multiple',
  122 + editableKeys,
  123 + actionRender: (row, config, defaultDoms) => {
  124 + return [defaultDoms.delete];
  125 + },
  126 +
  127 + onValuesChange: (record, recordList) => {
  128 + //修改recordList中tid为record.tid的元素,将它的specification属性设置为invoiceProject的specification属性
  129 + const records = recordList.map((item) => {
  130 + return item;
  131 + });
  132 + updateDetails(records);
  133 + },
  134 + }}
  135 + />
  136 + {
  137 + <ProCard title="表格数据" headerBordered collapsible defaultCollapsed>
  138 + <ProFormField
  139 + ignoreFormItem
  140 + fieldProps={{
  141 + style: {
  142 + width: '100%',
  143 + },
  144 + }}
  145 + mode="read"
  146 + valueType="jsonCode"
  147 + text={JSON.stringify(details)}
  148 + />
  149 + </ProCard>
  150 + }
  151 + </>
  152 + );
  153 +};
... ...
src/pages/Invoice/waitProcessRecord/components/InvoiceModal.tsx 0 → 100644
  1 +import Invoice from '@/pages/Invoice/waitProcessRecord/components/Invoice';
  2 +import { postServiceInvoiceGetInvoiceRecord } from '@/services';
  3 +import { ModalForm } from '@ant-design/pro-components';
  4 +import { Form } from 'antd';
  5 +import { useEffect, useState } from 'react';
  6 +
  7 +export default ({ recordId, getRecord, button }) => {
  8 + const [data, setData] = useState<any>({});
  9 + const getData = async () => {
  10 + let ret = await postServiceInvoiceGetInvoiceRecord({
  11 + query: {
  12 + id: recordId,
  13 + },
  14 + });
  15 + setData(ret.data);
  16 + };
  17 + useEffect(() => {
  18 + if (recordId) {
  19 + getData();
  20 + }
  21 + }, []);
  22 + const [form] = Form.useForm();
  23 + return (
  24 + <ModalForm
  25 + title="预览发票"
  26 + trigger={button ? button : <a type="primary">预览</a>}
  27 + onOpenChange={(open) => {
  28 + if (open) {
  29 + if (getRecord) {
  30 + setData(getRecord());
  31 + } else {
  32 + getData();
  33 + }
  34 + }
  35 + }}
  36 + width={1200}
  37 + form={form}
  38 + autoFocusFirstInput
  39 + submitter={false}
  40 + modalProps={{
  41 + destroyOnClose: true,
  42 + }}
  43 + >
  44 + <hr />
  45 + <Invoice data={data} />
  46 + </ModalForm>
  47 + );
  48 +};
... ...
src/pages/Invoice/waitProcessRecord/components/InvoiceProjectSelect.tsx 0 → 100644
  1 +import { postServiceConstListInvoiceDetailNames } from '@/services';
  2 +import { Select, Tooltip } from 'antd';
  3 +import { useState } from 'react';
  4 +
  5 +export const InvoiceProjectSelect = ({ readOnly, value, onChange }) => {
  6 + const [options, setOptions] = useState<any[]>([]);
  7 + // 定义防抖函数
  8 + let timeoutId = null;
  9 + const fetchOptions = async (keywords) => {
  10 + clearTimeout(timeoutId);
  11 + timeoutId = setTimeout(async () => {
  12 + const res = await postServiceConstListInvoiceDetailNames({
  13 + data: {
  14 + nameLike: keywords,
  15 + },
  16 + });
  17 + const data = res.data;
  18 +
  19 + setOptions(
  20 + data.map((item) => {
  21 + console.log(item);
  22 + return {
  23 + key: item.id,
  24 + label:
  25 + '*' +
  26 + item.productAndServiceCatagoryAbbreviation +
  27 + '*' +
  28 + item?.name,
  29 + value:
  30 + '*' +
  31 + item.productAndServiceCatagoryAbbreviation +
  32 + '*' +
  33 + item?.name,
  34 + ...item,
  35 + };
  36 + }),
  37 + );
  38 + // 这里可以放置实际的搜索逻辑,比如发起网络请求等
  39 + }, 500); // 设置延迟时间,单位毫秒
  40 + };
  41 +
  42 + return readOnly ? (
  43 + <Tooltip title={value}>{value}</Tooltip>
  44 + ) : (
  45 + <Select
  46 + key="project"
  47 + /*readonly={readonly}*/
  48 + showSearch
  49 + placeholder="请选择开票项目"
  50 + filterOption={(input, option) => (option?.label ?? '').includes(input)}
  51 + onChange={(e) => {
  52 + onChange(e);
  53 + }}
  54 + defaultValue={value}
  55 + options={options}
  56 + onSearch={(e) => {
  57 + fetchOptions(e);
  58 + }}
  59 + />
  60 + );
  61 +};
... ...
src/pages/Invoice/waitProcessRecord/components/InvoiceRecordDetailModal.tsx 0 → 100644
  1 +import { RESPONSE_CODE } from '@/constants/enum';
  2 +import InvoiceDetailTable from '@/pages/Invoice/waitProcessRecord/components/InvoiceDetailTable';
  3 +import {
  4 + postServiceConstGetPayeeEnum,
  5 + postServiceConstInvoiceType,
  6 + postServiceConstInvoicingType,
  7 + postServiceInvoiceGetInvoiceRecord,
  8 + postServiceInvoiceModifyRecord,
  9 +} from '@/services';
  10 +import { enumToSelect } from '@/utils';
  11 +import {
  12 + ModalForm,
  13 + ProCard,
  14 + ProForm,
  15 + ProFormInstance,
  16 + ProFormList,
  17 + ProFormSelect,
  18 + ProFormText,
  19 + ProFormTextArea,
  20 +} from '@ant-design/pro-components';
  21 +import { Button, Divider, Form, Space, message } from 'antd';
  22 +import { useEffect, useRef, useState } from 'react';
  23 +
  24 +export default ({ id, setVisible }) => {
  25 + const [readOnly, setReadOnly] = useState(true);
  26 + const [detailTableData, setDetailTableData] = useState([]);
  27 + const [payees, setPayees] = useState([]);
  28 + const [payeeNameOptions, setPayeeNameOptions] = useState([]);
  29 + const formRef = useRef<ProFormInstance>();
  30 + const [form] = Form.useForm();
  31 +
  32 + useEffect(() => {
  33 + console.log('id' + id);
  34 + const getPayees = async () => {
  35 + let res = await postServiceConstGetPayeeEnum();
  36 + setPayees(res.data);
  37 + let payeeNameOptions = res.data.map((item) => {
  38 + return {
  39 + label: item.payeeName,
  40 + value: item.payeeName,
  41 + };
  42 + });
  43 + setPayeeNameOptions(payeeNameOptions);
  44 + };
  45 + getPayees();
  46 + }, []);
  47 + const getRecord = async (id) => {
  48 + let ret = await postServiceInvoiceGetInvoiceRecord({
  49 + query: {
  50 + id: id,
  51 + },
  52 + });
  53 + console.log(ret.data);
  54 + const updatedInvoiceDetails = ret.data.invoiceDetails?.map(
  55 + (item, index) => ({
  56 + ...item, // 保留原有属性
  57 + tid: index + 1, // 添加tid属性,这里以T开头,后面跟索引+1,仅作示例,实际可根据需求生成tid
  58 + }),
  59 + );
  60 + setDetailTableData(updatedInvoiceDetails);
  61 + };
  62 + useEffect(() => {
  63 + getRecord(id);
  64 + }, []);
  65 +
  66 + const updateDetails = (values) => {
  67 + setDetailTableData(values);
  68 + };
  69 + return (
  70 + <>
  71 + <Space>
  72 + <ModalForm
  73 + open
  74 + title="发票详情"
  75 + formRef={formRef}
  76 + request={async () => {
  77 + let ret = await postServiceInvoiceGetInvoiceRecord({
  78 + query: {
  79 + id: id,
  80 + },
  81 + });
  82 + const data = ret.data;
  83 + const orderIdMap = data.orderIdMap;
  84 + const orderIdList = [];
  85 +
  86 + // 使用Object.entries()遍历属性
  87 + Object.entries(orderIdMap).forEach(([key, value]) => {
  88 + const orderId = {
  89 + mainId: key,
  90 + subIds: value,
  91 + };
  92 + orderIdList.push(orderId);
  93 + });
  94 + return {
  95 + ...data,
  96 + orderIdList: orderIdList,
  97 + };
  98 + }}
  99 + submitter={{
  100 + render: () => {
  101 + return [
  102 + <Button
  103 + type={readOnly ? 'primary' : 'default'}
  104 + key="ok"
  105 + onClick={() => {
  106 + setReadOnly(!readOnly);
  107 + }}
  108 + >
  109 + {readOnly ? '编辑' : '取消编辑'}
  110 + </Button>,
  111 + <>
  112 + {!readOnly && (
  113 + <Button
  114 + type="primary"
  115 + key="submit"
  116 + onClick={async () => {
  117 + const result = await postServiceInvoiceModifyRecord({
  118 + data: {
  119 + ...form.getFieldsValue(),
  120 + invoiceDetails: [...detailTableData],
  121 + },
  122 + });
  123 + if (result.result === RESPONSE_CODE.SUCCESS) {
  124 + message.success('提交成功');
  125 + }
  126 + setVisible(false);
  127 + return true;
  128 + }}
  129 + >
  130 + 提交
  131 + </Button>
  132 + )}
  133 + </>,
  134 + /*<Button
  135 + type={'default'}
  136 + key="ok"
  137 + onClick={() => {
  138 + setVisible(false)
  139 + }}
  140 + >
  141 + 取消
  142 + </Button>,*/
  143 + ];
  144 + },
  145 + }}
  146 + width={1200}
  147 + form={form}
  148 + autoFocusFirstInput
  149 + modalProps={{
  150 + destroyOnClose: true,
  151 + onCancel: () => {
  152 + setVisible(false);
  153 + },
  154 + }}
  155 + grid={true}
  156 + layout="horizontal"
  157 + rowProps={{
  158 + gutter: [0, 0],
  159 + }}
  160 + submitTimeout={2000}
  161 + onFinish={async (values) => {
  162 + const result = await postServiceInvoiceModifyRecord({
  163 + data: {
  164 + ...values,
  165 + invoiceDetails: {
  166 + ...detailTableData,
  167 + },
  168 + },
  169 + });
  170 + if (result.result === RESPONSE_CODE.SUCCESS) {
  171 + message.success('提交成功');
  172 + }
  173 + return true;
  174 + }}
  175 + >
  176 + <ProCard
  177 + title="基础信息"
  178 + bordered
  179 + //
  180 + headStyle={{}}
  181 + headerBordered
  182 + size={'small'}
  183 + >
  184 + <ProForm.Group>
  185 + <ProFormText
  186 + readonly
  187 + name="id"
  188 + label="订单批号"
  189 + colProps={{
  190 + span: 5,
  191 + }}
  192 + tooltip="最长为 24 位"
  193 + placeholder="请输入名称"
  194 + />
  195 +
  196 + <ProFormText
  197 + readonly
  198 + width="md"
  199 + colProps={{
  200 + span: 5,
  201 + }}
  202 + name="createByName"
  203 + label="销售代表"
  204 + placeholder="请输入名称"
  205 + />
  206 + <ProFormText
  207 + readonly
  208 + width="md"
  209 + colProps={{
  210 + span: 5,
  211 + }}
  212 + name="createTime"
  213 + label="申请时间"
  214 + placeholder="请输入名称"
  215 + />
  216 + <ProFormSelect
  217 + name="type"
  218 + label="发票类型"
  219 + colProps={{
  220 + span: 5,
  221 + }}
  222 + readonly={readOnly}
  223 + request={async () => {
  224 + let invoiceTypeRet = await postServiceConstInvoiceType();
  225 + return enumToSelect(invoiceTypeRet.data);
  226 + }}
  227 + placeholder="Please select a country"
  228 + rules={[
  229 + { required: true, message: 'Please select your country!' },
  230 + ]}
  231 + />
  232 + <ProFormSelect
  233 + name="invoicingType"
  234 + readonly={readOnly}
  235 + label="开具类型"
  236 + colProps={{
  237 + span: 4,
  238 + }}
  239 + request={async () => {
  240 + let invoicingTypeRet = await postServiceConstInvoicingType();
  241 + let options = enumToSelect(invoicingTypeRet.data);
  242 + return options;
  243 + }}
  244 + placeholder="Please select a country"
  245 + rules={[
  246 + { required: true, message: 'Please select your country!' },
  247 + ]}
  248 + />
  249 + <ProFormList
  250 + label="订单号"
  251 + name="orderIdList"
  252 + creatorButtonProps={false}
  253 + itemRender={({}, { record }) => {
  254 + console.log('record' + JSON.stringify(record));
  255 + return (
  256 + <Space>
  257 + <Button
  258 + key={record.mainId}
  259 + className="pl-1 pr-0"
  260 + type="link"
  261 + target="_blank"
  262 + href={'/order?id=' + record.mainId}
  263 + >
  264 + {record.mainId}
  265 + </Button>
  266 + (
  267 + {record.subIds.map((item) => {
  268 + return (
  269 + <Button
  270 + key={item}
  271 + className="pl-1 pr-0"
  272 + type="link"
  273 + target="_blank"
  274 + href={'/order?subOrderId=' + item}
  275 + >
  276 + {item}
  277 + </Button>
  278 + );
  279 + })}
  280 + )
  281 + <Divider type="vertical" />
  282 + </Space>
  283 + );
  284 + }}
  285 + >
  286 + <ProFormText allowClear={false} width="xs" name={['name']} />
  287 + </ProFormList>
  288 + </ProForm.Group>
  289 + </ProCard>
  290 + <hr />
  291 + <ProCard title="购方信息" bordered headerBordered size={'small'}>
  292 + <ProForm.Group>
  293 + <ProFormText
  294 + readonly={readOnly}
  295 + width="md"
  296 + colProps={{
  297 + span: 8,
  298 + }}
  299 + name="partyAName"
  300 + label="购方名称"
  301 + placeholder="请输入名称"
  302 + />
  303 + <ProFormText
  304 + readonly={readOnly}
  305 + width="md"
  306 + colProps={{
  307 + span: 8,
  308 + }}
  309 + name="partyATaxid"
  310 + label="购方税号"
  311 + placeholder="请输入名称"
  312 + />
  313 + <ProFormText
  314 + readonly={readOnly}
  315 + width="md"
  316 + colProps={{
  317 + span: 8,
  318 + }}
  319 + label="开户银行"
  320 + name={'partyAOpenBank'}
  321 + placeholder="请输入名称"
  322 + />
  323 + <ProFormText
  324 + readonly={readOnly}
  325 + width="md"
  326 + colProps={{
  327 + span: 8,
  328 + }}
  329 + name="partyABankAccount"
  330 + label="银行账号"
  331 + placeholder="请输入名称"
  332 + />
  333 + <ProFormText
  334 + readonly={readOnly}
  335 + width="md"
  336 + colProps={{
  337 + span: 8,
  338 + }}
  339 + name="partyAAddress"
  340 + label="购方地址"
  341 + placeholder="请输入名称"
  342 + />
  343 + <ProFormText
  344 + readonly={readOnly}
  345 + width="md"
  346 + colProps={{
  347 + span: 8,
  348 + }}
  349 + name="partyAPhoneNumber"
  350 + label="电话"
  351 + placeholder="请输入名称"
  352 + />
  353 + </ProForm.Group>
  354 + </ProCard>
  355 + <hr />
  356 + <ProCard title="销方信息" bordered headerBordered size={'small'}>
  357 + <ProForm.Group>
  358 + <ProFormSelect
  359 + readonly={readOnly}
  360 + width="md"
  361 + name="partyBName"
  362 + options={payeeNameOptions}
  363 + onChange={(value: any) => {
  364 + let payee = payees.find((item: any) => {
  365 + return item.payeeName === value;
  366 + });
  367 + console.log(JSON.stringify(payee));
  368 + form.setFieldsValue({
  369 + partyBTaxid: payee.taxId,
  370 + partyBBankAccount: payee.bankAccount,
  371 + partyBOpenBank: payee.openBank,
  372 + partyBAddress: payee.address,
  373 + partyBPhoneNumber: payee.phoneNumber,
  374 + });
  375 + }}
  376 + label="销方名称"
  377 + colProps={{
  378 + span: 8,
  379 + }}
  380 + placeholder="请输入名称"
  381 + />
  382 +
  383 + <ProFormText
  384 + readonly
  385 + width="md"
  386 + name="partyBTaxid"
  387 + label="销方税号"
  388 + colProps={{
  389 + span: 8,
  390 + }}
  391 + placeholder="请输入名称"
  392 + />
  393 + <ProFormText
  394 + readonly
  395 + width="md"
  396 + name="partyBOpenBank"
  397 + label="开户银行"
  398 + colProps={{
  399 + span: 8,
  400 + }}
  401 + placeholder="请输入名称"
  402 + />
  403 + <ProFormText
  404 + readonly
  405 + width="md"
  406 + name="partyBBankAccount"
  407 + label="银行账号"
  408 + colProps={{
  409 + span: 8,
  410 + }}
  411 + placeholder="请输入名称"
  412 + />
  413 + <ProFormText
  414 + readonly
  415 + width="md"
  416 + colProps={{
  417 + span: 8,
  418 + }}
  419 + name="partyBAddress"
  420 + label="销方地址"
  421 + placeholder="请输入名称"
  422 + />
  423 + <ProFormText
  424 + readonly
  425 + width="md"
  426 + colProps={{
  427 + span: 8,
  428 + }}
  429 + name="partyBPhoneNumber"
  430 + label="电话"
  431 + placeholder="请输入名称"
  432 + />
  433 + </ProForm.Group>
  434 + </ProCard>
  435 + <hr />
  436 + <ProCard title="发票明细" bordered headerBordered size={'small'}>
  437 + <InvoiceDetailTable
  438 + recordId={id}
  439 + details={detailTableData}
  440 + updateDetails={updateDetails}
  441 + readOnly={readOnly}
  442 + />
  443 + </ProCard>
  444 + <hr />
  445 + <ProCard title="备注" bordered headerBordered size={'small'}>
  446 + <ProFormTextArea
  447 + readonly={readOnly}
  448 + name="comment"
  449 + placeholder="请输入备注"
  450 + />
  451 + </ProCard>
  452 + </ModalForm>
  453 + </Space>
  454 + </>
  455 + );
  456 +};
... ...
src/pages/Invoice/waitProcessRecord/components/InvoiceVerificationModal.tsx 0 → 100644
  1 +import ButtonConfirm from '@/components/ButtomConfirm';
  2 +import EllipsisDiv from '@/components/Div/EllipsisDiv';
  3 +import { RESPONSE_CODE } from '@/constants/enum';
  4 +import { INVOCING_STATUS, PAYEE_OPTIONS } from '@/pages/Order/constant';
  5 +import {
  6 + postServiceInvoiceCancelInvoiceAndBankStatement,
  7 + postServiceInvoiceQueryInvoiceDetail,
  8 +} from '@/services';
  9 +import { enumValueToLabel, formatDateTime } from '@/utils';
  10 +import { formatDate } from '@/utils/time';
  11 +import { PlusOutlined } from '@ant-design/icons';
  12 +import {
  13 + ActionType,
  14 + ModalForm,
  15 + ProCard,
  16 + ProTable,
  17 +} from '@ant-design/pro-components';
  18 +import {
  19 + Button,
  20 + Descriptions,
  21 + DescriptionsProps,
  22 + Divider,
  23 + Flex,
  24 + Form,
  25 + message,
  26 +} from 'antd';
  27 +import { useEffect, useRef, useState } from 'react';
  28 +import { BANK_STATEMENT_COLUMNS, INVOICE_STATUS } from '../../constant';
  29 +import '../index.less';
  30 +import BankChooseModal from './BankChooseModal';
  31 +
  32 +export default ({ invoiceId, setVisible, onClose }) => {
  33 + const [form] = Form.useForm<{ id: string }>();
  34 + const [bankChooseModalVisible, setBankChooseModalVisible] = useState(false);
  35 + const [invoiceInfo, setInvoiceInfo] = useState({});
  36 + const [relationOrderIds, setRelationOrderIds] = useState([]);
  37 + const [relationBankStatements, setRelationBankStatements] = useState([]);
  38 + const actionRef = useRef<ActionType>();
  39 +
  40 + const loadInvoiceData = async () => {
  41 + let res = await postServiceInvoiceQueryInvoiceDetail({
  42 + data: { invoiceId: invoiceId },
  43 + });
  44 + if (res && res.data) {
  45 + setInvoiceInfo(res.data);
  46 + setRelationOrderIds(res.data.mainOrderIds);
  47 + console.log('bs:' + res.data.bankStatementDtos);
  48 + setRelationBankStatements(res.data.bankStatementDtos);
  49 + }
  50 + };
  51 +
  52 + const showRelationOrders = () => {
  53 + return relationOrderIds?.map((item) => {
  54 + return (
  55 + <>
  56 + <Button
  57 + className="pl-1 pr-0"
  58 + type="link"
  59 + target="_blank"
  60 + href={'/order?id=' + item}
  61 + >
  62 + {item}
  63 + </Button>
  64 + <Divider type="vertical" />
  65 + </>
  66 + );
  67 + });
  68 + };
  69 +
  70 + const items: DescriptionsProps['items'] = [
  71 + {
  72 + key: '1',
  73 + label: '发票号码',
  74 + children: invoiceInfo?.invoiceNumber,
  75 + span: 6,
  76 + },
  77 + {
  78 + key: '2',
  79 + label: '发票类型',
  80 + children: enumValueToLabel(invoiceInfo?.invoiceStatus, INVOCING_STATUS),
  81 + span: 6,
  82 + },
  83 + {
  84 + key: '3',
  85 + label: '状态',
  86 + children: enumValueToLabel(invoiceInfo?.status, INVOICE_STATUS),
  87 + span: 4,
  88 + },
  89 + {
  90 + key: '4',
  91 + label: '购买方',
  92 + children: invoiceInfo?.purchaser,
  93 + span: 8,
  94 + },
  95 + {
  96 + key: '5',
  97 + label: '收款单位',
  98 + children: enumValueToLabel(invoiceInfo?.payee, PAYEE_OPTIONS),
  99 + span: 12,
  100 + },
  101 + {
  102 + key: '6',
  103 + label: '联系人',
  104 + children: invoiceInfo?.contacts,
  105 + span: 4,
  106 + },
  107 + {
  108 + key: '7',
  109 + label: '销售',
  110 + children: invoiceInfo?.sale,
  111 + span: 8,
  112 + },
  113 +
  114 + {
  115 + key: '9',
  116 + label: '开票日期',
  117 + children: formatDate(invoiceInfo?.invoicingTime),
  118 + span: 12,
  119 + },
  120 + {
  121 + key: '10',
  122 + label: '收款时间',
  123 + children: formatDate(invoiceInfo?.collectionTime),
  124 + span: 4,
  125 + },
  126 + {
  127 + key: '8',
  128 + label: '金额',
  129 + children: invoiceInfo?.money,
  130 + span: 10,
  131 + },
  132 + {
  133 + key: '11',
  134 + label: '备注',
  135 + children: invoiceInfo?.notes,
  136 + span: 24,
  137 + },
  138 + ];
  139 +
  140 + const getTableCellText = (target: any) => {
  141 + if (!target) {
  142 + return '';
  143 + }
  144 +
  145 + if (target.props) {
  146 + return target.props.text;
  147 + }
  148 +
  149 + return target;
  150 + };
  151 +
  152 + /**
  153 + * 加载表格的各个列格式
  154 + */
  155 + const bankStatementColumnsInit = () => {
  156 + let columns = BANK_STATEMENT_COLUMNS.map((item) => {
  157 + let newItem = { ...item };
  158 + let dataIndex = item.dataIndex;
  159 + let dataType = item.valueType;
  160 +
  161 + newItem.render = (text, record) => {
  162 + let textValue = record[dataIndex];
  163 +
  164 + if (dataType === 'date') {
  165 + textValue = formatDate(textValue);
  166 + }
  167 +
  168 + if (dataType === 'dateTime') {
  169 + textValue = formatDateTime(textValue);
  170 + }
  171 +
  172 + if (dataType === 'money') {
  173 + textValue = '¥' + textValue;
  174 + }
  175 +
  176 + switch (dataIndex) {
  177 + case 'invoiceStatus':
  178 + return (
  179 + <EllipsisDiv
  180 + text={enumValueToLabel(
  181 + getTableCellText(textValue),
  182 + INVOCING_STATUS,
  183 + )}
  184 + />
  185 + );
  186 +
  187 + case 'status':
  188 + return (
  189 + <EllipsisDiv
  190 + text={enumValueToLabel(
  191 + getTableCellText(textValue),
  192 + INVOICE_STATUS,
  193 + )}
  194 + />
  195 + );
  196 +
  197 + case 'payee':
  198 + return (
  199 + <EllipsisDiv
  200 + text={enumValueToLabel(
  201 + getTableCellText(textValue),
  202 + PAYEE_OPTIONS,
  203 + )}
  204 + />
  205 + );
  206 +
  207 + default:
  208 + return <EllipsisDiv text={getTableCellText(textValue)} />;
  209 + }
  210 + };
  211 +
  212 + return newItem;
  213 + });
  214 +
  215 + columns.push({
  216 + title: '操作',
  217 + valueType: 'option',
  218 + key: 'option',
  219 + fixed: 'right',
  220 + width: 70,
  221 + render: (text, record) => {
  222 + let optBtns = [];
  223 + if (invoiceInfo?.status === 'VERIFIED') {
  224 + return [];
  225 + }
  226 +
  227 + optBtns.push(
  228 + <ButtonConfirm
  229 + key="delete"
  230 + className="p-0"
  231 + title={'确认删除此项吗?'}
  232 + text="删除"
  233 + onConfirm={async () => {
  234 + let res = await postServiceInvoiceCancelInvoiceAndBankStatement({
  235 + data: {
  236 + invoiceId: invoiceId,
  237 + cancelId: [record.id],
  238 + },
  239 + });
  240 + if (res.result === RESPONSE_CODE.SUCCESS) {
  241 + message.success(res.message);
  242 + loadInvoiceData();
  243 + }
  244 + }}
  245 + />,
  246 + );
  247 + return optBtns;
  248 + },
  249 + });
  250 +
  251 + return columns;
  252 + };
  253 +
  254 + useEffect(() => {
  255 + loadInvoiceData();
  256 + }, []);
  257 +
  258 + return (
  259 + <>
  260 + <ModalForm<{
  261 + id: string;
  262 + }>
  263 + className="invoice-detail"
  264 + open
  265 + width="80%"
  266 + title="发票详情"
  267 + form={form}
  268 + autoFocusFirstInput
  269 + modalProps={{
  270 + okText: '确定',
  271 + cancelText: '返回',
  272 + destroyOnClose: true,
  273 + onCancel: () => {
  274 + setVisible(false);
  275 + onClose();
  276 + },
  277 + }}
  278 + submitter={{
  279 + render: (props, defaultDoms) => {
  280 + return [defaultDoms[0]];
  281 + },
  282 + }}
  283 + onFinish={async () => {
  284 + onClose();
  285 + }}
  286 + onOpenChange={setVisible}
  287 + >
  288 + <Divider orientation="left" plain>
  289 + 发票信息
  290 + </Divider>
  291 +
  292 + <Descriptions
  293 + bordered
  294 + column={24}
  295 + size="small"
  296 + title=""
  297 + items={items}
  298 + />
  299 +
  300 + <Divider orientation="left" plain>
  301 + 订单号
  302 + </Divider>
  303 +
  304 + <ProCard bordered style={{}}>
  305 + <Flex>
  306 + <div>{showRelationOrders()}</div>
  307 + </Flex>
  308 + </ProCard>
  309 +
  310 + <Divider plain></Divider>
  311 +
  312 + <ProTable
  313 + columns={bankStatementColumnsInit()}
  314 + actionRef={actionRef}
  315 + cardBordered
  316 + pagination={{
  317 + pageSize: 10,
  318 + }}
  319 + dataSource={relationBankStatements}
  320 + columnsState={{
  321 + persistenceKey: 'pro-table-singe-demos',
  322 + persistenceType: 'localStorage',
  323 + defaultValue: {
  324 + option: { fixed: 'right', disable: true },
  325 + },
  326 + onChange(value) {
  327 + console.log('value: ', value);
  328 + },
  329 + }}
  330 + rowKey="id"
  331 + search={false}
  332 + options={{
  333 + setting: {
  334 + listsHeight: 400,
  335 + },
  336 + reload: false,
  337 + }}
  338 + form={{
  339 + // 由于配置了 transform,提交的参与与定义的不同这里需要转化一下
  340 + syncToUrl: (values, type) => {
  341 + if (type === 'get') {
  342 + return {
  343 + ...values,
  344 + created_at: [values.startTime, values.endTime],
  345 + };
  346 + }
  347 + return values;
  348 + },
  349 + }}
  350 + dateFormatter="string"
  351 + headerTitle="银行流水"
  352 + scroll={{ x: 1400, y: 360 }}
  353 + toolBarRender={() => [
  354 + <Button
  355 + key="button"
  356 + icon={<PlusOutlined />}
  357 + onClick={() => {
  358 + setBankChooseModalVisible(true);
  359 + }}
  360 + hidden={invoiceInfo?.status === 'VERIFIED'}
  361 + type="primary"
  362 + >
  363 + 添加
  364 + </Button>,
  365 + ]}
  366 + />
  367 + </ModalForm>
  368 +
  369 + {bankChooseModalVisible ? (
  370 + <BankChooseModal
  371 + loadInvoiceData={loadInvoiceData}
  372 + setVisible={setBankChooseModalVisible}
  373 + invoiceId={invoiceId}
  374 + onClose={() => {
  375 + setBankChooseModalVisible(false);
  376 + loadInvoiceData();
  377 + actionRef.current?.reload();
  378 + }}
  379 + ></BankChooseModal>
  380 + ) : (
  381 + ''
  382 + )}
  383 + </>
  384 + );
  385 +};
... ...
src/pages/Invoice/waitProcessRecord/components/InvoicingModal.tsx 0 → 100644
  1 +import { RESPONSE_CODE } from '@/constants/enum';
  2 +import { postServiceInvoiceInvoicing } from '@/services';
  3 +import { ModalForm } from '@ant-design/pro-components';
  4 +import { Button, Form, message } from 'antd';
  5 +
  6 +export default ({ selectedRowKeys, reloadRecordTable }) => {
  7 + const [form] = Form.useForm<{ name: string; company: string }>();
  8 + return (
  9 + <ModalForm<{
  10 + name: string;
  11 + company: string;
  12 + }>
  13 + title="开票"
  14 + trigger={
  15 + <Button type="primary" disabled={selectedRowKeys?.length === 0}>
  16 + 开票
  17 + </Button>
  18 + }
  19 + form={form}
  20 + autoFocusFirstInput
  21 + modalProps={{
  22 + destroyOnClose: true,
  23 + onCancel: () => console.log('run'),
  24 + }}
  25 + submitTimeout={2000}
  26 + onFinish={async (values) => {
  27 + let res = await postServiceInvoiceInvoicing({
  28 + data: {
  29 + ...values,
  30 + invoiceRecordIds: selectedRowKeys,
  31 + },
  32 + });
  33 + if (res.result === RESPONSE_CODE.SUCCESS) {
  34 + message.success(res.message);
  35 + }
  36 + reloadRecordTable();
  37 + message.success('提交成功');
  38 + return true;
  39 + }}
  40 + >
  41 + {/*<ProFormSelect
  42 + name="invoicingAccount"
  43 + label="开票账号"
  44 + request={async () => {
  45 + const res = await postServiceInvoiceGetInvoicingAccount();
  46 + return res.data.map((item) => {
  47 + return {
  48 + label: item.accountText,
  49 + value: item.account,
  50 + };
  51 + });
  52 + }}
  53 + placeholder="请选择开票账号"
  54 + rules={[{ required: true, message: '请选择开票账号!' }]}
  55 + />*/}
  56 + </ModalForm>
  57 + );
  58 +};
... ...
src/pages/Invoice/waitProcessRecord/components/ManualInvoicingModal.tsx 0 → 100644
  1 +import { RESPONSE_CODE } from '@/constants/enum';
  2 +import UploadC from '@/pages/Invoice/waitProcessRecord/components/UploadSingleImg';
  3 +import {
  4 + postOrderErpOrderStagesUpload,
  5 + postServiceInvoiceDealInvoicingResult,
  6 +} from '@/services';
  7 +import {
  8 + ModalForm,
  9 + ProFormDatePicker,
  10 + ProFormText,
  11 +} from '@ant-design/pro-components';
  12 +import { Col, Form, Row, message } from 'antd';
  13 +import { RcFile } from 'antd/es/upload';
  14 +import { useEffect } from 'react';
  15 +
  16 +export default ({ record }) => {
  17 + useEffect(() => {
  18 + console.log('invoicing');
  19 + }, []);
  20 + const [form] = Form.useForm();
  21 + return (
  22 + <ModalForm
  23 + title="手动开票"
  24 + trigger={<a type="primary">手动开票</a>}
  25 + width={600}
  26 + layout={'horizontal'}
  27 + form={form}
  28 + autoFocusFirstInput
  29 + modalProps={{
  30 + destroyOnClose: true,
  31 + onCancel: () => console.log('run'),
  32 + }}
  33 + submitTimeout={2000}
  34 + onFinish={async (values) => {
  35 + const res = await postServiceInvoiceDealInvoicingResult({
  36 + data: {
  37 + ...values,
  38 + isSuccess: true,
  39 + invoiceRecordId: record.id,
  40 + manual: true,
  41 + },
  42 + });
  43 + if (res.result === RESPONSE_CODE.SUCCESS) {
  44 + message.success('开票成功');
  45 + return true;
  46 + } else {
  47 + message.error('开票失败');
  48 + }
  49 + }}
  50 + >
  51 + {/*<ProFormText
  52 + rules={[{ required: true, message: '此项为必填项' }]}
  53 + width={'md'}
  54 + name="invoicingPerson"
  55 + label="开票人"
  56 + />*/}
  57 + <ProFormText
  58 + rules={[{ required: true, message: '此项为必填项' }]}
  59 + width={'md'}
  60 + name="invoiceNumber"
  61 + label="发票号码"
  62 + />
  63 + <ProFormDatePicker
  64 + rules={[{ required: true, message: '此项为必填项' }]}
  65 + fieldProps={{
  66 + format: 'YYYY-MM-DD',
  67 + }}
  68 + name="invoicingDate"
  69 + label="开票日期"
  70 + />
  71 + <ProFormText
  72 + rules={[{ required: true, message: '发票必须上传' }]}
  73 + hidden
  74 + name="url"
  75 + label="發票地址"
  76 + />
  77 + <Row>
  78 + <Col span={4}>上传发票</Col>
  79 + <Col span={20}>
  80 + <UploadC
  81 + onFilesChange={async (newFileList) => {
  82 + if (newFileList.length > 0) {
  83 + const formData = new FormData();
  84 + formData.append('file', newFileList[0].originFileObj as RcFile);
  85 + const res = await postOrderErpOrderStagesUpload({
  86 + data: formData,
  87 + headers: {
  88 + 'Content-Type':
  89 + 'multipart/form-data; boundary=----WebKitFormBoundarynl6gT1BKdPWIejNq',
  90 + },
  91 + });
  92 + const url = res.data;
  93 + form.setFieldValue('url', url);
  94 + } else {
  95 + form.setFieldValue('url', null);
  96 + }
  97 + }}
  98 + ></UploadC>
  99 + </Col>
  100 + </Row>
  101 + {/*<ProFormList
  102 + name="invoiceDetailDtoList"
  103 + label="明细"
  104 + creatorButtonProps={false}
  105 + copyIconProps={false}
  106 + itemRender={({ listDom }, { index }) => (
  107 + <ProCard
  108 + bordered
  109 + style={{ marginBlockEnd: 8 }}
  110 + title={`明细${index + 1}`}
  111 + bodyStyle={{ paddingBlockEnd: 0 }}
  112 + >
  113 + {listDom}
  114 + </ProCard>
  115 + )}
  116 + creatorRecord={{ name: '', items: [{ name: '' }] }}
  117 + initialValue={record.invoiceDetails}
  118 + >
  119 + <ProFormText
  120 + name="projectName"
  121 + label="名称"
  122 + placeholder="请输入名称"
  123 + readonly
  124 + />
  125 + <ProFormDigit label="税率" name="taxRate" min={0} max={100} />
  126 + <ProFormMoney label="税额" name="taxPrice" locale="zh-CN" min={0} />
  127 + </ProFormList>*/}
  128 + </ModalForm>
  129 + );
  130 +};
... ...
src/pages/Invoice/waitProcessRecord/components/UploadSingleImg.tsx 0 → 100644
  1 +import { PlusOutlined } from '@ant-design/icons';
  2 +import type { GetProp, UploadFile, UploadProps } from 'antd';
  3 +import { Image, Upload } from 'antd';
  4 +import { useState } from 'react';
  5 +
  6 +type FileType = Parameters<GetProp<UploadProps, 'beforeUpload'>>[0];
  7 +
  8 +const getBase64 = (file: FileType): Promise<string> =>
  9 + new Promise((resolve, reject) => {
  10 + const reader = new FileReader();
  11 + reader.readAsDataURL(file);
  12 + reader.onload = () => resolve(reader.result as string);
  13 + reader.onerror = (error) => reject(error);
  14 + });
  15 +
  16 +export default ({ onFilesChange }) => {
  17 + const [previewOpen, setPreviewOpen] = useState(false);
  18 + const [previewImage, setPreviewImage] = useState('');
  19 + const [fileList, setFileList] = useState<UploadFile[]>([]);
  20 +
  21 + const handlePreview = async (file: UploadFile) => {
  22 + if (!file.url && !file.preview) {
  23 + file.preview = await getBase64(file.originFileObj as FileType);
  24 + }
  25 +
  26 + setPreviewImage(file.url || (file.preview as string));
  27 + setPreviewOpen(true);
  28 + };
  29 +
  30 + const uploadButton = (
  31 + <button style={{ border: 0, background: 'none' }} type="button">
  32 + <PlusOutlined />
  33 + <div style={{ marginTop: 8 }}>Upload</div>
  34 + </button>
  35 + );
  36 + return (
  37 + <>
  38 + <Upload
  39 + listType="picture-card"
  40 + fileList={fileList}
  41 + onPreview={handlePreview}
  42 + onChange={({ fileList: newFileList }) => {
  43 + setFileList(newFileList);
  44 + console.log('file' + JSON.stringify(newFileList));
  45 + onFilesChange(newFileList);
  46 + }}
  47 + >
  48 + {fileList.length >= 1 ? null : uploadButton}
  49 + </Upload>
  50 + {previewImage && (
  51 + <Image
  52 + wrapperStyle={{ display: 'none' }}
  53 + preview={{
  54 + visible: previewOpen,
  55 + onVisibleChange: (visible) => setPreviewOpen(visible),
  56 + afterOpenChange: (visible) => !visible && setPreviewImage(''),
  57 + }}
  58 + src={previewImage}
  59 + />
  60 + )}
  61 + </>
  62 + );
  63 +};
... ...
src/pages/Invoice/waitProcessRecord/index.less 0 → 100644
  1 +.invoice-index td {
  2 + font-family: 'San Francisco', 'Helvetica Neue', Helvetica, Arial,
  3 + 'Microsoft YaHei', 'PingFang SC', 'Hiragino Sans GB', 'Heiti SC',
  4 + 'WenQuanYi Micro Hei', sans-serif;
  5 + font-size: 14px;
  6 +}
  7 +
  8 +.invoice-detail td {
  9 + font-family: 'San Francisco', 'Helvetica Neue', Helvetica, Arial,
  10 + 'Microsoft YaHei', 'PingFang SC', 'Hiragino Sans GB', 'Heiti SC',
  11 + 'WenQuanYi Micro Hei', sans-serif;
  12 + font-size: 14px;
  13 +}
  14 +
  15 +.bank-statement-choose td {
  16 + font-family: 'San Francisco', 'Helvetica Neue', Helvetica, Arial,
  17 + 'Microsoft YaHei', 'PingFang SC', 'Hiragino Sans GB', 'Heiti SC',
  18 + 'WenQuanYi Micro Hei', sans-serif;
  19 + font-size: 14px;
  20 +}
... ...
src/pages/Invoice/waitProcessRecord/index.tsx 0 → 100644
  1 +import InvoiceModal from '@/pages/Invoice/waitProcessRecord/components/InvoiceModal';
  2 +import InvoiceRecordDetailModal from '@/pages/Invoice/waitProcessRecord/components/InvoiceRecordDetailModal';
  3 +import InvoicingModal from '@/pages/Invoice/waitProcessRecord/components/InvoicingModal';
  4 +import ManualInvoicingModal from '@/pages/Invoice/waitProcessRecord/components/ManualInvoicingModal';
  5 +import { PAYEE_OPTIONS } from '@/pages/Order/constant';
  6 +import {
  7 + postServiceConstBeforeInvoicingInvoiceRecordStatus,
  8 + postServiceConstInvoiceType,
  9 + postServiceConstInvoicingType,
  10 + postServiceInvoiceQueryInvoiceRecordList,
  11 + postServiceOrderQuerySalesCode,
  12 +} from '@/services';
  13 +import { enumToProTableEnumValue, enumToSelect } from '@/utils';
  14 +import { ActionType, ProTable } from '@ant-design/pro-components';
  15 +import { Space, Table, message } from 'antd';
  16 +import { useEffect, useRef, useState } from 'react';
  17 +
  18 +const InvoiceRecord = () => {
  19 + const waitDealrecordActionRef = useRef<ActionType>();
  20 + const [invoiceTypeValueEnum, setInvoiceTypeValueEnum] = useState({});
  21 + const [invoicingTypeValueEnum, setInvoicingTypeValueEnum] = useState({});
  22 + const [salesCodeValueEnum, setSalesCodeValueEnum] = useState({});
  23 + const [invoiceRecordDetailVisible, setInvoiceRecordDetailVisible] =
  24 + useState(false);
  25 + const [invoiceRecord, setInvoiceRecord] = useState({});
  26 + const [contextHolder] = message.useMessage();
  27 +
  28 + useEffect(() => {
  29 + async function extracted() {
  30 + let invoiceTypeRet = await postServiceConstInvoiceType();
  31 + setInvoiceTypeValueEnum(invoiceTypeRet.data);
  32 + }
  33 +
  34 + extracted().catch(console.error);
  35 + }, []);
  36 +
  37 + useEffect(() => {
  38 + async function extracted() {
  39 + let invoicingTypeRet = await postServiceConstInvoicingType();
  40 + setInvoicingTypeValueEnum(invoicingTypeRet.data);
  41 + }
  42 +
  43 + extracted().catch(console.error);
  44 + }, []);
  45 +
  46 + useEffect(() => {
  47 + async function extracted() {
  48 + const res = await postServiceOrderQuerySalesCode();
  49 + let map = {};
  50 + res.data?.forEach((item) => {
  51 + map[item.userName] = { text: item.userName, status: item.userName };
  52 + });
  53 + setSalesCodeValueEnum(map);
  54 + }
  55 +
  56 + extracted().catch(console.error);
  57 + }, []);
  58 +
  59 + const reloadRecordTable = () => {
  60 + waitDealrecordActionRef.current?.reload();
  61 + };
  62 +
  63 + const waitDealRecordColumns = [
  64 + {
  65 + dataIndex: 'index',
  66 + valueType: 'indexBorder',
  67 + hideInSearch: true,
  68 + ellipsis: true,
  69 + width: 48,
  70 + },
  71 + {
  72 + title: '开票编号',
  73 + valueType: 'text',
  74 + dataIndex: 'id',
  75 + copyable: true,
  76 + hideInSearch: true,
  77 + ellipsis: true,
  78 + width: 100,
  79 + },
  80 + {
  81 + title: '发票状态',
  82 + valueType: 'Text',
  83 + dataIndex: 'statusText',
  84 + ellipsis: true,
  85 + hideInSearch: true,
  86 + },
  87 + {
  88 + title: '申请开票时间',
  89 + dataIndex: 'createTime',
  90 + valueType: 'dateTime',
  91 + hideInSearch: true,
  92 + ellipsis: true,
  93 + },
  94 + {
  95 + title: '销售代表',
  96 + valueType: 'text',
  97 + hideInSearch: true,
  98 + ellipsis: true,
  99 + dataIndex: 'createByName',
  100 + },
  101 + {
  102 + title: '购方名称',
  103 + valueType: 'text',
  104 + dataIndex: 'partyAName',
  105 + hideInSearch: true,
  106 + ellipsis: true,
  107 + },
  108 + {
  109 + title: '购方税号',
  110 + valueType: 'text',
  111 + hideInSearch: true,
  112 + dataIndex: 'partyATaxid',
  113 + ellipsis: true,
  114 + },
  115 + {
  116 + title: '收款单位',
  117 + valueType: 'text',
  118 + hideInSearch: true,
  119 + dataIndex: 'partyBName',
  120 + ellipsis: true,
  121 + },
  122 + {
  123 + title: '开票金额',
  124 + valueType: 'money',
  125 + dataIndex: 'price',
  126 + hideInSearch: true,
  127 + ellipsis: true,
  128 + },
  129 + {
  130 + title: '开具类型',
  131 + valueType: 'Text',
  132 + dataIndex: 'invoicingTypeText',
  133 + hideInSearch: true,
  134 + ellipsis: true,
  135 + },
  136 + {
  137 + title: '发票类型',
  138 + valueType: 'Text',
  139 + dataIndex: 'typeText',
  140 + hideInSearch: true,
  141 + ellipsis: true,
  142 + },
  143 + {
  144 + title: '是否加急',
  145 + valueType: 'Text',
  146 + dataIndex: 'isUrgentText',
  147 + hideInSearch: true,
  148 + ellipsis: true,
  149 + },
  150 + {
  151 + title: '申请备注',
  152 + valueType: 'text',
  153 + dataIndex: 'applyInvoicingNotes',
  154 + hideInSearch: true,
  155 + ellipsis: true,
  156 + },
  157 + {
  158 + title: '购方名称',
  159 + valueType: 'Text',
  160 + dataIndex: 'partyANameLike',
  161 + hideInTable: true,
  162 + },
  163 + {
  164 + title: '收款单位',
  165 + valueType: 'select',
  166 + dataIndex: 'partyB',
  167 + filters: true,
  168 + onFilter: true,
  169 + hideInTable: true,
  170 + valueEnum: enumToProTableEnumValue(PAYEE_OPTIONS),
  171 + },
  172 + {
  173 + title: '主订单号',
  174 + valueType: 'Text',
  175 + dataIndex: 'mainOrderId',
  176 + hideInTable: true,
  177 + },
  178 + {
  179 + title: '子订单号',
  180 + valueType: 'Text',
  181 + dataIndex: 'subOrderId',
  182 + hideInTable: true,
  183 + },
  184 + {
  185 + title: '销售代表',
  186 + valueType: 'select',
  187 + dataIndex: 'salesCode',
  188 + filters: true,
  189 + onFilter: true,
  190 + hideInTable: true,
  191 + valueEnum: salesCodeValueEnum,
  192 + },
  193 + {
  194 + title: '发票类型',
  195 + valueType: 'select',
  196 + dataIndex: 'type',
  197 + filters: true,
  198 + onFilter: true,
  199 + hideInTable: true,
  200 + valueEnum: enumToProTableEnumValue(invoiceTypeValueEnum),
  201 + },
  202 + {
  203 + title: '开具类型',
  204 + valueType: 'select',
  205 + dataIndex: 'invoicingType',
  206 + filters: true,
  207 + onFilter: true,
  208 + hideInTable: true,
  209 + valueEnum: enumToProTableEnumValue(invoicingTypeValueEnum),
  210 + },
  211 + {
  212 + title: '开票状态',
  213 + valueType: 'select',
  214 + dataIndex: 'status',
  215 + filters: true,
  216 + onFilter: true,
  217 + hideInTable: true,
  218 + request: async () => {
  219 + const res = await postServiceConstBeforeInvoicingInvoiceRecordStatus();
  220 + return enumToSelect(res.data);
  221 + },
  222 + },
  223 + {
  224 + title: '是否加急',
  225 + valueType: 'select',
  226 + dataIndex: 'isUrgent',
  227 + filters: true,
  228 + onFilter: true,
  229 + hideInTable: true,
  230 + valueEnum: {
  231 + true: {
  232 + text: '是',
  233 + status: true,
  234 + },
  235 + false: {
  236 + text: '否',
  237 + status: false,
  238 + },
  239 + },
  240 + },
  241 + {
  242 + title: '申请开票时间',
  243 + dataIndex: 'createTime',
  244 + valueType: 'dateTimeRange',
  245 + width: 200,
  246 + hideInTable: true,
  247 + search: {
  248 + transform: (value) => {
  249 + if (value) {
  250 + return {
  251 + createTimeGe: value[0],
  252 + createTimeLe: value[1],
  253 + };
  254 + }
  255 + },
  256 + },
  257 + },
  258 + {
  259 + title: '操作',
  260 + valueType: 'option',
  261 + key: 'option',
  262 + render: (text, record) => {
  263 + return [
  264 + /*<InvoiceRecordDetailModal
  265 + key="detail"
  266 + id={record.id}
  267 + subOrderIds={record.subOrderIds}
  268 + onClose={()=>{
  269 + waitDealrecordActionRef.current?.reload();
  270 + }
  271 + }
  272 + />*/
  273 + <>
  274 + {record.paths.includes('DETAIL') && (
  275 + <a
  276 + key="detail"
  277 + onClick={() => {
  278 + setInvoiceRecordDetailVisible(true);
  279 + setInvoiceRecord(record);
  280 + }}
  281 + >
  282 + 详情
  283 + </a>
  284 + )}
  285 + </>,
  286 + <>
  287 + {record.paths.includes('PREVIEW') && (
  288 + <InvoiceModal key="invoiceModal" recordId={record.id} />
  289 + )}
  290 + </>,
  291 + <>
  292 + {record.paths.includes('INVOICING') && (
  293 + <ManualInvoicingModal
  294 + key={'ManualInvoicingModal'}
  295 + record={record}
  296 + ></ManualInvoicingModal>
  297 + )}
  298 + </>,
  299 + ];
  300 + },
  301 + },
  302 + ];
  303 + return (
  304 + <div className="invoice-index">
  305 + <ProTable
  306 + columns={waitDealRecordColumns}
  307 + actionRef={waitDealrecordActionRef}
  308 + cardBordered
  309 + pagination={{
  310 + showSizeChanger: true, // 显示可以选择每页显示条数的下拉菜单
  311 + pageSizeOptions: ['10', '20', '50', '100'], // 设置可以选择的每页显示条数选项
  312 + }}
  313 + rowSelection={{
  314 + selections: [Table.SELECTION_ALL, Table.SELECTION_INVERT],
  315 + alwaysShowAlert: true,
  316 + }}
  317 + tableAlertOptionRender={({ selectedRowKeys, selectedRows }) => {
  318 + console.log(selectedRows);
  319 + console.log(selectedRowKeys);
  320 + return (
  321 + <Space size={16}>
  322 + <InvoicingModal
  323 + reloadRecordTable={reloadRecordTable}
  324 + key="button"
  325 + selectedRowKeys={selectedRowKeys}
  326 + />
  327 + </Space>
  328 + );
  329 + }}
  330 + request={async (params) => {
  331 + let res = await postServiceInvoiceQueryInvoiceRecordList({
  332 + data: {
  333 + ...params,
  334 + statusIn: [
  335 + 'WAITING_FOR_INVOICING',
  336 + 'AUDITING',
  337 + 'AUDITING_NOT_PASSED',
  338 + 'CANCELED',
  339 + ],
  340 + needBuildDetails: true,
  341 + needBuildSubOrders: true,
  342 + },
  343 + });
  344 + return {
  345 + data: res?.data?.data,
  346 + total: res?.data?.total || 0,
  347 + };
  348 + }}
  349 + columnsState={{
  350 + persistenceKey: 'pro-table-singe-demos',
  351 + persistenceType: 'localStorage',
  352 + defaultValue: {
  353 + option: { fixed: 'right', disable: true },
  354 + },
  355 + onChange(value) {
  356 + console.log('value: ', value);
  357 + },
  358 + }}
  359 + rowKey="id"
  360 + search={{
  361 + labelWidth: 'auto',
  362 + }}
  363 + options={{
  364 + setting: {
  365 + listsHeight: 400,
  366 + },
  367 + }}
  368 + form={{}}
  369 + dateFormatter="string"
  370 + headerTitle="待开票列表"
  371 + scroll={{ x: 1400, y: 360 }}
  372 + />
  373 + {invoiceRecordDetailVisible ? (
  374 + <InvoiceRecordDetailModal
  375 + key="detail"
  376 + id={invoiceRecord.id}
  377 + setVisible={setInvoiceRecordDetailVisible}
  378 + />
  379 + ) : (
  380 + ''
  381 + )}
  382 + {contextHolder}
  383 + </div>
  384 + );
  385 +};
  386 +
  387 +export default InvoiceRecord;
... ...
src/pages/Order/components/InvoicingDrawerForm.tsx
1 1 // import { PlusOutlined } from '@ant-design/icons';
2   -import InvoiceModal from '@/pages/Invoice/components/InvoiceModal';
  2 +import InvoiceModal from '@/pages/Invoice/InvoiceVerification/components/InvoiceModal';
3 3 import {
4 4 postServiceConstGetPayeeEnum,
5 5 postServiceConstInitInvoiceDetailNames,
... ... @@ -8,8 +8,9 @@ import {
8 8 postServiceConstListInvoiceDetailNames,
9 9 postServiceInvoiceApplyInvoice,
10 10 postServiceInvoiceQueryCompanyInfo,
  11 + postServiceInvoiceWaitReissueInvoices,
11 12 } from '@/services';
12   -import { enumToSelect } from '@/utils';
  13 +import { enum2ReverseSelect, enumToSelect } from '@/utils';
13 14 import { convertCurrency } from '@/utils/numberUtil';
14 15 import {
15 16 DrawerForm,
... ... @@ -117,10 +118,39 @@ export default ({ dataList, setVisible, onClose }) =&gt; {
117 118 .reduce((accumulator, currentValue) => {
118 119 return accumulator + currentValue.totalPrice;
119 120 }, 0);
  121 + const partyBName = form.getFieldValue('partyBName');
  122 + const openBank = form.getFieldValue('openBank');
  123 + const bankAccount = form.getFieldValue('bankAccount');
  124 + const bankCode = form.getFieldValue('bankCode');
  125 + console.log(
  126 + '开户名称: ' +
  127 + partyBName +
  128 + '\n' +
  129 + '开户行: ' +
  130 + openBank +
  131 + '\n' +
  132 + '账号: ' +
  133 + bankAccount +
  134 + '\n' +
  135 + '银行联行号: ' +
  136 + bankCode,
  137 + );
120 138 return {
121 139 ...form.getFieldsValue(),
122 140 totalPrice: totalPrice,
123 141 totalPriceText: convertCurrency(totalPrice),
  142 + comment:
  143 + '开户名称: ' +
  144 + partyBName +
  145 + '\n' +
  146 + '开户行: ' +
  147 + openBank +
  148 + '\n' +
  149 + '账号: ' +
  150 + bankAccount +
  151 + '\n' +
  152 + '银行联行号: ' +
  153 + bankCode,
124 154 };
125 155 }}
126 156 />,
... ... @@ -154,12 +184,31 @@ export default ({ dataList, setVisible, onClose }) =&gt; {
154 184 };
155 185 })}
156 186 deleteIconProps={false}
  187 + copyIconProps={false}
157 188 >
158 189 <ProFormGroup key="group">
159 190 <ProFormText readonly={true} name="value" label="" />
160 191 </ProFormGroup>
161 192 </ProFormList>
162 193 <ProFormSelect
  194 + name="ReissueInvoiceRecordIds"
  195 + label="重开的发票"
  196 + fieldProps={{
  197 + mode: 'multiple',
  198 + }}
  199 + placeholder="请选择重开发票"
  200 + request={async () => {
  201 + let reissueIds = dataListCopy.map((item) => {
  202 + return item.id;
  203 + });
  204 + let res = await postServiceInvoiceWaitReissueInvoices({
  205 + data: reissueIds,
  206 + });
  207 + console.log(res.data);
  208 + return enum2ReverseSelect(res.data);
  209 + }}
  210 + />
  211 + <ProFormSelect
163 212 key="key"
164 213 label="购方名称"
165 214 width="lg"
... ... @@ -284,6 +333,9 @@ export default ({ dataList, setVisible, onClose }) =&gt; {
284 333 form.setFieldsValue({
285 334 partyBName: option.payeeName,
286 335 partyBTaxid: option.taxId,
  336 + bankAccount: option.bankAccount,
  337 + openBank: option.openBank,
  338 + bankCode: option.bankCode,
287 339 });
288 340 }
289 341 }}
... ... @@ -302,6 +354,24 @@ export default ({ dataList, setVisible, onClose }) =&gt; {
302 354 hidden
303 355 rules={[{ required: true, message: '请选择收款单位!' }]}
304 356 />
  357 + <ProFormText
  358 + name="bankAccount"
  359 + label="账号"
  360 + hidden
  361 + rules={[{ required: true, message: '请选择账号!' }]}
  362 + />
  363 + <ProFormText
  364 + name="openBank"
  365 + label="开户行"
  366 + hidden
  367 + rules={[{ required: true, message: '请选择开户行!' }]}
  368 + />
  369 + <ProFormText
  370 + name="bankCode"
  371 + label="银行联行号"
  372 + hidden
  373 + rules={[{ required: true, message: '请选择银行联行号!' }]}
  374 + />
305 375 <ProFormSelect
306 376 name="isUrgent"
307 377 label="是否加急"
... ...
src/services/definition.ts
... ... @@ -701,10 +701,6 @@ export interface ApiQueryOrderStatusCountsRequest {
701 701 }
702 702  
703 703 export interface ApplyInvoiceDTO {
704   - /**
705   - * @description
706   - * 备注
707   - */
708 704 applyInvoicingNotes?: string;
709 705 /**
710 706 * @description
... ... @@ -867,6 +863,7 @@ export interface ApplyInvoiceDTO {
867 863 * 接收邮箱地址
868 864 */
869 865 receiveEmail?: string;
  866 + reissueInvoiceRecordIds?: Array<number>;
870 867 /**
871 868 * @description
872 869 * 订单来源
... ... @@ -1603,6 +1600,7 @@ export interface InvoiceRecordDTO {
1603 1600 * 接收邮箱地址
1604 1601 */
1605 1602 receiveEmail?: string;
  1603 + reissueInvoiceRecordIds?: Array<number>;
1606 1604 /**
1607 1605 * @description
1608 1606 * 订单来源
... ...
src/services/request.ts
... ... @@ -63,6 +63,7 @@ import type {
63 63 MaterialUnitListRes,
64 64 MeasureUnitListRes,
65 65 MessageQueryDTO,
  66 + ModelAndView,
66 67 OrderAddVO,
67 68 OrderAuditLogQueryVO,
68 69 OrderBaseInfoQueryVO,
... ... @@ -3225,9 +3226,7 @@ export interface GetErrorResponse {
3225 3226 * @description
3226 3227 * OK
3227 3228 */
3228   - 200: {
3229   - [propertyName: string]: any;
3230   - };
  3229 + 200: ModelAndView;
3231 3230 /**
3232 3231 * @description
3233 3232 * Unauthorized
... ... @@ -3248,9 +3247,9 @@ export interface GetErrorResponse {
3248 3247 export type GetErrorResponseSuccess = GetErrorResponse[200];
3249 3248 /**
3250 3249 * @description
3251   - * error
  3250 + * errorHtml
3252 3251 * @tags basic-error-controller
3253   - * @produces *
  3252 + * @produces text/html
3254 3253 */
3255 3254 export const getError = /* #__PURE__ */ (() => {
3256 3255 const method = 'get';
... ... @@ -3274,9 +3273,7 @@ export interface PutErrorResponse {
3274 3273 * @description
3275 3274 * OK
3276 3275 */
3277   - 200: {
3278   - [propertyName: string]: any;
3279   - };
  3276 + 200: ModelAndView;
3280 3277 /**
3281 3278 * @description
3282 3279 * Created
... ... @@ -3302,9 +3299,9 @@ export interface PutErrorResponse {
3302 3299 export type PutErrorResponseSuccess = PutErrorResponse[200];
3303 3300 /**
3304 3301 * @description
3305   - * error
  3302 + * errorHtml
3306 3303 * @tags basic-error-controller
3307   - * @produces *
  3304 + * @produces text/html
3308 3305 * @consumes application/json
3309 3306 */
3310 3307 export const putError = /* #__PURE__ */ (() => {
... ... @@ -3329,9 +3326,7 @@ export interface PostErrorResponse {
3329 3326 * @description
3330 3327 * OK
3331 3328 */
3332   - 200: {
3333   - [propertyName: string]: any;
3334   - };
  3329 + 200: ModelAndView;
3335 3330 /**
3336 3331 * @description
3337 3332 * Created
... ... @@ -3357,9 +3352,9 @@ export interface PostErrorResponse {
3357 3352 export type PostErrorResponseSuccess = PostErrorResponse[200];
3358 3353 /**
3359 3354 * @description
3360   - * error
  3355 + * errorHtml
3361 3356 * @tags basic-error-controller
3362   - * @produces *
  3357 + * @produces text/html
3363 3358 * @consumes application/json
3364 3359 */
3365 3360 export const postError = /* #__PURE__ */ (() => {
... ... @@ -3384,9 +3379,7 @@ export interface DeleteErrorResponse {
3384 3379 * @description
3385 3380 * OK
3386 3381 */
3387   - 200: {
3388   - [propertyName: string]: any;
3389   - };
  3382 + 200: ModelAndView;
3390 3383 /**
3391 3384 * @description
3392 3385 * No Content
... ... @@ -3407,9 +3400,9 @@ export interface DeleteErrorResponse {
3407 3400 export type DeleteErrorResponseSuccess = DeleteErrorResponse[200];
3408 3401 /**
3409 3402 * @description
3410   - * error
  3403 + * errorHtml
3411 3404 * @tags basic-error-controller
3412   - * @produces *
  3405 + * @produces text/html
3413 3406 */
3414 3407 export const deleteError = /* #__PURE__ */ (() => {
3415 3408 const method = 'delete';
... ... @@ -3433,9 +3426,7 @@ export interface OptionsErrorResponse {
3433 3426 * @description
3434 3427 * OK
3435 3428 */
3436   - 200: {
3437   - [propertyName: string]: any;
3438   - };
  3429 + 200: ModelAndView;
3439 3430 /**
3440 3431 * @description
3441 3432 * No Content
... ... @@ -3456,9 +3447,9 @@ export interface OptionsErrorResponse {
3456 3447 export type OptionsErrorResponseSuccess = OptionsErrorResponse[200];
3457 3448 /**
3458 3449 * @description
3459   - * error
  3450 + * errorHtml
3460 3451 * @tags basic-error-controller
3461   - * @produces *
  3452 + * @produces text/html
3462 3453 * @consumes application/json
3463 3454 */
3464 3455 export const optionsError = /* #__PURE__ */ (() => {
... ... @@ -3483,9 +3474,7 @@ export interface HeadErrorResponse {
3483 3474 * @description
3484 3475 * OK
3485 3476 */
3486   - 200: {
3487   - [propertyName: string]: any;
3488   - };
  3477 + 200: ModelAndView;
3489 3478 /**
3490 3479 * @description
3491 3480 * No Content
... ... @@ -3506,9 +3495,9 @@ export interface HeadErrorResponse {
3506 3495 export type HeadErrorResponseSuccess = HeadErrorResponse[200];
3507 3496 /**
3508 3497 * @description
3509   - * error
  3498 + * errorHtml
3510 3499 * @tags basic-error-controller
3511   - * @produces *
  3500 + * @produces text/html
3512 3501 * @consumes application/json
3513 3502 */
3514 3503 export const headError = /* #__PURE__ */ (() => {
... ... @@ -3533,9 +3522,7 @@ export interface PatchErrorResponse {
3533 3522 * @description
3534 3523 * OK
3535 3524 */
3536   - 200: {
3537   - [propertyName: string]: any;
3538   - };
  3525 + 200: ModelAndView;
3539 3526 /**
3540 3527 * @description
3541 3528 * No Content
... ... @@ -3556,9 +3543,9 @@ export interface PatchErrorResponse {
3556 3543 export type PatchErrorResponseSuccess = PatchErrorResponse[200];
3557 3544 /**
3558 3545 * @description
3559   - * error
  3546 + * errorHtml
3560 3547 * @tags basic-error-controller
3561   - * @produces *
  3548 + * @produces text/html
3562 3549 * @consumes application/json
3563 3550 */
3564 3551 export const patchError = /* #__PURE__ */ (() => {
... ... @@ -14458,6 +14445,77 @@ export const postServiceInvoiceUrgentInvoicing = /* #__PURE__ */ (() =&gt; {
14458 14445 return request;
14459 14446 })();
14460 14447  
  14448 +/** @description request parameter type for postServiceInvoiceWaitReissueInvoices */
  14449 +export interface PostServiceInvoiceWaitReissueInvoicesOption {
  14450 + /**
  14451 + * @description
  14452 + * ids
  14453 + */
  14454 + body: {
  14455 + /**
  14456 + @description
  14457 + ids */
  14458 + ids: Array<number>;
  14459 + };
  14460 +}
  14461 +
  14462 +/** @description response type for postServiceInvoiceWaitReissueInvoices */
  14463 +export interface PostServiceInvoiceWaitReissueInvoicesResponse {
  14464 + /**
  14465 + * @description
  14466 + * OK
  14467 + */
  14468 + 200: ServerResult;
  14469 + /**
  14470 + * @description
  14471 + * Created
  14472 + */
  14473 + 201: any;
  14474 + /**
  14475 + * @description
  14476 + * Unauthorized
  14477 + */
  14478 + 401: any;
  14479 + /**
  14480 + * @description
  14481 + * Forbidden
  14482 + */
  14483 + 403: any;
  14484 + /**
  14485 + * @description
  14486 + * Not Found
  14487 + */
  14488 + 404: any;
  14489 +}
  14490 +
  14491 +export type PostServiceInvoiceWaitReissueInvoicesResponseSuccess =
  14492 + PostServiceInvoiceWaitReissueInvoicesResponse[200];
  14493 +/**
  14494 + * @description
  14495 + * 获取待重新开票的开票记录
  14496 + * @tags 发票
  14497 + * @produces *
  14498 + * @consumes application/json
  14499 + */
  14500 +export const postServiceInvoiceWaitReissueInvoices = /* #__PURE__ */ (() => {
  14501 + const method = 'post';
  14502 + const url = '/service/invoice/waitReissueInvoices';
  14503 + function request(
  14504 + option: PostServiceInvoiceWaitReissueInvoicesOption,
  14505 + ): Promise<PostServiceInvoiceWaitReissueInvoicesResponseSuccess> {
  14506 + return requester(request.url, {
  14507 + method: request.method,
  14508 + ...option,
  14509 + }) as unknown as Promise<PostServiceInvoiceWaitReissueInvoicesResponseSuccess>;
  14510 + }
  14511 +
  14512 + /** http method */
  14513 + request.method = method;
  14514 + /** request url */
  14515 + request.url = url;
  14516 + return request;
  14517 +})();
  14518 +
14461 14519 /** @description request parameter type for postServiceOrderAddOrder */
14462 14520 export interface PostServiceOrderAddOrderOption {
14463 14521 /**
... ...
src/utils/index.ts
... ... @@ -8,6 +8,13 @@ function enumToSelect(data: any) {
8 8 });
9 9 }
10 10  
  11 +export function enum2ReverseSelect(data: any) {
  12 + const keys = Object.keys(data);
  13 + return keys.map((value) => {
  14 + return { label: data[value], value: value };
  15 + });
  16 +}
  17 +
11 18 //将枚举的value值转换为label
12 19 function enumValueToLabel(value: any, enumObj: any) {
13 20 console.log(value, enumObj);
... ...