From f10cf167372f2d8c4c0e14f42f361d7ab96d8347 Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期五, 03 七月 2026 13:59:00 +0800
Subject: [PATCH] Merge branch 'dev_pro2.0' of http://114.132.189.42:9002/r/mom-pro2-before into dev_pro2.0
---
src/views/mes/pd/project/data.ts | 535 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 535 insertions(+), 0 deletions(-)
diff --git a/src/views/mes/pd/project/data.ts b/src/views/mes/pd/project/data.ts
new file mode 100644
index 0000000..9d9cac6
--- /dev/null
+++ b/src/views/mes/pd/project/data.ts
@@ -0,0 +1,535 @@
+import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
+import type { VxeTableGridOptions } from '#/adapter/vxe-table';
+import type { MesMdItemApi } from '#/api/mes/md/item';
+import type { MesPdProjectApi } from '#/api/mes/pd/project';
+
+import { h, markRaw } from 'vue';
+
+import {
+ DICT_TYPE,
+ MesAutoCodeRuleCode,
+ MesPdDocumentTypeEnum,
+} from '#/packages/constants/src';
+import { getDictOptions } from '#/packages/effects/hooks/src';
+
+import { Button } from 'ant-design-vue';
+
+import { generateAutoCode } from '#/api/mes/md/autocode/record';
+import { isPdMockEnabled } from '#/api/mes/pd/mock/enabled';
+import { mockNextCode } from '#/api/mes/pd/mock/utils';
+import { getRangePickerDefaultProps } from '#/utils';
+import { MdItemSelect } from '#/views/mes/md/item/components';
+
+export type FormType = 'create' | 'detail' | 'update';
+
+async function generateTaskCode(formApi?: VbenFormApi) {
+ const code = isPdMockEnabled()
+ ? mockNextCode('DT-2026', Math.floor(Date.now() % 10_000))
+ : await generateAutoCode(MesAutoCodeRuleCode.PD_PROJECT_CODE);
+ await formApi?.setFieldValue('code', code);
+}
+
+async function syncTaskNameFromProduct(
+ formApi: VbenFormApi | undefined,
+ productName?: string,
+) {
+ const version = (await formApi?.getFieldValue('version')) as
+ | string
+ | undefined;
+ const name = productName?.trim();
+ if (name && version?.trim()) {
+ await formApi?.setFieldValue('name', `${name} ${version.trim()} 璁捐`);
+ }
+}
+
+/** 浜у搧閫夋嫨锛氶�夋嫨鍚庤嚜鍔ㄥ甫鍑轰骇鍝佺紪鐮� */
+function useProductSelectSchema(
+ formApi: VbenFormApi | undefined,
+ readonly: boolean,
+): VbenFormSchema[] {
+ if (readonly) {
+ return [
+ {
+ fieldName: 'productCode',
+ label: '浜у搧缂栫爜',
+ component: 'Input',
+ componentProps: { disabled: true },
+ },
+ {
+ fieldName: 'productName',
+ label: '浜у搧鍚嶇О',
+ component: 'Input',
+ componentProps: { disabled: true },
+ },
+ ];
+ }
+ return [
+ {
+ fieldName: 'productId',
+ label: '浜у搧',
+ component: markRaw(MdItemSelect),
+ componentProps: {
+ placeholder: '璇烽�夋嫨浜у搧',
+ onChange: async (item: MesMdItemApi.Item | undefined) => {
+ await formApi?.setFieldValue('productCode', item?.code ?? '');
+ await formApi?.setFieldValue('productName', item?.name ?? '');
+ await syncTaskNameFromProduct(formApi, item?.name);
+ },
+ },
+ rules: 'selectRequired',
+ },
+ {
+ fieldName: 'productCode',
+ label: '浜у搧缂栫爜',
+ component: 'Input',
+ componentProps: {
+ disabled: true,
+ placeholder: '閫夋嫨浜у搧鍚庤嚜鍔ㄥ甫鍑�',
+ },
+ rules: 'required',
+ },
+ {
+ fieldName: 'productName',
+ component: 'Input',
+ dependencies: { triggerFields: [''], show: () => false },
+ },
+ ];
+}
+
+/** 鍙戣捣璁捐浠诲姟琛ㄥ崟 */
+export function useCreateTaskSchema(formApi?: VbenFormApi): VbenFormSchema[] {
+ return [
+ {
+ fieldName: 'id',
+ component: 'Input',
+ dependencies: { triggerFields: [''], show: () => false },
+ },
+ {
+ fieldName: 'code',
+ label: '浠诲姟缂栫爜',
+ component: 'Input',
+ componentProps: { placeholder: '璇风偣鍑荤敓鎴愪换鍔$紪鐮�' },
+ rules: 'required',
+ suffix: () =>
+ h(
+ Button,
+ { type: 'default', onClick: () => generateTaskCode(formApi) },
+ { default: () => '鐢熸垚' },
+ ),
+ },
+ ...useProductSelectSchema(formApi, false),
+ {
+ fieldName: 'version',
+ label: '璁捐鐗堟湰',
+ component: 'Input',
+ componentProps: { placeholder: '濡� V1.0銆乂2.1' },
+ rules: 'required',
+ },
+ {
+ fieldName: 'name',
+ label: '浠诲姟鍚嶇О',
+ component: 'Input',
+ componentProps: { placeholder: '灏嗘牴鎹骇鍝佷笌鐗堟湰鑷姩鐢熸垚锛屽彲淇敼' },
+ rules: 'required',
+ dependencies: {
+ triggerFields: ['productName', 'version'],
+ trigger(values: Record<string, string>, form) {
+ const productName = values.productName?.trim();
+ const version = values.version?.trim();
+ if (productName && version) {
+ form.setFieldValue('name', `${productName} ${version} 璁捐`);
+ }
+ },
+ },
+ },
+ {
+ fieldName: 'designerName',
+ label: '涓昏璁″笀',
+ component: 'Input',
+ componentProps: { placeholder: '璇疯緭鍏ヤ富璁捐甯�' },
+ rules: 'required',
+ },
+ {
+ fieldName: 'reviewerName',
+ label: '瀹℃牳浜�',
+ component: 'Input',
+ componentProps: { placeholder: '璧勬枡瀹℃牳璐熻矗浜�' },
+ rules: 'required',
+ },
+ {
+ fieldName: 'planDateRange',
+ label: '璁″垝鍛ㄦ湡',
+ component: 'RangePicker',
+ componentProps: getRangePickerDefaultProps(),
+ rules: 'required',
+ },
+ {
+ fieldName: 'remark',
+ label: '浠诲姟璇存槑',
+ component: 'Textarea',
+ componentProps: {
+ placeholder: '绠�杩版湰娆¤璁$洰鏍囥�佸彉鏇磋儗鏅瓑',
+ rows: 3,
+ },
+ formItemClass: 'col-span-2',
+ },
+ ];
+}
+
+/** 鍙戝竷浠诲姟纭琛ㄥ崟 */
+export function usePublishFormSchema(): VbenFormSchema[] {
+ return [
+ {
+ fieldName: 'publishRemark',
+ label: '鍙戝竷璇存槑',
+ component: 'Textarea',
+ componentProps: {
+ placeholder: '鍙�夛紝濉啓鍙戝竷瑕佹眰鎴栨敞鎰忎簨椤�',
+ rows: 3,
+ },
+ formItemClass: 'col-span-2',
+ },
+ ];
+}
+
+export type WorkflowActionType = 'approve' | 'archive' | 'submit-review';
+
+export interface WorkflowActionConfig {
+ title: string;
+ alertMessage: string;
+ alertDescription: string;
+ remarkLabel: string;
+ remarkTag: string;
+ remarkPlaceholder: string;
+ successMessage: string;
+ alertType: 'info' | 'success' | 'warning';
+}
+
+export const WORKFLOW_ACTION_CONFIG: Record<
+ WorkflowActionType,
+ WorkflowActionConfig
+> = {
+ 'submit-review': {
+ title: '鎻愪氦璧勬枡瀹℃牳',
+ alertMessage: '纭鎻愪氦瀹℃牳',
+ alertDescription:
+ '鎻愪氦鍚庡皢杩涘叆璧勬枡瀹℃牳鐜妭锛岃纭璁捐璧勬枡宸蹭笂浼犲畬鏁淬�傛彁浜ゅ悗璁捐甯堝皢鏃犳硶缁х画淇敼璧勬枡銆�',
+ remarkLabel: '鎻愪氦璇存槑',
+ remarkTag: '銆愭彁浜よ鏄庛��',
+ remarkPlaceholder: '鍙�夛紝濉啓鎻愪氦瀹℃牳鐨勮ˉ鍏呰鏄�',
+ successMessage: '宸叉彁浜よ祫鏂欏鏍�',
+ alertType: 'info',
+ },
+ approve: {
+ title: '瀹℃牳閫氳繃',
+ alertMessage: '纭瀹℃牳閫氳繃',
+ alertDescription:
+ '瀹℃牳閫氳繃鍚庝换鍔¤繘鍏ャ�屽凡閫氳繃銆嶇姸鎬侊紝鍙繘琛屽綊妗f搷浣溿�傝纭璁捐璧勬枡绗﹀悎瑕佹眰銆�',
+ remarkLabel: '瀹℃牳鎰忚',
+ remarkTag: '銆愬鏍告剰瑙併��',
+ remarkPlaceholder: '鍙�夛紝濉啓瀹℃牳閫氳繃鎰忚',
+ successMessage: '璧勬枡瀹℃牳閫氳繃',
+ alertType: 'success',
+ },
+ archive: {
+ title: '褰掓。璁捐浠诲姟',
+ alertMessage: '纭褰掓。',
+ alertDescription:
+ '褰掓。鍚庡皢鐢熸垚鏈増鏈綊妗e彴璐﹁褰曪紝浠诲姟鐘舵�佸彉涓哄凡褰掓。锛岃璁¤祫鏂欏皢閿佸畾涓嶅彲淇敼銆�',
+ remarkLabel: '褰掓。璇存槑',
+ remarkTag: '銆愬綊妗h鏄庛��',
+ remarkPlaceholder: '鍙�夛紝濉啓褰掓。澶囨敞',
+ successMessage: '浠诲姟宸插綊妗�',
+ alertType: 'warning',
+ },
+};
+
+/** 娴佺▼鎿嶄綔纭琛ㄥ崟 */
+export function useWorkflowActionFormSchema(
+ action: WorkflowActionType,
+): VbenFormSchema[] {
+ const config = WORKFLOW_ACTION_CONFIG[action];
+ return [
+ {
+ fieldName: 'actionRemark',
+ label: config.remarkLabel,
+ component: 'Textarea',
+ componentProps: {
+ placeholder: config.remarkPlaceholder,
+ rows: 3,
+ },
+ formItemClass: 'col-span-2',
+ },
+ ];
+}
+
+export function useGridFormSchema(): VbenFormSchema[] {
+ return [
+ {
+ fieldName: 'code',
+ label: '浠诲姟缂栫爜',
+ component: 'Input',
+ componentProps: { placeholder: '璇疯緭鍏ヤ换鍔$紪鐮�' },
+ },
+ {
+ fieldName: 'name',
+ label: '浠诲姟鍚嶇О',
+ component: 'Input',
+ componentProps: { placeholder: '璇疯緭鍏ヤ换鍔″悕绉�' },
+ },
+ {
+ fieldName: 'productCode',
+ label: '浜у搧缂栫爜',
+ component: 'Input',
+ componentProps: { placeholder: '璇疯緭鍏ヤ骇鍝佺紪鐮�' },
+ },
+ {
+ fieldName: 'status',
+ label: '浠诲姟鐘舵��',
+ component: 'Select',
+ componentProps: {
+ allowClear: true,
+ options: getDictOptions(DICT_TYPE.MES_PD_PROJECT_STATUS, 'number'),
+ placeholder: '璇烽�夋嫨椤圭洰鐘舵��',
+ },
+ },
+ ];
+}
+
+export function useGridColumns(): VxeTableGridOptions['columns'] {
+ return [
+ { field: 'code', title: '浠诲姟缂栫爜', minWidth: 140, slots: { default: 'code' } },
+ { field: 'name', title: '浠诲姟鍚嶇О', minWidth: 160 },
+ { field: 'productCode', title: '浜у搧缂栫爜', minWidth: 120 },
+ { field: 'productName', title: '浜у搧鍚嶇О', minWidth: 140 },
+ { field: 'version', title: '鐗堟湰鍙�', minWidth: 90 },
+ {
+ field: 'status',
+ title: '鐘舵��',
+ minWidth: 100,
+ cellRender: {
+ name: 'CellDict',
+ props: { type: DICT_TYPE.MES_PD_PROJECT_STATUS },
+ },
+ },
+ { field: 'designerName', title: '涓昏璁″笀', minWidth: 100 },
+ { field: 'reviewerName', title: '瀹℃牳浜�', minWidth: 100 },
+ { field: 'planEndDate', title: '璁″垝瀹屾垚', minWidth: 120, formatter: 'formatDate' },
+ { field: 'createTime', title: '鍒涘缓鏃堕棿', minWidth: 160, formatter: 'formatDateTime' },
+ { field: 'action', title: '鎿嶄綔', width: 220, fixed: 'right', slots: { default: 'actions' } },
+ ];
+}
+
+export function useFormSchema(
+ formType: FormType,
+ formApi?: VbenFormApi,
+): VbenFormSchema[] {
+ const readonly = formType === 'detail';
+ return [
+ {
+ fieldName: 'id',
+ component: 'Input',
+ dependencies: { triggerFields: [''], show: () => false },
+ },
+ {
+ fieldName: 'code',
+ label: '浠诲姟缂栫爜',
+ component: 'Input',
+ componentProps: { disabled: readonly, placeholder: '璇疯緭鍏ヤ换鍔$紪鐮�' },
+ rules: 'required',
+ suffix:
+ formType === 'detail'
+ ? undefined
+ : () =>
+ h(
+ Button,
+ {
+ type: 'default',
+ onClick: async () => {
+ const code = isPdMockEnabled()
+ ? mockNextCode(
+ 'DT-2026',
+ Math.floor(Date.now() % 10_000),
+ )
+ : await generateAutoCode(
+ MesAutoCodeRuleCode.PD_PROJECT_CODE,
+ );
+ await formApi?.setFieldValue('code', code);
+ },
+ },
+ { default: () => '鐢熸垚' },
+ ),
+ },
+ ...useProductSelectSchema(formApi, readonly),
+ {
+ fieldName: 'version',
+ label: '鐗堟湰鍙�',
+ component: 'Input',
+ componentProps: { disabled: readonly, placeholder: '濡� V1.0' },
+ rules: 'required',
+ },
+ {
+ fieldName: 'name',
+ label: '浠诲姟鍚嶇О',
+ component: 'Input',
+ componentProps: { disabled: readonly, placeholder: '濡傦細鏅鸿兘娓╂帶妯$粍 V1.0 璁捐' },
+ rules: 'required',
+ dependencies: {
+ triggerFields: ['productName', 'version'],
+ trigger(values: Record<string, string>, form) {
+ if (readonly) {
+ return;
+ }
+ const productName = values.productName?.trim();
+ const version = values.version?.trim();
+ if (productName && version) {
+ form.setFieldValue('name', `${productName} ${version} 璁捐`);
+ }
+ },
+ },
+ },
+ {
+ fieldName: 'status',
+ label: '浠诲姟鐘舵��',
+ component: 'Select',
+ componentProps: {
+ disabled: true,
+ options: getDictOptions(DICT_TYPE.MES_PD_PROJECT_STATUS, 'number'),
+ },
+ dependencies: { triggerFields: [''], show: () => formType !== 'create' },
+ },
+ {
+ fieldName: 'designerName',
+ label: '涓昏璁″笀',
+ component: 'Input',
+ componentProps: { disabled: readonly, placeholder: '璇疯緭鍏ヤ富璁捐甯�' },
+ },
+ {
+ fieldName: 'reviewerName',
+ label: '瀹℃牳浜�',
+ component: 'Input',
+ componentProps: { disabled: readonly, placeholder: '璇疯緭鍏ュ鏍镐汉' },
+ },
+ {
+ fieldName: 'planDateRange',
+ label: '璁″垝鍛ㄦ湡',
+ component: 'RangePicker',
+ componentProps: {
+ ...getRangePickerDefaultProps(),
+ disabled: readonly,
+ },
+ },
+ {
+ fieldName: 'remark',
+ label: '澶囨敞',
+ component: 'Textarea',
+ componentProps: { disabled: readonly, placeholder: '璇疯緭鍏ュ娉�', rows: 3 },
+ formItemClass: 'col-span-3',
+ },
+ ];
+}
+
+/** 璁捐璧勬枡绫诲瀷閫夐」锛堜笂浼犳椂閫夋嫨锛� */
+export function getPdDocumentTypeOptions() {
+ return [
+ { label: '璁捐鏂规', value: MesPdDocumentTypeEnum.SCHEME },
+ { label: '璁捐鍥剧焊', value: MesPdDocumentTypeEnum.DRAWING },
+ { label: '璁捐妯″瀷', value: MesPdDocumentTypeEnum.MODEL },
+ { label: '浜у搧璁捐', value: MesPdDocumentTypeEnum.PRODUCT_DESIGN },
+ { label: 'BOM 娓呭崟', value: MesPdDocumentTypeEnum.BOM },
+ { label: '鍏朵粬闄勪欢', value: MesPdDocumentTypeEnum.OTHER },
+ ];
+}
+
+/** 缁熶竴璁捐璧勬枡鍒楄〃鍒� */
+export function useMaterialListGridFormSchema(): VbenFormSchema[] {
+ return [
+ {
+ fieldName: 'name',
+ label: '璧勬枡鍚嶇О',
+ component: 'Input',
+ componentProps: { placeholder: '璇疯緭鍏ヨ祫鏂欏悕绉�' },
+ },
+ {
+ fieldName: 'documentType',
+ label: '璧勬枡绫诲瀷',
+ component: 'Select',
+ componentProps: {
+ allowClear: true,
+ options: getPdDocumentTypeOptions(),
+ placeholder: '璇烽�夋嫨璧勬枡绫诲瀷',
+ },
+ },
+ ];
+}
+
+export function useMaterialListGridColumns(): VxeTableGridOptions['columns'] {
+ return [
+ {
+ field: 'documentType',
+ title: '璧勬枡绫诲瀷',
+ minWidth: 110,
+ formatter: ({ cellValue }: { cellValue: number }) => {
+ const option = getPdDocumentTypeOptions().find(
+ (item) => item.value === cellValue,
+ );
+ return option?.label ?? String(cellValue ?? '');
+ },
+ },
+ { field: 'name', title: '璧勬枡鍚嶇О', minWidth: 180 },
+ { field: 'version', title: '鐗堟湰', minWidth: 90 },
+ { field: 'fileName', title: '鏂囦欢鍚�', minWidth: 200 },
+ { field: 'uploaderName', title: '涓婁紶浜�', minWidth: 100 },
+ {
+ field: 'createTime',
+ title: '涓婁紶鏃堕棿',
+ minWidth: 160,
+ formatter: 'formatDateTime',
+ },
+ {
+ field: 'action',
+ title: '鎿嶄綔',
+ width: 140,
+ fixed: 'right',
+ slots: { default: 'actions' },
+ },
+ ];
+}
+
+/** @deprecated 鎸夌被鍨嬪垎 Tab 鏃朵娇鐢紝璇锋敼鐢� useMaterialListGridColumns */
+export function useDocumentGridColumns(documentType: number): VxeTableGridOptions['columns'] {
+ const typeLabel =
+ documentType === MesPdDocumentTypeEnum.SCHEME
+ ? '鏂规'
+ : documentType === MesPdDocumentTypeEnum.DRAWING
+ ? '鍥剧焊'
+ : documentType === MesPdDocumentTypeEnum.MODEL
+ ? '妯″瀷'
+ : documentType === MesPdDocumentTypeEnum.PRODUCT_DESIGN
+ ? '浜у搧璁捐'
+ : '璧勬枡';
+
+ return [
+ { field: 'name', title: `${typeLabel}鍚嶇О`, minWidth: 180 },
+ { field: 'version', title: '鐗堟湰', minWidth: 90 },
+ { field: 'fileName', title: '鏂囦欢鍚�', minWidth: 200 },
+ { field: 'uploaderName', title: '涓婁紶浜�', minWidth: 100 },
+ { field: 'createTime', title: '涓婁紶鏃堕棿', minWidth: 160, formatter: 'formatDateTime' },
+ { field: 'action', title: '鎿嶄綔', width: 140, slots: { default: 'actions' } },
+ ];
+}
+
+/** BOM 琛ㄦ牸鍒� */
+export function useBomGridColumns(): VxeTableGridOptions['columns'] {
+ return [
+ { field: 'itemCode', title: '鐗╂枡缂栫爜', minWidth: 120 },
+ { field: 'itemName', title: '鐗╂枡鍚嶇О', minWidth: 160 },
+ { field: 'specification', title: '瑙勬牸鍨嬪彿', minWidth: 140 },
+ { field: 'unitMeasureName', title: '鍗曚綅', minWidth: 80 },
+ { field: 'quantity', title: '鐢ㄩ噺', minWidth: 90 },
+ { field: 'remark', title: '澶囨敞', minWidth: 140 },
+ { field: 'action', title: '鎿嶄綔', width: 140, slots: { default: 'actions' } },
+ ];
+}
+
+export type { MesPdProjectApi };
--
Gitblit v1.9.3