From cbcce4d5e878cbdc68d7928634ab25c4d8efb125 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期三, 22 四月 2026 13:39:55 +0800
Subject: [PATCH] 工艺路线模块修改
---
src/views/productionManagement/processRoute/index.vue | 1
src/api/productionManagement/processRouteItem.js | 4
src/api/productionManagement/productionProcess.js | 2
src/views/productionManagement/processRoute/processRouteItem/index.vue | 471 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/components/ProcessParamListDialog.vue | 29 --
5 files changed, 480 insertions(+), 27 deletions(-)
diff --git a/src/api/productionManagement/processRouteItem.js b/src/api/productionManagement/processRouteItem.js
index 3843203..4c4bf53 100644
--- a/src/api/productionManagement/processRouteItem.js
+++ b/src/api/productionManagement/processRouteItem.js
@@ -12,7 +12,7 @@
export function addOrUpdateProcessRouteItem(data) {
return request({
- url: "/technologyRoutingOperation",
+ url: "/technologyRoutingOperation/add",
method: "post",
data: data,
});
@@ -54,7 +54,7 @@
// 宸ヨ壓璺嚎鍙傛暟鏂板
export function addProcessRouteItemParam(data) {
return request({
- url: "/technologyRoutingOperationParam",
+ url: "/technologyRoutingOperationParam/add",
method: "post",
data: data,
});
diff --git a/src/api/productionManagement/productionProcess.js b/src/api/productionManagement/productionProcess.js
index fbede6e..7001997 100644
--- a/src/api/productionManagement/productionProcess.js
+++ b/src/api/productionManagement/productionProcess.js
@@ -28,7 +28,7 @@
}
export function add(data) {
return request({
- url: "/technologyOperation/",
+ url: "/technologyOperation/add",
method: "post",
data: data,
});
diff --git a/src/components/ProcessParamListDialog.vue b/src/components/ProcessParamListDialog.vue
index 8ea5856..dffb7b5 100644
--- a/src/components/ProcessParamListDialog.vue
+++ b/src/components/ProcessParamListDialog.vue
@@ -128,8 +128,7 @@
<el-form-item label="鍗曚綅">
<span class="detail-text">{{ selectedParam.unit || '-' }}</span>
</el-form-item>
- <el-form-item label="鏍囧噯鍊�"
- v-if="selectedParam.paramType == '1'">
+ <el-form-item label="鏍囧噯鍊�">
<el-input v-model="selectedParam.standardValue"
placeholder="璇疯緭鍏ラ粯璁ゅ��" />
</el-form-item>
@@ -174,10 +173,8 @@
<span class="detail-text">{{ editParamForm.unit || '-' }}</span>
</el-form-item>
<el-form-item label="鏍囧噯鍊�"
- v-if="editParamForm.paramType == '1'"
prop="standardValue">
<el-input v-model="editParamForm.standardValue"
- type="number"
placeholder="璇疯緭鍏ユ爣鍑嗗��" />
</el-form-item>
</el-form>
@@ -272,7 +269,7 @@
unit: "",
});
const editParamRules = ref({
- standardValue: [{ required: true, message: "璇疯緭鍏ユ爣鍑嗗��", trigger: "blur" }],
+ // standardValue: [{ required: true, message: "璇疯緭鍏ユ爣鍑嗗��", trigger: "blur" }],
});
const editParamFormRef = ref(null);
@@ -374,9 +371,6 @@
return;
}
- // 鍒ゆ柇鍙傛暟绫诲瀷锛屽彧鏈夋暟鍊肩被鍨嬫墠浼犳爣鍑嗗�笺�佹渶澶у�煎拰鏈�灏忓��
- const isNumericMode = selectedParam.value.paramType == 1;
- console.log(isNumericMode, "isNumericMode");
// 璋冪敤API鏂板鍙傛暟
if (props.pageType === "order") {
addProcessRouteItemParamOrder({
@@ -385,9 +379,7 @@
routeItemId: props.process.id,
// routeItemId: Number(props.routeId),
paramId: selectedParam.value.id,
- standardValue: isNumericMode
- ? selectedParam.value.standardValue || ""
- : "",
+ standardValue: selectedParam.value.standardValue || "",
isRequired: selectedParam.value.isRequired || 0,
})
.then(res => {
@@ -409,9 +401,7 @@
addProcessRouteItemParam({
technologyRoutingOperationId: props.process.id,
paramId: selectedParam.value.id,
- standardValue: isNumericMode
- ? selectedParam.value.standardValue || ""
- : "",
+ standardValue: selectedParam.value.standardValue || "",
isRequired: selectedParam.value.isRequired || 0,
})
.then(res => {
@@ -435,17 +425,12 @@
if (!editParamFormRef.value) return;
editParamFormRef.value.validate(valid => {
if (valid) {
- // 鍒ゆ柇鍙傛暟绫诲瀷锛屽彧鏈夋暟鍊肩被鍨嬫墠浼犳爣鍑嗗�笺�佹渶澶у�煎拰鏈�灏忓��
- const isNumericMode = editParamForm.value.paramType == 1;
- console.log(isNumericMode, "isNumericMode");
if (props.pageType === "order") {
editProcessRouteItemParamOrder({
id: editParamForm.value.id,
// routeItemId: props.process.id,
// paramId: editParamForm.value.paramId,
- standardValue: isNumericMode
- ? editParamForm.value.standardValue || ""
- : "",
+ standardValue: editParamForm.value.standardValue || "",
isRequired: editParamForm.value.isRequired || 0,
})
.then(res => {
@@ -467,9 +452,7 @@
id: editParamForm.value.id,
technologyRoutingOperationId: props.process.id,
paramId: editParamForm.value.paramId,
- standardValue: isNumericMode
- ? editParamForm.value.standardValue || ""
- : "",
+ standardValue: editParamForm.value.standardValue || "",
isRequired: editParamForm.value.isRequired || 0,
})
.then(res => {
diff --git a/src/views/productionManagement/processRoute/index.vue b/src/views/productionManagement/processRoute/index.vue
index 3a8acc5..e30566e 100644
--- a/src/views/productionManagement/processRoute/index.vue
+++ b/src/views/productionManagement/processRoute/index.vue
@@ -177,6 +177,7 @@
productName: row.productName || "",
model: row.model || "",
bomNo: row.bomNo || "",
+ bomId: row.bomId || "",
description: row.description || "",
type: "route",
},
diff --git a/src/views/productionManagement/processRoute/processRouteItem/index.vue b/src/views/productionManagement/processRoute/processRouteItem/index.vue
index c310b45..6fbaa2c 100644
--- a/src/views/productionManagement/processRoute/processRouteItem/index.vue
+++ b/src/views/productionManagement/processRoute/processRouteItem/index.vue
@@ -191,6 +191,163 @@
</div>
</div>
</template>
+ <!-- bom妯″潡 -->
+ <div class="section-header"
+ style="margin-top: 20px;">
+ <div class="section-title">BOM 缁撴瀯</div>
+ <div class="section-actions"
+ v-if="pageType === 'order'">
+ <el-button v-if="!bomDataValue.isEdit"
+ type="primary"
+ @click="bomDataValue.isEdit = true">
+ 缂栬緫
+ </el-button>
+ <el-button v-if="bomDataValue.isEdit"
+ @click="cancelEditBom">
+ 鍙栨秷
+ </el-button>
+ <el-button v-if="bomDataValue.isEdit"
+ type="primary"
+ @click="handleSaveBom"
+ :loading="bomDataValue.loading">
+ 淇濆瓨BOM
+ </el-button>
+ </div>
+ </div>
+ <el-table :data="bomTableData"
+ border
+ :preserve-expanded-content="false"
+ :default-expand-all="true"
+ style="width: 100%">
+ <el-table-column type="expand">
+ <template #default="props">
+ <el-form ref="form"
+ :model="bomDataValue">
+ <el-table :data="bomDataValue.dataList"
+ row-key="tempId"
+ default-expand-all
+ :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+ style="width: 100%">
+ <el-table-column prop="productName"
+ label="浜у搧" />
+ <el-table-column prop="model"
+ label="瑙勬牸">
+ <template #default="{ row }">
+ <el-form-item v-if="pageType === 'order' && bomDataValue.isEdit"
+ :rules="[{ required: true, message: '璇烽�夋嫨瑙勬牸', trigger: ['blur','change'] }]"
+ style="margin: 0">
+ <el-select v-model="row.model"
+ placeholder="璇烽�夋嫨瑙勬牸"
+ clearable
+ :disabled="!bomDataValue.isEdit || bomDataValue.dataList.some(item => (item).tempId === row.tempId)"
+ style="width: 100%"
+ @visible-change="(v) => { if (v) openBomDialog(row.tempId) }">
+ <el-option v-if="row.model"
+ :label="row.model"
+ :value="row.model" />
+ </el-select>
+ </el-form-item>
+ </template>
+ </el-table-column>
+ <el-table-column prop="processName"
+ label="娑堣�楀伐搴�">
+ <template #default="{ row }">
+ <el-form-item v-if="pageType === 'order' && bomDataValue.isEdit"
+ :rules="bomDataValue.dataList.some(item => (item).tempId === row.tempId) ? [] : [{ required: true, message: '璇烽�夋嫨娑堣�楀伐搴�', trigger: 'change' }]"
+ style="margin: 0">
+ <el-select v-model="row.processId"
+ placeholder="璇烽�夋嫨"
+ filterable
+ clearable
+ style="width: 100%"
+ @change="value => handleBomProcessChange(row, value)"
+ :disabled="!bomDataValue.isEdit || bomDataValue.dataList.some(item => (item).tempId === row.tempId)">
+ <el-option v-for="item in bomDataValue.processOptions"
+ :key="item.id"
+ :label="item.name"
+ :value="item.id" />
+ </el-select>
+ </el-form-item>
+ </template>
+ </el-table-column>
+ <el-table-column prop="unitQuantity"
+ label="鍗曚綅浜у嚭鎵�闇�鏁伴噺">
+ <template #default="{ row }">
+ <el-form-item v-if="pageType === 'order' && bomDataValue.isEdit"
+ :rules="[{ required: true, message: '璇疯緭鍏ュ崟浣嶄骇鍑烘墍闇�鏁伴噺', trigger: ['blur','change'] }]"
+ style="margin: 0">
+ <el-input-number v-model="row.unitQuantity"
+ :min="0"
+ :precision="2"
+ :step="1"
+ controls-position="right"
+ style="width: 100%"
+ :disabled="!bomDataValue.isEdit || bomDataValue.dataList.some(item => (item).tempId === row.tempId)" />
+ </el-form-item>
+ </template>
+ </el-table-column>
+ <el-table-column v-if="pageType === 'order'"
+ prop="demandedQuantity"
+ label="闇�姹傛�婚噺">
+ <template #default="{ row }">
+ <el-form-item v-if="pageType === 'order' && bomDataValue.isEdit"
+ :rules="[{ required: true, message: '璇疯緭鍏ラ渶姹傛�婚噺', trigger: ['blur','change'] }]"
+ style="margin: 0">
+ <el-input-number v-model="row.demandedQuantity"
+ :min="0"
+ :precision="2"
+ :step="1"
+ controls-position="right"
+ style="width: 100%"
+ :disabled="!bomDataValue.isEdit || bomDataValue.dataList.some(item => (item).tempId === row.tempId)" />
+ </el-form-item>
+ </template>
+ </el-table-column>
+ <el-table-column prop="unit"
+ label="鍗曚綅">
+ <template #default="{ row }">
+ <el-form-item v-if="pageType === 'order' && bomDataValue.isEdit"
+ :rules="[{ required: true, message: '璇疯緭鍏ュ崟浣�', trigger: ['blur','change'] }]"
+ style="margin: 0">
+ <el-input v-model="row.unit"
+ placeholder="璇疯緭鍏ュ崟浣�"
+ clearable
+ :disabled="!bomDataValue.isEdit || bomDataValue.dataList.some(item => (item).tempId === row.tempId)" />
+ </el-form-item>
+ </template>
+ </el-table-column>
+ <el-table-column label="鎿嶄綔"
+ fixed="right"
+ width="200"
+ v-if="pageType === 'order' && bomDataValue.isEdit">
+ <template #default="{ row }">
+ <el-button v-if="bomDataValue.isEdit && !bomDataValue.dataList.some(item => (item).tempId === row.tempId)"
+ type="danger"
+ text
+ @click="removeBomItem(row.tempId)">鍒犻櫎
+ </el-button>
+ <el-button v-if="bomDataValue.isEdit"
+ type="primary"
+ text
+ @click="addBomItem(row.tempId)">娣诲姞
+ </el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ </el-form>
+ </template>
+ </el-table-column>
+ <el-table-column label="BOM缂栧彿"
+ prop="bomNo" />
+ <el-table-column label="浜у搧鍚嶇О"
+ prop="productName" />
+ <el-table-column label="瑙勬牸鍨嬪彿"
+ prop="model" />
+ </el-table>
+ <ProductSelectDialog v-if="bomDataValue.showProductDialog"
+ v-model:model-value="bomDataValue.showProductDialog"
+ :single="true"
+ @confirm="handleBomProduct" />
<!-- 鏂板/缂栬緫寮圭獥 -->
<el-dialog v-model="dialogVisible"
:title="operationType === 'add' ? '鏂板宸ヨ壓璺嚎椤圭洰' : '缂栬緫宸ヨ壓璺嚎椤圭洰'"
@@ -289,6 +446,11 @@
sortRouteItem,
} from "@/api/productionManagement/productProcessRoute.js";
import { processList } from "@/api/productionManagement/productionProcess.js";
+ import { listProcessBom } from "@/api/productionManagement/productionOrder.js";
+ import {
+ queryList,
+ addBomDetail,
+ } from "@/api/productionManagement/productStructure.js";
import { useRoute } from "vue-router";
import { ElMessageBox, ElMessage } from "element-plus";
import Sortable from "sortablejs";
@@ -414,6 +576,7 @@
processList({ size: -1, current: -1 })
.then(res => {
processOptions.value = res.data.records || [];
+ bomDataValue.value.processOptions = processOptions.value;
})
.catch(err => {
console.error("鑾峰彇宸ュ簭澶辫触锛�", err);
@@ -427,9 +590,13 @@
productName: route.query.productName || "",
model: route.query.model || "",
bomNo: route.query.bomNo || "",
+ bomId: route.query.bomId || "",
description: route.query.description || "",
status: !(route.query.status == 1 || route.query.status === "false"),
};
+ bomTableData.value[0].productName = routeInfo.value.productName;
+ bomTableData.value[0].model = routeInfo.value.model;
+ bomTableData.value[0].bomNo = routeInfo.value.bomNo;
};
// 鏂板
@@ -596,7 +763,7 @@
const handleViewParams = row => {
currentProcess.value = row;
const query = {
- routeItemId: row.id,
+ technologyRoutingOperationId: row.id,
orderId: orderId.value,
};
@@ -758,10 +925,312 @@
}
};
+ // BOM鐩稿叧鐘舵�佸拰鏂规硶
+ const bomTableData = ref([
+ {
+ productName: "",
+ model: "",
+ bomNo: "",
+ },
+ ]);
+
+ const bomDataValue = ref({
+ dataList: [],
+ processOptions: [],
+ showProductDialog: false,
+ currentRowName: null,
+ loading: false,
+ isEdit: false,
+ });
+
+ const syncProcessOperationFields = item => {
+ const processId = item.processId ?? item.operationId ?? "";
+ if (!processId) {
+ item.processId = "";
+ return;
+ }
+ const option = bomDataValue.value.processOptions.find(
+ p => p.id === processId
+ );
+ const processName =
+ option?.name || item.processName || item.operationName || "";
+
+ item.processId = processId;
+ item.operationId = processId;
+ item.processName = processName;
+ item.operationName = processName;
+ };
+
+ const normalizeTreeData = items => {
+ items.forEach(item => {
+ item.tempId = item.tempId || item.id || `${Date.now()}_${Math.random()}`;
+ syncProcessOperationFields(item);
+ if (Array.isArray(item.children) && item.children.length > 0) {
+ normalizeTreeData(item.children);
+ }
+ });
+ };
+
+ const handleBomProcessChange = (row, value) => {
+ row.processId = value || "";
+ syncProcessOperationFields(row);
+ };
+
+ const openBomDialog = tempId => {
+ bomDataValue.value.currentRowName = tempId;
+ bomDataValue.value.showProductDialog = true;
+ };
+
+ const fetchBomData = async () => {
+ try {
+ const { data } = await queryList(routeInfo.value.bomId);
+ bomDataValue.value.dataList = data || [];
+ normalizeTreeData(bomDataValue.value.dataList);
+ } catch (err) {
+ console.error("鑾峰彇BOM鏁版嵁澶辫触锛�", err);
+ }
+ };
+
+ const childItem = (item, tempId, productData) => {
+ if (item.tempId === tempId) {
+ item.productName = productData.productName;
+ item.model = productData.model;
+ item.productModelId = productData.id;
+ item.unit = productData.unit || "";
+ return true;
+ }
+ if (item.children && item.children.length > 0) {
+ for (let child of item.children) {
+ if (childItem(child, tempId, productData)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+
+ const handleBomProduct = row => {
+ if (!Array.isArray(row) || row.length === 0) {
+ ElMessage.warning("璇烽�夋嫨涓�涓骇鍝�");
+ return;
+ }
+ const productData = row[row.length - 1];
+
+ const isTopLevel = bomDataValue.value.dataList.some(
+ item => item.tempId === bomDataValue.value.currentRowName
+ );
+ if (isTopLevel) {
+ if (
+ productData.productName === bomTableData.value[0].productName &&
+ productData.model === bomTableData.value[0].model
+ ) {
+ const hasOther = bomDataValue.value.dataList.some(
+ item =>
+ item.tempId !== bomDataValue.value.currentRowName &&
+ item.productName === bomTableData.value[0].productName &&
+ item.model === bomTableData.value[0].model
+ );
+ if (hasOther) {
+ ElMessage.warning("鏈�澶栧眰鍜屽綋鍓嶄骇鍝佷竴鏍风殑涓�绾у彧鑳芥湁涓�涓�");
+ return;
+ }
+ }
+ }
+ bomDataValue.value.dataList.forEach(item => {
+ if (item.tempId === bomDataValue.value.currentRowName) {
+ item.productName = productData.productName;
+ item.model = productData.model;
+ item.productModelId = productData.id;
+ item.unit = productData.unit || "";
+ return;
+ }
+ childItem(item, bomDataValue.value.currentRowName, productData);
+ });
+ bomDataValue.value.showProductDialog = false;
+ };
+
+ const removeBomItem = tempId => {
+ const topIndex = bomDataValue.value.dataList.findIndex(
+ item => item.tempId === tempId
+ );
+ if (topIndex !== -1) {
+ bomDataValue.value.dataList.splice(topIndex, 1);
+ return;
+ }
+
+ const delchildItem = (items, tempId) => {
+ for (let i = 0; i < items.length; i++) {
+ const item = items[i];
+ if (item.tempId === tempId) {
+ items.splice(i, 1);
+ return true;
+ }
+ if (item.children && item.children.length > 0) {
+ if (delchildItem(item.children, tempId)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+
+ bomDataValue.value.dataList.forEach(item => {
+ if (item.children && item.children.length > 0) {
+ delchildItem(item.children, tempId);
+ }
+ });
+ };
+
+ const addchildItem = (item, tempId) => {
+ if (item.tempId === tempId) {
+ if (!item.children) {
+ item.children = [];
+ }
+ item.children.push({
+ parentId: item.id || "",
+ parentTempId: item.tempId || "",
+ productName: "",
+ productId: "",
+ model: undefined,
+ productModelId: undefined,
+ processId: "",
+ processName: "",
+ operationId: "",
+ operationName: "",
+ unitQuantity: 1,
+ demandedQuantity: 0,
+ children: [],
+ unit: "",
+ tempId: new Date().getTime(),
+ });
+ return true;
+ }
+ if (item.children && item.children.length > 0) {
+ for (let child of item.children) {
+ if (addchildItem(child, tempId)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+
+ const addBomItem = tempId => {
+ bomDataValue.value.dataList.forEach(item => {
+ if (item.tempId === tempId) {
+ if (!item.children) {
+ item.children = [];
+ }
+ item.children.push({
+ parentId: item.id || "",
+ parentTempId: item.tempId || "",
+ productName: "",
+ productId: "",
+ model: undefined,
+ productModelId: undefined,
+ processId: "",
+ processName: "",
+ operationId: "",
+ operationName: "",
+ unitQuantity: 1,
+ demandedQuantity: 0,
+ unit: "",
+ children: [],
+ tempId: new Date().getTime(),
+ });
+ return;
+ }
+ addchildItem(item, tempId);
+ });
+ };
+
+ const validateAllBom = () => {
+ let isValid = true;
+ const isOrderPage = pageType.value === "order";
+
+ const validateItem = (item, isTopLevel = false) => {
+ if (!item.model) {
+ ElMessage.error("璇烽�夋嫨瑙勬牸");
+ isValid = false;
+ return;
+ }
+ if (!isTopLevel && !item.processId) {
+ ElMessage.error("璇烽�夋嫨娑堣�楀伐搴�");
+ isValid = false;
+ return;
+ }
+ if (!item.unitQuantity) {
+ ElMessage.error("璇疯緭鍏ュ崟浣嶄骇鍑烘墍闇�鏁伴噺");
+ isValid = false;
+ return;
+ }
+ if (isOrderPage && !item.demandedQuantity) {
+ ElMessage.error("璇疯緭鍏ラ渶姹傛�婚噺");
+ isValid = false;
+ return;
+ }
+
+ if (item.children && item.children.length > 0) {
+ item.children.forEach(child => {
+ validateItem(child, false);
+ });
+ }
+ };
+
+ bomDataValue.value.dataList.forEach(item => {
+ validateItem(item, true);
+ });
+
+ return isValid;
+ };
+
+ const buildSubmitTree = items => {
+ return items.map(item => {
+ const current = { ...item };
+ syncProcessOperationFields(current);
+ current.children = Array.isArray(current.children)
+ ? buildSubmitTree(current.children)
+ : [];
+ return current;
+ });
+ };
+
+ const cancelEditBom = () => {
+ bomDataValue.value.isEdit = false;
+ fetchBomData();
+ };
+
+ const handleSaveBom = () => {
+ bomDataValue.value.loading = true;
+ normalizeTreeData(bomDataValue.value.dataList);
+
+ const valid = validateAllBom();
+ if (valid) {
+ addBomDetail({
+ bomId: routeInfo.value.bomId,
+ children: buildSubmitTree(bomDataValue.value.dataList || []),
+ })
+ .then(() => {
+ ElMessage.success("BOM淇濆瓨鎴愬姛");
+ bomDataValue.value.isEdit = false;
+ fetchBomData();
+ })
+ .catch(() => {
+ ElMessage.error("BOM淇濆瓨澶辫触");
+ })
+ .finally(() => {
+ bomDataValue.value.loading = false;
+ });
+ } else {
+ bomDataValue.value.loading = false;
+ }
+ };
+
onMounted(() => {
getRouteInfo();
getList();
getProcessList();
+ fetchBomData();
});
onUnmounted(() => {
--
Gitblit v1.9.3