From da7b9833e734332d47a42fb8ba30daf263864b27 Mon Sep 17 00:00:00 2001
From: fuliqi <fuliqi@qq.com>
Date: 星期二, 11 二月 2025 16:17:31 +0800
Subject: [PATCH] 文件上传组件图片预览、工单详情页图片预览

---
 src/views/system/work-order/detail/index.vue |   51 ++++++++++++++--
 src/components/FileUpload/index.vue          |   88 ++++++++++++++++++++---------
 2 files changed, 104 insertions(+), 35 deletions(-)

diff --git a/src/components/FileUpload/index.vue b/src/components/FileUpload/index.vue
index 95ae3a6..721b530 100644
--- a/src/components/FileUpload/index.vue
+++ b/src/components/FileUpload/index.vue
@@ -28,17 +28,32 @@
     <!-- 鏂囦欢鍒楄〃 -->
     <transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
       <li :key="file.url" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList">
-        <el-link @click="handleDownload(file.url)" :underline="false" target="_blank">
-          <span class="el-icon-document"> {{ getFileName(file.name) }} </span>
-        </el-link>
-        <!-- <el-link :href="`${baseUrl}${file.url}`" :underline="false" target="_blank">
-          <span class="el-icon-document"> {{ getFileName(file.name) }} </span>
-        </el-link> -->
+        <!-- 鍥剧墖鏂囦欢 -->
+        <template v-if="isImage(file)">
+          <div class="image-preview" @click="handlePreview(file)">
+            <img :src="getImageUrl(file.url)" class="thumbnail" />
+            <span class="filename">{{ getFileName(file.name) }}</span>
+          </div>
+        </template>
+        <!-- 闈炲浘鐗囨枃浠� -->
+        <template v-else>
+          <el-link @click="handleDownload(file.url)" :underline="false" target="_blank">
+            <span class="el-icon-document"> {{ getFileName(file.name) }} </span>
+          </el-link>
+        </template>
         <div class="ele-upload-list__item-content-action">
+          <template v-if="isImage(file)">
+            <el-link :underline="false" @click="handleDownload(file.url)" type="primary" class="action-link">涓嬭浇</el-link>
+          </template>
           <el-link :underline="false" @click="handleDelete(index)" type="danger">鍒犻櫎</el-link>
         </div>
       </li>
     </transition-group>
+
+    <!-- 鍥剧墖棰勮寮圭獥 -->
+    <el-dialog :visible.sync="previewVisible" append-to-body title="鍥剧墖棰勮" width="800px">
+      <img :src="previewUrl" style="width: 100%;" />
+    </el-dialog>
   </div>
 </template>
 
@@ -48,24 +63,19 @@
 export default {
   name: "FileUpload",
   props: {
-    // 鍊�
     value: [String, Object, Array],
-    // 鏁伴噺闄愬埗
     limit: {
       type: Number,
       default: 5,
     },
-    // 澶у皬闄愬埗(MB)
     fileSize: {
       type: Number,
       default: 20,
     },
-    // 鏂囦欢绫诲瀷, 渚嬪['png', 'jpg', 'jpeg']
     fileType: {
       type: Array,
       default: () => ["docx", "xlsx", "ppt", "txt", "pdf","png","jpg"],
     },
-    // 鏄惁鏄剧ず鎻愮ず
     isShowTip: {
       type: Boolean,
       default: true
@@ -76,11 +86,14 @@
       number: 0,
       uploadList: [],
       baseUrl: process.env.VUE_APP_BASE_API,
-      uploadFileUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 涓婁紶鏂囦欢鏈嶅姟鍣ㄥ湴鍧�
+      uploadFileUrl: process.env.VUE_APP_BASE_API + "/common/upload",
       headers: {
         Authorization: "Bearer " + getToken(),
       },
       fileList: [],
+      previewVisible: false,
+      previewUrl: "",
+      imageTypes: ['png', 'jpg', 'jpeg', 'gif']
     };
   },
   watch: {
@@ -88,9 +101,7 @@
       handler(val) {
         if (val) {
           let temp = 1;
-          // 棣栧厛灏嗗�艰浆涓烘暟缁�
           const list = Array.isArray(val) ? val : this.value.split(',');
-          // 鐒跺悗灏嗘暟缁勮浆涓哄璞℃暟缁�
           this.fileList = list.map(item => {
             if (typeof item === "string") {
               item = { name: item, url: item };
@@ -108,15 +119,24 @@
     }
   },
   computed: {
-    // 鏄惁鏄剧ず鎻愮ず
     showTip() {
       return this.isShowTip && (this.fileType || this.fileSize);
     },
   },
   methods: {
-    // 涓婁紶鍓嶆牎妫�鏍煎紡鍜屽ぇ灏�
+    isImage(file) {
+      const fileName = file.name.split('.');
+      const fileExt = fileName[fileName.length - 1].toLowerCase();
+      return this.imageTypes.includes(fileExt);
+    },
+    getImageUrl(url) {
+      return url.startsWith('http') ? url : `${this.baseUrl}${url}`;
+    },
+    handlePreview(file) {
+      this.previewUrl = this.getImageUrl(file.url);
+      this.previewVisible = true;
+    },
     handleBeforeUpload(file) {
-      // 鏍℃鏂囦欢绫诲瀷
       if (this.fileType) {
         const fileName = file.name.split('.');
         const fileExt = fileName[fileName.length - 1];
@@ -126,7 +146,6 @@
           return false;
         }
       }
-      // 鏍℃鏂囦欢澶у皬
       if (this.fileSize) {
         const isLt = file.size / 1024 / 1024 < this.fileSize;
         if (!isLt) {
@@ -138,16 +157,13 @@
       this.number++;
       return true;
     },
-    // 鏂囦欢涓暟瓒呭嚭
     handleExceed() {
       this.$modal.msgError(`涓婁紶鏂囦欢鏁伴噺涓嶈兘瓒呰繃 ${this.limit} 涓�!`);
     },
-    // 涓婁紶澶辫触
     handleUploadError(err) {
       this.$modal.msgError("涓婁紶鏂囦欢澶辫触锛岃閲嶈瘯");
       this.$modal.closeLoading();
     },
-    // 涓婁紶鎴愬姛鍥炶皟
     handleUploadSuccess(res, file) {
       if (res.code === 200) {
         this.uploadList.push({ name: res.fileName, url: res.fileName });
@@ -160,12 +176,10 @@
         this.uploadedSuccessfully();
       }
     },
-    // 鍒犻櫎鏂囦欢
     handleDelete(index) {
       this.fileList.splice(index, 1);
       this.$emit("input", this.listToString(this.fileList));
     },
-    // 涓婁紶缁撴潫澶勭悊
     uploadedSuccessfully() {
       if (this.number > 0 && this.uploadList.length === this.number) {
         this.fileList = this.fileList.concat(this.uploadList);
@@ -175,16 +189,13 @@
         this.$modal.closeLoading();
       }
     },
-    // 鑾峰彇鏂囦欢鍚嶇О
     getFileName(name) {
-      // 濡傛灉鏄痷rl閭d箞鍙栨渶鍚庣殑鍚嶅瓧 濡傛灉涓嶆槸鐩存帴杩斿洖
       if (name.lastIndexOf("/") > -1) {
         return name.slice(name.lastIndexOf("/") + 1);
       } else {
         return name;
       }
     },
-    // 瀵硅薄杞垚鎸囧畾瀛楃涓插垎闅�
     listToString(list, separator) {
       let strs = "";
       separator = separator || ",";
@@ -193,8 +204,7 @@
       }
       return strs != '' ? strs.substr(0, strs.length - 1) : '';
     },
-    /** 涓嬭浇鎸夐挳鎿嶄綔 */
-    handleDownload (data) {
+    handleDownload(data) {
       this.$download.resource(data);
     }
   }
@@ -220,4 +230,26 @@
 .ele-upload-list__item-content-action .el-link {
   margin-right: 10px;
 }
+
+.image-preview {
+  display: flex;
+  align-items: center;
+  cursor: pointer;
+
+  .thumbnail {
+    width: 60px;
+    height: 60px;
+    object-fit: cover;
+    margin-right: 10px;
+    border-radius: 4px;
+  }
+
+  .filename {
+    color: #606266;
+  }
+}
+
+.action-link {
+  margin-right: 10px;
+}
 </style>
diff --git a/src/views/system/work-order/detail/index.vue b/src/views/system/work-order/detail/index.vue
index 52b102d..9a8d9ef 100644
--- a/src/views/system/work-order/detail/index.vue
+++ b/src/views/system/work-order/detail/index.vue
@@ -109,10 +109,24 @@
                   <el-tag :type="report.reportType === '浜嬪墠鎶ュ' ? 'warning' : 'danger'">{{report.reportType}}</el-tag>
                 </div>
                 <div style="margin: 8px 0">
-                  <el-link
+                  <div
                     v-for="item in report.reportMaterials != null ? report.reportMaterials.split(',') : report.reportMaterials"
-                    :underline="false" type="primary" :key="item" @click="handleDownload(item)">{{ item.substring(item.lastIndexOf("/") + 1)
-                    }}</el-link>
+                    :key="item">
+                    <el-image
+                      v-if="isImageFile(item)"
+                      :src="getPreview(item)"
+                      :preview-src-list="[getPreview(item)]"
+                      fit="cover"
+                      style="width: 100px; height: 100px; margin: 5px;"
+                    >
+                    </el-image>
+                    <el-link
+                      v-else
+                      :underline="false" type="primary" @click="handleDownload(item)">{{
+                        item.substring(item.lastIndexOf("/") + 1)
+                      }}
+                    </el-link>
+                  </div>
                 </div>
                 <div v-html="report.reportContent"></div>
               </div>
@@ -131,10 +145,24 @@
               :timestamp="yw.createTime">
               <div>
                 <div style="margin: 8px 0">
-                  <el-link
+                  <div
                     v-for="item in yw.ywProofMaterials != null ? yw.ywProofMaterials.split(',') : yw.ywProofMaterials"
-                    :underline="false" type="primary" :key="item" @click="handleDownload(item)">{{ item.substring(item.lastIndexOf("/") + 1)
-                    }}</el-link>
+                    :key="item">
+                    <el-image
+                      v-if="isImageFile(item)"
+                      :src="getPreview(item)"
+                      :preview-src-list="[getPreview(item)]"
+                      fit="cover"
+                      style="width: 100px; height: 100px; margin: 5px;"
+                    >
+                    </el-image>
+                    <el-link
+                      v-else
+                      :underline="false" type="primary" @click="handleDownload(item)">{{
+                        item.substring(item.lastIndexOf("/") + 1)
+                      }}
+                    </el-link>
+                  </div>
                 </div>
                 <div v-html="yw.ywCondition"></div>
               </div>
@@ -223,7 +251,16 @@
     this.getWorkOrder()
   },
   methods: {
-
+    getPreview(url) {
+      // 浣跨敤鍏ㄥ眬閰嶇疆鐨勫浘鐗囧墠缂�
+      return this.$img + url;
+    },
+    isImageFile(url) {
+      const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp'];
+      return imageExtensions.some(ext =>
+        url.toLowerCase().endsWith(ext)
+      );
+    },
     closeAuditing() {
       this.auditingOpen = false
     },

--
Gitblit v1.8.0