From fb18aab2632a63851ed591595594006001e76d77 Mon Sep 17 00:00:00 2001 From: zch Date: Thu, 6 Feb 2025 16:45:24 +0800 Subject: [PATCH 1/5] =?UTF-8?q?add(mes):=20=E6=96=B0=E5=A2=9E=E7=89=A9?= =?UTF-8?q?=E6=96=99=20BOM=20=E4=BF=A1=E6=81=AF=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加了物料 BOM 信息批量新增的功能(根据结构BOM) - 新增了物料 BOM 对话框和相关组件 - 优化了物料选择和数据处理逻辑 - 更新了 API 接口和类型定义 --- src/api/mes/materialBom/index.ts | 15 +- src/api/mes/materialBom/types.ts | 1 + src/views/mes/materialBom/index.vue | 357 +++++++++++++++++++++++++++- 3 files changed, 361 insertions(+), 12 deletions(-) diff --git a/src/api/mes/materialBom/index.ts b/src/api/mes/materialBom/index.ts index 509f97d..d32797f 100644 --- a/src/api/mes/materialBom/index.ts +++ b/src/api/mes/materialBom/index.ts @@ -70,8 +70,21 @@ export const delMaterialBom = (materialBomId: string | number | Array { + return request({ + url: '/mes/materialBom/addBatchMaterialBom', + method: 'post', + data: data + }); +}; diff --git a/src/api/mes/materialBom/types.ts b/src/api/mes/materialBom/types.ts index 91d8c1e..d03cc3a 100644 --- a/src/api/mes/materialBom/types.ts +++ b/src/api/mes/materialBom/types.ts @@ -191,6 +191,7 @@ export interface MaterialBomForm extends BaseEntity { */ remark?: string; + materialBomList?: any[];//批量新增 } export interface MaterialBomQuery { diff --git a/src/views/mes/materialBom/index.vue b/src/views/mes/materialBom/index.vue index 6f4ba7b..d000206 100644 --- a/src/views/mes/materialBom/index.vue +++ b/src/views/mes/materialBom/index.vue @@ -36,6 +36,13 @@ 新增 + + + + 新增BOM + + + 展开/折叠 @@ -53,7 +60,7 @@ - + @@ -208,6 +215,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -217,10 +312,12 @@ import { getMaterialBom, delMaterialBom, addMaterialBom, - updateMaterialBom + updateMaterialBom, addBatchMaterialBom } from '@/api/mes/materialBom'; import { MaterialBomVO, MaterialBomQuery, MaterialBomForm } from '@/api/mes/materialBom/types'; import MaterialSelect from '@/views/mes/baseMaterialInfo/addMaterial.vue'; +import { BaseStructureBomVO } from '@/api/mes/baseStructureBom/types'; +import { getBaseStructureBomList } from '@/api/mes/baseStructureBom'; type MaterialBomOption = { materialBomId: number; @@ -233,7 +330,7 @@ const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { mes_check_type, material_classfication, active_flag } = toRefs(proxy?.useDict('mes_check_type', 'material_classfication', 'active_flag')); -const materialBomList = ref([]); +const materialBomList = ref([]); const materialBomOptions = ref([]); const buttonLoading = ref(false); const showSearch = ref(true); @@ -420,15 +517,253 @@ const handleDelete = async (row: MaterialBomVO) => { /** 新增按钮操作 */ const handleMaterialAdd = () => { materialOpen.value = true; -} - -/** 提交物料BOM信息按钮 */ +}; +// 提交物料选择 const submitMaterialForm = () => { - let selectedRow = materialSelectRef.value.tableRef.store.states.currentRow.value; - form.value.materialId = selectedRow.materialId - form.value.materialName = selectedRow.materialName - materialOpen.value = false; -} + const selectedRow = materialSelectRef.value.tableRef.store.states.currentRow.value; + if (materialOpen.value) { + if (currentRow.value && selectedRow) { + currentRow.value.materialId = selectedRow.materialId; + currentRow.value.materialName = selectedRow.materialName; + materialOpen.value = false; + } + } else { + form.value.materialId = selectedRow.materialId; + form.value.materialName = selectedRow.materialName; + materialOpen.value = false; + } +}; + +/** 当前选中的行 */ +const currentRow = ref(null); + +// 打开物料选择对话框 +const handleMaterialSelect = (row: any) => { + currentRow.value = row; + materialOpen.value = true; +}; + +// 物料选择回调 +const handleSelection = (selection: any) => { + if (currentRow.value) { + currentRow.value.materialId = selection.materialId; + currentRow.value.materialName = selection.materialName; + } +}; + +//根据结构BOM新增物料BOM对话框 +const materialBomDialog = reactive({ + visible: false, + title: '' +}); + +// const materialBomForm = ref({}); +// const currentStructureBom = ref({} as BaseStructureBomVO); +const materialOptions = ref({}); + + +// 打开添加物料BOM对话框 +const handleAddMaterialBom = async () => { + materialBomDialog.visible = true; + materialBomDialog.title = "新增BOM"; + // 重置物料BOM列表,避免影响页面主列表 + materialBomList.value = []; + // 获取结构BOM数据并生成物料BOM列表 + await generateMaterialBomList(); +}; + +// 生成物料BOM列表 +const generateMaterialBomList = async () => { + try { + // 获取结构BOM数据 + const res = await getBaseStructureBomList(null); + + // 递归处理结构BOM树 + const processBomTree = (items: any[]): MaterialBomForm[] => { + return items.map(item => ({ + materialBomId: -Math.abs(item.structureBomId), // 使用负数作为临时ID + parentId: item.parentId === 0 ? 0 : -Math.abs(item.parentId), // 保持父子关系 + materialTypeId: item.materialTypeId, + materialTypeName: item.materialTypeName, + materialId: undefined, + materialName: undefined, + materialBomDesc: '', + materialBomVersion: '', + standardAmount: undefined, + checkType: undefined, + activeFlag: undefined, + remark: '', + children: item.children && item.children.length > 0 + ? processBomTree(item.children) + : [] + })); + }; + + // 构建完整的树形结构 + const structureBomData = buildTree(res.data); + // 处理数据并赋值 + materialBomList.value = processBomTree(structureBomData); + } catch (error) { + console.error('获取结构BOM数据失败:', error); + proxy?.$modal.msgError('获取数据失败'); + } +}; + +// 构建树形结构 +const buildTree = (data: any[]) => { + const tree: any[] = []; + const map = new Map(); + + // 首先创建一个以id为键的映射 + data.forEach(item => { + // 创建新对象,避免修改原始数据 + const node = { ...item, children: [] }; + map.set(item.structureBomId, node); + }); + + // 然后构建树形结构 + data.forEach(item => { + const node = map.get(item.structureBomId); + if (item.parentId === 0) { + // 顶级节点直接加入树中 + tree.push(node); + } else { + // 将当前节点添加到父节点的children中 + const parent = map.get(item.parentId); + if (parent) { + if (!parent.children) { + parent.children = []; + } + parent.children.push(node); + } + } + }); + + return tree; +}; + +// 物料选择变更处理 +const handleMaterialChange = (materialId: string | number, row: any) => { + const material = materialOptions.value[row.materialTypeId]?.find( + (item: any) => item.materialId === materialId + ); + if (material) { + row.materialName = material.materialName; + } +}; + +// 提交物料BOM +const submitMaterialBom = async () => { + try { + // 验证数据完整性 + const validateTreeData = (nodes: any[], path: string = ''): string | null => { + for (let i = 0; i < nodes.length; i++) { + const node = nodes[i]; + const currentPath = path ? `${path} -> ${node.materialTypeName}` : node.materialTypeName; + + // 如果当前节点没有选择物料 + if (!node.materialId) { + // 但是有子节点被选择了,说明跳过了当前层。例如一三层填充但跳过了第二层 + if (hasSelectedDescendant(node)) { + return `请先为 "${currentPath}" 选择物料,不能跳过中间层级`; + } + } + + // 递归检查子节点 + if (node.children && node.children.length > 0) { + const childResult = validateTreeData(node.children, currentPath); + if (childResult) { + return childResult; + } + } + } + return null; + }; + + // 检查节点是否有被选择的后代节点 + const hasSelectedDescendant = (node: any): boolean => { + if (!node.children) { + return false; + } + return node.children.some((child: any) => { + if (child.materialId) { + return true; + } + return hasSelectedDescendant(child); + }); + }; + + // 执行验证 + const validationError = validateTreeData(materialBomList.value); + if (validationError) { + proxy?.$modal.msgError(validationError); + return; + } + + // 将树形结构转换为扁平数组,并处理父子关系 + const flattenTree = (nodes: any[], parentId: number = 0): any[] => { + let result: any[] = []; + nodes.forEach((node, index) => { + const { children, ...nodeWithoutChildren } = node; + + // 只处理选择了物料的节点 + if (nodeWithoutChildren.materialId) { + // 检查必填字段 + if (!nodeWithoutChildren.standardAmount) { + throw new Error(`物料 "${nodeWithoutChildren.materialName}" 的标准数量不能为空`); + } + if (nodeWithoutChildren.standardAmount <= 0) { + throw new Error(`物料 "${nodeWithoutChildren.materialName}" 的标准数量必须大于0`); + } + if (!nodeWithoutChildren.checkType) { + throw new Error(`物料 "${nodeWithoutChildren.materialName}" 的校验类型不能为空`); + } + if (!nodeWithoutChildren.activeFlag) { + throw new Error(`物料 "${nodeWithoutChildren.materialName}" 的激活标识不能为空`); + } + + const newNode = { + ...nodeWithoutChildren, + parentId: parentId + }; + + result.push(newNode); + + // 如果有子节点,递归处理 + if (children && children.length > 0) { + result = result.concat(flattenTree(children, newNode.materialBomId)); + } + } + }); + return result; + }; + + const flattenedData = flattenTree(materialBomList.value); + if (flattenedData.length === 0) { + proxy?.$modal.msgError('请至少输入一行有效数据'); + return; + } + + // 提交数据 + await addBatchMaterialBom(flattenedData); + proxy?.$modal.msgSuccess('新增成功'); + materialBomDialog.visible = false; + getList(); // 刷新列表 + } catch (error: any) { + console.error('提交失败:', error); + proxy?.$modal.msgError(error.message || '提交失败'); + } +}; + +// 取消 +const cancelMaterialBom = () => { + materialBomDialog.visible = false; + // 重新获取主列表数据 + getList(); +}; + +// 选中数据 +const selection = ref([]); onMounted(() => { getList(); From 8d75410f7d430a30a7a03ac0025cbc996100d66f Mon Sep 17 00:00:00 2001 From: zch Date: Thu, 6 Feb 2025 16:47:14 +0800 Subject: [PATCH 2/5] =?UTF-8?q?change(mes/materialBom):=20=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E7=BB=93=E6=9E=84=20BOM=20=E6=A0=91=E8=A1=A8=E6=A0=BC?= =?UTF-8?q?=E5=88=97=E6=A0=87=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将"物料类型"列的标题修改为"结构BOM名称" --- src/views/mes/materialBom/index.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/mes/materialBom/index.vue b/src/views/mes/materialBom/index.vue index d000206..d4b3730 100644 --- a/src/views/mes/materialBom/index.vue +++ b/src/views/mes/materialBom/index.vue @@ -229,7 +229,7 @@ :default-expand-all="true" > - +