feat(qc): 实现质检模板物料防重复选择功能
- 后端物料分页查询新增 excludeIds 参数以支持排除指定物料
- 前端物料选择组件及弹窗新增 excludeIds 属性并透传至查询接口
- 质检模板物料表单替换为自定义物料选择组件并传入排除列表
- 获取已绑定物料ID并作为排除项以防止重复选择
- 存储记录类型枚举新增巡检业务类型以支持相关记录
| | |
| | | |
| | | /** 物料分页查询参数 */ |
| | | export interface PageParams extends PageParam { |
| | | excludeIds?: string; |
| | | code?: string; |
| | | name?: string; |
| | | categoryId?: number; |
| | |
| | | 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; |
| | | |
| | |
| | | pageNo: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | ...formValues, |
| | | excludeIds: excludeIds.value.length ? excludeIds.value.join(',') : undefined, |
| | | }); |
| | | }, |
| | | }, |
| | |
| | | /** 打开物料选择弹窗 */ |
| | | 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), |
| | |
| | | modelValue?: number; |
| | | placeholder?: string; |
| | | label?: string; |
| | | excludeIds?: number[]; |
| | | }>(), |
| | | { |
| | | allowClear: true, |
| | |
| | | const selectedIds = ( |
| | | props.modelValue === null ? [] : [props.modelValue] |
| | | ) as number[]; |
| | | dialogRef.value?.open(selectedIds, { multiple: false }); |
| | | dialogRef.value?.open(selectedIds, { multiple: false, excludeIds: props.excludeIds }); |
| | | } |
| | | |
| | | /** 回填选中的物料 */ |
| | |
| | | |
| | | 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'; |
| | | |
| | |
| | | } |
| | | |
| | | /** 产品关联子表的表单 */ |
| | | export function useItemFormSchema(): VbenFormSchema[] { |
| | | export function useItemFormSchema(excludeIds: number[] = []): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'id', |
| | |
| | | { |
| | | 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', |
| | |
| | | import { |
| | | createTemplateItem, |
| | | getTemplateItem, |
| | | getTemplateItemPage, |
| | | updateTemplateItem, |
| | | } from '#/api/mes/qc/template/item'; |
| | | import { $t } from '#/locales'; |
| | |
| | | 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(); |
| | | } |