From ed36047f6ce0b91dad25efc10c8a0e83dd533a68 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期五, 20 三月 2026 17:15:37 +0800
Subject: [PATCH] change

---
 src/views/productionManagement/processRoute/processRouteItem/index.vue | 2092 +++++++++++++++++++++++++++++++++++++++--------------------
 1 files changed, 1,370 insertions(+), 722 deletions(-)

diff --git a/src/views/productionManagement/processRoute/processRouteItem/index.vue b/src/views/productionManagement/processRoute/processRouteItem/index.vue
index 99d89a9..5d841e8 100644
--- a/src/views/productionManagement/processRoute/processRouteItem/index.vue
+++ b/src/views/productionManagement/processRoute/processRouteItem/index.vue
@@ -1,9 +1,10 @@
 <template>
   <div class="app-container">
     <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">
@@ -15,18 +16,10 @@
         </div>
         <div class="info-item">
           <div class="info-label-wrapper">
-            <span class="info-label">浜у搧鍚嶇О</span>
+            <span class="info-label">浜у搧绫诲瀷</span>
           </div>
           <div class="info-value-wrapper">
-            <span class="info-value">{{ routeInfo.productName || '-' }}</span>
-          </div>
-        </div>
-        <div class="info-item">
-          <div class="info-label-wrapper">
-            <span class="info-label">瑙勬牸鍚嶇О</span>
-          </div>
-          <div class="info-value-wrapper">
-            <span class="info-value">{{ routeInfo.model || '-' }}</span>
+            <span class="info-value">{{ routeInfo.dictLabel || '-' }}</span>
           </div>
         </div>
         <div class="info-item">
@@ -37,7 +30,8 @@
             <span class="info-value">{{ routeInfo.bomNo || '-' }}</span>
           </div>
         </div>
-        <div class="info-item full-width" v-if="routeInfo.description">
+        <div class="info-item full-width"
+             v-if="routeInfo.description">
           <div class="info-label-wrapper">
             <span class="info-label">鎻忚堪</span>
           </div>
@@ -47,419 +41,425 @@
         </div>
       </div>
     </el-card>
-    
+    <!-- bom灞曠ず -->
     <!-- 琛ㄦ牸瑙嗗浘 -->
-    <div v-if="viewMode === 'table'" class="section-header">
+    <div v-if="viewMode === 'table'"
+         class="section-header">
       <div class="section-title">宸ヨ壓璺嚎椤圭洰鍒楄〃</div>
       <div class="section-actions">
-        <el-button 
-            icon="Grid" 
-            @click="toggleView"
-            style="margin-right: 10px;"
-        >
+        <div class="sort-tip">鎷栨嫿琛ㄦ牸鎺掑簭</div>
+        <el-button icon="Grid"
+                   @click="toggleView"
+                   style="margin-right: 10px;">
           鍗$墖瑙嗗浘
         </el-button>
-        <el-button type="primary" @click="handleAdd">鏂板</el-button>
+        <el-button type="primary"
+                   @click="handleAdd">鏂板</el-button>
       </div>
     </div>
-    <el-table
-        v-if="viewMode === 'table'"
-        ref="tableRef"
-        v-loading="tableLoading"
-        border
-        :data="tableData"
-        :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
-        row-key="id"
-        tooltip-effect="dark"
-        class="lims-table"
-    >
-      <el-table-column align="center" label="搴忓彿" width="60" type="index" />
-      <el-table-column label="宸ュ簭鍚嶇О" prop="processId" width="200">
+    <el-table v-if="viewMode === 'table'"
+              ref="tableRef"
+              v-loading="tableLoading"
+              border
+              :data="tableData"
+              :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
+              row-key="id"
+              height="350"
+              tooltip-effect="dark"
+              style="margin-bottom: 20px;"
+              class="lims-table">
+      <el-table-column align="center"
+                       label="搴忓彿"
+                       width="60"
+                       type="index" />
+      <el-table-column label="宸ュ簭鍚嶇О"
+                       prop="processId"
+                       width="200">
         <template #default="scope">
           {{ getProcessName(scope.row.processId) || '-' }}
         </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="鎿嶄綔" align="center" fixed="right" width="150">
+      <el-table-column label="鍙傛暟鍒楄〃"
+                       min-width="160">
         <template #default="scope">
-          <el-button type="primary" link size="small" @click="handleEdit(scope.row)" :disabled="scope.row.isComplete">缂栬緫</el-button>
-          <el-button type="danger" link size="small" @click="handleDelete(scope.row)" :disabled="scope.row.isComplete">鍒犻櫎</el-button>
+          <el-button type="primary"
+                     link
+                     size="small"
+                     @click="handleViewParams(scope.row)">鍙傛暟鍒楄〃</el-button>
+        </template>
+      </el-table-column>
+      <el-table-column label="鏄惁璐ㄦ"
+                       prop="isQuality">
+        <template #default="scope">
+          <el-tag :type="scope.row.isQuality == 1 ? 'success' : 'danger'">
+            {{scope.row.isQuality == 1 ? '鏄�' : '鍚�' }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔"
+                       align="center"
+                       fixed="right"
+                       width="150">
+        <template #default="scope">
+          <el-button type="primary"
+                     link
+                     size="small"
+                     @click="handleEdit(scope.row)"
+                     :disabled="scope.row.isComplete">缂栬緫</el-button>
+          <el-button type="danger"
+                     link
+                     size="small"
+                     @click="handleDelete(scope.row)"
+                     :disabled="scope.row.isComplete">鍒犻櫎</el-button>
         </template>
       </el-table-column>
     </el-table>
-    
     <!-- 鍗$墖瑙嗗浘 -->
     <template v-else>
       <div class="section-header">
         <div class="section-title">宸ヨ壓璺嚎椤圭洰鍒楄〃</div>
         <div class="section-actions">
-          <el-button 
-              icon="Menu" 
-              @click="toggleView"
-              style="margin-right: 10px;"
-          >
+          <div class="sort-tip">闀挎寜鎷栨嫿鍗$墖鎺掑簭</div>
+          <el-button icon="Menu"
+                     @click="toggleView"
+                     style="margin-right: 10px;">
             琛ㄦ牸瑙嗗浘
           </el-button>
-          <el-button type="primary" @click="handleAdd">鏂板</el-button>
+          <el-button type="primary"
+                     @click="handleAdd">鏂板</el-button>
         </div>
       </div>
-      <div v-loading="tableLoading" class="card-container">
-        <div 
-            ref="cardsContainer" 
-            class="cards-wrapper"
-        >
-        <div
-            v-for="(item, index) in tableData"
-            :key="item.id || index"
-            class="process-card"
-            :data-index="index"
-        >
-          <!-- 搴忓彿鍦嗗湀 -->
-          <div class="card-header">
-            <div class="card-number">{{ index + 1 }}</div>
-            <div class="card-process-name">{{ getProcessName(item.processId) || '-' }}</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>
+      <div v-loading="tableLoading"
+           class="card-container">
+        <div ref="cardsContainer"
+             class="cards-wrapper">
+          <div v-for="(item, index) in tableData"
+               :key="item.id || index"
+               class="process-card"
+               :data-index="index">
+            <!-- 搴忓彿鍦嗗湀 -->
+            <div class="card-header">
+              <div class="card-number">{{ index + 1 }}</div>
+              <div class="card-process-name">{{ getProcessName(item.processId) || '-' }}</div>
             </div>
-            <div v-else class="product-info empty">鏆傛棤浜у搧淇℃伅</div>
-          </div>
-          
-          <!-- 鎿嶄綔鎸夐挳 -->
-          <div class="card-footer">
-            <el-button type="primary" link size="small" @click="handleEdit(item)" :disabled="item.isComplete">缂栬緫</el-button>
-            <el-button type="danger" link size="small" @click="handleDelete(item)" :disabled="item.isComplete">鍒犻櫎</el-button>
+            <!-- 浜у搧淇℃伅 -->
+            <!-- <div class="card-content">
+            </div> -->
+            <!-- 鎿嶄綔鎸夐挳 -->
+            <div class="card-footer">
+              <el-button type="primary"
+                         link
+                         size="small"
+                         @click="handleEdit(item)"
+                         :disabled="item.isComplete">缂栬緫</el-button>
+              <el-button type="info"
+                         link
+                         size="small"
+                         @click="handleViewParams(item)">鍙傛暟鍒楄〃</el-button>
+              <el-button type="danger"
+                         link
+                         size="small"
+                         @click="handleDelete(item)"
+                         :disabled="item.isComplete">鍒犻櫎</el-button>
+            </div>
           </div>
         </div>
-      </div>
       </div>
     </template>
-
+    <div class="section-BOM">
+      <div class="section-header">
+        <div class="section-title">BOM</div>
+        <div class="section-actions"
+             v-if="pageType === 'order'">
+          <el-button type="primary"
+                     @click="toggleBomEdit">
+            {{ bomDataValue.isEdit ? '鍙栨秷' : '缂栬緫' }}
+          </el-button>
+          <el-button v-if=" bomDataValue.isEdit"
+                     type="success"
+                     @click="saveBomChanges">淇濆瓨</el-button>
+        </div>
+      </div>
+      <div>
+        <!-- BOM琛ㄦ牸 -->
+        <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="bomFormRef"
+                       :model="bomDataValue">
+                <el-table :data="props.row.bomList"
+                          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="bomDataValue.isEdit"
+                                    style="margin: 0">
+                        <el-select v-model="row.model"
+                                   placeholder="璇烽�夋嫨瑙勬牸"
+                                   :disabled="!bomDataValue.isEdit"
+                                   style="width: 100%"
+                                   @visible-change="(v) => { if (v) openBomProductDialog(row.tempId) }">
+                          <el-option v-if="row.model"
+                                     :label="row.model"
+                                     :value="row.model" />
+                        </el-select>
+                      </el-form-item>
+                      <span v-else>{{ row.model }}</span>
+                    </template>
+                  </el-table-column>
+                  <el-table-column prop="processName"
+                                   label="娑堣�楀伐搴�">
+                    <template #default="{ row }">
+                      <el-form-item v-if="bomDataValue.isEdit"
+                                    style="margin: 0">
+                        <el-select v-model="row.processId"
+                                   placeholder="璇烽�夋嫨娑堣�楀伐搴�"
+                                   :disabled="!bomDataValue.isEdit"
+                                   style="width: 100%">
+                          <el-option v-for="process in processOptions"
+                                     :key="process.id"
+                                     :label="process.name"
+                                     :value="process.id" />
+                        </el-select>
+                      </el-form-item>
+                      <span v-else>{{ row.processName }}</span>
+                    </template>
+                  </el-table-column>
+                  <el-table-column prop="unitQuantity"
+                                   label="鍗曚綅浜у嚭鎵�闇�鏁伴噺">
+                    <template #default="{ row }">
+                      <el-form-item v-if="bomDataValue.isEdit"
+                                    style="margin: 0">
+                        <el-input-number v-model="row.unitQuantity"
+                                         :min="0"
+                                         :step="1"
+                                         controls-position="right"
+                                         style="width: 100%"
+                                         :disabled="!bomDataValue.isEdit" />
+                      </el-form-item>
+                      <span v-else>{{ row.unitQuantity }}</span>
+                    </template>
+                  </el-table-column>
+                  <el-table-column prop="unit"
+                                   label="鍗曚綅">
+                    <template #default="{ row }">
+                      <el-form-item v-if="bomDataValue.isEdit"
+                                    style="margin: 0">
+                        <el-input v-model="row.unit"
+                                  placeholder="璇疯緭鍏ュ崟浣�"
+                                  clearable
+                                  :disabled="!bomDataValue.isEdit" />
+                      </el-form-item>
+                      <span v-else>{{ row.unit }}</span>
+                    </template>
+                  </el-table-column>
+                  <el-table-column label="鎿嶄綔"
+                                   fixed="right"
+                                   v-if="pageType === 'order'"
+                                   width="180">
+                    <template #default="{ row }">
+                      <el-button v-if="bomDataValue.isEdit"
+                                 type="danger"
+                                 text
+                                 size="small"
+                                 @click="removeBomItem(row.tempId)">鍒犻櫎</el-button>
+                      <el-button v-if="bomDataValue.isEdit"
+                                 type="primary"
+                                 text
+                                 size="small"
+                                 @click="addBomItem2(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="dictLabel" />
+          <!-- <el-table-column label="鎿嶄綔"
+                           width="150">
+            <template #default="{ row }">
+            
+            </template>
+          </el-table-column> -->
+          <!-- <el-table-column label="浜у搧缂栫爜"
+                           prop="productCode" />
+          <el-table-column label="浜у搧鍚嶇О"
+                           prop="productName" />
+          <el-table-column label="瑙勬牸鍨嬪彿"
+                           prop="model" /> -->
+        </el-table>
+        <div v-if="bomDataValue.isEdit"
+             style="text-align: center;border: 1px solid #e4e7ed;padding: 10px;transition: all 0.3s ease;cursor: pointer;"
+             :class="{'hover-effect': bomDataValue.isEdit}">
+          <el-button type="primary"
+                     text
+                     @click="addBomItem">
+            <el-icon style="vertical-align: middle;margin-right: 5px;">
+              <Plus />
+            </el-icon>
+            娣诲姞
+          </el-button>
+        </div>
+      </div>
+    </div>
     <!-- 鏂板/缂栬緫寮圭獥 -->
-    <el-dialog
-        v-model="dialogVisible"
-        :title="operationType === 'add' ? '鏂板宸ヨ壓璺嚎椤圭洰' : '缂栬緫宸ヨ壓璺嚎椤圭洰'"
-        width="500px"
-        @close="closeDialog"
-    >
-      <el-form
-          ref="formRef"
-          :model="form"
-          :rules="rules"
-          label-width="120px"
-      >
-        <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-dialog v-model="dialogVisible"
+               :title="operationType === 'add' ? '鏂板宸ヨ壓璺嚎椤圭洰' : '缂栬緫宸ヨ壓璺嚎椤圭洰'"
+               width="500px"
+               @close="closeDialog">
+      <el-form ref="formRef"
+               :model="form"
+               :rules="rules"
+               label-width="120px">
+        <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 label="鏄惁璐ㄦ"
+                      prop="isQuality">
+          <el-switch v-model="form.isQuality"
+                     :active-value="1"
+                     :inactive-value="0" />
         </el-form-item>
       </el-form>
-
       <template #footer>
         <el-button @click="closeDialog">鍙栨秷</el-button>
-        <el-button type="primary" @click="handleSubmit" :loading="submitLoading">纭畾</el-button>
+        <el-button type="primary"
+                   @click="handleSubmit"
+                   :loading="submitLoading">纭畾</el-button>
       </template>
     </el-dialog>
-
     <!-- 浜у搧閫夋嫨瀵硅瘽妗� -->
-    <ProductSelectDialog
-        v-model="showProductSelectDialog"
-        @confirm="handleProductSelect"
-        single
-    />
+    <ProductSelectDialog v-model="showProductSelectDialog"
+                         @confirm="handleProductSelect"
+                         single />
+    <!-- BOM浜у搧閫夋嫨瀵硅瘽妗� -->
+    <ProductSelectDialog v-model="bomDataValue.showProductDialog"
+                         @confirm="handleBomProductSelect"
+                         single />
+    <!-- 鍙傛暟鍒楄〃瀵硅瘽妗� -->
+    <ProcessParamListDialog v-model="showParamListDialog"
+                            :title="`${currentProcess ? getProcessName(currentProcess.processId) : ''} - 鍙傛暟鍒楄〃`"
+                            :route-id="routeId"
+                            :editable="editable"
+                            :order-id="orderId"
+                            :process="currentProcess"
+                            :page-type="pageType"
+                            :param-list="paramList"
+                            @refresh="refreshParamList" />
   </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 { useRoute } from 'vue-router'
-import { ElMessageBox } from 'element-plus'
-import Sortable from 'sortablejs'
+  import {
+    ref,
+    computed,
+    getCurrentInstance,
+    onMounted,
+    onUnmounted,
+    nextTick,
+  } from "vue";
+  import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
+  import ProcessParamListDialog from "@/components/ProcessParamListDialog.vue";
+  import {
+    findProcessRouteItemList,
+    addOrUpdateProcessRouteItem,
+    sortProcessRouteItem,
+    batchDeleteProcessRouteItem,
+    getProcessParamList,
+  } from "@/api/productionManagement/processRouteItem.js";
+  import {
+    findProductProcessRouteItemList,
+    deleteRouteItem,
+    addRouteItem,
+    findProcessParamListOrder,
+    addOrUpdateProductProcessRouteItem,
+    sortRouteItem,
+  } from "@/api/productionManagement/productProcessRoute.js";
+  import { processList } from "@/api/productionManagement/productionProcess.js";
+  import {
+    queryList2,
+    queryList,
+    add2,
+  } from "@/api/productionManagement/productStructure.js";
+  import { useRoute } from "vue-router";
+  import { ElMessageBox, ElMessage } from "element-plus";
+  import Sortable from "sortablejs";
 
-const route = useRoute()
-const { proxy } = getCurrentInstance() || {};
+  const route = useRoute();
+  const { proxy } = getCurrentInstance() || {};
 
-const routeId = computed(() => route.query.id);
-const orderId = computed(() => route.query.orderId);
-const pageType = computed(() => route.query.type);
+  const routeId = computed(() => route.query.id);
+  const orderId = computed(() => route.query.orderId);
+  const pageType = computed(() => route.query.type);
+  const editable = computed(() => route.query.editable === "true");
 
-const tableLoading = ref(false);
-const tableData = ref([]);
-const dialogVisible = ref(false);
-const operationType = ref('add'); // add | edit
-const formRef = ref(null);
-const submitLoading = ref(false);
-const cardsContainer = ref(null);
-const tableRef = ref(null);
-const viewMode = ref('table'); // table | card
-const routeInfo = ref({
-  processRouteCode: '',
-  productName: '',
-  model: '',
-  bomNo: '',
-  description: ''
-});
-
-const processOptions = ref([]);
-const showProductSelectDialog = ref(false);
-let tableSortable = null;
-let cardSortable = null;
-
-// 鍒囨崲瑙嗗浘
-const toggleView = () => {
-  viewMode.value = viewMode.value === 'table' ? 'card' : 'table';
-  // 鍒囨崲瑙嗗浘鍚庨噸鏂板垵濮嬪寲鎷栨嫿鎺掑簭
-  nextTick(() => {
-    initSortable();
+  const tableLoading = ref(false);
+  const tableData = ref([]);
+  const dialogVisible = ref(false);
+  const operationType = ref("add"); // add | edit
+  const formRef = ref(null);
+  const submitLoading = ref(false);
+  const cardsContainer = ref(null);
+  const tableRef = ref(null);
+  const viewMode = ref("table"); // table | card
+  const routeInfo = ref({
+    processRouteCode: "",
+    productName: "",
+    model: "",
+    bomNo: "",
+    dictLabel: "",
+    bomId: null,
+    description: "",
   });
-};
 
-const form = ref({
-  id: undefined,
-  routeId: routeId.value,
-  processId: undefined,
-  productModelId: undefined,
-  productName: "",
-  model: "",
-  unit: "",
-});
-
-const rules = {
-  processId: [{ 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 getList = () => {
-  tableLoading.value = true;
-  const listPromise =
-    pageType.value === "order"
-      ? findProductProcessRouteItemList({ orderId: orderId.value })
-      : findProcessRouteItemList({ routeId: routeId.value });
-
-  listPromise
-    .then(res => {
-      tableData.value = res.data || [];
-      tableLoading.value = false;
-      // 鍒楄〃鍔犺浇瀹屾垚鍚庡垵濮嬪寲鎷栨嫿鎺掑簭
-      nextTick(() => {
-        initSortable();
-      });
-    })
-    .catch(err => {
-      tableLoading.value = false;
-      console.error("鑾峰彇鍒楄〃澶辫触锛�", err);
-      proxy?.$modal?.msgError("鑾峰彇鍒楄〃澶辫触");
-    });
-};
-
-// 鑾峰彇宸ュ簭鍒楄〃
-const getProcessList = () => {
-  processList({})
-    .then(res => {
-      processOptions.value = res.data || [];
-    })
-    .catch(err => {
-      console.error("鑾峰彇宸ュ簭澶辫触锛�", err);
-    });
-};
-
-// 鑾峰彇宸ヨ壓璺嚎璇︽儏锛堜粠璺敱鍙傛暟鑾峰彇锛�
-const getRouteInfo = () => {
-  routeInfo.value = {
-    processRouteCode: route.query.processRouteCode || '',
-    productName: route.query.productName || '',
-    model: route.query.model || '',
-    bomNo: route.query.bomNo || '',
-    description: route.query.description || ''
-  };
-};
-
-// 鏂板
-const handleAdd = () => {
-  operationType.value = 'add';
-  resetForm();
-  dialogVisible.value = true;
-};
-
-// 缂栬緫
-const handleEdit = (row) => {
-  operationType.value = 'edit';
-  form.value = {
-    id: row.id,
-    routeId: routeId.value,
-    processId: row.processId,
-    productModelId: row.productModelId,
-    productName: row.productName || "",
-    model: row.model || "",
-    unit: row.unit || "",
-  };
-  dialogVisible.value = true;
-};
-
-// 鍒犻櫎
-const handleDelete = (row) => {
-  ElMessageBox.confirm('纭鍒犻櫎璇ュ伐鑹鸿矾绾块」鐩紵', '鎻愮ず', {
-    confirmButtonText: '纭',
-    cancelButtonText: '鍙栨秷',
-    type: 'warning'
-  })
-    .then(() => {
-      // 鐢熶骇璁㈠崟涓嬩娇鐢� productProcessRoute 鐨勫垹闄ゆ帴鍙o紙璺敱鍚庢嫾鎺� id锛夛紝鍏跺畠鎯呭喌浣跨敤宸ヨ壓璺嚎椤圭洰鎵归噺鍒犻櫎鎺ュ彛
-      const deletePromise =
-        pageType.value === 'order'
-          ? deleteRouteItem(row.id)
-          : batchDeleteProcessRouteItem([row.id]);
-
-      deletePromise
-        .then(() => {
-          proxy?.$modal?.msgSuccess('鍒犻櫎鎴愬姛');
-          getList();
-        })
-        .catch(() => {
-          proxy?.$modal?.msgError('鍒犻櫎澶辫触');
-        });
-    })
-    .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');
-  }
-};
-
-// 鎻愪氦
-const handleSubmit = () => {
-  formRef.value.validate((valid) => {
-    if (valid) {
-      submitLoading.value = true;
-      
-      if (operationType.value === 'add') {
-        // 鏂板锛氫紶鍗曚釜瀵硅薄锛屽寘鍚玠ragSort瀛楁
-        // dragSort = 褰撳墠鍒楄〃闀垮害 + 1锛岃〃绀烘柊澧炶褰曟帓鍦ㄦ渶鍚�
-        const dragSort = tableData.value.length + 1;
-        const isOrderPage = pageType.value === 'order';
-
-        const addPromise = isOrderPage
-          ? addRouteItem({
-              productOrderId: orderId.value,
-              productRouteId: routeId.value,
-              processId: form.value.processId,
-              productModelId: form.value.productModelId,
-              dragSort,
-            })
-          : addOrUpdateProcessRouteItem({
-              routeId: routeId.value,
-              processId: form.value.processId,
-              productModelId: form.value.productModelId,
-              dragSort,
-            });
-
-        addPromise
-          .then(() => {
-            proxy?.$modal?.msgSuccess('鏂板鎴愬姛');
-            closeDialog();
-            getList();
-          })
-          .catch(() => {
-            proxy?.$modal?.msgError('鏂板澶辫触');
-          })
-          .finally(() => {
-            submitLoading.value = false;
-          });
-      } else {
-        // 缂栬緫锛氱敓浜ц鍗曚笅浣跨敤 productProcessRoute/updateRouteItem锛屽叾瀹冩儏鍐典娇鐢ㄥ伐鑹鸿矾绾块」鐩洿鏂版帴鍙�
-        const isOrderPage = pageType.value === 'order';
-        
-        const updatePromise = isOrderPage
-          ? addOrUpdateProductProcessRouteItem({
-              id: form.value.id,
-              processId: form.value.processId,
-              productModelId: form.value.productModelId,
-            })
-          : addOrUpdateProcessRouteItem({
-              routeId: routeId.value,
-              processId: form.value.processId,
-              productModelId: form.value.productModelId,
-              id: form.value.id,
-            });
-
-        updatePromise
-          .then(() => {
-            proxy?.$modal?.msgSuccess('淇敼鎴愬姛');
-            closeDialog();
-            getList();
-          })
-          .catch(() => {
-            proxy?.$modal?.msgError('淇敼澶辫触');
-          })
-          .finally(() => {
-            submitLoading.value = false;
-          });
-      }
-    }
+  const processOptions = ref([]);
+  const showProductSelectDialog = ref(false);
+  const showParamListDialog = ref(false);
+  const currentProcess = ref(null);
+  const paramList = ref([]);
+  const bomTableData = ref([]);
+  const bomFormRef = ref(null);
+  const bomDataValue = ref({
+    dataList: [],
+    showProductDialog: false,
+    currentRowName: null,
+    loading: false,
+    isEdit: false,
   });
-};
+  let tableSortable = null;
+  let cardSortable = null;
 
-// 閲嶇疆琛ㄥ崟
-const resetForm = () => {
-  form.value = {
+  // 鍒囨崲瑙嗗浘
+  const toggleView = () => {
+    viewMode.value = viewMode.value === "table" ? "card" : "table";
+    // 鍒囨崲瑙嗗浘鍚庨噸鏂板垵濮嬪寲鎷栨嫿鎺掑簭
+    nextTick(() => {
+      initSortable();
+    });
+  };
+
+  const form = ref({
     id: undefined,
     routeId: routeId.value,
     processId: undefined,
@@ -467,410 +467,1058 @@
     productName: "",
     model: "",
     unit: "",
+    isQuality: 0,
+  });
+
+  const rules = {
+    processId: [{ required: true, message: "璇烽�夋嫨宸ュ簭", trigger: "change" }],
   };
-  formRef.value?.resetFields();
-};
 
-// 鍏抽棴寮圭獥
-const closeDialog = () => {
-  dialogVisible.value = false;
-  resetForm();
-};
+  // 鏍规嵁宸ュ簭ID鑾峰彇宸ュ簭鍚嶇О
+  const getProcessName = processId => {
+    if (!processId) return "";
+    const process = processOptions.value.find(p => p.id === processId);
+    return process ? process.name : "";
+  };
 
-// 鍒濆鍖栨嫋鎷芥帓搴�
-const initSortable = () => {
-  destroySortable();
-  
-  if (viewMode.value === 'table') {
-    // 琛ㄦ牸瑙嗗浘鐨勬嫋鎷芥帓搴�
-    if (!tableRef.value) return;
-    
-    const tbody = tableRef.value.$el.querySelector('.el-table__body tbody') ||
-        tableRef.value.$el.querySelector('.el-table__body-wrapper > table > tbody');
-    
-    if (!tbody) return;
+  // 鑾峰彇鍒楄〃
+  const getList = () => {
+    tableLoading.value = true;
+    const listPromise =
+      pageType.value === "order"
+        ? findProductProcessRouteItemList({ orderId: orderId.value })
+        : findProcessRouteItemList({ routeId: routeId.value });
 
-    tableSortable = new Sortable(tbody, {
-      animation: 150,
-      ghostClass: 'sortable-ghost',
-      handle: '.el-table__row',
-      filter: '.el-button, .el-select',
-      onEnd: (evt) => {
-        if (evt.oldIndex === evt.newIndex || !tableData.value[evt.oldIndex]) return;
+    listPromise
+      .then(res => {
+        tableData.value = res.data || [];
+        tableLoading.value = false;
+        // 鍒楄〃鍔犺浇瀹屾垚鍚庡垵濮嬪寲鎷栨嫿鎺掑簭
+        nextTick(() => {
+          initSortable();
+        });
+      })
+      .catch(err => {
+        tableLoading.value = false;
+        console.error("鑾峰彇鍒楄〃澶辫触锛�", err);
+        proxy?.$modal?.msgError("鑾峰彇鍒楄〃澶辫触");
+      });
+  };
 
-        // 閲嶆柊鎺掑簭鏁扮粍
-        const moveItem = tableData.value.splice(evt.oldIndex, 1)[0];
-        tableData.value.splice(evt.newIndex, 0, moveItem);
-        
-        // 璁$畻鏂扮殑搴忓彿锛坉ragSort浠�1寮�濮嬶級
-        const newIndex = evt.newIndex;
-        const dragSort = newIndex + 1;
-        
-        // 璋冪敤鎺掑簭鎺ュ彛
-        if (moveItem.id) {
-          const isOrderPage = pageType.value === 'order';
-          const sortPromise = isOrderPage
-            ? sortRouteItem({
-                id: moveItem.id,
-                dragSort: dragSort
-              })
-            : sortProcessRouteItem({
-                id: moveItem.id,
-                dragSort: dragSort
-              });
+  // 鑾峰彇宸ュ簭鍒楄〃
+  const getProcessList = () => {
+    processList({})
+      .then(res => {
+        processOptions.value = res.data || [];
+      })
+      .catch(err => {
+        console.error("鑾峰彇宸ュ簭澶辫触锛�", err);
+      });
+  };
 
-          sortPromise
-            .then(() => {
-              // 鏇存柊鎵�鏈夎鐨刣ragSort
-              tableData.value.forEach((item, index) => {
-                if (item.id) {
-                  item.dragSort = index + 1;
+  // 鑾峰彇宸ヨ壓璺嚎璇︽儏锛堜粠璺敱鍙傛暟鑾峰彇锛�
+  const getRouteInfo = () => {
+    routeInfo.value = {
+      processRouteCode: route.query.processRouteCode || "",
+      productName: route.query.productName || "",
+      model: route.query.model || "",
+      bomNo: route.query.bomNo || "",
+      dictLabel: route.query.dictLabel || "",
+      bomId: route.query.bomId || null,
+      description: route.query.description || "",
+    };
+    if (pageType.value === "order") {
+      queryList2(route.query.orderId)
+        .then(res => {
+          if (res.data) {
+            // 涓築OM鏁版嵁璁剧疆tempId
+            const setTempIdRecursively = items => {
+              items.forEach(item => {
+                item.tempId = item.id || new Date().getTime();
+                if (item.children && item.children.length > 0) {
+                  setTempIdRecursively(item.children);
                 }
               });
-              proxy?.$modal?.msgSuccess('鎺掑簭鎴愬姛');
+            };
+            setTempIdRecursively(res.data);
+
+            bomTableData.value = [
+              {
+                bomNo: routeInfo.value.bomNo,
+                dictLabel: routeInfo.value.dictLabel,
+                productCode: "",
+                productName: routeInfo.value.productName,
+                model: routeInfo.value.model,
+                bomList: res.data,
+              },
+            ];
+
+            // 淇濆瓨鍘熷BOM鏁版嵁
+            bomDataValue.value.dataList = res.data;
+          }
+        })
+        .catch(err => {
+          console.error("鑾峰彇BOM鏁版嵁澶辫触锛�", err);
+        });
+    } else {
+      queryList(Number(route.query.bomId))
+        .then(res => {
+          if (res.data) {
+            // 涓築OM鏁版嵁璁剧疆tempId
+            const setTempIdRecursively = items => {
+              items.forEach(item => {
+                item.tempId = item.id || new Date().getTime();
+                if (item.children && item.children.length > 0) {
+                  setTempIdRecursively(item.children);
+                }
+              });
+            };
+            setTempIdRecursively(res.data);
+
+            bomTableData.value = [
+              {
+                bomNo: routeInfo.value.bomNo,
+                dictLabel: routeInfo.value.dictLabel,
+                productCode: "",
+                productName: routeInfo.value.productName,
+                model: routeInfo.value.model,
+                bomList: res.data,
+              },
+            ];
+
+            // 淇濆瓨鍘熷BOM鏁版嵁
+            bomDataValue.value.dataList = res.data;
+          }
+        })
+        .catch(err => {
+          console.error("鑾峰彇BOM鏁版嵁澶辫触锛�", err);
+        });
+    }
+    // 鑾峰彇BOM鏁版嵁锛屼娇鐢ㄦ柊鐨勬帴鍙�
+  };
+
+  // 鏂板
+  const handleAdd = () => {
+    operationType.value = "add";
+    resetForm();
+    dialogVisible.value = true;
+  };
+
+  // 缂栬緫
+  const handleEdit = row => {
+    operationType.value = "edit";
+    form.value = {
+      id: row.id,
+      routeId: routeId.value,
+      processId: row.processId,
+      productModelId: row.productModelId,
+      productName: row.productName || "",
+      model: row.model || "",
+      unit: row.unit || "",
+      isQuality: row.isQuality,
+    };
+    dialogVisible.value = true;
+  };
+
+  // 鍒犻櫎
+  const handleDelete = row => {
+    ElMessageBox.confirm("纭鍒犻櫎璇ュ伐鑹鸿矾绾块」鐩紵", "鎻愮ず", {
+      confirmButtonText: "纭",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
+      .then(() => {
+        // 鐢熶骇璁㈠崟涓嬩娇鐢� productProcessRoute 鐨勫垹闄ゆ帴鍙o紙璺敱鍚庢嫾鎺� id锛夛紝鍏跺畠鎯呭喌浣跨敤宸ヨ壓璺嚎椤圭洰鎵归噺鍒犻櫎鎺ュ彛
+        const deletePromise =
+          pageType.value === "order"
+            ? deleteRouteItem(row.id)
+            : batchDeleteProcessRouteItem([row.id]);
+
+        deletePromise
+          .then(() => {
+            proxy?.$modal?.msgSuccess("鍒犻櫎鎴愬姛");
+            getList();
+          })
+          .catch(() => {
+            proxy?.$modal?.msgError("鍒犻櫎澶辫触");
+          });
+      })
+      .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");
+    }
+  };
+
+  // 鎻愪氦
+  const handleSubmit = () => {
+    formRef.value.validate(valid => {
+      if (valid) {
+        submitLoading.value = true;
+
+        if (operationType.value === "add") {
+          // 鏂板锛氫紶鍗曚釜瀵硅薄锛屽寘鍚玠ragSort瀛楁
+          // dragSort = 褰撳墠鍒楄〃闀垮害 + 1锛岃〃绀烘柊澧炶褰曟帓鍦ㄦ渶鍚�
+          const dragSort = tableData.value.length + 1;
+          const isOrderPage = pageType.value === "order";
+
+          const addPromise = isOrderPage
+            ? addRouteItem({
+                orderId: orderId.value,
+                routeId: routeId.value,
+                processId: form.value.processId,
+                isQuality: form.value.isQuality,
+              })
+            : addOrUpdateProcessRouteItem({
+                routeId: routeId.value,
+                processId: form.value.processId,
+                productModelId: form.value.productModelId,
+                isQuality: form.value.isQuality,
+                dragSort,
+              });
+
+          addPromise
+            .then(() => {
+              proxy?.$modal?.msgSuccess("鏂板鎴愬姛");
+              closeDialog();
+              getList();
             })
-            .catch((err) => {
-              // 鎺掑簭澶辫触锛屾仮澶嶅師鏁扮粍
-              tableData.value.splice(newIndex, 1);
-              tableData.value.splice(evt.oldIndex, 0, moveItem);
-              proxy?.$modal?.msgError('鎺掑簭澶辫触');
-              console.error("鎺掑簭澶辫触锛�", err);
+            .catch(() => {
+              proxy?.$modal?.msgError("鏂板澶辫触");
+            })
+            .finally(() => {
+              submitLoading.value = false;
+            });
+        } else {
+          // 缂栬緫锛氱敓浜ц鍗曚笅浣跨敤 productProcessRoute/updateRouteItem锛屽叾瀹冩儏鍐典娇鐢ㄥ伐鑹鸿矾绾块」鐩洿鏂版帴鍙�
+          const isOrderPage = pageType.value === "order";
+
+          const updatePromise = isOrderPage
+            ? addOrUpdateProductProcessRouteItem({
+                id: form.value.id,
+                processId: form.value.processId,
+                isQuality: form.value.isQuality,
+              })
+            : addOrUpdateProcessRouteItem({
+                routeId: routeId.value,
+                processId: form.value.processId,
+                productModelId: form.value.productModelId,
+                id: form.value.id,
+                isQuality: form.value.isQuality,
+              });
+
+          updatePromise
+            .then(() => {
+              proxy?.$modal?.msgSuccess("淇敼鎴愬姛");
+              closeDialog();
+              getList();
+            })
+            .catch(() => {
+              proxy?.$modal?.msgError("淇敼澶辫触");
+            })
+            .finally(() => {
+              submitLoading.value = false;
             });
         }
       }
     });
-  } else {
-    // 鍗$墖瑙嗗浘鐨勬嫋鎷芥帓搴�
-    if (!cardsContainer.value) return;
+  };
 
-    cardSortable = new Sortable(cardsContainer.value, {
-      animation: 150,
-      ghostClass: 'sortable-ghost',
-      handle: '.process-card',
-      filter: '.el-button',
-      onEnd: (evt) => {
-        if (evt.oldIndex === evt.newIndex || !tableData.value[evt.oldIndex]) return;
+  // 閲嶇疆琛ㄥ崟
+  const resetForm = () => {
+    form.value = {
+      id: undefined,
+      routeId: routeId.value,
+      processId: undefined,
+      productModelId: undefined,
+      productName: "",
+      model: "",
+      unit: "",
+    };
+    formRef.value?.resetFields();
+  };
 
-        // 閲嶆柊鎺掑簭鏁扮粍
-        const moveItem = tableData.value.splice(evt.oldIndex, 1)[0];
-        tableData.value.splice(evt.newIndex, 0, moveItem);
-        
-        // 璁$畻鏂扮殑搴忓彿锛坉ragSort浠�1寮�濮嬶級
-        const newIndex = evt.newIndex;
-        const dragSort = newIndex + 1;
-        
-        // 璋冪敤鎺掑簭鎺ュ彛
-        if (moveItem.id) {
-          const isOrderPage = pageType.value === 'order';
-          const sortPromise = isOrderPage
-            ? sortRouteItem({
-                id: moveItem.id,
-                dragSort: dragSort
-              })
-            : sortProcessRouteItem({
-                id: moveItem.id,
-                dragSort: dragSort
-              });
+  // 鍏抽棴寮圭獥
+  const closeDialog = () => {
+    dialogVisible.value = false;
+    resetForm();
+  };
 
-          sortPromise
-            .then(() => {
-              // 鏇存柊鎵�鏈夎鐨刣ragSort
-              tableData.value.forEach((item, index) => {
-                if (item.id) {
-                  item.dragSort = index + 1;
-                }
-              });
-              proxy?.$modal?.msgSuccess('鎺掑簭鎴愬姛');
-            })
-            .catch((err) => {
-              // 鎺掑簭澶辫触锛屾仮澶嶅師鏁扮粍
-              tableData.value.splice(newIndex, 1);
-              tableData.value.splice(evt.oldIndex, 0, moveItem);
-              proxy?.$modal?.msgError('鎺掑簭澶辫触');
-              console.error("鎺掑簭澶辫触锛�", err);
-            });
+  // BOM鐩稿叧鏂规硶
+  // 鍒囨崲BOM缂栬緫妯″紡
+  const toggleBomEdit = () => {
+    bomDataValue.value.isEdit = !bomDataValue.value.isEdit;
+    if (!bomDataValue.value.isEdit) {
+      // 鍙栨秷缂栬緫鏃堕噸鏂板姞杞芥暟鎹�
+      getRouteInfo();
+    }
+  };
+
+  // 娣诲姞BOM椤�
+  const addBomItem = () => {
+    if (bomTableData.value.length > 0) {
+      const newItem = {
+        parentId: "",
+        parentTempId: "",
+        productName: "",
+        productId: "",
+        model: undefined,
+        productModelId: undefined,
+        processId: "",
+        processName: "",
+        unitQuantity: 0,
+        unit: "",
+        children: [],
+        tempId: new Date().getTime(),
+      };
+      bomTableData.value[0].bomList.push(newItem);
+      // 鐢变簬bomDataValue.value.dataList鍜宐omTableData.value[0].bomList鎸囧悜鍚屼竴涓暟缁勶紝涓嶉渶瑕侀噸澶嶆坊鍔�
+    }
+  };
+
+  // 娣诲姞BOM瀛愰」
+  const addBomItem2 = tempId => {
+    const addChildItem = (items, tempId) => {
+      for (let i = 0; i < items.length; i++) {
+        const item = items[i];
+        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: "",
+            unitQuantity: 0,
+            unit: "",
+            children: [],
+            tempId: new Date().getTime(),
+          });
+          return true;
+        }
+        if (item.children && item.children.length > 0) {
+          if (addChildItem(item.children, tempId)) {
+            return true;
+          }
         }
       }
-    });
-  }
-};
+      return false;
+    };
 
-// 閿�姣佹嫋鎷芥帓搴�
-const destroySortable = () => {
-  if (tableSortable) {
-    tableSortable.destroy();
-    tableSortable = null;
-  }
-  if (cardSortable) {
-    cardSortable.destroy();
-    cardSortable = null;
-  }
-};
+    if (bomTableData.value.length > 0) {
+      addChildItem(bomTableData.value[0].bomList, tempId);
+      // 鐢变簬bomDataValue.value.dataList鍜宐omTableData.value[0].bomList鎸囧悜鍚屼竴涓暟缁勶紝涓嶉渶瑕侀噸澶嶆坊鍔�
+    }
+  };
 
-onMounted(() => {
-  getRouteInfo();
-  getList();
-  getProcessList();
-});
+  // 鍒犻櫎BOM椤�
+  const removeBomItem = tempId => {
+    // 浠嶣OM琛ㄦ牸鏁版嵁涓垹闄�
+    if (bomTableData.value.length > 0) {
+      const removeFromList = (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 (removeFromList(item.children, tempId)) {
+              return true;
+            }
+          }
+        }
+        return false;
+      };
+      removeFromList(bomTableData.value[0].bomList, tempId);
+      // 鐢变簬bomDataValue.value.dataList鍜宐omTableData.value[0].bomList鎸囧悜鍚屼竴涓暟缁勶紝涓嶉渶瑕侀噸澶嶅垹闄�
+    }
+  };
 
-onUnmounted(() => {
-  destroySortable();
-});
+  // 鎵撳紑BOM浜у搧閫夋嫨瀵硅瘽妗�
+  const openBomProductDialog = tempId => {
+    bomDataValue.value.currentRowName = tempId;
+    bomDataValue.value.showProductDialog = true;
+  };
+
+  // 澶勭悊BOM浜у搧閫夋嫨
+  const handleBomProductSelect = products => {
+    if (products && products.length > 0) {
+      const product = products[0];
+      const updateProductInfo = (items, tempId, productData) => {
+        for (let i = 0; i < items.length; i++) {
+          const item = items[i];
+          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) {
+            if (updateProductInfo(item.children, tempId, productData)) {
+              return true;
+            }
+          }
+        }
+        return false;
+      };
+
+      if (bomTableData.value.length > 0) {
+        updateProductInfo(
+          bomTableData.value[0].bomList,
+          bomDataValue.value.currentRowName,
+          product
+        );
+        // 鐢变簬bomDataValue.value.dataList鍜宐omTableData.value[0].bomList鎸囧悜鍚屼竴涓暟缁勶紝涓嶉渶瑕侀噸澶嶆洿鏂�
+      }
+      bomDataValue.value.showProductDialog = false;
+    }
+  };
+
+  // 淇濆瓨BOM鏇存敼
+  const saveBomChanges = () => {
+    // 鏍¢獙BOM鏁版嵁
+    const validateBomData = items => {
+      for (let i = 0; i < items.length; i++) {
+        const item = items[i];
+        // 鏍¢獙浜у搧鏄惁蹇呭~
+        if (!item.productModelId) {
+          ElMessage.error("璇烽�夋嫨浜у搧");
+          return false;
+        }
+        // 鏍¢獙鍗曚綅浜у嚭鎵�闇�鏁伴噺鏄惁蹇呭~
+        if (
+          item.unitQuantity === undefined ||
+          item.unitQuantity === null ||
+          item.unitQuantity === 0
+        ) {
+          ElMessage.error("璇峰~鍐欏崟浣嶄骇鍑烘墍闇�鏁伴噺");
+          return false;
+        }
+        // 閫掑綊鏍¢獙瀛愰」
+        if (item.children && item.children.length > 0) {
+          if (!validateBomData(item.children)) {
+            return false;
+          }
+        }
+      }
+      return true;
+    };
+
+    // 鎵ц鏍¢獙
+    if (bomTableData.value.length > 0) {
+      if (!validateBomData(bomTableData.value[0].bomList)) {
+        return;
+      }
+    }
+
+    // 璋冪敤鏂扮殑淇濆瓨鎺ュ彛
+    // 鍑嗗淇濆瓨鏁版嵁锛岀‘淇濇牸寮忔纭�
+    // 閫掑綊澶勭悊BOM椤瑰強鍏跺瓙椤�
+    const processBomItem = (item, parentId = null, parentTempId = null) => {
+      const cleanItem = {
+        id: item.id || null,
+        orderId: Number(orderId.value) || null,
+        parentId: parentId,
+        parentTempId: parentTempId || null,
+        productModelId: item.productModelId || null,
+        processId: item.processId || null,
+        unitQuantity: item.unitQuantity || 0,
+        demandedQuantity: item.demandedQuantity || null,
+        unit: item.unit || "",
+        tempId: item.tempId || new Date().getTime(),
+        tenantId: item.tenantId || null,
+        bomId: Number(route.query.bomId) || null,
+        children: [],
+      };
+
+      // 閫掑綊澶勭悊瀛愰」
+      if (item.children && item.children.length > 0) {
+        cleanItem.children = item.children.map(child =>
+          processBomItem(child, item.id, item.tempId || null)
+        );
+      }
+
+      return cleanItem;
+    };
+
+    const saveData = bomTableData.value[0].bomList.map(item =>
+      processBomItem(item, item.parentId, item.parentTempId || null)
+    );
+    const formData = {
+      orderId: Number(orderId.value) || null,
+      children: saveData,
+    };
+
+    add2(formData)
+      .then(res => {
+        if (res.code === 200) {
+          ElMessage.success("BOM淇濆瓨鎴愬姛");
+          bomDataValue.value.isEdit = false;
+          // 閲嶆柊鍔犺浇鏁版嵁浠ヨ幏鍙栨渶鏂扮姸鎬�
+          getRouteInfo();
+        } else {
+          ElMessage.error("BOM淇濆瓨澶辫触锛�" + (res.msg || "鏈煡閿欒"));
+        }
+      })
+      .catch(err => {
+        console.error("淇濆瓨BOM鏁版嵁澶辫触锛�", err);
+        ElMessage.error("BOM淇濆瓨澶辫触锛氱綉缁滈敊璇�");
+      });
+  };
+
+  // 鍙栨秷BOM缂栬緫
+  const cancelBomEdit = () => {
+    bomDataValue.value.isEdit = false;
+    getRouteInfo();
+  };
+
+  // 鍒濆鍖栨嫋鎷芥帓搴�
+  const initSortable = () => {
+    destroySortable();
+
+    if (viewMode.value === "table") {
+      // 琛ㄦ牸瑙嗗浘鐨勬嫋鎷芥帓搴�
+      if (!tableRef.value) return;
+
+      const tbody =
+        tableRef.value.$el.querySelector(".el-table__body tbody") ||
+        tableRef.value.$el.querySelector(
+          ".el-table__body-wrapper > table > tbody"
+        );
+
+      if (!tbody) return;
+
+      tableSortable = new Sortable(tbody, {
+        animation: 150,
+        ghostClass: "sortable-ghost",
+        handle: ".el-table__row",
+        filter: ".el-button, .el-select",
+        onEnd: evt => {
+          if (evt.oldIndex === evt.newIndex || !tableData.value[evt.oldIndex])
+            return;
+
+          // 閲嶆柊鎺掑簭鏁扮粍
+          const moveItem = tableData.value.splice(evt.oldIndex, 1)[0];
+          tableData.value.splice(evt.newIndex, 0, moveItem);
+
+          // 璁$畻鏂扮殑搴忓彿锛坉ragSort浠�1寮�濮嬶級
+          const newIndex = evt.newIndex;
+          const dragSort = newIndex + 1;
+
+          // 璋冪敤鎺掑簭鎺ュ彛
+          if (moveItem.id) {
+            const isOrderPage = pageType.value === "order";
+            const sortPromise = isOrderPage
+              ? sortRouteItem({
+                  id: moveItem.id,
+                  dragSort: dragSort,
+                })
+              : sortProcessRouteItem({
+                  id: moveItem.id,
+                  dragSort: dragSort,
+                });
+
+            sortPromise
+              .then(() => {
+                // 鏇存柊鎵�鏈夎鐨刣ragSort
+                tableData.value.forEach((item, index) => {
+                  if (item.id) {
+                    item.dragSort = index + 1;
+                  }
+                });
+                proxy?.$modal?.msgSuccess("鎺掑簭鎴愬姛");
+              })
+              .catch(err => {
+                // 鎺掑簭澶辫触锛屾仮澶嶅師鏁扮粍
+                tableData.value.splice(newIndex, 1);
+                tableData.value.splice(evt.oldIndex, 0, moveItem);
+                proxy?.$modal?.msgError("鎺掑簭澶辫触");
+                console.error("鎺掑簭澶辫触锛�", err);
+              });
+          }
+        },
+      });
+    } else {
+      // 鍗$墖瑙嗗浘鐨勬嫋鎷芥帓搴�
+      if (!cardsContainer.value) return;
+
+      cardSortable = new Sortable(cardsContainer.value, {
+        animation: 150,
+        ghostClass: "sortable-ghost",
+        handle: ".process-card",
+        filter: ".el-button",
+        delay: 500, // 闀挎寜500姣鍚庡紑濮嬫嫋鎷�
+        onEnd: evt => {
+          if (evt.oldIndex === evt.newIndex || !tableData.value[evt.oldIndex])
+            return;
+
+          // 閲嶆柊鎺掑簭鏁扮粍
+          const moveItem = tableData.value.splice(evt.oldIndex, 1)[0];
+          tableData.value.splice(evt.newIndex, 0, moveItem);
+
+          // 璁$畻鏂扮殑搴忓彿锛坉ragSort浠�1寮�濮嬶級
+          const newIndex = evt.newIndex;
+          const dragSort = newIndex + 1;
+
+          // 璋冪敤鎺掑簭鎺ュ彛
+          if (moveItem.id) {
+            const isOrderPage = pageType.value === "order";
+            const sortPromise = isOrderPage
+              ? sortRouteItem({
+                  id: moveItem.id,
+                  dragSort: dragSort,
+                })
+              : sortProcessRouteItem({
+                  id: moveItem.id,
+                  dragSort: dragSort,
+                });
+
+            sortPromise
+              .then(() => {
+                // 鏇存柊鎵�鏈夎鐨刣ragSort
+                tableData.value.forEach((item, index) => {
+                  if (item.id) {
+                    item.dragSort = index + 1;
+                  }
+                });
+                proxy?.$modal?.msgSuccess("鎺掑簭鎴愬姛");
+              })
+              .catch(err => {
+                // 鎺掑簭澶辫触锛屾仮澶嶅師鏁扮粍
+                tableData.value.splice(newIndex, 1);
+                tableData.value.splice(evt.oldIndex, 0, moveItem);
+                proxy?.$modal?.msgError("鎺掑簭澶辫触");
+                console.error("鎺掑簭澶辫触锛�", err);
+              });
+          }
+        },
+      });
+    }
+  };
+
+  // 閿�姣佹嫋鎷芥帓搴�
+  const destroySortable = () => {
+    if (tableSortable) {
+      tableSortable.destroy();
+      tableSortable = null;
+    }
+    if (cardSortable) {
+      cardSortable.destroy();
+      cardSortable = null;
+    }
+  };
+
+  onMounted(() => {
+    getRouteInfo();
+    getList();
+    getProcessList();
+  });
+
+  // 鏌ョ湅鍙傛暟鍒楄〃
+  const handleViewParams = process => {
+    currentProcess.value = process;
+    // 璋冪敤API鑾峰彇鍙傛暟鍒楄〃
+    if (pageType.value === "order") {
+      findProcessParamListOrder({
+        orderId: orderId.value,
+        routeItemId: process.id,
+        pageNum: 1,
+        pageSize: 1000,
+      })
+        .then(res => {
+          if (res.code === 200) {
+            paramList.value = res.data || [];
+          } else {
+            ElMessage.error(res.msg || "鑾峰彇鍙傛暟鍒楄〃澶辫触");
+            paramList.value = [];
+          }
+          showParamListDialog.value = true;
+        })
+        .catch(err => {
+          console.error("鑾峰彇鍙傛暟鍒楄〃澶辫触锛�", err);
+          ElMessage.error("鑾峰彇鍙傛暟鍒楄〃澶辫触");
+          paramList.value = [];
+          showParamListDialog.value = true;
+        });
+    } else {
+      getProcessParamList({
+        routeItemId: process.id,
+        pageNum: 1,
+        pageSize: 1000,
+      })
+        .then(res => {
+          if (res.code === 200) {
+            paramList.value = res.data?.records || [];
+          } else {
+            ElMessage.error(res.msg || "鑾峰彇鍙傛暟鍒楄〃澶辫触");
+            paramList.value = [];
+          }
+          showParamListDialog.value = true;
+        })
+        .catch(err => {
+          console.error("鑾峰彇鍙傛暟鍒楄〃澶辫触锛�", err);
+          ElMessage.error("鑾峰彇鍙傛暟鍒楄〃澶辫触");
+          paramList.value = [];
+          showParamListDialog.value = true;
+        });
+    }
+  };
+
+  // 鍒锋柊鍙傛暟鍒楄〃
+  const refreshParamList = () => {
+    if (!currentProcess.value) return;
+    // 閲嶆柊璋冪敤API鑾峰彇鍙傛暟鍒楄〃
+    if (pageType.value === "order") {
+      findProcessParamListOrder({
+        orderId: orderId.value,
+        routeItemId: currentProcess.value.id,
+        pageNum: 1,
+        pageSize: 1000,
+      })
+        .then(res => {
+          if (res.code === 200) {
+            paramList.value = res.data || [];
+          } else {
+            ElMessage.error(res.msg || "鑾峰彇鍙傛暟鍒楄〃澶辫触");
+            paramList.value = [];
+          }
+        })
+        .catch(err => {
+          console.error("鑾峰彇鍙傛暟鍒楄〃澶辫触锛�", err);
+          ElMessage.error("鑾峰彇鍙傛暟鍒楄〃澶辫触");
+          paramList.value = [];
+        });
+    } else {
+      getProcessParamList({
+        routeItemId: currentProcess.value.id,
+        pageNum: 1,
+        pageSize: 1000,
+      })
+        .then(res => {
+          if (res.code === 200) {
+            paramList.value = res.data?.records || [];
+          } else {
+            ElMessage.error(res.msg || "鑾峰彇鍙傛暟鍒楄〃澶辫触");
+            paramList.value = [];
+          }
+        })
+        .catch(err => {
+          console.error("鑾峰彇鍙傛暟鍒楄〃澶辫触锛�", err);
+          ElMessage.error("鑾峰彇鍙傛暟鍒楄〃澶辫触");
+          paramList.value = [];
+        });
+    }
+  };
+
+  onUnmounted(() => {
+    destroySortable();
+  });
 </script>
 
 <style scoped>
-.card-container {
-  padding: 20px 0;
-}
+  .card-container {
+    padding: 20px 0;
+    /* height: 350px; */
+    margin-bottom: 20px;
+  }
 
-.cards-wrapper {
-  display: flex;
-  gap: 16px;
-  overflow-x: auto;
-  padding: 10px 0;
-  min-height: 200px;
-}
+  .cards-wrapper {
+    display: flex;
+    gap: 24px;
+    overflow-x: auto;
+    padding: 10px 0;
+    /* min-height: 250px; */
+  }
 
-.cards-wrapper::-webkit-scrollbar {
-  height: 8px;
-}
+  .cards-wrapper::-webkit-scrollbar {
+    height: 8px;
+  }
 
-.cards-wrapper::-webkit-scrollbar-track {
-  background: #f1f1f1;
-  border-radius: 4px;
-}
+  .cards-wrapper::-webkit-scrollbar-track {
+    background: #f1f1f1;
+    border-radius: 4px;
+  }
 
-.cards-wrapper::-webkit-scrollbar-thumb {
-  background: #c1c1c1;
-  border-radius: 4px;
-}
+  .cards-wrapper::-webkit-scrollbar-thumb {
+    background: #c1c1c1;
+    border-radius: 4px;
+  }
 
-.cards-wrapper::-webkit-scrollbar-thumb:hover {
-  background: #a8a8a8;
-}
+  .cards-wrapper::-webkit-scrollbar-thumb:hover {
+    background: #a8a8a8;
+  }
 
-.process-card {
-  flex-shrink: 0;
-  width: 220px;
-  background: #fff;
-  border-radius: 8px;
-  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
-  padding: 16px;
-  display: flex;
-  flex-direction: column;
-  cursor: move;
-  transition: all 0.3s;
-}
+  .process-card {
+    flex-shrink: 0;
+    /* width: 300px; */
+    background: #fff;
+    border-radius: 12px;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+    /* padding: 30px 24px; */
+    padding: 25px 50px;
+    display: flex;
+    flex-direction: column;
+    cursor: move;
+    transition: all 0.3s;
+  }
 
-.process-card:hover {
-  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
-  transform: translateY(-2px);
-}
+  .process-card:hover {
+    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
+    transform: translateY(-4px);
+  }
 
-.card-header {
-  text-align: center;
-  margin-bottom: 12px;
-}
+  .card-header {
+    text-align: center;
+    margin-bottom: 20px;
+  }
 
-.card-number {
-  width: 36px;
-  height: 36px;
-  line-height: 36px;
-  border-radius: 50%;
-  background: #409eff;
-  color: #fff;
-  font-weight: bold;
-  font-size: 16px;
-  margin: 0 auto 8px;
-}
+  .card-number {
+    width: 60px;
+    height: 60px;
+    line-height: 60px;
+    border-radius: 50%;
+    background: #409eff;
+    color: #fff;
+    font-weight: bold;
+    font-size: 20px;
+    margin: 0 auto 16px;
+  }
 
-.card-process-name {
-  font-size: 14px;
-  color: #333;
-  font-weight: 500;
-  word-break: break-all;
-}
+  .card-process-name {
+    font-size: 18px;
+    color: #333;
+    font-weight: 600;
+    word-break: break-all;
+  }
 
-.card-content {
-  flex: 1;
-  margin-bottom: 12px;
-  min-height: 60px;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-}
+  .card-content {
+    flex: 1;
+    margin-bottom: 20px;
+    min-height: 80px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
 
-.product-info {
-  font-size: 13px;
-  color: #666;
-  text-align: center;
-  width: 100%;
-}
+  .product-info {
+    font-size: 14px;
+    color: #666;
+    text-align: center;
+    width: 100%;
+  }
 
-.product-info.empty {
-  color: #999;
-  text-align: center;
-  padding: 20px 0;
-}
+  .product-info.empty {
+    color: #999;
+    text-align: center;
+    padding: 20px 0;
+  }
 
-.product-name {
-  margin-bottom: 6px;
-  word-break: break-all;
-  line-height: 1.5;
-  text-align: center;
-}
+  .product-name {
+    margin-bottom: 8px;
+    word-break: break-all;
+    line-height: 1.5;
+    text-align: center;
+  }
 
-.product-model {
-  color: #909399;
-  font-size: 12px;
-  word-break: break-all;
-  line-height: 1.5;
-  text-align: center;
-}
+  .product-model {
+    color: #909399;
+    font-size: 13px;
+    word-break: break-all;
+    line-height: 1.5;
+    text-align: center;
+  }
 
-.product-unit {
-  margin-left: 4px;
-  color: #409eff;
-}
+  .product-unit {
+    margin-left: 4px;
+    color: #409eff;
+  }
 
-.card-footer {
-  display: flex;
-  justify-content: space-around;
-  padding-top: 12px;
-  border-top: 1px solid #f0f0f0;
-}
+  .product-tag {
+    margin: 12px 0;
+  }
 
-.card-footer .el-button {
-  padding: 0;
-  font-size: 12px;
-}
+  .card-footer {
+    display: flex;
+    justify-content: center;
+    gap: 20px;
+    padding-top: 16px;
+    border-top: 1px solid #f0f0f0;
+  }
 
-:deep(.sortable-ghost) {
-  opacity: 0.5;
-  background-color: #f5f7fa !important;
-}
+  .card-footer .el-button {
+    padding: 0;
+    font-size: 14px;
+  }
 
-:deep(.sortable-drag) {
-  opacity: 0.8;
-}
+  .card-footer .el-button:nth-child(1) {
+    color: #409eff;
+  }
 
-/* 琛ㄦ牸瑙嗗浘鏍峰紡 */
-:deep(.el-table__row) {
-  transition: background-color 0.2s;
-  cursor: move;
-}
+  .card-footer .el-button:nth-child(2) {
+    color: #67c23a;
+  }
 
-:deep(.el-table__row:hover) {
-  background-color: #f9fafc !important;
-}
+  .card-footer .el-button:nth-child(3) {
+    color: #f56c6c;
+  }
 
-/* 鍖哄煙鏍囬鏍峰紡 */
-.section-header {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  margin-bottom: 12px;
-}
+  :deep(.sortable-ghost) {
+    opacity: 0.5;
+    background-color: #f5f7fa !important;
+  }
 
-.section-title {
-  font-size: 16px;
-  font-weight: 600;
-  color: #303133;
-  padding-left: 12px;
-  position: relative;
-  margin-bottom: 0;
-}
+  :deep(.sortable-drag) {
+    opacity: 0.8;
+  }
 
-.section-title::before {
-  content: '';
-  position: absolute;
-  left: 0;
-  top: 50%;
-  transform: translateY(-50%);
-  width: 3px;
-  height: 16px;
-  background: #409eff;
-  border-radius: 2px;
-}
+  /* 琛ㄦ牸瑙嗗浘鏍峰紡 - 浠呭簲鐢ㄤ簬椤圭洰鍒楄〃 */
+  :deep(.lims-table .el-table__row) {
+    transition: background-color 0.2s;
+    cursor: move;
+  }
 
-.section-actions {
-  display: flex;
-  align-items: center;
-}
+  :deep(.lims-table .el-table__row:hover) {
+    background-color: #f9fafc !important;
+  }
 
-/* 宸ヨ壓璺嚎淇℃伅鍗$墖鏍峰紡 */
-.route-info-card {
-  margin-bottom: 20px;
-  border: 1px solid #e4e7ed;
-  background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
-  border-radius: 8px;
-  overflow: hidden;
-}
+  /* 鍖哄煙鏍囬鏍峰紡 */
+  .section-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 12px;
+  }
 
-.route-info {
-  display: grid;
-  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
-  gap: 16px;
-  padding: 4px;
-}
+  .section-title {
+    font-size: 16px;
+    font-weight: 600;
+    color: #303133;
+    padding-left: 12px;
+    position: relative;
+    margin-bottom: 0;
+  }
 
-.info-item {
-  display: flex;
-  flex-direction: column;
-  background: #ffffff;
-  border-radius: 6px;
-  padding: 14px 16px;
-  border: 1px solid #f0f2f5;
-  transition: all 0.3s ease;
-  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
-}
+  .section-title::before {
+    content: "";
+    position: absolute;
+    left: 0;
+    top: 50%;
+    transform: translateY(-50%);
+    width: 3px;
+    height: 16px;
+    background: #409eff;
+    border-radius: 2px;
+  }
 
-.info-item:hover {
-  border-color: #409eff;
-  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.15);
-  transform: translateY(-1px);
-}
+  .section-actions {
+    display: flex;
+    align-items: center;
+  }
+  .sort-tip {
+    font-size: 12px;
+    color: #909399;
+    margin-left: 8px;
+    margin-right: 20px;
+  }
 
-.info-item.full-width {
-  grid-column: 1 / -1;
-}
+  /* 宸ヨ壓璺嚎淇℃伅鍗$墖鏍峰紡 */
+  .route-info-card {
+    margin-bottom: 20px;
+    border: 1px solid #e4e7ed;
+    background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
+    border-radius: 8px;
+    overflow: hidden;
+  }
 
-.info-label-wrapper {
-  margin-bottom: 8px;
-}
+  .route-info {
+    display: grid;
+    grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
+    gap: 16px;
+    padding: 4px;
+  }
 
-.info-label {
-  display: inline-block;
-  color: #909399;
-  font-size: 12px;
-  font-weight: 500;
-  text-transform: uppercase;
-  letter-spacing: 0.5px;
-  padding: 2px 0;
-  position: relative;
-}
+  .info-item {
+    display: flex;
+    flex-direction: column;
+    background: #ffffff;
+    border-radius: 6px;
+    padding: 14px 16px;
+    border: 1px solid #f0f2f5;
+    transition: all 0.3s ease;
+    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
+  }
 
-.info-label::after {
-  content: '';
-  position: absolute;
-  left: 0;
-  bottom: 0;
-  width: 20px;
-  height: 2px;
-  background: linear-gradient(90deg, #409eff, transparent);
-  border-radius: 1px;
-}
+  .info-item:hover {
+    border-color: #409eff;
+    box-shadow: 0 2px 8px rgba(64, 158, 255, 0.15);
+    transform: translateY(-1px);
+  }
 
-.info-value-wrapper {
-  flex: 1;
-}
+  .info-item.full-width {
+    grid-column: 1 / -1;
+  }
 
-.info-value {
-  display: block;
-  color: #303133;
-  font-size: 15px;
-  font-weight: 500;
-  line-height: 1.5;
-  word-break: break-all;
-}
+  .info-label-wrapper {
+    margin-bottom: 8px;
+  }
+
+  .info-label {
+    display: inline-block;
+    color: #909399;
+    font-size: 12px;
+    font-weight: 500;
+    text-transform: uppercase;
+    letter-spacing: 0.5px;
+    padding: 2px 0;
+    position: relative;
+  }
+
+  .info-label::after {
+    content: "";
+    position: absolute;
+    left: 0;
+    bottom: 0;
+    width: 20px;
+    height: 2px;
+    background: linear-gradient(90deg, #409eff, transparent);
+    border-radius: 1px;
+  }
+
+  .info-value-wrapper {
+    flex: 1;
+  }
+
+  .info-value {
+    display: block;
+    color: #303133;
+    font-size: 15px;
+    font-weight: 500;
+    line-height: 1.5;
+    word-break: break-all;
+  }
 </style>
+<style scoped>
+  .hover-effect:hover {
+    border-color: #409eff;
+    background-color: #ecf5ff;
+    transform: translateY(-2px);
+    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+  }
+</style>
\ No newline at end of file

--
Gitblit v1.9.3