From ec5bd9a7abba71e9234fa0d327e8261f89723603 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期二, 17 三月 2026 16:22:20 +0800
Subject: [PATCH] 工艺路线替换回去,参数功能添加、dist.js修改字典增加id

---
 src/views/productionManagement/processRoute/ItemsForm.vue              |  531 ++++
 src/utils/dict.js                                                      |    2 
 src/views/productionManagement/processRoute/index.vue                  | 2567 +------------------
 src/views/productionManagement/processRoute/New.vue                    |  194 +
 src/views/productionManagement/processRoute/processRouteItem/index.vue | 1024 +++++++
 src/components/ProcessParamListDialog.vue                              |  631 ++++
 src/views/productionPlan/productionPlan/index.vue                      |  104 
 src/views/productionManagement/processRoute/Edit.vue                   |  257 +
 src/views/productionManagement/processRoute/index2.vue                 | 2417 ++++++++++++++++++
 9 files changed, 5,362 insertions(+), 2,365 deletions(-)

diff --git a/src/components/ProcessParamListDialog.vue b/src/components/ProcessParamListDialog.vue
new file mode 100644
index 0000000..3b9f158
--- /dev/null
+++ b/src/components/ProcessParamListDialog.vue
@@ -0,0 +1,631 @@
+<template>
+  <el-dialog v-model="visible"
+             :title="title"
+             width="800px"
+             destroy-on-close>
+    <div class="param-list-container">
+      <div class="params-header">
+        <span>鍙傛暟鍒楄〃</span>
+        <el-button v-if="editable"
+                   type="primary"
+                   link
+                   size="small"
+                   @click="handleAddParam">
+          <el-icon>
+            <Plus />
+          </el-icon>鏂板
+        </el-button>
+      </div>
+      <div class="params-list">
+        <div v-for="param in paramList"
+             :key="param.id"
+             class="param-item">
+          <div class="param-info">
+            <span class="param-code">{{ param.paramName }}</span>
+            <span v-if="param.valueMode == 1"
+                  class="param-value">
+              鏍囧噯鍊硷細{{ param.standardValue || "-" }} {{ param.unit }}
+            </span>
+            <span v-else
+                  class="param-value">
+              鏍囧噯鍊硷細{{ param.minValue || "-" }}-{{ param.maxValue || "-" }} {{ param.unit }}
+            </span>
+          </div>
+          <div class="param-actions">
+            <el-button v-if="editable"
+                       link
+                       type="primary"
+                       size="small"
+                       @click="handleEditParam(param)">
+              缂栬緫
+            </el-button>
+            <el-button v-if="editable"
+                       link
+                       type="danger"
+                       size="small"
+                       @click="handleDeleteParam(param)">
+              鍒犻櫎
+            </el-button>
+          </div>
+        </div>
+        <el-empty v-if="!paramList || paramList.length === 0"
+                  description="鏆傛棤鍙傛暟"
+                  :image-size="50" />
+      </div>
+    </div>
+    <!-- 閫夋嫨鍙傛暟瀵硅瘽妗� -->
+    <el-dialog v-model="selectParamDialogVisible"
+               title="閫夋嫨鍙傛暟"
+               width="1000px">
+      <div class="param-select-container">
+        <!-- 宸︿晶鍙傛暟鍒楄〃 -->
+        <div class="param-list-area">
+          <div class="area-title">鍙�夊弬鏁�</div>
+          <div class="search-box">
+            <el-input v-model="paramSearchKeyword"
+                      placeholder="璇疯緭鍏ュ弬鏁板悕绉版悳绱�"
+                      clearable
+                      size="small"
+                      @input="getBaseParamListData">
+              <template #prefix>
+                <el-icon>
+                  <Search />
+                </el-icon>
+              </template>
+            </el-input>
+          </div>
+          <el-table :data="filteredParamList"
+                    height="400"
+                    border
+                    highlight-current-row
+                    @current-change="handleSelectParam">
+            <el-table-column prop="paramName"
+                             label="鍙傛暟鍚嶇О" />
+            <el-table-column prop="paramType"
+                             label="鍙傛暟绫诲瀷">
+              <template #default="scope">
+                <el-tag size="small"
+                        :type="getParamTypeTag(scope.row.paramType)">{{ getParamTypeText(scope.row.paramType) }}</el-tag>
+              </template>
+            </el-table-column>
+          </el-table>
+          <!-- 鍒嗛〉鎺т欢 -->
+          <div class="pagination-container"
+               style="margin-top: 10px;">
+            <el-pagination v-model:current-page="paramPage.current"
+                           v-model:page-size="paramPage.size"
+                           :page-sizes="[10, 20, 50, 100]"
+                           layout="total, sizes, prev, pager, next, jumper"
+                           :total="paramPage.total"
+                           @size-change="getBaseParamListData"
+                           @current-change="getBaseParamListData"
+                           size="small" />
+          </div>
+        </div>
+        <!-- 鍙充晶鍙傛暟璇︽儏 -->
+        <div class="param-detail-area">
+          <div class="area-title">鍙傛暟璇︽儏</div>
+          <el-form v-if="selectedParam"
+                   :model="selectedParam"
+                   label-width="100px"
+                   class="param-detail-form">
+            <el-form-item label="鍙傛暟鍚嶇О">
+              <span class="detail-text">{{ selectedParam.paramName }}</span>
+            </el-form-item>
+            <el-form-item label="鍙傛暟妯″紡">
+              <el-tag size="small"
+                      :type="selectedParam.valueMode == '1' ? 'success' : 'warning'">
+                {{ selectedParam.valueMode == '1' ? '鍗曞��' : '鍖洪棿' }}
+              </el-tag>
+            </el-form-item>
+            <el-form-item label="鍙傛暟绫诲瀷">
+              <el-tag size="small"
+                      :type="getParamTypeTag(selectedParam.paramType)">{{ getParamTypeText(selectedParam.paramType) }}</el-tag>
+            </el-form-item>
+            <el-form-item label="鍙傛暟鏍煎紡">
+              <span class="detail-text">{{ selectedParam.paramFormat || '-' }}</span>
+            </el-form-item>
+            <el-form-item label="鍗曚綅">
+              <span class="detail-text">{{ selectedParam.unit || '-' }}</span>
+            </el-form-item>
+            <el-form-item label="鏍囧噯鍊�"
+                          v-if="selectedParam.valueMode == '1' && selectedParam.paramType == '1'">
+              <el-input v-model="selectedParam.standardValue"
+                        type="number"
+                        placeholder="璇疯緭鍏ラ粯璁ゅ��" />
+            </el-form-item>
+            <el-form-item label="鏈�灏忓��"
+                          v-if="selectedParam.valueMode == '2' && selectedParam.paramType == '1'">
+              <el-input v-model="selectedParam.minValue"
+                        type="number"
+                        placeholder="璇疯緭鍏ユ渶灏忓��" />
+            </el-form-item>
+            <el-form-item label="鏈�澶у��"
+                          v-if="selectedParam.valueMode == '2' && selectedParam.paramType == '1'">
+              <el-input v-model="selectedParam.maxValue"
+                        type="number"
+                        placeholder="璇疯緭鍏ユ渶澶у��" />
+            </el-form-item>
+            <el-form-item label="鎺掑簭">
+              <el-input v-model="selectedParam.sort"
+                        type="number"
+                        placeholder="璇疯緭鍏ユ帓搴�" />
+            </el-form-item>
+            <el-form-item label="鏄惁蹇呭~">
+              <el-switch v-model="selectedParam.isRequired" />
+            </el-form-item>
+          </el-form>
+          <el-empty v-else
+                    description="璇蜂粠宸︿晶閫夋嫨鍙傛暟"
+                    :image-size="100" />
+        </div>
+      </div>
+      <template #footer>
+        <el-button @click="selectParamDialogVisible = false">鍙栨秷</el-button>
+        <el-button type="primary"
+                   @click="handleParamSelectSubmit">纭畾</el-button>
+      </template>
+    </el-dialog>
+    <!-- 缂栬緫鍙傛暟瀵硅瘽妗� -->
+    <el-dialog v-model="editParamDialogVisible"
+               title="缂栬緫鍙傛暟"
+               width="600px">
+      <el-form :model="editParamForm"
+               :rules="editParamRules"
+               ref="editParamFormRef"
+               label-width="120px">
+        <el-form-item label="鍙傛暟鍚嶇О">
+          <span class="detail-text">{{ editParamForm.paramName }}</span>
+        </el-form-item>
+        <el-form-item label="鍙傛暟妯″紡">
+          <el-tag size="small"
+                  :type="editParamForm.valueMode == '1' ? 'success' : 'warning'">
+            {{ editParamForm.valueMode == '1' ? '鍗曞��' : '鍖洪棿' }}
+          </el-tag>
+        </el-form-item>
+        <el-form-item label="鍙傛暟绫诲瀷">
+          <el-tag size="small"
+                  :type="getParamTypeTag(editParamForm.paramType)">
+            {{ getParamTypeText(editParamForm.paramType) }}
+          </el-tag>
+        </el-form-item>
+        <el-form-item label="鍙傛暟鏍煎紡">
+          <span class="detail-text">{{ editParamForm.paramFormat || '-' }}</span>
+        </el-form-item>
+        <el-form-item label="鍗曚綅">
+          <span class="detail-text">{{ editParamForm.unit || '-' }}</span>
+        </el-form-item>
+        <el-form-item label="鏍囧噯鍊�"
+                      v-if="editParamForm.valueMode == '1' && editParamForm.paramType == '1'"
+                      prop="standardValue">
+          <el-input v-model="editParamForm.standardValue"
+                    type="number"
+                    placeholder="璇疯緭鍏ユ爣鍑嗗��" />
+        </el-form-item>
+        <el-form-item label="鏈�灏忓��"
+                      v-if="editParamForm.valueMode == '2' && editParamForm.paramType == '1'"
+                      prop="minValue">
+          <el-input v-model="editParamForm.minValue"
+                    type="number"
+                    placeholder="璇疯緭鍏ユ渶灏忓��" />
+        </el-form-item>
+        <el-form-item label="鏈�澶у��"
+                      v-if="editParamForm.valueMode == '2' && editParamForm.paramType == '1'"
+                      prop="maxValue">
+          <el-input v-model="editParamForm.maxValue"
+                    type="number"
+                    placeholder="璇疯緭鍏ユ渶澶у��" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="editParamDialogVisible = false">鍙栨秷</el-button>
+        <el-button type="primary"
+                   @click="handleEditParamSubmit">纭畾</el-button>
+      </template>
+    </el-dialog>
+  </el-dialog>
+</template>
+
+<script setup>
+  import { ref, computed, watch } from "vue";
+  import { ElMessage, ElMessageBox } from "element-plus";
+  import { Plus, Search } from "@element-plus/icons-vue";
+  import {
+    delProcessRouteItemParam,
+    editProcessRouteItemParam,
+    addProcessRouteItemParam,
+  } from "@/api/productionManagement/processRouteItem.js";
+  import { getBaseParamList } from "@/api/basicData/parameterMaintenance.js";
+
+  const props = defineProps({
+    modelValue: {
+      type: Boolean,
+      default: false,
+    },
+    title: {
+      type: String,
+      default: "鍙傛暟鍒楄〃",
+    },
+    routeId: {
+      type: Number,
+      default: 0,
+    },
+    process: {
+      type: Object,
+      default: () => ({}),
+    },
+    paramList: {
+      type: Array,
+      default: () => [],
+    },
+    editable: {
+      type: Boolean,
+      default: true,
+    },
+  });
+
+  const emit = defineEmits(["update:modelValue", "refresh"]);
+
+  const visible = computed({
+    get: () => props.modelValue,
+    set: value => emit("update:modelValue", value),
+  });
+
+  // 鍝嶅簲寮忔暟鎹�
+  const selectParamDialogVisible = ref(false);
+  const editParamDialogVisible = ref(false);
+  const paramSearchKeyword = ref("");
+  const selectedParam = ref(null);
+  const filteredParamList = ref([]);
+  const paramPage = ref({
+    current: 1,
+    size: 10,
+    total: 0,
+  });
+  const editParamForm = ref({
+    id: null,
+    processId: null,
+    paramId: null,
+    paramName: "",
+    valueMode: "1",
+    standardValue: null,
+    minValue: null,
+    maxValue: null,
+    sort: 1,
+    isRequired: 0,
+    paramType: null,
+    paramFormat: "",
+    unit: "",
+  });
+  const editParamRules = ref({
+    standardValue: [{ required: true, message: "璇疯緭鍏ユ爣鍑嗗��", trigger: "blur" }],
+    minValue: [{ required: true, message: "璇疯緭鍏ユ渶灏忓��", trigger: "blur" }],
+    maxValue: [{ required: true, message: "璇疯緭鍏ユ渶澶у��", trigger: "blur" }],
+  });
+  const editParamFormRef = ref(null);
+
+  // 鏂板鍙傛暟
+  const handleAddParam = () => {
+    selectedParam.value = null;
+    paramSearchKeyword.value = "";
+    paramPage.current = 1;
+    // 鑾峰彇鍙�夊弬鏁板垪琛�
+    getBaseParamListData();
+    selectParamDialogVisible.value = true;
+  };
+
+  // 缂栬緫鍙傛暟
+  const handleEditParam = param => {
+    editParamForm.value = {
+      id: param.id,
+      processId: props.process.id,
+      paramId: param.paramId,
+      paramName: param.parameterName || param.paramName,
+      valueMode: param.parameterType2 || param.valueMode || "1",
+      standardValue: param.standardValue,
+      minValue: param.minValue,
+      maxValue: param.maxValue,
+      sort: param.sort || 1,
+      isRequired: param.isRequired || 0,
+      paramType: param.parameterType || param.paramType,
+      paramFormat: param.parameterFormat || param.paramFormat,
+      unit: param.unit || param.unit,
+    };
+    editParamDialogVisible.value = true;
+  };
+
+  // 鍒犻櫎鍙傛暟
+  const handleDeleteParam = param => {
+    ElMessageBox.confirm("纭畾瑕佸垹闄よ鍙傛暟鍚楋紵", "鎻愮ず", {
+      confirmButtonText: "纭畾",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    })
+      .then(() => {
+        // 璋冪敤API鍒犻櫎鍙傛暟
+        delProcessRouteItemParam(param.id)
+          .then(res => {
+            ElMessage.success("鍒犻櫎鎴愬姛");
+            emit("refresh");
+          })
+          .catch(err => {
+            ElMessage.error("鍒犻櫎鍙傛暟澶辫触");
+            console.error("鍒犻櫎鍙傛暟澶辫触锛�", err);
+          });
+      })
+      .catch(() => {});
+  };
+
+  // 鑾峰彇鍙�夊弬鏁板垪琛�
+  const getBaseParamListData = () => {
+    getBaseParamList({
+      paramName: paramSearchKeyword.value,
+      current: paramPage.current,
+      size: paramPage.size,
+    }).then(res => {
+      if (res.code === 200) {
+        filteredParamList.value = res.data?.records || [];
+        paramPage.total = res.data?.total || 0;
+      } else {
+        ElMessage.error(res.msg || "鏌ヨ澶辫触");
+      }
+    });
+  };
+
+  // 閫夋嫨鍙傛暟
+  const handleSelectParam = param => {
+    selectedParam.value = param;
+  };
+
+  // 鎻愪氦閫夋嫨鍙傛暟
+  const handleParamSelectSubmit = () => {
+    if (!selectedParam.value) {
+      ElMessage.warning("璇峰厛閫夋嫨涓�涓弬鏁�");
+      return;
+    }
+
+    if (!props.process || !props.process.id) {
+      ElMessage.error("宸ヨ壓璺嚎椤圭洰淇℃伅涓嶅畬鏁�");
+      return;
+    }
+
+    // 鍒ゆ柇鍙傛暟绫诲瀷锛屽彧鏈夋暟鍊肩被鍨嬫墠浼犳爣鍑嗗�笺�佹渶澶у�煎拰鏈�灏忓��
+    const isNumericMode = selectedParam.value.valueMode === 1;
+
+    // 璋冪敤API鏂板鍙傛暟
+    addProcessRouteItemParam({
+      routeItemId: props.process.id,
+      paramId: selectedParam.value.id,
+      standardValue: isNumericMode ? selectedParam.value.standardValue || "" : "",
+      minValue: isNumericMode ? selectedParam.value.minValue || 0 : null,
+      maxValue: isNumericMode ? selectedParam.value.maxValue || 0 : null,
+      isRequired: selectedParam.value.isRequired || 0,
+      sort: selectedParam.value.sort || 1,
+    })
+      .then(res => {
+        if (res.code === 200) {
+          ElMessage.success("娣诲姞鍙傛暟鎴愬姛");
+          selectParamDialogVisible.value = false;
+          emit("refresh");
+        } else {
+          ElMessage.error(res.msg || "娣诲姞鍙傛暟澶辫触");
+        }
+      })
+      .catch(err => {
+        ElMessage.error("娣诲姞鍙傛暟澶辫触");
+        console.error("娣诲姞鍙傛暟澶辫触锛�", err);
+      });
+  };
+
+  // 鎻愪氦缂栬緫鍙傛暟
+  const handleEditParamSubmit = () => {
+    if (!editParamFormRef.value) return;
+    editParamFormRef.value.validate(valid => {
+      if (valid) {
+        // 鍒ゆ柇鍙傛暟绫诲瀷锛屽彧鏈夋暟鍊肩被鍨嬫墠浼犳爣鍑嗗�笺�佹渶澶у�煎拰鏈�灏忓��
+        const isNumericMode = editParamForm.value.valueMode == 1;
+
+        // 璋冪敤API淇敼鍙傛暟
+        editProcessRouteItemParam({
+          id: editParamForm.value.id,
+          routeItemId: props.process.id,
+          paramId: editParamForm.value.paramId,
+          standardValue: isNumericMode
+            ? editParamForm.value.standardValue || ""
+            : "",
+          minValue: isNumericMode ? editParamForm.value.minValue || 0 : null,
+          maxValue: isNumericMode ? editParamForm.value.maxValue || 0 : null,
+          isRequired: editParamForm.value.isRequired || 0,
+        })
+          .then(res => {
+            if (res.code === 200) {
+              ElMessage.success("缂栬緫鎴愬姛");
+              editParamDialogVisible.value = false;
+              emit("refresh");
+            } else {
+              ElMessage.error(res.msg || "缂栬緫澶辫触");
+            }
+          })
+          .catch(err => {
+            ElMessage.error("缂栬緫鍙傛暟澶辫触");
+            console.error("缂栬緫鍙傛暟澶辫触锛�", err);
+          });
+      }
+    });
+  };
+
+  // 鑾峰彇鍙傛暟绫诲瀷鏍囩
+  const getParamTypeTag = type => {
+    const typeMap = {
+      1: "primary",
+      2: "info",
+      3: "warning",
+      4: "success",
+    };
+    return typeMap[type] || "default";
+  };
+
+  // 鑾峰彇鍙傛暟绫诲瀷鏂囨湰
+  const getParamTypeText = type => {
+    const typeMap = {
+      1: "鏁板�兼牸寮�",
+      2: "鏂囨湰鏍煎紡",
+      3: "涓嬫媺閫夐」",
+      4: "鏃堕棿鏍煎紡",
+    };
+    return typeMap[type] || type;
+  };
+
+  watch(
+    () => props.modelValue,
+    newVal => {
+      if (!newVal) {
+        // 寮圭獥鍏抽棴鏃堕噸缃暟鎹�
+        selectParamDialogVisible.value = false;
+        editParamDialogVisible.value = false;
+        selectedParam.value = null;
+        paramSearchKeyword.value = "";
+        paramPage.current = 1;
+        filteredParamList.value = [];
+        editParamForm.value = {
+          id: null,
+          processId: null,
+          paramId: null,
+          paramName: "",
+          valueMode: "1",
+          standardValue: null,
+          minValue: null,
+          maxValue: null,
+          sort: 1,
+          isRequired: 0,
+          paramType: null,
+          paramFormat: "",
+          unit: "",
+        };
+      }
+    }
+  );
+</script>
+
+<style scoped>
+  .param-list-container {
+    padding: 10px 0;
+  }
+
+  .params-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 15px;
+    padding-bottom: 10px;
+    border-bottom: 1px solid #e4e7ed;
+  }
+
+  .params-header span {
+    font-size: 16px;
+    font-weight: 500;
+    color: #303133;
+  }
+
+  .params-list {
+    max-height: 400px;
+    overflow-y: auto;
+  }
+
+  .param-item {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 12px 16px;
+    margin-bottom: 8px;
+    background-color: #f9f9f9;
+    border-radius: 4px;
+    transition: all 0.3s ease;
+  }
+
+  .param-item:hover {
+    background-color: #ecf5ff;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+  }
+
+  .param-info {
+    display: flex;
+    align-items: center;
+    gap: 20px;
+    flex: 1;
+  }
+
+  .param-code {
+    font-weight: 500;
+    color: #303133;
+    min-width: 120px;
+  }
+
+  .param-value {
+    color: #606266;
+    font-size: 14px;
+  }
+
+  .param-actions {
+    display: flex;
+    gap: 10px;
+  }
+
+  /* 婊氬姩鏉℃牱寮� */
+  .params-list::-webkit-scrollbar {
+    width: 6px;
+  }
+
+  .params-list::-webkit-scrollbar-track {
+    background: #f1f1f1;
+    border-radius: 3px;
+  }
+
+  .params-list::-webkit-scrollbar-thumb {
+    background: #c1c1c1;
+    border-radius: 3px;
+  }
+
+  .params-list::-webkit-scrollbar-thumb:hover {
+    background: #a8a8a8;
+  }
+
+  /* 閫夋嫨鍙傛暟瀵硅瘽妗嗘牱寮� */
+  .param-select-container {
+    display: flex;
+    gap: 20px;
+  }
+
+  .param-list-area {
+    flex: 1;
+    min-width: 400px;
+  }
+
+  .param-detail-area {
+    flex: 1;
+    min-width: 300px;
+  }
+
+  .area-title {
+    font-size: 14px;
+    font-weight: 500;
+    margin-bottom: 10px;
+    color: #303133;
+  }
+
+  .search-box {
+    display: flex;
+    gap: 10px;
+    margin-bottom: 10px;
+  }
+
+  .param-detail-form {
+    background: #f9f9f9;
+    padding: 15px;
+    border-radius: 4px;
+  }
+
+  .detail-text {
+    font-weight: 500;
+  }
+</style>
\ No newline at end of file
diff --git a/src/utils/dict.js b/src/utils/dict.js
index a6db068..e457c19 100644
--- a/src/utils/dict.js
+++ b/src/utils/dict.js
@@ -14,7 +14,7 @@
         res.value[dictType] = dicts
       } else {
         getDicts(dictType).then(resp => {
-          res.value[dictType] = resp.data.map(p => ({ label: p.dictLabel, value: p.dictValue, elTagType: p.listClass, elTagClass: p.cssClass }))
+          res.value[dictType] = resp.data.map(p => ({ label: p.dictLabel, value: p.dictValue,id: p.dictCode, elTagType: p.listClass, elTagClass: p.cssClass }))
           useDictStore().setDict(dictType, res.value[dictType])
         })
       }
diff --git a/src/views/productionManagement/processRoute/Edit.vue b/src/views/productionManagement/processRoute/Edit.vue
new file mode 100644
index 0000000..53d8395
--- /dev/null
+++ b/src/views/productionManagement/processRoute/Edit.vue
@@ -0,0 +1,257 @@
+<template>
+  <div>
+    <el-dialog v-model="isShow"
+               title="缂栬緫宸ヨ壓璺嚎"
+               width="400"
+               @close="closeModal">
+      <el-form label-width="140px"
+               :model="formState"
+               label-position="top"
+               ref="formRef">
+        <el-form-item label="浜у搧鍚嶇О"
+                      prop="productModelId"
+                      :rules="[
+                {
+                required: true,
+                message: '璇烽�夋嫨浜у搧',
+                trigger: 'change',
+              }
+            ]">
+          <el-button type="primary"
+                     @click="showProductSelectDialog = true">
+            {{ formState.productName && formState.productModelName 
+              ? `${formState.productName} - ${formState.productModelName}` 
+              : '閫夋嫨浜у搧' }}
+          </el-button>
+        </el-form-item>
+        <el-form-item label="BOM"
+                      prop="bomId"
+                      :rules="[
+                {
+                required: true,
+                message: '璇烽�夋嫨BOM',
+                trigger: 'change',
+              }
+            ]">
+          <el-select v-model="formState.bomId"
+                     placeholder="璇烽�夋嫨BOM"
+                     clearable
+                     :disabled="!formState.productModelId || bomOptions.length === 0"
+                     style="width: 100%">
+            <el-option v-for="item in bomOptions"
+                       :key="item.id"
+                       :label="item.bomNo || `BOM-${item.id}`"
+                       :value="item.id" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="澶囨敞"
+                      prop="description">
+          <el-input v-model="formState.description"
+                    type="textarea" />
+        </el-form-item>
+      </el-form>
+      <!-- 浜у搧閫夋嫨寮圭獥 -->
+      <ProductSelectDialog v-model="showProductSelectDialog"
+                           @confirm="handleProductSelect"
+                           single />
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary"
+                     @click="handleSubmit">纭</el-button>
+          <el-button @click="closeModal">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+  import {
+    ref,
+    computed,
+    getCurrentInstance,
+    onMounted,
+    nextTick,
+    watch,
+  } from "vue";
+  import { update } from "@/api/productionManagement/processRoute.js";
+  import { getByModel } from "@/api/productionManagement/productBom.js";
+  import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
+
+  const props = defineProps({
+    visible: {
+      type: Boolean,
+      required: true,
+    },
+
+    record: {
+      type: Object,
+      required: true,
+    },
+  });
+
+  const emit = defineEmits(["update:visible", "completed"]);
+
+  // 鍝嶅簲寮忔暟鎹紙鏇夸唬閫夐」寮忕殑 data锛�
+  const formState = ref({
+    productId: undefined,
+    productModelId: undefined,
+    productName: "",
+    productModelName: "",
+    bomId: undefined,
+    description: "",
+  });
+
+  const isShow = computed({
+    get() {
+      return props.visible;
+    },
+    set(val) {
+      emit("update:visible", val);
+    },
+  });
+
+  const showProductSelectDialog = ref(false);
+  const bomOptions = ref([]);
+
+  let { proxy } = getCurrentInstance();
+
+  const closeModal = () => {
+    isShow.value = false;
+  };
+
+  // 璁剧疆琛ㄥ崟鏁版嵁
+  const setFormData = () => {
+    if (props.record) {
+      formState.value = {
+        ...props.record,
+        productId: props.record.productId,
+        productModelId: props.record.productModelId,
+        productName: props.record.productName || "",
+        // 娉ㄦ剰锛歳ecord涓殑瀛楁鏄痬odel锛岄渶瑕佹槧灏勫埌productModelName
+        productModelName:
+          props.record.model || props.record.productModelName || "",
+        bomId: props.record.bomId,
+        description: props.record.description || "",
+      };
+      // 濡傛灉鏈変骇鍝佸瀷鍙稩D锛屽姞杞紹OM鍒楄〃
+      if (props.record.productModelId) {
+        loadBomList(props.record.productModelId);
+      }
+    }
+  };
+
+  // 鍔犺浇BOM鍒楄〃
+  const loadBomList = async productModelId => {
+    if (!productModelId) {
+      bomOptions.value = [];
+      return;
+    }
+    try {
+      const res = await getByModel(productModelId);
+      // 澶勭悊杩斿洖鐨凚OM鏁版嵁锛氬彲鑳芥槸鏁扮粍銆佸璞℃垨鍖呭惈data瀛楁
+      let bomList = [];
+      if (Array.isArray(res)) {
+        bomList = res;
+      } else if (res && res.data) {
+        bomList = Array.isArray(res.data) ? res.data : [res.data];
+      } else if (res && typeof res === "object") {
+        bomList = [res];
+      }
+      bomOptions.value = bomList;
+    } catch (error) {
+      console.error("鍔犺浇BOM鍒楄〃澶辫触锛�", error);
+      bomOptions.value = [];
+    }
+  };
+
+  // 浜у搧閫夋嫨澶勭悊
+  const handleProductSelect = async products => {
+    if (products && products.length > 0) {
+      const product = products[0];
+      // 鍏堟煡璇OM鍒楄〃锛堝繀閫夛級
+      try {
+        const res = await getByModel(product.id);
+        // 澶勭悊杩斿洖鐨凚OM鏁版嵁锛氬彲鑳芥槸鏁扮粍銆佸璞℃垨鍖呭惈data瀛楁
+        let bomList = [];
+        if (Array.isArray(res)) {
+          bomList = res;
+        } else if (res && res.data) {
+          bomList = Array.isArray(res.data) ? res.data : [res.data];
+        } else if (res && typeof res === "object") {
+          bomList = [res];
+        }
+
+        if (bomList.length > 0) {
+          formState.value.productModelId = product.id;
+          formState.value.productName = product.productName;
+          formState.value.productModelName = product.model;
+          // 濡傛灉褰撳墠閫夋嫨鐨凚OM涓嶅湪鏂板垪琛ㄤ腑锛屽垯閲嶇疆BOM閫夋嫨
+          const currentBomExists = bomList.some(
+            bom => bom.id === formState.value.bomId
+          );
+          if (!currentBomExists) {
+            formState.value.bomId = undefined;
+          }
+          bomOptions.value = bomList;
+          showProductSelectDialog.value = false;
+          // 瑙﹀彂琛ㄥ崟楠岃瘉鏇存柊
+          proxy.$refs["formRef"]?.validateField("productModelId");
+        } else {
+          proxy.$modal.msgError("璇ヤ骇鍝佹病鏈塀OM锛岃鍏堝垱寤築OM");
+        }
+      } catch (error) {
+        // 濡傛灉鎺ュ彛杩斿洖404鎴栧叾浠栭敊璇紝璇存槑娌℃湁BOM
+        proxy.$modal.msgError("璇ヤ骇鍝佹病鏈塀OM锛岃鍏堝垱寤築OM");
+      }
+    }
+  };
+
+  const handleSubmit = () => {
+    proxy.$refs["formRef"].validate(valid => {
+      if (valid) {
+        // 楠岃瘉鏄惁閫夋嫨浜嗕骇鍝佸拰BOM
+        if (!formState.value.productModelId) {
+          proxy.$modal.msgError("璇烽�夋嫨浜у搧");
+          return;
+        }
+        if (!formState.value.bomId) {
+          proxy.$modal.msgError("璇烽�夋嫨BOM");
+          return;
+        }
+        update(formState.value).then(res => {
+          // 鍏抽棴妯℃�佹
+          isShow.value = false;
+          // 鍛婄煡鐖剁粍浠跺凡瀹屾垚
+          emit("completed");
+          proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+        });
+      }
+    });
+  };
+
+  defineExpose({
+    closeModal,
+    handleSubmit,
+    isShow,
+  });
+
+  // 鐩戝惉寮圭獥鎵撳紑锛屽垵濮嬪寲琛ㄥ崟鏁版嵁
+  watch(
+    () => props.visible,
+    visible => {
+      if (visible && props.record) {
+        nextTick(() => {
+          setFormData();
+        });
+      }
+    },
+    { immediate: true }
+  );
+
+  onMounted(() => {
+    if (props.visible && props.record) {
+      setFormData();
+    }
+  });
+</script>
diff --git a/src/views/productionManagement/processRoute/ItemsForm.vue b/src/views/productionManagement/processRoute/ItemsForm.vue
new file mode 100644
index 0000000..ed6e499
--- /dev/null
+++ b/src/views/productionManagement/processRoute/ItemsForm.vue
@@ -0,0 +1,531 @@
+<template>
+  <div>
+    <el-dialog
+        v-model="isShow"
+        title="宸ヨ壓璺嚎椤圭洰"
+        width="800px"
+        @close="closeModal"
+    >
+      <div class="operate-button">
+        <el-button
+            type="primary"
+            @click="isShowProductSelectDialog = true"
+            class="mb5"
+            style="margin-bottom: 10px;"
+        >
+          閫夋嫨浜у搧
+        </el-button>
+
+        <el-switch
+            v-model="isTable"
+            inline-prompt
+            active-text="琛ㄦ牸"
+            inactive-text="鍒楄〃"
+            @change="handleViewChange"
+        />
+      </div>
+
+      <el-table
+          v-if="isTable"
+          ref="multipleTable"
+          v-loading="tableLoading"
+          border
+          :data="routeItems"
+          :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
+          row-key="id"
+          tooltip-effect="dark"
+          class="lims-table"
+          style="cursor: move;"
+      >
+        <el-table-column align="center" label="搴忓彿" width="60">
+          <template #default="scope">
+            {{ scope.$index + 1 }}
+          </template>
+        </el-table-column>
+
+        <el-table-column
+            v-for="(item, index) in tableColumn"
+            :key="index"
+            :label="item.label"
+            :width="item.width"
+            show-overflow-tooltip
+        >
+          <template #default="scope" v-if="item.dataType === 'action'">
+            <el-button
+                v-for="(op, opIndex) in item.operation"
+                :key="opIndex"
+                :type="op.type"
+                :link="op.link"
+                size="small"
+                @click.stop="op.clickFun(scope.row)"
+            >
+              {{ op.name }}
+            </el-button>
+          </template>
+
+          <template #default="scope" v-else>
+            <template v-if="item.prop === 'processId'">
+              <el-select
+                  v-model="scope.row[item.prop]"
+                  style="width: 100%;"
+                  @mousedown.stop
+              >
+                <el-option
+                    v-for="process in processOptions"
+                    :key="process.id"
+                    :label="process.name"
+                    :value="process.id"
+                />
+              </el-select>
+            </template>
+            <template v-else>
+              {{ scope.row[item.prop] || '-' }}
+            </template>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- 浣跨敤鏅�歞iv鏇夸唬el-steps -->
+      <div
+          v-else
+          ref="stepsContainer"
+          class="mb5 custom-steps"
+          style="padding: 10px 0; display: flex; flex-wrap: nowrap; gap: 20px; align-items: flex-start;"
+      >
+        <div
+            v-for="(item, index) in routeItems"
+            :key="item.id"
+            class="custom-step draggable-step"
+            :data-id="item.id"
+            style="cursor: move; flex: 0 0 auto; min-width: 220px;"
+        >
+          <div class="step-content">
+            <div class="step-number">{{ index + 1 }}</div>
+            <el-card
+                :header="item.productName"
+                class="step-card"
+                style="cursor: move;"
+            >
+              <div class="step-card-content">
+                <p>{{ item.model }}</p>
+                <p>{{ item.unit }}</p>
+                <el-select
+                    v-model="item.processId"
+                    style="width: 100%;"
+                    @mousedown.stop
+                >
+                  <el-option
+                      v-for="process in processOptions"
+                      :key="process.id"
+                      :label="process.name"
+                      :value="process.id"
+                  />
+                </el-select>
+              </div>
+              <template #footer>
+                <div class="step-card-footer">
+                  <el-button type="danger" link size="small" @click.stop="removeItemByID(item.id)">鍒犻櫎</el-button>
+                </div>
+              </template>
+            </el-card>
+          </div>
+        </div>
+      </div>
+
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="handleSubmit">纭</el-button>
+          <el-button @click="closeModal">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+
+    <ProductSelectDialog
+        v-model="isShowProductSelectDialog"
+        @confirm="handelSelectProducts"
+    />
+  </div>
+</template>
+
+<script setup>
+import { ref, computed, getCurrentInstance, onMounted, onUnmounted, nextTick } from "vue";
+import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
+import { findProcessRouteItemList, addOrUpdateProcessRouteItem } from "@/api/productionManagement/processRouteItem.js";
+import { processList } from "@/api/productionManagement/productionProcess.js";
+import Sortable from 'sortablejs';
+
+const props = defineProps({
+  visible: {
+    type: Boolean,
+    required: true,
+    default: false
+  },
+  record: {
+    type: Object,
+    required: true,
+    default: () => ({})
+  }
+});
+
+const emit = defineEmits(['update:visible', 'completed']);
+
+const processOptions = ref([]);
+const tableLoading = ref(false);
+const isShowProductSelectDialog = ref(false);
+const routeItems = ref([]);
+let tableSortable = null;
+let stepsSortable = null;
+const multipleTable = ref(null);
+const stepsContainer = ref(null);
+const isTable = ref(true);
+
+const isShow = computed({
+  get() {
+    return props.visible;
+  },
+  set(val) {
+    emit('update:visible', val);
+  }
+});
+
+const tableColumn = ref([
+  { label: "浜у搧鍚嶇О", prop: "productName", width: 180 },
+  { label: "瑙勬牸鍚嶇О", prop: "model", width: 150 },
+  { label: "鍗曚綅", prop: "unit", width: 80 },
+  { label: "宸ュ簭鍚嶇О", prop: "processId", width: 180 },
+  {
+    dataType: "action",
+    label: "鎿嶄綔",
+    align: "center",
+    fixed: "right",
+    width: 100,
+    operation: [
+      {
+        name: "鍒犻櫎",
+        type: "danger",
+        link: true,
+        clickFun: (row) => {
+          const idx = routeItems.value.findIndex(item => item.id === row.id);
+          if (idx > -1) {
+            removeItem(idx)
+          }
+        }
+      }
+    ]
+  }
+]);
+
+const removeItem = (index) => {
+  routeItems.value.splice(index, 1);
+  nextTick(() => initSortable());
+};
+
+const removeItemByID = (id) => {
+  const idx = routeItems.value.findIndex(item => item.id === id);
+  if (idx > -1) {
+    routeItems.value.splice(idx, 1);
+    nextTick(() => initSortable());
+  }
+};
+
+const closeModal = () => {
+  isShow.value = false;
+};
+
+const handelSelectProducts = (products) => {
+  destroySortable();
+
+  const newData = products.map(({ id, ...product }) => ({
+    ...product,
+    productModelId: id,
+    routeId: props.record.id,
+    id: `${Date.now()}-${Math.random().toString(36).slice(2)}`,
+    processId: undefined
+  }));
+
+  console.log('閫夋嫨浜у搧鍓嶆暟缁�:', routeItems.value);
+  routeItems.value.push(...newData);
+  routeItems.value = [...routeItems.value];
+  console.log('閫夋嫨浜у搧鍚庢暟缁�:', routeItems.value);
+
+  // 寤惰繜鍒濆鍖栵紝纭繚DOM瀹屽叏娓叉煋
+  nextTick(() => {
+    // 寮哄埗閲嶆柊娓叉煋缁勪欢
+    if (proxy?.$forceUpdate) {
+      proxy.$forceUpdate();
+    }
+
+    const temp = [...routeItems.value];
+    routeItems.value = [];
+    nextTick(() => {
+      routeItems.value = temp;
+      initSortable();
+    });
+  });
+};
+
+const findProcessRouteItems = () => {
+  tableLoading.value = true;
+  findProcessRouteItemList({ routeId: props.record.id })
+      .then(res => {
+        tableLoading.value = false;
+        routeItems.value = res.data.map(item => ({
+          ...item,
+          processId: item.processId === 0 ? undefined : item.processId
+        }));
+        // 寤惰繜鍒濆鍖栵紝纭繚DOM瀹屽叏娓叉煋
+        nextTick(() => {
+          setTimeout(() => initSortable(), 100);
+        });
+      })
+      .catch(err => {
+        tableLoading.value = false;
+        console.error("鑾峰彇鍒楄〃澶辫触锛�", err);
+      });
+};
+
+const findProcessList = () => {
+  processList({})
+      .then(res => {
+        processOptions.value = res.data;
+      })
+      .catch(err => {
+        console.error("鑾峰彇宸ュ簭澶辫触锛�", err);
+      });
+};
+
+const { proxy } = getCurrentInstance() || {};
+
+const handleSubmit = () => {
+  const hasEmptyProcess = routeItems.value.some(item => !item.processId);
+  if (hasEmptyProcess) {
+    proxy?.$modal?.msgError("璇蜂负鎵�鏈夐」鐩�夋嫨宸ュ簭");
+    return;
+  }
+
+  addOrUpdateProcessRouteItem({
+    routeId: props.record.id,
+    processRouteItem: routeItems.value.map(({ id, ...item }) => item)
+  })
+      .then(res => {
+        isShow.value = false;
+        emit('completed');
+        proxy?.$modal?.msgSuccess("鎻愪氦鎴愬姛");
+      })
+      .catch(err => {
+        proxy?.$modal?.msgError(`鎻愪氦澶辫触锛�${err.msg || "缃戠粶寮傚父"}`);
+      });
+};
+
+const destroySortable = () => {
+  if (tableSortable) {
+    tableSortable.destroy();
+    tableSortable = null;
+  }
+  if (stepsSortable) {
+    stepsSortable.destroy();
+    stepsSortable = null;
+  }
+};
+
+const initSortable = () => {
+  destroySortable();
+
+  if (isTable.value) {
+    if (!multipleTable.value) return;
+    const tbody = multipleTable.value.$el.querySelector('.el-table__body tbody') ||
+        multipleTable.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 || !routeItems.value[evt.oldIndex]) return;
+
+        // 浣跨敤鏁扮粍 splice 鏂规硶閲嶆柊鎺掑簭锛屼笌琛ㄦ牸妯″紡淇濇寔涓�鑷�
+        const moveItem = routeItems.value.splice(evt.oldIndex, 1)[0];
+        routeItems.value.splice(evt.newIndex, 0, moveItem);
+        routeItems.value = [...routeItems.value];
+        console.log('鎺掑簭鍚庢暟缁�:', routeItems.value);
+      }
+    });
+  } else {
+    if (!stepsContainer.value) return;
+
+    // 淇敼锛氱洿鎺ヤ娇鐢╯tepsContainer.value浣滀负鎷栨嫿瀹瑰櫒
+    const stepsList = stepsContainer.value;
+    if (!stepsList) {
+      console.warn('鏈壘鍒版楠ゆ潯鎷栨嫿瀹瑰櫒');
+      return;
+    }
+
+    // 淇敼锛氱畝鍖栨嫋鎷介厤缃�
+    stepsSortable = new Sortable(stepsList, {
+      animation: 150,
+      ghostClass: 'sortable-ghost',
+      draggable: '.draggable-step', // 鍙嫋鎷藉厓绱�
+      handle: '.draggable-step, .step-card', // 鎷栨嫿鎵嬫焺
+      filter: '.el-button, .el-select, .el-input', // 杩囨护鎸夐挳/閫夋嫨鍣�
+      forceFallback: true,
+      fallbackClass: 'sortable-fallback',
+      preventOnFilter: true,
+      scroll: true,
+      scrollSensitivity: 30,
+      scrollSpeed: 10,
+      bubbleScroll: true,
+      onEnd: (evt) => {
+        if (evt.oldIndex === evt.newIndex || !routeItems.value[evt.oldIndex]) return;
+
+        // 浣跨敤鏁扮粍 splice 鏂规硶閲嶆柊鎺掑簭
+        const moveItem = routeItems.value.splice(evt.oldIndex, 1)[0];
+        routeItems.value.splice(evt.newIndex, 0, moveItem);
+        routeItems.value = [...routeItems.value];
+      }
+    });
+
+    // 璋冭瘯锛氭墦鍗板鍣ㄥ拰瀹炰緥锛岀‘璁ょ粦瀹氭垚鍔�
+    console.log('姝ラ鏉℃嫋鎷藉鍣�:', stepsList);
+    console.log('Sortable瀹炰緥:', stepsSortable);
+  }
+};
+
+const handleViewChange = () => {
+  destroySortable();
+  // 寤惰繜鍒濆鍖栵紝纭繚瑙嗗浘鍒囨崲鍚嶥OM瀹屽叏娓叉煋
+  nextTick(() => {
+    setTimeout(() => initSortable(), 100);
+  });
+};
+
+onMounted(() => {
+  findProcessRouteItems();
+  findProcessList();
+});
+
+onUnmounted(() => {
+  destroySortable();
+});
+
+defineExpose({
+  closeModal,
+  handleSubmit,
+  isShow
+});
+</script>
+
+<style scoped>
+:deep(.sortable-ghost) {
+  opacity: 0.6;
+  background-color: #f5f7fa !important;
+}
+
+:deep(.el-table__row) {
+  transition: background-color 0.2s;
+}
+
+:deep(.el-table__row:hover) {
+  background-color: #f9fafc !important;
+}
+
+:deep(.el-card__footer){
+  padding: 0 !important;
+}
+
+.operate-button {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+
+/* 淇敼锛氳嚜瀹氫箟姝ラ鏉″鍣ㄦ牱寮� */
+.custom-steps {
+  display: flex;
+  flex-wrap: wrap;
+  align-items: flex-start;
+  gap: 20px;
+  min-height: 100px;
+}
+
+/* 淇敼锛氳嚜瀹氫箟姝ラ椤规牱寮� */
+.custom-step {
+  cursor: move !important;
+  padding: 8px;
+  position: relative;
+  transition: all 0.2s ease;
+  flex: 0 0 auto;
+  min-width: 220px;
+  touch-action: none;
+}
+
+/* 鎷栨嫿鎮诞鏍峰紡锛屾彁绀哄彲鎷栨嫿 */
+.custom-step:hover {
+  background-color: rgba(64, 158, 255, 0.05);
+  transform: translateY(-2px);
+}
+
+.sortable-ghost {
+  opacity: 0.4;
+  background-color: #f5f7fa !important;
+  border: 2px dashed #409eff;
+  margin: 10px;
+  transform: scale(1.02);
+}
+
+.sortable-fallback {
+  opacity: 0.9;
+  background-color: #f5f7fa;
+  border: 1px solid #409eff;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+  transform: rotate(2deg);
+  margin: 10px;
+}
+
+.step-card {
+  cursor: move !important;
+  transition: box-shadow 0.2s ease;
+  user-select: none;
+  -webkit-user-select: none;
+  pointer-events: auto;
+  margin: 10px;
+  height: 240px;
+}
+
+.step-card:hover {
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+}
+
+.step-content {
+  width: 220px;
+  user-select: none;
+}
+
+.step-card-content {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+
+.step-card-footer {
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+  padding: 10px;
+}
+
+/* 鑷畾涔夊簭鍙锋牱寮忎紭鍖� */
+.step-number {
+  font-weight: bold;
+  text-align: center;
+  width: 36px;
+  height: 36px;
+  line-height: 36px;
+  margin: 0 auto 10px;
+  background: #409eff;
+  color: #fff;
+  border-radius: 50%;
+  font-size: 14px;
+}
+</style>
diff --git a/src/views/productionManagement/processRoute/New.vue b/src/views/productionManagement/processRoute/New.vue
new file mode 100644
index 0000000..62c6873
--- /dev/null
+++ b/src/views/productionManagement/processRoute/New.vue
@@ -0,0 +1,194 @@
+<template>
+  <div>
+    <el-dialog
+        v-model="isShow"
+        title="鏂板宸ヨ壓璺嚎"
+        width="400"
+        @close="closeModal"
+    >
+      <el-form label-width="140px" :model="formState" label-position="top" ref="formRef">
+        <el-form-item
+            label="浜у搧鍚嶇О"
+            prop="productModelId"
+            :rules="[
+                {
+                required: true,
+                message: '璇烽�夋嫨浜у搧',
+                trigger: 'change',
+              }
+            ]"
+        >
+          <el-button type="primary" @click="showProductSelectDialog = true">
+            {{ formState.productName && formState.productModelName 
+              ? `${formState.productName} - ${formState.productModelName}` 
+              : '閫夋嫨浜у搧' }}
+          </el-button>
+        </el-form-item>
+
+        <el-form-item
+            label="BOM"
+            prop="bomId"
+            :rules="[
+                {
+                required: true,
+                message: '璇烽�夋嫨BOM',
+                trigger: 'change',
+              }
+            ]"
+        >
+          <el-select
+              v-model="formState.bomId"
+              placeholder="璇烽�夋嫨BOM"
+              clearable
+              :disabled="!formState.productModelId || bomOptions.length === 0"
+              style="width: 100%"
+          >
+            <el-option
+                v-for="item in bomOptions"
+                :key="item.id"
+                :label="item.bomNo || `BOM-${item.id}`"
+                :value="item.id"
+            />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="澶囨敞" prop="description">
+          <el-input v-model="formState.description" type="textarea" />
+        </el-form-item>
+      </el-form>
+      
+      <!-- 浜у搧閫夋嫨寮圭獥 -->
+      <ProductSelectDialog
+          v-model="showProductSelectDialog"
+          @confirm="handleProductSelect"
+          single
+      />
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="handleSubmit">纭</el-button>
+          <el-button @click="closeModal">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import {ref, computed, getCurrentInstance} from "vue";
+import {add} from "@/api/productionManagement/processRoute.js";
+import {getByModel} from "@/api/productionManagement/productBom.js";
+import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
+
+const props = defineProps({
+  visible: {
+    type: Boolean,
+    required: true,
+  },
+});
+
+const emit = defineEmits(['update:visible', 'completed']);
+
+// 鍝嶅簲寮忔暟鎹紙鏇夸唬閫夐」寮忕殑 data锛�
+const formState = ref({
+  productId: undefined,
+  productModelId: undefined,
+  productName: "",
+  productModelName: "",
+  bomId: undefined,
+  description: '',
+});
+
+const isShow = computed({
+  get() {
+    return props.visible;
+  },
+  set(val) {
+    emit('update:visible', val);
+  },
+});
+
+const showProductSelectDialog = ref(false);
+const bomOptions = ref([]);
+
+let { proxy } = getCurrentInstance()
+
+const closeModal = () => {
+  // 閲嶇疆琛ㄥ崟鏁版嵁
+  formState.value = {
+    productId: undefined,
+    productModelId: undefined,
+    productName: "",
+    productModelName: "",
+    bomId: undefined,
+    description: '',
+  };
+  bomOptions.value = [];
+  isShow.value = false;
+};
+
+// 浜у搧閫夋嫨澶勭悊
+const handleProductSelect = async (products) => {
+  if (products && products.length > 0) {
+    const product = products[0];
+    // 鍏堟煡璇OM鍒楄〃锛堝繀閫夛級
+    try {
+      const res = await getByModel(product.id);
+      // 澶勭悊杩斿洖鐨凚OM鏁版嵁锛氬彲鑳芥槸鏁扮粍銆佸璞℃垨鍖呭惈data瀛楁
+      let bomList = [];
+      if (Array.isArray(res)) {
+        bomList = res;
+      } else if (res && res.data) {
+        bomList = Array.isArray(res.data) ? res.data : [res.data];
+      } else if (res && typeof res === 'object') {
+        bomList = [res];
+      }
+      
+      if (bomList.length > 0) {
+        formState.value.productModelId = product.id;
+        formState.value.productName = product.productName;
+        formState.value.productModelName = product.model;
+        formState.value.bomId = undefined; // 閲嶇疆BOM閫夋嫨
+        bomOptions.value = bomList;
+        showProductSelectDialog.value = false;
+        // 瑙﹀彂琛ㄥ崟楠岃瘉鏇存柊
+        proxy.$refs["formRef"]?.validateField('productModelId');
+      } else {
+        proxy.$modal.msgError("璇ヤ骇鍝佹病鏈塀OM锛岃鍏堝垱寤築OM");
+      }
+    } catch (error) {
+      // 濡傛灉鎺ュ彛杩斿洖404鎴栧叾浠栭敊璇紝璇存槑娌℃湁BOM
+      proxy.$modal.msgError("璇ヤ骇鍝佹病鏈塀OM锛岃鍏堝垱寤築OM");
+    }
+  }
+};
+
+const handleSubmit = () => {
+  proxy.$refs["formRef"].validate(valid => {
+    if (valid) {
+      // 楠岃瘉鏄惁閫夋嫨浜嗕骇鍝佸拰BOM
+      if (!formState.value.productModelId) {
+        proxy.$modal.msgError("璇烽�夋嫨浜у搧");
+        return;
+      }
+      if (!formState.value.bomId) {
+        proxy.$modal.msgError("璇烽�夋嫨BOM");
+        return;
+      }
+      add(formState.value).then(res => {
+        // 鍏抽棴妯℃�佹
+        isShow.value = false;
+        // 鍛婄煡鐖剁粍浠跺凡瀹屾垚
+        emit('completed');
+        proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+      })
+    }
+  })
+};
+
+
+defineExpose({
+  closeModal,
+  handleSubmit,
+  isShow,
+});
+</script>
diff --git a/src/views/productionManagement/processRoute/index.vue b/src/views/productionManagement/processRoute/index.vue
index 40ab129..83d789e 100644
--- a/src/views/productionManagement/processRoute/index.vue
+++ b/src/views/productionManagement/processRoute/index.vue
@@ -1,1201 +1,232 @@
 <template>
   <div class="app-container">
-    <div class="route-header">
-      <div class="add-route-btn"
-           @click="handleAddRoute">
-        <el-icon>
-          <Plus />
-        </el-icon>
-        <span>鏂板宸ヨ壓璺嚎</span>
-      </div>
+    <div class="search_form">
+      <el-form :model="searchForm"
+               :inline="true">
+        <el-form-item label="瑙勬牸鍚嶇О:">
+          <el-input v-model="searchForm.model"
+                    placeholder="璇疯緭鍏�"
+                    clearable
+                    prefix-icon="Search"
+                    style="width: 200px;"
+                    @change="handleQuery" />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary"
+                     @click="handleQuery">鎼滅储</el-button>
+        </el-form-item>
+      </el-form>
     </div>
-    <div class="route-card-list">
-      <div v-for="route in routeList"
-           :key="route.id"
-           class="route-card">
-        <div class="card-header">
-          <div class="route-info">
-            <span class="route-name"><el-icon style="margin-right: 8px;line-height: 30px;">
-                <ScaleToOriginal />
-              </el-icon>{{route.routeCode }}<el-tag style="margin-left: 8px"
-                      :type="!route.status ? 'warning' : 'success'">{{ !route.status ? '鑽夌' : '鎵瑰噯' }}</el-tag></span>
-            <!-- <span class="route-code">{{ route.routeCode }}</span> -->
-          </div>
-          <div class="route-actions">
-            <el-button v-if="!route.status"
-                       link
-                       type="success"
-                       @click="handleApproveRoute(route)">
-              <el-icon>
-                <Check />
-              </el-icon>
-              鎵瑰噯
-            </el-button>
-            <el-button v-if="route.status"
-                       link
-                       type="warning"
-                       @click="handleRevokeApproveRoute(route)">
-              <el-icon>
-                <Close />
-              </el-icon>
-              鎾ら攢鎵瑰噯
-            </el-button>
-            <el-button link
-                       type="primary"
-                       @click="handleEditRoute(route)">
-              <el-icon>
-                <Edit />
-              </el-icon>
-              缂栬緫
-            </el-button>
-            <el-button link
-                       type="danger"
-                       @click="handleDeleteRoute(route)">
-              <el-icon>
-                <Delete />
-              </el-icon>
-              鍒犻櫎
-            </el-button>
-          </div>
-        </div>
-        <div class="card-body">
-          <div class="route-meta">
-            <span class="meta-item">
-              <el-icon>
-                <Box />
-              </el-icon>
-              <span class="meta-label">浜у搧:</span>
-              <span class="meta-value">{{ route.productName }} - {{ route.productModelName }}</span>
-            </span>
-            <span class="meta-item">
-              <el-icon>
-                <Document />
-              </el-icon>
-              <span class="meta-label">BOM:</span>
-              <span class="meta-value">{{ route.bomNo || '-' }}</span>
-            </span>
-            <span class="meta-item">
-              <el-icon>
-                <Document />
-              </el-icon>
-              <span class="meta-label">澶囨敞:</span>
-              <span class="meta-value">{{ route.description || '鏆傛棤鎻忚堪' }}</span>
-            </span>
-          </div>
-          <div class="expand-btn-wrapper">
-            <el-button class="expand-btn"
-                       :class="{ expanded: route.expanded }"
-                       type="primary"
-                       text
-                       @click="toggleExpand(route)">
-              <span class="btn-text">{{ route.expanded ? '鏀惰捣宸ュ簭璺嚎' : '灞曞紑宸ュ簭璺嚎' }}</span>
-              <el-icon class="expand-icon">
-                <component :is="route.expanded ? 'ArrowUp' : 'ArrowDown'" />
-              </el-icon>
-            </el-button>
-          </div>
-        </div>
-        <div v-if="route.expanded"
-             class="process-route">
-          <div class="process-flow">
-            <div v-for="(process, index) in route.processList"
-                 :key="process.id"
-                 class="process-flow-item"
-                 draggable="true"
-                 @dragstart="handleDragStart($event, index, route.id)"
-                 @dragover="handleDragOver($event)"
-                 @drop="handleDrop($event, index, route.id)"
-                 @dragend="handleDragEnd">
-              <div class="process-node"
-                   :class="{ expanded: process.expanded }">
-                <div class="process-node-header">
-                  <div class="process-number">{{ index + 1 }}</div>
-                  <div class="process-actions">
-                    <el-button link
-                               type="primary"
-                               @click="handleEditProcessSelect(route, index, process)">
-                      <el-icon>
-                        <Edit />
-                      </el-icon>
-                    </el-button>
-                    <el-button link
-                               type="danger"
-                               @click="handleDeleteProcess(route.id, process)">
-                      <el-icon>
-                        <Delete />
-                      </el-icon>
-                    </el-button>
-                  </div>
-                </div>
-                <div class="process-node-body">
-                  <!-- <div class="process-code">{{ process.processId }}</div> -->
-                  <div class="process-name">{{ process.processName }}</div>
-                  <!-- <div class="process-desc">{{ process.remark || '鏆傛棤鎻忚堪' }}</div> -->
-                </div>
-                <div class="process-node-footer">
-                  <!-- <el-tag size="small"
-                          :type="process.status === '1' ? 'success' : 'info'">
-                    {{ process.status === '1' ? '鍚敤' : '鍋滅敤' }}
-                  </el-tag> -->
-                  <el-button type="primary"
-                             link
-                             size="small"
-                             @click="toggleProcessParams(process)">
-                    {{ process.expanded ? '鏀惰捣鍙傛暟' : '灞曞紑鍙傛暟' }}
-                    ({{ process.paramCount }})
-                  </el-button>
-                </div>
-                <div v-if="process.expanded"
-                     class="process-params-section">
-                  <div class="params-header">
-                    <span>鍙傛暟鍒楄〃</span>
-                    <el-button type="primary"
-                               link
-                               size="small"
-                               @click="handleAddParam(route.id, process)">
-                      <el-icon>
-                        <Plus />
-                      </el-icon>鏂板
-                    </el-button>
-                  </div>
-                  <div class="params-list">
-                    <div v-for="param in process.paramList"
-                         :key="param.id"
-                         class="param-item">
-                      <div class="param-info">
-                        <span class="param-code">{{ param.paramName }}</span>
-                        <!-- <span class="param-name">{{ param.paramName }}</span> -->
-                        <!-- <el-tag size="small"
-                                style="margin-right: 20px;"
-                                :type="getParamTypeTag(param.parameterType)">
-                          {{ param.parameterType }}
-                        </el-tag> -->
-                        <span v-if="param.valueMode==1"
-                              class="param-value">鏍囧噯鍊硷細{{ param.standardValue || "-" }} {{ param.unit }}</span>
-                        <span v-else
-                              class="param-value">鏍囧噯鍊硷細{{ param.minValue || "-" }}-{{ param.maxValue || "-" }} {{ param.unit }}</span>
-                      </div>
-                      <div class="param-actions">
-                        <el-button link
-                                   type="primary"
-                                   size="small"
-                                   @click="handleEditParam(route.id, process, param)">
-                          缂栬緫
-                        </el-button>
-                        <el-button link
-                                   type="danger"
-                                   size="small"
-                                   @click="handleDeleteParam(route.id, process, param)">
-                          鍒犻櫎
-                        </el-button>
-                      </div>
-                    </div>
-                    <el-empty v-if="!process.paramList || process.paramList.length === 0"
-                              description="鏆傛棤鍙傛暟"
-                              :image-size="50" />
-                  </div>
-                </div>
-              </div>
-              <div v-if="index < route.processList.length - 1"
-                   class="flow-arrow">
-                <el-icon>
-                  <Right />
-                </el-icon>
-              </div>
-            </div>
-            <div class="add-process-node"
-                 @click="handleSelectProcess(route, index)">
-              <el-icon>
-                <Plus />
-              </el-icon>
-              <span>鏂板宸ュ簭</span>
-            </div>
-          </div>
-        </div>
+    <div class="table_list">
+      <div style="text-align: right"
+           class="mb10">
+        <el-button type="primary"
+                   @click="showNewModal">鏂板宸ヨ壓璺嚎</el-button>
+        <el-button type="danger"
+                   @click="handleDelete"
+                   :disabled="selectedRows.length === 0"
+                   plain>鍒犻櫎宸ヨ壓璺嚎</el-button>
       </div>
+      <PIMTable rowKey="id"
+                :column="tableColumn"
+                :tableData="tableData"
+                :page="page"
+                :isSelection="true"
+                @selection-change="handleSelectionChange"
+                :tableLoading="tableLoading"
+                @pagination="pagination"
+                :total="page.total" />
     </div>
-    <!-- 鍒嗛〉鎺т欢 -->
-    <div class="pagination-container">
-      <el-pagination v-model:current-page="routePage.current"
-                     v-model:page-size="routePage.size"
-                     :page-sizes="[10, 20, 50, 100]"
-                     layout="total, sizes, prev, pager, next, jumper"
-                     :total="routePage.total"
-                     @size-change="handleRouteSizeChange"
-                     @current-change="handleRouteCurrentChange" />
-    </div>
-    <!-- 宸ヨ壓璺嚎鏂板/缂栬緫瀵硅瘽妗� -->
-    <el-dialog v-model="routeDialogVisible"
-               :title="isRouteEdit ? '缂栬緫宸ヨ壓璺嚎' : '鏂板宸ヨ壓璺嚎'"
-               width="500px">
-      <el-form :model="routeForm"
-               :rules="routeRules"
-               ref="routeFormRef"
-               label-width="120px">
-        <el-form-item label="浜у搧鍚嶇О"
-                      prop="productModelId">
-          <el-button type="primary"
-                     @click="handleProcessProductSelectClick2">
-            {{ routeForm.productName && routeForm.productModelName 
-              ? `${routeForm.productName} - ${routeForm.productModelName}` 
-              : '閫夋嫨浜у搧' }}
-          </el-button>
-        </el-form-item>
-        <el-form-item label="BOM"
-                      prop="bomId">
-          <el-select v-model="routeForm.bomId"
-                     placeholder="璇烽�夋嫨BOM"
-                     clearable
-                     :disabled="!routeForm.productModelId || bomOptions.length === 0"
-                     style="width: 100%">
-            <el-option v-for="item in bomOptions"
-                       :key="item.id"
-                       :label="item.bomNo || `BOM-${item.id}`"
-                       :value="item.id" />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="璺嚎缂栫爜"
-                      prop="routeCode">
-          <el-input v-model="routeForm.routeCode"
-                    disabled
-                    placeholder="鑷姩鐢熸垚" />
-        </el-form-item>
-        <el-form-item label="澶囨敞"
-                      prop="description">
-          <el-input v-model="routeForm.description"
-                    type="textarea"
-                    :rows="3"
-                    placeholder="璇疯緭鍏ヨ矾绾挎弿杩�" />
-        </el-form-item>
-        <!-- <el-form-item label="鐘舵��"
-                      prop="status">
-          <el-radio-group v-model="routeForm.status">
-            <el-radio label="1">鍚敤</el-radio>
-            <el-radio label="0">鍋滅敤</el-radio>
-          </el-radio-group>
-        </el-form-item> -->
-      </el-form>
-      <template #footer>
-        <span class="dialog-footer">
-          <el-button @click="routeDialogVisible = false">鍙栨秷</el-button>
-          <el-button type="primary"
-                     @click="handleRouteSubmit">纭畾</el-button>
-        </span>
-      </template>
-    </el-dialog>
-    <!-- 浜у搧閫夋嫨寮圭獥 -->
-    <ProductSelectDialog v-model="showProductSelectDialog"
-                         @confirm="handleProductSelect"
-                         single />
-    <!-- 宸ュ簭鏂板/缂栬緫瀵硅瘽妗� -->
-    <el-dialog v-model="processDialogVisible"
-               :title="isProcessEdit ? '缂栬緫宸ュ簭' : '鏂板宸ュ簭'"
-               width="500px">
-      <el-form :model="processForm"
-               :rules="processRules"
-               ref="processFormRef"
-               label-width="120px">
-        <el-form-item label="宸ュ簭缂栫爜"
-                      prop="no">
-          <el-input v-model="processForm.no"
-                    placeholder="璇疯緭鍏ュ伐搴忕紪鐮�" />
-        </el-form-item>
-        <el-form-item label="宸ュ簭鍚嶇О"
-                      prop="name">
-          <el-input v-model="processForm.name"
-                    placeholder="璇疯緭鍏ュ伐搴忓悕绉�" />
-        </el-form-item>
-        <el-form-item label="宸ュ簭鎻忚堪"
-                      prop="remark">
-          <el-input v-model="processForm.remark"
-                    type="textarea"
-                    :rows="3"
-                    placeholder="璇疯緭鍏ュ伐搴忔弿杩�" />
-        </el-form-item>
-        <el-form-item label="鐘舵��"
-                      prop="status">
-          <el-radio-group v-model="processForm.status">
-            <el-radio :label="true">鍚敤</el-radio>
-            <el-radio :label="false">鍋滅敤</el-radio>
-          </el-radio-group>
-        </el-form-item>
-      </el-form>
-      <template #footer>
-        <span class="dialog-footer">
-          <el-button @click="processDialogVisible = false">鍙栨秷</el-button>
-          <el-button type="primary"
-                     @click="handleProcessSubmit">纭畾</el-button>
-        </span>
-      </template>
-    </el-dialog>
-    <!-- 閫夋嫨宸ュ簭瀵硅瘽妗� -->
-    <el-dialog v-model="selectProcessDialogVisible"
-               title="閫夋嫨宸ュ簭"
-               width="1000px">
-      <div class="process-select-container">
-        <!-- 宸︿晶宸ュ簭鍒楄〃 -->
-        <div class="process-list-area">
-          <div class="area-title">鍙�夊伐搴�</div>
-          <div class="search-box">
-            <el-input v-model="processSearchKeyword"
-                      placeholder="璇疯緭鍏ュ伐搴忓悕绉版悳绱�"
-                      clearable
-                      size="small"
-                      @input="handleProcessSearch">
-              <template #prefix>
-                <el-icon>
-                  <Search />
-                </el-icon>
-              </template>
-            </el-input>
-          </div>
-          <el-table :data="filteredProcessList"
-                    height="360"
-                    border
-                    highlight-current-row
-                    @current-change="handleProcessSelect">
-            <el-table-column prop="no"
-                             label="宸ュ簭缂栧彿"
-                             width="100" />
-            <el-table-column prop="name"
-                             label="宸ュ簭鍚嶇О" />
-            <el-table-column prop="remark"
-                             label="宸ュ簭鎻忚堪" />
-            <el-table-column prop="status"
-                             label="鐘舵��"
-                             width="80">
-              <template #default="scope">
-                <el-tag size="small"
-                        :type="scope.row.status ? 'success' : 'info'">
-                  {{ scope.row.status ? '鍚敤' : '鍋滅敤' }}
-                </el-tag>
-              </template>
-            </el-table-column>
-          </el-table>
-        </div>
-        <!-- 鍙充晶宸ュ簭璇︽儏 -->
-        <div class="process-detail-area">
-          <div class="area-title">宸ュ簭璇︽儏</div>
-          <el-form v-if="selectedProcessItem"
-                   :model="processForm"
-                   label-width="100px"
-                   class="process-detail-form">
-            <el-form-item label="宸ュ簭缂栧彿">
-              <span class="detail-text">{{ selectedProcessItem.no }}</span>
-            </el-form-item>
-            <el-form-item label="宸ュ簭鍚嶇О">
-              <span class="detail-text">{{ selectedProcessItem.name }}</span>
-            </el-form-item>
-            <el-form-item label="宸ュ簭鎻忚堪">
-              <span class="detail-text">{{ selectedProcessItem.remark || '-' }}</span>
-            </el-form-item>
-            <el-form-item label="鐘舵��">
-              <el-tag size="small"
-                      :type="selectedProcessItem.status ? 'success' : 'info'">
-                {{ selectedProcessItem.status ? '鍚敤' : '鍋滅敤' }}
-              </el-tag>
-            </el-form-item>
-            <el-form-item label="鏄惁璐ㄦ">
-              <el-tag size="small"
-                      :type="selectedProcessItem.isQuality ? 'success' : 'info'">
-                {{ selectedProcessItem.isQuality ? '璐ㄦ' : '闈炶川妫�' }}
-              </el-tag>
-            </el-form-item>
-            <el-form-item label="浜у搧鍚嶇О"
-                          prop="productModelId">
-              <el-button type="primary"
-                         @click="handleProcessProductSelectClick">
-                {{ processForm.productName && processForm.model 
-                  ? `${processForm.productName} - ${processForm.model}` 
-                  : '閫夋嫨浜у搧' }}
-              </el-button>
-            </el-form-item>
-            <el-form-item label="鍗曚綅"
-                          prop="unit">
-              <el-input v-model="processForm.unit"
-                        :placeholder="processForm.productModelId ? '鏍规嵁閫夋嫨鐨勪骇鍝佽嚜鍔ㄥ甫鍑�' : '璇峰厛閫夋嫨浜у搧' "
-                        clearable
-                        :disabled="true" />
-            </el-form-item>
-            <el-form-item label="鏄惁璐ㄦ"
-                          prop="isQuality">
-              <el-switch v-model="processForm.isQuality"
-                         :active-value="true"
-                         inactive-value="false" />
-            </el-form-item>
-          </el-form>
-          <el-empty v-else
-                    description="璇蜂粠宸︿晶閫夋嫨宸ュ簭" />
-        </div>
-      </div>
-      <template #footer>
-        <span class="dialog-footer">
-          <el-button @click="selectProcessDialogVisible = false">鍙栨秷</el-button>
-          <el-button type="primary"
-                     :disabled="!selectedProcessItem || !processForm.productModelId"
-                     @click="handleProcessSelectSubmit">纭畾</el-button>
-        </span>
-      </template>
-    </el-dialog>
-    <!-- 鍙傛暟鏂板/缂栬緫瀵硅瘽妗� -->
-    <el-dialog v-model="paramDialogVisible"
-               :title="isParamEdit ? '缂栬緫鍙傛暟' : '鏂板鍙傛暟'"
-               width="500px">
-      <el-form :model="paramForm"
-               :rules="paramRules"
-               ref="paramFormRef"
-               label-width="120px">
-        <el-form-item label="鍙傛暟缂栧彿"
-                      prop="parameterCode">
-          <el-input v-model="paramForm.parameterCode"
-                    placeholder="璇疯緭鍏ュ弬鏁扮紪鍙�" />
-        </el-form-item>
-        <el-form-item label="鍙傛暟鍚嶇О"
-                      prop="parameterName">
-          <el-input v-model="paramForm.parameterName"
-                    placeholder="璇疯緭鍏ュ弬鏁板悕绉�" />
-        </el-form-item>
-        <el-form-item label="鍙傛暟妯″紡"
-                      prop="parameterType2">
-          <el-select v-model="paramForm.parameterType2"
-                     placeholder="璇烽�夋嫨鍙傛暟妯″紡">
-            <el-option label="鍗曞��"
-                       value="1" />
-            <el-option label="鍖洪棿"
-                       value="2" />
-          </el-select>
-        </el-form-item>
-        <el-form-item label="鍙傛暟绫诲瀷"
-                      prop="parameterType">
-          <el-select v-model="paramForm.parameterType"
-                     @change="handleParamTypeChange"
-                     placeholder="璇烽�夋嫨鍙傛暟绫诲瀷">
-            <el-option label="鏁板�兼牸寮�"
-                       value="鏁板�兼牸寮�" />
-            <el-option label="鏂囨湰鏍煎紡"
-                       value="鏂囨湰鏍煎紡" />
-            <el-option label="涓嬫媺閫夐」"
-                       value="涓嬫媺閫夐」" />
-            <el-option label="鏃堕棿鏍煎紡"
-                       value="鏃堕棿鏍煎紡" />
-          </el-select>
-        </el-form-item>
-        <el-form-item v-if="paramForm.parameterType === '涓嬫媺閫夐」'"
-                      label="鏁版嵁瀛楀吀"
-                      prop="parameterFormat">
-          <el-select v-model="paramForm.parameterFormat"
-                     placeholder="璇烽�夋嫨鏁版嵁瀛楀吀">
-            <el-option v-for="item in dictTypes"
-                       :key="item.dictType"
-                       :label="item.dictName"
-                       :value="item.dictType" />
-          </el-select>
-        </el-form-item>
-        <el-form-item v-else-if="paramForm.parameterType === '鏃堕棿鏍煎紡'"
-                      label="鏃堕棿鏍煎紡"
-                      prop="parameterFormat">
-          <el-select v-model="paramForm.parameterFormat"
-                     placeholder="璇烽�夋嫨鏃堕棿鏍煎紡">
-            <el-option label="YYYY-MM-DD HH:mm:ss"
-                       value="YYYY-MM-DD HH:mm:ss" />
-            <el-option label="YYYY-MM-DD"
-                       value="YYYY-MM-DD" />
-          </el-select>
-        </el-form-item>
-        <el-form-item v-else
-                      label="鍙傛暟鏍煎紡"
-                      prop="parameterFormat">
-          <el-input v-model="paramForm.parameterFormat"
-                    placeholder="璇疯緭鍏ュ弬鏁版牸寮�" />
-        </el-form-item>
-        <el-form-item label="鏍囧噯鍊�"
-                      prop="standardValue">
-          <el-input v-model="paramForm.standardValue"
-                    placeholder="璇疯緭鍏ユ爣鍑嗗��" />
-        </el-form-item>
-        <el-form-item label="鍗曚綅"
-                      prop="unit">
-          <el-input v-model="paramForm.unit"
-                    placeholder="璇疯緭鍏ュ崟浣�" />
-        </el-form-item>
-      </el-form>
-      <template #footer>
-        <span class="dialog-footer">
-          <el-button @click="paramDialogVisible = false">鍙栨秷</el-button>
-          <el-button type="primary"
-                     @click="handleParamSubmit">纭畾</el-button>
-        </span>
-      </template>
-    </el-dialog>
-    <!-- 閫夋嫨鍙傛暟瀵硅瘽妗� -->
-    <el-dialog v-model="selectParamDialogVisible"
-               title="閫夋嫨鍙傛暟"
-               width="1000px">
-      <div class="param-select-container">
-        <!-- 宸︿晶鍙傛暟鍒楄〃 -->
-        <div class="param-list-area">
-          <div class="area-title">鍙�夊弬鏁�</div>
-          <div class="search-box">
-            <el-input v-model="paramSearchKeyword"
-                      placeholder="璇疯緭鍏ュ弬鏁板悕绉版悳绱�"
-                      clearable
-                      size="small"
-                      @input="handleParamSearch">
-              <template #prefix>
-                <el-icon>
-                  <Search />
-                </el-icon>
-              </template>
-            </el-input>
-          </div>
-          <el-table :data="filteredParamList"
-                    height="300"
-                    border
-                    highlight-current-row
-                    @current-change="handleParamSelect">
-            <el-table-column prop="paramName"
-                             label="鍙傛暟鍚嶇О" />
-            <el-table-column prop="paramType"
-                             label="鍙傛暟绫诲瀷">
-              <template #default="scope">
-                <el-tag size="small"
-                        :type="getParamTypeTag(scope.row.paramType)">
-                  {{ getParamTypeText(scope.row.paramType) }}
-                </el-tag>
-              </template>
-            </el-table-column>
-          </el-table>
-          <!-- 鍒嗛〉鎺т欢 -->
-          <div class="pagination-container"
-               style="margin-top: 10px;">
-            <el-pagination v-model:current-page="paramPage.current"
-                           v-model:page-size="paramPage.size"
-                           :page-sizes="[10, 20, 50, 100]"
-                           layout="total, sizes, prev, pager, next, jumper"
-                           :total="paramPage.total"
-                           @size-change="handleParamSizeChange"
-                           @current-change="handleParamCurrentChange"
-                           size="small" />
-          </div>
-        </div>
-        <!-- 鍙充晶鍙傛暟璇︽儏 -->
-        <div class="param-detail-area">
-          <div class="area-title">鍙傛暟璇︽儏</div>
-          <el-form v-if="selectedParam"
-                   :model="selectedParam"
-                   label-width="100px"
-                   class="param-detail-form">
-            <el-form-item label="鍙傛暟鍚嶇О">
-              <span class="detail-text">{{ selectedParam.paramName }}</span>
-            </el-form-item>
-            <el-form-item label="鍙傛暟妯″紡">
-              <el-tag size="small"
-                      :type="selectedParam.valueMode == '1' ? 'success' : 'warning'">
-                {{ selectedParam.valueMode == '1' ? '鍗曞��' : '鍖洪棿' }}
-              </el-tag>
-            </el-form-item>
-            <el-form-item label="鍙傛暟绫诲瀷">
-              <el-tag size="small"
-                      :type="getParamTypeTag(selectedParam.paramType)">
-                {{ getParamTypeText(selectedParam.paramType) }}
-              </el-tag>
-            </el-form-item>
-            <el-form-item label="鍙傛暟鏍煎紡">
-              <span class="detail-text">{{ selectedParam.paramFormat || '-' }}</span>
-            </el-form-item>
-            <el-form-item label="鍗曚綅">
-              <span class="detail-text">{{ selectedParam.unit || '-' }}</span>
-            </el-form-item>
-            <el-form-item label="鏍囧噯鍊�"
-                          v-if="selectedParam.valueMode == '1' && selectedParam.paramType == '1'">
-              <el-input v-model="selectedParam.standardValue"
-                        type="number"
-                        placeholder="璇疯緭鍏ラ粯璁ゅ��" />
-            </el-form-item>
-            <el-form-item label="鏈�灏忓��"
-                          v-if="selectedParam.valueMode == '2' && selectedParam.paramType == '1'">
-              <el-input v-model="selectedParam.minValue"
-                        type="number"
-                        placeholder="璇疯緭鍏ユ渶灏忓��" />
-            </el-form-item>
-            <el-form-item label="鏈�澶у��"
-                          v-if="selectedParam.valueMode == '2' && selectedParam.paramType == '1'">
-              <el-input v-model="selectedParam.maxValue"
-                        type="number"
-                        placeholder="璇疯緭鍏ユ渶澶у��" />
-            </el-form-item>
-            <el-form-item label="鎺掑簭">
-              <el-input v-model="selectedParam.sort"
-                        type="number"
-                        placeholder="璇疯緭鍏ユ帓搴�" />
-            </el-form-item>
-            <el-form-item label="鏄惁蹇呭~">
-              <el-switch v-model="selectedParam.isRequired"
-                         :active-value="1"
-                         :inactive-value="0" />
-            </el-form-item>
-          </el-form>
-          <el-empty v-else
-                    description="璇蜂粠宸︿晶閫夋嫨鍙傛暟" />
-        </div>
-      </div>
-      <template #footer>
-        <span class="dialog-footer">
-          <el-button @click="selectParamDialogVisible = false">鍙栨秷</el-button>
-          <el-button type="primary"
-                     :disabled="!selectedParam"
-                     @click="handleParamSelectSubmit">纭畾</el-button>
-        </span>
-      </template>
-    </el-dialog>
-    <!-- 缂栬緫鍙傛暟瀵硅瘽妗� -->
-    <el-dialog v-model="editParamDialogVisible"
-               title="缂栬緫鍙傛暟"
-               width="600px">
-      <el-form :model="editParamForm"
-               :rules="editParamRules"
-               ref="editParamFormRef"
-               label-width="120px">
-        <el-form-item label="鍙傛暟鍚嶇О">
-          <span class="detail-text">{{ editParamForm.paramName }}</span>
-        </el-form-item>
-        <el-form-item label="鍙傛暟妯″紡">
-          <el-tag size="small"
-                  :type="editParamForm.valueMode == '1' ? 'success' : 'warning'">
-            {{ editParamForm.valueMode == '1' ? '鍗曞��' : '鍖洪棿' }}
-          </el-tag>
-        </el-form-item>
-        <el-form-item label="鍙傛暟绫诲瀷">
-          <el-tag size="small"
-                  :type="getParamTypeTag(editParamForm.paramType)">
-            {{ getParamTypeText(editParamForm.paramType) }}
-          </el-tag>
-        </el-form-item>
-        <el-form-item label="鍙傛暟鏍煎紡">
-          <span class="detail-text">{{ editParamForm.paramFormat || '-' }}</span>
-        </el-form-item>
-        <el-form-item label="鍗曚綅">
-          <span class="detail-text">{{ editParamForm.unit || '-' }}</span>
-        </el-form-item>
-        <el-form-item label="鏍囧噯鍊�"
-                      v-if="editParamForm.valueMode == '1' && editParamForm.paramType == '1'"
-                      prop="standardValue">
-          <el-input v-model="editParamForm.standardValue"
-                    type="number"
-                    placeholder="璇疯緭鍏ユ爣鍑嗗��" />
-        </el-form-item>
-        <el-form-item label="鏈�灏忓��"
-                      v-if="editParamForm.valueMode == '2' && editParamForm.paramType == '1'"
-                      prop="minValue">
-          <el-input v-model="editParamForm.minValue"
-                    type="number"
-                    placeholder="璇疯緭鍏ユ渶灏忓��" />
-        </el-form-item>
-        <el-form-item label="鏈�澶у��"
-                      v-if="editParamForm.valueMode == '2' && editParamForm.paramType == '1'"
-                      prop="maxValue">
-          <el-input v-model="editParamForm.maxValue"
-                    type="number"
-                    placeholder="璇疯緭鍏ユ渶澶у��" />
-        </el-form-item>
-        <el-form-item label="鎺掑簭"
-                      prop="sort">
-          <el-input v-model="editParamForm.sort"
-                    type="number"
-                    placeholder="璇疯緭鍏ユ帓搴�" />
-        </el-form-item>
-        <el-form-item label="鏄惁蹇呭~"
-                      prop="isRequired">
-          <el-switch v-model="editParamForm.isRequired"
-                     :active-value="1"
-                     :inactive-value="0" />
-        </el-form-item>
-      </el-form>
-      <template #footer>
-        <span class="dialog-footer">
-          <el-button @click="editParamDialogVisible = false">鍙栨秷</el-button>
-          <el-button type="primary"
-                     @click="handleEditParamSubmit">纭畾</el-button>
-        </span>
-      </template>
-    </el-dialog>
+    <new-process v-if="isShowNewModal"
+                 v-model:visible="isShowNewModal"
+                 @completed="getList" />
+    <edit-process v-if="isShowEditModal"
+                  v-model:visible="isShowEditModal"
+                  :record="record"
+                  @completed="getList" />
+    <route-item-form v-if="isShowItemModal"
+                     v-model:visible="isShowItemModal"
+                     :record="record"
+                     @completed="getList" />
   </div>
 </template>
 
 <script setup>
-  import { ref, reactive, getCurrentInstance, onMounted } from "vue";
-  import { ElMessage, ElMessageBox } from "element-plus";
+  import { onMounted, ref, reactive, toRefs, getCurrentInstance } from "vue";
+  import NewProcess from "@/views/productionManagement/processRoute/New.vue";
+  import EditProcess from "@/views/productionManagement/processRoute/Edit.vue";
+  import RouteItemForm from "@/views/productionManagement/processRoute/ItemsForm.vue";
   import {
-    Plus,
-    Edit,
-    Delete,
-    ArrowUp,
-    ArrowDown,
-    Right,
-    Search,
-    Check,
-    Close,
-    Box,
-    Document,
-  } from "@element-plus/icons-vue";
-  import { listType } from "@/api/system/dict/type";
-  import { getByModel } from "@/api/productionManagement/productBom.js";
-  import { add, update, del } from "@/api/productionManagement/processRoute.js";
-  import {
-    addOrUpdateProcessRouteItem,
-    batchDeleteProcessRouteItem,
-    sortProcessRouteItem,
-    findProcessRouteItemList,
-    getProcessParamList,
-    addProcessRouteItemParam,
-    editProcessRouteItemParam,
-    delProcessRouteItemParam,
-  } from "@/api/productionManagement/processRouteItem.js";
-  import { list as getProcessListApi } from "@/api/productionManagement/productionProcess.js";
-  import { getBaseParamList } from "@/api/basicData/parameterMaintenance.js";
-  import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
+    listPage,
+    del,
+    update,
+  } from "@/api/productionManagement/processRoute.js";
+  import { useRouter } from "vue-router";
+  import { ElMessageBox, ElMessage } from "element-plus";
 
-  // 宸ヨ壓璺嚎鍒楄〃
-  const routeList = ref([]);
-  const dictTypes = ref([]);
-
-  // 宸ヨ壓璺嚎鍒嗛〉
-  const routePage = reactive({
+  const router = useRouter();
+  const data = reactive({
+    searchForm: {
+      model: "",
+    },
+  });
+  const { searchForm } = toRefs(data);
+  const tableColumn = ref([
+    {
+      label: "宸ヨ壓璺嚎缂栧彿",
+      prop: "processRouteCode",
+    },
+    {
+      label: "浜у搧鍚嶇О",
+      prop: "productName",
+    },
+    {
+      label: "瑙勬牸鍚嶇О",
+      prop: "model",
+    },
+    {
+      label: "BOM缂栧彿",
+      prop: "bomNo",
+    },
+    {
+      label: "鎻忚堪",
+      prop: "description",
+    },
+    {
+      dataType: "action",
+      label: "鎿嶄綔",
+      align: "center",
+      fixed: "right",
+      width: 280,
+      operation: [
+        {
+          name: "缂栬緫",
+          type: "text",
+          clickFun: row => {
+            showEditModal(row);
+          },
+        },
+        {
+          name: "璺嚎椤圭洰",
+          type: "text",
+          clickFun: row => {
+            showItemModal(row);
+          },
+        },
+        {
+          name: "鎵瑰噯",
+          type: "primary",
+          text: true,
+          showHide: row => {
+            return !row.status;
+          },
+          clickFun: row => {
+            handleApproveRoute(row);
+          },
+        },
+        {
+          name: "鍙栨秷鎵瑰噯",
+          type: "warning",
+          text: true,
+          showHide: row => {
+            return row.status;
+          },
+          clickFun: row => {
+            handleRevokeApproveRoute(row);
+          },
+        },
+      ],
+    },
+  ]);
+  const tableData = ref([]);
+  const selectedRows = ref([]);
+  const tableLoading = ref(false);
+  const isShowNewModal = ref(false);
+  const isShowEditModal = ref(false);
+  const isShowItemModal = ref(false);
+  const record = ref({});
+  const page = reactive({
     current: 1,
-    size: 10,
+    size: 100,
     total: 0,
   });
-
-  // 鑾峰彇鍏ㄥ眬瀹炰緥
   const { proxy } = getCurrentInstance();
 
-  // 浜у搧閫夋嫨鍜孊OM鐩稿叧
-  const showProductSelectDialog = ref(false);
-  const bomOptions = ref([]);
-
-  // 宸ヨ壓璺嚎瀵硅瘽妗�
-  const routeDialogVisible = ref(false);
-  const isRouteEdit = ref(false);
-  const routeFormRef = ref(null);
-  const routeForm = reactive({
-    id: null,
-    productModelId: null,
-    productName: "",
-    productModelName: "",
-    bomId: null,
-    routeCode: "",
-    description: "",
-    status: true,
-  });
-  const routeRules = {
-    productModelId: [
-      { required: true, message: "璇烽�夋嫨浜у搧", trigger: "change" },
-    ],
-    bomId: [{ required: true, message: "璇烽�夋嫨BOM", trigger: "change" }],
+  // 鏌ヨ鍒楄〃
+  /** 鎼滅储鎸夐挳鎿嶄綔 */
+  const handleQuery = () => {
+    page.current = 1;
+    getList();
   };
 
-  // 宸ュ簭瀵硅瘽妗�
-  const processDialogVisible = ref(false);
-  const isProcessEdit = ref(false);
-  const processFormRef = ref(null);
-  const currentRouteId = ref(null);
-  const processForm = reactive({
-    id: null,
-    no: "",
-    name: "",
-    remark: "",
-    status: true,
-  });
-  const processRules = {
-    no: [{ required: true, message: "璇疯緭鍏ュ伐搴忕紪鐮�", trigger: "blur" }],
-    name: [{ required: true, message: "璇疯緭鍏ュ伐搴忓悕绉�", trigger: "blur" }],
+  const pagination = obj => {
+    page.current = obj.page;
+    page.size = obj.limit;
+    getList();
   };
-
-  // 閫夋嫨宸ュ簭瀵硅瘽妗�
-  const selectProcessDialogVisible = ref(false);
-  const availableProcessList = ref([]);
-  const filteredProcessList = ref([]);
-  const selectedProcessItem = ref(null);
-  const processSearchKeyword = ref("");
-  const currentRouteIndex = ref(null);
-
-  // 鍙傛暟瀵硅瘽妗�
-  const paramDialogVisible = ref(false);
-  const isParamEdit = ref(false);
-  const paramFormRef = ref(null);
-  const currentProcessId = ref(null);
-  const paramForm = reactive({
-    id: null,
-    parameterCode: "",
-    parameterName: "",
-    parameterType2: "1",
-    parameterType: "",
-    parameterFormat: "",
-    standardValue: "",
-    unit: "",
-  });
-  const paramRules = {
-    parameterCode: [
-      { required: true, message: "璇疯緭鍏ュ弬鏁扮紪鍙�", trigger: "blur" },
-    ],
-    parameterName: [
-      { required: true, message: "璇疯緭鍏ュ弬鏁板悕绉�", trigger: "blur" },
-    ],
-    parameterType: [
-      { required: true, message: "璇烽�夋嫨鍙傛暟绫诲瀷", trigger: "change" },
-    ],
-  };
-
-  // 閫夋嫨鍙傛暟瀵硅瘽妗�
-  const selectParamDialogVisible = ref(false);
-  const availableParamList = ref([]);
-  const filteredParamList = ref([]);
-  const selectedParam = ref(null);
-  const paramSearchKeyword = ref("");
-
-  // 鍙�夊弬鏁板垎椤�
-  const paramPage = reactive({
-    current: 1,
-    size: 10,
-    total: 0,
-  });
-
-  // 缂栬緫鍙傛暟瀵硅瘽妗�
-  const editParamDialogVisible = ref(false);
-  const editParamFormRef = ref(null);
-  const editParamForm = reactive({
-    id: null,
-    processId: null,
-    paramId: null,
-    paramName: "",
-    valueMode: "1",
-    standardValue: null,
-    minValue: null,
-    maxValue: null,
-    sort: 1,
-    isRequired: 0,
-  });
-  const editParamRules = reactive({
-    standardValue: [
-      {
-        required: true,
-        message: "璇疯緭鍏ユ爣鍑嗗��",
-        trigger: "blur",
-        validator: (rule, value, callback) => {
-          if (value === null || value === undefined || value === "") {
-            callback(new Error("璇疯緭鍏ユ爣鍑嗗��"));
-          } else {
-            callback();
-          }
-        },
-      },
-    ],
-    minValue: [
-      {
-        required: true,
-        message: "璇疯緭鍏ユ渶灏忓��",
-        trigger: "blur",
-        validator: (rule, value, callback) => {
-          if (value === null || value === undefined || value === "") {
-            callback(new Error("璇疯緭鍏ユ渶灏忓��"));
-          } else {
-            callback();
-          }
-        },
-      },
-    ],
-    maxValue: [
-      {
-        required: true,
-        message: "璇疯緭鍏ユ渶澶у��",
-        trigger: "blur",
-        validator: (rule, value, callback) => {
-          if (value === null || value === undefined || value === "") {
-            callback(new Error("璇疯緭鍏ユ渶澶у��"));
-          } else {
-            callback();
-          }
-        },
-      },
-    ],
-    sort: [
-      {
-        required: true,
-        message: "璇疯緭鍏ユ帓搴�",
-        trigger: "blur",
-        validator: (rule, value, callback) => {
-          if (value === null || value === undefined || value === "") {
-            callback(new Error("璇疯緭鍏ユ帓搴�"));
-          } else if (isNaN(value) || value < 1) {
-            callback(new Error("鎺掑簭蹇呴』鏄ぇ浜�0鐨勬暣鏁�"));
-          } else {
-            callback();
-          }
-        },
-      },
-    ],
-  });
-
-  // 鎷栨嫿鐩稿叧
-  const draggedItem = ref(null);
-  const draggedRouteId = ref(null);
-
-  // 鑾峰彇宸ヨ壓璺嚎鍒楄〃
-  const getRouteList = () => {
-    // 瀵煎叆 listPage 鏂规硶
-    import("@/api/productionManagement/processRoute.js").then(({ listPage }) => {
-      listPage({ pageNum: routePage.current, pageSize: routePage.size })
-        .then(res => {
-          // 澶勭悊杩斿洖鐨勬暟鎹紝鏄犲皠鍒伴〉闈㈤渶瑕佺殑鏍煎紡
-          routeList.value = (res.data?.records || []).map(item => ({
-            id: item.id,
-            productModelId: item.productModelId,
-            productName: item.productName,
-            productModelName: item.model || item.productModelName,
-            bomId: item.bomId,
-            bomNo: item.bomNo,
-            routeCode: item.processRouteCode || item.routeCode,
-            description: item.description || item.description,
-            status: item.status,
-            expanded: false,
-            processList: (item.processList || []).map(process => ({
-              ...process,
-              processId: process.processId || process.id,
-              expanded: false,
-            })),
-          }));
-          // 鏇存柊鍒嗛〉鎬绘暟
-          routePage.total = res.data?.total || 0;
-        })
-        .catch(err => {
-          console.error("鑾峰彇宸ヨ壓璺嚎鍒楄〃澶辫触锛�", err);
-          routeList.value = [];
-          routePage.total = 0;
-        });
-    });
-  };
-
-  // 灞曞紑/鏀惰捣宸ヨ壓璺嚎
-  const toggleExpand = route => {
-    route.expanded = !route.expanded;
-    if (route.expanded) {
-      // 璋冪敤鎺ュ彛鑾峰彇宸ュ簭鍒楄〃
-      findProcessRouteItemList({ routeId: route.id })
-        .then(res => {
-          route.processList = (res.data || []).map(process => ({
-            ...process,
-            processId: process.processId || process.id,
-            expanded: false,
-          }));
-        })
-        .catch(err => {
-          console.error("鑾峰彇宸ュ簭鍒楄〃澶辫触锛�", err);
-          route.processList = [];
-        });
-    }
-  };
-
-  // 灞曞紑/鏀惰捣宸ュ簭鍙傛暟
-  const toggleProcessParams = process => {
-    process.expanded = !process.expanded;
-    if (process.expanded && process.id) {
-      // 璋冪敤鎺ュ彛鑾峰彇鍙傛暟鍒楄〃
-      getProcessParamList({
-        routeItemId: process.id,
-        pageNum: 1,
-        pageSize: 1000,
+  const getList = () => {
+    tableLoading.value = true;
+    const params = { ...searchForm.value, ...page };
+    params.entryDate = undefined;
+    listPage(params)
+      .then(res => {
+        tableLoading.value = false;
+        tableData.value = res.data.records.map(item => ({
+          ...item,
+        }));
+        page.total = res.data.total;
       })
-        .then(res => {
-          if (res.code === 200) {
-            process.paramList = res.data?.records || [];
-            process.paramCount = process.paramList.length;
-          } else {
-            ElMessage.error(res.msg || "鑾峰彇鍙傛暟鍒楄〃澶辫触");
-            process.paramList = [];
-            process.paramCount = 0;
-          }
-        })
-        .catch(err => {
-          console.error("鑾峰彇鍙傛暟鍒楄〃澶辫触锛�", err);
-          ElMessage.error("鑾峰彇鍙傛暟鍒楄〃澶辫触");
-          process.paramList = [];
-          process.paramCount = 0;
-        });
-    }
+      .catch(err => {
+        tableLoading.value = false;
+      });
   };
-  const toggleProcessParams2 = process => {
-    if (process.expanded && process.id) {
-      // 璋冪敤鎺ュ彛鑾峰彇鍙傛暟鍒楄〃
-      getProcessParamList({
-        routeItemId: process.id,
-        pageNum: 1,
-        pageSize: 1000,
+  // 琛ㄦ牸閫夋嫨鏁版嵁
+  const handleSelectionChange = selection => {
+    selectedRows.value = selection;
+  };
+
+  // 鎵撳紑鏂板寮规
+  const showNewModal = () => {
+    isShowNewModal.value = true;
+  };
+
+  const showEditModal = row => {
+    isShowEditModal.value = true;
+    record.value = row;
+  };
+
+  const showItemModal = row => {
+    router.push({
+      path: "/productionManagement/processRouteItem",
+      query: {
+        id: row.id,
+        processRouteCode: row.processRouteCode || "",
+        productName: row.productName || "",
+        model: row.model || "",
+        bomNo: row.bomNo || "",
+        bomId: row.bomId || null,
+        description: row.description || "",
+        type: "route",
+      },
+    });
+  };
+
+  // 鍒犻櫎
+  function handleDelete() {
+    const ids = selectedRows.value.map(item => item.id);
+    proxy.$modal
+      .confirm("鏄惁纭鍒犻櫎宸插嬀閫夌殑鏁版嵁椤癸紵")
+      .then(function () {
+        return del(ids);
       })
-        .then(res => {
-          if (res.code === 200) {
-            process.paramList = res.data?.records || [];
-            process.paramCount = process.paramList.length;
-          } else {
-            ElMessage.error(res.msg || "鑾峰彇鍙傛暟鍒楄〃澶辫触");
-            process.paramList = [];
-            process.paramCount = 0;
-          }
-        })
-        .catch(err => {
-          console.error("鑾峰彇鍙傛暟鍒楄〃澶辫触锛�", err);
-          ElMessage.error("鑾峰彇鍙傛暟鍒楄〃澶辫触");
-          process.paramList = [];
-          process.paramCount = 0;
-        });
-    }
-  };
-  // 宸ヨ壓璺嚎鎿嶄綔
-  const handleAddRoute = () => {
-    isRouteEdit.value = false;
-    routeForm.id = null;
-    routeForm.productModelId = null;
-    routeForm.productName = "";
-    routeForm.productModelName = "";
-    routeForm.bomId = null;
-    routeForm.routeCode = "";
-    routeForm.description = "";
-    routeForm.status = false;
-    bomOptions.value = [];
-    routeDialogVisible.value = true;
-  };
+      .then(() => {
+        getList();
+        proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      })
+      .catch(() => {});
+  }
 
-  const handleEditRoute = route => {
-    isRouteEdit.value = true;
-    routeForm.id = route.id;
-    routeForm.productModelId = route.productModelId;
-    routeForm.productName = route.productName;
-    routeForm.productModelName = route.productModelName;
-    routeForm.bomId = route.bomId;
-    routeForm.routeCode = route.routeCode;
-    routeForm.description = route.description;
-    routeForm.status = route.status;
-    routeDialogVisible.value = true;
-  };
-
-  const handleDeleteRoute = route => {
-    ElMessageBox.confirm("纭畾瑕佸垹闄よ宸ヨ壓璺嚎鍚楋紵", "鎻愮ず", {
-      confirmButtonText: "纭畾",
-      cancelButtonText: "鍙栨秷",
-      type: "warning",
-    }).then(() => {
-      del(route.id)
-        .then(res => {
-          ElMessage.success("鍒犻櫎鎴愬姛");
-          getRouteList();
-        })
-        .catch(err => {
-          ElMessage.error("鍒犻櫎澶辫触");
-        });
-    });
-  };
-
-  const handleRouteSubmit = () => {
-    routeFormRef.value.validate(valid => {
-      if (valid) {
-        // 鏋勫缓鎻愪氦鏁版嵁
-        const submitData = {
-          ...routeForm,
-          // 娉ㄦ剰锛欰PI 鏈熸湜鐨勫瓧娈靛悕鍙兘涓庤〃鍗曞瓧娈靛悕涓嶅悓
-          productId: routeForm.productModelId,
-          productModelId: routeForm.productModelId,
-          description: routeForm.description,
-        };
-
-        if (isRouteEdit.value) {
-          // 缂栬緫鎿嶄綔
-          update(submitData)
-            .then(res => {
-              ElMessage.success("缂栬緫鎴愬姛");
-              routeDialogVisible.value = false;
-              getRouteList();
-            })
-            .catch(err => {
-              ElMessage.error("缂栬緫澶辫触");
-            });
-        } else {
-          // 鏂板鎿嶄綔
-          add(submitData)
-            .then(res => {
-              ElMessage.success("鏂板鎴愬姛");
-              routeDialogVisible.value = false;
-              getRouteList();
-            })
-            .catch(err => {
-              ElMessage.error("鏂板澶辫触");
-            });
-        }
-      }
-    });
-  };
-  const isform2 = ref(null);
-  const handleProcessProductSelectClick = () => {
-    isform2.value = true;
-    showProductSelectDialog.value = true;
-  };
-  const handleProcessProductSelectClick2 = () => {
-    isform2.value = false;
-    showProductSelectDialog.value = true;
-  };
-
-  // 浜у搧閫夋嫨澶勭悊
-  const handleProductSelect = async products => {
-    if (isform2.value) {
-      // 甯垜鍐欏伐搴忎腑鐨勯�夋嫨浜у搧鐨勫洖璋�,骞朵笖鎶婂瓧娈靛姞杩沺rocessForm
-      if (products && products.length > 0) {
-        const product = products[0];
-        console.log("product:", product);
-        // 鎶妏roduct涓殑瀛楁娣诲姞鍒皃rocessForm涓�
-        // Object.assign(processForm, product);
-        processForm.productModelId = product.id;
-        processForm.productName = product.productName;
-        processForm.model = product.model;
-        processForm.unit = product.unit || "";
-        console.log("processForm:", processForm);
-
-        // 瑙﹀彂琛ㄥ崟楠岃瘉鏇存柊
-        proxy.$refs["processFormRef"]?.validateField("productModelId");
-      }
-    } else {
-      if (products && products.length > 0) {
-        const product = products[0];
-        // 鍏堟煡璇OM鍒楄〃锛堝繀閫夛級
-        try {
-          const res = await getByModel(product.id);
-          // 澶勭悊杩斿洖鐨凚OM鏁版嵁锛氬彲鑳芥槸鏁扮粍銆佸璞℃垨鍖呭惈data瀛楁
-          let bomList = [];
-          if (Array.isArray(res)) {
-            bomList = res;
-          } else if (res && res.data) {
-            bomList = Array.isArray(res.data) ? res.data : [res.data];
-          } else if (res && typeof res === "object") {
-            bomList = [res];
-          }
-          console.log("bomList:", bomList);
-          if (bomList.length > 0) {
-            routeForm.productModelId = product.id;
-            routeForm.productName = product.productName;
-            routeForm.productModelName = product.model;
-            routeForm.bomId = undefined; // 閲嶇疆BOM閫夋嫨
-            bomOptions.value = bomList;
-            showProductSelectDialog.value = false;
-            // 瑙﹀彂琛ㄥ崟楠岃瘉鏇存柊
-            proxy.$refs["routeFormRef"]?.validateField("productModelId");
-          } else {
-            proxy.$modal.msgError("璇ヤ骇鍝佹病鏈塀OM锛岃鍏堝垱寤築OM");
-          }
-        } catch (error) {
-          // 濡傛灉鎺ュ彛杩斿洖404鎴栧叾浠栭敊璇紝璇存槑娌℃湁BOM
-          proxy.$modal.msgError("璇ヤ骇鍝佹病鏈塀OM锛岃鍏堝垱寤築OM");
-        }
-      }
-    }
-  };
-
+  // 鎵瑰噯宸ヨ壓璺嚎
   const handleApproveRoute = route => {
     ElMessageBox.confirm("纭畾瑕佹壒鍑嗚宸ヨ壓璺嚎鍚楋紵", "鎻愮ず", {
       confirmButtonText: "纭畾",
@@ -1206,7 +237,7 @@
       update({ id: route.id, status: true })
         .then(res => {
           ElMessage.success("鎵瑰噯鎴愬姛");
-          getRouteList();
+          getList();
         })
         .catch(err => {
           ElMessage.error("鎵瑰噯澶辫触");
@@ -1214,6 +245,7 @@
     });
   };
 
+  // 鍙栨秷鎵瑰噯宸ヨ壓璺嚎
   const handleRevokeApproveRoute = route => {
     ElMessageBox.confirm("纭畾瑕佹挙閿�鎵瑰噯璇ュ伐鑹鸿矾绾垮悧锛�", "鎻愮ず", {
       confirmButtonText: "纭畾",
@@ -1224,1194 +256,17 @@
       update({ id: route.id, status: false })
         .then(res => {
           ElMessage.success("鎾ら攢鎵瑰噯鎴愬姛");
-          getRouteList();
+          getList();
         })
         .catch(err => {
           ElMessage.error("鎾ら攢鎵瑰噯澶辫触");
         });
     });
   };
-  // 宸ュ簭鎿嶄綔
-  const handleSelectProcess = (route, index) => {
-    console.log("route:", route);
-    currentRouteId.value = route.id;
-    currentRouteIndex.value = index;
-    // 閲嶇疆鎼滅储鍜岄�夋嫨鐘舵��
-    filteredProcessList.value = availableProcessList.value;
-    processSearchKeyword.value = "";
-    selectedProcessItem.value = null;
-    selectProcessDialogVisible.value = true;
-  };
-  const dragSort = ref(0);
-  const currentId = ref(null);
-  // 淇敼宸ュ簭
-  const handleEditProcessSelect = (route, index, process) => {
-    console.log("route:", route);
-    console.log("process:", process);
-    currentId.value = process.id;
-    currentRouteId.value = route.id;
-    currentRouteIndex.value = index;
-    // 閲嶇疆鎼滅储鍜岄�夋嫨鐘舵��
-    filteredProcessList.value = availableProcessList.value;
-    processSearchKeyword.value = "";
-    // 璁剧疆閫変腑鐨勫伐搴�
-    filteredProcessList.value.map(item => {
-      if (item.id === process.processId) {
-        selectedProcessItem.value = item;
-      }
-    });
-    dragSort.value = process.dragSort;
-    // selectedProcessItem.value = process;
-    // 濉厖浜у搧閫夋嫨琛ㄥ崟
-    processForm.productModelId = process.productModelId;
-    processForm.productName = process.productName;
-    processForm.model = process.model;
-    processForm.processId = process.no;
-    // processForm.name = process.name;
-    processForm.unit = process.unit || "";
-    processForm.isQuality = process.isQuality || false;
-    selectProcessDialogVisible.value = true;
-  };
 
-  const handleEditProcess = (routeId, process) => {
-    currentRouteId.value = routeId;
-    isProcessEdit.value = true;
-    processForm.id = process.id;
-    processForm.no = process.no;
-    processForm.name = process.name;
-    processForm.remark = process.remark;
-    processForm.status = process.status;
-    processDialogVisible.value = true;
-  };
-
-  const handleDeleteProcess = (routeId, process) => {
-    ElMessageBox.confirm("纭畾瑕佸垹闄よ宸ュ簭鍚楋紵", "鎻愮ず", {
-      confirmButtonText: "纭畾",
-      cancelButtonText: "鍙栨秷",
-      type: "warning",
-    }).then(() => {
-      // 璋冪敤API鍒犻櫎宸ュ簭
-      batchDeleteProcessRouteItem([process.id])
-        .then(res => {
-          ElMessage.success("鍒犻櫎鎴愬姛");
-          // 璋冪敤鎺ュ彛鏇存柊宸ュ簭鍒楄〃
-          findProcessRouteItemList({ routeId: routeId })
-            .then(res => {
-              const route = routeList.value.find(r => r.id === routeId);
-              if (route) {
-                route.processList = (res.data || []).map(process => ({
-                  ...process,
-                  processId: process.processId || process.id,
-                  expanded: false,
-                }));
-              }
-            })
-            .catch(err => {
-              console.error("鑾峰彇宸ュ簭鍒楄〃澶辫触锛�", err);
-            });
-        })
-        .catch(err => {
-          ElMessage.error("鍒犻櫎澶辫触");
-          console.error("鍒犻櫎宸ュ簭澶辫触锛�", err);
-        });
-    });
-  };
-
-  const handleProcessSubmit = () => {
-    processFormRef.value.validate(valid => {
-      if (valid) {
-        ElMessage.success(isProcessEdit.value ? "缂栬緫鎴愬姛" : "鏂板鎴愬姛");
-        processDialogVisible.value = false;
-        // 璋冪敤鎺ュ彛鏇存柊宸ュ簭鍒楄〃
-        if (currentRouteId.value) {
-          findProcessRouteItemList({ routeId: currentRouteId.value })
-            .then(res => {
-              const route = routeList.value.find(
-                r => r.id === currentRouteId.value
-              );
-              if (route) {
-                route.processList = (res.data || []).map(process => ({
-                  ...process,
-                  processId: process.processId || process.id,
-                  expanded: false,
-                }));
-              }
-            })
-            .catch(err => {
-              console.error("鑾峰彇宸ュ簭鍒楄〃澶辫触锛�", err);
-            });
-        }
-      }
-    });
-  };
-
-  // 閫夋嫨宸ュ簭鐩稿叧鏂规硶
-  const handleProcessSearch = () => {
-    const keyword = processSearchKeyword.value.trim().toLowerCase();
-    if (!keyword) {
-      filteredProcessList.value = availableProcessList.value;
-    } else {
-      filteredProcessList.value = availableProcessList.value.filter(
-        item =>
-          (item.name && item.name.toLowerCase().includes(keyword)) ||
-          (item.no && item.no.toLowerCase().includes(keyword))
-      );
-    }
-  };
-
-  const handleProcessSelect = row => {
-    selectedProcessItem.value = row;
-    // 閲嶇疆浜у搧閫夋嫨琛ㄥ崟
-    processForm.productModelId = undefined;
-    processForm.productName = "";
-    processForm.productModelName = "";
-    processForm.unit = "";
-    processForm.isQuality = row.isQuality || false;
-  };
-
-  // 澶勭悊宸ュ簭閫夋嫨鏃剁殑浜у搧閫夋嫨
-  const handleProcessProductSelect = async products => {
-    if (products && products.length > 0) {
-      const product = products[0];
-      processForm.productModelId = product.id;
-      processForm.productName = product.productName;
-      processForm.productModelName = product.model;
-      processForm.unit = product.unit || "";
-      showProductSelectDialog.value = false;
-    }
-  };
-
-  const handleProcessSelectSubmit = () => {
-    if (!selectedProcessItem.value) {
-      ElMessage.warning("璇峰厛閫夋嫨涓�涓伐搴�");
-      return;
-    }
-
-    if (!processForm.productModelId) {
-      ElMessage.warning("璇烽�夋嫨浜у搧");
-      return;
-    }
-
-    // 鏋勫缓璇锋眰鍙傛暟
-    const params = {
-      routeId: currentRouteId.value,
-      processId: selectedProcessItem.value.id,
-      dragSort: routePage.total + 1,
-      ...processForm,
-    };
-
-    // 濡傛灉鏄慨鏀规搷浣滐紝娣诲姞id鍙傛暟
-    if (selectedProcessItem.value.id) {
-      params.id = currentId.value;
-      params.dragSort = dragSort.value;
-    }
-
-    // 璋冪敤API娣诲姞宸ュ簭鎴栦慨鏀瑰伐搴�
-    addOrUpdateProcessRouteItem(params)
-      .then(res => {
-        ElMessage.success(
-          selectedProcessItem.value.id ? "淇敼宸ュ簭鎴愬姛" : "娣诲姞宸ュ簭鎴愬姛"
-        );
-        selectProcessDialogVisible.value = false;
-        // 璋冪敤鎺ュ彛鏇存柊宸ュ簭鍒楄〃
-        findProcessRouteItemList({ routeId: currentRouteId.value })
-          .then(res => {
-            const route = routeList.value.find(
-              r => r.id === currentRouteId.value
-            );
-            if (route) {
-              route.processList = (res.data || []).map(process => ({
-                ...process,
-                processId: process.processId || process.id,
-                expanded: false,
-              }));
-            }
-          })
-          .catch(err => {
-            console.error("鑾峰彇宸ュ簭鍒楄〃澶辫触锛�", err);
-          });
-      })
-      .catch(err => {
-        ElMessage.error(
-          selectedProcessItem.value.id ? "淇敼宸ュ簭澶辫触" : "娣诲姞宸ュ簭澶辫触"
-        );
-        console.error(
-          selectedProcessItem.value.id ? "淇敼宸ュ簭澶辫触锛�" : "娣诲姞宸ュ簭澶辫触锛�",
-          err
-        );
-      });
-  };
-
-  // 鍙傛暟鎿嶄綔
-  const handleAddParam = (routeId, process) => {
-    currentRouteId.value = routeId;
-    currentProcessId.value = process.id;
-    selectedParam.value = null;
-    paramSearchKeyword.value = "";
-    paramPage.current = 1;
-    // 鑾峰彇鍙�夊弬鏁板垪琛�
-    getBaseParamList({
-      paramName: paramSearchKeyword.value,
-      current: paramPage.current,
-      size: paramPage.size,
-    }).then(res => {
-      if (res.code === 200) {
-        filteredParamList.value = res.data?.records || [];
-        paramPage.total = res.data?.total || 0;
-      } else {
-        ElMessage.error(res.msg || "鏌ヨ澶辫触");
-      }
-    });
-    selectParamDialogVisible.value = true;
-  };
-
-  const handleEditParam = (routeId, process, param) => {
-    currentRouteId.value = routeId;
-    currentProcessId.value = process.id;
-    editParamForm.id = param.id;
-    editParamForm.processId = process.id;
-    editParamForm.paramId = param.paramId;
-    editParamForm.paramName = param.parameterName || param.paramName;
-    editParamForm.valueMode = param.parameterType2 || param.valueMode || "1";
-    editParamForm.standardValue = param.standardValue;
-    editParamForm.minValue = param.minValue;
-    editParamForm.maxValue = param.maxValue;
-    editParamForm.sort = param.sort || 1;
-    editParamForm.isRequired = param.isRequired || 0;
-    editParamForm.paramType = param.parameterType || param.paramType;
-    editParamForm.paramFormat = param.parameterFormat || param.paramFormat;
-    editParamForm.unit = param.unit || param.unit;
-    editParamDialogVisible.value = true;
-  };
-
-  const handleDeleteParam = (routeId, process, param) => {
-    ElMessageBox.confirm("纭畾瑕佸垹闄よ鍙傛暟鍚楋紵", "鎻愮ず", {
-      confirmButtonText: "纭畾",
-      cancelButtonText: "鍙栨秷",
-      type: "warning",
-    }).then(() => {
-      // 璋冪敤API鍒犻櫎鍙傛暟
-      delProcessRouteItemParam(param.id)
-        .then(res => {
-          ElMessage.success("鍒犻櫎鎴愬姛");
-          // 鍒锋柊鍙傛暟鍒楄〃
-          toggleProcessParams2(process);
-        })
-        .catch(err => {
-          ElMessage.error("鍒犻櫎鍙傛暟澶辫触");
-          console.error("鍒犻櫎鍙傛暟澶辫触锛�", err);
-        });
-    });
-  };
-
-  const handleParamSubmit = () => {
-    paramFormRef.value.validate(valid => {
-      if (valid) {
-        ElMessage.success(isParamEdit.value ? "缂栬緫鎴愬姛" : "鏂板鎴愬姛");
-        paramDialogVisible.value = false;
-        getRouteList();
-      }
-    });
-  };
-
-  const handleParamTypeChange = () => {
-    if (paramForm.parameterType === "鏁板�兼牸寮�") {
-      paramForm.parameterFormat = "#.0000";
-    } else if (paramForm.parameterType === "鏃堕棿鏍煎紡") {
-      paramForm.parameterFormat = "YYYY-MM-DD HH:mm:ss";
-    } else {
-      paramForm.parameterFormat = "";
-    }
-  };
-
-  const getParamTypeTag = type => {
-    const typeMap = {
-      1: "primary",
-      2: "info",
-      3: "warning",
-      4: "success",
-    };
-    return typeMap[type] || "default";
-  };
-
-  const getParamTypeText = type => {
-    const typeMap = {
-      1: "鏁板�兼牸寮�",
-      2: "鏂囨湰鏍煎紡",
-      3: "涓嬫媺閫夐」",
-      4: "鏃堕棿鏍煎紡",
-    };
-    return typeMap[type] || "鏈煡鍙傛暟绫诲瀷";
-  };
-
-  // 閫夋嫨鍙傛暟鐩稿叧鏂规硶
-  const handleParamSearch = () => {
-    // 閲嶇疆鍒嗛〉
-    paramPage.current = 1;
-    // 閲嶆柊鍔犺浇鏁版嵁
-    getBaseParamList({
-      paramName: paramSearchKeyword.value,
-      current: paramPage.current,
-      size: paramPage.size,
-    }).then(res => {
-      if (res.code === 200) {
-        filteredParamList.value = res.data?.records || [];
-        paramPage.total = res.data?.total || 0;
-      } else {
-        ElMessage.error(res.msg || "鏌ヨ澶辫触");
-      }
-    });
-  };
-
-  const handleParamSelect = row => {
-    selectedParam.value = row;
-  };
-
-  // 澶勭悊鍒嗛〉澶у皬鍙樺寲
-  const handleParamSizeChange = size => {
-    paramPage.size = size;
-    getBaseParamList({
-      paramName: paramSearchKeyword.value,
-      current: paramPage.current,
-      size: paramPage.size,
-    }).then(res => {
-      if (res.code === 200) {
-        filteredParamList.value = res.data?.records || [];
-        paramPage.total = res.data?.total || 0;
-      } else {
-        ElMessage.error(res.msg || "鏌ヨ澶辫触");
-      }
-    });
-  };
-
-  // 澶勭悊褰撳墠椤电爜鍙樺寲
-  const handleParamCurrentChange = current => {
-    paramPage.current = current;
-    getBaseParamList({
-      paramName: paramSearchKeyword.value,
-      current: paramPage.current,
-      size: paramPage.size,
-    }).then(res => {
-      if (res.code === 200) {
-        filteredParamList.value = res.data?.records || [];
-        paramPage.total = res.data?.total || 0;
-      } else {
-        ElMessage.error(res.msg || "鏌ヨ澶辫触");
-      }
-    });
-  };
-
-  // 宸ヨ壓璺嚎鍒嗛〉澶勭悊
-  const handleRouteSizeChange = size => {
-    routePage.size = size;
-    getRouteList();
-  };
-
-  const handleRouteCurrentChange = current => {
-    routePage.current = current;
-    getRouteList();
-  };
-
-  const handleParamSelectSubmit = () => {
-    if (!selectedParam.value) {
-      ElMessage.warning("璇峰厛閫夋嫨涓�涓弬鏁�");
-      return;
-    }
-
-    // 鎵惧埌瀵瑰簲鐨勫伐鑹鸿矾绾垮拰宸ュ簭
-    const route = routeList.value.find(r => r.id === currentRouteId.value);
-    const process = route?.processList.find(p => p.id === currentProcessId.value);
-
-    if (route && process) {
-      // 妫�鏌ュ弬鏁版槸鍚﹀凡瀛樺湪
-      // const exists = process.paramList?.some(
-      //   p =>
-      //     p.paramId === selectedParam.value.id ||
-      //     p.parameterCode === selectedParam.value.paramCode
-      // );
-      // if (exists) {
-      //   ElMessage.warning("璇ュ弬鏁板凡瀛樺湪浜庡伐搴忎腑");
-      //   return;
-      // }
-
-      // 鍒ゆ柇鍙傛暟绫诲瀷锛屽彧鏈夋暟鍊肩被鍨嬫墠浼犳爣鍑嗗�笺�佹渶澶у�煎拰鏈�灏忓��
-      const isNumericMode = selectedParam.value.valueMode === 1;
-
-      // 璋冪敤API鏂板鍙傛暟
-      addProcessRouteItemParam({
-        routeItemId: process.id,
-        paramId: selectedParam.value.id,
-        standardValue: isNumericMode
-          ? selectedParam.value.standardValue || ""
-          : "",
-        minValue: isNumericMode ? selectedParam.value.minValue || 0 : null,
-        maxValue: isNumericMode ? selectedParam.value.maxValue || 0 : null,
-        isRequired: selectedParam.value.isRequired || 0,
-      })
-        .then(res => {
-          ElMessage.success("娣诲姞鍙傛暟鎴愬姛");
-          selectParamDialogVisible.value = false;
-          // 鍒锋柊鍙傛暟鍒楄〃
-          toggleProcessParams2(process);
-        })
-        .catch(err => {
-          ElMessage.error("娣诲姞鍙傛暟澶辫触");
-          console.error("娣诲姞鍙傛暟澶辫触锛�", err);
-        });
-    }
-  };
-
-  const handleEditParamSubmit = () => {
-    editParamFormRef.value.validate(valid => {
-      if (valid) {
-        // 鍒ゆ柇鍙傛暟绫诲瀷锛屽彧鏈夋暟鍊肩被鍨嬫墠浼犳爣鍑嗗�笺�佹渶澶у�煎拰鏈�灏忓��
-        const isNumericMode = editParamForm.valueMode == 1;
-
-        // 璋冪敤API淇敼鍙傛暟
-        editProcessRouteItemParam({
-          id: editParamForm.id,
-          routeItemId: currentProcessId.value,
-          paramId: editParamForm.paramId,
-          standardValue: isNumericMode ? editParamForm.standardValue || "" : "",
-          minValue: isNumericMode ? editParamForm.minValue || 0 : null,
-          maxValue: isNumericMode ? editParamForm.maxValue || 0 : null,
-          isRequired: editParamForm.isRequired || 0,
-        })
-          .then(res => {
-            ElMessage.success("缂栬緫鎴愬姛");
-            editParamDialogVisible.value = false;
-            // 鎵惧埌瀵瑰簲鐨勫伐鑹鸿矾绾垮拰宸ュ簭
-            const route = routeList.value.find(
-              r => r.id === currentRouteId.value
-            );
-            const process = route?.processList.find(
-              p => p.id === currentProcessId.value
-            );
-            // 鍒锋柊鍙傛暟鍒楄〃
-            if (process) {
-              toggleProcessParams2(process);
-            }
-          })
-          .catch(err => {
-            ElMessage.error("缂栬緫鍙傛暟澶辫触");
-            console.error("缂栬緫鍙傛暟澶辫触锛�", err);
-          });
-      }
-    });
-  };
-
-  // 鎷栨嫿鎺掑簭
-  const handleDragStart = (event, index, routeId) => {
-    draggedItem.value = index;
-    draggedRouteId.value = routeId;
-    event.dataTransfer.effectAllowed = "move";
-  };
-
-  const handleDragOver = event => {
-    event.preventDefault();
-    event.dataTransfer.dropEffect = "move";
-  };
-
-  const handleDrop = (event, dropIndex, routeId) => {
-    event.preventDefault();
-    if (draggedItem.value === null || draggedItem.value === dropIndex) return;
-
-    const route = routeList.value.find(r => r.id === routeId);
-    if (route && route.processList) {
-      const draggedProcess = route.processList[draggedItem.value];
-
-      // 璁$畻鏂扮殑鎺掑簭鍊�
-      const newDragSort = dropIndex + 1;
-
-      // 璋冪敤API鎺掑簭宸ュ簭
-      sortProcessRouteItem({
-        id: draggedProcess.id,
-        dragSort: newDragSort,
-      })
-        .then(res => {
-          // 璋冪敤鎺ュ彛鑾峰彇鏈�鏂扮殑宸ュ簭鍒楄〃
-          findProcessRouteItemList({ routeId: routeId })
-            .then(res => {
-              if (route) {
-                route.processList = (res.data || []).map(process => ({
-                  ...process,
-                  processId: process.processId || process.id,
-                  expanded: false,
-                }));
-              }
-              ElMessage.success("鎺掑簭鎴愬姛");
-            })
-            .catch(err => {
-              console.error("鑾峰彇宸ュ簭鍒楄〃澶辫触锛�", err);
-              ElMessage.success("鎺掑簭鎴愬姛");
-            });
-        })
-        .catch(err => {
-          ElMessage.error("鎺掑簭澶辫触");
-          console.error("鎺掑簭宸ュ簭澶辫触锛�", err);
-        });
-    }
-  };
-
-  const handleDragEnd = () => {
-    draggedItem.value = null;
-    draggedRouteId.value = null;
-  };
-
-  // 鑾峰彇鏁版嵁瀛楀吀
-  const getDictTypes = () => {
-    listType({ pageNum: 1, pageSize: 1000 }).then(res => {
-      dictTypes.value = res.rows || [];
-    });
-  };
-
-  getRouteList();
-  getDictTypes();
-
-  // 椤甸潰鍔犺浇鏃惰幏鍙栧伐搴忓垪琛�
   onMounted(() => {
-    getProcessListApi()
-      .then(res => {
-        // 澶勭悊杩斿洖鐨勬暟鎹紝鏄犲皠鍒伴〉闈㈤渶瑕佺殑鏍煎紡
-        availableProcessList.value = (res.data || []).map(item => ({
-          id: item.id,
-          no: item.no || item.no,
-          name: item.name || item.name,
-          remark: item.remark || item.remark,
-          status: item.status,
-          isQuality: item.isQuality,
-        }));
-        filteredProcessList.value = availableProcessList.value;
-      })
-      .catch(() => {
-        ElMessage.error("鑾峰彇宸ュ簭鍒楄〃澶辫触");
-      });
+    getList();
   });
 </script>
 
-<style scoped lang="scss">
-  .app-container {
-    padding: 20px;
-    padding-bottom: 80px;
-    background-color: #f0f2f5;
-    min-height: calc(100vh - 84px);
-    overflow: hidden;
-  }
-
-  .route-header {
-    margin-bottom: 20px;
-
-    .add-route-btn {
-      width: 100%;
-      display: inline-flex;
-      flex-direction: column;
-      align-items: center;
-      justify-content: center;
-      min-width: 120px;
-      height: 100px;
-      border: 2px dashed #dcdfe6;
-      border-radius: 12px;
-      background: #fafafa;
-      cursor: pointer;
-      transition: all 0.3s ease;
-      color: #909399;
-      padding: 0 20px;
-
-      .el-icon {
-        font-size: 24px;
-        margin-bottom: 8px;
-      }
-
-      span {
-        font-size: 13px;
-      }
-
-      &:hover {
-        border-color: #409eff;
-        background: #ecf5ff;
-        color: #409eff;
-      }
-    }
-  }
-
-  .route-card-list {
-    display: grid;
-    grid-template-columns: repeat(1, 1fr);
-    gap: 20px;
-    max-height: calc(100vh - 240px);
-    overflow-y: auto;
-    padding-right: 10px;
-  }
-
-  /* 鑷畾涔夋粴鍔ㄦ潯鏍峰紡 */
-  .route-card-list::-webkit-scrollbar {
-    width: 8px;
-  }
-
-  .route-card-list::-webkit-scrollbar-track {
-    background: #f1f1f1;
-    border-radius: 4px;
-  }
-
-  .route-card-list::-webkit-scrollbar-thumb {
-    background: #c1c1c1;
-    border-radius: 4px;
-  }
-
-  .route-card-list::-webkit-scrollbar-thumb:hover {
-    background: #a8a8a8;
-  }
-
-  .route-card {
-    background: #fff;
-    border-radius: 8px;
-    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
-    overflow: hidden;
-
-    .card-header {
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      padding: 20px 40px;
-      border-bottom: 1px solid #ebeef5;
-      background: #f8f9fa;
-
-      .route-info {
-        display: flex;
-        // flex-direction: column;
-        // justify-content: center;
-        // items-align: center;
-        gap: 4px;
-
-        .route-code {
-          font-size: 12px;
-          color: #909399;
-          font-family: "Courier New", monospace;
-          line-height: 30px;
-        }
-
-        .route-name {
-          font-size: 18px;
-          font-weight: 600;
-          color: #303133;
-          display: flex;
-          align-items: center;
-        }
-      }
-
-      .route-actions {
-        display: flex;
-        gap: 8px;
-
-        // .el-button {
-        //   color: #409eff;
-        // }
-      }
-    }
-
-    .card-body {
-      padding: 16px 40px;
-
-      .route-desc {
-        font-size: 14px;
-        color: #606266;
-        margin-bottom: 12px;
-      }
-
-      .route-meta {
-        display: flex;
-        gap: 24px;
-        margin-bottom: 12px;
-        padding: 10px 14px;
-        background: linear-gradient(135deg, #f5f7fa 0%, #e8ecf1 100%);
-        border-radius: 8px;
-        border-left: 3px solid #409eff;
-
-        .meta-item {
-          display: flex;
-          align-items: center;
-          gap: 6px;
-          font-size: 13px;
-          margin-right: 40px;
-
-          .el-icon {
-            font-size: 14px;
-            color: #409eff;
-          }
-
-          .meta-label {
-            color: #909399;
-            font-weight: 500;
-          }
-
-          .meta-value {
-            color: #303133;
-            font-weight: 600;
-          }
-        }
-      }
-
-      .expand-btn-wrapper {
-        display: flex;
-        justify-content: center;
-        margin-top: 8px;
-
-        .expand-btn {
-          padding: 8px 20px;
-          border-radius: 20px;
-          background: linear-gradient(135deg, #ecf5ff 0%, #d9ecff 100%);
-          border: 1px solid #b3d8ff;
-          transition: all 0.3s ease;
-
-          .btn-text {
-            font-size: 13px;
-            font-weight: 500;
-            color: #409eff;
-            margin-right: 6px;
-          }
-
-          .expand-icon {
-            font-size: 14px;
-            color: #409eff;
-            transition: transform 0.3s ease;
-          }
-
-          &:hover {
-            background: linear-gradient(135deg, #409eff 0%, #66b1ff 100%);
-            border-color: #409eff;
-            box-shadow: 0 4px 12px rgba(64, 158, 255, 0.3);
-
-            .btn-text,
-            .expand-icon {
-              color: #fff;
-            }
-          }
-
-          &.expanded {
-            background: linear-gradient(135deg, #f0f9eb 0%, #e1f3d8 100%);
-            border-color: #a5d69a;
-
-            .btn-text,
-            .expand-icon {
-              color: #67c23a;
-            }
-
-            &:hover {
-              background: linear-gradient(135deg, #67c23a 0%, #85ce61 100%);
-              border-color: #67c23a;
-              box-shadow: 0 4px 12px rgba(103, 194, 58, 0.3);
-
-              .btn-text,
-              .expand-icon {
-                color: #fff;
-              }
-            }
-          }
-        }
-      }
-    }
-
-    .process-route {
-      padding: 0 20px 20px;
-      background: #f5f7fa;
-      border-top: 1px solid #ebeef5;
-
-      .process-flow {
-        display: flex;
-        align-items: flex-start;
-        gap: 8px;
-        padding: 20px 0;
-        overflow-x: auto;
-        overflow-y: hidden;
-
-        .process-flow-item {
-          display: flex;
-          align-items: center;
-          gap: 8px;
-
-          .process-node {
-            background: #fff;
-            border-radius: 12px;
-            padding: 16px;
-            border: 2px solid #ebeef5;
-            cursor: move;
-            transition: all 0.3s ease;
-            // min-width: 180px;
-            // max-width: 220px;
-            width: 300px;
-
-            &.expanded {
-              width: 400px;
-            }
-
-            &:hover {
-              box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
-              transform: translateY(-2px);
-              border-color: #409eff;
-            }
-
-            &:active {
-              cursor: grabbing;
-            }
-
-            .process-node-header {
-              display: flex;
-              justify-content: space-between;
-              align-items: center;
-              margin-bottom: 12px;
-
-              .process-number {
-                width: 28px;
-                height: 28px;
-                border-radius: 50%;
-                background: #409eff;
-                color: #ffffff;
-                font-size: 12px;
-                font-weight: 600;
-                display: flex;
-                align-items: center;
-                justify-content: center;
-              }
-
-              .process-actions {
-                display: flex;
-                gap: 4px;
-              }
-            }
-
-            .process-node-body {
-              text-align: center;
-              margin-bottom: 12px;
-
-              .process-code {
-                font-size: 11px;
-                color: #909399;
-                font-family: "Courier New", monospace;
-                margin-bottom: 4px;
-              }
-
-              .process-name {
-                font-size: 15px;
-                font-weight: 600;
-                color: #303133;
-                margin-bottom: 6px;
-              }
-
-              .process-desc {
-                font-size: 12px;
-                color: #606266;
-                overflow: hidden;
-                text-overflow: ellipsis;
-                display: -webkit-box;
-                -webkit-line-clamp: 2;
-                -webkit-box-orient: vertical;
-              }
-            }
-
-            .process-node-footer {
-              display: flex;
-              justify-content: flex-end;
-              align-items: center;
-              padding-top: 10px;
-              border-top: 1px solid #ebeef5;
-            }
-
-            .process-params-section {
-              margin-top: 12px;
-              padding-top: 12px;
-              border-top: 1px solid #ebeef5;
-
-              .params-header {
-                display: flex;
-                justify-content: space-between;
-                align-items: center;
-                margin-bottom: 8px;
-                font-size: 13px;
-                font-weight: 600;
-                color: #303133;
-              }
-
-              .params-list {
-                display: flex;
-                flex-direction: column;
-                gap: 6px;
-                max-height: 200px;
-                overflow-y: auto;
-
-                .param-item {
-                  display: flex;
-                  justify-content: space-between;
-                  align-items: center;
-                  padding: 6px 8px;
-                  background: #fafafa;
-                  border-radius: 4px;
-                  border-left: 2px solid #409eff;
-                  font-size: 12px;
-
-                  .param-info {
-                    display: flex;
-                    flex-direction: row;
-                    align-items: center;
-                    gap: 6px;
-                    flex: 1;
-                    min-width: 0;
-
-                    .param-code {
-                      font-size: 11px;
-                      color: #e6a23c;
-                      font-family: "Courier New", monospace;
-                      margin-right: 20px;
-                    }
-
-                    .param-name {
-                      font-size: 12px;
-                      color: #303133;
-                      font-weight: 500;
-                      margin-right: 20px;
-                    }
-
-                    .param-value {
-                      font-size: 11px;
-                      color: #606266;
-                    }
-                  }
-
-                  .param-actions {
-                    display: flex;
-                    gap: 4px;
-                    flex-shrink: 0;
-                  }
-                }
-              }
-            }
-          }
-
-          .flow-arrow {
-            display: flex;
-            align-items: center;
-            color: #c0c4cc;
-            font-size: 24px;
-            padding: 0 4px;
-
-            .el-icon {
-              font-size: 20px;
-            }
-          }
-        }
-
-        .add-process-node {
-          display: flex;
-          flex-direction: column;
-          align-items: center;
-          justify-content: center;
-          min-width: 100px;
-          height: 137px;
-          border: 2px dashed #dcdfe6;
-          border-radius: 12px;
-          background: #fafafa;
-          cursor: pointer;
-          transition: all 0.3s ease;
-          color: #909399;
-          // margin-left: 10px;
-
-          .el-icon {
-            font-size: 24px;
-            margin-bottom: 8px;
-          }
-
-          span {
-            font-size: 13px;
-          }
-
-          &:hover {
-            border-color: #409eff;
-            background: #ecf5ff;
-            color: #409eff;
-          }
-        }
-      }
-    }
-  }
-
-  // 鎷栨嫿鏃剁殑鏍峰紡
-  .process-flow-item.dragging {
-    opacity: 0.5;
-    transform: scale(0.98);
-  }
-
-  // 閫夋嫨宸ュ簭瀵硅瘽妗嗘牱寮�
-  .process-select-container {
-    display: flex;
-    gap: 20px;
-    height: 450px;
-
-    .process-list-area {
-      flex: 1;
-      display: flex;
-      flex-direction: column;
-
-      .area-title {
-        font-size: 14px;
-        font-weight: 600;
-        color: #303133;
-        margin-bottom: 12px;
-        padding-bottom: 8px;
-        border-bottom: 1px solid #ebeef5;
-      }
-
-      .search-box {
-        margin-bottom: 12px;
-
-        .el-input {
-          width: 100%;
-        }
-      }
-    }
-
-    .process-detail-area {
-      width: 380px;
-      display: flex;
-      flex-direction: column;
-      background: #f5f7fa;
-      border-radius: 8px;
-      padding: 16px;
-
-      .area-title {
-        font-size: 14px;
-        font-weight: 600;
-        color: #303133;
-        margin-bottom: 16px;
-        padding-bottom: 8px;
-        border-bottom: 1px solid #ebeef5;
-      }
-
-      .process-detail-form {
-        .el-form-item {
-          margin-bottom: 12px;
-
-          .el-form-item__label {
-            color: #606266;
-            font-weight: 500;
-          }
-        }
-
-        .detail-text {
-          color: #303133;
-          font-weight: 500;
-        }
-      }
-    }
-  }
-
-  // 閫夋嫨鍙傛暟瀵硅瘽妗嗘牱寮�
-  .param-select-container {
-    display: flex;
-    gap: 20px;
-    height: 450px;
-
-    .param-list-area {
-      // flex: 1;
-      width: 380px;
-      display: flex;
-      flex-direction: column;
-
-      .area-title {
-        font-size: 14px;
-        font-weight: 600;
-        color: #303133;
-        margin-bottom: 12px;
-        padding-bottom: 8px;
-        border-bottom: 1px solid #ebeef5;
-      }
-
-      .search-box {
-        margin-bottom: 12px;
-
-        .el-input {
-          width: 100%;
-        }
-      }
-    }
-
-    .param-detail-area {
-      // width: 380px;
-      flex: 1;
-      display: flex;
-      flex-direction: column;
-      background: #f5f7fa;
-      border-radius: 8px;
-      padding: 16px;
-
-      .area-title {
-        font-size: 14px;
-        font-weight: 600;
-        color: #303133;
-        margin-bottom: 16px;
-        padding-bottom: 8px;
-        border-bottom: 1px solid #ebeef5;
-      }
-
-      .param-detail-form {
-        .el-form-item {
-          margin-bottom: 12px;
-
-          .el-form-item__label {
-            color: #606266;
-            font-weight: 500;
-          }
-        }
-
-        .detail-text {
-          color: #303133;
-          font-weight: 500;
-        }
-      }
-    }
-  }
-
-  // 鍒嗛〉鎺т欢鏍峰紡
-  .pagination-container {
-    position: fixed;
-    bottom: 0;
-    left: 0;
-    right: 0;
-    display: flex;
-    justify-content: flex-end;
-    padding: 16px 20px;
-    background-color: #fff !important;
-    border-top: 1px solid #ebeef5;
-    box-shadow: 0 -2px 12px 0 rgba(0, 0, 0, 0.1);
-    z-index: 100;
-
-    .el-pagination {
-      .el-pagination__sizes {
-        margin-right: 16px;
-      }
-
-      .el-pagination__jump {
-        margin-left: 16px;
-      }
-
-      .el-pagination__total {
-        color: #606266;
-        font-size: 14px;
-      }
-
-      .el-pagination__button {
-        border-radius: 4px;
-        transition: all 0.3s ease;
-
-        &:hover:not(:disabled) {
-          color: #409eff;
-          border-color: #409eff;
-        }
-      }
-
-      .el-pagination__button--active {
-        background-color: #409eff;
-        border-color: #409eff;
-        color: #fff;
-      }
-    }
-  }
-</style>
+<style scoped></style>
diff --git a/src/views/productionManagement/processRoute/index2.vue b/src/views/productionManagement/processRoute/index2.vue
new file mode 100644
index 0000000..40ab129
--- /dev/null
+++ b/src/views/productionManagement/processRoute/index2.vue
@@ -0,0 +1,2417 @@
+<template>
+  <div class="app-container">
+    <div class="route-header">
+      <div class="add-route-btn"
+           @click="handleAddRoute">
+        <el-icon>
+          <Plus />
+        </el-icon>
+        <span>鏂板宸ヨ壓璺嚎</span>
+      </div>
+    </div>
+    <div class="route-card-list">
+      <div v-for="route in routeList"
+           :key="route.id"
+           class="route-card">
+        <div class="card-header">
+          <div class="route-info">
+            <span class="route-name"><el-icon style="margin-right: 8px;line-height: 30px;">
+                <ScaleToOriginal />
+              </el-icon>{{route.routeCode }}<el-tag style="margin-left: 8px"
+                      :type="!route.status ? 'warning' : 'success'">{{ !route.status ? '鑽夌' : '鎵瑰噯' }}</el-tag></span>
+            <!-- <span class="route-code">{{ route.routeCode }}</span> -->
+          </div>
+          <div class="route-actions">
+            <el-button v-if="!route.status"
+                       link
+                       type="success"
+                       @click="handleApproveRoute(route)">
+              <el-icon>
+                <Check />
+              </el-icon>
+              鎵瑰噯
+            </el-button>
+            <el-button v-if="route.status"
+                       link
+                       type="warning"
+                       @click="handleRevokeApproveRoute(route)">
+              <el-icon>
+                <Close />
+              </el-icon>
+              鎾ら攢鎵瑰噯
+            </el-button>
+            <el-button link
+                       type="primary"
+                       @click="handleEditRoute(route)">
+              <el-icon>
+                <Edit />
+              </el-icon>
+              缂栬緫
+            </el-button>
+            <el-button link
+                       type="danger"
+                       @click="handleDeleteRoute(route)">
+              <el-icon>
+                <Delete />
+              </el-icon>
+              鍒犻櫎
+            </el-button>
+          </div>
+        </div>
+        <div class="card-body">
+          <div class="route-meta">
+            <span class="meta-item">
+              <el-icon>
+                <Box />
+              </el-icon>
+              <span class="meta-label">浜у搧:</span>
+              <span class="meta-value">{{ route.productName }} - {{ route.productModelName }}</span>
+            </span>
+            <span class="meta-item">
+              <el-icon>
+                <Document />
+              </el-icon>
+              <span class="meta-label">BOM:</span>
+              <span class="meta-value">{{ route.bomNo || '-' }}</span>
+            </span>
+            <span class="meta-item">
+              <el-icon>
+                <Document />
+              </el-icon>
+              <span class="meta-label">澶囨敞:</span>
+              <span class="meta-value">{{ route.description || '鏆傛棤鎻忚堪' }}</span>
+            </span>
+          </div>
+          <div class="expand-btn-wrapper">
+            <el-button class="expand-btn"
+                       :class="{ expanded: route.expanded }"
+                       type="primary"
+                       text
+                       @click="toggleExpand(route)">
+              <span class="btn-text">{{ route.expanded ? '鏀惰捣宸ュ簭璺嚎' : '灞曞紑宸ュ簭璺嚎' }}</span>
+              <el-icon class="expand-icon">
+                <component :is="route.expanded ? 'ArrowUp' : 'ArrowDown'" />
+              </el-icon>
+            </el-button>
+          </div>
+        </div>
+        <div v-if="route.expanded"
+             class="process-route">
+          <div class="process-flow">
+            <div v-for="(process, index) in route.processList"
+                 :key="process.id"
+                 class="process-flow-item"
+                 draggable="true"
+                 @dragstart="handleDragStart($event, index, route.id)"
+                 @dragover="handleDragOver($event)"
+                 @drop="handleDrop($event, index, route.id)"
+                 @dragend="handleDragEnd">
+              <div class="process-node"
+                   :class="{ expanded: process.expanded }">
+                <div class="process-node-header">
+                  <div class="process-number">{{ index + 1 }}</div>
+                  <div class="process-actions">
+                    <el-button link
+                               type="primary"
+                               @click="handleEditProcessSelect(route, index, process)">
+                      <el-icon>
+                        <Edit />
+                      </el-icon>
+                    </el-button>
+                    <el-button link
+                               type="danger"
+                               @click="handleDeleteProcess(route.id, process)">
+                      <el-icon>
+                        <Delete />
+                      </el-icon>
+                    </el-button>
+                  </div>
+                </div>
+                <div class="process-node-body">
+                  <!-- <div class="process-code">{{ process.processId }}</div> -->
+                  <div class="process-name">{{ process.processName }}</div>
+                  <!-- <div class="process-desc">{{ process.remark || '鏆傛棤鎻忚堪' }}</div> -->
+                </div>
+                <div class="process-node-footer">
+                  <!-- <el-tag size="small"
+                          :type="process.status === '1' ? 'success' : 'info'">
+                    {{ process.status === '1' ? '鍚敤' : '鍋滅敤' }}
+                  </el-tag> -->
+                  <el-button type="primary"
+                             link
+                             size="small"
+                             @click="toggleProcessParams(process)">
+                    {{ process.expanded ? '鏀惰捣鍙傛暟' : '灞曞紑鍙傛暟' }}
+                    ({{ process.paramCount }})
+                  </el-button>
+                </div>
+                <div v-if="process.expanded"
+                     class="process-params-section">
+                  <div class="params-header">
+                    <span>鍙傛暟鍒楄〃</span>
+                    <el-button type="primary"
+                               link
+                               size="small"
+                               @click="handleAddParam(route.id, process)">
+                      <el-icon>
+                        <Plus />
+                      </el-icon>鏂板
+                    </el-button>
+                  </div>
+                  <div class="params-list">
+                    <div v-for="param in process.paramList"
+                         :key="param.id"
+                         class="param-item">
+                      <div class="param-info">
+                        <span class="param-code">{{ param.paramName }}</span>
+                        <!-- <span class="param-name">{{ param.paramName }}</span> -->
+                        <!-- <el-tag size="small"
+                                style="margin-right: 20px;"
+                                :type="getParamTypeTag(param.parameterType)">
+                          {{ param.parameterType }}
+                        </el-tag> -->
+                        <span v-if="param.valueMode==1"
+                              class="param-value">鏍囧噯鍊硷細{{ param.standardValue || "-" }} {{ param.unit }}</span>
+                        <span v-else
+                              class="param-value">鏍囧噯鍊硷細{{ param.minValue || "-" }}-{{ param.maxValue || "-" }} {{ param.unit }}</span>
+                      </div>
+                      <div class="param-actions">
+                        <el-button link
+                                   type="primary"
+                                   size="small"
+                                   @click="handleEditParam(route.id, process, param)">
+                          缂栬緫
+                        </el-button>
+                        <el-button link
+                                   type="danger"
+                                   size="small"
+                                   @click="handleDeleteParam(route.id, process, param)">
+                          鍒犻櫎
+                        </el-button>
+                      </div>
+                    </div>
+                    <el-empty v-if="!process.paramList || process.paramList.length === 0"
+                              description="鏆傛棤鍙傛暟"
+                              :image-size="50" />
+                  </div>
+                </div>
+              </div>
+              <div v-if="index < route.processList.length - 1"
+                   class="flow-arrow">
+                <el-icon>
+                  <Right />
+                </el-icon>
+              </div>
+            </div>
+            <div class="add-process-node"
+                 @click="handleSelectProcess(route, index)">
+              <el-icon>
+                <Plus />
+              </el-icon>
+              <span>鏂板宸ュ簭</span>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <!-- 鍒嗛〉鎺т欢 -->
+    <div class="pagination-container">
+      <el-pagination v-model:current-page="routePage.current"
+                     v-model:page-size="routePage.size"
+                     :page-sizes="[10, 20, 50, 100]"
+                     layout="total, sizes, prev, pager, next, jumper"
+                     :total="routePage.total"
+                     @size-change="handleRouteSizeChange"
+                     @current-change="handleRouteCurrentChange" />
+    </div>
+    <!-- 宸ヨ壓璺嚎鏂板/缂栬緫瀵硅瘽妗� -->
+    <el-dialog v-model="routeDialogVisible"
+               :title="isRouteEdit ? '缂栬緫宸ヨ壓璺嚎' : '鏂板宸ヨ壓璺嚎'"
+               width="500px">
+      <el-form :model="routeForm"
+               :rules="routeRules"
+               ref="routeFormRef"
+               label-width="120px">
+        <el-form-item label="浜у搧鍚嶇О"
+                      prop="productModelId">
+          <el-button type="primary"
+                     @click="handleProcessProductSelectClick2">
+            {{ routeForm.productName && routeForm.productModelName 
+              ? `${routeForm.productName} - ${routeForm.productModelName}` 
+              : '閫夋嫨浜у搧' }}
+          </el-button>
+        </el-form-item>
+        <el-form-item label="BOM"
+                      prop="bomId">
+          <el-select v-model="routeForm.bomId"
+                     placeholder="璇烽�夋嫨BOM"
+                     clearable
+                     :disabled="!routeForm.productModelId || bomOptions.length === 0"
+                     style="width: 100%">
+            <el-option v-for="item in bomOptions"
+                       :key="item.id"
+                       :label="item.bomNo || `BOM-${item.id}`"
+                       :value="item.id" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="璺嚎缂栫爜"
+                      prop="routeCode">
+          <el-input v-model="routeForm.routeCode"
+                    disabled
+                    placeholder="鑷姩鐢熸垚" />
+        </el-form-item>
+        <el-form-item label="澶囨敞"
+                      prop="description">
+          <el-input v-model="routeForm.description"
+                    type="textarea"
+                    :rows="3"
+                    placeholder="璇疯緭鍏ヨ矾绾挎弿杩�" />
+        </el-form-item>
+        <!-- <el-form-item label="鐘舵��"
+                      prop="status">
+          <el-radio-group v-model="routeForm.status">
+            <el-radio label="1">鍚敤</el-radio>
+            <el-radio label="0">鍋滅敤</el-radio>
+          </el-radio-group>
+        </el-form-item> -->
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="routeDialogVisible = false">鍙栨秷</el-button>
+          <el-button type="primary"
+                     @click="handleRouteSubmit">纭畾</el-button>
+        </span>
+      </template>
+    </el-dialog>
+    <!-- 浜у搧閫夋嫨寮圭獥 -->
+    <ProductSelectDialog v-model="showProductSelectDialog"
+                         @confirm="handleProductSelect"
+                         single />
+    <!-- 宸ュ簭鏂板/缂栬緫瀵硅瘽妗� -->
+    <el-dialog v-model="processDialogVisible"
+               :title="isProcessEdit ? '缂栬緫宸ュ簭' : '鏂板宸ュ簭'"
+               width="500px">
+      <el-form :model="processForm"
+               :rules="processRules"
+               ref="processFormRef"
+               label-width="120px">
+        <el-form-item label="宸ュ簭缂栫爜"
+                      prop="no">
+          <el-input v-model="processForm.no"
+                    placeholder="璇疯緭鍏ュ伐搴忕紪鐮�" />
+        </el-form-item>
+        <el-form-item label="宸ュ簭鍚嶇О"
+                      prop="name">
+          <el-input v-model="processForm.name"
+                    placeholder="璇疯緭鍏ュ伐搴忓悕绉�" />
+        </el-form-item>
+        <el-form-item label="宸ュ簭鎻忚堪"
+                      prop="remark">
+          <el-input v-model="processForm.remark"
+                    type="textarea"
+                    :rows="3"
+                    placeholder="璇疯緭鍏ュ伐搴忔弿杩�" />
+        </el-form-item>
+        <el-form-item label="鐘舵��"
+                      prop="status">
+          <el-radio-group v-model="processForm.status">
+            <el-radio :label="true">鍚敤</el-radio>
+            <el-radio :label="false">鍋滅敤</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="processDialogVisible = false">鍙栨秷</el-button>
+          <el-button type="primary"
+                     @click="handleProcessSubmit">纭畾</el-button>
+        </span>
+      </template>
+    </el-dialog>
+    <!-- 閫夋嫨宸ュ簭瀵硅瘽妗� -->
+    <el-dialog v-model="selectProcessDialogVisible"
+               title="閫夋嫨宸ュ簭"
+               width="1000px">
+      <div class="process-select-container">
+        <!-- 宸︿晶宸ュ簭鍒楄〃 -->
+        <div class="process-list-area">
+          <div class="area-title">鍙�夊伐搴�</div>
+          <div class="search-box">
+            <el-input v-model="processSearchKeyword"
+                      placeholder="璇疯緭鍏ュ伐搴忓悕绉版悳绱�"
+                      clearable
+                      size="small"
+                      @input="handleProcessSearch">
+              <template #prefix>
+                <el-icon>
+                  <Search />
+                </el-icon>
+              </template>
+            </el-input>
+          </div>
+          <el-table :data="filteredProcessList"
+                    height="360"
+                    border
+                    highlight-current-row
+                    @current-change="handleProcessSelect">
+            <el-table-column prop="no"
+                             label="宸ュ簭缂栧彿"
+                             width="100" />
+            <el-table-column prop="name"
+                             label="宸ュ簭鍚嶇О" />
+            <el-table-column prop="remark"
+                             label="宸ュ簭鎻忚堪" />
+            <el-table-column prop="status"
+                             label="鐘舵��"
+                             width="80">
+              <template #default="scope">
+                <el-tag size="small"
+                        :type="scope.row.status ? 'success' : 'info'">
+                  {{ scope.row.status ? '鍚敤' : '鍋滅敤' }}
+                </el-tag>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+        <!-- 鍙充晶宸ュ簭璇︽儏 -->
+        <div class="process-detail-area">
+          <div class="area-title">宸ュ簭璇︽儏</div>
+          <el-form v-if="selectedProcessItem"
+                   :model="processForm"
+                   label-width="100px"
+                   class="process-detail-form">
+            <el-form-item label="宸ュ簭缂栧彿">
+              <span class="detail-text">{{ selectedProcessItem.no }}</span>
+            </el-form-item>
+            <el-form-item label="宸ュ簭鍚嶇О">
+              <span class="detail-text">{{ selectedProcessItem.name }}</span>
+            </el-form-item>
+            <el-form-item label="宸ュ簭鎻忚堪">
+              <span class="detail-text">{{ selectedProcessItem.remark || '-' }}</span>
+            </el-form-item>
+            <el-form-item label="鐘舵��">
+              <el-tag size="small"
+                      :type="selectedProcessItem.status ? 'success' : 'info'">
+                {{ selectedProcessItem.status ? '鍚敤' : '鍋滅敤' }}
+              </el-tag>
+            </el-form-item>
+            <el-form-item label="鏄惁璐ㄦ">
+              <el-tag size="small"
+                      :type="selectedProcessItem.isQuality ? 'success' : 'info'">
+                {{ selectedProcessItem.isQuality ? '璐ㄦ' : '闈炶川妫�' }}
+              </el-tag>
+            </el-form-item>
+            <el-form-item label="浜у搧鍚嶇О"
+                          prop="productModelId">
+              <el-button type="primary"
+                         @click="handleProcessProductSelectClick">
+                {{ processForm.productName && processForm.model 
+                  ? `${processForm.productName} - ${processForm.model}` 
+                  : '閫夋嫨浜у搧' }}
+              </el-button>
+            </el-form-item>
+            <el-form-item label="鍗曚綅"
+                          prop="unit">
+              <el-input v-model="processForm.unit"
+                        :placeholder="processForm.productModelId ? '鏍规嵁閫夋嫨鐨勪骇鍝佽嚜鍔ㄥ甫鍑�' : '璇峰厛閫夋嫨浜у搧' "
+                        clearable
+                        :disabled="true" />
+            </el-form-item>
+            <el-form-item label="鏄惁璐ㄦ"
+                          prop="isQuality">
+              <el-switch v-model="processForm.isQuality"
+                         :active-value="true"
+                         inactive-value="false" />
+            </el-form-item>
+          </el-form>
+          <el-empty v-else
+                    description="璇蜂粠宸︿晶閫夋嫨宸ュ簭" />
+        </div>
+      </div>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="selectProcessDialogVisible = false">鍙栨秷</el-button>
+          <el-button type="primary"
+                     :disabled="!selectedProcessItem || !processForm.productModelId"
+                     @click="handleProcessSelectSubmit">纭畾</el-button>
+        </span>
+      </template>
+    </el-dialog>
+    <!-- 鍙傛暟鏂板/缂栬緫瀵硅瘽妗� -->
+    <el-dialog v-model="paramDialogVisible"
+               :title="isParamEdit ? '缂栬緫鍙傛暟' : '鏂板鍙傛暟'"
+               width="500px">
+      <el-form :model="paramForm"
+               :rules="paramRules"
+               ref="paramFormRef"
+               label-width="120px">
+        <el-form-item label="鍙傛暟缂栧彿"
+                      prop="parameterCode">
+          <el-input v-model="paramForm.parameterCode"
+                    placeholder="璇疯緭鍏ュ弬鏁扮紪鍙�" />
+        </el-form-item>
+        <el-form-item label="鍙傛暟鍚嶇О"
+                      prop="parameterName">
+          <el-input v-model="paramForm.parameterName"
+                    placeholder="璇疯緭鍏ュ弬鏁板悕绉�" />
+        </el-form-item>
+        <el-form-item label="鍙傛暟妯″紡"
+                      prop="parameterType2">
+          <el-select v-model="paramForm.parameterType2"
+                     placeholder="璇烽�夋嫨鍙傛暟妯″紡">
+            <el-option label="鍗曞��"
+                       value="1" />
+            <el-option label="鍖洪棿"
+                       value="2" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="鍙傛暟绫诲瀷"
+                      prop="parameterType">
+          <el-select v-model="paramForm.parameterType"
+                     @change="handleParamTypeChange"
+                     placeholder="璇烽�夋嫨鍙傛暟绫诲瀷">
+            <el-option label="鏁板�兼牸寮�"
+                       value="鏁板�兼牸寮�" />
+            <el-option label="鏂囨湰鏍煎紡"
+                       value="鏂囨湰鏍煎紡" />
+            <el-option label="涓嬫媺閫夐」"
+                       value="涓嬫媺閫夐」" />
+            <el-option label="鏃堕棿鏍煎紡"
+                       value="鏃堕棿鏍煎紡" />
+          </el-select>
+        </el-form-item>
+        <el-form-item v-if="paramForm.parameterType === '涓嬫媺閫夐」'"
+                      label="鏁版嵁瀛楀吀"
+                      prop="parameterFormat">
+          <el-select v-model="paramForm.parameterFormat"
+                     placeholder="璇烽�夋嫨鏁版嵁瀛楀吀">
+            <el-option v-for="item in dictTypes"
+                       :key="item.dictType"
+                       :label="item.dictName"
+                       :value="item.dictType" />
+          </el-select>
+        </el-form-item>
+        <el-form-item v-else-if="paramForm.parameterType === '鏃堕棿鏍煎紡'"
+                      label="鏃堕棿鏍煎紡"
+                      prop="parameterFormat">
+          <el-select v-model="paramForm.parameterFormat"
+                     placeholder="璇烽�夋嫨鏃堕棿鏍煎紡">
+            <el-option label="YYYY-MM-DD HH:mm:ss"
+                       value="YYYY-MM-DD HH:mm:ss" />
+            <el-option label="YYYY-MM-DD"
+                       value="YYYY-MM-DD" />
+          </el-select>
+        </el-form-item>
+        <el-form-item v-else
+                      label="鍙傛暟鏍煎紡"
+                      prop="parameterFormat">
+          <el-input v-model="paramForm.parameterFormat"
+                    placeholder="璇疯緭鍏ュ弬鏁版牸寮�" />
+        </el-form-item>
+        <el-form-item label="鏍囧噯鍊�"
+                      prop="standardValue">
+          <el-input v-model="paramForm.standardValue"
+                    placeholder="璇疯緭鍏ユ爣鍑嗗��" />
+        </el-form-item>
+        <el-form-item label="鍗曚綅"
+                      prop="unit">
+          <el-input v-model="paramForm.unit"
+                    placeholder="璇疯緭鍏ュ崟浣�" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="paramDialogVisible = false">鍙栨秷</el-button>
+          <el-button type="primary"
+                     @click="handleParamSubmit">纭畾</el-button>
+        </span>
+      </template>
+    </el-dialog>
+    <!-- 閫夋嫨鍙傛暟瀵硅瘽妗� -->
+    <el-dialog v-model="selectParamDialogVisible"
+               title="閫夋嫨鍙傛暟"
+               width="1000px">
+      <div class="param-select-container">
+        <!-- 宸︿晶鍙傛暟鍒楄〃 -->
+        <div class="param-list-area">
+          <div class="area-title">鍙�夊弬鏁�</div>
+          <div class="search-box">
+            <el-input v-model="paramSearchKeyword"
+                      placeholder="璇疯緭鍏ュ弬鏁板悕绉版悳绱�"
+                      clearable
+                      size="small"
+                      @input="handleParamSearch">
+              <template #prefix>
+                <el-icon>
+                  <Search />
+                </el-icon>
+              </template>
+            </el-input>
+          </div>
+          <el-table :data="filteredParamList"
+                    height="300"
+                    border
+                    highlight-current-row
+                    @current-change="handleParamSelect">
+            <el-table-column prop="paramName"
+                             label="鍙傛暟鍚嶇О" />
+            <el-table-column prop="paramType"
+                             label="鍙傛暟绫诲瀷">
+              <template #default="scope">
+                <el-tag size="small"
+                        :type="getParamTypeTag(scope.row.paramType)">
+                  {{ getParamTypeText(scope.row.paramType) }}
+                </el-tag>
+              </template>
+            </el-table-column>
+          </el-table>
+          <!-- 鍒嗛〉鎺т欢 -->
+          <div class="pagination-container"
+               style="margin-top: 10px;">
+            <el-pagination v-model:current-page="paramPage.current"
+                           v-model:page-size="paramPage.size"
+                           :page-sizes="[10, 20, 50, 100]"
+                           layout="total, sizes, prev, pager, next, jumper"
+                           :total="paramPage.total"
+                           @size-change="handleParamSizeChange"
+                           @current-change="handleParamCurrentChange"
+                           size="small" />
+          </div>
+        </div>
+        <!-- 鍙充晶鍙傛暟璇︽儏 -->
+        <div class="param-detail-area">
+          <div class="area-title">鍙傛暟璇︽儏</div>
+          <el-form v-if="selectedParam"
+                   :model="selectedParam"
+                   label-width="100px"
+                   class="param-detail-form">
+            <el-form-item label="鍙傛暟鍚嶇О">
+              <span class="detail-text">{{ selectedParam.paramName }}</span>
+            </el-form-item>
+            <el-form-item label="鍙傛暟妯″紡">
+              <el-tag size="small"
+                      :type="selectedParam.valueMode == '1' ? 'success' : 'warning'">
+                {{ selectedParam.valueMode == '1' ? '鍗曞��' : '鍖洪棿' }}
+              </el-tag>
+            </el-form-item>
+            <el-form-item label="鍙傛暟绫诲瀷">
+              <el-tag size="small"
+                      :type="getParamTypeTag(selectedParam.paramType)">
+                {{ getParamTypeText(selectedParam.paramType) }}
+              </el-tag>
+            </el-form-item>
+            <el-form-item label="鍙傛暟鏍煎紡">
+              <span class="detail-text">{{ selectedParam.paramFormat || '-' }}</span>
+            </el-form-item>
+            <el-form-item label="鍗曚綅">
+              <span class="detail-text">{{ selectedParam.unit || '-' }}</span>
+            </el-form-item>
+            <el-form-item label="鏍囧噯鍊�"
+                          v-if="selectedParam.valueMode == '1' && selectedParam.paramType == '1'">
+              <el-input v-model="selectedParam.standardValue"
+                        type="number"
+                        placeholder="璇疯緭鍏ラ粯璁ゅ��" />
+            </el-form-item>
+            <el-form-item label="鏈�灏忓��"
+                          v-if="selectedParam.valueMode == '2' && selectedParam.paramType == '1'">
+              <el-input v-model="selectedParam.minValue"
+                        type="number"
+                        placeholder="璇疯緭鍏ユ渶灏忓��" />
+            </el-form-item>
+            <el-form-item label="鏈�澶у��"
+                          v-if="selectedParam.valueMode == '2' && selectedParam.paramType == '1'">
+              <el-input v-model="selectedParam.maxValue"
+                        type="number"
+                        placeholder="璇疯緭鍏ユ渶澶у��" />
+            </el-form-item>
+            <el-form-item label="鎺掑簭">
+              <el-input v-model="selectedParam.sort"
+                        type="number"
+                        placeholder="璇疯緭鍏ユ帓搴�" />
+            </el-form-item>
+            <el-form-item label="鏄惁蹇呭~">
+              <el-switch v-model="selectedParam.isRequired"
+                         :active-value="1"
+                         :inactive-value="0" />
+            </el-form-item>
+          </el-form>
+          <el-empty v-else
+                    description="璇蜂粠宸︿晶閫夋嫨鍙傛暟" />
+        </div>
+      </div>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="selectParamDialogVisible = false">鍙栨秷</el-button>
+          <el-button type="primary"
+                     :disabled="!selectedParam"
+                     @click="handleParamSelectSubmit">纭畾</el-button>
+        </span>
+      </template>
+    </el-dialog>
+    <!-- 缂栬緫鍙傛暟瀵硅瘽妗� -->
+    <el-dialog v-model="editParamDialogVisible"
+               title="缂栬緫鍙傛暟"
+               width="600px">
+      <el-form :model="editParamForm"
+               :rules="editParamRules"
+               ref="editParamFormRef"
+               label-width="120px">
+        <el-form-item label="鍙傛暟鍚嶇О">
+          <span class="detail-text">{{ editParamForm.paramName }}</span>
+        </el-form-item>
+        <el-form-item label="鍙傛暟妯″紡">
+          <el-tag size="small"
+                  :type="editParamForm.valueMode == '1' ? 'success' : 'warning'">
+            {{ editParamForm.valueMode == '1' ? '鍗曞��' : '鍖洪棿' }}
+          </el-tag>
+        </el-form-item>
+        <el-form-item label="鍙傛暟绫诲瀷">
+          <el-tag size="small"
+                  :type="getParamTypeTag(editParamForm.paramType)">
+            {{ getParamTypeText(editParamForm.paramType) }}
+          </el-tag>
+        </el-form-item>
+        <el-form-item label="鍙傛暟鏍煎紡">
+          <span class="detail-text">{{ editParamForm.paramFormat || '-' }}</span>
+        </el-form-item>
+        <el-form-item label="鍗曚綅">
+          <span class="detail-text">{{ editParamForm.unit || '-' }}</span>
+        </el-form-item>
+        <el-form-item label="鏍囧噯鍊�"
+                      v-if="editParamForm.valueMode == '1' && editParamForm.paramType == '1'"
+                      prop="standardValue">
+          <el-input v-model="editParamForm.standardValue"
+                    type="number"
+                    placeholder="璇疯緭鍏ユ爣鍑嗗��" />
+        </el-form-item>
+        <el-form-item label="鏈�灏忓��"
+                      v-if="editParamForm.valueMode == '2' && editParamForm.paramType == '1'"
+                      prop="minValue">
+          <el-input v-model="editParamForm.minValue"
+                    type="number"
+                    placeholder="璇疯緭鍏ユ渶灏忓��" />
+        </el-form-item>
+        <el-form-item label="鏈�澶у��"
+                      v-if="editParamForm.valueMode == '2' && editParamForm.paramType == '1'"
+                      prop="maxValue">
+          <el-input v-model="editParamForm.maxValue"
+                    type="number"
+                    placeholder="璇疯緭鍏ユ渶澶у��" />
+        </el-form-item>
+        <el-form-item label="鎺掑簭"
+                      prop="sort">
+          <el-input v-model="editParamForm.sort"
+                    type="number"
+                    placeholder="璇疯緭鍏ユ帓搴�" />
+        </el-form-item>
+        <el-form-item label="鏄惁蹇呭~"
+                      prop="isRequired">
+          <el-switch v-model="editParamForm.isRequired"
+                     :active-value="1"
+                     :inactive-value="0" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="editParamDialogVisible = false">鍙栨秷</el-button>
+          <el-button type="primary"
+                     @click="handleEditParamSubmit">纭畾</el-button>
+        </span>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+  import { ref, reactive, getCurrentInstance, onMounted } from "vue";
+  import { ElMessage, ElMessageBox } from "element-plus";
+  import {
+    Plus,
+    Edit,
+    Delete,
+    ArrowUp,
+    ArrowDown,
+    Right,
+    Search,
+    Check,
+    Close,
+    Box,
+    Document,
+  } from "@element-plus/icons-vue";
+  import { listType } from "@/api/system/dict/type";
+  import { getByModel } from "@/api/productionManagement/productBom.js";
+  import { add, update, del } from "@/api/productionManagement/processRoute.js";
+  import {
+    addOrUpdateProcessRouteItem,
+    batchDeleteProcessRouteItem,
+    sortProcessRouteItem,
+    findProcessRouteItemList,
+    getProcessParamList,
+    addProcessRouteItemParam,
+    editProcessRouteItemParam,
+    delProcessRouteItemParam,
+  } from "@/api/productionManagement/processRouteItem.js";
+  import { list as getProcessListApi } from "@/api/productionManagement/productionProcess.js";
+  import { getBaseParamList } from "@/api/basicData/parameterMaintenance.js";
+  import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
+
+  // 宸ヨ壓璺嚎鍒楄〃
+  const routeList = ref([]);
+  const dictTypes = ref([]);
+
+  // 宸ヨ壓璺嚎鍒嗛〉
+  const routePage = reactive({
+    current: 1,
+    size: 10,
+    total: 0,
+  });
+
+  // 鑾峰彇鍏ㄥ眬瀹炰緥
+  const { proxy } = getCurrentInstance();
+
+  // 浜у搧閫夋嫨鍜孊OM鐩稿叧
+  const showProductSelectDialog = ref(false);
+  const bomOptions = ref([]);
+
+  // 宸ヨ壓璺嚎瀵硅瘽妗�
+  const routeDialogVisible = ref(false);
+  const isRouteEdit = ref(false);
+  const routeFormRef = ref(null);
+  const routeForm = reactive({
+    id: null,
+    productModelId: null,
+    productName: "",
+    productModelName: "",
+    bomId: null,
+    routeCode: "",
+    description: "",
+    status: true,
+  });
+  const routeRules = {
+    productModelId: [
+      { required: true, message: "璇烽�夋嫨浜у搧", trigger: "change" },
+    ],
+    bomId: [{ required: true, message: "璇烽�夋嫨BOM", trigger: "change" }],
+  };
+
+  // 宸ュ簭瀵硅瘽妗�
+  const processDialogVisible = ref(false);
+  const isProcessEdit = ref(false);
+  const processFormRef = ref(null);
+  const currentRouteId = ref(null);
+  const processForm = reactive({
+    id: null,
+    no: "",
+    name: "",
+    remark: "",
+    status: true,
+  });
+  const processRules = {
+    no: [{ required: true, message: "璇疯緭鍏ュ伐搴忕紪鐮�", trigger: "blur" }],
+    name: [{ required: true, message: "璇疯緭鍏ュ伐搴忓悕绉�", trigger: "blur" }],
+  };
+
+  // 閫夋嫨宸ュ簭瀵硅瘽妗�
+  const selectProcessDialogVisible = ref(false);
+  const availableProcessList = ref([]);
+  const filteredProcessList = ref([]);
+  const selectedProcessItem = ref(null);
+  const processSearchKeyword = ref("");
+  const currentRouteIndex = ref(null);
+
+  // 鍙傛暟瀵硅瘽妗�
+  const paramDialogVisible = ref(false);
+  const isParamEdit = ref(false);
+  const paramFormRef = ref(null);
+  const currentProcessId = ref(null);
+  const paramForm = reactive({
+    id: null,
+    parameterCode: "",
+    parameterName: "",
+    parameterType2: "1",
+    parameterType: "",
+    parameterFormat: "",
+    standardValue: "",
+    unit: "",
+  });
+  const paramRules = {
+    parameterCode: [
+      { required: true, message: "璇疯緭鍏ュ弬鏁扮紪鍙�", trigger: "blur" },
+    ],
+    parameterName: [
+      { required: true, message: "璇疯緭鍏ュ弬鏁板悕绉�", trigger: "blur" },
+    ],
+    parameterType: [
+      { required: true, message: "璇烽�夋嫨鍙傛暟绫诲瀷", trigger: "change" },
+    ],
+  };
+
+  // 閫夋嫨鍙傛暟瀵硅瘽妗�
+  const selectParamDialogVisible = ref(false);
+  const availableParamList = ref([]);
+  const filteredParamList = ref([]);
+  const selectedParam = ref(null);
+  const paramSearchKeyword = ref("");
+
+  // 鍙�夊弬鏁板垎椤�
+  const paramPage = reactive({
+    current: 1,
+    size: 10,
+    total: 0,
+  });
+
+  // 缂栬緫鍙傛暟瀵硅瘽妗�
+  const editParamDialogVisible = ref(false);
+  const editParamFormRef = ref(null);
+  const editParamForm = reactive({
+    id: null,
+    processId: null,
+    paramId: null,
+    paramName: "",
+    valueMode: "1",
+    standardValue: null,
+    minValue: null,
+    maxValue: null,
+    sort: 1,
+    isRequired: 0,
+  });
+  const editParamRules = reactive({
+    standardValue: [
+      {
+        required: true,
+        message: "璇疯緭鍏ユ爣鍑嗗��",
+        trigger: "blur",
+        validator: (rule, value, callback) => {
+          if (value === null || value === undefined || value === "") {
+            callback(new Error("璇疯緭鍏ユ爣鍑嗗��"));
+          } else {
+            callback();
+          }
+        },
+      },
+    ],
+    minValue: [
+      {
+        required: true,
+        message: "璇疯緭鍏ユ渶灏忓��",
+        trigger: "blur",
+        validator: (rule, value, callback) => {
+          if (value === null || value === undefined || value === "") {
+            callback(new Error("璇疯緭鍏ユ渶灏忓��"));
+          } else {
+            callback();
+          }
+        },
+      },
+    ],
+    maxValue: [
+      {
+        required: true,
+        message: "璇疯緭鍏ユ渶澶у��",
+        trigger: "blur",
+        validator: (rule, value, callback) => {
+          if (value === null || value === undefined || value === "") {
+            callback(new Error("璇疯緭鍏ユ渶澶у��"));
+          } else {
+            callback();
+          }
+        },
+      },
+    ],
+    sort: [
+      {
+        required: true,
+        message: "璇疯緭鍏ユ帓搴�",
+        trigger: "blur",
+        validator: (rule, value, callback) => {
+          if (value === null || value === undefined || value === "") {
+            callback(new Error("璇疯緭鍏ユ帓搴�"));
+          } else if (isNaN(value) || value < 1) {
+            callback(new Error("鎺掑簭蹇呴』鏄ぇ浜�0鐨勬暣鏁�"));
+          } else {
+            callback();
+          }
+        },
+      },
+    ],
+  });
+
+  // 鎷栨嫿鐩稿叧
+  const draggedItem = ref(null);
+  const draggedRouteId = ref(null);
+
+  // 鑾峰彇宸ヨ壓璺嚎鍒楄〃
+  const getRouteList = () => {
+    // 瀵煎叆 listPage 鏂规硶
+    import("@/api/productionManagement/processRoute.js").then(({ listPage }) => {
+      listPage({ pageNum: routePage.current, pageSize: routePage.size })
+        .then(res => {
+          // 澶勭悊杩斿洖鐨勬暟鎹紝鏄犲皠鍒伴〉闈㈤渶瑕佺殑鏍煎紡
+          routeList.value = (res.data?.records || []).map(item => ({
+            id: item.id,
+            productModelId: item.productModelId,
+            productName: item.productName,
+            productModelName: item.model || item.productModelName,
+            bomId: item.bomId,
+            bomNo: item.bomNo,
+            routeCode: item.processRouteCode || item.routeCode,
+            description: item.description || item.description,
+            status: item.status,
+            expanded: false,
+            processList: (item.processList || []).map(process => ({
+              ...process,
+              processId: process.processId || process.id,
+              expanded: false,
+            })),
+          }));
+          // 鏇存柊鍒嗛〉鎬绘暟
+          routePage.total = res.data?.total || 0;
+        })
+        .catch(err => {
+          console.error("鑾峰彇宸ヨ壓璺嚎鍒楄〃澶辫触锛�", err);
+          routeList.value = [];
+          routePage.total = 0;
+        });
+    });
+  };
+
+  // 灞曞紑/鏀惰捣宸ヨ壓璺嚎
+  const toggleExpand = route => {
+    route.expanded = !route.expanded;
+    if (route.expanded) {
+      // 璋冪敤鎺ュ彛鑾峰彇宸ュ簭鍒楄〃
+      findProcessRouteItemList({ routeId: route.id })
+        .then(res => {
+          route.processList = (res.data || []).map(process => ({
+            ...process,
+            processId: process.processId || process.id,
+            expanded: false,
+          }));
+        })
+        .catch(err => {
+          console.error("鑾峰彇宸ュ簭鍒楄〃澶辫触锛�", err);
+          route.processList = [];
+        });
+    }
+  };
+
+  // 灞曞紑/鏀惰捣宸ュ簭鍙傛暟
+  const toggleProcessParams = process => {
+    process.expanded = !process.expanded;
+    if (process.expanded && process.id) {
+      // 璋冪敤鎺ュ彛鑾峰彇鍙傛暟鍒楄〃
+      getProcessParamList({
+        routeItemId: process.id,
+        pageNum: 1,
+        pageSize: 1000,
+      })
+        .then(res => {
+          if (res.code === 200) {
+            process.paramList = res.data?.records || [];
+            process.paramCount = process.paramList.length;
+          } else {
+            ElMessage.error(res.msg || "鑾峰彇鍙傛暟鍒楄〃澶辫触");
+            process.paramList = [];
+            process.paramCount = 0;
+          }
+        })
+        .catch(err => {
+          console.error("鑾峰彇鍙傛暟鍒楄〃澶辫触锛�", err);
+          ElMessage.error("鑾峰彇鍙傛暟鍒楄〃澶辫触");
+          process.paramList = [];
+          process.paramCount = 0;
+        });
+    }
+  };
+  const toggleProcessParams2 = process => {
+    if (process.expanded && process.id) {
+      // 璋冪敤鎺ュ彛鑾峰彇鍙傛暟鍒楄〃
+      getProcessParamList({
+        routeItemId: process.id,
+        pageNum: 1,
+        pageSize: 1000,
+      })
+        .then(res => {
+          if (res.code === 200) {
+            process.paramList = res.data?.records || [];
+            process.paramCount = process.paramList.length;
+          } else {
+            ElMessage.error(res.msg || "鑾峰彇鍙傛暟鍒楄〃澶辫触");
+            process.paramList = [];
+            process.paramCount = 0;
+          }
+        })
+        .catch(err => {
+          console.error("鑾峰彇鍙傛暟鍒楄〃澶辫触锛�", err);
+          ElMessage.error("鑾峰彇鍙傛暟鍒楄〃澶辫触");
+          process.paramList = [];
+          process.paramCount = 0;
+        });
+    }
+  };
+  // 宸ヨ壓璺嚎鎿嶄綔
+  const handleAddRoute = () => {
+    isRouteEdit.value = false;
+    routeForm.id = null;
+    routeForm.productModelId = null;
+    routeForm.productName = "";
+    routeForm.productModelName = "";
+    routeForm.bomId = null;
+    routeForm.routeCode = "";
+    routeForm.description = "";
+    routeForm.status = false;
+    bomOptions.value = [];
+    routeDialogVisible.value = true;
+  };
+
+  const handleEditRoute = route => {
+    isRouteEdit.value = true;
+    routeForm.id = route.id;
+    routeForm.productModelId = route.productModelId;
+    routeForm.productName = route.productName;
+    routeForm.productModelName = route.productModelName;
+    routeForm.bomId = route.bomId;
+    routeForm.routeCode = route.routeCode;
+    routeForm.description = route.description;
+    routeForm.status = route.status;
+    routeDialogVisible.value = true;
+  };
+
+  const handleDeleteRoute = route => {
+    ElMessageBox.confirm("纭畾瑕佸垹闄よ宸ヨ壓璺嚎鍚楋紵", "鎻愮ず", {
+      confirmButtonText: "纭畾",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    }).then(() => {
+      del(route.id)
+        .then(res => {
+          ElMessage.success("鍒犻櫎鎴愬姛");
+          getRouteList();
+        })
+        .catch(err => {
+          ElMessage.error("鍒犻櫎澶辫触");
+        });
+    });
+  };
+
+  const handleRouteSubmit = () => {
+    routeFormRef.value.validate(valid => {
+      if (valid) {
+        // 鏋勫缓鎻愪氦鏁版嵁
+        const submitData = {
+          ...routeForm,
+          // 娉ㄦ剰锛欰PI 鏈熸湜鐨勫瓧娈靛悕鍙兘涓庤〃鍗曞瓧娈靛悕涓嶅悓
+          productId: routeForm.productModelId,
+          productModelId: routeForm.productModelId,
+          description: routeForm.description,
+        };
+
+        if (isRouteEdit.value) {
+          // 缂栬緫鎿嶄綔
+          update(submitData)
+            .then(res => {
+              ElMessage.success("缂栬緫鎴愬姛");
+              routeDialogVisible.value = false;
+              getRouteList();
+            })
+            .catch(err => {
+              ElMessage.error("缂栬緫澶辫触");
+            });
+        } else {
+          // 鏂板鎿嶄綔
+          add(submitData)
+            .then(res => {
+              ElMessage.success("鏂板鎴愬姛");
+              routeDialogVisible.value = false;
+              getRouteList();
+            })
+            .catch(err => {
+              ElMessage.error("鏂板澶辫触");
+            });
+        }
+      }
+    });
+  };
+  const isform2 = ref(null);
+  const handleProcessProductSelectClick = () => {
+    isform2.value = true;
+    showProductSelectDialog.value = true;
+  };
+  const handleProcessProductSelectClick2 = () => {
+    isform2.value = false;
+    showProductSelectDialog.value = true;
+  };
+
+  // 浜у搧閫夋嫨澶勭悊
+  const handleProductSelect = async products => {
+    if (isform2.value) {
+      // 甯垜鍐欏伐搴忎腑鐨勯�夋嫨浜у搧鐨勫洖璋�,骞朵笖鎶婂瓧娈靛姞杩沺rocessForm
+      if (products && products.length > 0) {
+        const product = products[0];
+        console.log("product:", product);
+        // 鎶妏roduct涓殑瀛楁娣诲姞鍒皃rocessForm涓�
+        // Object.assign(processForm, product);
+        processForm.productModelId = product.id;
+        processForm.productName = product.productName;
+        processForm.model = product.model;
+        processForm.unit = product.unit || "";
+        console.log("processForm:", processForm);
+
+        // 瑙﹀彂琛ㄥ崟楠岃瘉鏇存柊
+        proxy.$refs["processFormRef"]?.validateField("productModelId");
+      }
+    } else {
+      if (products && products.length > 0) {
+        const product = products[0];
+        // 鍏堟煡璇OM鍒楄〃锛堝繀閫夛級
+        try {
+          const res = await getByModel(product.id);
+          // 澶勭悊杩斿洖鐨凚OM鏁版嵁锛氬彲鑳芥槸鏁扮粍銆佸璞℃垨鍖呭惈data瀛楁
+          let bomList = [];
+          if (Array.isArray(res)) {
+            bomList = res;
+          } else if (res && res.data) {
+            bomList = Array.isArray(res.data) ? res.data : [res.data];
+          } else if (res && typeof res === "object") {
+            bomList = [res];
+          }
+          console.log("bomList:", bomList);
+          if (bomList.length > 0) {
+            routeForm.productModelId = product.id;
+            routeForm.productName = product.productName;
+            routeForm.productModelName = product.model;
+            routeForm.bomId = undefined; // 閲嶇疆BOM閫夋嫨
+            bomOptions.value = bomList;
+            showProductSelectDialog.value = false;
+            // 瑙﹀彂琛ㄥ崟楠岃瘉鏇存柊
+            proxy.$refs["routeFormRef"]?.validateField("productModelId");
+          } else {
+            proxy.$modal.msgError("璇ヤ骇鍝佹病鏈塀OM锛岃鍏堝垱寤築OM");
+          }
+        } catch (error) {
+          // 濡傛灉鎺ュ彛杩斿洖404鎴栧叾浠栭敊璇紝璇存槑娌℃湁BOM
+          proxy.$modal.msgError("璇ヤ骇鍝佹病鏈塀OM锛岃鍏堝垱寤築OM");
+        }
+      }
+    }
+  };
+
+  const handleApproveRoute = route => {
+    ElMessageBox.confirm("纭畾瑕佹壒鍑嗚宸ヨ壓璺嚎鍚楋紵", "鎻愮ず", {
+      confirmButtonText: "纭畾",
+      cancelButtonText: "鍙栨秷",
+      type: "info",
+    }).then(() => {
+      // 璋冪敤淇敼鎺ュ彛锛屽彧淇敼status瀛楁涓烘壒鍑嗙姸鎬�
+      update({ id: route.id, status: true })
+        .then(res => {
+          ElMessage.success("鎵瑰噯鎴愬姛");
+          getRouteList();
+        })
+        .catch(err => {
+          ElMessage.error("鎵瑰噯澶辫触");
+        });
+    });
+  };
+
+  const handleRevokeApproveRoute = route => {
+    ElMessageBox.confirm("纭畾瑕佹挙閿�鎵瑰噯璇ュ伐鑹鸿矾绾垮悧锛�", "鎻愮ず", {
+      confirmButtonText: "纭畾",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    }).then(() => {
+      // 璋冪敤淇敼鎺ュ彛锛屽彧淇敼status瀛楁涓鸿崏绋跨姸鎬�
+      update({ id: route.id, status: false })
+        .then(res => {
+          ElMessage.success("鎾ら攢鎵瑰噯鎴愬姛");
+          getRouteList();
+        })
+        .catch(err => {
+          ElMessage.error("鎾ら攢鎵瑰噯澶辫触");
+        });
+    });
+  };
+  // 宸ュ簭鎿嶄綔
+  const handleSelectProcess = (route, index) => {
+    console.log("route:", route);
+    currentRouteId.value = route.id;
+    currentRouteIndex.value = index;
+    // 閲嶇疆鎼滅储鍜岄�夋嫨鐘舵��
+    filteredProcessList.value = availableProcessList.value;
+    processSearchKeyword.value = "";
+    selectedProcessItem.value = null;
+    selectProcessDialogVisible.value = true;
+  };
+  const dragSort = ref(0);
+  const currentId = ref(null);
+  // 淇敼宸ュ簭
+  const handleEditProcessSelect = (route, index, process) => {
+    console.log("route:", route);
+    console.log("process:", process);
+    currentId.value = process.id;
+    currentRouteId.value = route.id;
+    currentRouteIndex.value = index;
+    // 閲嶇疆鎼滅储鍜岄�夋嫨鐘舵��
+    filteredProcessList.value = availableProcessList.value;
+    processSearchKeyword.value = "";
+    // 璁剧疆閫変腑鐨勫伐搴�
+    filteredProcessList.value.map(item => {
+      if (item.id === process.processId) {
+        selectedProcessItem.value = item;
+      }
+    });
+    dragSort.value = process.dragSort;
+    // selectedProcessItem.value = process;
+    // 濉厖浜у搧閫夋嫨琛ㄥ崟
+    processForm.productModelId = process.productModelId;
+    processForm.productName = process.productName;
+    processForm.model = process.model;
+    processForm.processId = process.no;
+    // processForm.name = process.name;
+    processForm.unit = process.unit || "";
+    processForm.isQuality = process.isQuality || false;
+    selectProcessDialogVisible.value = true;
+  };
+
+  const handleEditProcess = (routeId, process) => {
+    currentRouteId.value = routeId;
+    isProcessEdit.value = true;
+    processForm.id = process.id;
+    processForm.no = process.no;
+    processForm.name = process.name;
+    processForm.remark = process.remark;
+    processForm.status = process.status;
+    processDialogVisible.value = true;
+  };
+
+  const handleDeleteProcess = (routeId, process) => {
+    ElMessageBox.confirm("纭畾瑕佸垹闄よ宸ュ簭鍚楋紵", "鎻愮ず", {
+      confirmButtonText: "纭畾",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    }).then(() => {
+      // 璋冪敤API鍒犻櫎宸ュ簭
+      batchDeleteProcessRouteItem([process.id])
+        .then(res => {
+          ElMessage.success("鍒犻櫎鎴愬姛");
+          // 璋冪敤鎺ュ彛鏇存柊宸ュ簭鍒楄〃
+          findProcessRouteItemList({ routeId: routeId })
+            .then(res => {
+              const route = routeList.value.find(r => r.id === routeId);
+              if (route) {
+                route.processList = (res.data || []).map(process => ({
+                  ...process,
+                  processId: process.processId || process.id,
+                  expanded: false,
+                }));
+              }
+            })
+            .catch(err => {
+              console.error("鑾峰彇宸ュ簭鍒楄〃澶辫触锛�", err);
+            });
+        })
+        .catch(err => {
+          ElMessage.error("鍒犻櫎澶辫触");
+          console.error("鍒犻櫎宸ュ簭澶辫触锛�", err);
+        });
+    });
+  };
+
+  const handleProcessSubmit = () => {
+    processFormRef.value.validate(valid => {
+      if (valid) {
+        ElMessage.success(isProcessEdit.value ? "缂栬緫鎴愬姛" : "鏂板鎴愬姛");
+        processDialogVisible.value = false;
+        // 璋冪敤鎺ュ彛鏇存柊宸ュ簭鍒楄〃
+        if (currentRouteId.value) {
+          findProcessRouteItemList({ routeId: currentRouteId.value })
+            .then(res => {
+              const route = routeList.value.find(
+                r => r.id === currentRouteId.value
+              );
+              if (route) {
+                route.processList = (res.data || []).map(process => ({
+                  ...process,
+                  processId: process.processId || process.id,
+                  expanded: false,
+                }));
+              }
+            })
+            .catch(err => {
+              console.error("鑾峰彇宸ュ簭鍒楄〃澶辫触锛�", err);
+            });
+        }
+      }
+    });
+  };
+
+  // 閫夋嫨宸ュ簭鐩稿叧鏂规硶
+  const handleProcessSearch = () => {
+    const keyword = processSearchKeyword.value.trim().toLowerCase();
+    if (!keyword) {
+      filteredProcessList.value = availableProcessList.value;
+    } else {
+      filteredProcessList.value = availableProcessList.value.filter(
+        item =>
+          (item.name && item.name.toLowerCase().includes(keyword)) ||
+          (item.no && item.no.toLowerCase().includes(keyword))
+      );
+    }
+  };
+
+  const handleProcessSelect = row => {
+    selectedProcessItem.value = row;
+    // 閲嶇疆浜у搧閫夋嫨琛ㄥ崟
+    processForm.productModelId = undefined;
+    processForm.productName = "";
+    processForm.productModelName = "";
+    processForm.unit = "";
+    processForm.isQuality = row.isQuality || false;
+  };
+
+  // 澶勭悊宸ュ簭閫夋嫨鏃剁殑浜у搧閫夋嫨
+  const handleProcessProductSelect = async products => {
+    if (products && products.length > 0) {
+      const product = products[0];
+      processForm.productModelId = product.id;
+      processForm.productName = product.productName;
+      processForm.productModelName = product.model;
+      processForm.unit = product.unit || "";
+      showProductSelectDialog.value = false;
+    }
+  };
+
+  const handleProcessSelectSubmit = () => {
+    if (!selectedProcessItem.value) {
+      ElMessage.warning("璇峰厛閫夋嫨涓�涓伐搴�");
+      return;
+    }
+
+    if (!processForm.productModelId) {
+      ElMessage.warning("璇烽�夋嫨浜у搧");
+      return;
+    }
+
+    // 鏋勫缓璇锋眰鍙傛暟
+    const params = {
+      routeId: currentRouteId.value,
+      processId: selectedProcessItem.value.id,
+      dragSort: routePage.total + 1,
+      ...processForm,
+    };
+
+    // 濡傛灉鏄慨鏀规搷浣滐紝娣诲姞id鍙傛暟
+    if (selectedProcessItem.value.id) {
+      params.id = currentId.value;
+      params.dragSort = dragSort.value;
+    }
+
+    // 璋冪敤API娣诲姞宸ュ簭鎴栦慨鏀瑰伐搴�
+    addOrUpdateProcessRouteItem(params)
+      .then(res => {
+        ElMessage.success(
+          selectedProcessItem.value.id ? "淇敼宸ュ簭鎴愬姛" : "娣诲姞宸ュ簭鎴愬姛"
+        );
+        selectProcessDialogVisible.value = false;
+        // 璋冪敤鎺ュ彛鏇存柊宸ュ簭鍒楄〃
+        findProcessRouteItemList({ routeId: currentRouteId.value })
+          .then(res => {
+            const route = routeList.value.find(
+              r => r.id === currentRouteId.value
+            );
+            if (route) {
+              route.processList = (res.data || []).map(process => ({
+                ...process,
+                processId: process.processId || process.id,
+                expanded: false,
+              }));
+            }
+          })
+          .catch(err => {
+            console.error("鑾峰彇宸ュ簭鍒楄〃澶辫触锛�", err);
+          });
+      })
+      .catch(err => {
+        ElMessage.error(
+          selectedProcessItem.value.id ? "淇敼宸ュ簭澶辫触" : "娣诲姞宸ュ簭澶辫触"
+        );
+        console.error(
+          selectedProcessItem.value.id ? "淇敼宸ュ簭澶辫触锛�" : "娣诲姞宸ュ簭澶辫触锛�",
+          err
+        );
+      });
+  };
+
+  // 鍙傛暟鎿嶄綔
+  const handleAddParam = (routeId, process) => {
+    currentRouteId.value = routeId;
+    currentProcessId.value = process.id;
+    selectedParam.value = null;
+    paramSearchKeyword.value = "";
+    paramPage.current = 1;
+    // 鑾峰彇鍙�夊弬鏁板垪琛�
+    getBaseParamList({
+      paramName: paramSearchKeyword.value,
+      current: paramPage.current,
+      size: paramPage.size,
+    }).then(res => {
+      if (res.code === 200) {
+        filteredParamList.value = res.data?.records || [];
+        paramPage.total = res.data?.total || 0;
+      } else {
+        ElMessage.error(res.msg || "鏌ヨ澶辫触");
+      }
+    });
+    selectParamDialogVisible.value = true;
+  };
+
+  const handleEditParam = (routeId, process, param) => {
+    currentRouteId.value = routeId;
+    currentProcessId.value = process.id;
+    editParamForm.id = param.id;
+    editParamForm.processId = process.id;
+    editParamForm.paramId = param.paramId;
+    editParamForm.paramName = param.parameterName || param.paramName;
+    editParamForm.valueMode = param.parameterType2 || param.valueMode || "1";
+    editParamForm.standardValue = param.standardValue;
+    editParamForm.minValue = param.minValue;
+    editParamForm.maxValue = param.maxValue;
+    editParamForm.sort = param.sort || 1;
+    editParamForm.isRequired = param.isRequired || 0;
+    editParamForm.paramType = param.parameterType || param.paramType;
+    editParamForm.paramFormat = param.parameterFormat || param.paramFormat;
+    editParamForm.unit = param.unit || param.unit;
+    editParamDialogVisible.value = true;
+  };
+
+  const handleDeleteParam = (routeId, process, param) => {
+    ElMessageBox.confirm("纭畾瑕佸垹闄よ鍙傛暟鍚楋紵", "鎻愮ず", {
+      confirmButtonText: "纭畾",
+      cancelButtonText: "鍙栨秷",
+      type: "warning",
+    }).then(() => {
+      // 璋冪敤API鍒犻櫎鍙傛暟
+      delProcessRouteItemParam(param.id)
+        .then(res => {
+          ElMessage.success("鍒犻櫎鎴愬姛");
+          // 鍒锋柊鍙傛暟鍒楄〃
+          toggleProcessParams2(process);
+        })
+        .catch(err => {
+          ElMessage.error("鍒犻櫎鍙傛暟澶辫触");
+          console.error("鍒犻櫎鍙傛暟澶辫触锛�", err);
+        });
+    });
+  };
+
+  const handleParamSubmit = () => {
+    paramFormRef.value.validate(valid => {
+      if (valid) {
+        ElMessage.success(isParamEdit.value ? "缂栬緫鎴愬姛" : "鏂板鎴愬姛");
+        paramDialogVisible.value = false;
+        getRouteList();
+      }
+    });
+  };
+
+  const handleParamTypeChange = () => {
+    if (paramForm.parameterType === "鏁板�兼牸寮�") {
+      paramForm.parameterFormat = "#.0000";
+    } else if (paramForm.parameterType === "鏃堕棿鏍煎紡") {
+      paramForm.parameterFormat = "YYYY-MM-DD HH:mm:ss";
+    } else {
+      paramForm.parameterFormat = "";
+    }
+  };
+
+  const getParamTypeTag = type => {
+    const typeMap = {
+      1: "primary",
+      2: "info",
+      3: "warning",
+      4: "success",
+    };
+    return typeMap[type] || "default";
+  };
+
+  const getParamTypeText = type => {
+    const typeMap = {
+      1: "鏁板�兼牸寮�",
+      2: "鏂囨湰鏍煎紡",
+      3: "涓嬫媺閫夐」",
+      4: "鏃堕棿鏍煎紡",
+    };
+    return typeMap[type] || "鏈煡鍙傛暟绫诲瀷";
+  };
+
+  // 閫夋嫨鍙傛暟鐩稿叧鏂规硶
+  const handleParamSearch = () => {
+    // 閲嶇疆鍒嗛〉
+    paramPage.current = 1;
+    // 閲嶆柊鍔犺浇鏁版嵁
+    getBaseParamList({
+      paramName: paramSearchKeyword.value,
+      current: paramPage.current,
+      size: paramPage.size,
+    }).then(res => {
+      if (res.code === 200) {
+        filteredParamList.value = res.data?.records || [];
+        paramPage.total = res.data?.total || 0;
+      } else {
+        ElMessage.error(res.msg || "鏌ヨ澶辫触");
+      }
+    });
+  };
+
+  const handleParamSelect = row => {
+    selectedParam.value = row;
+  };
+
+  // 澶勭悊鍒嗛〉澶у皬鍙樺寲
+  const handleParamSizeChange = size => {
+    paramPage.size = size;
+    getBaseParamList({
+      paramName: paramSearchKeyword.value,
+      current: paramPage.current,
+      size: paramPage.size,
+    }).then(res => {
+      if (res.code === 200) {
+        filteredParamList.value = res.data?.records || [];
+        paramPage.total = res.data?.total || 0;
+      } else {
+        ElMessage.error(res.msg || "鏌ヨ澶辫触");
+      }
+    });
+  };
+
+  // 澶勭悊褰撳墠椤电爜鍙樺寲
+  const handleParamCurrentChange = current => {
+    paramPage.current = current;
+    getBaseParamList({
+      paramName: paramSearchKeyword.value,
+      current: paramPage.current,
+      size: paramPage.size,
+    }).then(res => {
+      if (res.code === 200) {
+        filteredParamList.value = res.data?.records || [];
+        paramPage.total = res.data?.total || 0;
+      } else {
+        ElMessage.error(res.msg || "鏌ヨ澶辫触");
+      }
+    });
+  };
+
+  // 宸ヨ壓璺嚎鍒嗛〉澶勭悊
+  const handleRouteSizeChange = size => {
+    routePage.size = size;
+    getRouteList();
+  };
+
+  const handleRouteCurrentChange = current => {
+    routePage.current = current;
+    getRouteList();
+  };
+
+  const handleParamSelectSubmit = () => {
+    if (!selectedParam.value) {
+      ElMessage.warning("璇峰厛閫夋嫨涓�涓弬鏁�");
+      return;
+    }
+
+    // 鎵惧埌瀵瑰簲鐨勫伐鑹鸿矾绾垮拰宸ュ簭
+    const route = routeList.value.find(r => r.id === currentRouteId.value);
+    const process = route?.processList.find(p => p.id === currentProcessId.value);
+
+    if (route && process) {
+      // 妫�鏌ュ弬鏁版槸鍚﹀凡瀛樺湪
+      // const exists = process.paramList?.some(
+      //   p =>
+      //     p.paramId === selectedParam.value.id ||
+      //     p.parameterCode === selectedParam.value.paramCode
+      // );
+      // if (exists) {
+      //   ElMessage.warning("璇ュ弬鏁板凡瀛樺湪浜庡伐搴忎腑");
+      //   return;
+      // }
+
+      // 鍒ゆ柇鍙傛暟绫诲瀷锛屽彧鏈夋暟鍊肩被鍨嬫墠浼犳爣鍑嗗�笺�佹渶澶у�煎拰鏈�灏忓��
+      const isNumericMode = selectedParam.value.valueMode === 1;
+
+      // 璋冪敤API鏂板鍙傛暟
+      addProcessRouteItemParam({
+        routeItemId: process.id,
+        paramId: selectedParam.value.id,
+        standardValue: isNumericMode
+          ? selectedParam.value.standardValue || ""
+          : "",
+        minValue: isNumericMode ? selectedParam.value.minValue || 0 : null,
+        maxValue: isNumericMode ? selectedParam.value.maxValue || 0 : null,
+        isRequired: selectedParam.value.isRequired || 0,
+      })
+        .then(res => {
+          ElMessage.success("娣诲姞鍙傛暟鎴愬姛");
+          selectParamDialogVisible.value = false;
+          // 鍒锋柊鍙傛暟鍒楄〃
+          toggleProcessParams2(process);
+        })
+        .catch(err => {
+          ElMessage.error("娣诲姞鍙傛暟澶辫触");
+          console.error("娣诲姞鍙傛暟澶辫触锛�", err);
+        });
+    }
+  };
+
+  const handleEditParamSubmit = () => {
+    editParamFormRef.value.validate(valid => {
+      if (valid) {
+        // 鍒ゆ柇鍙傛暟绫诲瀷锛屽彧鏈夋暟鍊肩被鍨嬫墠浼犳爣鍑嗗�笺�佹渶澶у�煎拰鏈�灏忓��
+        const isNumericMode = editParamForm.valueMode == 1;
+
+        // 璋冪敤API淇敼鍙傛暟
+        editProcessRouteItemParam({
+          id: editParamForm.id,
+          routeItemId: currentProcessId.value,
+          paramId: editParamForm.paramId,
+          standardValue: isNumericMode ? editParamForm.standardValue || "" : "",
+          minValue: isNumericMode ? editParamForm.minValue || 0 : null,
+          maxValue: isNumericMode ? editParamForm.maxValue || 0 : null,
+          isRequired: editParamForm.isRequired || 0,
+        })
+          .then(res => {
+            ElMessage.success("缂栬緫鎴愬姛");
+            editParamDialogVisible.value = false;
+            // 鎵惧埌瀵瑰簲鐨勫伐鑹鸿矾绾垮拰宸ュ簭
+            const route = routeList.value.find(
+              r => r.id === currentRouteId.value
+            );
+            const process = route?.processList.find(
+              p => p.id === currentProcessId.value
+            );
+            // 鍒锋柊鍙傛暟鍒楄〃
+            if (process) {
+              toggleProcessParams2(process);
+            }
+          })
+          .catch(err => {
+            ElMessage.error("缂栬緫鍙傛暟澶辫触");
+            console.error("缂栬緫鍙傛暟澶辫触锛�", err);
+          });
+      }
+    });
+  };
+
+  // 鎷栨嫿鎺掑簭
+  const handleDragStart = (event, index, routeId) => {
+    draggedItem.value = index;
+    draggedRouteId.value = routeId;
+    event.dataTransfer.effectAllowed = "move";
+  };
+
+  const handleDragOver = event => {
+    event.preventDefault();
+    event.dataTransfer.dropEffect = "move";
+  };
+
+  const handleDrop = (event, dropIndex, routeId) => {
+    event.preventDefault();
+    if (draggedItem.value === null || draggedItem.value === dropIndex) return;
+
+    const route = routeList.value.find(r => r.id === routeId);
+    if (route && route.processList) {
+      const draggedProcess = route.processList[draggedItem.value];
+
+      // 璁$畻鏂扮殑鎺掑簭鍊�
+      const newDragSort = dropIndex + 1;
+
+      // 璋冪敤API鎺掑簭宸ュ簭
+      sortProcessRouteItem({
+        id: draggedProcess.id,
+        dragSort: newDragSort,
+      })
+        .then(res => {
+          // 璋冪敤鎺ュ彛鑾峰彇鏈�鏂扮殑宸ュ簭鍒楄〃
+          findProcessRouteItemList({ routeId: routeId })
+            .then(res => {
+              if (route) {
+                route.processList = (res.data || []).map(process => ({
+                  ...process,
+                  processId: process.processId || process.id,
+                  expanded: false,
+                }));
+              }
+              ElMessage.success("鎺掑簭鎴愬姛");
+            })
+            .catch(err => {
+              console.error("鑾峰彇宸ュ簭鍒楄〃澶辫触锛�", err);
+              ElMessage.success("鎺掑簭鎴愬姛");
+            });
+        })
+        .catch(err => {
+          ElMessage.error("鎺掑簭澶辫触");
+          console.error("鎺掑簭宸ュ簭澶辫触锛�", err);
+        });
+    }
+  };
+
+  const handleDragEnd = () => {
+    draggedItem.value = null;
+    draggedRouteId.value = null;
+  };
+
+  // 鑾峰彇鏁版嵁瀛楀吀
+  const getDictTypes = () => {
+    listType({ pageNum: 1, pageSize: 1000 }).then(res => {
+      dictTypes.value = res.rows || [];
+    });
+  };
+
+  getRouteList();
+  getDictTypes();
+
+  // 椤甸潰鍔犺浇鏃惰幏鍙栧伐搴忓垪琛�
+  onMounted(() => {
+    getProcessListApi()
+      .then(res => {
+        // 澶勭悊杩斿洖鐨勬暟鎹紝鏄犲皠鍒伴〉闈㈤渶瑕佺殑鏍煎紡
+        availableProcessList.value = (res.data || []).map(item => ({
+          id: item.id,
+          no: item.no || item.no,
+          name: item.name || item.name,
+          remark: item.remark || item.remark,
+          status: item.status,
+          isQuality: item.isQuality,
+        }));
+        filteredProcessList.value = availableProcessList.value;
+      })
+      .catch(() => {
+        ElMessage.error("鑾峰彇宸ュ簭鍒楄〃澶辫触");
+      });
+  });
+</script>
+
+<style scoped lang="scss">
+  .app-container {
+    padding: 20px;
+    padding-bottom: 80px;
+    background-color: #f0f2f5;
+    min-height: calc(100vh - 84px);
+    overflow: hidden;
+  }
+
+  .route-header {
+    margin-bottom: 20px;
+
+    .add-route-btn {
+      width: 100%;
+      display: inline-flex;
+      flex-direction: column;
+      align-items: center;
+      justify-content: center;
+      min-width: 120px;
+      height: 100px;
+      border: 2px dashed #dcdfe6;
+      border-radius: 12px;
+      background: #fafafa;
+      cursor: pointer;
+      transition: all 0.3s ease;
+      color: #909399;
+      padding: 0 20px;
+
+      .el-icon {
+        font-size: 24px;
+        margin-bottom: 8px;
+      }
+
+      span {
+        font-size: 13px;
+      }
+
+      &:hover {
+        border-color: #409eff;
+        background: #ecf5ff;
+        color: #409eff;
+      }
+    }
+  }
+
+  .route-card-list {
+    display: grid;
+    grid-template-columns: repeat(1, 1fr);
+    gap: 20px;
+    max-height: calc(100vh - 240px);
+    overflow-y: auto;
+    padding-right: 10px;
+  }
+
+  /* 鑷畾涔夋粴鍔ㄦ潯鏍峰紡 */
+  .route-card-list::-webkit-scrollbar {
+    width: 8px;
+  }
+
+  .route-card-list::-webkit-scrollbar-track {
+    background: #f1f1f1;
+    border-radius: 4px;
+  }
+
+  .route-card-list::-webkit-scrollbar-thumb {
+    background: #c1c1c1;
+    border-radius: 4px;
+  }
+
+  .route-card-list::-webkit-scrollbar-thumb:hover {
+    background: #a8a8a8;
+  }
+
+  .route-card {
+    background: #fff;
+    border-radius: 8px;
+    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+    overflow: hidden;
+
+    .card-header {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      padding: 20px 40px;
+      border-bottom: 1px solid #ebeef5;
+      background: #f8f9fa;
+
+      .route-info {
+        display: flex;
+        // flex-direction: column;
+        // justify-content: center;
+        // items-align: center;
+        gap: 4px;
+
+        .route-code {
+          font-size: 12px;
+          color: #909399;
+          font-family: "Courier New", monospace;
+          line-height: 30px;
+        }
+
+        .route-name {
+          font-size: 18px;
+          font-weight: 600;
+          color: #303133;
+          display: flex;
+          align-items: center;
+        }
+      }
+
+      .route-actions {
+        display: flex;
+        gap: 8px;
+
+        // .el-button {
+        //   color: #409eff;
+        // }
+      }
+    }
+
+    .card-body {
+      padding: 16px 40px;
+
+      .route-desc {
+        font-size: 14px;
+        color: #606266;
+        margin-bottom: 12px;
+      }
+
+      .route-meta {
+        display: flex;
+        gap: 24px;
+        margin-bottom: 12px;
+        padding: 10px 14px;
+        background: linear-gradient(135deg, #f5f7fa 0%, #e8ecf1 100%);
+        border-radius: 8px;
+        border-left: 3px solid #409eff;
+
+        .meta-item {
+          display: flex;
+          align-items: center;
+          gap: 6px;
+          font-size: 13px;
+          margin-right: 40px;
+
+          .el-icon {
+            font-size: 14px;
+            color: #409eff;
+          }
+
+          .meta-label {
+            color: #909399;
+            font-weight: 500;
+          }
+
+          .meta-value {
+            color: #303133;
+            font-weight: 600;
+          }
+        }
+      }
+
+      .expand-btn-wrapper {
+        display: flex;
+        justify-content: center;
+        margin-top: 8px;
+
+        .expand-btn {
+          padding: 8px 20px;
+          border-radius: 20px;
+          background: linear-gradient(135deg, #ecf5ff 0%, #d9ecff 100%);
+          border: 1px solid #b3d8ff;
+          transition: all 0.3s ease;
+
+          .btn-text {
+            font-size: 13px;
+            font-weight: 500;
+            color: #409eff;
+            margin-right: 6px;
+          }
+
+          .expand-icon {
+            font-size: 14px;
+            color: #409eff;
+            transition: transform 0.3s ease;
+          }
+
+          &:hover {
+            background: linear-gradient(135deg, #409eff 0%, #66b1ff 100%);
+            border-color: #409eff;
+            box-shadow: 0 4px 12px rgba(64, 158, 255, 0.3);
+
+            .btn-text,
+            .expand-icon {
+              color: #fff;
+            }
+          }
+
+          &.expanded {
+            background: linear-gradient(135deg, #f0f9eb 0%, #e1f3d8 100%);
+            border-color: #a5d69a;
+
+            .btn-text,
+            .expand-icon {
+              color: #67c23a;
+            }
+
+            &:hover {
+              background: linear-gradient(135deg, #67c23a 0%, #85ce61 100%);
+              border-color: #67c23a;
+              box-shadow: 0 4px 12px rgba(103, 194, 58, 0.3);
+
+              .btn-text,
+              .expand-icon {
+                color: #fff;
+              }
+            }
+          }
+        }
+      }
+    }
+
+    .process-route {
+      padding: 0 20px 20px;
+      background: #f5f7fa;
+      border-top: 1px solid #ebeef5;
+
+      .process-flow {
+        display: flex;
+        align-items: flex-start;
+        gap: 8px;
+        padding: 20px 0;
+        overflow-x: auto;
+        overflow-y: hidden;
+
+        .process-flow-item {
+          display: flex;
+          align-items: center;
+          gap: 8px;
+
+          .process-node {
+            background: #fff;
+            border-radius: 12px;
+            padding: 16px;
+            border: 2px solid #ebeef5;
+            cursor: move;
+            transition: all 0.3s ease;
+            // min-width: 180px;
+            // max-width: 220px;
+            width: 300px;
+
+            &.expanded {
+              width: 400px;
+            }
+
+            &:hover {
+              box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+              transform: translateY(-2px);
+              border-color: #409eff;
+            }
+
+            &:active {
+              cursor: grabbing;
+            }
+
+            .process-node-header {
+              display: flex;
+              justify-content: space-between;
+              align-items: center;
+              margin-bottom: 12px;
+
+              .process-number {
+                width: 28px;
+                height: 28px;
+                border-radius: 50%;
+                background: #409eff;
+                color: #ffffff;
+                font-size: 12px;
+                font-weight: 600;
+                display: flex;
+                align-items: center;
+                justify-content: center;
+              }
+
+              .process-actions {
+                display: flex;
+                gap: 4px;
+              }
+            }
+
+            .process-node-body {
+              text-align: center;
+              margin-bottom: 12px;
+
+              .process-code {
+                font-size: 11px;
+                color: #909399;
+                font-family: "Courier New", monospace;
+                margin-bottom: 4px;
+              }
+
+              .process-name {
+                font-size: 15px;
+                font-weight: 600;
+                color: #303133;
+                margin-bottom: 6px;
+              }
+
+              .process-desc {
+                font-size: 12px;
+                color: #606266;
+                overflow: hidden;
+                text-overflow: ellipsis;
+                display: -webkit-box;
+                -webkit-line-clamp: 2;
+                -webkit-box-orient: vertical;
+              }
+            }
+
+            .process-node-footer {
+              display: flex;
+              justify-content: flex-end;
+              align-items: center;
+              padding-top: 10px;
+              border-top: 1px solid #ebeef5;
+            }
+
+            .process-params-section {
+              margin-top: 12px;
+              padding-top: 12px;
+              border-top: 1px solid #ebeef5;
+
+              .params-header {
+                display: flex;
+                justify-content: space-between;
+                align-items: center;
+                margin-bottom: 8px;
+                font-size: 13px;
+                font-weight: 600;
+                color: #303133;
+              }
+
+              .params-list {
+                display: flex;
+                flex-direction: column;
+                gap: 6px;
+                max-height: 200px;
+                overflow-y: auto;
+
+                .param-item {
+                  display: flex;
+                  justify-content: space-between;
+                  align-items: center;
+                  padding: 6px 8px;
+                  background: #fafafa;
+                  border-radius: 4px;
+                  border-left: 2px solid #409eff;
+                  font-size: 12px;
+
+                  .param-info {
+                    display: flex;
+                    flex-direction: row;
+                    align-items: center;
+                    gap: 6px;
+                    flex: 1;
+                    min-width: 0;
+
+                    .param-code {
+                      font-size: 11px;
+                      color: #e6a23c;
+                      font-family: "Courier New", monospace;
+                      margin-right: 20px;
+                    }
+
+                    .param-name {
+                      font-size: 12px;
+                      color: #303133;
+                      font-weight: 500;
+                      margin-right: 20px;
+                    }
+
+                    .param-value {
+                      font-size: 11px;
+                      color: #606266;
+                    }
+                  }
+
+                  .param-actions {
+                    display: flex;
+                    gap: 4px;
+                    flex-shrink: 0;
+                  }
+                }
+              }
+            }
+          }
+
+          .flow-arrow {
+            display: flex;
+            align-items: center;
+            color: #c0c4cc;
+            font-size: 24px;
+            padding: 0 4px;
+
+            .el-icon {
+              font-size: 20px;
+            }
+          }
+        }
+
+        .add-process-node {
+          display: flex;
+          flex-direction: column;
+          align-items: center;
+          justify-content: center;
+          min-width: 100px;
+          height: 137px;
+          border: 2px dashed #dcdfe6;
+          border-radius: 12px;
+          background: #fafafa;
+          cursor: pointer;
+          transition: all 0.3s ease;
+          color: #909399;
+          // margin-left: 10px;
+
+          .el-icon {
+            font-size: 24px;
+            margin-bottom: 8px;
+          }
+
+          span {
+            font-size: 13px;
+          }
+
+          &:hover {
+            border-color: #409eff;
+            background: #ecf5ff;
+            color: #409eff;
+          }
+        }
+      }
+    }
+  }
+
+  // 鎷栨嫿鏃剁殑鏍峰紡
+  .process-flow-item.dragging {
+    opacity: 0.5;
+    transform: scale(0.98);
+  }
+
+  // 閫夋嫨宸ュ簭瀵硅瘽妗嗘牱寮�
+  .process-select-container {
+    display: flex;
+    gap: 20px;
+    height: 450px;
+
+    .process-list-area {
+      flex: 1;
+      display: flex;
+      flex-direction: column;
+
+      .area-title {
+        font-size: 14px;
+        font-weight: 600;
+        color: #303133;
+        margin-bottom: 12px;
+        padding-bottom: 8px;
+        border-bottom: 1px solid #ebeef5;
+      }
+
+      .search-box {
+        margin-bottom: 12px;
+
+        .el-input {
+          width: 100%;
+        }
+      }
+    }
+
+    .process-detail-area {
+      width: 380px;
+      display: flex;
+      flex-direction: column;
+      background: #f5f7fa;
+      border-radius: 8px;
+      padding: 16px;
+
+      .area-title {
+        font-size: 14px;
+        font-weight: 600;
+        color: #303133;
+        margin-bottom: 16px;
+        padding-bottom: 8px;
+        border-bottom: 1px solid #ebeef5;
+      }
+
+      .process-detail-form {
+        .el-form-item {
+          margin-bottom: 12px;
+
+          .el-form-item__label {
+            color: #606266;
+            font-weight: 500;
+          }
+        }
+
+        .detail-text {
+          color: #303133;
+          font-weight: 500;
+        }
+      }
+    }
+  }
+
+  // 閫夋嫨鍙傛暟瀵硅瘽妗嗘牱寮�
+  .param-select-container {
+    display: flex;
+    gap: 20px;
+    height: 450px;
+
+    .param-list-area {
+      // flex: 1;
+      width: 380px;
+      display: flex;
+      flex-direction: column;
+
+      .area-title {
+        font-size: 14px;
+        font-weight: 600;
+        color: #303133;
+        margin-bottom: 12px;
+        padding-bottom: 8px;
+        border-bottom: 1px solid #ebeef5;
+      }
+
+      .search-box {
+        margin-bottom: 12px;
+
+        .el-input {
+          width: 100%;
+        }
+      }
+    }
+
+    .param-detail-area {
+      // width: 380px;
+      flex: 1;
+      display: flex;
+      flex-direction: column;
+      background: #f5f7fa;
+      border-radius: 8px;
+      padding: 16px;
+
+      .area-title {
+        font-size: 14px;
+        font-weight: 600;
+        color: #303133;
+        margin-bottom: 16px;
+        padding-bottom: 8px;
+        border-bottom: 1px solid #ebeef5;
+      }
+
+      .param-detail-form {
+        .el-form-item {
+          margin-bottom: 12px;
+
+          .el-form-item__label {
+            color: #606266;
+            font-weight: 500;
+          }
+        }
+
+        .detail-text {
+          color: #303133;
+          font-weight: 500;
+        }
+      }
+    }
+  }
+
+  // 鍒嗛〉鎺т欢鏍峰紡
+  .pagination-container {
+    position: fixed;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    display: flex;
+    justify-content: flex-end;
+    padding: 16px 20px;
+    background-color: #fff !important;
+    border-top: 1px solid #ebeef5;
+    box-shadow: 0 -2px 12px 0 rgba(0, 0, 0, 0.1);
+    z-index: 100;
+
+    .el-pagination {
+      .el-pagination__sizes {
+        margin-right: 16px;
+      }
+
+      .el-pagination__jump {
+        margin-left: 16px;
+      }
+
+      .el-pagination__total {
+        color: #606266;
+        font-size: 14px;
+      }
+
+      .el-pagination__button {
+        border-radius: 4px;
+        transition: all 0.3s ease;
+
+        &:hover:not(:disabled) {
+          color: #409eff;
+          border-color: #409eff;
+        }
+      }
+
+      .el-pagination__button--active {
+        background-color: #409eff;
+        border-color: #409eff;
+        color: #fff;
+      }
+    }
+  }
+</style>
diff --git a/src/views/productionManagement/processRoute/processRouteItem/index.vue b/src/views/productionManagement/processRoute/processRouteItem/index.vue
new file mode 100644
index 0000000..ce3ee0b
--- /dev/null
+++ b/src/views/productionManagement/processRoute/processRouteItem/index.vue
@@ -0,0 +1,1024 @@
+<template>
+  <div class="app-container">
+    <PageHeader content="宸ヨ壓璺嚎椤圭洰" />
+    <!-- 宸ヨ壓璺嚎淇℃伅灞曠ず -->
+    <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">
+            <span class="info-label">宸ヨ壓璺嚎缂栧彿</span>
+          </div>
+          <div class="info-value-wrapper">
+            <span class="info-value">{{ routeInfo.processRouteCode }}</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.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>
+          </div>
+        </div>
+        <div class="info-item">
+          <div class="info-label-wrapper">
+            <span class="info-label">BOM缂栧彿</span>
+          </div>
+          <div class="info-value-wrapper">
+            <span class="info-value">{{ routeInfo.bomNo || '-' }}</span>
+          </div>
+        </div>
+        <div class="info-item full-width"
+             v-if="routeInfo.description">
+          <div class="info-label-wrapper">
+            <span class="info-label">鎻忚堪</span>
+          </div>
+          <div class="info-value-wrapper">
+            <span class="info-value">{{ routeInfo.description }}</span>
+          </div>
+        </div>
+      </div>
+    </el-card>
+    <!-- bom灞曠ず -->
+    <!-- 琛ㄦ牸瑙嗗浘 -->
+    <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;">
+          鍗$墖瑙嗗浘
+        </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">
+        <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="鍙傛暟鍒楄〃"
+                       min-width="160">
+        <template #default="scope">
+          <el-button type="primary"
+                     link
+                     size="small"
+                     @click="handleViewParams(scope.row)">鍙傛暟鍒楄〃</el-button>
+        </template>
+      </el-table-column>
+      <el-table-column label="鍗曚綅"
+                       prop="unit"
+                       width="100" />
+      <el-table-column label="鏄惁璐ㄦ"
+                       prop="isQuality"
+                       width="100">
+        <template #default="scope">
+          {{scope.row.isQuality ? "鏄�" : "鍚�"}}
+        </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="info"
+                     link
+                     size="small"
+                     @click="handleViewParams(scope.row)">鍙傛暟鍒楄〃</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;">
+            琛ㄦ牸瑙嗗浘
+          </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>
+                <el-tag type="primary"
+                        class="product-tag"
+                        v-if="item.isQuality">璐ㄦ</el-tag>
+              </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="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>
+    </template>
+    <!-- 鏂板/缂栬緫寮圭獥 -->
+    <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>
+        <el-form-item label="鏄惁璐ㄦ"
+                      prop="isQuality">
+          <el-switch v-model="form.isQuality"
+                     :active-value="true"
+                     inactive-value="false" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="closeDialog">鍙栨秷</el-button>
+        <el-button type="primary"
+                   @click="handleSubmit"
+                   :loading="submitLoading">纭畾</el-button>
+      </template>
+    </el-dialog>
+    <!-- 浜у搧閫夋嫨瀵硅瘽妗� -->
+    <ProductSelectDialog v-model="showProductSelectDialog"
+                         @confirm="handleProductSelect"
+                         single />
+    <!-- 鍙傛暟鍒楄〃瀵硅瘽妗� -->
+    <ProcessParamListDialog v-model="showParamListDialog"
+                            :title="`${currentProcess ? getProcessName(currentProcess.processId) : ''} - 鍙傛暟鍒楄〃`"
+                            :route-id="routeId"
+                            :editable="false"
+                            :process="currentProcess"
+                            :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 ProcessParamListDialog from "@/components/ProcessParamListDialog.vue";
+  import {
+    findProcessRouteItemList,
+    addOrUpdateProcessRouteItem,
+    sortProcessRouteItem,
+    batchDeleteProcessRouteItem,
+    getProcessParamList,
+  } 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, ElMessage } from "element-plus";
+  import Sortable from "sortablejs";
+
+  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 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: "",
+    bomId: null,
+    description: "",
+  });
+
+  const processOptions = ref([]);
+  const showProductSelectDialog = ref(false);
+  const showParamListDialog = ref(false);
+  const currentProcess = ref(null);
+  const paramList = ref([]);
+  let tableSortable = null;
+  let cardSortable = null;
+
+  // 鍒囨崲瑙嗗浘
+  const toggleView = () => {
+    viewMode.value = viewMode.value === "table" ? "card" : "table";
+    // 鍒囨崲瑙嗗浘鍚庨噸鏂板垵濮嬪寲鎷栨嫿鎺掑簭
+    nextTick(() => {
+      initSortable();
+    });
+  };
+
+  const form = ref({
+    id: undefined,
+    routeId: routeId.value,
+    processId: undefined,
+    productModelId: undefined,
+    productName: "",
+    model: "",
+    unit: "",
+    isQuality: false,
+  });
+
+  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 || "",
+      bomId: route.query.bomId || null,
+      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 || "",
+      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({
+                productOrderId: orderId.value,
+                productRouteId: routeId.value,
+                processId: form.value.processId,
+                productModelId: form.value.productModelId,
+                isQuality: form.value.isQuality,
+                dragSort,
+              })
+            : 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(() => {
+              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,
+                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;
+            });
+        }
+      }
+    });
+  };
+
+  // 閲嶇疆琛ㄥ崟
+  const resetForm = () => {
+    form.value = {
+      id: undefined,
+      routeId: routeId.value,
+      processId: undefined,
+      productModelId: undefined,
+      productName: "",
+      model: "",
+      unit: "",
+    };
+    formRef.value?.resetFields();
+  };
+
+  // 鍏抽棴寮圭獥
+  const closeDialog = () => {
+    dialogVisible.value = false;
+    resetForm();
+  };
+
+  // 鍒濆鍖栨嫋鎷芥帓搴�
+  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",
+        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鑾峰彇鍙傛暟鍒楄〃
+    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鑾峰彇鍙傛暟鍒楄〃
+    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;
+  }
+
+  .cards-wrapper {
+    display: flex;
+    gap: 16px;
+    overflow-x: auto;
+    padding: 10px 0;
+    min-height: 200px;
+  }
+
+  .cards-wrapper::-webkit-scrollbar {
+    height: 8px;
+  }
+
+  .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: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:hover {
+    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+    transform: translateY(-2px);
+  }
+
+  .card-header {
+    text-align: center;
+    margin-bottom: 12px;
+  }
+
+  .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-process-name {
+    font-size: 14px;
+    color: #333;
+    font-weight: 500;
+    word-break: break-all;
+  }
+
+  .card-content {
+    flex: 1;
+    margin-bottom: 12px;
+    min-height: 60px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+
+  .product-info {
+    font-size: 13px;
+    color: #666;
+    text-align: center;
+    width: 100%;
+  }
+
+  .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-model {
+    color: #909399;
+    font-size: 12px;
+    word-break: break-all;
+    line-height: 1.5;
+    text-align: center;
+  }
+
+  .product-unit {
+    margin-left: 4px;
+    color: #409eff;
+  }
+
+  .product-tag {
+    margin: 10px 0;
+  }
+
+  .card-footer {
+    display: flex;
+    justify-content: space-around;
+    padding-top: 12px;
+    border-top: 1px solid #f0f0f0;
+  }
+
+  .card-footer .el-button {
+    padding: 0;
+    font-size: 12px;
+  }
+
+  :deep(.sortable-ghost) {
+    opacity: 0.5;
+    background-color: #f5f7fa !important;
+  }
+
+  :deep(.sortable-drag) {
+    opacity: 0.8;
+  }
+
+  /* 琛ㄦ牸瑙嗗浘鏍峰紡 */
+  :deep(.el-table__row) {
+    transition: background-color 0.2s;
+    cursor: move;
+  }
+
+  :deep(.el-table__row:hover) {
+    background-color: #f9fafc !important;
+  }
+
+  /* 鍖哄煙鏍囬鏍峰紡 */
+  .section-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 12px;
+  }
+
+  .section-title {
+    font-size: 16px;
+    font-weight: 600;
+    color: #303133;
+    padding-left: 12px;
+    position: relative;
+    margin-bottom: 0;
+  }
+
+  .section-title::before {
+    content: "";
+    position: absolute;
+    left: 0;
+    top: 50%;
+    transform: translateY(-50%);
+    width: 3px;
+    height: 16px;
+    background: #409eff;
+    border-radius: 2px;
+  }
+
+  .section-actions {
+    display: flex;
+    align-items: center;
+  }
+
+  /* 宸ヨ壓璺嚎淇℃伅鍗$墖鏍峰紡 */
+  .route-info-card {
+    margin-bottom: 20px;
+    border: 1px solid #e4e7ed;
+    background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
+    border-radius: 8px;
+    overflow: hidden;
+  }
+
+  .route-info {
+    display: grid;
+    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
+    gap: 16px;
+    padding: 4px;
+  }
+
+  .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-item:hover {
+    border-color: #409eff;
+    box-shadow: 0 2px 8px rgba(64, 158, 255, 0.15);
+    transform: translateY(-1px);
+  }
+
+  .info-item.full-width {
+    grid-column: 1 / -1;
+  }
+
+  .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>
diff --git a/src/views/productionPlan/productionPlan/index.vue b/src/views/productionPlan/productionPlan/index.vue
index d2a3efd..e6f209b 100644
--- a/src/views/productionPlan/productionPlan/index.vue
+++ b/src/views/productionPlan/productionPlan/index.vue
@@ -117,6 +117,21 @@
                           value-format="YYYY-MM-DD"
                           style="width: 100%" />
         </el-form-item>
+        <el-form-item label="寮哄害"
+                      v-if="mergeForm.productName === '鐮屽潡'">
+          <div v-if="strengthError"
+               class="strength-error"
+               style="color: red; margin-bottom: 8px;">{{ strengthError }}</div>
+          <el-select v-model="mergeForm.strength"
+                     placeholder="璇烽�夋嫨寮哄害"
+                     style="width: 100%"
+                     required>
+            <el-option v-for="item in block_strength"
+                       :key="item.id"
+                       :label="item.label"
+                       :value="item.id" />
+          </el-select>
+        </el-form-item>
         <el-form-item label="鐢熶骇鏂规暟">
           <el-input-number v-model="mergeForm.totalAssignedQuantity"
                            :min="0"
@@ -301,14 +316,15 @@
                           placeholder="璇烽�夋嫨璁″垝缁撴潫鏃ユ湡" />
         </el-form-item>
         <el-form-item label="寮哄害"
-                      prop="strength">
+                      prop="strength"
+                      v-if="form.productName === '鐮屽潡'">
           <el-select v-model="form.strength"
                      placeholder="璇烽�夋嫨寮哄害"
                      style="width: 100%">
-            <el-option label="A3.5"
-                       value="A3.5" />
-            <el-option label="A5.0"
-                       value="A5.0" />
+            <el-option v-for="item in block_strength"
+                       :key="item.id"
+                       :label="item.label"
+                       :value="item.id" />
           </el-select>
         </el-form-item>
         <el-form-item label="澶囨敞 1"
@@ -334,11 +350,12 @@
 </template>
 
 <script setup>
-  import { onMounted, ref, reactive, getCurrentInstance } from "vue";
+  import { onMounted, ref, reactive, getCurrentInstance, toRefs } from "vue";
   import { ElMessage } from "element-plus";
   import dayjs from "dayjs";
   import ImportDialog from "@/components/Dialog/ImportDialog.vue";
   import { getToken } from "@/utils/auth";
+  import { useDict } from "@/utils/dict";
   import {
     productionPlanListPage,
     loadProdData,
@@ -490,6 +507,11 @@
     {
       label: "寮哄害",
       prop: "strength",
+      formatData: cell => {
+        if (!cell) return "";
+        const strengthItem = block_strength.value.find(item => item.id === cell);
+        return strengthItem ? strengthItem.label : cell;
+      },
     },
 
     {
@@ -546,6 +568,7 @@
           clickFun: row => {
             // 鍗曠嫭涓嬪彂鎿嶄綔
             // 璁剧疆琛ㄥ崟鏁版嵁
+            strengthError.value = "";
             mergeForm.ids = [row.id];
             mergeForm.materialCode = row.materialCode;
             mergeForm.productName = row.productName || "";
@@ -556,6 +579,7 @@
             mergeForm.totalAssignedQuantity =
               (Number(row.volume) - Number(row.assignedQuantity)).toFixed(4) || 0;
             mergeForm.planCompleteTime = row.planCompleteTime || "";
+            mergeForm.strength = row.strength || "";
             sumAssignedQuantity.value = mergeForm.totalAssignedQuantity;
             // 鎵撳紑寮圭獥
             isShowNewModal.value = true;
@@ -597,6 +621,7 @@
     height: 0,
     totalAssignedQuantity: 0,
     planCompleteTime: "",
+    strength: "",
   });
 
   // 杩借釜杩涘害寮圭獥鎺у埗
@@ -625,6 +650,8 @@
   const productOptions = ref([]);
   const specificationOptions = ref([]);
   const formRef = ref(null);
+  // 鑾峰彇寮哄害瀛楀吀
+  const { block_strength } = useDict("block_strength");
   const form = reactive({
     id: undefined,
     applyNo: "",
@@ -656,6 +683,19 @@
     volume: [{ required: true, message: "璇疯緭鍏ユ柟鏁�", trigger: "blur" }],
     productMaterialId: [
       { required: true, message: "璇烽�夋嫨浜у搧", trigger: "change" },
+    ],
+    strength: [
+      {
+        validator: (rule, value, callback) => {
+          if (form.productName === "鐮屽潡" && !value) {
+            callback(new Error("鐮屽潡浜у搧鐨勫己搴︿负蹇呭~椤�"));
+          } else {
+            callback();
+          }
+        },
+        trigger: ["blur", "change"],
+        required: false,
+      },
     ],
   });
 
@@ -709,6 +749,26 @@
 
   const handleProductChange = value => {
     form.productMaterialSkuId = undefined;
+    // 鏌ユ壘閫変腑鐨勪骇鍝佸悕绉�
+    const findProductName = (options, value) => {
+      for (const option of options) {
+        if (option.value === value) {
+          return option.label;
+        }
+        if (option.children) {
+          const found = findProductName(option.children, value);
+          if (found) {
+            return found;
+          }
+        }
+      }
+      return "";
+    };
+    form.productName = findProductName(productOptions.value, value);
+    // 瑙﹀彂寮哄害瀛楁楠岃瘉
+    if (formRef.value) {
+      formRef.value.validateField("strength");
+    }
     fetchSpecificationOptions(value);
   };
 
@@ -931,6 +991,9 @@
       .catch(() => {});
   };
   const sumAssignedQuantity = ref(0);
+  // 鍝嶅簲寮忔暟鎹�
+  const strengthError = ref("");
+
   // 澶勭悊鍚堝苟涓嬪彂鎸夐挳鐐瑰嚮
   const handleMerge = () => {
     if (selectedRows.value.length === 0) {
@@ -938,6 +1001,26 @@
       return;
     }
     console.log(selectedRows.value);
+    // 妫�鏌ュ己搴︿竴鑷存��
+    const firstRow = selectedRows.value[0];
+    const productName = firstRow.productName || "";
+    let strengthConsistent = true;
+    let firstStrength = firstRow.strength || "";
+    strengthError.value = "";
+
+    if (productName === "鐮屽潡") {
+      for (const row of selectedRows.value) {
+        if (row.strength !== firstStrength) {
+          strengthConsistent = false;
+          break;
+        }
+      }
+
+      if (!strengthConsistent) {
+        strengthError.value = "閫夋嫨鐨勭爩鍧楀己搴︿笉涓�鑷达紝璇烽噸鏂伴�夋嫨";
+      }
+    }
+
     // 璁$畻鎬诲埗閫犳暟閲�
     const totalAssignedQuantity = selectedRows.value.reduce((sum, row) => {
       return (
@@ -950,15 +1033,15 @@
     sumAssignedQuantity.value = totalAssignedQuantity;
     console.log(totalAssignedQuantity);
     // 璁剧疆琛ㄥ崟鏁版嵁
-    const firstRow = selectedRows.value[0];
     mergeForm.materialCode = selectedserialNo.value;
-    mergeForm.productName = firstRow.productName || "";
+    mergeForm.productName = productName;
     mergeForm.model = firstRow.model || "";
     mergeForm.length = firstRow.length || 0;
     mergeForm.width = firstRow.width || 0;
     mergeForm.height = firstRow.height || 0;
     mergeForm.totalAssignedQuantity = totalAssignedQuantity;
     mergeForm.planCompleteTime = firstRow.planCompleteTime || "";
+    mergeForm.strength = firstStrength;
     mergeForm.ids = selectedRows.value.map(row => row.id);
 
     // 鎵撳紑寮圭獥
@@ -971,6 +1054,11 @@
       ElMessage.warning("璇疯緭鍏ョ敓浜ф柟鏁�");
       return;
     }
+    // 楠岃瘉鐮屽潡浜у搧鐨勫己搴�
+    if (mergeForm.productName === "鐮屽潡" && !mergeForm.strength) {
+      ElMessage.error("鐮屽潡浜у搧鐨勫己搴︿负蹇呭~椤�");
+      return;
+    }
     console.log(sumAssignedQuantity.value, "sumAssignedQuantity");
     // 璁$畻褰撳墠閫変腑琛岀殑鎬绘柟鏁�
     const totalVolume = selectedRows.value.reduce((sum, row) => {

--
Gitblit v1.9.3