From e756e3cc5ddd0ddb42c5f00d6bb3eee76ba73e6f Mon Sep 17 00:00:00 2001
From: ZN <zhang_12370@163.com>
Date: 星期一, 09 三月 2026 14:14:24 +0800
Subject: [PATCH] feat(project-type): 优化附件管理和界面交互

---
 src/views/projectManagement/projectType/index.vue |  160 +++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 107 insertions(+), 53 deletions(-)

diff --git a/src/views/projectManagement/projectType/index.vue b/src/views/projectManagement/projectType/index.vue
index 34344c9..c2ea441 100644
--- a/src/views/projectManagement/projectType/index.vue
+++ b/src/views/projectManagement/projectType/index.vue
@@ -9,54 +9,64 @@
     </div>
 
     <div class="content-section" v-loading="loading">
-      <div v-for="item in projectTypeList" :key="item.id" class="project-type-card">
-        <div class="card-header">
-          <div class="info-group">
-            <span class="label">绫诲瀷鍚嶇О:</span>
-            <span class="value">{{ item.name }}</span>
-          </div>
-          <div class="info-group">
-            <span class="label">澶囨敞:</span>
-            <span class="value">{{ item.description || '--' }}</span>
-          </div>
-          <div class="info-group">
-            <span class="label">闄勪欢:</span>
-            <div class="attachment-info" v-if="item.attachment" @click="handleExpand(item)">
-              <el-icon class="file-icon"><Document /></el-icon>
-              <span class="file-name">{{ item.attachment.name }}</span>
-              <el-icon class="download-icon" @click.stop="handleDownload(item.attachment)"><Download /></el-icon>
-              <span class="expand-link">{{ item.expanded ? '鏀惰捣' : '灞曞紑' }}</span>
-              <el-icon class="arrow-icon" :class="{ 'is-reverse': item.expanded }"><ArrowDown /></el-icon>
+      <div class="card-list-scroll">
+        <div v-for="item in projectTypeList" :key="item.id" class="project-type-card">
+          <div class="card-header">
+            <div class="info-group">
+              <span class="label">绫诲瀷鍚嶇О:</span>
+              <span class="value">{{ item.name }}</span>
             </div>
-            <span class="value" v-else>--</span>
-          </div>
-          <div class="actions">
-            <el-button link type="primary" @click="handleUpdate(item)">缂栬緫</el-button>
-            <el-button link type="primary" @click="handleCopy(item)">澶嶅埗</el-button>
-            <el-button link type="danger" @click="handleDelete(item)">鍒犻櫎</el-button>
-          </div>
-        </div>
-
-        <el-collapse-transition>
-          <div v-show="item.expanded" class="expanded-content">
-            <div class="attachment-list">
-              <div class="attachment-item">
-                <el-icon><Document /></el-icon>
-                <span>{{ item.attachment?.name }}</span>
-                <el-button link type="primary" size="small" @click="handleDownload(item.attachment)">涓嬭浇</el-button>
+            <div class="info-group">
+              <span class="label">澶囨敞:</span>
+              <span class="value">{{ item.description || '--' }}</span>
+            </div>
+            <div class="info-group">
+              <span class="label">闄勪欢:</span>
+              <div
+                class="attachment-info"
+                v-if="(item.attachmentList?.length || 0) > 0"
+                @click="handleExpand(item)"
+              >
+                {{ item.attachmentList[0]?.fileName || item.attachmentList[0]?.name }}
+                <span v-if="item.attachmentList.length > 1" class="file-count">
+                  +{{ item.attachmentList.length - 1 }}
+                </span>
+                <span class="expand-link">{{ item.expanded ? '鏀惰捣' : '灞曞紑' }}</span>
               </div>
+              <span class="value" v-else>--</span>
+            </div>
+            <div class="actions">
+              <el-button link type="primary" @click="handleUpdate(item)">缂栬緫</el-button>
+              <el-button link type="primary" @click="handleCopy(item)">澶嶅埗</el-button>
+              <el-button link type="danger" @click="handleDelete(item)">鍒犻櫎</el-button>
             </div>
           </div>
-        </el-collapse-transition>
 
-        <div class="card-body">
-          <div class="workflow-container">
-            <div v-for="(step, index) in item.steps" :key="index" class="workflow-step">
-              <div class="step-main">
-                <div class="step-circle">{{ index + 1 }}</div>
-                <div v-if="index < item.steps.length - 1" class="step-line"></div>
+          <el-collapse-transition>
+            <div v-show="item.expanded" class="expanded-content">
+              <div class="attachment-list">
+                <div
+                  v-for="att in (item.attachmentList || [])"
+                  :key="att.id || att.url || att.fileUrl || att.fileName || att.name"
+                  class="attachment-item"
+                >
+                  <el-icon><Document /></el-icon>
+                  <span class="attachment-name">{{ att.fileName || att.name || '--' }}</span>
+                  <el-button link type="primary" size="small" @click="handleDownload(att)">涓嬭浇</el-button>
+                </div>
               </div>
-              <div class="step-label">{{ step.label }}</div>
+            </div>
+          </el-collapse-transition>
+
+          <div class="card-body">
+            <div class="workflow-container">
+              <div v-for="(step, index) in item.steps" :key="index" class="workflow-step">
+                <div class="step-main">
+                  <div class="step-circle">{{ index + 1 }}</div>
+                  <div v-if="index < item.steps.length - 1" class="step-line"></div>
+                </div>
+                <div class="step-label">{{ step.label }}</div>
+              </div>
             </div>
           </div>
         </div>
@@ -122,6 +132,7 @@
       projectTypeList.value = res.data.records.map(item => ({
         ...item,
         expanded: false,
+        attachmentList: Array.isArray(item.attachmentList) ? item.attachmentList : [],
         // 鍚庣杩斿洖鐨勮妭鐐瑰垪琛ㄥ彲鑳芥槸 planNodeList 鎴� savePlanNodeList
         steps: (item.planNodeList || item.savePlanNodeList || []).map(node => ({
           label: node.name
@@ -140,7 +151,7 @@
           id: 1,
           name: 'A椤圭洰',
           description: '',
-          attachment: { name: 'precaution...' },
+          attachmentList: [{ id: 1, fileName: 'precaution...' }],
           steps: [{ label: '绔嬮」' }, { label: '璁捐' }, { label: '閲囪喘' }, { label: '鐢熶骇' }, { label: '鍑鸿揣' }],
           expanded: false
         }
@@ -208,7 +219,9 @@
   const copyData = {
     name: row.name + " - 鍓湰",
     description: row.description,
-    attachmentIds: row.attachmentIds || [],
+    attachmentIds: Array.isArray(row.attachmentIds)
+      ? row.attachmentIds
+      : (row.attachmentList || []).map(x => x.id).filter(Boolean),
     savePlanNodeList: (row.planNodeList || row.savePlanNodeList || []).map(node => ({
       name: node.name,
       leaderId: node.leaderId,
@@ -238,8 +251,12 @@
 
 /** 涓嬭浇闄勪欢 */
 function handleDownload(attachment) {
-  // 瀹炵幇涓嬭浇閫昏緫
-  ElMessage.info("寮�濮嬩笅杞�: " + (attachment.name || "鏂囦欢"));
+  const url = attachment?.url || attachment?.fileUrl || attachment?.tempPath || attachment?.fileName;
+  if (!url) {
+    ElMessage.warning("鏈壘鍒板彲涓嬭浇鐨勬枃浠跺湴鍧�");
+    return;
+  }
+  proxy.$download.name(url);
 }
 
 onMounted(() => {
@@ -250,11 +267,15 @@
 <style scoped lang="scss">
 .app-container {
   background-color: #f5f7fa;
-  min-height: calc(100vh - 84px);
+  height: calc(100vh - 84px);
   padding: 20px;
+  display: flex;
+  flex-direction: column;
+  overflow: hidden;
 }
 
 .header-section {
+  flex-shrink: 0;
   display: flex;
   justify-content: space-between;
   align-items: center;
@@ -288,12 +309,33 @@
   }
 }
 
+.content-section{
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  overflow: hidden;
+  background: #fff;
+  border-radius: 8px;
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
+}
+
+.card-list-scroll {
+  flex: 1;
+  overflow-y: auto;
+  padding: 20px;
+}
+
 .project-type-card {
   background-color: #fff;
   border-radius: 8px;
   padding: 20px;
   margin-bottom: 20px;
   box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
+  border: 1px solid #ebeef5;
+
+  &:last-child {
+    margin-bottom: 0;
+  }
 
   .card-header {
     display: flex;
@@ -335,6 +377,12 @@
           overflow: hidden;
           text-overflow: ellipsis;
           white-space: nowrap;
+        }
+
+        .file-count {
+          margin-right: 8px;
+          font-size: 12px;
+          color: #909399;
         }
 
         .download-icon {
@@ -379,6 +427,13 @@
       .el-icon {
         font-size: 16px;
         color: #409eff;
+      }
+
+      .attachment-name {
+        flex: 1;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
       }
     }
   }
@@ -443,9 +498,13 @@
 }
 
 .pagination-container {
+  flex-shrink: 0;
   display: flex;
   justify-content: flex-end;
-  margin-top: 20px;
+  padding: 10px 20px;
+  background-color: #fff;
+  border-top: 1px solid #ebeef5;
+  margin-top: 0;
 }
 
 .step-config-item {
@@ -453,10 +512,5 @@
   align-items: center;
   gap: 10px;
   margin-bottom: 10px;
-}
-.content-section{
-    background: #fff;
-    border-radius: 8px;
-    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
 }
 </style>

--
Gitblit v1.9.3