From c4599aa279fd2f90b741608392e056fbae2282d5 Mon Sep 17 00:00:00 2001
From: WXL <wl_5969728@163.com>
Date: 星期四, 20 八月 2026 17:16:54 +0800
Subject: [PATCH] 各表单布局调整

---
 src/views/business/course/components/OrganUtilizationStage.vue | 1929 ++++++++++++++++++++++++++++++++++++----------------------
 1 files changed, 1,198 insertions(+), 731 deletions(-)

diff --git a/src/views/business/course/components/OrganUtilizationStage.vue b/src/views/business/course/components/OrganUtilizationStage.vue
index aa76231..a3e8163 100644
--- a/src/views/business/course/components/OrganUtilizationStage.vue
+++ b/src/views/business/course/components/OrganUtilizationStage.vue
@@ -1,812 +1,1279 @@
 <template>
-  <base-stage :stage-data="stageData" :case-info="caseInfo">
-    <!-- 澶撮儴璀﹀憡淇℃伅 -->
-    <template #header>
-      <el-alert
-        :title="`鍣ㄥ畼鍒╃敤 - ${getStatusText()}`"
-        :type="getAlertType()"
-        :description="getAlertDescription()"
-        show-icon
-        :closable="false"
-      />
-    </template>
+  <div class="organ-procurement-detail">
+    <!-- <case-basic-info :case-id="caseId" :show-attachment="true":column="3" /> -->
 
-    <!-- 缁熻姒傝琛� -->
-    <el-row :gutter="20" style="margin-top: 20px;">
-      <el-col :span="6">
-        <el-card>
-          <div slot="header" class="card-header">
-            <span>鍒╃敤姒傚喌</span>
-          </div>
-          <div class="utilization-overview">
-            <div class="overview-item">
-              <div class="overview-icon" style="color: #67C23A;">
-                <i class="el-icon-success"></i>
-              </div>
-              <div class="overview-content">
-                <div class="value">{{ utilizationStats.transplanted }}</div>
-                <div class="label">宸茬Щ妞嶅櫒瀹�</div>
-              </div>
-            </div>
-            <div class="overview-item">
-              <div class="overview-icon" style="color: #E6A23C;">
-                <i class="el-icon-time"></i>
-              </div>
-              <div class="overview-content">
-                <div class="value">{{ utilizationStats.inProgress }}</div>
-                <div class="label">绉绘涓�</div>
-              </div>
-            </div>
-            <div class="overview-item">
-              <div class="overview-icon" style="color: #F56C6C;">
-                <i class="el-icon-warning"></i>
-              </div>
-              <div class="overview-content">
-                <div class="value">{{ utilizationStats.failed }}</div>
-                <div class="label">绉绘澶辫触</div>
-              </div>
-            </div>
-          </div>
-        </el-card>
-      </el-col>
-
-      <el-col :span="6">
-        <el-card>
-          <div slot="header" class="card-header">
-            <span>鎴愬姛鐜囩粺璁�</span>
-          </div>
-          <div class="success-stats">
-            <div class="success-item">
-              <span class="label">绉绘鎴愬姛鐜�:</span>
-              <el-progress
-                :percentage="utilizationStats.successRate"
-                :status="utilizationStats.successRate > 85 ? 'success' : 'warning'"
-              />
-            </div>
-            <div class="success-item">
-              <span class="label">鍣ㄥ畼鍒╃敤鐜�:</span>
-              <el-progress
-                :percentage="utilizationStats.utilizationRate"
-                status="success"
-              />
-            </div>
-            <div class="success-item">
-              <span class="label">鎮h�呭瓨娲荤巼:</span>
-              <el-progress
-                :percentage="utilizationStats.survivalRate"
-                status="success"
-              />
-            </div>
-          </div>
-        </el-card>
-      </el-col>
-
-      <el-col :span="6">
-        <el-card>
-          <div slot="header" class="card-header">
-            <span>鏃堕棿璺熻釜</span>
-          </div>
-          <div class="time-tracking">
-            <div class="time-item">
-              <span class="label">鑾峰彇鍒扮Щ妞�:</span>
-              <span class="value">{{ timeTracking.procurementToTransplant }}</span>
-            </div>
-            <div class="time-item">
-              <span class="label">鍐风己琛�鏃堕棿:</span>
-              <span class="value">{{ timeTracking.coldIschemiaTime }}</span>
-            </div>
-            <div class="time-item">
-              <span class="label">鎵嬫湳鏃堕暱:</span>
-              <span class="value">{{ timeTracking.surgeryDuration }}</span>
-            </div>
-            <div class="time-item">
-              <span class="label">ICU鍋滅暀:</span>
-              <span class="value">{{ timeTracking.icuStay }}</span>
-            </div>
-          </div>
-        </el-card>
-      </el-col>
-
-      <el-col :span="6">
-        <el-card>
-          <div slot="header" class="card-header">
-            <span>璐ㄩ噺璇勪及</span>
-          </div>
-          <div class="quality-assessment">
-            <div class="quality-item">
-              <span class="label">鍣ㄥ畼璐ㄩ噺璇勫垎:</span>
-              <el-rate
-                v-model="qualityStats.organQuality"
-                disabled
-                show-score
-                text-color="#ff9900"
-                score-template="{value}"
-              />
-            </div>
-            <div class="quality-item">
-              <span class="label">鎵嬫湳璐ㄩ噺:</span>
-              <el-rate
-                v-model="qualityStats.surgeryQuality"
-                disabled
-                show-score
-                text-color="#ff9900"
-                score-template="{value}"
-              />
-            </div>
-            <div class="quality-item">
-              <span class="label">闅忚瀹屾垚鐜�:</span>
-              <el-progress
-                :percentage="qualityStats.followupCompletionRate"
-                status="success"
-              />
-            </div>
-          </div>
-        </el-card>
-      </el-col>
-    </el-row>
-
-    <!-- 鏁版嵁鍙鍖栭儴鍒� -->
-    <el-row :gutter="20" style="margin-top: 20px;">
-      <!-- 鍣ㄥ畼鍒╃敤鍒嗗竷鍥� -->
-      <el-col :span="12">
-        <el-card>
-          <div slot="header" class="card-header">
-            <span>鍣ㄥ畼鍒╃敤鍒嗗竷</span>
-            <el-radio-group v-model="chartView" size="small" @change="updateCharts">
-              <el-radio-button label="bar">鏌辩姸鍥�</el-radio-button>
-              <el-radio-button label="pie">楗煎浘</el-radio-button>
-            </el-radio-group>
-          </div>
-          <div class="chart-container">
-            <div ref="organDistributionChart" style="width: 100%; height: 300px;"></div>
-          </div>
-        </el-card>
-      </el-col>
-
-      <!-- 鎴愬姛鐜囪秼鍔垮浘 -->
-      <el-col :span="12">
-        <el-card>
-          <div slot="header" class="card-header">
-            <span>绉绘鎴愬姛鐜囪秼鍔�</span>
-          </div>
-          <div class="chart-container">
-            <div ref="successTrendChart" style="width: 100%; height: 300px;"></div>
-          </div>
-        </el-card>
-      </el-col>
-    </el-row>
-
-    <el-row :gutter="20" style="margin-top: 20px;">
-      <!-- 闅忚鏁版嵁缁熻 -->
-      <el-col :span="12">
-        <el-card>
-          <div slot="header" class="card-header">
-            <span>闅忚鏁版嵁缁熻</span>
-          </div>
-          <div class="chart-container">
-            <div ref="followupStatsChart" style="width: 100%; height: 300px;"></div>
-          </div>
-        </el-card>
-      </el-col>
-
-      <!-- 骞跺彂鐥囧垎鏋� -->
-      <el-col :span="12">
-        <el-card>
-          <div slot="header" class="card-header">
-            <span>骞跺彂鐥囧垎鏋�</span>
-          </div>
-          <div class="chart-container">
-            <div ref="complicationChart" style="width: 100%; height: 300px;"></div>
-          </div>
-        </el-card>
-      </el-col>
-    </el-row>
-
-    <!-- 璇︾粏鏁版嵁琛ㄦ牸 -->
-    <el-card style="margin-top: 20px;">
-      <div slot="header" class="card-header">
-        <span>鍣ㄥ畼鍒╃敤璇︽儏</span>
-        <el-button type="primary" size="small" @click="exportData">
-          瀵煎嚭鏁版嵁
-        </el-button>
+    <!-- 鍩烘湰淇℃伅 -->
+    <el-card class="detail-card">
+      <div slot="header" class="clearfix">
+        <span class="detail-title">鍣ㄥ畼鑾峰彇鍩烘湰淇℃伅</span>
       </div>
 
-      <el-table :data="organUtilizationData" v-loading="loading" border>
-        <el-table-column label="鍣ㄥ畼鍚嶇О" prop="organName" width="120" align="center" />
-        <el-table-column label="绉绘鐘舵��" width="100" align="center">
-          <template slot-scope="scope">
-            <el-tag :type="getTransplantStatusTag(scope.row.status)">
-              {{ scope.row.status }}
-            </el-tag>
-          </template>
-        </el-table-column>
-        <el-table-column label="鍙椾綋淇℃伅" width="150">
-          <template slot-scope="scope">
-            <div>{{ scope.row.recipientName }}</div>
-            <div style="font-size: 12px; color: #909399;">{{ scope.row.recipientAge }}宀�/{{ scope.row.recipientGender }}</div>
-          </template>
-        </el-table-column>
-        <el-table-column label="绉绘鍖婚櫌" prop="hospital" min-width="180" />
-        <el-table-column label="绉绘鏃堕棿" width="160" align="center">
-          <template slot-scope="scope">
-            {{ formatTime(scope.row.transplantTime) }}
-          </template>
-        </el-table-column>
-        <el-table-column label="闅忚娆℃暟" width="100" align="center">
-          <template slot-scope="scope">
-            <el-tag :type="scope.row.followupCount > 0 ? 'success' : 'info'">
-              {{ scope.row.followupCount }}
-            </el-tag>
-          </template>
-        </el-table-column>
-        <el-table-column label="褰撳墠鐘舵��" width="120" align="center">
-          <template slot-scope="scope">
-            <el-tag :type="getRecipientStatusTag(scope.row.recipientStatus)">
-              {{ scope.row.recipientStatus }}
-            </el-tag>
-          </template>
-        </el-table-column>
-        <el-table-column label="鎿嶄綔" width="150" align="center">
-          <template slot-scope="scope">
-            <el-button type="text" size="small" @click="handleViewDetails(scope.row)">
-              鏌ョ湅璇︽儏
-            </el-button>
-            <el-button type="text" size="small" @click="handleAddFollowup(scope.row)">
-              娣诲姞闅忚
-            </el-button>
-          </template>
-        </el-table-column>
-      </el-table>
+      <el-descriptions title="鎵嬫湳淇℃伅" :column="descriptionColumn" border size="small">
+        <el-descriptions-item label="鎵嬫湳鍖荤敓">{{ form.operationdoctor || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="鎵嬫湳寮�濮嬫椂闂�">{{ form.operationbegtime || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="鎵嬫湳缁撴潫鏃堕棿">{{ form.operationendtime || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="鑵逛富鍔ㄨ剦鎻掔鏃堕棿">{{ form.abdominalaortacannulatime || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="鑵逛富鍔ㄨ剦鐏屾敞鏃堕棿">{{ form.abdominalaortaperfusiontime || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="闂ㄩ潤鑴夋彃绠℃椂闂�">{{ form.portalveincannulatime || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="闂ㄩ潤鑴夌亴娉ㄦ椂闂�">{{ form.portalveinperfusiontime || '-' }}</el-descriptions-item>
+      </el-descriptions>
+
+      <el-descriptions title="鍗忚皟鍛樹俊鎭�" :column="descriptionColumn" border size="small">
+        <el-descriptions-item label="杩涙墜鏈鏃堕棿">{{ form.coordinatorInOperating || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="鍑烘墜鏈鏃堕棿">{{ form.coordinatorOutOperating || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="鏄惁榛樺搥缂呮��">{{ form.isspendremember === 1 ? '鏄�' : form.isspendremember === 0 ? '鍚�' : '-' }}</el-descriptions-item>
+        <el-descriptions-item label="鎭㈠閬椾綋浠">{{ form.isrestoreremains === 1 ? '鏄�' : form.isrestoreremains === 0 ? '鍚�' : '-' }}</el-descriptions-item>
+      </el-descriptions>
+
+      <el-descriptions title="璐熻矗浜轰俊鎭�" :column="descriptionColumn" border size="small">
+        <el-descriptions-item label="璐熻矗浜哄鍚�">{{ form.responsibleusername || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="鍗忚皟鍛樹竴">{{ form.coordinatedusernameo || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="鍗忚皟鍛樹簩">{{ form.coordinatedusernamet || '-' }}</el-descriptions-item>
+      </el-descriptions>
+
+      <el-descriptions title="鑾峰彇鏈烘瀯淇℃伅" :column="descriptionColumn" border size="small">
+        <el-descriptions-item label="鑾峰彇鏈烘瀯鍚嶇О">{{ form.gainhospitalname || '-' }}</el-descriptions-item>
+      </el-descriptions>
     </el-card>
 
-    <!-- 琛屽姩鎸夐挳 -->
-    <template #footer>
-      <div class="action-buttons" style="margin-top: 20px; text-align: center;">
-        <el-button type="primary" @click="handleGenerateReport">
-          鐢熸垚鍒╃敤鎶ュ憡
-        </el-button>
-        <el-button type="success" @click="handleCompleteUtilization">
-          瀹屾垚鍣ㄥ畼鍒╃敤
-        </el-button>
-        <el-button type="warning" @click="handleStatistics">
-          缁熻鏁版嵁鍒嗘瀽
-        </el-button>
+    <!-- 鍣ㄥ畼鑾峰彇璁板綍閮ㄥ垎 -->
+    <el-card class="procurement-card">
+      <div slot="header" class="clearfix">
+        <span class="detail-title">鍣ㄥ畼鑾峰彇璁板綍</span>
+        <div style="float: right;">
+          <dict-tag
+            :options="dict.type.Obtain_status"
+            :value="form.witnessState"
+          />
+        </div>
       </div>
-    </template>
-  </base-stage>
+
+      <el-descriptions title="鎹愮尞鍣ㄥ畼" :column="1" border size="small" style="margin-bottom: 16px;">
+        <el-descriptions-item label="鎹愮尞鍣ㄥ畼">
+          <template v-if="selectedOrgans && selectedOrgans.length">
+            <span v-for="(v, i) in selectedOrgans" :key="v">
+              {{ getOrganLabel(v) }}<span v-if="i < selectedOrgans.length - 1">銆�</span>
+            </span>
+          </template>
+          <template v-else>-</template>
+        </el-descriptions-item>
+      </el-descriptions>
+
+      <el-table :data="displayOrgans" v-loading="loading" border style="width: 100%">
+        <el-table-column label="鍣ㄥ畼鍚嶇О" align="center" prop="organname" />
+        <el-table-column label="鑾峰彇寮�濮嬫椂闂�" align="center" prop="organStartTime" />
+        <el-table-column label="鍣ㄥ畼绂讳綋鏃堕棿" align="center" prop="organgettime" />
+        <el-table-column label="鑾峰彇鍖婚櫌" align="center" prop="gainhospitalname" show-overflow-tooltip />
+        <el-table-column label="鑾峰彇鍖诲笀" align="center" prop="organgetdoct" />
+        <el-table-column label="璇存槑" align="center" prop="notgetreason" min-width="200" show-overflow-tooltip />
+      </el-table>
+
+      <div v-if="!displayOrgans.length" class="empty-procurement">
+        <el-empty description="鏆傛棤鑾峰彇璁板綍" :image-size="80" />
+      </div>
+    </el-card>
+
+    <!-- 闄勪欢绠$悊閮ㄥ垎 - 鍒嗙被Tab灞曠ず -->
+    <el-card class="attachment-card">
+      <div slot="header" class="clearfix">
+        <span class="detail-title">鐩稿叧闄勪欢</span>
+      </div>
+
+      <!-- 闄勪欢鍒楄〃 - 鍒嗙被Tab灞曠ず -->
+      <el-tabs v-model="activeTab" type="border-card">
+        <el-tab-pane
+          v-for="category in categories"
+          :key="category"
+          :label="category + '(' + getCategoryCount(category) + ')'"
+          :name="category"
+        >
+          <el-table
+            :data="getCategoryFiles(category)"
+            style="width: 100%"
+            size="small"
+            border
+          >
+            <el-table-column label="鏂囦欢鍚�" min-width="180">
+              <template #default="scope">
+                <i
+                  class="el-icon-document"
+                  style="margin-right: 8px; color: #409EFF;"
+                ></i>
+                <span class="file-name">{{ scope.row.fileName }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="鍒嗙被" width="150">
+              <template #default="scope">
+                <span>{{ scope.row.fileType || '鏈垎绫�' }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="鏂囦欢绫诲瀷" width="100">
+              <template #default="scope">
+                <el-tag size="small">{{
+                  getFileTypeText(scope.row.fileName)
+                }}</el-tag>
+              </template>
+            </el-table-column>
+            <el-table-column label="涓婁紶鏃堕棿" width="160">
+              <template #default="scope">
+                <span>{{ formatDateTime(scope.row.uploadTime) }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="鏂囦欢澶у皬" width="100">
+              <template #default="scope">
+                <span>{{ formatFileSize(scope.row.fileSize) }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="鎿嶄綔" width="100" fixed="right">
+              <template #default="scope">
+                <el-button
+                  size="mini"
+                  type="primary"
+                  @click="handlePreview(scope.row)"
+                  >棰勮</el-button
+                >
+              </template>
+            </el-table-column>
+          </el-table>
+          <div
+            v-if="getCategoryFiles(category).length === 0"
+            style="text-align:center; padding:20px; color:#909399;"
+          >
+            鏆傛棤闄勪欢
+          </div>
+        </el-tab-pane>
+      </el-tabs>
+    </el-card>
+    <!-- 鏂囦欢棰勮寮圭獥 -->
+    <FilePreviewDialog
+      :visible="previewVisible"
+      :file="currentPreviewFile"
+      @close="previewVisible = false"
+      @download="handleDownload"
+    />
+  </div>
 </template>
 
 <script>
-import BaseStage from './BaseStage.vue';
-import * as echarts from 'echarts';
+import { witnessList, witnessadd, witnessedit } from "@/api/businessApi";
+import FilePreviewDialog from "@/components/FilePreviewDialog";
+import CaseBasicInfo from "@/components/CaseBasicInfo";
+import { getToken } from "@/utils/auth";
+import dayjs from "dayjs";
+import readonlyDescriptionsMixin from "./readonlyDescriptionsMixin";
 
 export default {
-  name: 'OrganUtilizationStage',
-  components: { BaseStage },
+  name: "OrganProcurementDetail",
+  components: {
+    FilePreviewDialog,
+    CaseBasicInfo
+  },
+  mixins: [readonlyDescriptionsMixin],
+  dicts: [
+    "sys_BloodType",
+    "Geta_hospital",
+    "sys_DonationCategory",
+    "sys_Organ",
+    "Obtain_status"
+  ],
   props: {
-    stageData: {
-      type: Object,
-      default: () => ({})
-    },
-    caseInfo: {
-      type: Object,
-      default: () => ({})
+    infoid: {
+      type: String,
+      default: true
     }
   },
   data() {
     return {
-      chartView: 'bar',
+      caseId: null,
+      // 琛ㄥ崟鏁版嵁
+      form: {
+        id: undefined,
+        infoid: undefined,
+        name: "",
+        inpatientno: "",
+        witnessState: "2",
+        caseNo: "",
+        donorno: "",
+        treatmenthospitalname: "",
+        treatmenthospitalno: "",
+        sex: "",
+        age: "",
+        bloodtype: "",
+        idcardno: "",
+        diagnosisname: "",
+        coordinatorName: "",
+        gainhospitalno: "",
+        gainhospitalname: "",
+        deathtime: "",
+        deathreason: "",
+        deathjudgedocto: "",
+        deathjudgedoctt: "",
+        deathjudgeannex: "",
+        operationbegtime: "",
+        operationendtime: "",
+        operationdoctor: "",
+        isspendremember: 1,
+        isrestoreremains: 1,
+        rememberannex: "",
+        responsibleuserid: "",
+        responsibleusername: "",
+        coordinateduserido: "",
+        coordinatedusernameo: "",
+        coordinateduseridt: "",
+        coordinatedusernamet: "",
+        abdominalaortacannulatime: "",
+        abdominalaortaperfusiontime: "",
+        portalveincannulatime: "",
+        portalveinperfusiontime: "",
+        pulmonaryarterycannulatime: "",
+        pulmonaryarteryperfusiontime: "",
+        aortacannulatime: "",
+        aortaperfusiontime: "",
+        organdonation: "",
+        organdonationOther: "",
+        donationcategory: "",
+        coordinatorInOperating: "",
+        coordinatorOutOperating: "",
+        coordinatorSign: "",
+        coordinatorSignTime: "",
+        attachments: []
+      },
+      activeTab: "鍘熻〃鎷嶇収", // 褰撳墠婵�娲荤殑闄勪欢鍒嗙被Tab
+      presetCategories: [
+        "鍘熻〃鎷嶇収",
+        "浼︾悊瀹℃煡鏉愭枡",
+        "姝讳骸鍒ゅ畾鏉愭枡",
+        "榛樺搥浠紡鐓х墖",
+        "鎹愮尞瑙佽瘉瑙嗛"
+      ], // 棰勮鍒嗙被
+      organExpansionMap: {
+        C64: { subItems: ["C64L", "C64R"], subNames: ["宸﹁偩", "鍙宠偩"] },
+        C34: { subItems: ["C34L", "C34R"], subNames: ["宸﹁偤", "鍙宠偤"] }
+      },
+      // 琛ㄥ崟楠岃瘉瑙勫垯
+      rules: {
+        name: [
+          { required: true, message: "鎹愮尞鑰呭鍚嶄笉鑳戒负绌�", trigger: "blur" }
+        ],
+        diagnosisname: [
+          { required: true, message: "鐤剧梾璇婃柇涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        donationcategory: [
+          { required: true, message: "鎹愮尞绫诲埆涓嶈兘涓虹┖", trigger: "change" }
+        ],
+        operationdoctor: [
+          { required: true, message: "鎵嬫湳鍖荤敓涓嶈兘涓虹┖", trigger: "blur" }
+        ]
+      },
+      // 鑾峰彇璁板綍楠岃瘉瑙勫垯
+      procurementRules: {},
+      // 淇濆瓨鍔犺浇鐘舵��
+      saveLoading: false,
+      confirmLoading: false,
+      // 鍔犺浇鐘舵��
       loading: false,
-      utilizationStats: {
-        transplanted: 3,
-        inProgress: 0,
-        failed: 0,
-        successRate: 95,
-        utilizationRate: 100,
-        survivalRate: 92
+      // 閫変腑鐨勫櫒瀹�
+      selectedOrgans: [],
+      // 鍖婚櫌鍒楄〃
+      hospitalList: [],
+      // 鑾峰彇璁板綍鏁版嵁
+      procurementData: {
+        serviceDonationwitnessorgans: []
       },
-      timeTracking: {
-        procurementToTransplant: '4.5灏忔椂',
-        coldIschemiaTime: '鑲濊剰:6h,鑲捐剰:8h,蹇冭剰:3h',
-        surgeryDuration: '鑲濊剰:4h,鑲捐剰:3h,蹇冭剰:5h',
-        icuStay: '鑲濊剰:3澶�,鑲捐剰:2澶�,蹇冭剰:5澶�'
+      // 闄勪欢鏁版嵁
+      attachments: [],
+      // 涓婁紶鐩稿叧
+      uploadAction: process.env.VUE_APP_BASE_API + "/common/upload",
+      headers: {
+        Authorization: "Bearer " + getToken()
       },
-      qualityStats: {
-        organQuality: 4.5,
-        surgeryQuality: 4.8,
-        followupCompletionRate: 85
-      },
-      organUtilizationData: [
-        {
-          organName: '鑲濊剰',
-          status: '绉绘鎴愬姛',
-          recipientName: '鐜嬪厛鐢�',
-          recipientAge: 45,
-          recipientGender: '鐢�',
-          hospital: '鍖椾含鍗忓拰鍖婚櫌绉绘涓績',
-          transplantTime: '2025-12-04 16:00:00',
-          followupCount: 3,
-          recipientStatus: '鎭㈠鑹ソ'
-        },
-        {
-          organName: '鑲捐剰',
-          status: '绉绘鎴愬姛',
-          recipientName: '鏉庡コ澹�',
-          recipientAge: 38,
-          recipientGender: '濂�',
-          hospital: '涓婃捣鐟為噾鍖婚櫌绉绘涓績',
-          transplantTime: '2025-12-04 17:30:00',
-          followupCount: 2,
-          recipientStatus: '绋冲畾鎭㈠'
-        },
-        {
-          organName: '蹇冭剰',
-          status: '绉绘鎴愬姛',
-          recipientName: '闄堝厛鐢�',
-          recipientAge: 52,
-          recipientGender: '鐢�',
-          hospital: '骞垮窞涓北鍖婚櫌蹇冭剰涓績',
-          transplantTime: '2025-12-04 18:15:00',
-          followupCount: 1,
-          recipientStatus: '瀵嗗垏瑙傚療'
-        }
-      ],
-      // 鍥捐〃瀹炰緥
-      organDistributionChart: null,
-      successTrendChart: null,
-      followupStatsChart: null,
-      complicationChart: null
+      uploadDialogVisible: false,
+      uploadLoading: false,
+      tempFileList: [],
+      currentUploadCategory: "",
+      // 缂栬緫瀵硅瘽妗�
+      editDialogVisible: false,
+      currentRecord: {},
+      currentEditIndex: -1,
+      // 鏂囦欢棰勮鐩稿叧
+      previewVisible: false,
+      currentPreviewFile: null
     };
   },
-  mounted() {
-    this.$nextTick(() => {
-      this.initCharts();
-    });
+  computed: {
+    // 褰撳墠鐢ㄦ埛淇℃伅
+    currentUser() {
+      return JSON.parse(sessionStorage.getItem("user") || "{}");
+    },
+    displayOrgans() {
+      return (this.procurementData.serviceDonationwitnessorgans || []).filter(
+        item => item.delFlag !== 1
+      );
+    },
+    categories() {
+      // 濮嬬粓杩斿洖鎵�鏈夐璁惧垎绫� + 鏈垎绫伙紝鏃犺鏄惁鏈夋暟鎹�
+      return [
+        "鍘熻〃鎷嶇収",
+        "浼︾悊瀹℃煡鏉愭枡",
+        "姝讳骸鍒ゅ畾鏉愭枡",
+        "榛樺搥浠紡鐓х墖",
+        "鎹愮尞瑙佽瘉瑙嗛",
+        "鏈垎绫�"
+      ];
+    },
+    organReverseMap() {
+      const map = {};
+      for (const key in this.organExpansionMap) {
+        const { subItems } = this.organExpansionMap[key];
+        subItems.forEach(item => {
+          map[item] = key;
+        });
+      }
+      return map;
+    },
+    // 涓嶅畬鏁寸殑璁板綍鏁伴噺
+    incompleteRecords() {
+      if (!this.procurementData.serviceDonationwitnessorgans) return 0;
+      return this.procurementData.serviceDonationwitnessorgans.filter(
+        record =>
+          !record.organStartTime ||
+          !record.organgettime ||
+          !record.gainhospitalno ||
+          !record.organgetdoct
+      ).length;
+    },
+    // 鍞竴鍖婚櫌鏁伴噺
+    uniqueHospitals() {
+      if (!this.procurementData.serviceDonationwitnessorgans) return 0;
+      const hospitals = this.procurementData.serviceDonationwitnessorgans
+        .map(record => record.gainhospitalno)
+        .filter(Boolean);
+      return new Set(hospitals).size;
+    },
+    // 鑾峰彇鍣ㄥ畼瀛楀吀
+    organDict() {
+      return this.dict.type.sys_Organ || [];
+    }
   },
-  beforeDestroy() {
-    // 閿�姣佸浘琛ㄥ疄渚�
-    if (this.organDistributionChart) {
-      this.organDistributionChart.dispose();
-    }
-    if (this.successTrendChart) {
-      this.successTrendChart.dispose();
-    }
-    if (this.followupStatsChart) {
-      this.followupStatsChart.dispose();
-    }
-    if (this.complicationChart) {
-      this.complicationChart.dispose();
-    }
+  created() {
+    this.caseId = this.infoid;
+
+    this.initData();
   },
   methods: {
-    // 鍒濆鍖栧浘琛�
-    initCharts() {
-      this.initOrganDistributionChart();
-      this.initSuccessTrendChart();
-      this.initFollowupStatsChart();
-      this.initComplicationChart();
+    // 鏍规嵁瀛楀吀value鑾峰彇label
+    getOrganLabel(organValue) {
+      const dictItem = this.organDict.find(item => item.value === organValue);
+      return dictItem ? dictItem.label : organValue;
     },
 
-    // 鍒濆鍖栧櫒瀹樺垎甯冨浘琛�
-    initOrganDistributionChart() {
-      this.organDistributionChart = echarts.init(this.$refs.organDistributionChart);
-      const option = {
-        tooltip: {
-          trigger: 'item',
-          formatter: '{a} <br/>{b}: {c} ({d}%)'
-        },
-        legend: {
-          orient: 'vertical',
-          right: 10,
-          top: 'center',
-          data: ['鑲濊剰', '鑲捐剰', '蹇冭剰', '鑲鸿剰', '瑙掕啘', '鍏朵粬']
-        },
-        series: [
-          {
-            name: '鍣ㄥ畼鍒╃敤',
-            type: 'pie',
-            radius: ['50%', '70%'],
-            avoidLabelOverlap: false,
-            label: {
-              show: false,
-              position: 'center'
-            },
-            emphasis: {
-              label: {
-                show: true,
-                fontSize: '18',
-                fontWeight: 'bold'
-              }
-            },
-            labelLine: {
-              show: false
-            },
-            data: [
-              { value: 35, name: '鑲濊剰' },
-              { value: 30, name: '鑲捐剰' },
-              { value: 15, name: '蹇冭剰' },
-              { value: 10, name: '鑲鸿剰' },
-              { value: 8, name: '瑙掕啘' },
-              { value: 2, name: '鍏朵粬' }
-            ]
-          }
-        ]
-      };
-      this.organDistributionChart.setOption(option);
-    },
+    // 鍒濆鍖栨暟鎹�
+    initData() {
+      const infoid = this.infoid;
 
-    // 鍒濆鍖栨垚鍔熺巼瓒嬪娍鍥捐〃
-    initSuccessTrendChart() {
-      this.successTrendChart = echarts.init(this.$refs.successTrendChart);
-      const option = {
-        tooltip: {
-          trigger: 'axis'
-        },
-        legend: {
-          data: ['鑲濊剰绉绘', '鑲捐剰绉绘', '蹇冭剰绉绘', '骞冲潎鎴愬姛鐜�']
-        },
-        grid: {
-          left: '3%',
-          right: '4%',
-          bottom: '3%',
-          containLabel: true
-        },
-        xAxis: {
-          type: 'category',
-          boundaryGap: false,
-          data: ['1鏈�', '2鏈�', '3鏈�', '4鏈�', '5鏈�', '6鏈�', '7鏈�']
-        },
-        yAxis: {
-          type: 'value',
-          min: 80,
-          max: 100
-        },
-        series: [
-          {
-            name: '鑲濊剰绉绘',
-            type: 'line',
-            smooth: true,
-            data: [92, 93, 94, 95, 96, 95, 96]
-          },
-          {
-            name: '鑲捐剰绉绘',
-            type: 'line',
-            smooth: true,
-            data: [94, 95, 95, 96, 95, 96, 97]
-          },
-          {
-            name: '蹇冭剰绉绘',
-            type: 'line',
-            smooth: true,
-            data: [88, 89, 90, 91, 92, 91, 92]
-          },
-          {
-            name: '骞冲潎鎴愬姛鐜�',
-            type: 'line',
-            smooth: true,
-            lineStyle: {
-              type: 'dashed'
-            },
-            data: [91.3, 92.3, 93, 94, 94.3, 94, 95]
-          }
-        ]
-      };
-      this.successTrendChart.setOption(option);
-    },
+      if (!infoid) {
+        this.$message.error("缂哄皯蹇呰鐨勮矾鐢卞弬鏁� infoid");
+        this.$router.back();
+        return;
+      }
 
-    // 鍒濆鍖栭殢璁跨粺璁″浘琛�
-    initFollowupStatsChart() {
-      this.followupStatsChart = echarts.init(this.$refs.followupStatsChart);
-      const option = {
-        tooltip: {
-          trigger: 'axis',
-          axisPointer: {
-            type: 'shadow'
-          }
-        },
-        legend: {
-          data: ['璁″垝闅忚', '宸插畬鎴�', '閫炬湡鏈畬鎴�']
-        },
-        grid: {
-          left: '3%',
-          right: '4%',
-          bottom: '3%',
-          containLabel: true
-        },
-        xAxis: {
-          type: 'value'
-        },
-        yAxis: {
-          type: 'category',
-          data: ['1涓湀', '3涓湀', '6涓湀', '1骞�', '2骞�', '5骞�']
-        },
-        series: [
-          {
-            name: '璁″垝闅忚',
-            type: 'bar',
-            stack: 'total',
-            label: {
-              show: true
-            },
-            emphasis: {
-              focus: 'series'
-            },
-            data: [120, 132, 101, 134, 90, 60]
-          },
-          {
-            name: '宸插畬鎴�',
-            type: 'bar',
-            stack: 'total',
-            label: {
-              show: true
-            },
-            emphasis: {
-              focus: 'series'
-            },
-            data: [115, 125, 95, 120, 85, 55]
-          },
-          {
-            name: '閫炬湡鏈畬鎴�',
-            type: 'bar',
-            stack: 'total',
-            label: {
-              show: true
-            },
-            emphasis: {
-              focus: 'series'
-            },
-            data: [5, 7, 6, 14, 5, 5]
-          }
-        ]
-      };
-      this.followupStatsChart.setOption(option);
-    },
+      this.form.infoid = infoid;
+      // this.generateDonorNo();
 
-    // 鍒濆鍖栧苟鍙戠棁鍒嗘瀽鍥捐〃
-    initComplicationChart() {
-      this.complicationChart = echarts.init(this.$refs.complicationChart);
-      const option = {
-        tooltip: {
-          trigger: 'axis',
-          axisPointer: {
-            type: 'shadow'
-          }
-        },
-        radar: {
-          indicator: [
-            { name: '鎰熸煋椋庨櫓', max: 100 },
-            { name: '鎺掓枼鍙嶅簲', max: 100 },
-            { name: '琛�绠″苟鍙戠棁', max: 100 },
-            { name: '鑳嗛亾骞跺彂鐥�', max: 100 },
-            { name: '浠h阿寮傚父', max: 100 },
-            { name: '鍏朵粬骞跺彂鐥�', max: 100 }
-          ]
-        },
-        series: [
-          {
-            type: 'radar',
-            data: [
-              {
-                value: [85, 90, 78, 82, 75, 70],
-                name: '鑲濊剰绉绘',
-                areaStyle: {}
-              },
-              {
-                value: [78, 85, 72, 65, 80, 68],
-                name: '鑲捐剰绉绘',
-                areaStyle: {}
-              },
-              {
-                value: [90, 88, 85, 60, 82, 75],
-                name: '蹇冭剰绉绘',
-                areaStyle: {}
-              }
-            ]
-          }
-        ]
-      };
-      this.complicationChart.setOption(option);
-    },
+      if (infoid) {
+        this.getDetail(infoid);
+      }
 
-    // 鏇存柊鍥捐〃瑙嗗浘
-    updateCharts() {
-      if (this.chartView === 'bar') {
-        this.updateToBarChart();
-      } else {
-        this.initOrganDistributionChart(); // 鍒囧洖楗煎浘
+      this.getHospitalData();
+    },
+    getOrganNameByNo(organno) {
+      // 妫�鏌ユ槸鍚﹀湪鏄犲皠鐨勫瓙椤逛腑
+      for (const key in this.organExpansionMap) {
+        const { subItems, subNames } = this.organExpansionMap[key];
+        const idx = subItems.indexOf(organno);
+        if (idx !== -1) {
+          return subNames[idx];
+        }
+      }
+      // 鍚﹀垯浠庡瓧鍏镐腑鑾峰彇
+      return this.getOrganLabel(organno);
+    },
+    // 鑾峰彇璇︽儏
+    async getDetail(infoid) {
+      this.loading = true;
+      try {
+        const response = await witnessList({ infoid });
+        if (
+          response.code === 200 &&
+          response.data &&
+          response.data.length > 0
+        ) {
+          const data = response.data[0];
+          if (!data.witnessState || data.witnessState == 1) {
+            data.witnessState = "2";
+          }
+
+          // 濉厖琛ㄥ崟鏁版嵁
+          Object.assign(this.form, data);
+
+          // 鍒濆鍖栭檮浠�
+          if (this.form.deathjudgeannex) {
+            const parsed = JSON.parse(this.form.deathjudgeannex);
+            this.attachments = parsed.map(item => ({
+              ...item,
+              fileType: item.fileType || "" // 榛樿绌哄瓧绗︿覆琛ㄧず鏈垎绫�
+            }));
+            this.form.attachments = this.attachments;
+          } else {
+            this.attachments = [];
+          }
+
+          // 澶勭悊鎹愮尞鍣ㄥ畼瀛楁
+          if (data.organdonation) {
+            const organArray = Array.isArray(data.organdonation)
+              ? data.organdonation
+              : (data.organdonation || "").split(",").filter(item => item);
+            this.selectedOrgans = organArray;
+            this.form.organdonationOther = data.organdonationOther || "";
+          }
+
+          // 澶勭悊鍣ㄥ畼鑾峰彇璁板綍
+          if (data.serviceDonationwitnessorgans) {
+            this.procurementData.serviceDonationwitnessorgans = Array.isArray(
+              data.serviceDonationwitnessorgans
+            )
+              ? data.serviceDonationwitnessorgans
+              : [];
+          }
+
+          this.$message.success("鏁版嵁鍔犺浇鎴愬姛");
+          this.syncOrgansFromSelection();
+        } else {
+          this.$message.warning("鏈壘鍒板搴旂殑鍣ㄥ畼鑾峰彇鏁版嵁");
+        }
+      } catch (error) {
+        console.error("鑾峰彇鍣ㄥ畼鑾峰彇璇︽儏澶辫触:", error);
+        this.$message.error("鑾峰彇璇︽儏澶辫触");
+      } finally {
+        this.loading = false;
       }
     },
+    syncOrgansFromSelection() {
+      const records = this.procurementData.serviceDonationwitnessorgans || [];
+      const targetNos = [];
+      this.selectedOrgans.forEach(val => {
+        if (this.organExpansionMap[val]) {
+          targetNos.push(...this.organExpansionMap[val].subItems);
+        } else {
+          targetNos.push(val);
+        }
+      });
 
-    // 鏇存柊涓烘煴鐘跺浘
-    updateToBarChart() {
-      const option = {
-        tooltip: {
-          trigger: 'axis',
-          axisPointer: {
-            type: 'shadow'
+      // 鏂板鎴栨仮澶�
+      targetNos.forEach(no => {
+        const existing = records.find(r => r.organno === no);
+        if (existing) {
+          if (existing.delFlag === 1) {
+            existing.delFlag = 0; // 鎭㈠鏄剧ず
           }
-        },
-        grid: {
-          left: '3%',
-          right: '4%',
-          bottom: '3%',
-          containLabel: true
-        },
-        xAxis: {
-          type: 'category',
-          data: ['鑲濊剰', '鑲捐剰', '蹇冭剰', '鑲鸿剰', '瑙掕啘', '鍏朵粬']
-        },
-        yAxis: {
-          type: 'value',
-          name: '鏁伴噺'
-        },
-        series: [
-          {
-            name: '鍣ㄥ畼鍒╃敤鏁伴噺',
-            type: 'bar',
-            data: [35, 30, 15, 10, 8, 2],
-            itemStyle: {
-              color: function(params) {
-                const colorList = ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272'];
-                return colorList[params.dataIndex];
-              }
+        } else {
+          records.push({
+            id: null,
+            organname: this.getOrganNameByNo(no),
+            organno: no,
+            organStartTime: "",
+            organgettime: "",
+            gainhospitalno: "",
+            gainhospitalname: "",
+            organgetdoct: "",
+            assistant: "",
+            procurementNurse: "",
+            operatingRoomNurse: "",
+            anesthesiologist: "",
+            organstate: "1",
+            notgetreason: "",
+            delFlag: 0
+          });
+        }
+      });
+
+      // 锛堝彲閫夛級濡傛灉鍔犺浇鏃跺悗绔繑鍥炰簡 delFlag=1 鐨勮褰曪紝浣嗗疄闄呭簲璇ユ樉绀猴紝寮哄埗閲嶇疆
+      records.forEach(r => {
+        if (r.delFlag === 1) r.delFlag = 0;
+      });
+
+      this.form.organdonation = this.selectedOrgans.join(",");
+    },
+    // 鑾峰彇鍖婚櫌鏁版嵁
+    async getHospitalData() {
+      try {
+        // TODO: 鏇挎崲涓哄疄闄呯殑鍖婚櫌鍒楄〃鎺ュ彛
+        // 鏆傛椂浣跨敤妯℃嫙鏁版嵁
+        this.hospitalList = [
+          { hospitalNo: "H001", hospitalName: "鍖椾含鍗忓拰鍖婚櫌" },
+          { hospitalNo: "H002", hospitalName: "涓婃捣鍗庡北鍖婚櫌" },
+          { hospitalNo: "H003", hospitalName: "骞垮窞涓北鍖婚櫌" },
+          { hospitalNo: "H004", hospitalName: "姝︽眽鍚屾祹鍖婚櫌" },
+          { hospitalNo: "H005", hospitalName: "鎴愰兘鍗庤タ鍖婚櫌" }
+        ];
+      } catch (error) {
+        console.error("鑾峰彇鍖婚櫌鏁版嵁澶辫触:", error);
+        this.$message.error("鑾峰彇鍖婚櫌鏁版嵁澶辫触");
+      }
+    },
+    // 绉绘鍖婚櫌妯$硦鎼滅储
+    queryHospitalSearch(queryString, cb) {
+      const hospitals = this.dict.type.Geta_hospital || [];
+      const results = queryString
+        ? hospitals.filter(item =>
+            item.label.toLowerCase().includes(queryString.toLowerCase())
+          )
+        : hospitals;
+
+      // el-autocomplete 闇�瑕� value 瀛楁
+      cb(results.map(item => ({ value: item.label })));
+    },
+    // 鍣ㄥ畼閫夋嫨鐘舵�佸彉鍖�
+    async handleOrganSelectionChange(selectedValues) {
+      // 1. 澶勭悊浜掓枼閫昏緫锛堜慨鏀� this.selectedOrgans锛�
+      this.handleExclusiveSelections(selectedValues);
+
+      const finalSelected = this.selectedOrgans;
+      const records = this.procurementData.serviceDonationwitnessorgans || [];
+
+      // 2. 鏋勫缓鐩爣鍣ㄥ畼缂栧彿鍒楄〃锛堝睍寮�缁勫悎鍣ㄥ畼锛�
+      const targetOrganNos = [];
+      finalSelected.forEach(val => {
+        if (this.organExpansionMap[val]) {
+          targetOrganNos.push(...this.organExpansionMap[val].subItems);
+        } else {
+          targetOrganNos.push(val);
+        }
+      });
+
+      // 3. 鏂板鎴栨仮澶嶇洰鏍囧櫒瀹樿褰曪紙鏃犲脊绐楋級
+      targetOrganNos.forEach(no => {
+        const existing = records.find(r => r.organno === no);
+        if (existing) {
+          if (existing.delFlag === 1) {
+            existing.delFlag = 0; // 鎭㈠鏄剧ず
+          }
+        } else {
+          records.push({
+            id: null,
+            organname: this.getOrganNameByNo(no),
+            organno: no,
+            organStartTime: "",
+            organgettime: "",
+            gainhospitalno: "",
+            gainhospitalname: "",
+            organgetdoct: "",
+            assistant: "",
+            procurementNurse: "",
+            operatingRoomNurse: "",
+            anesthesiologist: "",
+            organstate: "1",
+            notgetreason: "",
+            delFlag: 0
+          });
+        }
+      });
+
+      // 4. 鎵惧嚭闇�瑕佸彇娑堢殑璁板綍锛堜笉鍦ㄧ洰鏍囬泦鍚堜腑锛�
+      const toRemove = records.filter(r => !targetOrganNos.includes(r.organno));
+      const toRemoveSaved = toRemove.filter(r => r.id); // 宸蹭繚瀛橈紝闇�纭
+      const toRemoveUnsaved = toRemove.filter(r => !r.id); // 鏈繚瀛橈紝鐩存帴绉婚櫎
+
+      // 4.1 鐩存帴绉婚櫎鏈繚瀛樼殑璁板綍
+      toRemoveUnsaved.forEach(r => {
+        const idx = records.indexOf(r);
+        if (idx !== -1) records.splice(idx, 1);
+      });
+
+      // 4.2 澶勭悊宸蹭繚瀛樼殑璁板綍锛氬脊绐楃‘璁�
+      if (toRemoveSaved.length > 0) {
+        const organNames = toRemoveSaved.map(r => r.organname).join("銆�");
+        try {
+          await this.$confirm(
+            `鎮ㄧ‘瀹氳鍙栨秷浠ヤ笅宸蹭繚瀛樼殑鍣ㄥ畼鑾峰彇璁板綍鍚楋紵\n${organNames}\n鍙栨秷鍚庯紝杩欎簺璁板綍灏嗕粠鍒楄〃涓Щ闄わ紙鏁版嵁浠嶄繚鐣欙紝鍙仮澶嶏級銆俙,
+            "鎻愮ず",
+            {
+              confirmButtonText: "纭畾绉婚櫎",
+              cancelButtonText: "鍙栨秷",
+              type: "warning"
             }
-          }
-        ]
-      };
-      this.organDistributionChart.setOption(option);
-    },
-
-    // 鑾峰彇鐘舵�佹枃鏈�
-    getStatusText() {
-      const status = this.stageData.status;
-      return status === 'completed' ? '宸插畬鎴�' :
-             status === 'in_progress' ? '杩涜涓�' : '鏈紑濮�';
-    },
-
-    // 鑾峰彇璀﹀憡绫诲瀷
-    getAlertType() {
-      const status = this.stageData.status;
-      return status === 'completed' ? 'success' :
-             status === 'in_progress' ? 'warning' : 'info';
-    },
-
-    // 鑾峰彇璀﹀憡鎻忚堪
-    getAlertDescription() {
-      const status = this.stageData.status;
-      if (status === 'completed') {
-        return '鍣ㄥ畼鍒╃敤闃舵宸插畬鎴愶紝鎵�鏈夊櫒瀹樺潎宸叉垚鍔熺Щ妞嶅苟寮�濮嬮殢璁�';
-      } else if (status === 'in_progress') {
-        return '鍣ㄥ畼鍒╃敤杩涜涓紝绉绘鎵嬫湳宸插畬鎴愶紝姝e湪杩涜鏈悗闅忚';
+          );
+          // 鐢ㄦ埛纭锛氭爣璁� delFlag=1
+          toRemoveSaved.forEach(r => {
+            r.delFlag = 1;
+          });
+        } catch (error) {
+          // 鐢ㄦ埛鍙栨秷锛氭仮澶嶉�変腑鐘舵��
+          const parentToRestore = new Set();
+          toRemoveSaved.forEach(r => {
+            const parent = this.organReverseMap[r.organno];
+            if (parent) {
+              parentToRestore.add(parent);
+            } else {
+              parentToRestore.add(r.organno);
+            }
+          });
+          parentToRestore.forEach(val => {
+            if (!this.selectedOrgans.includes(val)) {
+              this.selectedOrgans.push(val);
+            }
+          });
+          this.$message.info("宸插彇娑堝垹闄ゆ搷浣�");
+          // 鏇存柊琛ㄥ崟瀛楁锛堜繚鎸佷竴鑷存�э級
+          this.form.organdonation = this.selectedOrgans.join(",");
+          return; // 閫�鍑烘柟娉曪紝閬垮厤缁х画鎵ц
+        }
       }
-      return '绛夊緟寮�濮嬪櫒瀹樺埄鐢ㄦ祦绋�';
+
+      // 5. 鏇存柊琛ㄥ崟瀛楁
+      this.form.organdonation = this.selectedOrgans.join(",");
     },
 
-    // 鑾峰彇绉绘鐘舵�佹爣绛�
-    getTransplantStatusTag(status) {
-      const map = {
-        '绉绘鎴愬姛': 'success',
-        '绉绘涓�': 'warning',
-        '绉绘澶辫触': 'danger'
-      };
-      return map[status] || 'info';
+    // 澶勭悊浜掓枼閫夋嫨
+    handleExclusiveSelections(selectedValues) {
+      // 鍙岃偩涓庡乏鍙宠偩浜掓枼
+      if (selectedValues.includes("C64")) {
+        this.selectedOrgans = selectedValues.filter(
+          item => item !== "C64L" && item !== "C64R"
+        );
+      } else if (
+        selectedValues.includes("C64L") ||
+        selectedValues.includes("C64R")
+      ) {
+        this.selectedOrgans = selectedValues.filter(item => item !== "C64");
+      }
+
+      // 鍏ㄨ偤涓庡乏鍙宠偤浜掓枼
+      if (selectedValues.includes("C34")) {
+        this.selectedOrgans = selectedValues.filter(
+          item => item !== "C34L" && item !== "C34R"
+        );
+      } else if (
+        selectedValues.includes("C34L") ||
+        selectedValues.includes("C34R")
+      ) {
+        this.selectedOrgans = selectedValues.filter(item => item !== "C34");
+      }
     },
 
-    // 鑾峰彇鍙椾綋鐘舵�佹爣绛�
-    getRecipientStatusTag(status) {
-      const map = {
-        '鎭㈠鑹ソ': 'success',
-        '绋冲畾鎭㈠': 'warning',
-        '瀵嗗垏瑙傚療': 'danger'
-      };
-      return map[status] || 'info';
-    },
+    // 鍒涘缓鍣ㄥ畼璁板綍
+    createOrganRecord(organValue) {
+      const organName = this.getOrganLabel(organValue);
 
-    // 鏌ョ湅璇︽儏
-    handleViewDetails(row) {
-      this.$message.info(`鏌ョ湅${row.organName}绉绘璇︽儏`);
-    },
-
-    // 娣诲姞闅忚
-    handleAddFollowup(row) {
-      this.$message.info(`涓�${row.recipientName}娣诲姞闅忚璁板綍`);
-    },
-
-    // 鐢熸垚鎶ュ憡
-    handleGenerateReport() {
-      this.$message.info('鐢熸垚鍣ㄥ畼鍒╃敤鍒嗘瀽鎶ュ憡');
-    },
-
-    // 瀹屾垚鍒╃敤
-    handleCompleteUtilization() {
-      this.$confirm('纭瀹屾垚鍣ㄥ畼鍒╃敤闃舵鍚楋紵', '鎻愮ず', {
-        confirmButtonText: '纭畾',
-        cancelButtonText: '鍙栨秷',
-        type: 'success'
-      }).then(() => {
-        this.$message.success('鍣ㄥ畼鍒╃敤闃舵宸插畬鎴�');
+      this.procurementData.serviceDonationwitnessorgans.push({
+        id: null,
+        organname: organName,
+        organno: organValue,
+        organStartTime: "",
+        organgettime: "",
+        gainhospitalno: "",
+        gainhospitalname: "",
+        organgetdoct: "",
+        assistant: "",
+        procurementNurse: "",
+        operatingRoomNurse: "",
+        anesthesiologist: "",
+        organstate: "1",
+        notgetreason: ""
       });
     },
 
-    // 缁熻鏁版嵁鍒嗘瀽
-    handleStatistics() {
-      this.$message.info('鎵撳紑缁熻鍒嗘瀽闈㈡澘');
+    // 鍖婚櫌閫夋嫨鍙樺寲
+    handleHospitalChange(row, hospitalNo) {
+      const hospital = this.hospitalList.find(
+        item => item.hospitalNo === hospitalNo
+      );
+      if (hospital) {
+        row.gainhospitalname = hospital.hospitalName;
+      }
+    },
+    // 缂栬緫鑾峰彇璁板綍
+    handleEditProcurement(row) {
+      const index = this.procurementData.serviceDonationwitnessorgans.findIndex(
+        item => item.organno === row.organno
+      );
+      if (index !== -1) {
+        this.currentRecord = { ...row };
+        this.currentEditIndex = index;
+        this.editDialogVisible = true;
+      }
+    },
+    // 纭缂栬緫
+    handleEditConfirm() {
+      if (this.currentEditIndex !== -1) {
+        this.procurementData.serviceDonationwitnessorgans[
+          this.currentEditIndex
+        ] = {
+          ...this.currentRecord
+        };
+        this.$message.success("鑾峰彇璁板綍鏇存柊鎴愬姛");
+        this.editDialogVisible = false;
+      }
+    },
+    // 鍣ㄥ畼琛屾牱寮�
+    getOrganRowClassName({ row }) {
+      if (
+        !row.organStartTime ||
+        !row.organgettime ||
+        !row.gainhospitalno ||
+        !row.organgetdoct
+      ) {
+        return "warning-row";
+      }
+      return "";
+    },
+    // 淇濆瓨鍩烘湰淇℃伅
+    async handleSave() {
+      this.$refs.form.validate(async valid => {
+        if (valid) {
+          this.saveLoading = true;
+          try {
+            console.log(this.procurementData.serviceDonationwitnessorgans);
+
+            const saveData = {
+              ...this.form,
+              deathjudgeannex: JSON.stringify(this.attachments),
+              organdonation: this.selectedOrgans.join(","),
+              serviceDonationwitnessorganList:
+                this.procurementData.serviceDonationwitnessorgans || [],
+              serviceDonationwitnessorgans:
+                this.procurementData.serviceDonationwitnessorgans || []
+            };
+            console.log(saveData.serviceDonationwitnessorganList);
+            console.log(saveData.serviceDonationwitnessorgans);
+
+            const apiMethod = this.form.id ? witnessedit : witnessadd;
+            const response = await apiMethod(saveData);
+
+            if (response.code === 200) {
+              this.$message.success("淇濆瓨鎴愬姛");
+              if (!this.form.id && response.data && response.data.id) {
+                this.form.id = response.data.id;
+                this.$router.replace({
+                  query: { ...this.$route.query, id: this.form.id }
+                });
+              }
+            } else {
+              this.$message.error("淇濆瓨澶辫触锛�" + (response.msg || "鏈煡閿欒"));
+            }
+          } catch (error) {
+            console.error("淇濆瓨澶辫触:", error);
+            this.$message.error("淇濆瓨澶辫触");
+          } finally {
+            this.saveLoading = false;
+          }
+        }
+      });
+    },
+    // 淇濆瓨鑾峰彇璁板綍
+    async handleSaveProcurement() {
+      if (!this.form.id) {
+        this.$message.warning("璇峰厛淇濆瓨鍩烘湰淇℃伅");
+        return;
+      }
+
+      this.saveLoading = true;
+      try {
+        const saveData = {
+          ...this.form,
+          attachments: this.attachments,
+          organdonation: this.selectedOrgans.join(","),
+          serviceDonationwitnessorgans:
+            this.procurementData.serviceDonationwitnessorgans || []
+        };
+
+        const response = await witnessedit(saveData);
+
+        if (response.code === 200) {
+          this.$message.success("鑾峰彇璁板綍淇濆瓨鎴愬姛");
+        } else {
+          this.$message.error(
+            "淇濆瓨鑾峰彇璁板綍澶辫触锛�" + (response.msg || "鏈煡閿欒")
+          );
+        }
+      } catch (error) {
+        console.error("淇濆瓨鑾峰彇璁板綍澶辫触:", error);
+        this.$message.error("淇濆瓨鑾峰彇璁板綍澶辫触");
+      } finally {
+        this.saveLoading = false;
+      }
+    },
+    // 纭瀹屾垚鑾峰彇
+    async handleConfirmProcurement() {
+      if (this.incompleteRecords > 0) {
+        this.$message.warning("璇峰厛瀹屽杽鎵�鏈夎幏鍙栬褰曠殑淇℃伅");
+        return;
+      }
+
+      this.$confirm("纭瀹屾垚鍣ㄥ畼鑾峰彇鍚楋紵瀹屾垚鍚庡皢鏃犳硶淇敼鑾峰彇淇℃伅銆�", "鎻愮ず", {
+        confirmButtonText: "纭畾",
+        cancelButtonText: "鍙栨秷",
+        type: "warning"
+      })
+        .then(async () => {
+          this.confirmLoading = true;
+          this.form.witnessState = "3";
+          this.form.operationendtime =
+            this.form.operationendtime ||
+            new Date()
+              .toISOString()
+              .replace("T", " ")
+              .substring(0, 19);
+
+          try {
+            const saveData = {
+              ...this.form,
+              attachments: this.attachments,
+              organdonation: this.selectedOrgans.join(","),
+              serviceDonationwitnessorgans:
+                this.procurementData.serviceDonationwitnessorgans || []
+            };
+
+            const response = await witnessedit(saveData);
+
+            if (response.code === 200) {
+              this.$message.success("鍣ㄥ畼鑾峰彇宸插畬鎴�");
+            } else {
+              this.$message.error(
+                "纭鑾峰彇澶辫触锛�" + (response.msg || "鏈煡閿欒")
+              );
+              this.form.witnessState = "2";
+              this.form.operationendtime = "";
+            }
+          } catch (error) {
+            console.error("纭鑾峰彇澶辫触:", error);
+            this.$message.error("纭鑾峰彇澶辫触");
+            this.form.witnessState = "2";
+            this.form.operationendtime = "";
+          } finally {
+            this.confirmLoading = false;
+          }
+        })
+        .catch(() => {});
+    },
+    // 纭鑾峰彇鎸夐挳鍒悕
+    handleProcure() {
+      this.handleConfirmProcurement();
     },
 
-    // 瀵煎嚭鏁版嵁
-    exportData() {
-      this.$message.info('瀵煎嚭鍣ㄥ畼鍒╃敤鏁版嵁');
+    // ===== 闄勪欢鐩稿叧鏂规硶 =====
+    // 鎵撳紑涓婁紶瀵硅瘽妗�
+    openUploadDialog(category) {
+      this.currentUploadCategory = category;
+      this.tempFileList = [];
+      this.uploadDialogVisible = true;
+      this.$nextTick(() => {
+        if (this.$refs.uploadRef) {
+          this.$refs.uploadRef.clearFiles();
+        }
+      });
+    },
+
+    // 涓婁紶鍓嶆牎楠�
+    beforeUpload(file) {
+      const allowedTypes = [
+        "application/pdf",
+        "image/jpeg",
+        "image/png",
+        "application/msword",
+        "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
+      ];
+      const maxSize = 10 * 1024 * 1024;
+      const isTypeOk =
+        allowedTypes.includes(file.type) ||
+        file.name.endsWith(".pdf") ||
+        file.name.endsWith(".jpg") ||
+        file.name.endsWith(".jpeg") ||
+        file.name.endsWith(".png") ||
+        file.name.endsWith(".doc") ||
+        file.name.endsWith(".docx");
+      if (!isTypeOk) {
+        this.$message.error(
+          "鏂囦欢鏍煎紡涓嶆敮鎸侊紝璇蜂笂浼爌df銆乯pg銆乸ng銆乨oc鎴杁ocx鏍煎紡鏂囦欢"
+        );
+        return false;
+      }
+      if (file.size > maxSize) {
+        this.$message.error("鏂囦欢澶у皬涓嶈兘瓒呰繃10MB");
+        return false;
+      }
+      return true;
+    },
+
+    // 鏂囦欢閫夋嫨鍙樺寲
+    handleFileChange(file, fileList) {
+      this.tempFileList = fileList;
+    },
+
+    // 涓存椂绉婚櫎
+    handleTempRemove(file, fileList) {
+      this.tempFileList = fileList;
+    },
+
+    // 涓婁紶鎴愬姛澶勭悊
+    handleUploadSuccess(response, file, fileList) {
+      if (response.code !== 200) {
+        this.$message.error(response.msg || "涓婁紶澶辫触");
+        return;
+      }
+      // 鏈垎绫诲搴旂┖瀛楃涓诧紝涓庡睍绀�/淇濆瓨閫昏緫涓�鑷�
+      const category =
+        this.currentUploadCategory === "鏈垎绫�"
+          ? ""
+          : this.currentUploadCategory;
+      const attachmentObj = {
+        fileName: file.name,
+        path: response.fileUrl || response.url || response.data || file.url,
+        fileUrl: response.fileUrl || response.url || response.data || file.url,
+        fileType: category,
+        fileSize: file.size,
+        uploadTime: dayjs().format("YYYY-MM-DD HH:mm:ss")
+      };
+      if (!Array.isArray(this.attachments)) {
+        this.attachments = [];
+      }
+      this.attachments.push(attachmentObj);
+      this.$message.success("鏂囦欢涓婁紶鎴愬姛");
+      this.uploadLoading = false;
+      this.uploadDialogVisible = false;
+      this.tempFileList = [];
+    },
+
+    // 鎻愪氦涓婁紶
+    submitUpload() {
+      if (this.tempFileList.length === 0) {
+        this.$message.warning("璇峰厛閫夋嫨瑕佷笂浼犵殑鏂囦欢");
+        return;
+      }
+      this.uploadLoading = true;
+      this.$refs.uploadRef.submit();
+    },
+
+    // 鑾峰彇鏌愬垎绫荤殑鏂囦欢鏁伴噺
+    getCategoryCount(category) {
+      return this.attachments.filter(item => {
+        const type = item.fileType || "";
+        if (category === "鏈垎绫�") {
+          return !this.presetCategories.includes(type);
+        }
+        return type === category;
+      }).length;
+    },
+
+    // 鑾峰彇鏌愬垎绫荤殑鏂囦欢鍒楄〃
+    getCategoryFiles(category) {
+      return this.attachments.filter(item => {
+        const type = item.fileType || "";
+        if (category === "鏈垎绫�") {
+          return !this.presetCategories.includes(type);
+        }
+        return type === category;
+      });
+    },
+
+    // 鏇存柊闄勪欢鍒嗙被锛堜笅鎷変慨鏀规椂瑙﹀彂锛�
+    updateAttachmentCategory(row, newVal) {
+      const target = this.attachments.find(item => item === row);
+      if (target) {
+        target.fileType = newVal;
+        const currentTabHasFiles =
+          this.getCategoryFiles(this.activeTab).length > 0;
+        if (!currentTabHasFiles) {
+          const firstCategory = this.categories[0];
+          if (firstCategory) this.activeTab = firstCategory;
+        }
+      }
+    },
+
+    // 鎸夋枃浠跺璞″垹闄わ紙鐢ㄤ簬琛ㄦ牸涓殑鍒犻櫎鎸夐挳锛�
+    handleRemoveAttachmentByFile(file) {
+      this.$confirm("纭畾瑕佸垹闄よ繖涓檮浠跺悧锛�", "鎻愮ず", {
+        confirmButtonText: "纭畾",
+        cancelButtonText: "鍙栨秷",
+        type: "warning"
+      })
+        .then(() => {
+          const index = this.attachments.findIndex(item => item === file);
+          if (index > -1) {
+            this.attachments.splice(index, 1);
+            this.$message.success("闄勪欢鍒犻櫎鎴愬姛");
+          }
+        })
+        .catch(() => {});
+    },
+
+    // 鏂囦欢棰勮
+    handlePreview(file) {
+      this.currentPreviewFile = {
+        fileName: file.fileName,
+        fileUrl: file.path || file.fileUrl,
+        fileType: this.getFileType(file.fileName)
+      };
+      this.previewVisible = true;
+    },
+
+    // 鏂囦欢涓嬭浇
+    handleDownload(file) {
+      const fileUrl = file.path || file.fileUrl;
+      const fileName = file.fileName;
+
+      if (fileUrl) {
+        const link = document.createElement("a");
+        link.href = fileUrl;
+        link.download = fileName;
+        link.style.display = "none";
+        document.body.appendChild(link);
+        link.click();
+        document.body.removeChild(link);
+        this.$message.success("寮�濮嬩笅杞芥枃浠�");
+      } else {
+        this.$message.warning("鏂囦欢璺緞涓嶅瓨鍦紝鏃犳硶涓嬭浇");
+      }
+    },
+
+    /** 鑾峰彇鏂囦欢绫诲瀷 */
+    getFileType(fileName) {
+      if (!fileName) return "other";
+      const extension = fileName
+        .split(".")
+        .pop()
+        .toLowerCase();
+      const imageTypes = ["jpg", "jpeg", "png", "gif", "bmp", "webp"];
+      const pdfTypes = ["pdf"];
+      const officeTypes = ["doc", "docx", "xls", "xlsx", "ppt", "pptx"];
+      if (imageTypes.includes(extension)) return "image";
+      if (pdfTypes.includes(extension)) return "pdf";
+      if (officeTypes.includes(extension)) return "office";
+      return "other";
+    },
+
+    /** 鑾峰彇鏂囦欢鍥炬爣棰滆壊 */
+    getFileIconColor(fileName) {
+      const type = this.getFileType(fileName);
+      const colorMap = {
+        image: "#67C23A",
+        pdf: "#F56C6C",
+        office: "#409EFF",
+        other: "#909399"
+      };
+      return colorMap[type] || "#909399";
+    },
+
+    /** 鑾峰彇鏂囦欢鏍囩绫诲瀷 */
+    getFileTagType(fileName) {
+      const type = this.getFileType(fileName);
+      const typeMap = {
+        image: "success",
+        pdf: "danger",
+        office: "primary",
+        other: "info"
+      };
+      return typeMap[type] || "info";
+    },
+
+    /** 鑾峰彇鏂囦欢绫诲瀷鏂囨湰 */
+    getFileTypeText(fileName) {
+      const type = this.getFileType(fileName);
+      const textMap = {
+        image: "鍥剧墖",
+        pdf: "PDF",
+        office: "鏂囨。",
+        other: "鍏朵粬"
+      };
+      return textMap[type] || "鏈煡";
+    },
+
+    /** 妫�鏌ユ槸鍚﹀彲棰勮 */
+    isPreviewable(fileName) {
+      const type = this.getFileType(fileName);
+      return ["image", "pdf"].includes(type);
+    },
+
+    /** 鑾峰彇鏂囦欢鎵╁睍鍚� */
+    getFileExtension(filename) {
+      return filename
+        .split(".")
+        .pop()
+        .toLowerCase();
+    },
+
+    /** 鏍煎紡鍖栨枃浠跺ぇ灏� */
+    formatFileSize(bytes) {
+      if (!bytes || bytes === 0) return "0 B";
+      const k = 1024;
+      const sizes = ["B", "KB", "MB", "GB"];
+      const i = Math.floor(Math.log(bytes) / Math.log(k));
+      return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
+    },
+
+    /** 鏃ユ湡鏃堕棿鏍煎紡鍖� */
+    formatDateTime(dateTime) {
+      if (!dateTime) return "";
+      try {
+        const date = new Date(dateTime);
+        if (isNaN(date.getTime())) return dateTime;
+        const year = date.getFullYear();
+        const month = String(date.getMonth() + 1).padStart(2, "0");
+        const day = String(date.getDate()).padStart(2, "0");
+        const hours = String(date.getHours()).padStart(2, "0");
+        const minutes = String(date.getMinutes()).padStart(2, "0");
+        return `${year}-${month}-${day} ${hours}:${minutes}`;
+      } catch (error) {
+        return dateTime;
+      }
     }
   }
 };
 </script>
 
 <style scoped>
-.utilization-overview {
-  padding: 10px 0;
+.organ-procurement-detail {
+  padding: 20px;
+  background-color: #f5f7fa;
+  min-height: 100vh;
 }
 
-.overview-item {
+.detail-card {
+  margin-bottom: 20px;
+  border-radius: 8px;
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+  border: 1px solid #e4e7ed;
+}
+
+.procurement-card {
+  margin-bottom: 20px;
+  border-radius: 8px;
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+  border: 1px solid #e4e7ed;
+}
+
+.attachment-card {
+  margin-bottom: 20px;
+  border-radius: 8px;
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+  border: 1px solid #e4e7ed;
+  padding: 20px;
+  background: #fafafa;
+}
+
+.attachment-header {
   display: flex;
   align-items: center;
-  margin-bottom: 15px;
-  padding: 8px 0;
-  border-bottom: 1px solid #f0f0f0;
+  gap: 8px;
+  margin-bottom: 16px;
+  padding-bottom: 8px;
+  border-bottom: 1px solid #ebeef5;
 }
 
-.overview-icon {
-  font-size: 24px;
-  margin-right: 15px;
-}
-
-.overview-content .value {
-  font-size: 24px;
-  font-weight: bold;
+.attachment-title {
+  font-weight: 600;
   color: #303133;
 }
 
-.overview-content .label {
+.attachment-tip {
   font-size: 12px;
   color: #909399;
+  margin-left: auto;
 }
 
-.success-stats, .time-tracking, .quality-assessment {
-  padding: 10px 0;
+.attachment-list {
+  margin-top: 16px;
 }
 
-.success-item, .time-item, .quality-item {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  margin-bottom: 15px;
-}
-
-.success-item .label, .time-item .label, .quality-item .label {
-  color: #606266;
+.list-title {
+  font-weight: bold;
+  margin-bottom: 12px;
+  color: #303133;
   font-size: 14px;
-  min-width: 80px;
 }
 
-.time-item .value {
+.file-name {
+  font-size: 13px;
+  margin-left: 8px;
+}
+
+.detail-title {
+  font-size: 18px;
   font-weight: 600;
-  color: #409EFF;
+  color: #303133;
+  line-height: 1.4;
 }
 
-.chart-container {
-  position: relative;
-  min-height: 300px;
-}
-
-.action-buttons {
-  display: flex;
-  justify-content: center;
-  gap: 15px;
+/* 缁熻淇℃伅鏍峰紡 */
+.procurement-stats {
   margin-top: 20px;
+  padding: 15px;
+  background: linear-gradient(135deg, #a6b2e7 0%, #8a66ad 100%);
+  border-radius: 8px;
+  color: white;
 }
 
-.card-header {
+.stat-item {
   display: flex;
-  justify-content: space-between;
+  flex-direction: column;
   align-items: center;
+  padding: 10px;
+  text-align: center;
+}
+
+.stat-label {
+  font-size: 12px;
+  opacity: 0.9;
+  margin-bottom: 5px;
+  color: rgba(255, 255, 255, 0.9);
+}
+
+.stat-value {
+  font-size: 18px;
+  font-weight: bold;
+  color: white;
+}
+
+/* 绌虹姸鎬佹牱寮� */
+.empty-procurement {
+  text-align: center;
+  padding: 40px 0;
+  color: #909399;
+  background: #fafafa;
+  border-radius: 4px;
+  margin: 20px 0;
+}
+
+/* 瀵硅瘽妗嗗簳閮ㄦ寜閽� */
+.dialog-footer {
+  margin-top: 20px;
+  text-align: center;
+  padding-top: 20px;
+  border-top: 1px solid #e4e7ed;
+}
+
+.dialog-footer .el-button {
+  margin: 0 10px;
+  min-width: 120px;
+}
+
+/* 琛ㄦ牸琛屾牱寮� */
+:deep(.warning-row) {
+  background-color: #fff7e6 !important;
+}
+
+:deep(.warning-row:hover) {
+  background-color: #ffecc2 !important;
+}
+
+/* 鍝嶅簲寮忚璁� */
+@media (max-width: 768px) {
+  .organ-procurement-detail {
+    padding: 10px;
+  }
+
+  .procurement-stats .el-col {
+    margin-bottom: 10px;
+  }
 }
 </style>

--
Gitblit v1.9.3