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 ++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 280 insertions(+), 93 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(() => {

--
Gitblit v1.9.3