diff --git a/src/pages/Invoice/Invoice/components/InvoiceDetailImportModal.tsx b/src/pages/Invoice/Invoice/components/InvoiceDetailImportModal.tsx deleted file mode 100644 index 63b7882..0000000 --- a/src/pages/Invoice/Invoice/components/InvoiceDetailImportModal.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { RESPONSE_CODE } from '@/constants/enum'; -import { postServiceInvoiceImportInvoiceDetails } from '@/services'; -import { ModalForm, ProFormUploadDragger } from '@ant-design/pro-components'; -import { Button, Form, message } from 'antd'; - -export default ({ recordId }) => { - const [form] = Form.useForm(); - return ( - <ModalForm - title="新建表单" - trigger={<Button type="primary">导入明细</Button>} - form={form} - autoFocusFirstInput - modalProps={{ - destroyOnClose: true, - onCancel: () => console.log('run'), - }} - submitTimeout={2000} - onFinish={async (values) => { - const formData = new FormData(); - // console.log(fileList[0] as RcFile) - // formData.append('file', fileList[0] as RcFile); - formData.append('invoiceRecordId', recordId); - formData.append('detailsExcel', values.detailsExcel[0].originFileObj); - // You can use any AJAX library you like - const res = await postServiceInvoiceImportInvoiceDetails({ - data: formData, - headers: { - 'Content-Type': - 'multipart/form-data; boundary=----WebKitFormBoundarynl6gT1BKdPWIejNq', - }, - }); - if (res.result === RESPONSE_CODE.SUCCESS) { - message.success('导入成功'); - return true; - } - }} - > - <ProFormUploadDragger name="detailsExcel" label="导入明细表" /> - </ModalForm> - ); -}; diff --git a/src/pages/Invoice/Invoice/components/InvoiceDetailTable.tsx b/src/pages/Invoice/Invoice/components/InvoiceDetailTable.tsx deleted file mode 100644 index eac41ba..0000000 --- a/src/pages/Invoice/Invoice/components/InvoiceDetailTable.tsx +++ /dev/null @@ -1,153 +0,0 @@ -import InvoiceDetailImportModal from '@/pages/Invoice/Invoice/components/InvoiceDetailImportModal'; -import { InvoiceProjectSelect } from '@/pages/Invoice/Invoice/components/InvoiceProjectSelect'; -import { - ActionType, - EditableProTable, - ProCard, - ProColumns, - ProFormField, -} from '@ant-design/pro-components'; -import { useEffect, useRef, useState } from 'react'; - -export default ({ recordId, details, updateDetails, readOnly }) => { - const [editableKeys, setEditableRowKeys] = useState([]); - const ref = useRef<ActionType>(); - useEffect(() => { - updateDetails(details); - }, []); - - useEffect(() => { - setEditableRowKeys(details?.map((item) => item.tid)); - }, [details]); - const columns: ProColumns[] = [ - { - title: '项目名称', - dataIndex: 'projectName', - width: 200, - ellipsis: true, - readonly: readOnly, - renderFormItem: () => { - return <InvoiceProjectSelect readOnly={readOnly} />; - }, - }, - { - title: '规格型号', - readonly: readOnly, - dataIndex: 'specification', - valueType: 'text', - ellipsis: true, - }, - { - title: '单位', - readonly: readOnly, - dataIndex: 'unit', - valueType: 'text', - ellipsis: true, - }, - { - title: '数量', - readonly: readOnly, - dataIndex: 'quantity', - valueType: 'digit', - ellipsis: true, - }, - { - title: '单价', - readonly: readOnly, - dataIndex: 'price', - valueType: 'digit', - ellipsis: true, - }, - { - title: '金额', - readonly: readOnly, - dataIndex: 'totalPrice', - valueType: 'digit', - ellipsis: true, - }, - { - title: '税率/征收率', - readonly: true, - dataIndex: 'taxRate', - valueType: () => ({ - type: 'percent', - }), - ellipsis: true, - }, - { - title: '税额', - readonly: true, - dataIndex: 'taxPrice', - valueType: 'digit', - ellipsis: true, - }, - { - title: '操作', - valueType: 'option', - width: 100, - render: () => { - return null; - }, - }, - ]; - - return ( - <> - <EditableProTable - columns={columns} - actionRef={ref} - rowKey="tid" - scroll={{ - x: 960, - }} - value={details} - controlled={true} - recordCreatorProps={ - readOnly - ? false - : { - newRecordType: 'dataSource', - record: () => ({ - tid: Date.now(), - }), - } - } - toolBarRender={() => { - return [ - <InvoiceDetailImportModal key={'import'} recordId={recordId} />, - ]; - }} - editable={{ - type: 'multiple', - editableKeys, - actionRender: (row, config, defaultDoms) => { - return [defaultDoms.delete]; - }, - - onValuesChange: (record, recordList) => { - //修改recordList中tid为record.tid的元素,将它的specification属性设置为invoiceProject的specification属性 - const records = recordList.map((item) => { - return item; - }); - updateDetails(records); - }, - }} - /> - { - <ProCard title="表格数据" headerBordered collapsible defaultCollapsed> - <ProFormField - ignoreFormItem - fieldProps={{ - style: { - width: '100%', - }, - }} - mode="read" - valueType="jsonCode" - text={JSON.stringify(details)} - /> - </ProCard> - } - </> - ); -}; diff --git a/src/pages/Invoice/Invoice/components/InvoiceProjectSelect.tsx b/src/pages/Invoice/Invoice/components/InvoiceProjectSelect.tsx deleted file mode 100644 index 779c9b7..0000000 --- a/src/pages/Invoice/Invoice/components/InvoiceProjectSelect.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { postServiceConstListInvoiceDetailNames } from '@/services'; -import { Select, Tooltip } from 'antd'; -import { useState } from 'react'; - -export const InvoiceProjectSelect = ({ readOnly, value, onChange }) => { - const [options, setOptions] = useState<any[]>([]); - // 定义防抖函数 - let timeoutId = null; - const fetchOptions = async (keywords) => { - clearTimeout(timeoutId); - timeoutId = setTimeout(async () => { - const res = await postServiceConstListInvoiceDetailNames({ - data: { - nameLike: keywords, - }, - }); - const data = res.data; - - setOptions( - data.map((item) => { - console.log(item); - return { - key: item.id, - label: - '*' + - item.productAndServiceCatagoryAbbreviation + - '*' + - item?.name, - value: - '*' + - item.productAndServiceCatagoryAbbreviation + - '*' + - item?.name, - ...item, - }; - }), - ); - // 这里可以放置实际的搜索逻辑,比如发起网络请求等 - }, 500); // 设置延迟时间,单位毫秒 - }; - - return readOnly ? ( - <Tooltip title={value}>{value}</Tooltip> - ) : ( - <Select - key="project" - /*readonly={readonly}*/ - showSearch - placeholder="请选择开票项目" - filterOption={(input, option) => (option?.label ?? '').includes(input)} - onChange={(e) => { - onChange(e); - }} - defaultValue={value} - options={options} - onSearch={(e) => { - fetchOptions(e); - }} - /> - ); -}; diff --git a/src/pages/Invoice/Invoice/components/invoiceWriteOffModal.tsx b/src/pages/Invoice/Invoice/components/invoiceWriteOffModal.tsx new file mode 100644 index 0000000..10ef4d2 --- /dev/null +++ b/src/pages/Invoice/Invoice/components/invoiceWriteOffModal.tsx @@ -0,0 +1,213 @@ +import { + EditableFormInstance, + EditableProTable, + ModalForm, + ProCard, + ProColumns, + ProForm, + ProFormDependency, + ProFormField, + ProFormInstance, + ProFormSwitch, +} from '@ant-design/pro-components'; +import { Button } from 'antd'; +import React, { useRef, useState } from 'react'; + +type DataSourceType = { + id: React.Key; + title?: string; + decs?: string; + state?: string; + created_at?: number; + update_at?: number; + children?: DataSourceType[]; +}; + +const defaultData: DataSourceType[] = [ + { + id: '624748504', + title: '活动名称一', + decs: '这个活动真好玩', + state: 'open', + created_at: 1590486176000, + update_at: 1590486176000, + }, + { + id: '624691229', + title: '活动名称二', + decs: '这个活动真好玩', + state: 'closed', + created_at: 1590481162000, + update_at: 1590481162000, + }, +]; + +let i = 0; + +export default () => { + const [editableKeys, setEditableRowKeys] = useState<React.Key[]>(() => []); + const [controlled, setControlled] = useState<boolean>(false); + const formRef = useRef<ProFormInstance<any>>(); + const editorFormRef = useRef<EditableFormInstance<DataSourceType>>(); + const columns: ProColumns<DataSourceType>[] = [ + { + title: '活动名称', + dataIndex: 'title', + formItemProps: () => { + return { + rules: [{ required: true, message: '此项为必填项' }], + }; + }, + }, + { + title: '状态', + key: 'state', + dataIndex: 'state', + valueType: 'select', + valueEnum: { + all: { text: '全部', status: 'Default' }, + open: { + text: '未解决', + status: 'Error', + }, + closed: { + text: '已解决', + status: 'Success', + }, + }, + }, + { + title: '描述', + dataIndex: 'decs', + }, + { + title: '活动时间', + dataIndex: 'created_at', + valueType: 'date', + }, + { + title: '操作', + valueType: 'option', + width: 200, + render: (text, record, _, action) => [ + <a + key="editable" + onClick={() => { + action?.startEditable?.(record.id, record); + }} + > + 编辑 + </a>, + <a + key="delete" + onClick={() => { + const tableDataSource = formRef.current?.getFieldValue( + 'table', + ) as DataSourceType[]; + formRef.current?.setFieldsValue({ + table: tableDataSource.filter((item) => item.id !== record.id), + }); + }} + > + 删除 + </a>, + ], + }, + ]; + + return ( + <ModalForm + formRef={formRef} + initialValues={{ + table: defaultData, + }} + trigger={<Button type="primary">核销</Button>} + validateTrigger="onBlur" + > + <EditableProTable<DataSourceType> + rowKey="id" + scroll={{ + x: 960, + }} + editableFormRef={editorFormRef} + headerTitle="可编辑表格" + maxLength={5} + name="table" + controlled={controlled} + recordCreatorProps={false} + toolBarRender={() => [ + <ProFormSwitch + key="render" + fieldProps={{ + style: { + marginBlockEnd: 0, + }, + checked: controlled, + onChange: (value) => { + setControlled(value); + }, + }} + checkedChildren="数据更新通知 Form" + unCheckedChildren="保存后通知 Form" + noStyle + />, + <Button + key="rows" + onClick={() => { + const rows = editorFormRef.current?.getRowsData?.(); + console.log(rows); + }} + > + 获取 table 的数据 + </Button>, + ]} + columns={columns} + editable={{ + type: 'multiple', + editableKeys, + onChange: setEditableRowKeys, + actionRender: (row, config, defaultDom) => { + return [ + defaultDom.save, + defaultDom.delete, + defaultDom.cancel, + <a + key="set" + onClick={() => { + console.log(config.index); + i++; + editorFormRef.current?.setRowData?.(config.index!, { + title: '动态设置的title' + i, + }); + }} + > + 动态设置此项 + </a>, + ]; + }, + }} + /> + <ProForm.Item> + <ProCard title="表格数据" headerBordered collapsible defaultCollapsed> + <ProFormDependency name={['table']}> + {({ table }) => { + return ( + <ProFormField + ignoreFormItem + fieldProps={{ + style: { + width: '100%', + }, + }} + mode="read" + valueType="jsonCode" + text={JSON.stringify(table)} + /> + ); + }} + </ProFormDependency> + </ProCard> + </ProForm.Item> + </ModalForm> + ); +}; diff --git a/src/pages/Invoice/Invoice/index.tsx b/src/pages/Invoice/Invoice/index.tsx index c5bd828..7b9572a 100644 --- a/src/pages/Invoice/Invoice/index.tsx +++ b/src/pages/Invoice/Invoice/index.tsx @@ -3,6 +3,7 @@ import EllipsisDiv from '@/components/Div/EllipsisDiv'; import AddInvoiceDrawerForm from '@/pages/Invoice/Invoice/components/AddInvoiceDrawerForm'; import BankImportModal from '@/pages/Invoice/Invoice/components/BankImportModal'; import InvoiceVerificationModal from '@/pages/Invoice/Invoice/components/InvoiceVerificationModal'; +import InvoiceWriteOffModal from '@/pages/Invoice/Invoice/components/invoiceWriteOffModal'; import { INVOICE_COLUMNS } from '@/pages/Invoice/constant'; import { INVOCING_STATUS, PAYEE_OPTIONS } from '@/pages/Order/constant'; import { @@ -206,6 +207,7 @@ const InvoiceRecord = () => { }} key="add" ></AddInvoiceDrawerForm>, + <InvoiceWriteOffModal key="writeOff" />, ]} /> diff --git a/src/pages/Invoice/InvoiceVerification/components/AddInvoiceDrawerForm.tsx b/src/pages/Invoice/InvoiceVerification/components/AddInvoiceDrawerForm.tsx deleted file mode 100644 index 329ee31..0000000 --- a/src/pages/Invoice/InvoiceVerification/components/AddInvoiceDrawerForm.tsx +++ /dev/null @@ -1,199 +0,0 @@ -import { RESPONSE_CODE } from '@/constants/enum'; -import { PAYEE_OPTIONS } from '@/pages/Order/constant'; -import { - postServiceInvoiceAddInvoice, - postServiceOrderQuerySalesCode, -} from '@/services'; -import { enumToSelect } from '@/utils'; -import { PlusOutlined } from '@ant-design/icons'; -import { - DrawerForm, - ProFormDateTimePicker, - ProFormGroup, - ProFormList, - ProFormMoney, - ProFormSelect, - ProFormText, - ProFormTextArea, -} from '@ant-design/pro-components'; -import { Button, Form, message } from 'antd'; -import { useEffect, useState } from 'react'; - -export default ({ onClose }) => { - const [form] = Form.useForm<{ - invoiceNumber: ''; - invoiceStatus: ''; - purchaser: ''; - payee: ''; - contacts: ''; - sale: ''; - invoicingTime: ''; - notes: ''; - mainOrderIdObjs: [ - { - mainOrderId: ''; - }, - ]; - money: ''; - }>(); - const [salesCodeOptions, setSalesCodeOptions] = useState([]); - const getSalesCodeOptions = async () => { - const res = await postServiceOrderQuerySalesCode(); - let options = res.data?.map((item) => { - return { - label: item.userName, - value: item.userName, - number: item.number, - }; - }); - setSalesCodeOptions(options); - }; - useEffect(() => { - getSalesCodeOptions(); - }, []); - return ( - <DrawerForm<{ - invoiceNumber: string; - invoiceStatus: string; - purchaser: string; - payee: string; - contacts: string; - sale: string; - invoicingTime: Date; - notes: string; - mainOrderIdObjs: [ - { - mainOrderId: string; - }, - ]; - money: string; - }> - title="新增开票" - resize={{ - onResize() { - console.log('resize!'); - }, - maxWidth: window.innerWidth * 0.8, - minWidth: 500, - }} - form={form} - trigger={ - <Button type="primary"> - <PlusOutlined /> - 新增 - </Button> - } - autoFocusFirstInput - drawerProps={{ - destroyOnClose: true, - }} - submitTimeout={2000} - onFinish={async (values) => { - console.log(values); - const mainOrderIds = values.mainOrderIdObjs.flatMap( - (item) => item.mainOrderId, - ); - let attrs = { ...values, mainOrderIds }; - let res = await postServiceInvoiceAddInvoice({ - data: { ...attrs }, - }); - if (res.result === RESPONSE_CODE.SUCCESS) { - message.success(res.message); - } else { - message.error(res.message); - return false; - } - onClose(); - // 不返回不会关闭弹框 - return true; - }} - > - <ProFormText - name="invoiceNumber" - width="md" - label="发票号码" - placeholder="请输入名称" - rules={[{ required: true, message: '请输入名称!' }]} - /> - <ProFormSelect - name="invoiceStatus" - label="发票类型" - valueEnum={{ - SPECIALLY_INVOICED: '专票', - COMMON_INVOICED: '普票', - }} - rules={[{ required: true, message: '请选择发票类型!' }]} - /> - <ProFormText - name="purchaser" - width="md" - label="购买方" - placeholder="请输入购买方" - rules={[{ required: true, message: '请输入购买方!' }]} - /> - <ProFormSelect - placeholder="收款单位" - name="payee" - width="lg" - key="payee" - showSearch - label="开票收款单位" - tooltip="财务开票将依据这个字段,选择对应的公司开票" - options={enumToSelect(PAYEE_OPTIONS)} - /> - <ProFormText - name="contacts" - width="md" - label="联系人" - placeholder="请输入联系人" - rules={[{ required: true, message: '请输入联系人!' }]} - /> - <ProFormSelect - name="sale" - key="sale" - width="lg" - showSearch - label="销售代表" - placeholder="请选择销售代表" - options={salesCodeOptions} - /> - <ProFormDateTimePicker - name="invoicingTime" - label="开票时间" - fieldProps={{ - format: (value) => value.format('YYYY-MM-DD'), - }} - rules={[{ required: true, message: '请输入开票时间!' }]} - /> - <ProFormTextArea name="notes" label="备注" placeholder="请输入名称" /> - <ProFormList - name="mainOrderIdObjs" - label="订单号" - min={1} - copyIconProps={false} - deleteIconProps={{ - tooltipText: '删除', - }} - initialValue={[ - { - mainOrderId: '', - }, - ]} - > - <ProFormGroup key="group"> - <ProFormText - rules={[{ required: true, message: '请输入关联订单!' }]} - name="mainOrderId" - /> - </ProFormGroup> - </ProFormList> - <ProFormMoney - label="金额" - name="money" - customSymbol="¥" - min={0} - rules={[{ required: true, message: '请输入金额!' }]} - /> - </DrawerForm> - ); -}; diff --git a/src/pages/Invoice/InvoiceVerification/components/InvoicingModal.tsx b/src/pages/Invoice/InvoiceVerification/components/InvoicingModal.tsx deleted file mode 100644 index 0f9b320..0000000 --- a/src/pages/Invoice/InvoiceVerification/components/InvoicingModal.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { RESPONSE_CODE } from '@/constants/enum'; -import { postServiceInvoiceInvoicing } from '@/services'; -import { ModalForm } from '@ant-design/pro-components'; -import { Button, Form, message } from 'antd'; - -export default ({ selectedRowKeys, reloadRecordTable }) => { - const [form] = Form.useForm<{ name: string; company: string }>(); - return ( - <ModalForm<{ - name: string; - company: string; - }> - title="开票" - trigger={ - <Button type="primary" disabled={selectedRowKeys?.length === 0}> - 开票 - </Button> - } - form={form} - autoFocusFirstInput - modalProps={{ - destroyOnClose: true, - onCancel: () => console.log('run'), - }} - submitTimeout={2000} - onFinish={async (values) => { - let res = await postServiceInvoiceInvoicing({ - data: { - ...values, - invoiceRecordIds: selectedRowKeys, - }, - }); - if (res.result === RESPONSE_CODE.SUCCESS) { - message.success(res.message); - } - reloadRecordTable(); - message.success('提交成功'); - return true; - }} - > - {/*<ProFormSelect - name="invoicingAccount" - label="开票账号" - request={async () => { - const res = await postServiceInvoiceGetInvoicingAccount(); - return res.data.map((item) => { - return { - label: item.accountText, - value: item.account, - }; - }); - }} - placeholder="请选择开票账号" - rules={[{ required: true, message: '请选择开票账号!' }]} - />*/} - </ModalForm> - ); -}; diff --git a/src/pages/Invoice/InvoiceVerification/components/ManualInvoicingModal.tsx b/src/pages/Invoice/InvoiceVerification/components/ManualInvoicingModal.tsx deleted file mode 100644 index 3d2c3e0..0000000 --- a/src/pages/Invoice/InvoiceVerification/components/ManualInvoicingModal.tsx +++ /dev/null @@ -1,130 +0,0 @@ -import { RESPONSE_CODE } from '@/constants/enum'; -import UploadC from '@/pages/Invoice/InvoiceVerification/components/UploadSingleImg'; -import { - postOrderErpOrderStagesUpload, - postServiceInvoiceDealInvoicingResult, -} from '@/services'; -import { - ModalForm, - ProFormDatePicker, - ProFormText, -} from '@ant-design/pro-components'; -import { Col, Form, Row, message } from 'antd'; -import { RcFile } from 'antd/es/upload'; -import { useEffect } from 'react'; - -export default ({ record }) => { - useEffect(() => { - console.log('invoicing'); - }, []); - const [form] = Form.useForm(); - return ( - <ModalForm - title="手动开票" - trigger={<a type="primary">手动开票</a>} - width={600} - layout={'horizontal'} - form={form} - autoFocusFirstInput - modalProps={{ - destroyOnClose: true, - onCancel: () => console.log('run'), - }} - submitTimeout={2000} - onFinish={async (values) => { - const res = await postServiceInvoiceDealInvoicingResult({ - data: { - ...values, - isSuccess: true, - invoiceRecordId: record.id, - manual: true, - }, - }); - if (res.result === RESPONSE_CODE.SUCCESS) { - message.success('开票成功'); - return true; - } else { - message.error('开票失败'); - } - }} - > - {/*<ProFormText - rules={[{ required: true, message: '此项为必填项' }]} - width={'md'} - name="invoicingPerson" - label="开票人" - />*/} - <ProFormText - rules={[{ required: true, message: '此项为必填项' }]} - width={'md'} - name="invoiceNumber" - label="发票号码" - /> - <ProFormDatePicker - rules={[{ required: true, message: '此项为必填项' }]} - fieldProps={{ - format: 'YYYY-MM-DD', - }} - name="invoicingDate" - label="开票日期" - /> - <ProFormText - rules={[{ required: true, message: '发票必须上传' }]} - hidden - name="url" - label="發票地址" - /> - <Row> - <Col span={4}>上传发票</Col> - <Col span={20}> - <UploadC - onFilesChange={async (newFileList) => { - if (newFileList.length > 0) { - const formData = new FormData(); - formData.append('file', newFileList[0].originFileObj as RcFile); - const res = await postOrderErpOrderStagesUpload({ - data: formData, - headers: { - 'Content-Type': - 'multipart/form-data; boundary=----WebKitFormBoundarynl6gT1BKdPWIejNq', - }, - }); - const url = res.data; - form.setFieldValue('url', url); - } else { - form.setFieldValue('url', null); - } - }} - ></UploadC> - </Col> - </Row> - {/*<ProFormList - name="invoiceDetailDtoList" - label="明细" - creatorButtonProps={false} - copyIconProps={false} - itemRender={({ listDom }, { index }) => ( - <ProCard - bordered - style={{ marginBlockEnd: 8 }} - title={`明细${index + 1}`} - bodyStyle={{ paddingBlockEnd: 0 }} - > - {listDom} - </ProCard> - )} - creatorRecord={{ name: '', items: [{ name: '' }] }} - initialValue={record.invoiceDetails} - > - <ProFormText - name="projectName" - label="名称" - placeholder="请输入名称" - readonly - /> - <ProFormDigit label="税率" name="taxRate" min={0} max={100} /> - <ProFormMoney label="税额" name="taxPrice" locale="zh-CN" min={0} /> - </ProFormList>*/} - </ModalForm> - ); -};