zhangwencui
2026-07-10 8d6b574a04d1cba911465aabb042c093ab2f646c
mes基础参数/参数模版接口调用
已修改9个文件
986 ■■■■ 文件已修改
src/api/mdm/unit/index.ts 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/mes/pro/processdesign/parameter/index.ts 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/mes/pro/processdesign/template/index.ts 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mes/process-design/parameter/data.ts 189 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mes/process-design/parameter/index.vue 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mes/process-design/template/data.ts 131 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mes/process-design/template/index.vue 198 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mes/process-design/template/modules/form.vue 317 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mes/process-design/template/modules/parameter-select-dialog.vue 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/mdm/unit/index.ts
@@ -1,6 +1,6 @@
import type { PageParam, PageResult } from '#/packages/effects/request/src';
import type { PageParam, PageResult } from "#/packages/effects/request/src";
import { requestClient } from '#/api/request';
import { requestClient } from "#/api/request";
export namespace MdmUnitApi {
  /** 计量单位信息 */
@@ -18,7 +18,7 @@
/** 查询计量单位分页 */
export function getUnitPage(params: PageParam) {
  return requestClient.get<PageResult<MdmUnitApi.Unit>>('/mdm/unit/page', {
  return requestClient.get<PageResult<MdmUnitApi.Unit>>("/mdm/unit/page", {
    params,
  });
}
@@ -35,12 +35,12 @@
/** 新增计量单位 */
export function createUnit(data: MdmUnitApi.Unit) {
  return requestClient.post('/mdm/unit/create', data);
  return requestClient.post("/mdm/unit/create", data);
}
/** 修改计量单位 */
export function updateUnit(data: MdmUnitApi.Unit) {
  return requestClient.put('/mdm/unit/update', data);
  return requestClient.put("/mdm/unit/update", data);
}
/** 删除计量单位 */
src/api/mes/pro/processdesign/parameter/index.ts
@@ -6,22 +6,25 @@
  /** 工艺参数 */
  export interface Parameter {
    id?: number;
    code?: string;
    name?: string;
    type?: number;
    unit?: string;
    requiredFlag?: boolean;
    dictType?: string;
    apiUrl?: string;
    paramCode?: string;
    paramName?: string;
    paramType?: number;
    unitMeasureId?: number;
    unitMeasureName?: string;
    required?: boolean;
    remark?: string;
    createTime?: Date;
  }
}
/** 查询工艺参数分页 */
export function getParameterPage(params: PageParam) {
export function getParameterPage(params: PageParam & {
  paramCode?: string;
  paramName?: string;
  paramType?: number;
}) {
  return requestClient.get<PageResult<MesPdParameterApi.Parameter>>(
    '/mes/pro/process-design/parameter/page',
    '/mes/pd/process-param/page',
    { params },
  );
}
@@ -29,21 +32,21 @@
/** 查询工艺参数精简列表 */
export function getParameterSimpleList() {
  return requestClient.get<MesPdParameterApi.Parameter[]>(
    '/mes/pro/process-design/parameter/simple-list',
    '/mes/pd/process-param/simple-list',
  );
}
/** 查询工艺参数详情 */
export function getParameter(id: number) {
  return requestClient.get<MesPdParameterApi.Parameter>(
    `/mes/pro/process-design/parameter/get?id=${id}`,
    `/mes/pd/process-param/get?id=${id}`,
  );
}
/** 新增工艺参数 */
export function createParameter(data: MesPdParameterApi.Parameter) {
  return requestClient.post(
    '/mes/pro/process-design/parameter/create',
    '/mes/pd/process-param/create',
    data,
  );
}
@@ -51,7 +54,7 @@
/** 修改工艺参数 */
export function updateParameter(data: MesPdParameterApi.Parameter) {
  return requestClient.put(
    '/mes/pro/process-design/parameter/update',
    '/mes/pd/process-param/update',
    data,
  );
}
@@ -59,6 +62,14 @@
/** 删除工艺参数 */
export function deleteParameter(id: number) {
  return requestClient.delete(
    `/mes/pro/process-design/parameter/delete?id=${id}`,
    `/mes/pd/process-param/delete?id=${id}`,
  );
}
/** 导出工艺参数 */
export function exportParameterExcel(params: any) {
  return requestClient.download(
    '/mes/pd/process-param/export-excel',
    { params },
  );
}
src/api/mes/pro/processdesign/template/index.ts
@@ -1,53 +1,65 @@
import type { PageParam, PageResult } from '../../../../../packages/effects/request/src';
import type { PageParam, PageResult } from "../../../../../packages/effects/request/src";
import { requestClient } from '#/api/request';
import { requestClient } from "#/api/request";
export namespace MesPdTemplateApi {
  /** 模板明细 */
  export interface TemplateDetail {
    id?: number;
    templateId?: number;
    processParamId?: number;
    paramCode?: string;
    paramName?: string;
    paramType?: number;
    unitMeasureName?: string;
    required?: boolean;
    remark?: string;
  }
  /** 工艺参数模板 */
  export interface Template {
    id?: number;
    name?: string;
    type?: number;
    parameterIds?: number[];
    createUser?: string;
    templateCode?: string;
    templateName?: string;
    templateType?: number;
    remark?: string;
    details?: TemplateDetail[];
    createTime?: Date;
  }
}
/** 查询工艺参数模板分页 */
export function getTemplatePage(params: PageParam) {
  return requestClient.get<PageResult<MesPdTemplateApi.Template>>(
    '/mes/pro/process-design/template/page',
    { params },
  );
export function getTemplatePage(
  params: PageParam & {
    templateCode?: string;
    templateName?: string;
    templateType?: number;
  },
) {
  return requestClient.get<PageResult<MesPdTemplateApi.Template>>("/mes/pd/process-param-template/page", { params });
}
/** 查询工艺参数模板详情 */
export function getTemplate(id: number) {
  return requestClient.get<MesPdTemplateApi.Template>(
    `/mes/pro/process-design/template/get?id=${id}`,
  );
  return requestClient.get<MesPdTemplateApi.Template>(`/mes/pd/process-param-template/get?id=${id}`);
}
/** 新增工艺参数模板 */
export function createTemplate(data: MesPdTemplateApi.Template) {
  return requestClient.post(
    '/mes/pro/process-design/template/create',
    data,
  );
  return requestClient.post("/mes/pd/process-param-template/create", data);
}
/** 修改工艺参数模板 */
export function updateTemplate(data: MesPdTemplateApi.Template) {
  return requestClient.put(
    '/mes/pro/process-design/template/update',
    data,
  );
  return requestClient.put("/mes/pd/process-param-template/update", data);
}
/** 删除工艺参数模板 */
export function deleteTemplate(id: number) {
  return requestClient.delete(
    `/mes/pro/process-design/template/delete?id=${id}`,
  );
  return requestClient.delete(`/mes/pd/process-param-template/delete?id=${id}`);
}
/** 导出工艺参数模板 */
export function exportTemplateExcel(params: any) {
  return requestClient.download("/mes/pd/process-param-template/export-excel", { params });
}
src/views/mes/process-design/parameter/data.ts
@@ -1,113 +1,96 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { MesPdParameterApi } from '#/api/mes/pro/processdesign/parameter';
import type { VbenFormSchema } from "#/adapter/form";
import type { VxeTableGridOptions } from "#/adapter/vxe-table";
import type { MesPdParameterApi } from "#/api/mes/pro/processdesign/parameter";
import { DICT_TYPE } from '../../../../packages/constants/src';
import { getDictOptions } from '../../../../packages/effects/hooks/src';
import { DICT_TYPE } from "../../../../packages/constants/src";
import { getDictOptions } from "../../../../packages/effects/hooks/src";
import { z } from '#/adapter/form';
/** 参数类型 - 下拉选项的值 */
const PARAM_TYPE_SELECT = 3;
import { z } from "#/adapter/form";
import { getUnitPage } from "#/api/mdm/unit";
/** 表单类型 */
export type FormType = 'create' | 'detail' | 'update';
export type FormType = "create" | "detail" | "update";
/** 新增/修改工艺参数的表单 */
export function useFormSchema(): VbenFormSchema[] {
  return [
    {
      fieldName: 'id',
      component: 'Input',
      fieldName: "id",
      component: "Input",
      dependencies: {
        triggerFields: [''],
        triggerFields: [""],
        show: () => false,
      },
    },
    {
      fieldName: 'code',
      label: '参数编码',
      component: 'Input',
      fieldName: "paramCode",
      label: "参数编码",
      component: "Input",
      componentProps: {
        maxLength: 64,
        placeholder: '请输入参数编码',
        placeholder: "参数编码自动生成",
        disabled: true,
      },
      rules: z.string().min(1, '参数编码不能为空').max(64),
    },
    {
      fieldName: 'name',
      label: '参数名称',
      component: 'Input',
      fieldName: "paramName",
      label: "参数名称",
      component: "Input",
      componentProps: {
        maxLength: 100,
        placeholder: '请输入参数名称',
        placeholder: "请输入参数名称",
      },
      rules: z.string().min(1, '参数名称不能为空').max(100),
      rules: z.string().min(1, "参数名称不能为空").max(100),
    },
    {
      fieldName: 'type',
      label: '参数类型',
      component: 'Select',
      fieldName: "paramType",
      label: "参数类型",
      component: "Select",
      componentProps: {
        allowClear: true,
        options: getDictOptions(DICT_TYPE.MES_PD_PARAM_TYPE, 'number'),
        placeholder: '请选择参数类型',
        options: getDictOptions(DICT_TYPE.MES_PD_PARAM_TYPE, "number"),
        placeholder: "请选择参数类型",
      },
      rules: 'selectRequired',
      rules: "selectRequired",
    },
    {
      fieldName: 'unit',
      label: '单位',
      component: 'Input',
      fieldName: "unitMeasureId",
      label: "计量单位",
      component: "ApiSelect",
      componentProps: {
        maxLength: 20,
        placeholder: '请输入单位',
        allowClear: true,
        api: async () => {
          const result = await getUnitPage({ pageNo: 1, pageSize: 100 });
          return result.list.map(item => ({
            label: item.name || "",
            value: item.id || 0,
          }));
        },
        labelField: "label",
        valueField: "value",
        placeholder: "请选择计量单位",
        showSearch: true,
        filterOption: true,
      },
    },
    {
      fieldName: 'requiredFlag',
      label: '是否必填',
      component: 'Switch',
      fieldName: "required",
      label: "是否必填",
      component: "Switch",
      componentProps: {
        checkedChildren: '是',
        unCheckedChildren: '否',
        checkedChildren: "是",
        unCheckedChildren: "否",
      },
      rules: z.boolean().default(false),
    },
    {
      fieldName: 'dictType',
      label: '字典类型',
      component: 'Input',
      componentProps: {
        maxLength: 64,
        placeholder: '请输入字典类型(下拉选项时配置)',
      },
      dependencies: {
        triggerFields: ['type'],
        show: (values) => values?.type === PARAM_TYPE_SELECT,
      },
    },
    {
      fieldName: 'apiUrl',
      label: '接口地址',
      component: 'Input',
      fieldName: "remark",
      label: "备注",
      component: "Textarea",
      formItemClass: "col-span-2",
      componentProps: {
        maxLength: 250,
        placeholder: '请输入接口地址(下拉选项时配置)',
      },
      dependencies: {
        triggerFields: ['type'],
        show: (values) => values?.type === PARAM_TYPE_SELECT,
      },
    },
    {
      fieldName: 'remark',
      label: '备注',
      component: 'Textarea',
      formItemClass: 'col-span-2',
      componentProps: {
        maxLength: 250,
        placeholder: '请输入备注',
        placeholder: "请输入备注",
        rows: 3,
      },
    },
@@ -118,79 +101,79 @@
export function useGridFormSchema(): VbenFormSchema[] {
  return [
    {
      fieldName: 'code',
      label: '参数编码',
      component: 'Input',
      fieldName: "paramCode",
      label: "参数编码",
      component: "Input",
      componentProps: {
        allowClear: true,
        placeholder: '请输入参数编码',
        placeholder: "请输入参数编码",
      },
    },
    {
      fieldName: 'name',
      label: '参数名称',
      component: 'Input',
      fieldName: "paramName",
      label: "参数名称",
      component: "Input",
      componentProps: {
        allowClear: true,
        placeholder: '请输入参数名称',
        placeholder: "请输入参数名称",
      },
    },
    {
      fieldName: 'type',
      label: '参数类型',
      component: 'Select',
      fieldName: "paramType",
      label: "参数类型",
      component: "Select",
      componentProps: {
        allowClear: true,
        options: getDictOptions(DICT_TYPE.MES_PD_PARAM_TYPE, 'number'),
        placeholder: '请选择参数类型',
        options: getDictOptions(DICT_TYPE.MES_PD_PARAM_TYPE, "number"),
        placeholder: "请选择参数类型",
      },
    },
  ];
}
/** 列表的字段 */
export function useGridColumns(): VxeTableGridOptions<MesPdParameterApi.Parameter>['columns'] {
export function useGridColumns(): VxeTableGridOptions<MesPdParameterApi.Parameter>["columns"] {
  return [
    {
      type: 'seq',
      title: '序号',
      type: "seq",
      title: "序号",
      width: 60,
      align: 'center',
      align: "center",
    },
    { field: 'code', title: '参数编码', minWidth: 150 },
    { field: 'name', title: '参数名称', minWidth: 180 },
    { field: "paramCode", title: "参数编码", minWidth: 150 },
    { field: "paramName", title: "参数名称", minWidth: 180 },
    {
      field: 'type',
      title: '参数类型',
      field: "paramType",
      title: "参数类型",
      width: 120,
      cellRender: {
        name: 'CellDict',
        name: "CellDict",
        props: { type: DICT_TYPE.MES_PD_PARAM_TYPE },
      },
    },
    { field: 'unit', title: '单位', width: 80 },
    { field: "unitMeasureName", title: "单位", width: 80 },
    {
      field: 'requiredFlag',
      title: '是否必填',
      field: "required",
      title: "是否必填",
      width: 90,
      cellRender: {
        name: 'CellDict',
        name: "CellDict",
        props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING },
      },
    },
    { field: 'remark', title: '备注', minWidth: 180 },
    { field: "remark", title: "备注", minWidth: 180 },
    {
      field: 'createTime',
      title: '创建时间',
      field: "createTime",
      title: "创建时间",
      width: 180,
      formatter: 'formatDateTime',
      formatter: "formatDateTime",
    },
    {
      title: '操作',
      title: "操作",
      width: 150,
      fixed: 'right',
      fixed: "right",
      slots: {
        default: 'actions',
        default: "actions",
      },
    },
  ];
src/views/mes/process-design/parameter/index.vue
@@ -10,8 +10,10 @@
import {
  deleteParameter,
  getParameterPage,
  exportParameterExcel,
} from '#/api/mes/pro/processdesign/parameter';
import { $t } from '#/locales';
import { downloadFileFromBlobPart } from '../../../../packages/utils/src';
import { useGridColumns, useGridFormSchema } from './data';
import Form from './modules/form.vue';
@@ -44,16 +46,23 @@
/** 删除工艺参数 */
async function handleDelete(row: MesPdParameterApi.Parameter) {
  const hideLoading = message.loading({
    content: $t('ui.actionMessage.deleting', [row.name]),
    content: $t('ui.actionMessage.deleting', [row.paramName]),
    duration: 0,
  });
  try {
    await deleteParameter(row.id!);
    message.success($t('ui.actionMessage.deleteSuccess', [row.name]));
    message.success($t('ui.actionMessage.deleteSuccess', [row.paramName]));
    handleRefresh();
  } finally {
    hideLoading();
  }
}
/** 导出工艺参数 */
async function handleExport() {
  const formValues = await gridApi.formApi.getValues();
  const data = await exportParameterExcel(formValues);
  downloadFileFromBlobPart({ fileName: '工艺参数.xlsx', source: data });
}
const [Grid, gridApi] = useVbenVxeGrid({
@@ -100,11 +109,18 @@
              auth: ['mes:pd:parameter:create'],
              onClick: handleCreate,
            },
            {
              label: $t('ui.actionTitle.export'),
              type: 'primary',
              icon: ACTION_ICON.DOWNLOAD,
              auth: ['mes:pd:parameter:export'],
              onClick: handleExport,
            },
          ]"
        />
      </template>
      <template #code="{ row }">
        <Button type="link" @click="handleDetail(row)">{{ row.code }}</Button>
      <template #paramCode="{ row }">
        <Button type="link" @click="handleDetail(row)">{{ row.paramCode }}</Button>
      </template>
      <template #actions="{ row }">
        <TableAction
@@ -123,7 +139,7 @@
              icon: ACTION_ICON.DELETE,
              auth: ['mes:pd:parameter:delete'],
              popConfirm: {
                title: $t('ui.actionMessage.deleteConfirm', [row.name]),
                title: $t('ui.actionMessage.deleteConfirm', [row.paramName]),
                confirm: handleDelete.bind(null, row),
              },
            },
src/views/mes/process-design/template/data.ts
@@ -1,64 +1,65 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { MesPdTemplateApi } from '#/api/mes/pro/processdesign/template';
import type { VbenFormSchema } from "#/adapter/form";
import type { VxeTableGridOptions } from "#/adapter/vxe-table";
import type { MesPdTemplateApi } from "#/api/mes/pro/processdesign/template";
import { DICT_TYPE } from '../../../../packages/constants/src';
import { getDictOptions } from '../../../../packages/effects/hooks/src';
import { DICT_TYPE } from "../../../../packages/constants/src";
import { getDictOptions } from "../../../../packages/effects/hooks/src";
import { z } from '#/adapter/form';
import { z } from "#/adapter/form";
/** 表单类型 */
export type FormType = 'create' | 'detail' | 'update';
export type FormType = "create" | "detail" | "update";
/** 新增/修改工艺参数模板的表单 */
export function useFormSchema(): VbenFormSchema[] {
  return [
    {
      fieldName: 'id',
      component: 'Input',
      fieldName: "id",
      component: "Input",
      dependencies: {
        triggerFields: [''],
        triggerFields: [""],
        show: () => false,
      },
    },
    {
      fieldName: 'name',
      label: '模板名称',
      component: 'Input',
      fieldName: "templateCode",
      label: "模板编码",
      component: "Input",
      componentProps: {
        maxLength: 64,
        placeholder: "模板编码自动生成",
        disabled: true,
      },
    },
    {
      fieldName: "templateName",
      label: "模板名称",
      component: "Input",
      componentProps: {
        maxLength: 100,
        placeholder: '请输入模板名称',
        placeholder: "请输入模板名称",
      },
      rules: z.string().min(1, '模板名称不能为空').max(100),
      rules: z.string().min(1, "模板名称不能为空").max(100),
    },
    {
      fieldName: 'type',
      label: '模板类型',
      component: 'Select',
      fieldName: "templateType",
      label: "模板类型",
      component: "Select",
      componentProps: {
        allowClear: true,
        options: getDictOptions(DICT_TYPE.MES_PD_TEMPLATE_TYPE, 'number'),
        placeholder: '请选择模板类型',
        options: getDictOptions(DICT_TYPE.MES_PD_TEMPLATE_TYPE, "number"),
        placeholder: "请选择模板类型",
      },
      rules: 'selectRequired',
      rules: "selectRequired",
    },
    {
      fieldName: 'parameterIds',
      label: '关联参数',
      component: 'Input',
      dependencies: {
        triggerFields: [''],
        show: () => false,
      },
    },
    {
      fieldName: 'remark',
      label: '备注',
      component: 'Textarea',
      formItemClass: 'col-span-2',
      fieldName: "remark",
      label: "备注",
      component: "Textarea",
      formItemClass: "col-span-2",
      componentProps: {
        maxLength: 250,
        placeholder: '请输入备注',
        placeholder: "请输入备注",
        rows: 3,
      },
    },
@@ -69,59 +70,69 @@
export function useGridFormSchema(): VbenFormSchema[] {
  return [
    {
      fieldName: 'name',
      label: '模板名称',
      component: 'Input',
      fieldName: "templateCode",
      label: "模板编码",
      component: "Input",
      componentProps: {
        allowClear: true,
        placeholder: '请输入模板名称',
        placeholder: "请输入模板编码",
      },
    },
    {
      fieldName: 'type',
      label: '模板类型',
      component: 'Select',
      fieldName: "templateName",
      label: "模板名称",
      component: "Input",
      componentProps: {
        allowClear: true,
        options: getDictOptions(DICT_TYPE.MES_PD_TEMPLATE_TYPE, 'number'),
        placeholder: '请选择模板类型',
        placeholder: "请输入模板名称",
      },
    },
    {
      fieldName: "templateType",
      label: "模板类型",
      component: "Select",
      componentProps: {
        allowClear: true,
        options: getDictOptions(DICT_TYPE.MES_PD_TEMPLATE_TYPE, "number"),
        placeholder: "请选择模板类型",
      },
    },
  ];
}
/** 列表的字段 */
export function useGridColumns(): VxeTableGridOptions<MesPdTemplateApi.Template>['columns'] {
export function useGridColumns(): VxeTableGridOptions<MesPdTemplateApi.Template>["columns"] {
  return [
    {
      type: 'seq',
      title: '序号',
      type: "seq",
      title: "序号",
      width: 60,
      align: 'center',
      align: "center",
    },
    { field: 'name', title: '模板名称', minWidth: 180 },
    { field: "templateCode", title: "模板编码", minWidth: 150 },
    { field: "templateName", title: "模板名称", minWidth: 180 },
    {
      field: 'type',
      title: '模板类型',
      field: "templateType",
      title: "模板类型",
      width: 120,
      cellRender: {
        name: 'CellDict',
        name: "CellDict",
        props: { type: DICT_TYPE.MES_PD_TEMPLATE_TYPE },
      },
    },
    { field: 'createUser', title: '创建人', width: 120 },
    { field: "remark", title: "备注", minWidth: 180 },
    {
      field: 'createTime',
      title: '创建时间',
      field: "createTime",
      title: "创建时间",
      width: 180,
      formatter: 'formatDateTime',
      formatter: "formatDateTime",
    },
    {
      title: '操作',
      width: 150,
      fixed: 'right',
      title: "操作",
      width: 240,
      fixed: "right",
      slots: {
        default: 'actions',
        default: "actions",
      },
    },
  ];
src/views/mes/process-design/template/index.vue
@@ -1,98 +1,107 @@
<script lang="ts" setup>
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { MesPdTemplateApi } from '#/api/mes/pro/processdesign/template';
  import type { VxeTableGridOptions } from "#/adapter/vxe-table";
  import type { MesPdTemplateApi } from "#/api/mes/pro/processdesign/template";
import { Page, useVbenModal } from '../../../../packages/effects/common-ui/src';
  import { Page, useVbenModal } from "../../../../packages/effects/common-ui/src";
import { Button, message } from 'ant-design-vue';
  import { Button, message } from "ant-design-vue";
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import {
  deleteTemplate,
  getTemplatePage,
} from '#/api/mes/pro/processdesign/template';
import { $t } from '#/locales';
  import { ACTION_ICON, TableAction, useVbenVxeGrid } from "#/adapter/vxe-table";
  import {
    deleteTemplate,
    getTemplatePage,
    exportTemplateExcel,
  } from "#/api/mes/pro/processdesign/template";
  import { $t } from "#/locales";
  import { downloadFileFromBlobPart } from "../../../../packages/utils/src";
import { useGridColumns, useGridFormSchema } from './data';
import Form from './modules/form.vue';
  import { useGridColumns, useGridFormSchema } from "./data";
  import Form from "./modules/form.vue";
const [FormModal, formModalApi] = useVbenModal({
  connectedComponent: Form,
  destroyOnClose: true,
});
/** 刷新表格 */
function handleRefresh() {
  gridApi.query();
}
/** 创建工艺参数模板 */
function handleCreate() {
  formModalApi.setData({ formType: 'create' }).open();
}
/** 编辑工艺参数模板 */
function handleEdit(row: MesPdTemplateApi.Template) {
  formModalApi.setData({ id: row.id, formType: 'update' }).open();
}
/** 查看工艺参数模板详情 */
function handleDetail(row: MesPdTemplateApi.Template) {
  formModalApi.setData({ id: row.id, formType: 'detail' }).open();
}
/** 删除工艺参数模板 */
async function handleDelete(row: MesPdTemplateApi.Template) {
  const hideLoading = message.loading({
    content: $t('ui.actionMessage.deleting', [row.name]),
    duration: 0,
  const [FormModal, formModalApi] = useVbenModal({
    connectedComponent: Form,
    destroyOnClose: true,
  });
  try {
    await deleteTemplate(row.id!);
    message.success($t('ui.actionMessage.deleteSuccess', [row.name]));
    handleRefresh();
  } finally {
    hideLoading();
  }
}
const [Grid, gridApi] = useVbenVxeGrid({
  formOptions: {
    schema: useGridFormSchema(),
  },
  gridOptions: {
    columns: useGridColumns(),
    height: 'auto',
    keepSource: true,
    proxyConfig: {
      ajax: {
        query: async ({ page }, formValues) => {
          return await getTemplatePage({
            pageNo: page.currentPage,
            pageSize: page.pageSize,
            ...formValues,
          });
  /** 刷新表格 */
  function handleRefresh() {
    gridApi.query();
  }
  /** 创建工艺参数模板 */
  function handleCreate() {
    formModalApi.setData({ formType: "create" }).open();
  }
  /** 编辑工艺参数模板 */
  function handleEdit(row: MesPdTemplateApi.Template) {
    formModalApi.setData({ id: row.id, formType: "update" }).open();
  }
  /** 查看工艺参数模板详情 */
  function handleDetail(row: MesPdTemplateApi.Template) {
    formModalApi.setData({ id: row.id, formType: "detail" }).open();
  }
  /** 删除工艺参数模板 */
  async function handleDelete(row: MesPdTemplateApi.Template) {
    const hideLoading = message.loading({
      content: $t("ui.actionMessage.deleting", [row.templateName]),
      duration: 0,
    });
    try {
      await deleteTemplate(row.id!);
      message.success($t("ui.actionMessage.deleteSuccess", [row.templateName]));
      handleRefresh();
    } finally {
      hideLoading();
    }
  }
  /** 导出工艺参数模板 */
  async function handleExport() {
    const formValues = await gridApi.formApi.getValues();
    const data = await exportTemplateExcel(formValues);
    downloadFileFromBlobPart({ fileName: "工艺参数模板.xlsx", source: data });
  }
  const [Grid, gridApi] = useVbenVxeGrid({
    formOptions: {
      schema: useGridFormSchema(),
    },
    gridOptions: {
      columns: useGridColumns(),
      height: "auto",
      keepSource: true,
      proxyConfig: {
        ajax: {
          query: async ({ page }, formValues) => {
            return await getTemplatePage({
              pageNo: page.currentPage,
              pageSize: page.pageSize,
              ...formValues,
            });
          },
        },
      },
    },
    rowConfig: {
      isHover: true,
      keyField: 'id',
    },
    toolbarConfig: {
      refresh: true,
      search: true,
    },
  } as VxeTableGridOptions<MesPdTemplateApi.Template>,
});
      rowConfig: {
        isHover: true,
        keyField: "id",
      },
      toolbarConfig: {
        refresh: true,
        search: true,
      },
    } as VxeTableGridOptions<MesPdTemplateApi.Template>,
  });
</script>
<template>
  <Page auto-content-height><FormModal @success="handleRefresh" />
  <Page auto-content-height>
    <FormModal @success="handleRefresh" />
    <Grid table-title="工艺参数模板列表">
      <template #toolbar-tools>
        <TableAction
          :actions="[
        <TableAction :actions="[
            {
              label: $t('ui.actionTitle.create', ['模板']),
              type: 'primary',
@@ -100,15 +109,27 @@
              auth: ['mes:pd:template:create'],
              onClick: handleCreate,
            },
          ]"
        />
            {
              label: $t('ui.actionTitle.export'),
              type: 'primary',
              icon: ACTION_ICON.DOWNLOAD,
              auth: ['mes:pd:template:export'],
              onClick: handleExport,
            },
          ]" />
      </template>
      <template #name="{ row }">
        <Button type="link" @click="handleDetail(row)">{{ row.name }}</Button>
      <template #templateCode="{ row }">
        <Button type="link"
                @click="handleDetail(row)">{{ row.templateCode }}</Button>
      </template>
      <template #actions="{ row }">
        <TableAction
          :actions="[
        <TableAction :actions="[
            {
              label: $t('common.detail'),
              type: 'link',
              icon: ACTION_ICON.VIEW,
              onClick: handleDetail.bind(null, row),
            },
            {
              label: $t('common.edit'),
              type: 'link',
@@ -123,12 +144,11 @@
              icon: ACTION_ICON.DELETE,
              auth: ['mes:pd:template:delete'],
              popConfirm: {
                title: $t('ui.actionMessage.deleteConfirm', [row.name]),
                title: $t('ui.actionMessage.deleteConfirm', [row.templateName]),
                confirm: handleDelete.bind(null, row),
              },
            },
          ]"
        />
          ]" />
      </template>
    </Grid>
  </Page>
src/views/mes/process-design/template/modules/form.vue
@@ -1,173 +1,206 @@
<script lang="ts" setup>
import type { FormType } from '../data';
  import type { FormType } from "../data";
import type { MesPdParameterApi } from '#/api/mes/pro/processdesign/parameter';
import type { MesPdTemplateApi } from '#/api/mes/pro/processdesign/template';
  import type { MesPdParameterApi } from "#/api/mes/pro/processdesign/parameter";
  import type { MesPdTemplateApi } from "#/api/mes/pro/processdesign/template";
import { computed, ref } from 'vue';
  import { computed, ref } from "vue";
import { useVbenModal } from '../../../../../packages/effects/common-ui/src';
  import { useVbenModal } from "../../../../../packages/effects/common-ui/src";
import { Button, message, Tag } from 'ant-design-vue';
  import { Button, message, Switch, Input } from "ant-design-vue";
import { useVbenForm } from '#/adapter/form';
import {
  createTemplate,
  getTemplate,
  updateTemplate,
} from '#/api/mes/pro/processdesign/template';
import { $t } from '#/locales';
  import { useVbenForm } from "#/adapter/form";
  import {
    createTemplate,
    getTemplate,
    updateTemplate,
  } from "#/api/mes/pro/processdesign/template";
  import { $t } from "#/locales";
import { useFormSchema } from '../data';
import ParameterSelectDialog from './parameter-select-dialog.vue';
  import { useFormSchema } from "../data";
  import ParameterSelectDialog from "./parameter-select-dialog.vue";
const emit = defineEmits(['success']);
const formType = ref<FormType>('create');
const formData = ref<MesPdTemplateApi.Template>();
  const emit = defineEmits(["success"]);
  const formType = ref<FormType>("create");
  const formData = ref<MesPdTemplateApi.Template>();
/** 已选参数列表(用于页面展示) */
const selectedParameters = ref<MesPdParameterApi.Parameter[]>([]);
const parameterSelectDialogRef = ref<InstanceType<typeof ParameterSelectDialog>>();
  /** 已选参数列表(用于页面展示) */
  const selectedDetails = ref<MesPdTemplateApi.TemplateDetail[]>([]);
  const parameterSelectDialogRef =
    ref<InstanceType<typeof ParameterSelectDialog>>();
const isDetail = computed(() => formType.value === 'detail');
const getTitle = computed(() => {
  if (formType.value === 'detail') {
    return $t('ui.actionTitle.detail', ['工艺参数模板']);
  }
  return formType.value === 'update'
    ? $t('ui.actionTitle.edit', ['工艺参数模板'])
    : $t('ui.actionTitle.create', ['工艺参数模板']);
});
  const isDetail = computed(() => formType.value === "detail");
  const getTitle = computed(() => {
    if (formType.value === "detail") {
      return $t("ui.actionTitle.detail", ["工艺参数模板"]);
    }
    return formType.value === "update"
      ? $t("ui.actionTitle.edit", ["工艺参数模板"])
      : $t("ui.actionTitle.create", ["工艺参数模板"]);
  });
const [Form, formApi] = useVbenForm({
  commonConfig: {
    componentProps: {
      class: 'w-full',
  const [Form, formApi] = useVbenForm({
    commonConfig: {
      componentProps: {
        class: "w-full",
      },
      formItemClass: "col-span-1",
      labelWidth: 100,
    },
    formItemClass: 'col-span-1',
    labelWidth: 100,
  },
  layout: 'horizontal',
  schema: [],
  showDefaultActions: false,
  wrapperClass: 'grid-cols-2',
});
    layout: "horizontal",
    schema: [],
    showDefaultActions: false,
    wrapperClass: "grid-cols-2",
  });
/** 打开工艺参数选择弹窗 */
function handleSelectParameters() {
  parameterSelectDialogRef.value?.open(
    selectedParameters.value
      .map((p) => p.id)
      .filter((id): id is number => id !== undefined),
  );
}
  /** 打开工艺参数选择弹窗 */
  function handleSelectParameters() {
    parameterSelectDialogRef.value?.open(
      selectedDetails.value
        .map(d => d.processParamId)
        .filter((id): id is number => id !== undefined)
    );
  }
/** 接收选中的参数 */
function onParametersSelected(rows: MesPdParameterApi.Parameter[]) {
  selectedParameters.value = rows;
}
  /** 接收选中的参数 */
  function onParametersSelected(rows: MesPdParameterApi.Parameter[]) {
    selectedDetails.value = rows.map(row => ({
      processParamId: row.id,
      paramCode: row.paramCode,
      paramName: row.paramName,
      paramType: row.paramType,
      unitMeasureName: row.unitMeasureName,
      required: row.required,
      remark: row.remark,
    }));
  }
/** 移除已选参数 */
function removeParameter(param: MesPdParameterApi.Parameter) {
  selectedParameters.value = selectedParameters.value.filter(
    (p) => p.id !== param.id,
  );
}
  /** 移除已选参数 */
  function removeParameter(index: number) {
    selectedDetails.value.splice(index, 1);
  }
const [Modal, modalApi] = useVbenModal({
  async onConfirm() {
    if (isDetail.value) {
      await modalApi.close();
      return;
    }
    const { valid } = await formApi.validate();
    if (!valid) {
      return;
    }
    if (selectedParameters.value.length === 0) {
      message.warning('请至少选择一个工艺参数');
      return;
    }
    modalApi.lock();
    const data = (await formApi.getValues()) as MesPdTemplateApi.Template;
    data.parameterIds = selectedParameters.value
      .map((p) => p.id)
      .filter((id): id is number => id !== undefined);
    try {
      await (formData.value?.id ? updateTemplate(data) : createTemplate(data));
      await modalApi.close();
      emit('success');
      message.success($t('ui.actionMessage.operationSuccess'));
    } finally {
      modalApi.unlock();
    }
  },
  async onOpenChange(isOpen: boolean) {
    if (!isOpen) {
      formData.value = undefined;
      selectedParameters.value = [];
      return;
    }
    formApi.setState({ schema: useFormSchema() });
    const data = modalApi.getData<{ formType: FormType; id?: number }>();
    formType.value = data.formType;
    formApi.setDisabled(formType.value === 'detail');
    modalApi.setState({ showConfirmButton: formType.value !== 'detail' });
    if (!data?.id) {
      return;
    }
    modalApi.lock();
    try {
      formData.value = await getTemplate(data.id);
      await formApi.setValues(formData.value);
      // 回显已选参数(从详情接口返回的参数列表中获取)
      if (formData.value.parameterIds) {
        // parameterIds 已由后端返回,selectedParameters 在详情模式下展示
  const [Modal, modalApi] = useVbenModal({
    async onConfirm() {
      if (isDetail.value) {
        await modalApi.close();
        return;
      }
    } finally {
      modalApi.unlock();
    }
  },
});
      const { valid } = await formApi.validate();
      if (!valid) {
        return;
      }
      if (selectedDetails.value.length === 0) {
        message.warning("请至少选择一个工艺参数");
        return;
      }
      modalApi.lock();
      const data = (await formApi.getValues()) as MesPdTemplateApi.Template;
      data.details = selectedDetails.value.map(d => ({
        ...d,
        processParamId: d.processParamId,
        required: d.required,
        remark: d.remark,
      }));
      try {
        await (formData.value?.id ? updateTemplate(data) : createTemplate(data));
        await modalApi.close();
        emit("success");
        message.success($t("ui.actionMessage.operationSuccess"));
      } finally {
        modalApi.unlock();
      }
    },
    async onOpenChange(isOpen: boolean) {
      if (!isOpen) {
        formData.value = undefined;
        selectedDetails.value = [];
        return;
      }
      formApi.setState({ schema: useFormSchema() });
      const data = modalApi.getData<{ formType: FormType; id?: number }>();
      formType.value = data.formType;
      formApi.setDisabled(formType.value === "detail");
      modalApi.setState({ showConfirmButton: formType.value !== "detail" });
      if (!data?.id) {
        return;
      }
      modalApi.lock();
      try {
        formData.value = await getTemplate(data.id);
        await formApi.setValues(formData.value);
        // 回显已选参数(从详情接口返回的参数列表中获取)
        if (formData.value.details) {
          selectedDetails.value = [...formData.value.details];
        }
      } finally {
        modalApi.unlock();
      }
    },
  });
</script>
<template>
  <Modal :title="getTitle" class="w-4/5">
  <Modal :title="getTitle"
         class="w-4/5">
    <Form class="mx-4" />
    <!-- 关联参数选择区域 -->
    <!-- 模板明细区域 -->
    <div class="mx-4 mt-4">
      <div class="mb-2 flex items-center justify-between">
        <span class="text-sm font-medium">关联工艺参数</span>
        <Button
          v-if="!isDetail"
          type="primary"
          size="small"
          @click="handleSelectParameters"
        >
          选择参数
        <span class="text-sm font-medium">模板明细</span>
        <Button v-if="!isDetail"
                type="primary"
                size="small"
                @click="handleSelectParameters">
          添加参数
        </Button>
      </div>
      <div
        v-if="selectedParameters.length > 0"
        class="min-h-10 rounded border border-gray-200 p-2"
      >
        <Tag
          v-for="param in selectedParameters"
          :key="param.id"
          :closable="!isDetail"
          class="mb-1 mr-1"
          @close="removeParameter(param)"
        >
          {{ param.name }}({{ param.code }})
        </Tag>
      <div v-if="selectedDetails.length > 0"
           class="rounded border border-gray-200">
        <div class="grid grid-cols-12 gap-2 border-b border-gray-200 bg-gray-50 p-2 text-xs font-medium">
          <div class="col-span-3">参数名称</div>
          <div class="col-span-2">参数编码</div>
          <div class="col-span-2">单位</div>
          <div class="col-span-2 text-center">是否必填</div>
          <div class="col-span-2">备注</div>
          <div v-if="!isDetail"
               class="col-span-1 text-center">操作</div>
        </div>
        <div v-for="(detail, index) in selectedDetails"
             :key="detail.processParamId || index"
             class="grid grid-cols-12 gap-2 border-b border-gray-100 p-2">
          <div class="col-span-3 text-sm">{{ detail.paramName }}</div>
          <div class="col-span-2 text-sm text-gray-500">{{ detail.paramCode }}</div>
          <div class="col-span-2 text-sm">{{ detail.unitMeasureName }}</div>
          <div class="col-span-2 flex items-center justify-center">
            <Switch v-model:checked="detail.required"
                    :disabled="isDetail"
                    size="small" />
          </div>
          <div class="col-span-2">
            <Input v-model:value="detail.remark"
                   :disabled="isDetail"
                   placeholder="备注"
                   size="small" />
          </div>
          <div v-if="!isDetail"
               class="col-span-1 flex items-center justify-center">
            <Button type="text"
                    danger
                    size="small"
                    @click="removeParameter(index)">
              删除
            </Button>
          </div>
        </div>
      </div>
      <div v-else class="rounded border border-dashed border-gray-300 p-4 text-center text-gray-400">
      <div v-else
           class="rounded border border-dashed border-gray-300 p-4 text-center text-gray-400">
        暂未选择参数
      </div>
    </div>
    <ParameterSelectDialog
      ref="parameterSelectDialogRef"
      @selected="onParametersSelected"
    />
    <ParameterSelectDialog ref="parameterSelectDialogRef"
                           @selected="onParametersSelected" />
  </Modal>
</template>
src/views/mes/process-design/template/modules/parameter-select-dialog.vue
@@ -57,7 +57,7 @@
  formOptions: {
    schema: [
      {
        fieldName: 'code',
        fieldName: 'paramCode',
        label: '参数编码',
        component: 'Input',
        componentProps: {
@@ -66,7 +66,7 @@
        },
      },
      {
        fieldName: 'name',
        fieldName: 'paramName',
        label: '参数名称',
        component: 'Input',
        componentProps: {
@@ -79,10 +79,10 @@
  gridOptions: {
    columns: [
      { type: 'checkbox', width: 50 },
      { field: 'code', title: '参数编码', minWidth: 150 },
      { field: 'name', title: '参数名称', minWidth: 180 },
      { field: 'paramCode', title: '参数编码', minWidth: 150 },
      { field: 'paramName', title: '参数名称', minWidth: 180 },
      {
        field: 'type',
        field: 'paramType',
        title: '参数类型',
        width: 120,
        cellRender: {
@@ -90,9 +90,9 @@
          props: { type: DICT_TYPE.MES_PD_PARAM_TYPE },
        },
      },
      { field: 'unit', title: '单位', width: 80 },
      { field: 'unitMeasureName', title: '单位', width: 80 },
      {
        field: 'requiredFlag',
        field: 'required',
        title: '是否必填',
        width: 90,
        cellRender: {