fix: 完善聊天解析与导出体验

- 修复引用消息名称和图片布局
- 明确单会话图片测试日志范围
- 支持导出文件附件
- 完善图片批测、会话刷新和安全退出
This commit is contained in:
Wxw-Gu
2026-08-04 12:03:07 +08:00
parent d76727875d
commit c70e49bf16
41 changed files with 2320 additions and 221 deletions
+20 -1
View File
@@ -17,6 +17,7 @@ import { ImageKeyConfigService } from './services/image-key-config-service'
import { VideoAssetService } from './video-asset-service'
import { StickerService } from './sticker-service'
import { getImageExportAttempts } from '../shared/export-media'
import { FileAssetService } from './file-asset-service'
const jobs = new Set<string>()
const safeFilePart = (value: string): string =>
@@ -87,6 +88,7 @@ async function readAvatarAsset(
const kindOf = (message: Message): ExportMessageKind => {
const type = message.contentData?.type
if (type === 'system' && message.contentData?.pat) return 'text'
if (type === 'share' && message.contentData.typeVal === '6') return 'file'
if (
type === 'image' ||
type === 'video' ||
@@ -142,6 +144,7 @@ export async function runExport(request: ExportRequest, win: BrowserWindow): Pro
for (const message of messages) {
message.exportMediaUrl = undefined
message.exportMediaType = undefined
message.exportMediaName = undefined
message.exportMediaError = undefined
message.voiceDataUrl = undefined
message.exportShowAvatar = request.includeAvatars !== false
@@ -149,7 +152,7 @@ export async function runExport(request: ExportRequest, win: BrowserWindow): Pro
if (mappedName) message.name = mappedName
if (
request.format !== 'html' &&
['image', 'video', 'voice', 'sticker'].includes(kindOf(message))
['image', 'video', 'voice', 'sticker', 'file'].includes(kindOf(message))
) {
message.exportMediaError = '当前导出格式记录媒体状态,但不复制媒体文件'
}
@@ -198,6 +201,7 @@ export async function runExport(request: ExportRequest, win: BrowserWindow): Pro
: null
const videoService = client ? new VideoAssetService(client) : null
const stickerService = client ? new StickerService(client) : null
const fileService = client ? new FileAssetService(client) : null
const exportedAvatars = new Map<string, string>()
const voiceService =
request.includeMedia && chat.getChatDb()
@@ -362,6 +366,21 @@ export async function runExport(request: ExportRequest, win: BrowserWindow): Pro
} else {
keepMediaError(request, message, result.error || '表情资源缺失或下载失败')
}
} else if (message.contentData.type === 'share' && message.contentData.typeVal === '6') {
if (!fileService) {
keepMediaError(request, message, '数据库未连接,无法定位本地文件附件')
} else {
const resolved = fileService.resolve(message.contentData.title, message.createTime)
if (!resolved.success || !resolved.filePath || !resolved.fileName) {
keepMediaError(request, message, resolved.error || '本地文件附件缺失')
} else {
const name = `file_${index + 1}_${safeFilePart(resolved.fileName)}`
await fs.copyFile(resolved.filePath, join(outputDir, 'media', name))
message.exportMediaUrl = `media/${name}`
message.exportMediaType = 'file'
message.exportMediaName = message.contentData.title || resolved.fileName
}
}
}
send({
jobId: request.jobId,