From 3ea71df71466c881f92887524aefe1b6837dc869 Mon Sep 17 00:00:00 2001 From: "zangch@mesnac.com" Date: Wed, 18 Mar 2026 17:30:07 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BF=AE=E5=A4=8D=E8=AE=A2=E5=8D=95BOM?= =?UTF-8?q?=E6=A0=91=E8=8A=82=E7=82=B9=E5=AE=9A=E4=BD=8D=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E9=97=AE=E9=A2=98=EF=BC=8C=E6=B7=BB=E5=8A=A0BASE=5FDEVICE=5FPA?= =?UTF-8?q?RAM=5FVAL=E6=97=81=E8=B7=AF=E8=83=BD=E5=8A=9B=E6=94=B9=E9=80=A0?= =?UTF-8?q?=E6=96=B9=E6=A1=88=E6=96=87=E6=A1=A3=E5=92=8C=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/board/mixData.js | 1 - src/api/production/orderNote.js | 39 + src/api/production/processRoute.js | 39 + src/api/production/stationCapability.js | 39 + src/api/production/taskPool.js | 47 ++ src/api/production/teamShift.js | 39 + src/router/index.js | 4 +- src/views/base/orderBomInfo/childIndex.vue | 129 +++- src/views/base/orderBomInfo/index.vue | 517 ++++++------- ...ARAM_VAL_旁路能力改造实现方案.md | 687 ++++++++++++++++++ src/views/board/board3/index.vue | 1 - src/views/production/orderNote/index.vue | 239 ++++++ src/views/production/processRoute/index.vue | 348 +++++++++ .../production/stationCapability/index.vue | 283 ++++++++ src/views/production/taskPool/index.vue | 323 ++++++++ src/views/production/teamShift/index.vue | 293 ++++++++ src/views/report/WIPInquiryReport/index.vue | 8 +- .../report/adverseRecordYearOnYear/index.vue | 1 - .../report/boxTraceabilityReport/index.vue | 2 +- .../boxTurnoverTraceabilityReport/index.vue | 2 +- .../downgradeProportionReport/index.vue | 2 +- .../report/fewerMistakesReport/index.vue | 2 +- src/views/report/highFault/index.vue | 2 +- .../report/inventoryRateReport/index.vue | 24 +- src/views/report/materialReport/index.vue | 6 +- src/views/report/pourRecordReport/index.vue | 2 +- .../productTraceabilityReport/index.vue | 2 +- .../index.vue | 2 +- .../report/qualityIssuesReport/index.vue | 2 +- src/views/report/repairRateReport/index.vue | 2 +- .../report/scanOfflineRecordReport/index.vue | 2 +- src/views/report/weldLeakRate/index.vue | 2 +- 32 files changed, 2785 insertions(+), 306 deletions(-) create mode 100644 src/api/production/orderNote.js create mode 100644 src/api/production/processRoute.js create mode 100644 src/api/production/stationCapability.js create mode 100644 src/api/production/taskPool.js create mode 100644 src/api/production/teamShift.js create mode 100644 src/views/baseDeviceParamVal/trace/BASE_DEVICE_PARAM_VAL_旁路能力改造实现方案.md create mode 100644 src/views/production/orderNote/index.vue create mode 100644 src/views/production/processRoute/index.vue create mode 100644 src/views/production/stationCapability/index.vue create mode 100644 src/views/production/taskPool/index.vue create mode 100644 src/views/production/teamShift/index.vue diff --git a/src/api/board/mixData.js b/src/api/board/mixData.js index 27228fe..ba827fa 100644 --- a/src/api/board/mixData.js +++ b/src/api/board/mixData.js @@ -34,7 +34,6 @@ export function mixData(params,customType=1) { } if (type === 3) { getFoamingData({ - "PRODUCT_LINE_CODE": "CX_02" }).then(val2 => { (params?.f || (() => { }))(screenData(val2) || []) diff --git a/src/api/production/orderNote.js b/src/api/production/orderNote.js new file mode 100644 index 0000000..64cd0f6 --- /dev/null +++ b/src/api/production/orderNote.js @@ -0,0 +1,39 @@ +import request from '@/utils/request' + +export function listOrderNote(query) { + return request({ + url: '/production/orderNote/list', + method: 'get', + params: query + }) +} + +export function getOrderNote(objId) { + return request({ + url: '/production/orderNote/' + objId, + method: 'get' + }) +} + +export function addOrderNote(data) { + return request({ + url: '/production/orderNote', + method: 'post', + data: data + }) +} + +export function updateOrderNote(data) { + return request({ + url: '/production/orderNote', + method: 'put', + data: data + }) +} + +export function delOrderNote(objId) { + return request({ + url: '/production/orderNote/' + objId, + method: 'delete' + }) +} diff --git a/src/api/production/processRoute.js b/src/api/production/processRoute.js new file mode 100644 index 0000000..e8a1f8b --- /dev/null +++ b/src/api/production/processRoute.js @@ -0,0 +1,39 @@ +import request from '@/utils/request' + +export function listProcessRoute(query) { + return request({ + url: '/production/processRoute/list', + method: 'get', + params: query + }) +} + +export function getProcessRoute(objId) { + return request({ + url: '/production/processRoute/' + objId, + method: 'get' + }) +} + +export function addProcessRoute(data) { + return request({ + url: '/production/processRoute', + method: 'post', + data: data + }) +} + +export function updateProcessRoute(data) { + return request({ + url: '/production/processRoute', + method: 'put', + data: data + }) +} + +export function delProcessRoute(objId) { + return request({ + url: '/production/processRoute/' + objId, + method: 'delete' + }) +} diff --git a/src/api/production/stationCapability.js b/src/api/production/stationCapability.js new file mode 100644 index 0000000..2f46a42 --- /dev/null +++ b/src/api/production/stationCapability.js @@ -0,0 +1,39 @@ +import request from '@/utils/request' + +export function listStationCapability(query) { + return request({ + url: '/production/stationCapability/list', + method: 'get', + params: query + }) +} + +export function getStationCapability(objId) { + return request({ + url: '/production/stationCapability/' + objId, + method: 'get' + }) +} + +export function addStationCapability(data) { + return request({ + url: '/production/stationCapability', + method: 'post', + data: data + }) +} + +export function updateStationCapability(data) { + return request({ + url: '/production/stationCapability', + method: 'put', + data: data + }) +} + +export function delStationCapability(objId) { + return request({ + url: '/production/stationCapability/' + objId, + method: 'delete' + }) +} diff --git a/src/api/production/taskPool.js b/src/api/production/taskPool.js new file mode 100644 index 0000000..ecd6438 --- /dev/null +++ b/src/api/production/taskPool.js @@ -0,0 +1,47 @@ +import request from '@/utils/request' + +export function listTaskPool(query) { + return request({ + url: '/production/taskPool/list', + method: 'get', + params: query + }) +} + +export function getTaskPool(orderCode) { + return request({ + url: '/production/taskPool/' + orderCode, + method: 'get' + }) +} + +export function addTaskPool(data) { + return request({ + url: '/production/taskPool', + method: 'post', + data: data + }) +} + +export function updateTaskPool(data) { + return request({ + url: '/production/taskPool', + method: 'put', + data: data + }) +} + +export function changeTaskStatus(data) { + return request({ + url: '/production/taskPool/changeStatus', + method: 'put', + data: data + }) +} + +export function delTaskPool(orderCode) { + return request({ + url: '/production/taskPool/' + orderCode, + method: 'delete' + }) +} diff --git a/src/api/production/teamShift.js b/src/api/production/teamShift.js new file mode 100644 index 0000000..c4e6df1 --- /dev/null +++ b/src/api/production/teamShift.js @@ -0,0 +1,39 @@ +import request from '@/utils/request' + +export function listTeamShift(query) { + return request({ + url: '/production/teamShift/list', + method: 'get', + params: query + }) +} + +export function getTeamShift(objId) { + return request({ + url: '/production/teamShift/' + objId, + method: 'get' + }) +} + +export function addTeamShift(data) { + return request({ + url: '/production/teamShift', + method: 'post', + data: data + }) +} + +export function updateTeamShift(data) { + return request({ + url: '/production/teamShift', + method: 'put', + data: data + }) +} + +export function delTeamShift(objId) { + return request({ + url: '/production/teamShift/' + objId, + method: 'delete' + }) +} diff --git a/src/router/index.js b/src/router/index.js index 690d468..50dcc4f 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -333,8 +333,8 @@ export const dynamicRoutes = [ permissions: ["base:orderBomInfo:list"], children: [ { - // 订单BOM与生产BOM共用物料编码规则,这里同样放开参数约束,避免同类跳转问题再次出现。 - path: "index/:materialCode", + // 子BOM页面必须带具体节点主键,避免同一物料编码挂在不同父节点下时串树。 + path: "index/:objId(\\d+)", component: () => import("@/views/base/orderBomInfo/childIndex"), name: "childBom", meta: {title: "查看订单子BOM信息", activeMenu: "/base/orderBomInfo"}, diff --git a/src/views/base/orderBomInfo/childIndex.vue b/src/views/base/orderBomInfo/childIndex.vue index 81a4708..6686e5e 100644 --- a/src/views/base/orderBomInfo/childIndex.vue +++ b/src/views/base/orderBomInfo/childIndex.vue @@ -59,7 +59,7 @@ v-if="refreshTable" v-loading="loading" :data="orderBomInfoList" - row-key="materialCode" + row-key="objId" :default-expand-all="isExpandAll" :tree-props="{children: 'children', hasChildren: 'hasChildren'}" > @@ -124,8 +124,8 @@ - - + + @@ -220,6 +220,10 @@ export default { orderBomInfoList: [], // 订单BOM树选项 orderBomInfoOptions: [], + // 工具栏列配置占位,避免 right-toolbar 读取 undefined + columns: [], + // 扁平节点缓存 + allOrderBomNodes: [], // 物料下拉选项 materialOptions: [], // 弹出层标题 @@ -230,6 +234,12 @@ export default { isExpandAll: true, // 重新渲染表格状态 refreshTable: true, + // 当前子树根节点主键 + currentRootObjId: null, + // 当前子树根节点物料编码 + currentRootMaterialCode: null, + // 当前子树根节点完整祖级链 + currentRootAncestors: null, // 查询参数 queryParams: { bomCode: null, @@ -237,6 +247,7 @@ export default { materialName: null, materialType: null, standardAmount: null, + parentObjId: null, parentId: null, isFlag: null, createdBy: null, @@ -257,36 +268,102 @@ export default { }; }, created() { - this.queryParams.ancestors = this.$route.params && this.$route.params.materialCode; + this.currentRootObjId = Number(this.$route.params && this.$route.params.objId) || null; + this.currentRootMaterialCode = this.$route.query && this.$route.query.materialCode; + this.queryParams.ancestors = this.currentRootMaterialCode; this.loadMaterialOptions(); - this.getList(); + this.initCurrentRoot(); }, methods: { + /** 先定位当前根节点的完整祖级链,再查询当前这一棵子树,避免同编码分支串树 */ + initCurrentRoot() { + if (!this.currentRootObjId) { + this.getList(); + return; + } + getOrderBomInfo(this.currentRootObjId).then(response => { + const rootNode = response.data || {}; + this.currentRootMaterialCode = rootNode.materialCode || this.currentRootMaterialCode; + this.currentRootAncestors = rootNode.ancestors || rootNode.materialCode || null; + this.queryParams.ancestors = this.currentRootMaterialCode; + this.getList(); + }); + }, /** 查询订单BOM列表 */ getList() { this.loading = true; findOrderBomList(this.queryParams).then(response => { - this.orderBomInfoList = this.handleTree(response.data, "materialCode", "parentId"); + const normalizedList = this.decorateTreeNodes(this.filterCurrentSubtree(response.data || [])); + this.orderBomInfoList = this.handleTree(normalizedList, "objId", "treeParentObjId"); this.loading = false; }); }, + filterCurrentSubtree(list) { + if (!this.currentRootAncestors) { + return list; + } + return (list || []).filter(item => { + const ancestors = item.ancestors || item.materialCode || ""; + return ancestors === this.currentRootAncestors || ancestors.indexOf(this.currentRootAncestors + ",") === 0; + }); + }, /** 转换订单BOM数据结构 */ normalizer(node) { if (node.children && !node.children.length) { delete node.children; } return { - id: node.materialCode, - label: node.materialName, + id: node.objId, + label: (node.materialCode || "") + " / " + (node.materialName || ""), children: node.children }; }, - /** 查询订单BOM下拉树结构 */ + /** + * 把后端返回的编码路径补成节点主键路径 + * + * 这里保留后端现有的 ancestors/materialCode 模型,同时在前端补出 treeParentObjId, + * 让树控件和路由都基于 objId 工作,避免同编码物料在不同分支下串树。 + */ + decorateTreeNodes(list) { + const nodes = (list || []).map(item => ({ ...item })); + const identityMap = new Map(); + nodes.forEach(item => { + identityMap.set(this.buildNodeIdentity(item.materialCode, item.ancestors), item.objId); + }); + this.allOrderBomNodes = nodes.map(item => ({ + ...item, + treeParentObjId: this.resolveTreeParentObjId(item, identityMap) + })); + return this.allOrderBomNodes; + }, + buildNodeIdentity(materialCode, ancestors) { + return `${materialCode || ""}@@${ancestors || ""}`; + }, + resolveTreeParentObjId(item, identityMap) { + if (!item.parentId || item.parentId === "0") { + return 0; + } + if (item.parentObjId && item.parentObjId > 0) { + return item.parentObjId; + } + const parentAncestors = this.resolveParentAncestors(item); + return identityMap.get(this.buildNodeIdentity(item.parentId, parentAncestors)) || 0; + }, + resolveParentAncestors(item) { + const ancestors = (item.ancestors || "").split(",").filter(Boolean); + if (ancestors.length <= 1) { + return ""; + } + ancestors.pop(); + return ancestors.join(","); + }, + /** 查询订单BOM下拉树结构 */ getTreeselect() { - findOrderBomList().then(response => { + findOrderBomList().then(response => { + const normalizedList = this.decorateTreeNodes(response.data || []); this.orderBomInfoOptions = []; - const data = { materialCode: 0, materialName: '顶级节点', children: [] }; - data.children = this.handleTree(response.data, "materialCode", "parentId"); + const data = { objId: 0, materialCode: "0", materialName: "顶级节点", children: [] }; + data.children = this.handleTree(normalizedList, "objId", "treeParentObjId"); this.orderBomInfoOptions.push(data); }); }, @@ -314,6 +391,16 @@ export default { this.form.bomCode = selectedMaterial.materialCode; } }, + /** 选择父节点后同步回填父级物料编码,兼容历史接口仍按 parentId 查询 */ + handleParentChange(parentObjId) { + if (!parentObjId) { + this.form.parentObjId = 0; + this.form.parentId = "0"; + return; + } + const parentNode = this.allOrderBomNodes.find(item => item.objId === parentObjId); + this.form.parentId = parentNode ? parentNode.materialCode : null; + }, // 取消按钮 cancel() { this.open = false; @@ -328,6 +415,7 @@ export default { materialName: null, materialType: null, standardAmount: null, + parentObjId: 0, parentId: null, isFlag: 0, createdBy: null, @@ -355,10 +443,13 @@ export default { handleAdd(row) { this.reset(); this.getTreeselect(); - if (row != null && row.materialCode) { - this.form.parentId = row.materialCode; + const parentNode = row && row.objId ? row : this.allOrderBomNodes.find(item => item.objId === this.currentRootObjId); + if (parentNode) { + this.form.parentObjId = parentNode.objId; + this.form.parentId = parentNode.materialCode; } else { - this.form.parentId = 0; + this.form.parentObjId = 0; + this.form.parentId = "0"; } this.open = true; this.title = "添加订单BOM"; @@ -380,11 +471,13 @@ export default { handleUpdate(row) { this.reset(); this.getTreeselect(); - if (row != null) { - this.form.parentId = row.parentId; - } getOrderBomInfo(row.objId).then(response => { this.form = response.data; + if ((!this.form.parentObjId || this.form.parentObjId <= 0) && row && row.treeParentObjId >= 0) { + // 历史数据没有 parentObjId 时,优先用当前树上下文补齐,避免编辑后把节点挂到错误父级。 + this.form.parentObjId = row.treeParentObjId || 0; + } + this.handleParentChange(this.form.parentObjId); this.handleMaterialChange(this.form.materialCode); this.open = true; this.title = "修改订单BOM"; diff --git a/src/views/base/orderBomInfo/index.vue b/src/views/base/orderBomInfo/index.vue index befa40f..8a8940d 100644 --- a/src/views/base/orderBomInfo/index.vue +++ b/src/views/base/orderBomInfo/index.vue @@ -1,32 +1,24 @@