云
3 天以前 77066a73e57b26ff20a2512a6db35f8e08231c11
feat(qc): 实现质检模板物料防重复选择功能

- 后端物料分页查询新增 excludeIds 参数以支持排除指定物料
- 前端物料选择组件及弹窗新增 excludeIds 属性并透传至查询接口
- 质检模板物料表单替换为自定义物料选择组件并传入排除列表
- 获取已绑定物料ID并作为排除项以防止重复选择
- 存储记录类型枚举新增巡检业务类型以支持相关记录
已修改5个文件
48 ■■■■■ 文件已修改
src/api/mdm/item/index.ts 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/basicData/mdm/components/select-dialog.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/basicData/mdm/components/select.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mes/qc/template/data.ts 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mes/qc/template/modules/item-form.vue 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/mdm/item/index.ts
@@ -53,6 +53,7 @@
  /** 物料分页查询参数 */
  export interface PageParams extends PageParam {
    excludeIds?: string;
    code?: string;
    name?: string;
    categoryId?: number;
src/views/basicData/mdm/components/select-dialog.vue
@@ -27,6 +27,7 @@
const selectedRows = ref<MdmItemApi.Item[]>([]); // 已选物料列表
const preSelectedIds = ref<number[]>([]); // 预选物料编号列表
const categoryList = ref<MesMdItemTypeApi.ItemType[]>([]); // 分类列表缓存
const excludeIds = ref<number[]>([]);
const TAG_COLORS = ['green', 'orange', 'blue', 'purple', 'cyan', 'magenta', 'geekblue', 'volcano', 'gold', 'lime'] as const;
@@ -149,6 +150,7 @@
            pageNo: page.currentPage,
            pageSize: page.pageSize,
            ...formValues,
            excludeIds: excludeIds.value.length ? excludeIds.value.join(',') : undefined,
          });
        },
      },
@@ -184,11 +186,12 @@
/** 打开物料选择弹窗 */
async function openModal(
  selectedIds?: number[],
  options?: { multiple?: boolean },
  options?: { multiple?: boolean; excludeIds?: number[] },
) {
  open.value = true;
  multiple.value = options?.multiple ?? true;
  preSelectedIds.value = selectedIds || [];
  excludeIds.value = options?.excludeIds || [];
  await nextTick();
  gridApi.setGridOptions({
    columns: useMdmItemSelectGridColumns(multiple.value),
src/views/basicData/mdm/components/select.vue
@@ -20,6 +20,7 @@
    modelValue?: number;
    placeholder?: string;
    label?: string;
    excludeIds?: number[];
  }>(),
  {
    allowClear: true,
@@ -88,7 +89,7 @@
  const selectedIds = (
    props.modelValue === null ? [] : [props.modelValue]
  ) as number[];
  dialogRef.value?.open(selectedIds, { multiple: false });
  dialogRef.value?.open(selectedIds, { multiple: false, excludeIds: props.excludeIds });
}
/** 回填选中的物料 */
src/views/mes/qc/template/data.ts
@@ -17,7 +17,7 @@
import { z } from '#/adapter/form';
import { generateAutoCode } from '#/api/mes/md/autocode/record';
import { getItemPage } from '#/api/mdm/item';
import { MdmItemSelect } from '#/views/basicData/mdm/components';
import { MdUnitMeasureSelect } from '#/views/mes/md/unitmeasure/components';
import { QcIndicatorSelect } from '#/views/mes/qc/indicator/components';
@@ -408,7 +408,7 @@
}
/** 产品关联子表的表单 */
export function useItemFormSchema(): VbenFormSchema[] {
export function useItemFormSchema(excludeIds: number[] = []): VbenFormSchema[] {
  return [
    {
      fieldName: 'id',
@@ -421,19 +421,11 @@
    {
      fieldName: 'itemId',
      label: '产品物料',
      component: 'ApiSelect',
      component: markRaw(MdmItemSelect),
      componentProps: {
        placeholder: '请选择产品物料',
        allowClear: true,
        showSearch: true,
        api: getItemPage,
        resultField: 'list',
        labelField: 'name',
        valueField: 'id',
        optionRender: (option: any) => {
          const item = option.data;
          return `${item.code} - ${item.name}`;
        },
        excludeIds,
      },
      formItemClass: 'col-span-3',
      rules: 'required',
src/views/mes/qc/template/modules/item-form.vue
@@ -11,6 +11,7 @@
import {
  createTemplateItem,
  getTemplateItem,
  getTemplateItemPage,
  updateTemplateItem,
} from '#/api/mes/qc/template/item';
import { $t } from '#/locales';
@@ -74,14 +75,26 @@
      MesQcTemplateItemApi.TemplateItem & { templateId: number }
    >();
    templateId.value = data.templateId;
    if (!data?.id) {
      return;
    }
    modalApi.lock();
    try {
      formData.value = await getTemplateItem(data.id);
      formData.value = data.id ? await getTemplateItem(data.id) : undefined;
      const boundItems: MesQcTemplateItemApi.TemplateItem[] = [];
      let pageNo = 1;
      const pageSize = 200;
      let total: number;
      do {
        const page = await getTemplateItemPage({ templateId: data.templateId, pageNo, pageSize });
        boundItems.push(...page.list);
        total = page.total;
        pageNo++;
        if (page.list.length === 0) break;
      } while (boundItems.length < total);
      const excludeIds = boundItems
        .filter(item => item.id !== data.id && item.itemId != null)
        .map(item => item.itemId!);
      await formApi.updateSchema(useItemFormSchema(excludeIds));
      // 设置到 values
      await formApi.setValues(formData.value);
      if (formData.value) await formApi.setValues(formData.value);
    } finally {
      modalApi.unlock();
    }