Преглед изворни кода

Merge branch 'dev' of http://110.41.163.243:9980/kd-aiot/kd-aiot-frontend into dev

xieyong пре 3 дана
родитељ
комит
71bfb04109

+ 55 - 0
src/api/system/organization/index.js

@@ -213,3 +213,58 @@ export async function createPersonal(data) {
   }
   return Promise.reject(new Error(res.data.message));
 }
+
+/**
+ * 分页查询部门岗位编制
+ */
+export async function getDepartmentPositionPage(data) {
+  const res = await request.post('/fm/tmaindepartmentposition/page', data);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+/**
+ * 批量保存部门岗位编制(有 id 修改,无 id 新增)
+ */
+export async function saveDepartmentPositionBatch(data) {
+  const res = await request.post('/fm/tmaindepartmentposition/saveBatch', data);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+/**
+ * 删除部门岗位编制
+ */
+export async function deleteDepartmentPosition(id) {
+  const res = await request.delete(`/fm/tmaindepartmentposition/delete/${id}`);
+  if (res.data.code == 0) {
+    return res.data.message;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+/**
+ * 岗位分页(岗位名称、层级选项)
+ */
+export async function getHrPositionPage(data) {
+  const res = await request.post('/hr/position/page', data);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+/**
+ * 岗位详情(取岗位层级主键)
+ */
+export async function getHrPositionById(id) {
+  const res = await request.get(`/hr/position/getById/${id}`);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}

+ 280 - 11
src/views/enterpriseModel/dept/components/org-edit.vue

@@ -219,6 +219,94 @@
         </el-col>
       </el-row>
     </el-form>
+    <headerTitle
+      title="部门信息"
+      style="margin-top: 30px"
+      v-if="isDeptType"
+    >
+      <el-button
+        type="primary"
+        size="small"
+        icon="el-icon-plus"
+        class="ele-btn-icon"
+        @click="addDeptPosition"
+      >
+        新增
+      </el-button>
+    </headerTitle>
+    <el-table
+      v-if="isDeptType"
+      :data="departmentPositionList"
+      border
+      class="dept-position-table"
+    >
+      <el-table-column type="index" label="序号" width="80" align="center" />
+      <el-table-column label="岗位名称" min-width="160" align="center">
+        <template slot-scope="{ row }">
+          <el-select
+            v-if="!row.id"
+            v-model="row.positionId"
+            filterable
+            clearable
+            placeholder="请选择"
+            style="width: 100%"
+            @change="onDeptPositionNameChange(row)"
+          >
+            <el-option
+              v-for="item in positionList"
+              :key="item.id"
+              :label="item.positionName"
+              :value="item.id"
+            />
+          </el-select>
+          <span v-else>{{ row.positionName }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="岗位层级" min-width="140" align="center">
+        <template slot-scope="{ row }">
+          <el-select
+            v-if="!row.id"
+            v-model="row.positionLevelId"
+            filterable
+            clearable
+            placeholder="请选择"
+            style="width: 100%"
+            :disabled="!row.positionId"
+            @change="onDeptPositionLevelChange(row)"
+          >
+            <el-option
+              v-for="item in row.levelOptions"
+              :key="item.positionLevelId"
+              :label="item.positionLevel"
+              :value="item.positionLevelId"
+            />
+          </el-select>
+          <span v-else>{{ row.positionLevel }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="编制人数" min-width="120" align="center">
+        <template slot-scope="{ row }">
+          <el-input-number
+            v-model="row.establishmentCount"
+            :min="0"
+            :precision="0"
+            controls-position="right"
+            style="width: 100%"
+          />
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="80" align="center">
+        <template slot-scope="{ row }">
+          <el-link
+            type="danger"
+            :underline="false"
+            @click="removeDeptPosition(row)"
+          >
+            删除
+          </el-link>
+        </template>
+      </el-table-column>
+    </el-table>
     <!-- <headerTitle
       title="工厂信息"
       style="margin-top: 30px"
@@ -372,7 +460,12 @@
     addOrganization,
     updateOrganization,
     getById,
-    getCode
+    getCode,
+    getDepartmentPositionPage,
+    saveDepartmentPositionBatch,
+    deleteDepartmentPosition,
+    getHrPositionPage,
+    getHrPositionById
   } from '@/api/system/organization';
   import { basicAreaPageAPI } from '@/api/regionalManage';
   import { cityDataLabel } from 'ele-admin/packages/utils/regions';
@@ -449,13 +542,18 @@
         // 提交状态
         loading: false,
         // 是否是修改
-        isUpdate: false
+        isUpdate: false,
+        departmentPositionList: [],
+        positionList: []
       };
     },
     computed: {
       // 是否开启响应式布局
       styleResponsive() {
         return this.$store.state.theme.styleResponsive;
+      },
+      isDeptType() {
+        return String(this.form.type) === '30';
       }
     },
     created() {
@@ -491,18 +589,175 @@
         const saveOrUpdate = this.isUpdate
           ? updateOrganization
           : addOrganization;
-        saveOrUpdate(data)
-          .then((msg) => {
-            this.loading = false;
-            this.$message.success(msg);
-            this.updateVisible(false);
-            this.$emit('done');
-          })
-          .catch((e) => {
+        const submit = async () => {
+          if (this.isDeptType) {
+            const payload = this.buildDepartmentPositionPayload();
+            if (payload === false) {
+              return;
+            }
+            if (payload.length) {
+              await saveDepartmentPositionBatch(payload);
+            }
+          }
+          const msg = await saveOrUpdate(data);
+          this.$message.success(msg);
+          this.updateVisible(false);
+          this.$emit('done');
+        };
+        submit()
+          .catch(() => {})
+          .finally(() => {
             this.loading = false;
-            // this.$message.error(e.message);
           });
       },
+      createDeptPositionRow() {
+        return {
+          id: null,
+          positionId: '',
+          positionName: '',
+          positionLevel: '',
+          positionLevelId: '',
+          establishmentCount: undefined,
+          levelOptions: []
+        };
+      },
+      buildDepartmentPositionPayload() {
+        if (!this.form.id) {
+          return [];
+        }
+        const rows = [];
+        for (const row of this.departmentPositionList) {
+          const isNew = !row.id;
+          const emptyNew =
+            isNew &&
+            !row.positionId &&
+            !row.positionLevelId &&
+            (row.establishmentCount === undefined ||
+              row.establishmentCount === null ||
+              row.establishmentCount === '');
+          if (emptyNew) {
+            continue;
+          }
+          if (
+            !row.positionId ||
+            !row.positionName ||
+            !row.positionLevelId ||
+            row.establishmentCount === undefined ||
+            row.establishmentCount === null ||
+            row.establishmentCount === ''
+          ) {
+            this.$message.warning('请完善部门岗位信息');
+            return false;
+          }
+          rows.push({
+            ...(row.id ? { id: row.id } : {}),
+            deptId: this.form.id,
+            positionId: row.positionId,
+            positionName: row.positionName,
+            positionLevelId: row.positionLevelId,
+            positionLevel: row.positionLevel,
+            establishmentCount: Number(row.establishmentCount)
+          });
+        }
+        return rows;
+      },
+      isDeptPositionFilled(row) {
+        return (
+          !!row.positionId &&
+          !!row.positionLevelId &&
+          row.establishmentCount !== undefined &&
+          row.establishmentCount !== null &&
+          row.establishmentCount !== ''
+        );
+      },
+      addDeptPosition() {
+        if (
+          this.departmentPositionList.some(
+            (item) => !this.isDeptPositionFilled(item)
+          )
+        ) {
+          this.$message.warning('请先填写岗位名称、岗位层级和编制人数');
+          return;
+        }
+        this.ensurePositionOptions();
+        this.departmentPositionList.push(this.createDeptPositionRow());
+      },
+      async removeDeptPosition(row) {
+        const list = this.departmentPositionList;
+        const index = list.indexOf(row);
+        if (index < 0) {
+          return;
+        }
+        if (!row.id) {
+          list.splice(index, 1);
+          return;
+        }
+        try {
+          await this.$confirm('确定删除该岗位编制吗?', '提示', {
+            type: 'warning'
+          });
+          await deleteDepartmentPosition(row.id);
+          list.splice(index, 1);
+          this.$message.success('删除成功');
+        } catch (e) {}
+      },
+      async ensurePositionOptions() {
+        if (this.positionList.length) {
+          return;
+        }
+        const res = await getHrPositionPage({
+          pageNum: 1,
+          size: 9999,
+          status: 1
+        });
+        this.positionList = (res && res.list) || [];
+      },
+      async onDeptPositionNameChange(row) {
+        row.positionLevel = '';
+        row.positionLevelId = '';
+        row.levelOptions = [];
+        const position = this.positionList.find(
+          (item) => item.id === row.positionId
+        );
+        row.positionName = position ? position.positionName : '';
+        if (!row.positionId) {
+          return;
+        }
+        const detail = await getHrPositionById(row.positionId);
+        const configs = (detail && detail.levelConfigs) || [];
+        row.levelOptions = configs
+          .filter((item) => item.positionLevelId)
+          .map((item) => ({
+            positionLevelId: item.positionLevelId,
+            positionLevel: item.positionLevel
+          }));
+      },
+      onDeptPositionLevelChange(row) {
+        const level = (row.levelOptions || []).find(
+          (item) => item.positionLevelId === row.positionLevelId
+        );
+        row.positionLevel = level ? level.positionLevel : '';
+      },
+      async loadDepartmentPositions() {
+        if (!this.form.id || !this.isDeptType) {
+          this.departmentPositionList = [];
+          return;
+        }
+        await this.ensurePositionOptions();
+        const res = await getDepartmentPositionPage({
+          deptId: this.form.id,
+          pageNum: 1,
+          size: 9999
+        });
+        this.departmentPositionList = ((res && res.list) || []).map((item) => ({
+          ...item,
+          levelOptions: []
+        }));
+      },
+      resetDepartmentPosition() {
+        this.departmentPositionList = [];
+        this.positionList = [];
+      },
       formValidate() {
         return new Promise((resolve, reject) => {
           this.$refs.form.validate((valid) => {
@@ -568,6 +823,11 @@
           this.factoryForm.name = n.name;
         }
       },
+      'form.type'(val) {
+        if (this.visible && String(val) === '30' && this.form.id) {
+          this.loadDepartmentPositions();
+        }
+      },
       visible(visible) {
         if (visible) {
           if (this.data) {
@@ -594,6 +854,7 @@
               }
               this.responsibleName =
                 res.manager && res.manager.map((item) => item.name).toString();
+              this.loadDepartmentPositions();
             });
 
             // this.form.type = '' + this.form.type; //回显
@@ -616,8 +877,16 @@
           this.enterprise = { ...defEnterprise };
           this.managerFirst = {};
           this.responsibleName = '';
+          this.resetDepartmentPosition();
         }
       }
     }
   };
 </script>
+
+<style scoped>
+  .dept-position-table {
+    width: 100%;
+    margin-bottom: 10px;
+  }
+</style>

+ 5 - 0
src/views/factoryModel/station/components/stationBeatDialog.vue

@@ -86,6 +86,11 @@
             prop: 'leaderName',
             slot: 'factory'
           },
+          {
+            // 工位操作人(人员)姓名,后端 FactoryWorkstationVO.userNames,多个人以逗号分隔
+            label: '操作人姓名',
+            prop: 'userNames'
+          },
           {
             label: '所属区域',
             prop: 'areaName'

+ 5 - 0
src/views/factoryModel/station/index.vue

@@ -137,6 +137,11 @@
             prop: 'leaderName',
             slot: 'factory'
           },
+          {
+            // 工位操作人(人员)姓名,后端 FactoryWorkstationVO.userNames,多个人以逗号分隔
+            label: '操作人姓名',
+            prop: 'userNames'
+          },
           {
             label: '所属区域',
             prop: 'areaName'

+ 177 - 60
src/views/material/BOMmanage/components/workmanship.vue

@@ -223,6 +223,7 @@
             :underline="false"
             icon="el-icon-view"
             @click="openConfigure(row, true)"
+            v-if="!row._isRouteOnly"
           >
             详情
           </el-link>
@@ -231,7 +232,7 @@
             :underline="false"
             icon="el-icon-setting"
             @click="openStepSetting(row)"
-            v-if="attributeData.status != 1"
+            v-if="attributeData.status != 1 && !row._isRouteOnly"
           >
             工步
           </el-link>
@@ -240,7 +241,7 @@
             :underline="false"
             icon="el-icon-plus"
             @click="openCreateStep(row)"
-            v-if="attributeData.status != 1"
+            v-if="attributeData.status != 1 && !row._isRouteOnly"
           >
             创建工步
           </el-link>
@@ -249,9 +250,13 @@
             :underline="false"
             icon="el-icon-setting"
             @click="openConfigure(row)"
+            v-if="!row._isRouteOnly"
           >
             配置
           </el-link>
+          <span v-if="row._isRouteOnly" class="workmanship-route-only-tip">
+            未配置
+          </span>
           <!-- <el-popconfirm
             class="ele-action"
             title="确定要删除当前工序吗?"
@@ -511,7 +516,9 @@
         // 工艺路线分组展开状态:{ [routeId]: true/false },默认全部展开
         expandedRouteMap: {},
         // 完整分组数据(含分组标题行),用于按展开状态过滤显示
-        rawGroupedList: []
+        rawGroupedList: [],
+        // 表格数据源请求序号(只用于比较,不参与渲染)
+        loadSeq: 0
       };
     },
     methods: {
@@ -661,7 +668,9 @@
           this.refreshTableView();
         });
       },
-      // 根据工艺路线对工序数据进行分组
+      // 根据工艺路线对工序数据进行分组:
+      // 分组依据是"工艺路线接口返回的工序列表",即每条工艺路线展示它自己的完整工序;
+      // 多条工艺路线共用同一道工序(sourceTaskId 相同)时,各分组下各展示一份,不做过滤。
       async groupTaskParamByRoute(dataList, routes) {
         if (!Array.isArray(dataList) || dataList.length === 0) {
           return [];
@@ -683,94 +692,162 @@
           });
           return result;
         }
-        // 通过路由查询工序,建立 sourceTaskId -> Set<routingId> 的多归属映射
-        // 一条工序可以同时属于多条工艺路线,不能再用一对一赋值(会覆盖)
-        const taskRouteMap = Object.create(null);
+
+        // 1) 按工艺路线逐条查询工序:N 次请求的结果各自保留、互不覆盖,
+        //    任何一条路线的返回都不能把其它路线的结果顶掉。
+        const routeEntryList = routes.map((r) => ({
+          route: r,
+          routeKey: String(r.id),
+          items: []
+        }));
         await Promise.all(
-          routes.map(async (r) => {
+          routeEntryList.map(async (entry) => {
             try {
               const res = await route.taskinstanceList({
-                routingId: r.id,
+                routingId: entry.route.id,
                 isDetail: true,
                 pageNum: 1,
                 size: -1
               });
               const list = (res && res.list) || [];
-              list.forEach((it) => {
-                const detail = it.detail || it;
-                const stid =
-                  detail.sourceTaskId != null
-                    ? detail.sourceTaskId
-                    : it.sourceTaskId;
-                if (stid != null) {
-                  if (!taskRouteMap[stid]) {
-                    taskRouteMap[stid] = new Set();
+              entry.items = list
+                .map((it, idx) => {
+                  const detail = it.detail || it;
+                  const stid =
+                    detail.sourceTaskId != null
+                      ? detail.sourceTaskId
+                      : it.sourceTaskId;
+                  if (stid == null) {
+                    return null;
                   }
-                  taskRouteMap[stid].add(r.id);
-                }
-              });
+                  return {
+                    sourceTaskId: stid,
+                    detail,
+                    orderNum: it.orderNum != null ? it.orderNum : idx + 1
+                  };
+                })
+                .filter((it) => it != null);
             } catch (e) {
               console.log(e, 'get route task list err');
             }
           })
         );
-        // 按工艺路线顺序分组,剩余未匹配到路线的归入"未分组"
-        const groups = routes.map((r) => ({ route: r, processes: [] }));
-        const ungrouped = [];
+
+        // 2) MBOM 工序记录索引:sourceTaskId -> 记录列表(保持 mBomPage 返回的顺序)
+        const recordBySourceTaskId = new Map();
         dataList.forEach((item) => {
-          // 收集本工序归属的全部 routeId:优先用 sourceTaskId 查表,回退到工序自带的 routingId
-          const routeIds = new Set();
-          const mapped = taskRouteMap[item.sourceTaskId];
-          if (mapped instanceof Set) {
-            mapped.forEach((id) => routeIds.add(id));
+          if (item.sourceTaskId == null) {
+            return;
           }
-          if (routeIds.size === 0 && item.routingId != null) {
-            routeIds.add(item.routingId);
+          const key = String(item.sourceTaskId);
+          if (!recordBySourceTaskId.has(key)) {
+            recordBySourceTaskId.set(key, []);
           }
-          if (routeIds.size === 0) {
-            item._routeId = UNGROUPED_ROUTE_ID;
-            ungrouped.push(item);
-            return;
+          recordBySourceTaskId.get(key).push(item);
+        });
+        // 已被前面分组优先占用的记录(只影响分配优先级,不阻止后续路线复用同一条记录)
+        const occupiedRecords = new Set();
+        // 取某条路线上某道工序对应的 MBOM 记录:
+        // 1) 记录自身 routingId 就是本路线的最精确,优先;
+        // 2) 其次取还没被别组占用的记录;
+        // 3) 都被占用时复用其中一条 —— 共用工序要在每条路线下各显示一份,不能过滤掉。
+        const pickRecord = (routeId, sourceTaskId) => {
+          const list = recordBySourceTaskId.get(String(sourceTaskId));
+          if (!list || !list.length) {
+            return null;
           }
-          // 多归属:浅克隆一份给每个归属路线,避免 _rowKey 冲突、且不污染原对象
-          // 浅克隆的嵌套字段(categoryParamStepList / produceList)继续共享引用,
-          // 由 fillStepLists 的 id 级缓存保证工步数据一致。
-          routeIds.forEach((routeId) => {
-            const matchedGroup = groups.find((g) => g.route.id === routeId);
-            if (!matchedGroup) {
-              item._routeId = UNGROUPED_ROUTE_ID;
-              ungrouped.push(item);
+          const own = list.find(
+            (rec) =>
+              rec.routingId != null && String(rec.routingId) === String(routeId)
+          );
+          if (own) {
+            return own;
+          }
+          return list.find((rec) => !occupiedRecords.has(rec)) || list[0];
+        };
+
+        // 3) 按工艺路线顺序组装分组数据
+        const renderedRecords = new Set();
+        const result = [];
+        routeEntryList.forEach((entry, gIdx) => {
+          const rows = [];
+          const pushRecordRow = (record, seq) => {
+            // 同一条 MBOM 工序可能同时出现在多条工艺路线分组下,
+            // 必须复制出行对象,否则 _routeId/_rowKey 会互相覆盖,分组展开状态会错乱
+            const row = Object.assign({}, record);
+            row._routeId = entry.route.id;
+            row._rowKey = `route_${entry.routeKey}_${
+              record.id != null ? 'id_' + record.id : 'idx_' + seq
+            }_${seq}`;
+            rows.push(row);
+            renderedRecords.add(record);
+          };
+          entry.items.forEach((item, idx) => {
+            const record = pickRecord(entry.route.id, item.sourceTaskId);
+            if (record) {
+              occupiedRecords.add(record);
+              pushRecordRow(record, idx);
               return;
             }
-            const cloned = {
-              ...item,
-              _routeId: matchedGroup.route.id,
-              _rowKey: `${item._rowKey}__r${matchedGroup.route.id}`
-            };
-            matchedGroup.processes.push(cloned);
+            // 该路线有这道工序、但 MBOM 里还没有对应记录:用接口明细补一行展示,
+            // 保证"路线里有就要显示",不因为没配置就被过滤掉(该行不可配置)
+            rows.push({
+              _rowKey: `routeonly_${entry.routeKey}_${String(
+                item.sourceTaskId
+              )}_${idx}`,
+              _routeId: entry.route.id,
+              _isRouteOnly: true,
+              code: item.detail.code,
+              name: item.detail.name,
+              controlName: item.detail.controlName,
+              workCenterName: item.detail.workCenterName,
+              routingId: entry.route.id,
+              sourceTaskId: item.sourceTaskId,
+              sort: null,
+              categoryParamStepList: []
+            });
           });
-        });
-        const result = [];
-        groups.forEach((group, gIdx) => {
-          if (group.processes.length === 0) {
+          // 接口没返回数据(或该路线确实没工序)时的兜底:
+          // 把 routingId 属于本路线、且还没出现在任何分组里的记录补进来,避免丢数据
+          if (rows.length === 0) {
+            dataList.forEach((record) => {
+              if (
+                record.routingId != null &&
+                String(record.routingId) === entry.routeKey &&
+                !renderedRecords.has(record)
+              ) {
+                occupiedRecords.add(record);
+                pushRecordRow(record, rows.length);
+              }
+            });
+          }
+          if (rows.length === 0) {
             return;
           }
           result.push({
-            _rowKey: `group_header_${group.route.id}_${gIdx}`,
+            _rowKey: `group_header_${entry.routeKey}_${gIdx}`,
             _isGroupHeader: true,
-            _routeId: group.route.id,
-            _routeInfo: group.route
+            _routeId: entry.route.id,
+            _routeInfo: entry.route
           });
-          group.processes.forEach((item) => result.push(item));
+          rows.forEach((row) => result.push(row));
         });
+
+        // 4) MBOM 里有、但所有工艺路线接口都没返回的工序 → 归入"未关联工艺路线"
+        const ungrouped = dataList.filter(
+          (record) => !renderedRecords.has(record)
+        );
         if (ungrouped.length > 0) {
           result.push({
-            _rowKey: `group_header_ungrouped_${groups.length}`,
+            _rowKey: `group_header_ungrouped_${routeEntryList.length}`,
             _isGroupHeader: true,
             _routeId: UNGROUPED_ROUTE_ID,
             _routeInfo: { name: '未关联工艺路线' }
           });
-          ungrouped.forEach((item) => result.push(item));
+          ungrouped.forEach((item) => {
+            item._routeId = UNGROUPED_ROUTE_ID;
+            result.push(item);
+          });
         }
         return result;
       },
@@ -1014,6 +1091,10 @@
       },
       /* 表格数据源 */
       async datasource({ page, limit, where }) {
+        // 请求序号:datasource 可能被并发触发多次(attributeData 深度监听 + 切换 tab 都会 reload),
+        // 只允许最新一次查询写回表格数据,避免先发后到的旧数据覆盖新数据
+        const loadSeq = (this.loadSeq || 0) + 1;
+        this.loadSeq = loadSeq;
         let data = await getMbomPage({
           ...where,
           bomCategoryId: this.resourceBomId,
@@ -1021,6 +1102,9 @@
           pageNum: page,
           size: limit
         });
+        if (loadSeq !== this.loadSeq) {
+          return this.buildVisibleRows();
+        }
         if (data?.length > 0) {
           this.currentTableData = data[0];
           let dataList = [];
@@ -1050,6 +1134,10 @@
             dataList,
             routes
           );
+          // 分组过程包含异步请求,这里再校验一次请求序号,确保只有最新一次查询写回
+          if (loadSeq !== this.loadSeq) {
+            return this.buildVisibleRows();
+          }
 
           // 保存完整分组数据(含标题行),便于按展开状态过滤
           this.rawGroupedList = groupedList;
@@ -1063,7 +1151,32 @@
           const processList = groupedList.filter(
             (item) => !this.isGroupHeader(item)
           );
-          await this.fillStepLists(processList);
+          // 同一道 MBOM 工序可能同时出现在多条工艺路线分组下,
+          // 工步只请求一次,再把结果共享给各分组里的同名行
+          const stepRowMap = new Map();
+          const stepRowList = [];
+          processList.forEach((row) => {
+            if (row._isRouteOnly) {
+              return;
+            }
+            const key = row.id != null ? String(row.id) : row._rowKey;
+            if (stepRowMap.has(key)) {
+              return;
+            }
+            stepRowMap.set(key, row);
+            stepRowList.push(row);
+          });
+          await this.fillStepLists(stepRowList);
+          processList.forEach((row) => {
+            if (row._isRouteOnly) {
+              return;
+            }
+            const key = row.id != null ? String(row.id) : row._rowKey;
+            const source = stepRowMap.get(key);
+            if (source && source !== row) {
+              row.categoryParamStepList = source.categoryParamStepList;
+            }
+          });
 
           return this.buildVisibleRows();
 
@@ -1260,6 +1373,10 @@
             color: #409eff;
           }
         }
+        .workmanship-route-only-tip {
+          color: #e6a23c;
+          font-size: 12px;
+        }
       }
     }
   }

+ 4 - 0
src/views/material/materialBOM/components/view-dialog.vue

@@ -116,6 +116,10 @@
             label: '物料编码',
             prop: 'categoryCode'
           },
+          {
+            label: '下料尺寸',
+            prop: 'cuttingSize'
+          },
           {
             label: '牌号',
             prop: 'brandNum'