From 55884200dade84f4c2001b15b915772816c65ac6 Mon Sep 17 00:00:00 2001 From: louis <869322496@qq.com> Date: Tue, 5 Mar 2024 22:26:43 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=87=BA=E5=85=A5=E5=BA=93=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E6=A8=A1=E5=9D=97=EF=BC=8C=E4=BA=A7=E5=93=81=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E5=BC=80=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/backend/api/materialsInOut.ts | 2 +- src/api/backend/api/product.ts | 2 + src/api/backend/api/typings.d.ts | 27 ++- .../src/hooks/useExportData2Excel.ts | 16 +- .../core/dynamic-table/src/types/column.ts | 2 + src/router/routes/modules/index.ts | 4 +- src/utils/request.ts | 9 +- .../company/columns.tsx | 0 .../company/formSchemas.ts | 0 .../company/index.vue | 0 .../in-out/columns.tsx | 2 + .../materials-inventory/in-out/formSchemas.ts | 191 ++++++++++++++++++ .../in-out/index.vue | 98 ++++----- .../inventory-check/columns.tsx | 0 .../inventory-check/formSchemas.ts | 0 .../inventory-check/index.vue | 2 +- .../product/columns.tsx | 0 .../product/formSchemas.ts | 31 +-- .../product/index.vue | 7 +- .../meterials-inventory/in-out/formSchemas.ts | 111 ---------- 20 files changed, 302 insertions(+), 202 deletions(-) rename src/views/{meterials-inventory => materials-inventory}/company/columns.tsx (100%) rename src/views/{meterials-inventory => materials-inventory}/company/formSchemas.ts (100%) rename src/views/{meterials-inventory => materials-inventory}/company/index.vue (100%) rename src/views/{meterials-inventory => materials-inventory}/in-out/columns.tsx (97%) create mode 100644 src/views/materials-inventory/in-out/formSchemas.ts rename src/views/{meterials-inventory => materials-inventory}/in-out/index.vue (74%) rename src/views/{meterials-inventory => materials-inventory}/inventory-check/columns.tsx (100%) rename src/views/{meterials-inventory => materials-inventory}/inventory-check/formSchemas.ts (100%) rename src/views/{meterials-inventory => materials-inventory}/inventory-check/index.vue (99%) rename src/views/{meterials-inventory => materials-inventory}/product/columns.tsx (100%) rename src/views/{meterials-inventory => materials-inventory}/product/formSchemas.ts (65%) rename src/views/{meterials-inventory => materials-inventory}/product/index.vue (95%) delete mode 100644 src/views/meterials-inventory/in-out/formSchemas.ts diff --git a/src/api/backend/api/materialsInOut.ts b/src/api/backend/api/materialsInOut.ts index fcee606..2d18155 100644 --- a/src/api/backend/api/materialsInOut.ts +++ b/src/api/backend/api/materialsInOut.ts @@ -77,7 +77,7 @@ export async function unlinkAttachments( } /** 更新原材料出入库记录 PUT /api/materials-in-out/${param0} */ -export async function MaterialsInOutUpdate( +export async function materialsInOutUpdate( // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) params: API.MaterialsInOutUpdateParams, body: API.MaterialsInOutUpdateDto, diff --git a/src/api/backend/api/product.ts b/src/api/backend/api/product.ts index 2cb23f8..e9d4b38 100644 --- a/src/api/backend/api/product.ts +++ b/src/api/backend/api/product.ts @@ -1,5 +1,7 @@ import { request, type RequestOptions } from '@/utils/request'; + + /** 获取产品列表 GET /api/product */ export async function productList(params: API.ProductParams, options?: RequestOptions) { return request<{ diff --git a/src/api/backend/api/typings.d.ts b/src/api/backend/api/typings.d.ts index 01a9d5c..a331c6f 100644 --- a/src/api/backend/api/typings.d.ts +++ b/src/api/backend/api/typings.d.ts @@ -1536,7 +1536,8 @@ declare namespace API { type CompanyParams = { page?: number; pageSize?: number; - name?:string; + name?: string; + productId?:number; field?: string; order?: 'ASC' | 'DESC'; _t?: number; @@ -1584,7 +1585,8 @@ declare namespace API { type ProductParams = { page?: number; pageSize?: number; - company?:string; + company?: string; + name?: string; field?: string; order?: 'ASC' | 'DESC'; _t?: number; @@ -1609,6 +1611,7 @@ declare namespace API { // Materials In out history type MaterialsInOutUpdateParams = { id: number; + fileIds?: number[]; }; type MaterialsInOutInfoParams = { @@ -1626,8 +1629,10 @@ declare namespace API { type MaterialsInOutEntity = { /** 公司名称 */ companyName: string; - /** 产品名称 */ - product: number; + /** 产品Id */ + productId: number; + /** 产品信息 */ + product?: ProductEntity; /** 出库或入库 */ inOrOut: number; /** 单位(字典) */ @@ -1658,8 +1663,10 @@ declare namespace API { type MaterialsInOutDto = { /** 公司名称 */ companyName: string; - /** 产品名称 */ - product: number; + /** 产品Id */ + productId: number; + /** 产品信息 */ + product?: ProductEntity; /** 出库或入库 */ inOrOut: number; /** 单位(字典) */ @@ -1680,14 +1687,12 @@ declare namespace API { project: string; /** 备注 */ remark: string; - /** 附件 */ - files: StorageInfo[]; }; type MaterialsInOutUpdateDto = { /** 公司名称 */ companyName: string; - /** 产品名称 */ - product: number; + /** 产品Id */ + productId: number; /** 出库或入库 */ inOrOut: number; /** 单位(字典) */ @@ -1709,7 +1714,7 @@ declare namespace API { /** 备注 */ remark: string; /** 附件 */ - fileIds: number[]; + fileIds?: number[]; }; type MaterialsInOutDeleteParams = { id: number; diff --git a/src/components/core/dynamic-table/src/hooks/useExportData2Excel.ts b/src/components/core/dynamic-table/src/hooks/useExportData2Excel.ts index 28bc3ab..a8b75fa 100644 --- a/src/components/core/dynamic-table/src/hooks/useExportData2Excel.ts +++ b/src/components/core/dynamic-table/src/hooks/useExportData2Excel.ts @@ -3,6 +3,7 @@ import { columnKeyFlags } from '../types'; import type { DynamicTableProps } from '../dynamic-table'; import type { TableMethods, TableState } from './index'; import { exportJson2Excel } from '@/utils/Export2Excel'; +import { unref } from 'vue'; export type UseExportData2ExcelContext = { state: TableState; @@ -23,7 +24,7 @@ export const useExportData2Excel = ({ props, state, methods }: UseExportData2Exc const theaders = columns.filter((n) => { const key = getColumnKey(n); - return key && !columnKeyFlags.includes(key); + return key && !columnKeyFlags.includes(key) && n.hideInExport !== true; }); if (exportFormatter) { @@ -40,9 +41,20 @@ export const useExportData2Excel = ({ props, state, methods }: UseExportData2Exc }); } } else { + const data = tableData.value.map((v) => + theaders.map((header) => { + const { customRender } = unref(header); + if (customRender) { + const renderParam: any = { record: v }; + return customRender(renderParam); + } else { + return get(v, getColumnKey(header)!); + } + }), + ); exportJson2Excel({ header: theaders.map((n) => n.title as string), - data: tableData.value.map((v) => theaders.map((header) => get(v, getColumnKey(header)!))), + data, filename: exportFileName, bookType: exportBookType, autoWidth: exportAutoWidth, diff --git a/src/components/core/dynamic-table/src/types/column.ts b/src/components/core/dynamic-table/src/types/column.ts index 897f2fc..08b8b2c 100644 --- a/src/components/core/dynamic-table/src/types/column.ts +++ b/src/components/core/dynamic-table/src/types/column.ts @@ -36,6 +36,8 @@ export type TableColumn = ColumnType & { searchField?: string; /** 在查询表单中不展示此项 */ hideInSearch?: boolean; + /** 在表格中不导出此列 */ + hideInExport?: boolean; /** 在 Table 中不展示此列 */ hideInTable?: boolean; /** 传递给搜索表单 Form.Item 的配置,可以配置 rules */ diff --git a/src/router/routes/modules/index.ts b/src/router/routes/modules/index.ts index 9f1aac5..bdfc3cf 100644 --- a/src/router/routes/modules/index.ts +++ b/src/router/routes/modules/index.ts @@ -1,5 +1,5 @@ import dashboard from './dashboard'; -// import demos from './demos'; +import demos from './demos'; import account from './account'; -export default [/* ...demos, */ ...dashboard, ...account]; +export default [...demos, ...dashboard, ...account]; diff --git a/src/utils/request.ts b/src/utils/request.ts index b9b0d35..478476e 100644 --- a/src/utils/request.ts +++ b/src/utils/request.ts @@ -6,7 +6,7 @@ import { ACCESS_TOKEN_KEY } from '@/enums/cacheEnum'; import { Storage } from '@/utils/Storage'; import { ResultEnum } from '@/enums/httpEnum'; import { useUserStore } from '@/store/modules/user'; - +import * as qs from 'qs'; export interface RequestOptions extends AxiosRequestConfig { /** 是否直接将数据从响应中提取出,例如直接返回 res.data,而忽略 res.code 等信息 */ isReturnResult?: boolean; @@ -123,15 +123,20 @@ export async function request(_url: string | RequestOptions, _config: RequestOpt try { // 兼容 from data 文件上传的情况 const { requestType, isReturnResult = true, ...rest } = config; - + // 修复query传递数组时,time变成time[]的解析问题 + const paramsSerializer = (params) => { + return qs.stringify(params, { arrayFormat: 'repeat' }); + }; const response = (await service.request({ url, ...rest, + paramsSerializer, // headers: { ...rest.headers, ...(requestType === 'form' ? { 'Content-Type': 'multipart/form-data' } : {}), }, })) as AxiosResponse; + const { data } = response; const { code, message } = data || {}; diff --git a/src/views/meterials-inventory/company/columns.tsx b/src/views/materials-inventory/company/columns.tsx similarity index 100% rename from src/views/meterials-inventory/company/columns.tsx rename to src/views/materials-inventory/company/columns.tsx diff --git a/src/views/meterials-inventory/company/formSchemas.ts b/src/views/materials-inventory/company/formSchemas.ts similarity index 100% rename from src/views/meterials-inventory/company/formSchemas.ts rename to src/views/materials-inventory/company/formSchemas.ts diff --git a/src/views/meterials-inventory/company/index.vue b/src/views/materials-inventory/company/index.vue similarity index 100% rename from src/views/meterials-inventory/company/index.vue rename to src/views/materials-inventory/company/index.vue diff --git a/src/views/meterials-inventory/in-out/columns.tsx b/src/views/materials-inventory/in-out/columns.tsx similarity index 97% rename from src/views/meterials-inventory/in-out/columns.tsx rename to src/views/materials-inventory/in-out/columns.tsx index a765eac..1835016 100644 --- a/src/views/meterials-inventory/in-out/columns.tsx +++ b/src/views/materials-inventory/in-out/columns.tsx @@ -57,6 +57,7 @@ export const baseColumns: TableColumnItem[] = [ width: 120, align: 'center', dataIndex: 'time', + formItemProps: { component: 'RangePicker' }, customRender: ({ record }) => { return formatToDate(record.time); }, @@ -78,6 +79,7 @@ export const baseColumns: TableColumnItem[] = [ width: 80, align: 'center', dataIndex: 'amount', + hideInSearch: true, }, { title: '经办人', diff --git a/src/views/materials-inventory/in-out/formSchemas.ts b/src/views/materials-inventory/in-out/formSchemas.ts new file mode 100644 index 0000000..b5e91d8 --- /dev/null +++ b/src/views/materials-inventory/in-out/formSchemas.ts @@ -0,0 +1,191 @@ +import type { FormSchema } from '@/components/core/schema-form/'; +import { ContractStatusEnum } from '@/enums/contractEnum'; +import { formatStatus } from './columns'; +import Api from '@/api'; +import { debounce } from 'lodash-es'; +import { MaterialsInOutEnum } from '@/enums/materialsInventoryEnum'; + +export const formSchemas: FormSchema[] = [ + { + field: 'productId', + component: 'Select', + label: '产品', + colProps: { + span: 16, + }, + helpMessage:'如未找到对应产品,请先去产品管理添加产品。', + rules: [{ required: true, type: 'number' }], + componentProps: ({ formInstance, schema, formModel }) => ({ + showSearch: true, + filterOption: false, + fieldNames: { + label: 'label', + value: 'value', + }, + options: [], + getPopupContainer: () => document.body, + defaultActiveFirstOption: true, + onChange: async (value) => { + if (!value) { + const options = await getProductOptions(); + const newSchema = { + field: schema.field, + componentProps: { + options, + }, + }; + formInstance?.updateSchema([newSchema]); + } + }, + request: () => { + return getProductOptions(); + }, + onSearch: debounce(async (keyword) => { + schema.loading = true; + const newSchema = { + field: schema.field, + componentProps: { + options: [] as LabelValueOptions, + }, + }; + formInstance?.updateSchema([newSchema]); + const options = await getProductOptions(keyword).finally(() => (schema.loading = false)); + newSchema.componentProps.options = options; + formInstance?.updateSchema([newSchema]); + }, 500), + }), + }, + + { + field: 'inOrOut', + component: 'Select', + label: '出入库', + rules: [{ required: true, type: 'number' }], + defaultValue: MaterialsInOutEnum.In, + colProps: { + span: 8, + }, + componentProps: { + options: [ + { label: '出库', value: MaterialsInOutEnum.Out }, + { label: '入库', value: MaterialsInOutEnum.In }, + ], + }, + }, + // { + // field: 'title', + // component: 'Input', + // label: '合同标题', + // rules: [{ required: true, type: 'string' }], + // colProps: { + // span: 12, + // }, + // }, + // { + // field: 'partyA', + // component: 'Input', + // label: '甲方', + // rules: [{ required: true, type: 'string' }], + // colProps: { + // span: 12, + // }, + // }, + // { + // field: 'partyB', + // component: 'Input', + // label: '乙方', + // rules: [{ required: true, type: 'string' }], + // colProps: { + // span: 12, + // }, + // }, + // { + // field: 'signingDate', + // label: '签订时间', + // component: 'DatePicker', + // // defaultValue: new Date(), + // colProps: { span: 12 }, + // componentProps: {}, + // }, + // { + // field: 'deliveryDeadline', + // label: '交付期限', + // component: 'DatePicker', + // // defaultValue: new Date(), + // colProps: { span: 12 }, + // }, + // { + // field: 'type', + // label: '合同类型', + // component: 'Select', + // required: true, + // colProps: { + // span: 12, + // }, + // componentProps: { + // options: contractTypes.map(({ label, id }) => ({ value: id, label })), + // }, + // }, + // { + // field: 'status', + // label: '审核结果', + // component: 'Select', + // required:true, + // defaultValue: 0, + // colProps: { + // span: 12, + // }, + // componentProps: { + // allowClear: false, + // options: Object.values(ContractStatusEnum) + // .filter((value) => typeof value === 'number') + // .map((item) => formatStatus(item as ContractStatusEnum)), + // }, + // }, + // { + // field: 'remark', + // component: 'InputTextArea', + // label: '备注', + // }, + // { + // field: 'menuIds', + // component: 'Tree', + // label: '菜单权限', + // componentProps: { + // checkable: true, + // vModelKey: 'checkedKeys', + // fieldNames: { + // title: 'name', + // key: 'id', + // }, + // style: { + // height: '350px', + // paddingTop: '5px', + // overflow: 'auto', + // borderRadius: '6px', + // border: '1px solid #dcdfe6', + // resize: 'vertical', + // }, + // }, + // }, +]; + +const getProductOptions = async (keyword?: string): Promise => { + const { items: result } = await Api.product.productList({ pageSize: 100, name: keyword }); + return ( + result?.map((item) => ({ + label: `${item.name}` + (item.company?.name ? `(${item.company?.name})` : ''), + value: item.id, + })) || [] + ); +}; + +const getCompanyOptions = async ({ keyword, id }): Promise => { + const { items: result } = await Api.company.companyList({ pageSize: 100, name: keyword }); + return ( + result?.map((item) => ({ + label: item.name, + value: item.id, + })) || [] + ); +}; diff --git a/src/views/meterials-inventory/in-out/index.vue b/src/views/materials-inventory/in-out/index.vue similarity index 74% rename from src/views/meterials-inventory/in-out/index.vue rename to src/views/materials-inventory/in-out/index.vue index cf1d717..cb5a1b4 100644 --- a/src/views/meterials-inventory/in-out/index.vue +++ b/src/views/materials-inventory/in-out/index.vue @@ -30,6 +30,7 @@ import { onMounted, ref, type FunctionalComponent } from 'vue'; import { useFormModal, useModal } from '@/hooks/useModal'; import { Button } from 'ant-design-vue'; + import { formSchemas } from './formSchemas'; import AttachmentManage from '@/components/business/attachment-manage/index.vue'; import AttachmentUpload from '@/components/business/attachment-upload/index.vue'; defineOptions({ @@ -93,24 +94,24 @@ }); const openAttachmentUploadModal = async (record: TableListItem) => { - // isUploadPopupVisiable.value = true; - // fnModal.show({ - // width: 800, - // title: `记录编号: ${record.contractNumber}`, - // content: () => { - // return ( - // { - // afterUploadCallback(files, record.id); - // }} - // > - // ); - // }, - // destroyOnClose: true, - // open: isUploadPopupVisiable.value, - // footer: null, - // }); + isUploadPopupVisiable.value = true; + fnModal.show({ + width: 800, + title: `上传附件: ${record.id}`, + content: () => { + return ( + { + afterUploadCallback(files, record.id); + }} + > + ); + }, + destroyOnClose: true, + open: isUploadPopupVisiable.value, + footer: null, + }); }; const handleUploadClose = (hasSuccess: boolean) => { fnModal.hide(); @@ -128,37 +129,36 @@ * @description 打开新增/编辑弹窗 */ const openEditModal = async (record: Partial) => { - // const [formRef] = await showModal({ - // modalProps: { - // title: `${record.id ? '编辑' : '新增'}盘点记录`, - // width: '50%', - // onFinish: async (values) => { - // const params = { - // ...values, - // signingDate: formatToDate(values.signingDate), - // deliveryDeadline: formatToDate(values.deliveryDeadline), - // }; - // if (record.id) { - // await Api.contract.contractUpdate({ id: record.id }, params); - // } else { - // await Api.contract.contractCreate(params); - // } - // dynamicTableInstance?.reload(); - // }, - // }, - // formProps: { - // labelWidth: 100, - // schemas: contractSchemas(contractTypes.value), - // }, - // }); - - // // 如果是编辑的话,需要获取角色详情 - // if (record.id) { - // const info = await Api.contract.contractInfo({ id: record.id }); - // formRef?.setFieldsValue({ - // ...info, - // }); - // } + const [formRef] = await showModal({ + modalProps: { + title: `${record.id ? '编辑' : '新增'}出入库记录`, + width: '50%', + onFinish: async (values) => { + const params: API.MaterialsInOutUpdateDto = { + ...values, + // signingDate: formatToDate(values.signingDate), + // deliveryDeadline: formatToDate(values.deliveryDeadline), + }; + if (record.id) { + await Api.materialsInOut.materialsInOutUpdate({ id: record.id }, params); + } else { + await Api.materialsInOut.materialsInOutCreate(params); + } + dynamicTableInstance?.reload(); + }, + }, + formProps: { + labelWidth: 100, + schemas: formSchemas, + }, + }); + // 如果是编辑的话,需要获取详情 + if (record.id) { + const info = await Api.contract.contractInfo({ id: record.id }); + formRef?.setFieldsValue({ + ...info, + }); + } }; const delRowConfirm = async (record) => { await Api.contract.contractDelete({ id: record }); diff --git a/src/views/meterials-inventory/inventory-check/columns.tsx b/src/views/materials-inventory/inventory-check/columns.tsx similarity index 100% rename from src/views/meterials-inventory/inventory-check/columns.tsx rename to src/views/materials-inventory/inventory-check/columns.tsx diff --git a/src/views/meterials-inventory/inventory-check/formSchemas.ts b/src/views/materials-inventory/inventory-check/formSchemas.ts similarity index 100% rename from src/views/meterials-inventory/inventory-check/formSchemas.ts rename to src/views/materials-inventory/inventory-check/formSchemas.ts diff --git a/src/views/meterials-inventory/inventory-check/index.vue b/src/views/materials-inventory/inventory-check/index.vue similarity index 99% rename from src/views/meterials-inventory/inventory-check/index.vue rename to src/views/materials-inventory/inventory-check/index.vue index 366f966..b194bf3 100644 --- a/src/views/meterials-inventory/inventory-check/index.vue +++ b/src/views/materials-inventory/inventory-check/index.vue @@ -37,7 +37,7 @@ import AttachmentManage from '@/components/business/attachment-manage/index.vue'; import AttachmentUpload from '@/components/business/attachment-upload/index.vue'; defineOptions({ - name: 'MeterialsInventory', + name: 'MaterialsInventory', }); const [DynamicTable, dynamicTableInstance] = useTable(); const [showModal] = useFormModal(); diff --git a/src/views/meterials-inventory/product/columns.tsx b/src/views/materials-inventory/product/columns.tsx similarity index 100% rename from src/views/meterials-inventory/product/columns.tsx rename to src/views/materials-inventory/product/columns.tsx diff --git a/src/views/meterials-inventory/product/formSchemas.ts b/src/views/materials-inventory/product/formSchemas.ts similarity index 65% rename from src/views/meterials-inventory/product/formSchemas.ts rename to src/views/materials-inventory/product/formSchemas.ts index 03d8371..31bb15a 100644 --- a/src/views/meterials-inventory/product/formSchemas.ts +++ b/src/views/materials-inventory/product/formSchemas.ts @@ -16,12 +16,7 @@ export const formSchemas: FormSchema[] = [ field: 'companyId', component: 'Select', label: '所属公司', - // componentProps: { - // request: async () => { - // const { items: result } = await Api.company.companyList({ pageSize: 100 }); - // return result?.map((item) => ({ label: item.name, value: item.id })); - // }, - // }, + helpMessage: '如未找到对应公司,请先去公司管理添加公司。', componentProps: ({ formInstance, schema }) => ({ showSearch: true, filterOption: false, @@ -32,24 +27,23 @@ export const formSchemas: FormSchema[] = [ options: [], getPopupContainer: () => document.body, defaultActiveFirstOption: true, - onChange: async (value, option) => { + onChange: async (value) => { console.log('onChange'); if (!value) { formInstance?.setFieldsValue({ companyId: undefined }); - const { items: result } = await Api.company.companyList({ pageSize: 100 }); + const options = await getCompanyOptions(); const newSchema = { field: schema.field, componentProps: { - options: result?.map((item) => ({ label: item.name, value: item.id })), + options, }, }; formInstance?.updateSchema([newSchema]); } }, - + request: () => { return getCompanyOptions(); - }, onSearch: debounce(async (keyword) => { schema.loading = true; @@ -60,23 +54,16 @@ export const formSchemas: FormSchema[] = [ }, }; formInstance?.updateSchema([newSchema]); - const { items: result } = await Api.company - .companyList({ pageSize: 100, name: keyword }) - .finally(() => (schema.loading = false)); - if (result) { - newSchema.componentProps.options = result.map((item) => ({ - value: item.id, - label: item.name, - })); - } + const options = await getCompanyOptions(keyword).finally(() => (schema.loading = false)); + newSchema.componentProps.options = options; formInstance?.updateSchema([newSchema]); }, 500), }), }, ]; -const getCompanyOptions = async (keyword?): Promise => { - const { items: result } = await Api.company.companyList({ pageSize: 100 }); +const getCompanyOptions = async (keyword?: string): Promise => { + const { items: result } = await Api.company.companyList({ pageSize: 100, name: keyword }); return ( result?.map((item) => ({ label: item.name, diff --git a/src/views/meterials-inventory/product/index.vue b/src/views/materials-inventory/product/index.vue similarity index 95% rename from src/views/meterials-inventory/product/index.vue rename to src/views/materials-inventory/product/index.vue index 3c9ca22..49a18f1 100644 --- a/src/views/meterials-inventory/product/index.vue +++ b/src/views/materials-inventory/product/index.vue @@ -6,6 +6,7 @@ title-tooltip="" :data-request="Api.product.productList" :columns="columns" + :exportFileName="'产品'" bordered size="small" > @@ -23,7 +24,7 @@