feat(mes): 更新IPQC过程检验功能
- 移除生产工单、生产任务、工位、工序相关字段
- 新增批号字段并设为必填
- 更新数据库表结构包括SQL导出文件和H2测试脚本
- 修改IPQC相关的控制器、服务和数据对象
- 调整AI服务中的查询逻辑适配新的字段结构
- 更新文档说明去除生产相关信息增加批号和MDM物料说明
- 添加批号必填的错误码常量
- 替换MES内部物料服务调用为MDM物料API调用
| | |
| | | sourceDocId?: number; // 来源单据 ID |
| | | sourceLineId?: number; // 来源单据行 ID |
| | | sourceDocCode?: string; // 来源单据编号(关联查询) |
| | | workOrderId?: number; // 生产订单 ID |
| | | workOrderCode?: string; // 订单编号(关联查询) |
| | | workOrderName?: string; // 订单名称(关联查询) |
| | | taskId?: number; // 生产任务 ID |
| | | workstationId?: number; // 工位 ID |
| | | workstationName?: string; // 工位名称(关联查询) |
| | | processId?: number; // 工序 ID |
| | | processName?: string; // 工序名称(关联查询) |
| | | itemId?: number; // 产品物料 ID |
| | | batchCode?: string; // 批号(必填) |
| | | itemId?: number; // 产品物料 ID(MDM 物料) |
| | | itemCode?: string; // 产品物料编码(关联查询) |
| | | itemName?: string; // 产品物料名称(关联查询) |
| | | itemSpecification?: string; // 规格型号(关联查询) |
| | |
| | | sourceDocId?: number; // 来源单据 ID |
| | | sourceLineId?: number; // 来源单据行 ID |
| | | sourceDocCode?: string; // 来源单据编号 |
| | | batchCode?: string; // 批号(仅 IPQC/OQC/RQC 来源有值) |
| | | qcType?: number; // 检验类型(MesQcTypeEnum) |
| | | itemId?: number; // 物料 ID |
| | | itemCode?: string; // 物料编码 |
| | |
| | | return requestClient.delete(`/mes/qc/template/item/delete?id=${id}`); |
| | | } |
| | | |
| | | /** 根据物料或工单/任务和检测种类获取可用质检方案列表 */ |
| | | /** 根据物料和检测种类获取可用质检方案列表(itemId 为 MDM 物料 ID) */ |
| | | export function getTemplateItemOptionList(params: { |
| | | itemId?: number; |
| | | qcType: number; |
| | | taskId?: number; |
| | | workOrderId?: number; |
| | | }) { |
| | | return requestClient.get<MesQcTemplateItemOptionApi.Option[]>( |
| | | '/mes/qc/template/item/list-by-item-and-type', |
| | |
| | | label: '核算', |
| | | type: 'primary', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['hrm:salary-calculation:calculate'], |
| | | auth: ['hrm:salary:calculate'], |
| | | onClick: openCalculateModal, |
| | | }, |
| | | { |
| | | label: '批量确认', |
| | | type: 'primary', |
| | | auth: ['hrm:salary-calculation:confirm'], |
| | | auth: ['hrm:salary:confirm'], |
| | | onClick: handleBatchConfirm, |
| | | }, |
| | | { |
| | | label: '批量保存', |
| | | type: 'primary', |
| | | auth: ['hrm:salary-calculation:save'], |
| | | auth: ['hrm:salary:calculate'], |
| | | onClick: handleBatchSave, |
| | | }, |
| | | { |
| | | label: $t('ui.actionTitle.export'), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.DOWNLOAD, |
| | | auth: ['hrm:salary-calculation:export'], |
| | | auth: ['hrm:salary:export'], |
| | | onClick: handleExport, |
| | | }, |
| | | ]" |
| | |
| | | { |
| | | label: '确认', |
| | | type: 'link', |
| | | auth: ['hrm:salary-calculation:confirm'], |
| | | auth: ['hrm:salary:confirm'], |
| | | ifShow: row.status === 0, |
| | | onClick: handleConfirm.bind(null, row), |
| | | }, |
| | |
| | | label: '删除', |
| | | type: 'link', |
| | | danger: true, |
| | | auth: ['hrm:salary-calculation:delete'], |
| | | auth: ['hrm:salary:delete'], |
| | | ifShow: row.status === 0, |
| | | onClick: handleDelete.bind(null, row), |
| | | }, |
| | | { |
| | | label: '撤销确认', |
| | | type: 'link', |
| | | auth: ['hrm:salary-calculation:confirm'], |
| | | auth: ['hrm:salary:confirm'], |
| | | ifShow: row.status === 10, |
| | | onClick: handleRevoke.bind(null, row), |
| | | }, |
| | |
| | | label: '生成台账', |
| | | type: 'primary', |
| | | icon: ACTION_ICON.ADD, |
| | | auth: ['hrm:salary-payment:generate'], |
| | | auth: ['hrm:salary:generate'], |
| | | onClick: openGenerateModal, |
| | | }, |
| | | { |
| | | label: $t('ui.actionTitle.export'), |
| | | type: 'primary', |
| | | icon: ACTION_ICON.DOWNLOAD, |
| | | auth: ['hrm:salary-payment:export'], |
| | | auth: ['hrm:salary:export'], |
| | | onClick: handleExport, |
| | | }, |
| | | ]" |
| | |
| | | label: '发放', |
| | | type: 'link', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['hrm:salary-payment:pay'], |
| | | auth: ['hrm:salary:pay'], |
| | | ifShow: row.status === 0, |
| | | popConfirm: { |
| | | title: '确认发放该周期的薪资吗?', |
| | |
| | | |
| | | import { h, markRaw } from 'vue'; |
| | | |
| | | import { |
| | | DICT_TYPE, |
| | | MesAutoCodeRuleCode, |
| | | MesProTaskStatusEnum, |
| | | MesProWorkOrderStatusEnum, |
| | | } from '@vben/constants'; |
| | | import { DICT_TYPE, MesAutoCodeRuleCode } from '@vben/constants'; |
| | | import { getDictOptions } from '@vben/hooks'; |
| | | |
| | | import { Button } from 'ant-design-vue'; |
| | |
| | | import { getTemplateItemOptionList } from '#/api/mes/qc/template/item'; |
| | | import { getSimpleUserList } from '#/api/system/user'; |
| | | import { getRangePickerDefaultProps } from '#/utils'; |
| | | import { MdItemSelect } from '#/views/mes/md/item/components'; |
| | | import { MdWorkstationSelect } from '#/views/mes/md/workstation/components'; |
| | | import { ProTaskSelect } from '#/views/mes/pro/task/components'; |
| | | import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components'; |
| | | import { MdmItemSelect } from '#/views/basicData/mdm/components'; |
| | | |
| | | /** 表单类型 */ |
| | | export type FormType = 'create' | 'detail' | 'update'; |
| | |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'workOrderId', |
| | | label: '生产订单', |
| | | component: markRaw(ProWorkOrderSelect), |
| | | fieldName: 'itemId', |
| | | label: '产品物料', |
| | | component: markRaw(MdmItemSelect), |
| | | componentProps: { |
| | | placeholder: '请选择生产订单', |
| | | status: MesProWorkOrderStatusEnum.CONFIRMED, |
| | | // 订单变更时清空生产任务 |
| | | onChange: () => formApi?.setFieldValue('taskId', undefined), |
| | | placeholder: '请选择产品物料', |
| | | }, |
| | | rules: 'selectRequired', |
| | | dependencies: { |
| | | triggerFields: ['sourceDocId'], |
| | | componentProps: (values) => ({ |
| | | disabled: !!values.sourceDocId, |
| | | placeholder: '请选择生产订单', |
| | | status: MesProWorkOrderStatusEnum.CONFIRMED, |
| | | onChange: () => formApi?.setFieldValue('taskId', undefined), |
| | | placeholder: '请选择产品物料', |
| | | }), |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'workstationId', |
| | | label: '工位', |
| | | component: markRaw(MdWorkstationSelect), |
| | | fieldName: 'batchCode', |
| | | label: '批号', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请选择工位', |
| | | maxlength: 100, |
| | | placeholder: '请输入批号', |
| | | }, |
| | | rules: 'selectRequired', |
| | | dependencies: { |
| | | triggerFields: ['sourceDocId'], |
| | | componentProps: (values) => ({ |
| | | disabled: !!values.sourceDocId, |
| | | placeholder: '请选择工位', |
| | | }), |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'taskId', |
| | | label: '生产任务', |
| | | component: markRaw(ProTaskSelect), |
| | | componentProps: { |
| | | placeholder: '请选择生产任务', |
| | | statuses: [MesProTaskStatusEnum.PREPARE], |
| | | }, |
| | | dependencies: { |
| | | triggerFields: ['sourceDocId', 'workOrderId', 'workstationId'], |
| | | componentProps: (values) => ({ |
| | | disabled: !!values.sourceDocId || !values.workOrderId, |
| | | placeholder: '请选择生产任务', |
| | | statuses: [MesProTaskStatusEnum.PREPARE], |
| | | workOrderId: values.workOrderId, |
| | | workstationId: values.workstationId, |
| | | }), |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'templateId', |
| | |
| | | }, |
| | | rules: 'selectRequired', |
| | | dependencies: { |
| | | triggerFields: ['workOrderId', 'taskId'], |
| | | triggerFields: ['itemId'], |
| | | componentProps: (values) => ({ |
| | | api: getTemplateItemOptionList, |
| | | autoSelect: 'first', |
| | | labelField: 'templateName', |
| | | valueField: 'templateId', |
| | | disabled: formType !== 'create' || !values.workOrderId, |
| | | params: values.workOrderId |
| | | ? { |
| | | qcType: 2, |
| | | workOrderId: values.workOrderId, |
| | | taskId: values.taskId, |
| | | } |
| | | : {}, |
| | | placeholder: values.workOrderId |
| | | ? '请选择质检方案' |
| | | : '请先选择生产订单', |
| | | disabled: formType !== 'create' || !values.itemId, |
| | | params: values.itemId ? { itemId: values.itemId, qcType: 2 } : {}, |
| | | placeholder: values.itemId ? '请选择质检方案' : '请先选择产品物料', |
| | | }), |
| | | }, |
| | | }, |
| | |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'workOrderId', |
| | | label: '生产订单', |
| | | component: markRaw(ProWorkOrderSelect), |
| | | fieldName: 'batchCode', |
| | | label: '批号', |
| | | component: 'Input', |
| | | componentProps: { |
| | | placeholder: '请选择生产订单', |
| | | allowClear: true, |
| | | placeholder: '请输入批号', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'itemId', |
| | | label: '产品物料', |
| | | component: markRaw(MdItemSelect), |
| | | component: markRaw(MdmItemSelect), |
| | | componentProps: { |
| | | placeholder: '请选择产品物料', |
| | | }, |
| | |
| | | }, |
| | | }, |
| | | { |
| | | field: 'workOrderCode', |
| | | title: '生产订单编号', |
| | | width: 140, |
| | | }, |
| | | { |
| | | field: 'itemCode', |
| | | title: '产品物料编码', |
| | | width: 130, |
| | |
| | | width: 130, |
| | | }, |
| | | { |
| | | field: 'batchCode', |
| | | title: '批号', |
| | | width: 140, |
| | | }, |
| | | { |
| | | field: 'unitName', |
| | | title: '单位', |
| | | width: 80, |
| | |
| | | minWidth: 180, |
| | | }, |
| | | { |
| | | field: 'vendorNickname', |
| | | title: '供应商简称', |
| | | width: 120, |
| | | }, |
| | | { |
| | | field: 'vendorBatch', |
| | | title: '供应商批次号', |
| | | width: 130, |
| | | }, |
| | | { |
| | | field: 'itemCode', |
| | | title: '产品物料编码', |
| | | width: 130, |
| | |
| | | componentProps: { |
| | | placeholder: '请选择客户', |
| | | }, |
| | | rules: 'selectRequired', |
| | | dependencies: { |
| | | triggerFields: ['sourceDocId'], |
| | | componentProps: (values) => ({ |
| | |
| | | } |
| | | }, |
| | | }, |
| | | rules: 'required', |
| | | dependencies: { |
| | | triggerFields: ['sourceDocId'], |
| | | componentProps: (values) => ({ |
| | |
| | | } |
| | | }, |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'qualifiedQuantity', |
| | |
| | | placeholder: '请选择出货日期', |
| | | valueFormat: 'YYYY-MM-DD', |
| | | }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'inspectDate', |
| | |
| | | minWidth: 180, |
| | | }, |
| | | { |
| | | field: 'clientNickname', |
| | | title: '客户名称', |
| | | width: 120, |
| | | }, |
| | | { |
| | | field: 'batchCode', |
| | | title: '批次号', |
| | | width: 130, |
| | | }, |
| | | { |
| | | field: 'itemCode', |
| | | title: '产品物料编码', |
| | | width: 130, |
| | |
| | | width: 80, |
| | | }, |
| | | { |
| | | field: 'outQuantity', |
| | | title: '发货数量', |
| | | width: 100, |
| | | }, |
| | | { |
| | | field: 'checkQuantity', |
| | | title: '检测数量', |
| | | width: 100, |
| | | }, |
| | | { |
| | | field: 'unqualifiedQuantity', |
| | | title: '不合格数', |
| | | width: 100, |
| | |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.MES_QC_CHECK_RESULT }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'outDate', |
| | | title: '出货日期', |
| | | width: 120, |
| | | formatter: 'formatDate', |
| | | }, |
| | | { |
| | | field: 'inspectDate', |
| | |
| | | } |
| | | } else if (data?.prefill) { |
| | | // 预填模式:来自待检任务。源项目靠 watcher 自动把 outQuantity 同步到 |
| | | // checkQuantity,这里显式补齐,避免必填的检测数量为空 |
| | | // checkQuantity,这里显式补齐 |
| | | const prefill = { |
| | | ...data.prefill, |
| | | checkQuantity: data.prefill.checkQuantity ?? data.prefill.outQuantity, |
| | |
| | | /** 创建过程检验单(IPQC) */ |
| | | function handleCreateIpqc(row: MesQcPendingInspectApi.PendingInspect) { |
| | | const prefill: MesQcIpqcApi.Ipqc = { |
| | | batchCode: row.batchCode, |
| | | checkQuantity: row.quantity, |
| | | inspectDate: row.recordTime, |
| | | itemId: row.itemId, |
| | |
| | | sourceDocId: row.sourceDocId, |
| | | sourceDocType: row.sourceDocType, |
| | | sourceLineId: row.sourceLineId, |
| | | taskId: row.taskId, |
| | | workOrderId: row.workOrderId, |
| | | workstationId: row.workstationId, |
| | | }; |
| | | ipqcFormModalApi.setData({ formType: 'create', prefill }).open(); |
| | | } |
| | |
| | | minWidth: 180, |
| | | }, |
| | | { |
| | | field: 'sourceDocType', |
| | | title: '来源单据类型', |
| | | width: 120, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.MES_QC_SOURCE_DOC_TYPE }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'sourceDocCode', |
| | | title: '来源单据编码', |
| | | width: 160, |
| | | }, |
| | | { |
| | | field: 'itemCode', |
| | | title: '产品物料编码', |
| | | width: 130, |
| | |
| | | field: 'unitName', |
| | | title: '单位', |
| | | width: 80, |
| | | }, |
| | | { |
| | | field: 'batchCode', |
| | | title: '批次号', |
| | | width: 130, |
| | | }, |
| | | { |
| | | field: 'checkResult', |