瀏覽代碼

feat(claim): 添加理赔附件缩略图和图片预览功能

yz 3 周之前
父節點
當前提交
85d5a4af2f
共有 3 個文件被更改,包括 220 次插入2 次删除
  1. 61 0
      src/views/claim/index.js
  2. 103 0
      src/views/claim/index.scss
  3. 56 2
      src/views/claim/index.vue

+ 61 - 0
src/views/claim/index.js

@@ -61,6 +61,11 @@ export default {
           { required: true, message: '请选择审核时间', trigger: 'change' }
         ]
       },
+      // 添加图片预览相关状态
+      imagePreviewVisible: false,
+      previewImageUrl: '',
+      previewImageList: [],
+      currentPreviewIndex: 0,
       option: {
         height: 'auto',
         calcHeight: 30,
@@ -423,6 +428,62 @@ export default {
       window.open(file.fileUrl)
     },
 
+    /**
+     * 判断文件是否为图片
+     * @param {string} fileName - 文件名
+     * @returns {boolean} 是否为图片
+     */
+    isImageFile(fileName) {
+      if (!fileName) return false
+      const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg']
+      const extension = fileName.toLowerCase().substring(fileName.lastIndexOf('.'))
+      return imageExtensions.includes(extension)
+    },
+
+    /**
+     * 判断文件是否为视频
+     * @param {string} fileName - 文件名
+     * @returns {boolean} 是否为视频
+     */
+    isVideoFile(fileName) {
+      if (!fileName) return false
+      const videoExtensions = ['.mp4', '.avi', '.mov', '.wmv', '.flv', '.webm', '.mkv']
+      const extension = fileName.toLowerCase().substring(fileName.lastIndexOf('.'))
+      return videoExtensions.includes(extension)
+    },
+
+    /**
+     * 预览图片
+     * @param {Object} file - 文件信息
+     * @param {number} index - 当前图片索引
+     */
+    previewImage(file, index = 0) {
+      // 获取所有图片文件
+      const imageFiles = this.attachmentList.filter(item => this.isImageFile(item.fileName))
+      this.previewImageList = imageFiles.map(item => item.fileUrl)
+      this.currentPreviewIndex = imageFiles.findIndex(item => item.id === file.id)
+      this.previewImageUrl = file.fileUrl
+      this.imagePreviewVisible = true
+    },
+
+    /**
+     * 关闭图片预览
+     */
+    closeImagePreview() {
+      this.imagePreviewVisible = false
+      this.previewImageUrl = ''
+      this.previewImageList = []
+      this.currentPreviewIndex = 0
+    },
+
+    /**
+     * 处理图片加载错误
+     * @param {Event} event - 错误事件
+     */
+    handleImageError(event) {
+      event.target.src = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHZpZXdCb3g9IjAgMCA0MCA0MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjQwIiBoZWlnaHQ9IjQwIiBmaWxsPSIjRjVGNUY1Ii8+CjxwYXRoIGQ9Ik0yMCAyNkM5LjUgMjYgMSAxNy41IDEgN0MxIDMuNSA0IDEgNyAxSDMzQzM2IDEgMzkgMy41IDM5IDdDMzkgMTcuNSAzMC41IDI2IDIwIDI2WiIgZmlsbD0iI0NDQ0NDQyIvPgo8L3N2Zz4K'
+    },
+
     // 添加公共方法引用
     formatFileSize,
 

+ 103 - 0
src/views/claim/index.scss

@@ -0,0 +1,103 @@
+.thumbnail-container {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 50px;
+  height: 50px;
+  
+  .thumbnail-image {
+    width: 50px;
+    height: 50px;
+    object-fit: cover;
+    border-radius: 4px;
+    cursor: pointer;
+    transition: transform 0.2s;
+    
+    &:hover {
+      transform: scale(1.1);
+    }
+  }
+  
+  .thumbnail-video {
+    width: 50px;
+    height: 50px;
+    background: #f5f5f5;
+    border: 1px solid #ddd;
+    border-radius: 4px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    cursor: pointer;
+    transition: background-color 0.2s;
+    
+    &:hover {
+      background: #e6f7ff;
+    }
+    
+    i {
+      font-size: 20px;
+      color: #1890ff;
+    }
+  }
+  
+  .thumbnail-file {
+    width: 50px;
+    height: 50px;
+    background: #f5f5f5;
+    border: 1px solid #ddd;
+    border-radius: 4px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    
+    i {
+      font-size: 20px;
+      color: #666;
+    }
+  }
+}
+
+.image-preview-container {
+  text-align: center;
+  
+  .preview-image {
+    max-width: 100%;
+    max-height: 80vh; // 增加最大高度限制
+    min-height: 200px; // 设置最小高度
+  }
+  
+  .image-slot {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    height: 200px;
+    color: #999;
+    
+    i {
+      font-size: 40px;
+      margin-bottom: 10px;
+    }
+  }
+}
+
+// 新增:图片预览对话框样式
+.image-preview-dialog {
+  .el-dialog {
+    margin-top: 5vh !important;
+    margin-bottom: 5vh !important;
+    max-height: 90vh;
+    display: flex;
+    flex-direction: column;
+  }
+  
+  .el-dialog__body {
+    flex: 1;
+    padding: 20px;
+    overflow: auto;
+  }
+  
+  .el-dialog__footer {
+    flex-shrink: 0;
+  }
+}

+ 56 - 2
src/views/claim/index.vue

@@ -87,9 +87,34 @@
     <!-- 附件列表对话框 -->
     <el-dialog title="理赔附件"
                :visible.sync="attachmentVisible"
-               width="600px"
+               width="800px"
                append-to-body>
       <el-table :data="attachmentList" v-loading="attachmentLoading">
+        <!-- 新增缩略图列 -->
+        <el-table-column label="缩略图" width="80" align="center">
+          <template slot-scope="scope">
+            <div class="thumbnail-container">
+              <!-- 图片缩略图 -->
+              <img v-if="isImageFile(scope.row.fileName)"
+                   :src="scope.row.fileUrl"
+                   class="thumbnail-image"
+                   style="height: auto !important;"
+                   @click="previewImage(scope.row)"
+                   @error="handleImageError"
+                   alt="缩略图" />
+              <!-- 视频缩略图 -->
+              <div v-else-if="isVideoFile(scope.row.fileName)"
+                   class="thumbnail-video"
+                   @click="previewImage(scope.row)">
+                <i class="el-icon-video-play"></i>
+              </div>
+              <!-- 其他文件类型图标 -->
+              <div v-else class="thumbnail-file">
+                <i class="el-icon-document"></i>
+              </div>
+            </div>
+          </template>
+        </el-table-column>
         <el-table-column prop="fileName" label="文件名" show-overflow-tooltip></el-table-column>
         <el-table-column prop="fileType" label="文件类型" width="100"></el-table-column>
         <el-table-column prop="fileSize" label="文件大小" width="120">
@@ -97,8 +122,12 @@
             {{ formatFileSize(scope.row.fileSize) }}
           </template>
         </el-table-column>
-        <el-table-column label="操作" width="100">
+        <el-table-column label="操作" width="150">
           <template slot-scope="scope">
+            <el-button v-if="isImageFile(scope.row.fileName)"
+                       type="text"
+                       size="small"
+                       @click="previewImage(scope.row)">预览</el-button>
             <el-button type="text" size="small" @click="downloadFile(scope.row)">下载</el-button>
           </template>
         </el-table-column>
@@ -108,6 +137,31 @@
       </span>
     </el-dialog>
 
+    <!-- 图片预览对话框 -->
+    <el-dialog title="图片预览"
+               :visible.sync="imagePreviewVisible"
+               width="80%"
+               :close-on-click-modal="false"
+               append-to-body
+               custom-class="image-preview-dialog"
+               @close="closeImagePreview">
+      <div class="image-preview-container">
+        <el-image :src="previewImageUrl"
+                  :preview-src-list="previewImageList"
+                  :initial-index="currentPreviewIndex"
+                  fit="contain"
+                  class="preview-image">
+          <div slot="error" class="image-slot">
+            <i class="el-icon-picture-outline"></i>
+            <p>图片加载失败</p>
+          </div>
+        </el-image>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="closeImagePreview">关闭</el-button>
+      </span>
+    </el-dialog>
+
     <!-- 审核记录对话框 -->
     <el-dialog title="审核记录"
                :visible.sync="auditVisible"