From dc082351978a1e9f75d7a1471a0ca7ebeac552a5 Mon Sep 17 00:00:00 2001
From: WXL <wl_5969728@163.com>
Date: 星期一, 01 六月 2026 11:07:50 +0800
Subject: [PATCH] opo维护

---
 src/views/business/course/index.vue |  858 +++++++++++++++++++++++++++-----------------------------
 1 files changed, 414 insertions(+), 444 deletions(-)

diff --git a/src/views/business/course/index.vue b/src/views/business/course/index.vue
index 9342dda..02501b3 100644
--- a/src/views/business/course/index.vue
+++ b/src/views/business/course/index.vue
@@ -6,50 +6,53 @@
         <div class="timeline-section">
           <div class="section-header">
             <h3>鎹愮尞杩涚▼鏃堕棿绾�</h3>
-            <el-tag :type="getOverallStatusTag(caseInfo.status)">
-              {{ getStatusText(caseInfo.status) }}
-            </el-tag>
           </div>
 
-          <div class="timeline-container">
-            <div
-              v-for="stage in processStages"
-              :key="stage.key"
-              class="timeline-item"
-              :class="{
-                'active': activeStage === stage.key,
-                'completed': stage.status === 'completed',
-                'in-progress': stage.status === 'in_progress',
-                'pending': stage.status === 'pending'
-              }"
-              @click="handleStageClick(stage)"
-            >
-              <div class="timeline-marker">
-                <i v-if="stage.status === 'completed'" class="el-icon-check"></i>
-                <i v-else-if="stage.status === 'in_progress'" class="el-icon-loading"></i>
-                <i v-else class="el-icon-time"></i>
-              </div>
-
-              <div class="timeline-content">
-                <div class="stage-header">
-                  <span class="stage-name">{{ stage.name }}</span>
-                  <el-tag
-                    size="small"
-                    :type="getStageStatusTag(stage.status)"
-                  >
-                    {{ getStageStatusText(stage.status) }}
-                  </el-tag>
+          <div class="timeline-scroll-container">
+            <div class="timeline-container">
+              <div
+                v-for="stage in processStages"
+                :key="stage.key"
+                class="timeline-item"
+                :class="{
+                  active: stage.status == 'active',
+                  completed: stage.status == 'completed',
+                  progress: stage.status == 'progress',
+                  pending: stage.status == 'pending'
+                }"
+                @click="handleStageClick(stage)"
+              >
+                <div class="timeline-marker">
+                  <i
+                    v-if="stage.status == 'completed'"
+                    class="el-icon-check"
+                  ></i>
+                  <i
+                    v-else-if="stage.status == 'progress'"
+                    class="el-icon-loading"
+                  ></i>
+                  <i v-else class="el-icon-time"></i>
                 </div>
 
-                <div class="stage-info">
-                  <div v-if="stage.completeTime" class="time-info">
-                    <span>瀹屾垚鏃堕棿: {{ formatTime(stage.completeTime) }}</span>
+                <div class="timeline-content">
+                  <div class="stage-header">
+                    <span class="stage-name">{{ stage.name }}</span>
+                    <dict-tag
+                      :options="dict.type[stage.dict]"
+                      :value="stage.state"
+                    />
                   </div>
-                  <div v-if="stage.updateTime" class="time-info">
-                    <span>鏈�杩戞洿鏂�: {{ formatTime(stage.updateTime) }}</span>
-                  </div>
-                  <div v-if="stage.operator" class="operator-info">
-                    <span>璐熻矗浜�: {{ stage.operator }}</span>
+
+                  <div class="stage-info">
+                    <div v-if="stage.createtime" class="time-info">
+                      鍒涘缓鏃堕棿: {{ formatTime(stage.createtime) }}
+                    </div>
+                    <div v-if="stage.updateTime" class="time-info">
+                      鏈�杩戞洿鏂�: {{ formatTime(stage.updateTime) }}
+                    </div>
+                    <div v-if="stage.operator" class="operator-info">
+                      璐熻矗浜�: {{ stage.operator }}
+                    </div>
                   </div>
                 </div>
               </div>
@@ -57,103 +60,21 @@
           </div>
         </div>
 
-        <!-- 鍙充晶鍐呭鍖哄煙 -->
+        <!-- 鍙充晶鍐呭 -->
         <div class="content-section">
-          <!-- 妗堜緥鍩烘湰淇℃伅 -->
-          <div class="basic-info-section">
-            <div class="section-header">
-              <h3>妗堜緥鍩烘湰淇℃伅</h3>
-              <el-button
-                type="primary"
-                size="small"
-                @click="handleEditBasicInfo"
-              >
-                缂栬緫淇℃伅
-              </el-button>
-            </div>
+          <case-basic-info :case-id="caseId" :show-attachment="true" />
 
-            <el-descriptions :column="2" border>
-              <el-descriptions-item label="浣忛櫌鍙�">
-                {{ caseInfo.caseNo }}
-              </el-descriptions-item>
-              <el-descriptions-item label="浣忛櫌鍙�">
-                {{ caseInfo.hospitalNo }}
-              </el-descriptions-item>
-              <el-descriptions-item label="鎹愮尞鑰呭鍚�">
-                {{ caseInfo.donorName }}
-              </el-descriptions-item>
-              <el-descriptions-item label="鎬у埆">
-                <dict-tag
-                  :options="dict.type.sys_user_sex"
-                  :value="parseInt(caseInfo.gender)"
-                />
-              </el-descriptions-item>
-              <el-descriptions-item label="骞撮緞">
-                {{ caseInfo.age }} 宀�
-              </el-descriptions-item>
-              <el-descriptions-item label="琛�鍨�">
-                <dict-tag
-                  :options="dict.type.sys_BloodType"
-                  :value="caseInfo.bloodType"
-                />
-              </el-descriptions-item>
-              <el-descriptions-item label="鐤剧梾璇婃柇">
-                {{ caseInfo.diagnosis }}
-              </el-descriptions-item>
-              <el-descriptions-item label="妗堜緥鐘舵��">
-                <el-tag :type="getOverallStatusTag(caseInfo.status)">
-                  {{ getStatusText(caseInfo.status) }}
-                </el-tag>
-              </el-descriptions-item>
-              <el-descriptions-item label="鍒涘缓鏃堕棿">
-                {{ formatTime(caseInfo.createTime) }}
-              </el-descriptions-item>
-              <el-descriptions-item label="鐧昏浜�">
-                {{ caseInfo.registrant }}
-              </el-descriptions-item>
-              <el-descriptions-item label="褰撳墠闃舵">
-                {{ getCurrentStageName() }}
-              </el-descriptions-item>
-            </el-descriptions>
-          </div>
-
-          <!-- 闃舵璇︽儏鍐呭 -->
           <div class="stage-detail-section">
             <div class="section-header">
               <h3>{{ activeStageName }} - 闃舵璇︽儏</h3>
-              <div class="stage-actions">
-                <!-- <el-button
-                  v-if="activeStageData.status !== 'completed'"
-                  type="success"
-                  size="small"
-                  @click="handleCompleteStage"
-                >
-                  瀹屾垚闃舵
-                </el-button>
-                <el-button
-                  type="primary"
-                  size="small"
-                  @click="handleViewDetail"
-                >
-                  鏌ョ湅璇︽儏
-                </el-button>
-                <el-button
-                  v-if="activeStageData.status === 'completed'"
-                  type="warning"
-                  size="small"
-                  @click="handleModifyStage"
-                >
-                  淇敼淇℃伅
-                </el-button> -->
-              </div>
             </div>
 
-            <!-- 鍔ㄦ�侀樁娈靛唴瀹� -->
-            <div class="stage-content">
+            <div class="stage-content-wrapper">
               <component
                 :is="getStageComponent()"
                 :stageData="activeStageData"
                 :caseInfo="caseInfo"
+                :infoid="caseId"
               />
             </div>
           </div>
@@ -164,298 +85,200 @@
 </template>
 
 <script>
-import { getDonationProcessDetail } from './donationProcess';
-import DonorMaintenanceStage from './components/DonorMaintenanceStage';
-import MedicalAssessmentStage from './components/MedicalAssessmentStage';
-import DeathJudgmentStage from './components/DeathJudgmentStage';
-import DonationConfirmStage from './components/DonationConfirmStage';
-import EthicalReviewStage from './components/EthicalReviewStage';
-import OrganAllocationStage from './components/OrganAllocationStage';
-import OrganProcurementStage from './components/OrganProcurementStage';
-import OrganUtilizationStage from './components/OrganUtilizationStage';
+// ===================== 瀛楀吀 Label 鈫� UI 涓婚 =====================
+function mapDictLabelToTheme(label) {
+  if (!label) return "pending";
+
+  const l = label.trim();
+
+  // 寰� XX
+  if (/^寰�/.test(l)) {
+    return "progress";
+  }
+
+  // XX涓�
+  if (/涓�$/.test(l)) {
+    return "active";
+  }
+
+  // 瀹屾垚 / 瀹屾垚XX
+  if (/瀹屾垚/.test(l)) {
+    return "completed";
+  }
+
+  // 寮冪敤 / 鏀惧純
+  if (/寮冪敤|鏀惧純/.test(l)) {
+    return "danger";
+  }
+
+  return "pending";
+}
+import { getDonatebaseinfoflow } from "@/api/project/donatebaseinfo";
+import CaseBasicInfo from "@/components/CaseBasicInfo";
+
+import DonorMaintenanceStage from "./components/DonorMaintenanceStage";
+import DeathJudgmentStage from "./components/DeathJudgmentStage";
+import MedicalAssessmentStage from "./components/MedicalAssessmentStage";
+import DonationConfirmStage from "./components/DonationConfirmStage";
+import EthicalReviewStage from "./components/EthicalReviewStage";
+import OrganAllocationStage from "./components/OrganAllocationStage";
+import OrganProcurementStage from "./components/OrganProcurementStage";
+import OrganUtilizationStage from "./components/OrganUtilizationStage";
+
 import dayjs from "dayjs";
 
+// ============== 瀛楀吀鏄犲皠锛堜綘鍚庨潰鑷繁鏀癸級 ==============
+const STAGE_DICT_MAP = {
+  donatemaintenance: "maintain_type",
+  deathinfo: "decide_type",
+  medicalevaluation: "state_Evaluation",
+  relativesconfirmation: "affirm_type",
+  donateflowcharts: "sys_ethical",
+  donateorgansService: "allocation_Status",
+  donationwitness: "Obtain_status",
+  donatecompletioninfo: "utilize_statue"
+};
+
+// state -> 娴佺▼鐘舵��
+const STATE_MAP = {
+  0: "pending",
+  1: "progress",
+  2: "completed",
+  3: "terminated"
+};
+
+// 闃舵閰嶇疆
+const STAGE_CONFIG = [
+  { key: "donor_maintenance", name: "渚涜�呯淮鎶�", apiKey: "donatemaintenance" },
+  { key: "death_judgment", name: "姝讳骸鍒ゅ畾", apiKey: "deathinfo" },
+  { key: "medical_assessment", name: "鍖诲璇勪及", apiKey: "medicalevaluation" },
+  {
+    key: "donation_confirm",
+    name: "鎹愮尞纭",
+    apiKey: "relativesconfirmation"
+  },
+  { key: "ethical_review", name: "浼︾悊瀹℃煡", apiKey: "donateflowcharts" },
+  { key: "organ_allocation", name: "鍣ㄥ畼鍒嗛厤", apiKey: "donateorgansService" },
+  { key: "organ_procurement", name: "鍣ㄥ畼鑾峰彇", apiKey: "donationwitness" },
+  { key: "organ_utilization", name: "鍣ㄥ畼鍒╃敤", apiKey: "donatecompletioninfo" }
+];
+
 export default {
-  name: 'DonationProcessDetail',
+  name: "DonationProcessDetail",
   components: {
+    CaseBasicInfo,
     DonorMaintenanceStage,
-    MedicalAssessmentStage,
     DeathJudgmentStage,
+    MedicalAssessmentStage,
     DonationConfirmStage,
     EthicalReviewStage,
     OrganAllocationStage,
     OrganProcurementStage,
     OrganUtilizationStage
   },
-  dicts: ['sys_user_sex', 'sys_BloodType', 'sys_0_1'],
+  dicts: [
+    "decide_type",
+    "maintain_type",
+    "state_Evaluation",
+    "affirm_type",
+    "sys_ethical",
+    "allocation_Status",
+    "Obtain_status",
+    "utilize_statue"
+  ], // 杩欓噷鍙0鏄庝竴涓嵆鍙紝鍏朵綑閫氳繃 dict.type[xxx] 浣跨敤
   data() {
     return {
       caseId: null,
-      caseInfo: {
-        id: '',
-        caseNo: '',
-        hospitalNo: '',
-        donorName: '',
-        gender: '',
-        age: '',
-        bloodType: '',
-        diagnosis: '',
-        status: 'in_progress',
-        createTime: '',
-        registrant: '',
-        currentStage: 'donor_maintenance'
-      },
-      processStages: [
-        {
-          key: 'donor_maintenance',
-          name: '渚涜�呯淮鎶�',
-          status: 'completed',
-          completeTime: '2025-12-01 10:00:00',
-          updateTime: '2025-12-01 10:00:00',
-          operator: '寮犲尰鐢�'
-        },
-        {
-          key: 'medical_assessment',
-          name: '鍖诲璇勪及',
-          status: 'completed',
-          completeTime: '2025-12-02 14:30:00',
-          updateTime: '2025-12-02 14:30:00',
-          operator: '鏉庝富浠�'
-        },
-        {
-          key: 'death_judgment',
-          name: '姝讳骸鍒ゅ畾',
-          status: 'completed',
-          completeTime: '2025-12-03 09:15:00',
-          updateTime: '2025-12-03 09:15:00',
-          operator: '鐜嬪尰鐢�'
-        },
-        {
-          key: 'donation_confirm',
-          name: '鎹愮尞纭',
-          status: 'completed',
-          completeTime: '2025-12-03 11:00:00',
-          updateTime: '2025-12-03 11:00:00',
-          operator: '璧靛崗璋冨憳'
-        },
-        {
-          key: 'ethical_review',
-          name: '浼︾悊瀹℃煡',
-          status: 'completed',
-          completeTime: '2025-12-03 15:20:00',
-          updateTime: '2025-12-03 15:20:00',
-          operator: '浼︾悊濮斿憳浼�'
-        },
-        {
-          key: 'organ_allocation',
-          name: '鍣ㄥ畼鍒嗛厤',
-          status: 'in_progress',
-          updateTime: '2025-12-04 10:00:00',
-          operator: '鍒嗛厤绯荤粺'
-        },
-        {
-          key: 'organ_procurement',
-          name: '鍣ㄥ畼鑾峰彇',
-          status: 'pending',
-          operator: '寰呭垎閰�'
-        },
-        {
-          key: 'organ_utilization',
-          name: '鍣ㄥ畼鍒╃敤',
-          status: 'pending',
-          operator: '寰呭垎閰�'
-        }
-      ],
-      activeStage: 'organ_allocation',
-      activeStageName: '鍣ㄥ畼鍒嗛厤',
-      activeStageData: {},
-      loading: false
+      caseInfo: {},
+      processStages: [],
+      activeStage: "",
+      activeStageName: "",
+      activeStageData: {}
     };
-  },
-  computed: {
-
   },
   created() {
     this.caseId = this.$route.query.id;
     if (this.caseId) {
       this.getDetail();
-    } else {
-      this.generateMockData();
     }
-    this.setActiveStage(this.activeStage);
   },
   methods: {
-       getStageComponent() {
-      const componentMap = {
-        'donor_maintenance': 'DonorMaintenanceStage',
-        'medical_assessment': 'MedicalAssessmentStage',
-        'death_judgment': 'DeathJudgmentStage',
-        'donation_confirm': 'DonationConfirmStage',
-        'ethical_review': 'EthicalReviewStage',
-        'organ_allocation': 'OrganAllocationStage',
-        'organ_procurement': 'OrganProcurementStage',
-        'organ_utilization': 'OrganUtilizationStage'
-      };
-      return componentMap[this.activeStage];
-    },
-    // 鑾峰彇璇︽儏鏁版嵁
     async getDetail() {
-      this.loading = true;
       try {
-        const response = await getDonationProcessDetail(this.caseId);
-        if (response.code === 200) {
-          this.caseInfo = response.data.caseInfo;
-          this.processStages = response.data.processStages;
-          this.setActiveStage(response.data.currentStage);
-        }
-      } catch (error) {
-        console.error('鑾峰彇鎹愮尞杩涚▼璇︽儏澶辫触:', error);
-        this.$message.error('鑾峰彇璇︽儏澶辫触');
-      } finally {
-        this.loading = false;
-      }
-    },
-    // 鐢熸垚妯℃嫙鏁版嵁
-    generateMockData() {
-      this.caseInfo = {
-        id: '202512001',
-        caseNo: 'C202512001',
-        hospitalNo: 'D202512001',
-        donorName: '寮犱笁',
-        gender: '0',
-        age: 45,
-        bloodType: 'A',
-        diagnosis: '鑴戝浼�',
-        status: 'in_progress',
-        createTime: '2025-12-01 08:00:00',
-        registrant: '鏉庡崗璋冨憳',
-        currentStage: 'organ_allocation'
-      };
-    },
-    // 璁剧疆褰撳墠婵�娲婚樁娈�
-    setActiveStage(stageKey) {
-      this.activeStage = stageKey;
-      const stage = this.processStages.find(s => s.key === stageKey);
-      if (stage) {
-        this.activeStageName = stage.name;
-        this.activeStageData = stage;
-      }
-    },
-    // 澶勭悊闃舵鐐瑰嚮
-    handleStageClick(stage) {
-      if (stage.status !== 'pending') {
-        this.setActiveStage(stage.key);
-      } else {
-        this.$message.warning('璇ラ樁娈靛皻鏈紑濮嬶紝鏃犳硶鏌ョ湅璇︽儏');
-      }
-    },
-    // 鑾峰彇闃舵鐘舵�佹爣绛剧被鍨�
-    getStageStatusTag(status) {
-      const map = {
-        'completed': 'success',
-        'in_progress': 'warning',
-        'pending': 'info'
-      };
-      return map[status] || 'info';
-    },
-    // 鑾峰彇闃舵鐘舵�佹枃鏈�
-    getStageStatusText(status) {
-      const map = {
-        'completed': '宸插畬鎴�',
-        'in_progress': '杩涜涓�',
-        'pending': '鏈紑濮�'
-      };
-      return map[status] || '鏈煡';
-    },
-    // 鑾峰彇鏁翠綋鐘舵�佹爣绛剧被鍨�
-    getOverallStatusTag(status) {
-      const map = {
-        'completed': 'success',
-        'in_progress': 'warning',
-        'pending': 'info',
-        'terminated': 'danger'
-      };
-      return map[status] || 'info';
-    },
-    // 鑾峰彇鏁翠綋鐘舵�佹枃鏈�
-    getStatusText(status) {
-      const map = {
-        'completed': '宸插畬鎴�',
-        'in_progress': '杩涜涓�',
-        'pending': '鏈紑濮�',
-        'terminated': '宸茬粓姝�'
-      };
-      return map[status] || '鏈煡';
-    },
-    // 鏃堕棿鏍煎紡鍖�
-    formatTime(time) {
-      if (!time) return '-';
-      return dayjs(time).format('YYYY-MM-DD HH:mm');
-    },
+        const res = await getDonatebaseinfoflow(this.caseId);
 
-    // 鑾峰彇褰撳墠闃舵鍚嶇О
-    getCurrentStageName() {
-      const currentStage = this.processStages.find(
-        stage => stage.status === 'in_progress'
-      );
-      return currentStage ? currentStage.name : '宸插畬鎴�';
-    },
-    // 缂栬緫鍩烘湰淇℃伅
-    handleEditBasicInfo() {
-      this.$message.info('缂栬緫鍩烘湰淇℃伅鍔熻兘');
-    },
-    // 瀹屾垚闃舵
-    handleCompleteStage() {
-      this.$confirm(`纭畾瑕佸畬鎴愩��${this.activeStageName}銆戦樁娈靛悧锛焋, '鎻愮ず', {
-        confirmButtonText: '纭畾',
-        cancelButtonText: '鍙栨秷',
-        type: 'warning'
-      }).then(() => {
-        // 鏇存柊褰撳墠闃舵鐘舵��
-        const currentIndex = this.processStages.findIndex(
-          stage => stage.key === this.activeStage
-        );
+        const data = res;
 
-        if (currentIndex !== -1) {
-          this.processStages[currentIndex].status = 'completed';
-          this.processStages[currentIndex].completeTime = new Date().toISOString();
+        this.caseInfo = data.donatebaseinfo || {};
 
-          // 婵�娲讳笅涓�涓樁娈�
-          if (currentIndex < this.processStages.length - 1) {
-            this.processStages[currentIndex + 1].status = 'in_progress';
-            this.setActiveStage(this.processStages[currentIndex + 1].key);
-          } else {
-            this.caseInfo.status = 'completed';
-          }
+        this.processStages = STAGE_CONFIG.map(stage => {
+          const obj = data[stage.apiKey] || {};
+          console.log(stage.apiKey, "stage.apiKey");
+          console.log(this.dict?.type?.[STAGE_DICT_MAP[stage.apiKey]]);
 
-          this.$message.success('闃舵宸插畬鎴�');
-        }
-      });
-    },
-    // 鏌ョ湅璇︽儏
-    handleViewDetail() {
-      const routeMap = {
-        'donor_maintenance': '/case/donorMaintenance/detail',
-        'medical_assessment': '/case/medicalAssessment/detail',
-        'death_judgment': '/case/deathJudgment/detail',
-        'donation_confirm': '/case/donationConfirm/detail',
-        'ethical_review': '/case/ethicalReview/detail',
-        'organ_allocation': '/case/organAllocation/detail',
-        'organ_procurement': '/case/organProcurement/detail',
-        'organ_utilization': '/case/organUtilization/detail'
-      };
+          const dictLabel =
+            this.dict?.type?.[STAGE_DICT_MAP[stage.apiKey]]?.find(
+              d => d.value == obj.state
+            )?.label || "";
 
-      const route = routeMap[this.activeStage];
-      if (route) {
-        this.$router.push({
-          path: route,
-          query: { id: this.caseId }
+          const theme = mapDictLabelToTheme(dictLabel);
+
+          return {
+            key: stage.key,
+            name: stage.name,
+            dict: STAGE_DICT_MAP[stage.apiKey],
+            state: obj.state,
+            dictLabel,
+            status: theme, // 鉁� 鏍稿績锛歎I 涓婚鐢� dictLabel 鍐冲畾
+            createtime: obj.createtime,
+            updateTime: obj.updatetime,
+            operator: obj.updateperson || obj.createperson
+          };
         });
+
+        const active =
+          this.processStages.find(s => s.status == "progress") ||
+          [...this.processStages].reverse().find(s => s.status == "completed");
+
+        this.setActiveStage(active?.key || STAGE_CONFIG[0].key);
+      } catch (e) {
+        console.error(e);
+        this.$message.error("鑾峰彇娴佺▼璇︽儏澶辫触");
       }
     },
-    // 淇敼闃舵淇℃伅
-    handleModifyStage() {
-      this.$message.info(`淇敼${this.activeStageName}淇℃伅鍔熻兘`);
+
+    setActiveStage(key) {
+      const stage = this.processStages.find(s => s.key == key);
+      if (!stage) return;
+      this.activeStage = key;
+      this.activeStageName = stage.name;
+      this.activeStageData = stage;
+    },
+
+    getStageComponent() {
+      const map = {
+        donor_maintenance: "DonorMaintenanceStage",
+        death_judgment: "DeathJudgmentStage",
+        medical_assessment: "MedicalAssessmentStage",
+        donation_confirm: "DonationConfirmStage",
+        ethical_review: "EthicalReviewStage",
+        organ_allocation: "OrganAllocationStage",
+        organ_procurement: "OrganProcurementStage",
+        organ_utilization: "OrganUtilizationStage"
+      };
+      return map[this.activeStage];
+    },
+
+    handleStageClick(stage) {
+      if (stage.status == "pending") {
+        this.$message.warning("璇ラ樁娈靛皻鏈紑濮�");
+        return;
+      }
+      this.setActiveStage(stage.key);
+    },
+
+    formatTime(time) {
+      return time ? dayjs(time).format("YYYY-MM-DD HH:mm") : "-";
     }
   }
 };
@@ -466,47 +289,190 @@
   padding: 20px;
   background-color: #f5f7fa;
   min-height: 100vh;
+  box-sizing: border-box;
 }
 
 .process-card {
   border-radius: 8px;
   box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+  margin-bottom: 20px;
 }
 
 .process-container {
   display: flex;
-  min-height: 800px;
+  min-height: 600px;
+  /* 璁剧疆涓�涓渶灏忛珮搴� */
   gap: 20px;
+  align-items: flex-start;
+  /* 椤堕儴瀵归綈 */
 }
 
-/* 宸︿晶鏃堕棿绾挎牱寮� */
+/* 宸︿晶鏃堕棿绾挎牱寮� - 鍥哄畾楂樺害锛屽唴閮ㄦ粴鍔� */
 .timeline-section {
-  flex: 0 0 300px;
+  flex: 0 0 320px;
+  /* 鍥哄畾瀹藉害 */
+  display: flex;
+  flex-direction: column;
   background: white;
   border-radius: 6px;
   padding: 20px;
   box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
+  height: calc(120vh - 120px);
+  /* 鏍规嵁瑙嗗彛楂樺害鑷�傚簲 */
+  max-height: 1200px;
+  /* 璁剧疆鏈�澶ч珮搴� */
+  position: sticky;
+  /* 浣跨敤 sticky 瀹氫綅 */
+  top: 20px;
+  /* 璺濈椤堕儴 20px */
 }
 
-.section-header {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  margin-bottom: 20px;
-  padding-bottom: 15px;
-  border-bottom: 1px solid #e4e7ed;
+.timeline-scroll-container {
+  flex: 1;
+  overflow-y: auto;
+  /* 鍐呴儴鍙粴鍔� */
+  margin-top: 20px;
+  padding-right: 8px;
+  /* 涓烘粴鍔ㄦ潯鐣欏嚭绌洪棿 */
 }
 
-.section-header h3 {
-  margin: 0;
-  color: #303133;
-  font-size: 16px;
+.timeline-scroll-container::-webkit-scrollbar {
+  width: 6px;
+}
+
+.timeline-scroll-container::-webkit-scrollbar-track {
+  background: #f1f1f1;
+  border-radius: 3px;
+}
+
+.timeline-scroll-container::-webkit-scrollbar-thumb {
+  background: #c1c1c1;
+  border-radius: 3px;
+}
+
+.timeline-scroll-container::-webkit-scrollbar-thumb:hover {
+  background: #a8a8a8;
 }
 
 .timeline-container {
   display: flex;
   flex-direction: column;
   gap: 15px;
+  padding-bottom: 10px;
+}
+
+/* 鍙充晶鍐呭鍖哄煙鏍峰紡 - 鑷�傚簲楂樺害 */
+.content-section {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  gap: 20px;
+  min-height: 0;
+  /* 閲嶈锛氬厑璁竑lex瀛愰」鍘嬬缉 */
+}
+
+.basic-info-section {
+  background: white;
+  border-radius: 6px;
+  padding: 20px;
+  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
+  display: flex;
+  flex-direction: column;
+  min-height: 0;
+  /* 閲嶈 */
+}
+
+.basic-info-content {
+  flex: 1;
+  max-height: 300px;
+  /* 鍩烘湰淇℃伅鍖哄煙鏈�澶ч珮搴� */
+  overflow-y: auto;
+  /* 鍩烘湰淇℃伅鍐呴儴鍙粴鍔� */
+  margin-top: 20px;
+  padding-right: 8px;
+}
+
+.basic-info-content::-webkit-scrollbar {
+  width: 6px;
+}
+
+.basic-info-content::-webkit-scrollbar-track {
+  background: #f1f1f1;
+  border-radius: 3px;
+}
+
+.basic-info-content::-webkit-scrollbar-thumb {
+  background: #c1c1c1;
+  border-radius: 3px;
+}
+
+.basic-info-content::-webkit-scrollbar-thumb:hover {
+  background: #a8a8a8;
+}
+
+.basic-info-content .el-descriptions {
+  width: 100%;
+}
+
+.stage-detail-section {
+  flex: 1;
+  /* 鍗犳嵁鍓╀綑绌洪棿 */
+  background: white;
+  border-radius: 6px;
+  padding: 20px;
+  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
+  display: flex;
+  flex-direction: column;
+  min-height: 400px;
+  /* 鏈�灏忛珮搴� */
+  max-height: 800px;
+  /* 鏈�澶ч珮搴︼紝鍙牴鎹渶瑕佽皟鏁� */
+  overflow: hidden;
+  /* 闅愯棌澶栧眰婧㈠嚭 */
+}
+
+.stage-content-wrapper {
+  flex: 1;
+  overflow-y: auto;
+  /* 闃舵璇︽儏鍐呴儴鍙粴鍔� */
+  margin-top: 20px;
+  padding-right: 8px;
+  min-height: 0;
+  /* 閲嶈 */
+}
+
+.stage-content-wrapper::-webkit-scrollbar {
+  width: 6px;
+}
+
+.stage-content-wrapper::-webkit-scrollbar-track {
+  background: #f1f1f1;
+  border-radius: 3px;
+}
+
+.stage-content-wrapper::-webkit-scrollbar-thumb {
+  background: #c1c1c1;
+  border-radius: 3px;
+}
+
+.stage-content-wrapper::-webkit-scrollbar-thumb:hover {
+  background: #a8a8a8;
+}
+
+/* 鍘熸湁鏍峰紡淇濇寔涓嶅彉 */
+.section-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  flex-shrink: 0;
+  /* 闃叉琚帇缂� */
+}
+
+.section-header h3 {
+  margin: 0;
+  color: #303133;
+  font-size: 16px;
+  white-space: nowrap;
 }
 
 .timeline-item {
@@ -517,25 +483,34 @@
   cursor: pointer;
   transition: all 0.3s ease;
   border: 1px solid #e4e7ed;
+  flex-shrink: 0;
+  /* 闃叉琚帇缂� */
 }
 
 .timeline-item:hover {
   box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
   transform: translateY(-1px);
 }
+.timeline-item.danger {
+  border-color: #f56c6c;
+  background-color: #fef0f0;
+}
 
+.timeline-item.danger .timeline-marker {
+  background-color: #f56c6c;
+}
 .timeline-item.active {
-  border-color: #409EFF;
+  border-color: #409eff;
   background-color: #f0f9ff;
 }
 
 .timeline-item.completed {
-  border-color: #67C23A;
+  border-color: #67c23a;
   background-color: #f0f9e8;
 }
 
-.timeline-item.in-progress {
-  border-color: #E6A23C;
+.timeline-item.progress {
+  border-color: #e6a23c;
   background-color: #fdf6ec;
 }
 
@@ -557,11 +532,14 @@
 }
 
 .timeline-item.completed .timeline-marker {
-  background-color: #67C23A;
+  background-color: #67c23a;
+}
+.timeline-item.active .timeline-marker {
+  background-color: #409eff;
 }
 
-.timeline-item.in-progress .timeline-marker {
-  background-color: #E6A23C;
+.timeline-item.progress .timeline-marker {
+  background-color: #e6a23c;
 }
 
 .timeline-item.pending .timeline-marker {
@@ -583,6 +561,10 @@
   font-weight: 600;
   color: #303133;
   font-size: 14px;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  max-width: 150px;
 }
 
 .stage-info {
@@ -590,33 +572,18 @@
   color: #606266;
 }
 
-.time-info, .operator-info {
+.time-info,
+.operator-info {
   margin-bottom: 4px;
-}
-
-/* 鍙充晶鍐呭鍖哄煙鏍峰紡 */
-.content-section {
-  flex: 1;
-  display: flex;
-  flex-direction: column;
-  gap: 20px;
-}
-
-.basic-info-section,
-.stage-detail-section {
-  background: white;
-  border-radius: 6px;
-  padding: 20px;
-  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
 }
 
 .stage-actions {
   display: flex;
   gap: 10px;
-}
-
-.stage-content {
-  margin-top: 20px;
+  flex-wrap: wrap;
 }
 
 /* 鍝嶅簲寮忚璁� */
@@ -627,7 +594,19 @@
 
   .timeline-section {
     flex: none;
-    margin-bottom: 20px;
+    width: 100%;
+    height: auto;
+    max-height: 300px;
+    position: static;
+    /* 灏忓睆骞曞彇娑� sticky */
+  }
+
+  .timeline-scroll-container {
+    max-height: 250px;
+  }
+
+  .stage-detail-section {
+    max-height: 500px;
   }
 }
 
@@ -652,26 +631,17 @@
     gap: 10px;
   }
 
-  .stage-actions {
-    flex-wrap: wrap;
+  .stage-name {
+    max-width: 120px;
   }
-}
 
-/* 鍔ㄧ敾鏁堟灉 */
-.timeline-item {
-  transition: all 0.3s ease;
-}
+  .basic-info-content {
+    max-height: 250px;
+  }
 
-.timeline-item:hover {
-  transform: translateY(-2px);
-}
-
-/* 杩涘害鏉℃牱寮忎紭鍖� */
-:deep(.el-progress-bar) {
-  padding-right: 0;
-}
-
-:deep(.el-progress__text) {
-  font-size: 12px;
+  .stage-detail-section {
+    min-height: 300px;
+    max-height: 400px;
+  }
 }
 </style>

--
Gitblit v1.9.3