Commit 4fff2654574fbdf3dc9459b5e2ab6610736d98e5

Authored by 曾国涛
1 parent a1e377cf

feat(product): 采购管理添加产品选择功能

- 在采购管理页面添加产品选择下拉框
- 实现产品数据的异步加载和动态更新
- 优化采购单的创建和编辑功能,支持产品信息的自动填充
src/models/enum.ts
... ... @@ -3,6 +3,7 @@ import {
3 3 postServiceConstInvoiceReissueRecordStatus,
4 4 postServiceConstPayees,
5 5 postServiceConstProductCollectBillStatus,
  6 + postServiceConstProducts,
6 7 postServiceConstStores,
7 8 } from '@/services';
8 9 import { useCallback } from 'react';
... ... @@ -28,11 +29,16 @@ export default () => {
28 29 const result = await postServiceConstStores();
29 30 return result.data;
30 31 }, []);
  32 + const getProducts = useCallback(async () => {
  33 + const res = await postServiceConstProducts();
  34 + return res.data;
  35 + }, []);
31 36 return {
32 37 getPayees,
33 38 getInvoiceReissueRecordStatus,
34 39 getInvoiceFlushStatus,
35 40 getProductCollectBillAuditStatus,
36 41 getWarehouse,
  42 + getProducts,
37 43 };
38 44 };
... ...
src/pages/product/procure/components/AddOrUpdate.tsx 0 → 100644
  1 +import { postProcureBillAddOrModify } from '@/services';
  2 +import { useModel } from '@@/exports';
  3 +import {
  4 + EditableProTable,
  5 + ModalForm,
  6 + ProCard,
  7 + ProColumns,
  8 + ProForm,
  9 + ProFormDependency,
  10 + ProFormField,
  11 + ProFormSwitch,
  12 + ProFormTextArea,
  13 +} from '@ant-design/pro-components';
  14 +import { Button, Form, message } from 'antd';
  15 +import React, { useEffect, useRef, useState } from 'react';
  16 +
  17 +export default ({ record, onfinish }) => {
  18 + const [editableKeys, setEditableRowKeys] = useState<React.Key[]>([]);
  19 + const [controlled, setControlled] = useState<boolean>(false);
  20 + const [processedRecord, setProcessedRecord] = useState(record);
  21 + const formRef = useRef(null);
  22 + const editorFormRef = useRef(null);
  23 + const { getProducts } = useModel('enum');
  24 +
  25 + // 使用 useEffect 为 procureBillDetailList 中的每个元素添加 key
  26 + useEffect(() => {
  27 + if (record?.procureBillDetailList) {
  28 + const updatedProcureBillDetailList = record.procureBillDetailList.map(
  29 + (item) => ({
  30 + ...item,
  31 + key: item.key || `key-${Math.random().toString(36).substr(2, 9)}`, // 动态生成唯一 key
  32 + }),
  33 + );
  34 + setProcessedRecord({
  35 + ...record,
  36 + procureBillDetailList: updatedProcureBillDetailList,
  37 + });
  38 + }
  39 + }, [record]);
  40 +
  41 + const columns: ProColumns[] = [
  42 + {
  43 + title: '商品',
  44 + dataIndex: 'productId',
  45 + valueType: 'select',
  46 + request: async () => {
  47 + const res = await getProducts();
  48 + return res.map((item) => ({
  49 + ...item,
  50 + label: item.name,
  51 + value: item.id,
  52 + productUnitName: item.baseUnitName,
  53 + productUnitPrice: item.unitPrice,
  54 + }));
  55 + },
  56 + fieldProps: (_, { rowIndex }) => ({
  57 + onSelect: (value, option) => {
  58 + console.log('option111111' + JSON.stringify(option));
  59 + const currentTableData = editorFormRef.current?.getRowsData?.();
  60 + if (currentTableData) {
  61 + const updatedData = [...currentTableData];
  62 + updatedData[rowIndex] = {
  63 + ...updatedData[rowIndex],
  64 + productUnitName: option.productUnitName,
  65 + productUnitPrice: option.productUnitPrice,
  66 + };
  67 + formRef.current?.setFieldsValue({
  68 + procureBillDetailList: updatedData,
  69 + });
  70 + }
  71 + },
  72 + }),
  73 + },
  74 + {
  75 + title: '单位',
  76 + dataIndex: 'productUnitName',
  77 + valueType: 'text',
  78 + editable: false,
  79 + },
  80 + {
  81 + title: '单价',
  82 + dataIndex: 'productUnitPrice',
  83 + valueType: 'digit',
  84 + editable: false,
  85 + },
  86 + {
  87 + title: '数量',
  88 + dataIndex: 'number',
  89 + valueType: 'digit',
  90 + },
  91 + {
  92 + title: '备注',
  93 + dataIndex: 'created_at',
  94 + valueType: 'textarea',
  95 + },
  96 + {
  97 + title: '附件',
  98 + dataIndex: 'annex',
  99 + render: () => {},
  100 + renderFormItem: () => {},
  101 + },
  102 + {
  103 + title: '操作',
  104 + valueType: 'option',
  105 + render: (text, record, _, action) => [
  106 + <a
  107 + key="editable"
  108 + onClick={() => {
  109 + action?.startEditable?.(record.key);
  110 + }}
  111 + >
  112 + 编辑
  113 + </a>,
  114 + <a
  115 + key="delete"
  116 + onClick={() => {
  117 + const tableDataSource = formRef.current?.getFieldValue(
  118 + 'procureBillDetailList',
  119 + );
  120 + formRef.current?.setFieldsValue({
  121 + table: tableDataSource.filter((item) => item.key !== record.key),
  122 + });
  123 + }}
  124 + >
  125 + 删除
  126 + </a>,
  127 + ],
  128 + },
  129 + ];
  130 +
  131 + const [form] = Form.useForm();
  132 + return (
  133 + <ModalForm
  134 + formRef={formRef}
  135 + initialValues={processedRecord}
  136 + validateTrigger="onBlur"
  137 + title="新建表单"
  138 + trigger={
  139 + record?.id ? (
  140 + <Button type="link">修改</Button>
  141 + ) : (
  142 + <Button type="primary">新建</Button>
  143 + )
  144 + }
  145 + form={form}
  146 + autoFocusFirstInput
  147 + modalProps={{
  148 + destroyOnClose: true,
  149 + onCancel: () => console.log('run'),
  150 + }}
  151 + submitTimeout={2000}
  152 + onFinish={async (values) => {
  153 + const res = await postProcureBillAddOrModify({
  154 + data: {
  155 + ...record,
  156 + ...values,
  157 + },
  158 + });
  159 + if (res) {
  160 + message.success(res.message);
  161 + onfinish();
  162 + }
  163 + return true;
  164 + }}
  165 + >
  166 + <EditableProTable
  167 + rowKey="key"
  168 + scroll={{
  169 + x: 960,
  170 + }}
  171 + editableFormRef={editorFormRef}
  172 + headerTitle="可编辑表格"
  173 + maxLength={5}
  174 + name="procureBillDetailList"
  175 + controlled={controlled}
  176 + recordCreatorProps={{
  177 + position: 'bottom',
  178 + record: () => ({
  179 + key: `key-${Math.random().toString(36).substr(2, 9)}`,
  180 + }),
  181 + }}
  182 + toolBarRender={() => [
  183 + <ProFormSwitch
  184 + key="render"
  185 + fieldProps={{
  186 + style: {
  187 + marginBlockEnd: 0,
  188 + },
  189 + checked: controlled,
  190 + onChange: (value) => {
  191 + setControlled(value);
  192 + },
  193 + }}
  194 + checkedChildren="数据更新通知 Form"
  195 + unCheckedChildren="保存后通知 Form"
  196 + noStyle
  197 + />,
  198 + <Button
  199 + key="rows"
  200 + onClick={() => {
  201 + const rows = editorFormRef.current?.getRowsData?.();
  202 + console.log(rows);
  203 + }}
  204 + >
  205 + 获取 table 的数据
  206 + </Button>,
  207 + ]}
  208 + columns={columns}
  209 + editable={{
  210 + type: 'multiple',
  211 + editableKeys,
  212 + onChange: setEditableRowKeys,
  213 + actionRender: (row, config, defaultDom) => {
  214 + return [defaultDom.save, defaultDom.delete, defaultDom.cancel];
  215 + },
  216 + }}
  217 + />
  218 + <ProForm.Item>
  219 + <ProCard title="表格数据" headerBordered collapsible defaultCollapsed>
  220 + <ProFormDependency name={['procureBillDetailList']}>
  221 + {({ procureBillDetailList }) => (
  222 + <ProFormField
  223 + ignoreFormItem
  224 + fieldProps={{
  225 + style: {
  226 + width: '100%',
  227 + },
  228 + }}
  229 + mode="read"
  230 + valueType="jsonCode"
  231 + text={JSON.stringify(procureBillDetailList)}
  232 + />
  233 + )}
  234 + </ProFormDependency>
  235 + </ProCard>
  236 + </ProForm.Item>
  237 + <ProFormTextArea name="notes" label="备注" />
  238 + </ModalForm>
  239 + );
  240 +};
... ...
src/pages/product/procure/index.tsx
  1 +import ButtonConfirm from '@/components/ButtomConfirm';
1 2 import { RESPONSE_CODE } from '@/constants/enum';
2   -import { postProcureBillPage } from '@/services';
3   -import { DownOutlined } from '@ant-design/icons';
4   -import { ProTable } from '@ant-design/pro-components';
5   -import { Button } from 'antd';
  3 +import AddOrUpdate from '@/pages/product/procure/components/AddOrUpdate';
  4 +import { postProcureBillDelete, postProcureBillPage } from '@/services';
  5 +import { ProTable, type ActionType } from '@ant-design/pro-components';
  6 +import { message } from 'antd';
  7 +import { useRef } from 'react';
6 8  
7 9 export default () => {
  10 + const actionRef = useRef<ActionType>();
8 11 const columns = [
9 12 {
10 13 title: '创建时间',
... ... @@ -48,10 +51,40 @@ export default () =&gt; {
48 51 width: 180,
49 52 hideInSearch: true,
50 53 },
  54 + {
  55 + title: '操作',
  56 + valueType: 'option',
  57 + key: 'option',
  58 + render: (text, record) => [
  59 + <AddOrUpdate
  60 + key="update"
  61 + record={record}
  62 + onfinish={() => {
  63 + actionRef.current?.reload();
  64 + }}
  65 + />,
  66 + <ButtonConfirm
  67 + key="delete"
  68 + className="p-0"
  69 + title={'确认删除该记录?'}
  70 + text="删除"
  71 + onConfirm={async () => {
  72 + let res = await postProcureBillDelete({
  73 + query: { id: record.id },
  74 + });
  75 + if (res) {
  76 + message.success(res.message);
  77 + actionRef.current?.reload();
  78 + }
  79 + }}
  80 + />,
  81 + ],
  82 + },
51 83 ];
52 84  
53 85 return (
54 86 <ProTable
  87 + actionRef={actionRef}
55 88 columns={columns}
56 89 request={async (params) => {
57 90 const res = await postProcureBillPage({
... ... @@ -78,8 +111,24 @@ export default () =&gt; {
78 111 expandedRowRender: (record) => (
79 112 <ProTable
80 113 columns={[
81   - { title: '商品名称', dataIndex: 'totalPrice', key: 'totalPrice' },
  114 + {
  115 + title: '商品名称',
  116 + dataIndex: 'productName',
  117 + key: 'productName',
  118 + },
  119 + {
  120 + title: '单位',
  121 + dataIndex: 'productUnitName',
  122 + key: 'productUnitName',
  123 + },
  124 + {
  125 + title: '单价',
  126 + dataIndex: 'productUnitPrice',
  127 + key: 'productUnitPrice',
  128 + },
82 129 { title: '数量', dataIndex: 'number', key: 'number' },
  130 + { title: '小计', dataIndex: 'totalPrice', key: 'totalPrice' },
  131 + { title: '附件', dataIndex: 'annex', key: 'annex' },
83 132 { title: '备注', dataIndex: 'notes', key: 'notes' },
84 133 ]}
85 134 headerTitle={false}
... ... @@ -92,17 +141,14 @@ export default () =&gt; {
92 141 }}
93 142 search={false}
94 143 dateFormatter="string"
95   - headerTitle="嵌套表格"
  144 + headerTitle="采购管理"
96 145 options={false}
97 146 toolBarRender={() => [
98   - <Button key="show">查看日志</Button>,
99   - <Button key="out">
100   - 导出数据
101   - <DownOutlined />
102   - </Button>,
103   - <Button key="primary" type="primary">
104   - 创建应用
105   - </Button>,
  147 + <AddOrUpdate
  148 + key="add"
  149 + record={undefined}
  150 + onfinish={() => actionRef.current?.reload()}
  151 + />,
106 152 ]}
107 153 />
108 154 );
... ...
src/pages/product/product/index.tsx
... ... @@ -7,14 +7,6 @@ import { ProTable } from &#39;@ant-design/pro-components&#39;;
7 7 import { message } from 'antd';
8 8 import { useRef } from 'react';
9 9  
10   -export const waitTimePromise = async (time: number = 100) => {
11   - return new Promise((resolve) => {
12   - setTimeout(() => {
13   - resolve(true);
14   - }, time);
15   - });
16   -};
17   -
18 10 export default () => {
19 11 const actionRef = useRef<ActionType>();
20 12 const columns: ProColumns[] = [
... ...
src/pages/product/productCollect/index.tsx
... ... @@ -96,8 +96,6 @@ export default () =&gt; {
96 96 hideInTable: true,
97 97 request: async () => {
98 98 const res = await postServiceConstStores();
99   - console.log('Stores' + JSON.stringify(res));
100   - console.log('Stores' + JSON.stringify(res.data));
101 99 return enumToSelect(res.data);
102 100 },
103 101 },
... ...
src/services/request.ts
... ... @@ -16346,6 +16346,60 @@ export const postServiceConstProductCollectBillStatus = /* #__PURE__ */ (() =&gt; {
16346 16346 return request;
16347 16347 })();
16348 16348  
  16349 +/** @description response type for postServiceConstProducts */
  16350 +export interface PostServiceConstProductsResponse {
  16351 + /**
  16352 + * @description
  16353 + * OK
  16354 + */
  16355 + 200: ServerResult;
  16356 + /**
  16357 + * @description
  16358 + * Created
  16359 + */
  16360 + 201: any;
  16361 + /**
  16362 + * @description
  16363 + * Unauthorized
  16364 + */
  16365 + 401: any;
  16366 + /**
  16367 + * @description
  16368 + * Forbidden
  16369 + */
  16370 + 403: any;
  16371 + /**
  16372 + * @description
  16373 + * Not Found
  16374 + */
  16375 + 404: any;
  16376 +}
  16377 +
  16378 +export type PostServiceConstProductsResponseSuccess =
  16379 + PostServiceConstProductsResponse[200];
  16380 +/**
  16381 + * @description
  16382 + * 商品列表
  16383 + * @tags front-const-controller
  16384 + * @produces *
  16385 + * @consumes application/json
  16386 + */
  16387 +export const postServiceConstProducts = /* #__PURE__ */ (() => {
  16388 + const method = 'post';
  16389 + const url = '/service/const/products';
  16390 + function request(): Promise<PostServiceConstProductsResponseSuccess> {
  16391 + return requester(request.url, {
  16392 + method: request.method,
  16393 + }) as unknown as Promise<PostServiceConstProductsResponseSuccess>;
  16394 + }
  16395 +
  16396 + /** http method */
  16397 + request.method = method;
  16398 + /** request url */
  16399 + request.url = url;
  16400 + return request;
  16401 +})();
  16402 +
16349 16403 /** @description response type for postServiceConstStores */
16350 16404 export interface PostServiceConstStoresResponse {
16351 16405 /**
... ...