From 45a98ba63e6541a82416fde84aa5fa2efb9679bd Mon Sep 17 00:00:00 2001
From: huminmin <mac@MacBook-Pro.local>
Date: 星期三, 20 五月 2026 17:01:02 +0800
Subject: [PATCH] Merge branch 'dev_NEW_pro' of http://114.132.189.42:9002/r/product-inventory-management into dev_NEW_pro
---
src/views/productionManagement/productStructure/Detail/index.vue | 259 ++++++++++++++++++++++++++++++++++++++++++++-------
1 files changed, 221 insertions(+), 38 deletions(-)
diff --git a/src/views/productionManagement/productStructure/Detail/index.vue b/src/views/productionManagement/productStructure/Detail/index.vue
index 3a76e48..5cb08e8 100644
--- a/src/views/productionManagement/productStructure/Detail/index.vue
+++ b/src/views/productionManagement/productStructure/Detail/index.vue
@@ -64,6 +64,7 @@
filterable
clearable
style="width: 100%"
+ @change="value => handleProcessChange(row, value)"
:disabled="!dataValue.isEdit || dataValue.dataList.some(item => (item as any).tempId === row.tempId)">
<el-option v-for="item in dataValue.processOptions"
:key="item.id"
@@ -85,6 +86,7 @@
:step="1"
controls-position="right"
style="width: 100%"
+ @change="handleUnitQuantityChange"
:disabled="!dataValue.isEdit || dataValue.dataList.some(item => (item as any).tempId === row.tempId)" />
</el-form-item>
</template>
@@ -102,7 +104,7 @@
:step="1"
controls-position="right"
style="width: 100%"
- :disabled="!dataValue.isEdit || dataValue.dataList.some(item => (item as any).tempId === row.tempId)" />
+ :disabled="true" />
</el-form-item>
</template>
</el-table-column>
@@ -115,7 +117,7 @@
<el-input v-model="row.unit"
placeholder="璇疯緭鍏ュ崟浣�"
clearable
- :disabled="!dataValue.isEdit || dataValue.dataList.some(item => (item as any).tempId === row.tempId)" />
+ :disabled="!dataValue.isEdit || dataValue.dataList.some(item => (item as any).tempId === row.tempId)" />
</el-form-item>
</template>
</el-table-column>
@@ -148,6 +150,7 @@
</el-table>
<product-select-dialog v-if="dataValue.showProductDialog"
v-model:model-value="dataValue.showProductDialog"
+ :single="true"
@confirm="handleProduct" />
</div>
</template>
@@ -161,7 +164,10 @@
reactive,
ref,
} from "vue";
- import { queryList, add } from "@/api/productionManagement/productStructure.js";
+ import {
+ queryList,
+ addBomDetail,
+ } from "@/api/productionManagement/productStructure.js";
import { listProcessBom } from "@/api/productionManagement/productionOrder.js";
import { list } from "@/api/productionManagement/productionProcess";
import { ElMessage } from "element-plus";
@@ -212,6 +218,140 @@
isEdit: false,
});
+ const normalizeListData = (source: any) => {
+ if (Array.isArray(source)) {
+ return source;
+ }
+ if (Array.isArray(source?.records)) {
+ return source.records;
+ }
+ return [];
+ };
+
+ const getProcessOptionById = (id: any) => {
+ if (id === undefined || id === null || id === "") {
+ return null;
+ }
+ return (
+ normalizeListData(dataValue.processOptions).find(
+ option => String(option.id) === String(id)
+ ) || null
+ );
+ };
+
+ const syncProcessOperationFields = (item: any) => {
+ const processId = item.processId ?? item.operationId ?? "";
+ if (!processId) {
+ item.processId = "";
+ item.operationId = "";
+ item.processName = "";
+ item.operationName = "";
+ return;
+ }
+
+ const option = getProcessOptionById(processId);
+ const processName =
+ option?.name || item.processName || item.operationName || "";
+
+ item.processId = processId;
+ item.operationId = processId;
+ item.processName = processName;
+ item.operationName = processName;
+ };
+
+ const normalizeTreeData = (items: any[]) => {
+ items.forEach((item: any) => {
+ 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 toQuantityNumber = (value: any) => {
+ const numberValue = Number(value);
+ if (!Number.isFinite(numberValue)) {
+ return 0;
+ }
+ return Number(numberValue.toFixed(2));
+ };
+
+ const syncDemandedQuantityTree = (
+ items: any[],
+ parentDemandedQuantity: number | null = null
+ ) => {
+ items.forEach((item: any) => {
+ if (parentDemandedQuantity !== null) {
+ item.demandedQuantity = toQuantityNumber(
+ parentDemandedQuantity * toQuantityNumber(item.unitQuantity)
+ );
+ }
+
+ if (Array.isArray(item.children) && item.children.length > 0) {
+ syncDemandedQuantityTree(
+ item.children,
+ toQuantityNumber(item.demandedQuantity)
+ );
+ }
+ });
+ };
+
+ const recalculateDemandedQuantities = () => {
+ if (!isOrderPage.value) {
+ return;
+ }
+
+ syncDemandedQuantityTree(dataValue.dataList);
+ };
+
+ const buildSubmitTree = (items: any[]) => {
+ return items.map((item: any) => {
+ const current = { ...item };
+ syncProcessOperationFields(current);
+ current.children = Array.isArray(current.children)
+ ? buildSubmitTree(current.children)
+ : [];
+ return current;
+ });
+ };
+
+ const findSiblings = (items: any[], tempId: string): any[] | null => {
+ if (!items || items.length === 0) return null;
+ // 妫�鏌ュ綋鍓嶅眰绾�
+ if (items.some(item => item.tempId === tempId)) {
+ return items;
+ }
+ // 閫掑綊鏌ユ壘瀛愮骇
+ for (const item of items) {
+ if (item.children && item.children.length > 0) {
+ const result = findSiblings(item.children, tempId);
+ if (result) return result;
+ }
+ }
+ return null;
+ };
+
+ const handleProcessChange = (row: any, value: any) => {
+ row.processId = value || "";
+ syncProcessOperationFields(row);
+
+ // 妫�鏌ュ悓涓�灞傜骇鏄惁宸茬粡鏈夊叾浠栦笉鍚岀殑宸ュ簭琚�変腑
+ const siblings = findSiblings(dataValue.dataList, row.tempId);
+ if (siblings && value) {
+ const hasDifferentProcess = siblings.some(sibling => {
+ return sibling.tempId !== row.tempId && sibling.processId && sibling.processId !== value;
+ });
+ if (hasDifferentProcess) {
+ ElMessage.warning("鍚屼竴灞傜骇宸插瓨鍦ㄤ笉鍚岀殑宸ュ簭锛岃鍏堢粺涓�宸ュ簭鍚庡啀杩涜淇敼");
+ }
+ }
+ };
+
+ const handleUnitQuantityChange = () => {
+ recalculateDemandedQuantities();
+ };
+
const tableData = reactive([
{
productName: "",
@@ -231,48 +371,47 @@
// 璁㈠崟鎯呭喌锛氫娇鐢ㄨ鍗曠殑浜у搧缁撴瀯鎺ュ彛
const { data } = await listProcessBom({ orderId: routeOrderId.value });
dataValue.dataList = (data as any) || [];
+ normalizeTreeData(dataValue.dataList);
+ recalculateDemandedQuantities();
} else {
// 闈炶鍗曟儏鍐碉細浣跨敤鍘熸潵鐨勬帴鍙�
const { data } = await queryList(routeId.value);
dataValue.dataList = (data as any) || [];
- // 涓烘墍鏈夐」鍙婂叾瀛愰」璁剧疆name灞炴��
- const setNameRecursively = (items: any[]) => {
- items.forEach((item: any) => {
- item.tempId = item.id;
- item.processName =
- dataValue.processOptions.find(option => option.id === item.processId)
- ?.name || "";
- if (item.children && item.children.length > 0) {
- setNameRecursively(item.children);
- }
- });
- };
- setNameRecursively(dataValue.dataList);
+ console.log(dataValue);
+ normalizeTreeData(dataValue.dataList);
console.log(dataValue.dataList, "dataValue.dataList");
}
};
const fetchProcessOptions = async () => {
- const { data } = await list();
- dataValue.processOptions = data as any;
+ const { data } = await list({});
+ console.log(data, "dataValue.dataList");
+ dataValue.processOptions = normalizeListData(data);
};
const handleProduct = (row: any) => {
- if (row?.length > 1) {
- ElMessage.error("鍙兘閫夋嫨涓�涓骇鍝�");
+ if (!Array.isArray(row) || row.length === 0) {
+ ElMessage.warning("璇烽�夋嫨涓�涓骇鍝�");
+ return;
}
- const productData = row[0];
+ // 鍙厑璁镐竴涓細濡傛灉涓婃父杩斿洖浜嗗涓紝榛樿浣跨敤鏈�鍚庝竴娆¢�夋嫨骞惰鐩栧綋鍓嶅��
+ const productData = row[row.length - 1];
// 鏈�澶栧眰缁勪欢涓紝涓庡綋鍓嶄骇鍝佺浉鍚岀殑浜у搧鍙兘鏈変竴涓�
- const isTopLevel = dataValue.dataList.some(item => (item as any).tempId === dataValue.currentRowName);
+ const isTopLevel = dataValue.dataList.some(
+ item => (item as any).tempId === dataValue.currentRowName
+ );
if (isTopLevel) {
- if (productData.productName === tableData[0].productName &&
- productData.model === tableData[0].model) {
+ if (
+ productData.productName === tableData[0].productName &&
+ productData.model === tableData[0].model
+ ) {
// 鏌ユ壘鏄惁宸茬粡鏈夊叾浠栭《灞傝宸茬粡鏄繖涓骇鍝�
- const hasOther = dataValue.dataList.some(item =>
- (item as any).tempId !== dataValue.currentRowName &&
- (item as any).productName === tableData[0].productName &&
- (item as any).model === tableData[0].model
+ const hasOther = dataValue.dataList.some(
+ item =>
+ (item as any).tempId !== dataValue.currentRowName &&
+ (item as any).productName === tableData[0].productName &&
+ (item as any).model === tableData[0].model
);
if (hasOther) {
ElMessage.warning("鏈�澶栧眰鍜屽綋鍓嶄骇鍝佷竴鏍风殑涓�绾у彧鑳芥湁涓�涓�");
@@ -319,8 +458,41 @@
const validateAll = () => {
let isValid = true;
+ // 鏍¢獙涓�缁勫厔寮熻妭鐐圭殑宸ュ簭鏄惁閮界浉鍚�
+ const checkProcessUniqueness = (items: any[]) => {
+ if (!items || items.length === 0 || !isValid) return;
+
+ // 鑾峰彇绗竴涓潪绌虹殑宸ュ簭ID浣滀负鍙傝��
+ const firstProcessId = items.find(item => item.processId)?.processId;
+
+ // 濡傛灉鏈夊伐搴廔D锛屾鏌ユ墍鏈夐」鏄惁閮戒娇鐢ㄧ浉鍚岀殑宸ュ簭
+ if (firstProcessId) {
+ for (const item of items) {
+ if (item.processId && item.processId !== firstProcessId) {
+ const option1 = getProcessOptionById(firstProcessId);
+ const option2 = getProcessOptionById(item.processId);
+ const processName1 = option1?.name || "鏈煡宸ュ簭";
+ const processName2 = option2?.name || "鏈煡宸ュ簭";
+ ElMessage.error(
+ `褰撳墠灞傜骇涓嬪伐搴忎笉涓�鑷达紝璇蜂娇鐢ㄧ浉鍚岀殑宸ュ簭銆傚瓨鍦ㄣ��${processName1}銆嶅拰銆�${processName2}銆峘
+ );
+ isValid = false;
+ return;
+ }
+ }
+ }
+
+ // 閫掑綊鏍¢獙瀛愮骇鐨勫厔寮熻妭鐐�
+ for (const item of items) {
+ if (item.children && item.children.length > 0) {
+ checkProcessUniqueness(item.children);
+ }
+ }
+ };
+
// 鏍¢獙鍑芥暟
const validateItem = (item: any, isTopLevel = false) => {
+ if (!isValid) return;
// 鏍¢獙褰撳墠椤圭殑蹇呭~瀛楁
if (!item.model) {
ElMessage.error("璇烽�夋嫨瑙勬牸");
@@ -348,7 +520,7 @@
// return;
// }
- // 閫掑綊鏍¢獙瀛愰」
+ // 閫掑綊鏍¢獙瀛愰」瀛楁
if (item.children && item.children.length > 0) {
item.children.forEach(child => {
validateItem(child, false);
@@ -356,7 +528,11 @@
}
};
- // 閬嶅巻鎵�鏈夐《灞傞」
+ // 1. 棣栧厛鏍¢獙鍚屼竴鐖剁骇涓嬬殑鍚屽眰娑堣�楀伐搴忔槸鍚﹀敮涓�
+ checkProcessUniqueness(dataValue.dataList);
+ if (!isValid) return false;
+
+ // 2. 鐒跺悗閬嶅巻鏍¢獙鎵�鏈夐《灞傞」鐨勫瓧娈靛繀濉儏鍐�
dataValue.dataList.forEach(item => {
validateItem(item, true);
});
@@ -366,19 +542,19 @@
const submit = () => {
dataValue.loading = true;
+ normalizeTreeData(dataValue.dataList);
+ recalculateDemandedQuantities();
// 鍏堣繘琛岃〃鍗曟牎楠�
const valid = validateAll();
console.log(dataValue.dataList, "dataValue.dataList");
if (valid) {
- add({
+ addBomDetail({
bomId: routeId.value,
- children: dataValue.dataList || [],
+ children: buildSubmitTree(dataValue.dataList || []),
})
.then(res => {
- router.push({
- path: "/productionManagement/productionManagement/productStructure/index",
- });
+ router.go(-1);
ElMessage.success("淇濆瓨鎴愬姛");
dataValue.loading = false;
})
@@ -390,7 +566,7 @@
}
};
- const removeItem = (tempId:string) => {
+ const removeItem = (tempId: string) => {
// 鍏堝皾璇曚粠椤跺眰鍒犻櫎
const topIndex = dataValue.dataList.findIndex(item => item.tempId === tempId);
if (topIndex !== -1) {
@@ -436,13 +612,16 @@
productModelId: undefined,
processId: "",
processName: "",
- unitQuantity: 0,
+ operationId: "",
+ operationName: "",
+ unitQuantity: 1,
demandedQuantity: 0,
unit: "",
children: [],
tempId: new Date().getTime(),
});
+ recalculateDemandedQuantities();
return;
}
addchildItem(item, tempId);
@@ -462,12 +641,16 @@
model: undefined,
productModelId: undefined,
processId: "",
- unitQuantity: 0,
+ processName: "",
+ operationId: "",
+ operationName: "",
+ unitQuantity: 1,
demandedQuantity: 0,
children: [],
unit: "",
tempId: new Date().getTime(),
});
+ recalculateDemandedQuantities();
return true;
}
if (item.children && item.children.length > 0) {
--
Gitblit v1.9.3