Преглед изворни кода

fix(photography): 优化缩略图生成逻辑并修复图片加载问题

- 将缩略图映射的数据类型从字符串改为字符串或null
- 使用AbortController管理缩略图生成过程,支持中断操作
- 添加生成状态检查避免重复请求
- 修改条件判断逻辑,使用逻辑或运算符替代三元运算符
- 在组件卸载时清理所有正在进行的缩略图生成任务
- 添加actionId参数区分不同操作的缩略图生成
- 统一错误处理,将失败的缩略图设置为null而非空字符串
panqiuyao пре 2 недеља
родитељ
комит
4034caa048

+ 30 - 11
frontend/src/views/Photography/composables/useThumbnails.ts

@@ -1,16 +1,30 @@
 import { ref, nextTick, onBeforeUnmount, Ref } from 'vue'
 
 export function useThumbnails(getFilePath: (p: string) => string) {
-  const thumbnailMap = ref<Record<string, string>>({})
-  const generatingSet = new Set<string>()
+  const thumbnailMap = ref<Record<string, string | null>>({})
+  const generatingMap = new Map<string, AbortController>()
   const placeholderDataUrl =
     'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="300" height="200"><rect width="100%" height="100%" fill="#F5F7FA"/></svg>'
 
-  async function generateThumbnail(imagePath: string, maxW = 400, maxH = 400) {
+  function isGenerating(key: string) {
+    return generatingMap.has(key)
+  }
+
+  function startGenerating(key: string) {
+    generatingMap.set(key, new AbortController())
+  }
+
+  function stopGenerating(key: string) {
+    generatingMap.get(key)?.abort()
+    generatingMap.delete(key)
+  }
+
+  async function generateThumbnail(imagePath: string, actionId: string, maxW = 400, maxH = 400) {
     if (!imagePath) return
-    if (thumbnailMap.value[imagePath]) return
-    if (generatingSet.has(imagePath)) return
-    generatingSet.add(imagePath)
+    const key = `${imagePath}::${actionId}`
+    if (thumbnailMap.value[imagePath] !== undefined) return
+    if (isGenerating(key)) return
+    startGenerating(key)
     try {
       const src = getFilePath(imagePath)
       const img = new Image()
@@ -22,7 +36,7 @@ export function useThumbnails(getFilePath: (p: string) => string) {
       const w = img.naturalWidth || img.width
       const h = img.naturalHeight || img.height
       if (!w || !h) {
-        thumbnailMap.value[imagePath] = ''
+        thumbnailMap.value[imagePath] = null
         return
       }
       const ratio = Math.min(1, maxW / w, maxH / h)
@@ -33,7 +47,7 @@ export function useThumbnails(getFilePath: (p: string) => string) {
       canvas.height = th
       const ctx = canvas.getContext('2d')
       if (!ctx) {
-        thumbnailMap.value[imagePath] = ''
+        thumbnailMap.value[imagePath] = null
         return
       }
       ctx.drawImage(img, 0, 0, tw, th)
@@ -41,9 +55,9 @@ export function useThumbnails(getFilePath: (p: string) => string) {
       thumbnailMap.value[imagePath] = dataUrl
     } catch (e) {
       console.warn('generateThumbnail error', e)
-      thumbnailMap.value[imagePath] = ''
+      thumbnailMap.value[imagePath] = null
     } finally {
-      generatingSet.delete(imagePath)
+      stopGenerating(key)
     }
   }
 
@@ -63,7 +77,10 @@ export function useThumbnails(getFilePath: (p: string) => string) {
             if (item && Array.isArray(item.items)) {
               item.items.forEach((img: any) => {
                 const p = img?.PhotoRecord?.image_path
-                if (p && !thumbnailMap.value[p]) generateThumbnail(p, 400, 400)
+                const actionId = img?.action_id || img?.action_name || ''
+                if (p && thumbnailMap.value[p] === undefined) {
+                  generateThumbnail(p, actionId, 400, 400)
+                }
               })
             }
             observer?.unobserve(el)
@@ -91,6 +108,8 @@ export function useThumbnails(getFilePath: (p: string) => string) {
       observer.disconnect()
       observer = null
     }
+    generatingMap.forEach((ctrl) => ctrl.abort())
+    generatingMap.clear()
   }
 
   onBeforeUnmount(() => {

+ 1 - 1
frontend/src/views/Photography/processImage.vue

@@ -60,7 +60,7 @@
                   <span class="tag" v-if="!image.PhotoRecord.image_path">{{ image.action_name }}</span>
                   <el-image
                     v-if="image.PhotoRecord.image_path"
-                    :src="thumbnailMap[image.PhotoRecord.image_path] ? thumbnailMap[image.PhotoRecord.image_path] : ''"
+                    :src="thumbnailMap[image.PhotoRecord.image_path] || getFilePath(image.PhotoRecord.image_path)"
                     :preview-src-list="getPreviewImageList(item)"
                     hide-on-click-modal
                     :initial-index="getPreviewIndex(item, index)"

+ 1 - 1
frontend/src/views/Photography/shot.vue

@@ -117,7 +117,7 @@
 <!--                  <span class="tag" v-if="!image.PhotoRecord.image_path">{{ image.action_name }}</span>-->
                   <div class="el-image_view" >
                     <el-image
-                      :src="thumbnailMap[image.PhotoRecord.image_path] ? thumbnailMap[image.PhotoRecord.image_path] : ''"
+                      :src="thumbnailMap[image.PhotoRecord.image_path] || getFilePath(image.PhotoRecord.image_path)"
                       :preview-src-list="getPreviewImageList(item)"
                       hide-on-click-modal
                       :initial-index="getPreviewIndex(item, index)"