From 065e8da04dede836cd708948b28f4c2a1b911154 Mon Sep 17 00:00:00 2001 From: jingrow Date: Sat, 11 Oct 2025 04:53:23 +0800 Subject: [PATCH] =?UTF-8?q?pagetype=E8=AF=A6=E6=83=85=E9=A1=B5=E7=9A=84?= =?UTF-8?q?=E5=9B=BE=E7=89=87=E5=A6=82=E6=9E=9C=E6=9C=AC=E5=9C=B0=E4=B8=8D?= =?UTF-8?q?=E5=AD=98=E5=9C=A8=E5=B0=B1=E8=87=AA=E5=8A=A8=E5=BC=82=E6=AD=A5?= =?UTF-8?q?=E4=B8=8B=E8=BD=BD=E5=88=B0=E6=9C=AC=E5=9C=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/views/pagetype/GenericDetailPage.vue | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/frontend/src/views/pagetype/GenericDetailPage.vue b/frontend/src/views/pagetype/GenericDetailPage.vue index 163390c..ec6e431 100644 --- a/frontend/src/views/pagetype/GenericDetailPage.vue +++ b/frontend/src/views/pagetype/GenericDetailPage.vue @@ -416,6 +416,7 @@ import axios from 'axios' import { t } from '../../shared/i18n' import { get_session_api_headers } from '../../shared/api/auth' import { updateRecord, getRecord } from '../../shared/api/common' +import { downloadImageToLocal } from '../../shared/api/common' import { usePageTypeSlug } from '../../shared/utils/slug' const route = useRoute() @@ -860,6 +861,73 @@ async function loadMeta() { } } +// 提取图片URL的函数 +function extractImageUrls(data: any): string[] { + const urls: string[] = [] + + // 从HTML字符串中提取图片URL的正则表达式 + const imageUrlRegex = /\/files\/[^"'\s>]+\.(jpg|jpeg|png|gif|webp)/gi + + function traverse(obj: any) { + if (typeof obj === 'string') { + // 检查是否是直接的相对路径图片URL + if (obj.startsWith('/files/') && (obj.includes('.jpg') || obj.includes('.jpeg') || obj.includes('.png') || obj.includes('.gif') || obj.includes('.webp'))) { + urls.push(obj) + } + + // 从HTML字符串中提取图片URL + const matches = obj.match(imageUrlRegex) + if (matches) { + urls.push(...matches) + } + } else if (Array.isArray(obj)) { + obj.forEach(traverse) + } else if (obj && typeof obj === 'object') { + Object.values(obj).forEach(traverse) + } + } + + traverse(data) + return [...new Set(urls)] // 去重 +} + +// 图片下载缓存,避免重复检查 +const imageDownloadCache = new Set() + +// 自动下载图片的函数(优化版) +async function autoDownloadImages(imageUrls: string[]) { + const downloadPromises = imageUrls.map(async (url) => { + const filename = url.split('/').pop() || 'image.jpg' + + // 使用缓存避免重复检查 + if (imageDownloadCache.has(filename)) { + return false + } + + try { + const result = await downloadImageToLocal(url, filename) + if (result.success) { + imageDownloadCache.add(filename) + return true + } + } catch (error) { + // 静默处理下载错误 + } + return false + }) + + const results = await Promise.all(downloadPromises) + const hasNewDownloads = results.some(Boolean) + + if (hasNewDownloads) { + // 使用更平滑的更新方式,而不是整页刷新 + setTimeout(() => { + // 重新加载当前页面数据,而不是整页刷新 + loadDetail() + }, 300) + } +} + // 加载详情数据 async function loadDetail() { if (isNew.value) { @@ -872,6 +940,12 @@ async function loadDetail() { const res = await getRecord(entity.value, id.value) if (res.success && res.data) { record.value = res.data + + // 自动下载相对路径的图片 + const imageUrls = extractImageUrls(record.value) + if (imageUrls.length > 0) { + await autoDownloadImages(imageUrls) + } } else { message.error(res.message || t('Failed to load detail')) record.value = {}