From ac5dac41df2b75de998a79701d846b33a47ce64c Mon Sep 17 00:00:00 2001
From: liding <756868258@qq.com>
Date: 星期五, 05 六月 2026 16:59:06 +0800
Subject: [PATCH] feat(approve): 优化审批详情面板显示逻辑并增加附件功能

---
 src/views/officeProcessAutomation/ApproveManage/approve-list/components/ApproveDetailPanel.vue |  185 +++++++++++++++++++++++++++++++---------------
 1 files changed, 124 insertions(+), 61 deletions(-)

diff --git a/src/views/officeProcessAutomation/ApproveManage/approve-list/components/ApproveDetailPanel.vue b/src/views/officeProcessAutomation/ApproveManage/approve-list/components/ApproveDetailPanel.vue
index 19328af..6d8c9de 100644
--- a/src/views/officeProcessAutomation/ApproveManage/approve-list/components/ApproveDetailPanel.vue
+++ b/src/views/officeProcessAutomation/ApproveManage/approve-list/components/ApproveDetailPanel.vue
@@ -1,82 +1,145 @@
-<!-- 缁熶竴瀹℃壒锛氫笟鍔℃憳瑕� -->
+<!-- 瀹℃壒璇︽儏锛氬熀纭�淇℃伅 + 濉姤鍐呭 -->
 <template>
-  <el-descriptions :column="2" border>
-    <el-descriptions-item label="涓氬姟鍗曞彿">{{ row.bizId || row.id || "鈥�" }}</el-descriptions-item>
-    <el-descriptions-item label="瀹℃壒鐘舵��">
-      <el-tag :type="approvalStatusTagType(row.approvalStatus)" size="small" effect="plain">
-        {{ approvalStatusLabel(row.approvalStatus) }}
-      </el-tag>
-    </el-descriptions-item>
-    <el-descriptions-item label="瀹℃壒绫诲瀷">
-      <span class="approve-type-cell" :style="approvalTypeStyle(row.approvalType)">
-        {{ approvalTypeLabel(row.approvalType) }}
-      </span>
-    </el-descriptions-item>
-    <el-descriptions-item label="瀹℃壒鏂瑰紡">
-      <span class="approval-method-text">{{ approvalModeLabel(row.approvalMode) }}</span>
-    </el-descriptions-item>
-    <el-descriptions-item label="鐢宠浜虹紪鍙�">{{ row.applicantNo || "鈥�" }}</el-descriptions-item>
-    <el-descriptions-item label="鐢宠浜哄悕绉�">{{ row.applicantName || "鈥�" }}</el-descriptions-item>
-    <el-descriptions-item label="鐢宠鎽樿" :span="2">{{ row.summary || "鈥�" }}</el-descriptions-item>
-    <el-descriptions-item v-if="row.rejectReason" label="椹冲洖鍘熷洜" :span="2">
-      <span class="reject-text">{{ row.rejectReason }}</span>
-    </el-descriptions-item>
-    <el-descriptions-item label="鍒涘缓鏃堕棿" :span="2">{{ row.createTime || "鈥�" }}</el-descriptions-item>
-  </el-descriptions>
+  <div class="approve-detail-panel">
+    <div class="detail-block">
+      <div class="detail-block-title">鍩烘湰淇℃伅</div>
+      <el-descriptions :column="2" border>
+        <el-descriptions-item label="涓氬姟鍗曞彿">{{ row.bizId || row.id || "鈥�" }}</el-descriptions-item>
+        <el-descriptions-item label="瀹℃壒鐘舵��">
+          <el-tag :type="approvalStatusTagType(row.approvalStatus)" size="small" effect="plain">
+            {{ approvalStatusLabel(row.approvalStatus) }}
+          </el-tag>
+        </el-descriptions-item>
+        <el-descriptions-item label="瀹℃壒绫诲瀷">
+          <span class="approve-type-cell" :style="approvalTypeStyle(row.approvalType)">
+            {{ approvalTypeLabel(row.approvalType) }}
+          </span>
+        </el-descriptions-item>
+        <el-descriptions-item label="鐢宠浜虹紪鍙�">{{ row.applicantNo || "鈥�" }}</el-descriptions-item>
+        <el-descriptions-item label="鐢宠浜哄悕绉�">{{ applicantNameDisplay }}</el-descriptions-item>
+        <el-descriptions-item label="鐢宠鎽樿">{{ row.summary || "鈥�" }}</el-descriptions-item>
+        <el-descriptions-item v-if="row.rejectReason" label="椹冲洖鍘熷洜" :span="2">
+          <span class="reject-text">{{ row.rejectReason }}</span>
+        </el-descriptions-item>
+        <el-descriptions-item label="鍒涘缓鏃堕棿" :span="2">
+          {{ formatDisplayTime(row.createTime) }}
+        </el-descriptions-item>
+      </el-descriptions>
+    </div>
 
-  <template v-if="extraFields.length">
-    <el-divider content-position="left">濉姤鍐呭</el-divider>
-    <el-descriptions :column="2" border size="small">
-      <el-descriptions-item v-for="item in extraFields" :key="item.key" :label="item.label">
-        {{ item.display }}
-      </el-descriptions-item>
-    </el-descriptions>
-  </template>
+    <div class="detail-block">
+      <div class="detail-block-title">濉姤鍐呭</div>
+      <FormPayloadFields
+        :fields="formResolved.fields"
+        :form-payload="formResolved.formPayload"
+        readonly
+      />
+    </div>
+
+    <div class="detail-block">
+      <div class="detail-block-title">闄勪欢</div>
+      <template v-if="attachmentFiles.length">
+        <el-tag v-for="(f, i) in attachmentFiles" :key="i" class="file-tag" type="info" @click="openFile(f)">
+          {{ f.name || f.originalFilename }}
+        </el-tag>
+      </template>
+      <el-empty v-else description="鏆傛棤闄勪欢" :image-size="48" />
+    </div>
+  </div>
 </template>
 
 <script setup>
-import { computed } from "vue";
+import { computed, onMounted, watch } from "vue";
+import { formatDisplayTime } from "../../approve-template/approveTemplateConstants.js";
+import { useSelectOptionSources } from "../../approve-template/useSelectOptionSources.js";
 import {
   approvalTypeLabel,
   approvalTypeStyle,
-  approvalModeLabel,
   approvalStatusLabel,
   approvalStatusTagType,
-  SUBMIT_TEMPLATES,
+  resolveInstanceFormFields,
+  formatFieldDisplayValue,
 } from "../approveListConstants.js";
+import FormPayloadFields from "./FormPayloadFields.vue";
 
 const props = defineProps({
   row: { type: Object, default: () => ({}) },
 });
 
-const extraFields = computed(() => {
-  const payload = props.row?.formPayload || {};
-  const tpl = Object.values(SUBMIT_TEMPLATES).find((t) => t.approvalType === props.row?.approvalType);
-  if (!tpl?.fields?.length) {
-    return Object.keys(payload)
-      .filter((k) => k !== "summary" && payload[k] != null && payload[k] !== "")
-      .map((k) => ({ key: k, label: k, display: formatValue(payload[k]) }));
-  }
-  return tpl.fields
-    .map((f) => {
-      const val = payload[f.key];
-      if (val == null || val === "" || (Array.isArray(val) && !val.length)) return null;
-      let display = formatValue(val);
-      if (f.type === "select" && f.options) {
-        display = f.options.find((o) => o.value === val)?.label || display;
-      }
-      return { key: f.key, label: f.label, display };
-    })
-    .filter(Boolean);
+const { ensureForFields, getDisplayLabel } = useSelectOptionSources();
+
+const formResolved = computed(() => resolveInstanceFormFields(props.row));
+
+const applicantField = computed(() => {
+  const fields = formResolved.value.fields || [];
+  return (
+    fields.find((f) => String(f?.label || "").includes("鐢宠浜�")) ||
+    fields.find((f) => f?.type === "select" && f?.optionSource === "user") ||
+    null
+  );
 });
 
-function formatValue(val) {
-  if (Array.isArray(val)) return val.join(" 鑷� ");
-  return String(val);
+const applicantNameDisplay = computed(() => {
+  if (!applicantField.value) return props.row?.applicantName || "鈥�";
+  const val = formResolved.value.formPayload?.[applicantField.value.key];
+  if (val == null || val === "") return props.row?.applicantName || "鈥�";
+  if (applicantField.value.optionSource && applicantField.value.optionSource !== "static") {
+    const label = getDisplayLabel(applicantField.value, val);
+    if (label && label !== "鈥�") return label;
+  }
+  const formatted = formatFieldDisplayValue(applicantField.value, val);
+  if (formatted && formatted !== "鈥�") return formatted;
+  return props.row?.applicantName || "鈥�";
+});
+
+async function loadOptionCaches() {
+  await ensureForFields(formResolved.value.fields || []);
+}
+
+onMounted(() => {
+  loadOptionCaches();
+});
+
+watch(
+  () => formResolved.value.fields,
+  () => {
+    loadOptionCaches();
+  },
+  { deep: true }
+);
+
+const attachmentFiles = computed(() => {
+  const list =
+    props.row?.storageBlobVOList ||
+    props.row?.storageBlobDTOs ||
+    props.row?.storageBlobDTOS ||
+    props.row?.storageBlobVOS ||
+    props.row?.attachmentList ||
+    [];
+  return Array.isArray(list) ? list : [];
+});
+
+function openFile(f) {
+  const url = f?.url || f?.previewURL || f?.downloadURL;
+  if (url) window.open(url, "_blank");
 }
 </script>
 
 <style scoped>
+.approve-detail-panel {
+  display: flex;
+  flex-direction: column;
+  gap: 20px;
+}
+.detail-block-title {
+  font-size: 14px;
+  font-weight: 600;
+  color: var(--el-text-color-primary);
+  margin: 0 0 12px;
+  padding-left: 10px;
+  border-left: 3px solid var(--el-color-primary);
+  line-height: 1.4;
+}
 .approve-type-cell {
   display: inline-block;
   padding: 2px 10px;
@@ -84,11 +147,11 @@
   font-size: 13px;
   line-height: 1.5;
 }
-.approval-method-text {
-  color: var(--el-color-danger);
-  font-weight: 500;
-}
 .reject-text {
   color: var(--el-color-danger);
 }
+.file-tag {
+  margin: 0 8px 8px 0;
+  cursor: pointer;
+}
 </style>

--
Gitblit v1.9.3