From 21c1360819a78ab734046fe6e0aa91b4da9f510a Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期六, 18 四月 2026 10:02:55 +0800
Subject: [PATCH] 生产订单工艺路线
---
src/views/productionManagement/processRoute/processRouteItem/index.vue | 373 ++++++++++++++++++++++++++++++++++++++++-------------
src/views/productionManagement/productionOrder/index.vue | 40 ++--
2 files changed, 300 insertions(+), 113 deletions(-)
diff --git a/src/views/productionManagement/processRoute/processRouteItem/index.vue b/src/views/productionManagement/processRoute/processRouteItem/index.vue
index c1c490c..c2c24b4 100644
--- a/src/views/productionManagement/processRoute/processRouteItem/index.vue
+++ b/src/views/productionManagement/processRoute/processRouteItem/index.vue
@@ -1,9 +1,9 @@
<template>
<div class="app-container">
- <PageHeader content="宸ヨ壓璺嚎椤圭洰" />
+ <PageHeader content="浜у搧閮ㄤ欢" />
<!-- 宸ヨ壓璺嚎淇℃伅灞曠ず -->
- <el-card v-if="routeInfo.processRouteCode" class="route-info-card" shadow="hover">
+ <!-- <el-card v-if="routeInfo.processRouteCode" class="route-info-card" shadow="hover">
<div class="route-info">
<div class="info-item">
<div class="info-label-wrapper">
@@ -46,11 +46,11 @@
</div>
</div>
</div>
- </el-card>
+ </el-card> -->
<!-- 琛ㄦ牸瑙嗗浘 -->
<div v-if="viewMode === 'table'" class="section-header">
- <div class="section-title">宸ヨ壓璺嚎椤圭洰鍒楄〃</div>
+ <div class="section-title">浜у搧閮ㄤ欢鍒楄〃</div>
<div class="section-actions">
<el-button
icon="Grid"
@@ -74,17 +74,49 @@
class="lims-table"
>
<el-table-column align="center" label="搴忓彿" width="60" type="index" />
- <el-table-column label="宸ュ簭鍚嶇О" prop="processId" width="200">
+ <el-table-column label="浜у搧鍚嶇О" prop="name" min-width="140" show-overflow-tooltip>
<template #default="scope">
- {{ getProcessName(scope.row.processId) || '-' }}
+ {{ getProcessField(scope.row, 'name') }}
</template>
</el-table-column>
- <el-table-column label="浜у搧鍚嶇О" prop="productName" min-width="160" />
- <el-table-column label="瑙勬牸鍚嶇О" prop="model" min-width="140" />
- <el-table-column label="鍗曚綅" prop="unit" width="100" />
- <el-table-column label="鏄惁璐ㄦ" prop="isQuality" width="100">
+ <el-table-column label="浜у搧瑙勬牸" prop="productModel" min-width="120" show-overflow-tooltip>
<template #default="scope">
- {{scope.row.isQuality ? "鏄�" : "鍚�"}}
+ {{ getProcessField(scope.row, 'productModel') }}
+ </template>
+ </el-table-column>
+ <el-table-column label="閮ㄤ欢缂栧彿" prop="no" width="120" show-overflow-tooltip>
+ <template #default="scope">
+ {{ getProcessField(scope.row, 'no') }}
+ </template>
+ </el-table-column>
+ <el-table-column label="閮ㄤ欢绫诲瀷" prop="typeText" width="120" show-overflow-tooltip>
+ <template #default="scope">
+ {{ getProcessTypeText(getProcessRaw(scope.row)?.type) || '-' }}
+ </template>
+ </el-table-column>
+ <el-table-column label="璁″垝宸ユ椂(灏忔椂)" prop="salaryQuota" width="130" align="center">
+ <template #default="scope">
+ {{ getProcessField(scope.row, 'salaryQuota') }}
+ </template>
+ </el-table-column>
+ <el-table-column label="璁″垝浜哄憳" prop="plannerName" width="100" show-overflow-tooltip>
+ <template #default="scope">
+ {{ getProcessField(scope.row, 'plannerName') }}
+ </template>
+ </el-table-column>
+ <el-table-column label="鏄惁璐ㄦ" prop="isQuality" width="90" align="center">
+ <template #default="scope">
+ {{ scope.row.isQuality ? '鏄�' : '鍚�' }}
+ </template>
+ </el-table-column>
+ <el-table-column label="澶囨敞" prop="remark" min-width="100" show-overflow-tooltip>
+ <template #default="scope">
+ {{ getProcessField(scope.row, 'remark') }}
+ </template>
+ </el-table-column>
+ <el-table-column label="鏇存柊鏃堕棿" prop="updateTime" width="160" align="center">
+ <template #default="scope">
+ {{ getProcessField(scope.row, 'updateTime') }}
</template>
</el-table-column>
<el-table-column label="鎿嶄綔" align="center" fixed="right" width="150">
@@ -124,20 +156,19 @@
<!-- 搴忓彿鍦嗗湀 -->
<div class="card-header">
<div class="card-number">{{ index + 1 }}</div>
- <div class="card-process-name">{{ getProcessName(item.processId) || '-' }}</div>
+ <div class="card-process-name">{{ getProcessField(item, 'name') }}</div>
</div>
- <!-- 浜у搧淇℃伅 -->
+ <!-- 涓庡伐搴忎富琛ㄤ竴鑷寸殑绠�瑕佷俊鎭� -->
<div class="card-content">
- <div v-if="item.productName" class="product-info">
- <div class="product-name">{{ item.productName }}</div>
- <div v-if="item.model" class="product-model">
- {{ item.model }}
- <!-- <span v-if="item.unit" class="product-unit">{{ item.unit }}</span> -->
+ <div class="product-info">
+ <div class="product-name">{{ getProcessField(item, 'productModel') }}</div>
+ <div v-if="getProcessRaw(item)?.no" class="product-model">缂栧彿 {{ getProcessRaw(item)?.no }}</div>
+ <div v-if="getProcessTypeText(getProcessRaw(item)?.type)" class="product-model">
+ {{ getProcessTypeText(getProcessRaw(item)?.type) }}
</div>
<el-tag type="primary" class="product-tag" v-if="item.isQuality">璐ㄦ</el-tag>
</div>
- <div v-else class="product-info empty">鏆傛棤浜у搧淇℃伅</div>
</div>
<!-- 鎿嶄綔鎸夐挳 -->
@@ -150,55 +181,112 @@
</div>
</template>
- <!-- 鏂板/缂栬緫寮圭獥 -->
+ <!-- 鏂板/缂栬緫寮圭獥锛堝竷灞�銆佸瓧娈典笌宸ュ簭/閮ㄤ欢椤� New銆丒dit 涓�鑷达紱鎻愪氦鍙傛暟浠嶄负鍘熸帴鍙e瓧娈碉級 -->
<el-dialog
v-model="dialogVisible"
:title="operationType === 'add' ? '鏂板宸ヨ壓璺嚎椤圭洰' : '缂栬緫宸ヨ壓璺嚎椤圭洰'"
- width="500px"
+ width="760"
@close="closeDialog"
>
<el-form
ref="formRef"
:model="form"
:rules="rules"
- label-width="120px"
+ label-width="140px"
+ label-position="top"
>
- <el-form-item label="宸ュ簭" prop="processId">
- <el-select
- v-model="form.processId"
- placeholder="璇烽�夋嫨宸ュ簭"
- clearable
- style="width: 100%"
- >
- <el-option
- v-for="process in processOptions"
- :key="process.id"
- :label="process.name"
- :value="process.id"
- />
- </el-select>
- </el-form-item>
-
- <el-form-item label="浜у搧鍚嶇О" prop="productModelId">
- <el-button type="primary" @click="showProductSelectDialog = true">
- {{ form.productName && form.model
- ? `${form.productName} - ${form.model}`
- : '閫夋嫨浜у搧' }}
- </el-button>
- </el-form-item>
-
- <el-form-item label="鍗曚綅" prop="unit">
- <el-input
- v-model="form.unit"
- :placeholder="form.productModelId ? '鏍规嵁閫夋嫨鐨勪骇鍝佽嚜鍔ㄥ甫鍑�' : '璇峰厛閫夋嫨浜у搧'"
- clearable
- :disabled="true"
- />
- </el-form-item>
-
- <el-form-item label="鏄惁璐ㄦ" prop="isQuality">
- <el-switch v-model="form.isQuality" :active-value="true" inactive-value="false"/>
- </el-form-item>
+ <el-row :gutter="16">
+ <el-col :span="24">
+ <el-form-item label="閮ㄤ欢" prop="processId">
+ <el-select
+ v-model="form.processId"
+ placeholder="璇烽�夋嫨閮ㄤ欢"
+ clearable
+ filterable
+ style="width: 100%"
+ >
+ <el-option
+ v-for="process in processOptions"
+ :key="process.id"
+ :label="formatProcessOptionLabel(process)"
+ :value="process.id"
+ />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item
+ label="浜у搧鍚嶇О锛�"
+ prop="productId"
+ >
+ <el-tree-select
+ v-model="form.productId"
+ placeholder="璇烽�夋嫨浜у搧鍚嶇О"
+ clearable
+ filterable
+ check-strictly
+ :data="productCategoryOptions"
+ :render-after-expand="false"
+ style="width: 100%"
+ @change="handleProductChange"
+ />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item
+ label="浜у搧瑙勬牸锛�"
+ prop="productModelId"
+ >
+ <el-select
+ v-model="form.productModelId"
+ placeholder="璇烽�夋嫨浜у搧瑙勬牸"
+ clearable
+ filterable
+ :disabled="!form.productId"
+ style="width: 100%"
+ >
+ <el-option
+ v-for="item in modelOptions"
+ :key="item.id"
+ :label="item.model"
+ :value="item.id"
+ />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="閮ㄤ欢缂栧彿">
+ <el-input :model-value="selectedProcess?.no ?? ''" readonly />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="閮ㄤ欢绫诲瀷">
+ <el-input :model-value="getProcessTypeText(selectedProcess?.type) || '-'" readonly />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="璁″垝宸ユ椂(灏忔椂)">
+ <el-input :model-value="selectedProcess?.salaryQuota != null && selectedProcess?.salaryQuota !== '' ? String(selectedProcess.salaryQuota) : ''" readonly>
+ <template #append>灏忔椂</template>
+ </el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="璁″垝浜哄憳">
+ <el-input :model-value="selectedProcess?.plannerName ?? ''" readonly />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鏄惁璐ㄦ" prop="isQuality">
+ <el-switch v-model="form.isQuality" :active-value="true" inactive-value="false"/>
+ </el-form-item>
+ </el-col>
+ <el-col :span="24">
+ <el-form-item label="澶囨敞">
+ <el-input :model-value="selectedProcess?.remark ?? ''" type="textarea" readonly />
+ </el-form-item>
+ </el-col>
+ </el-row>
</el-form>
<template #footer>
@@ -206,22 +294,15 @@
<el-button @click="closeDialog">鍙栨秷</el-button>
</template>
</el-dialog>
-
- <!-- 浜у搧閫夋嫨瀵硅瘽妗� -->
- <ProductSelectDialog
- v-model="showProductSelectDialog"
- @confirm="handleProductSelect"
- single
- />
</div>
</template>
<script setup>
import { ref, computed, getCurrentInstance, onMounted, onUnmounted, nextTick } from "vue";
-import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
import { findProcessRouteItemList, addOrUpdateProcessRouteItem, sortProcessRouteItem, batchDeleteProcessRouteItem } from "@/api/productionManagement/processRouteItem.js";
import { findProductProcessRouteItemList, deleteRouteItem, addRouteItem, addOrUpdateProductProcessRouteItem, sortRouteItem } from "@/api/productionManagement/productProcessRoute.js";
import { processList } from "@/api/productionManagement/productionProcess.js";
+import { modelListPage, productTreeList } from "@/api/basicData/product";
import { useRoute } from 'vue-router'
import { ElMessageBox } from 'element-plus'
import Sortable from 'sortablejs'
@@ -251,7 +332,8 @@
});
const processOptions = ref([]);
-const showProductSelectDialog = ref(false);
+const productCategoryOptions = ref([]);
+const modelOptions = ref([]);
let tableSortable = null;
let cardSortable = null;
@@ -268,23 +350,133 @@
id: undefined,
routeId: routeId.value,
processId: undefined,
+ productId: undefined,
productModelId: undefined,
productName: "",
model: "",
- unit: "",
isQuality: false,
});
const rules = {
- processId: [{ required: true, message: '璇烽�夋嫨宸ュ簭', trigger: 'change' }],
- productModelId: [{ required: true, message: '璇烽�夋嫨浜у搧', trigger: 'change' }],
+ processId: [{ required: true, message: '璇烽�夋嫨閮ㄤ欢', trigger: 'change' }],
+ productId: [{ required: true, message: '璇烽�夋嫨浜у搧鍚嶇О', trigger: 'change' }],
+ productModelId: [{ required: true, message: '璇烽�夋嫨浜у搧瑙勬牸', trigger: 'change' }],
};
-// 鏍规嵁宸ュ簭ID鑾峰彇宸ュ簭鍚嶇О
-const getProcessName = (processId) => {
- if (!processId) return '';
- const process = processOptions.value.find(p => p.id === processId);
- return process ? process.name : '';
+const selectedProcess = computed(() => {
+ if (form.value.processId === undefined || form.value.processId === null || form.value.processId === '') return null;
+ return processOptions.value.find(p => String(p.id) === String(form.value.processId)) || null;
+});
+
+const getProcessTypeText = (type) => {
+ if (type === undefined || type === null) return '';
+ const map = {
+ 1: '鍔犲伐',
+ 2: '鍒澘鍐疯姱鍒朵綔',
+ 3: '绠¤矾缁勫',
+ 4: '缃愪綋杩炴帴鍙婅皟璇�',
+ 5: '娴嬭瘯鎵撳帇',
+ 6: '鍏朵粬',
+ };
+ return map[type] || '';
+};
+
+const getProcessRaw = (row) => {
+ if (!row?.processId) return null;
+ return processOptions.value.find(p => String(p.id) === String(row.processId)) || null;
+};
+
+const getProcessField = (row, key) => {
+ const p = getProcessRaw(row);
+ const fromProcess = p ? p[key] : undefined;
+ if (fromProcess !== undefined && fromProcess !== null && fromProcess !== '') return fromProcess;
+ if (key === 'name' && row.productName) return row.productName;
+ if (key === 'productModel' && row.model) return row.model;
+ const fromRow = row[key];
+ if (fromRow !== undefined && fromRow !== null && fromRow !== '') return fromRow;
+ return '-';
+};
+
+const formatProcessOptionLabel = (process) => {
+ if (!process) return '';
+ const no = process.no ? String(process.no).trim() : '';
+ const name = process.name || '';
+ if (no && name) return `${no} ${name}`;
+ return name || no || '';
+};
+
+const convertProductTree = (list) => {
+ return (list || []).map(item => {
+ const children = convertProductTree(item.children || item.childList || []);
+ return {
+ ...item,
+ value: item.id,
+ label: item.name || item.label,
+ children,
+ disabled: children.length > 0,
+ };
+ });
+};
+
+const findNodeById = (nodes, targetId) => {
+ for (const node of nodes || []) {
+ if (String(node.value) === String(targetId)) {
+ return node;
+ }
+ if (node.children && node.children.length > 0) {
+ const found = findNodeById(node.children, targetId);
+ if (found) return found;
+ }
+ }
+ return null;
+};
+
+const findNodeIdByLabel = (nodes, targetLabel) => {
+ for (const node of nodes || []) {
+ if (node.label === targetLabel) {
+ return node.value;
+ }
+ if (node.children && node.children.length > 0) {
+ const found = findNodeIdByLabel(node.children, targetLabel);
+ if (found !== null && found !== undefined) return found;
+ }
+ }
+ return undefined;
+};
+
+const getProductCategoryOptions = async () => {
+ try {
+ const res = await productTreeList();
+ const list = Array.isArray(res) ? res : res?.data || [];
+ productCategoryOptions.value = convertProductTree(list);
+ } catch (e) {
+ productCategoryOptions.value = [];
+ }
+};
+
+const getModelOptions = async (productId) => {
+ if (!productId) {
+ modelOptions.value = [];
+ return;
+ }
+ try {
+ const res = await modelListPage({
+ id: productId,
+ current: 1,
+ size: 999,
+ });
+ const records = res?.records || res?.data?.records || [];
+ modelOptions.value = records;
+ } catch (e) {
+ modelOptions.value = [];
+ }
+};
+
+const handleProductChange = async (value) => {
+ const selectedNode = findNodeById(productCategoryOptions.value, value);
+ form.value.productName = selectedNode?.label || '';
+ form.value.productModelId = undefined;
+ await getModelOptions(value);
};
// 鑾峰彇鍒楄〃
@@ -338,22 +530,28 @@
operationType.value = 'add';
resetForm();
dialogVisible.value = true;
+ getProductCategoryOptions();
};
// 缂栬緫
-const handleEdit = (row) => {
+const handleEdit = async (row) => {
operationType.value = 'edit';
form.value = {
id: row.id,
routeId: routeId.value,
processId: row.processId,
+ productId: row.productId,
productModelId: row.productModelId,
productName: row.productName || "",
model: row.model || "",
- unit: row.unit || "",
isQuality: row.isQuality,
};
dialogVisible.value = true;
+ await getProductCategoryOptions();
+ if (!form.value.productId && form.value.productName) {
+ form.value.productId = findNodeIdByLabel(productCategoryOptions.value, form.value.productName);
+ }
+ await getModelOptions(form.value.productId);
};
// 鍒犻櫎
@@ -380,20 +578,6 @@
});
})
.catch(() => {});
-};
-
-// 浜у搧閫夋嫨
-const handleProductSelect = (products) => {
- if (products && products.length > 0) {
- const product = products[0];
- form.value.productModelId = product.id;
- form.value.productName = product.productName;
- form.value.model = product.model;
- form.value.unit = product.unit || "";
- showProductSelectDialog.value = false;
- // 瑙﹀彂琛ㄥ崟楠岃瘉
- formRef.value?.validateField('productModelId');
- }
};
// 鎻愪氦
@@ -479,12 +663,14 @@
id: undefined,
routeId: routeId.value,
processId: undefined,
+ productId: undefined,
productModelId: undefined,
productName: "",
model: "",
- unit: "",
+ isQuality: false,
};
- formRef.value?.resetFields();
+ modelOptions.value = [];
+ nextTick(() => formRef.value?.clearValidate());
};
// 鍏抽棴寮圭獥
@@ -627,6 +813,7 @@
getRouteInfo();
getList();
getProcessList();
+ getProductCategoryOptions();
});
onUnmounted(() => {
diff --git a/src/views/productionManagement/productionOrder/index.vue b/src/views/productionManagement/productionOrder/index.vue
index 729cd5a..b722592 100644
--- a/src/views/productionManagement/productionOrder/index.vue
+++ b/src/views/productionManagement/productionOrder/index.vue
@@ -144,11 +144,11 @@
prop: "specificationModel",
width: '120px',
},
- {
- label: "宸ヨ壓璺嚎缂栧彿",
- prop: "processRouteCode",
- width: '200px',
- },
+ // {
+ // label: "宸ヨ壓璺嚎缂栧彿",
+ // prop: "processRouteCode",
+ // width: '200px',
+ // },
{
label: "闇�姹傛暟閲�",
prop: "quantity",
@@ -196,21 +196,21 @@
showRouteItemModal(row);
},
},
- {
- name: "缁戝畾宸ヨ壓璺嚎",
- type: "text",
- showHide: row => !row.processRouteCode,
- clickFun: row => {
- openBindRouteDialog(row);
- },
- },
- {
- name: "浜у搧缁撴瀯",
- type: "text",
- clickFun: row => {
- showProductStructure(row);
- },
- },
+ // {
+ // name: "缁戝畾宸ヨ壓璺嚎",
+ // type: "text",
+ // showHide: row => !row.processRouteCode,
+ // clickFun: row => {
+ // openBindRouteDialog(row);
+ // },
+ // },
+ // {
+ // name: "浜у搧缁撴瀯",
+ // type: "text",
+ // clickFun: row => {
+ // showProductStructure(row);
+ // },
+ // },
],
},
]);
--
Gitblit v1.9.3