mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-05-28 01:57:25 +08:00
feat: 解析器重构
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { FileDropZone } from '@/components/UI'
|
||||
|
||||
interface FileInfo {
|
||||
@@ -8,8 +8,21 @@ interface FileInfo {
|
||||
name: string
|
||||
format: string
|
||||
messageCount: number
|
||||
fileSize?: number // 文件大小(字节)
|
||||
status: 'pending' | 'parsed' | 'error'
|
||||
error?: string
|
||||
// 解析进度(用于大文件)
|
||||
progress?: number
|
||||
progressMessage?: string
|
||||
}
|
||||
|
||||
// 格式化文件大小
|
||||
function formatFileSize(bytes?: number): string {
|
||||
if (!bytes) return ''
|
||||
if (bytes < 1024) return `${bytes} B`
|
||||
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`
|
||||
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`
|
||||
return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`
|
||||
}
|
||||
|
||||
interface MergeConflict {
|
||||
@@ -35,6 +48,34 @@ const mergeProgress = ref(0)
|
||||
const currentStep = ref<'select' | 'conflict' | 'done'>('select')
|
||||
const outputFilePath = ref('')
|
||||
|
||||
// 解析进度监听
|
||||
let unsubscribeProgress: (() => void) | null = null
|
||||
|
||||
onMounted(() => {
|
||||
// 监听解析进度
|
||||
unsubscribeProgress = window.mergeApi.onParseProgress(({ filePath, progress }) => {
|
||||
const file = files.value.find((f) => f.path === filePath)
|
||||
if (file && file.status === 'pending') {
|
||||
// 使用 percentage 而不是 progress(更准确)
|
||||
file.progress = progress.percentage ?? progress.progress ?? 0
|
||||
// 构建更详细的进度消息
|
||||
if (progress.messagesProcessed && progress.messagesProcessed > 0) {
|
||||
file.progressMessage = `已处理 ${progress.messagesProcessed.toLocaleString()} 条消息`
|
||||
} else if (progress.message) {
|
||||
file.progressMessage = progress.message
|
||||
} else {
|
||||
file.progressMessage = '正在解析...'
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (unsubscribeProgress) {
|
||||
unsubscribeProgress()
|
||||
}
|
||||
})
|
||||
|
||||
// 计算总消息数
|
||||
const totalMessages = computed(() => files.value.reduce((sum, f) => sum + (f.messageCount || 0), 0))
|
||||
|
||||
@@ -66,6 +107,7 @@ async function addFilesByPaths(filePaths: string[]) {
|
||||
if (file) {
|
||||
file.format = info.format
|
||||
file.messageCount = info.messageCount
|
||||
file.fileSize = info.fileSize
|
||||
file.status = 'parsed'
|
||||
|
||||
// 设置默认输出名称(取第一个文件的群名)
|
||||
@@ -293,13 +335,34 @@ const file2Name = computed(() => files.value[1]?.name || '文件 2')
|
||||
|
||||
<!-- 文件信息 -->
|
||||
<div class="min-w-0 flex-1">
|
||||
<p class="truncate text-sm font-medium text-gray-900 dark:text-white">{{ file.name }}</p>
|
||||
<div class="flex items-center gap-2">
|
||||
<p class="truncate text-sm font-medium text-gray-900 dark:text-white">{{ file.name }}</p>
|
||||
<span
|
||||
v-if="file.fileSize && file.fileSize > 50 * 1024 * 1024"
|
||||
class="shrink-0 rounded bg-amber-100 px-1.5 py-0.5 text-xs text-amber-700 dark:bg-amber-900/30 dark:text-amber-400"
|
||||
>
|
||||
大文件
|
||||
</span>
|
||||
</div>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">
|
||||
<span :class="getStatusColor(file.status)">
|
||||
{{ file.status === 'pending' ? '解析中...' : file.status === 'error' ? file.error : file.format }}
|
||||
{{
|
||||
file.status === 'pending'
|
||||
? file.progressMessage || '解析中...'
|
||||
: file.status === 'error'
|
||||
? file.error
|
||||
: file.format
|
||||
}}
|
||||
</span>
|
||||
<template v-if="file.status === 'parsed'">· {{ file.messageCount.toLocaleString() }} 条消息</template>
|
||||
<template v-if="file.status === 'parsed'">
|
||||
· {{ file.messageCount.toLocaleString() }} 条消息
|
||||
<span v-if="file.fileSize" class="text-gray-400">· {{ formatFileSize(file.fileSize) }}</span>
|
||||
</template>
|
||||
</p>
|
||||
<!-- 解析进度条(大文件时显示) -->
|
||||
<div v-if="file.status === 'pending' && file.progress !== undefined" class="mt-1.5">
|
||||
<UProgress :model-value="file.progress" size="xs" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 删除按钮 -->
|
||||
|
||||
+24
-4
@@ -74,12 +74,14 @@ function openTutorial(type: 'wechat' | 'qq') {
|
||||
function getProgressText(): string {
|
||||
if (!importProgress.value) return ''
|
||||
switch (importProgress.value.stage) {
|
||||
case 'detecting':
|
||||
return '正在检测格式...'
|
||||
case 'reading':
|
||||
return '正在读取中...'
|
||||
return '正在读取文件...'
|
||||
case 'parsing':
|
||||
return '解析器解析中...'
|
||||
return '正在解析消息...'
|
||||
case 'saving':
|
||||
return '写入本地数据库中...'
|
||||
return '正在写入数据库...'
|
||||
case 'done':
|
||||
return '导入完成'
|
||||
case 'error':
|
||||
@@ -88,6 +90,24 @@ function getProgressText(): string {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
function getProgressDetail(): string {
|
||||
if (!importProgress.value) return ''
|
||||
const { messagesProcessed, totalBytes, bytesRead } = importProgress.value
|
||||
|
||||
if (messagesProcessed && messagesProcessed > 0) {
|
||||
return `已处理 ${messagesProcessed.toLocaleString()} 条消息`
|
||||
}
|
||||
|
||||
if (totalBytes && bytesRead) {
|
||||
const percent = Math.round((bytesRead / totalBytes) * 100)
|
||||
const mbRead = (bytesRead / 1024 / 1024).toFixed(1)
|
||||
const mbTotal = (totalBytes / 1024 / 1024).toFixed(1)
|
||||
return `${mbRead} MB / ${mbTotal} MB (${percent}%)`
|
||||
}
|
||||
|
||||
return importProgress.value.message || ''
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -165,7 +185,7 @@ function getProgressText(): string {
|
||||
<UProgress v-model="importProgress.progress" size="md" />
|
||||
</div>
|
||||
<p class="mt-3 text-sm text-gray-500 dark:text-gray-400">
|
||||
{{ importProgress.message }}
|
||||
{{ getProgressDetail() }}
|
||||
</p>
|
||||
</template>
|
||||
<template v-else>
|
||||
|
||||
+2
-2
@@ -71,9 +71,9 @@ export const useChatStore = defineStore(
|
||||
|
||||
// 初始化状态
|
||||
importProgress.value = {
|
||||
stage: 'reading',
|
||||
stage: 'detecting',
|
||||
progress: 0,
|
||||
message: '',
|
||||
message: '准备导入...',
|
||||
}
|
||||
|
||||
// 进度队列控制
|
||||
|
||||
+6
-1
@@ -355,9 +355,13 @@ export interface MemberNameHistory {
|
||||
* 导入进度回调
|
||||
*/
|
||||
export interface ImportProgress {
|
||||
stage: 'reading' | 'parsing' | 'saving' | 'done' | 'error'
|
||||
stage: 'detecting' | 'reading' | 'parsing' | 'saving' | 'done' | 'error'
|
||||
progress: number // 0-100
|
||||
message?: string
|
||||
// 流式解析额外字段
|
||||
bytesRead?: number
|
||||
totalBytes?: number
|
||||
messagesProcessed?: number
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -756,6 +760,7 @@ export interface FileParseInfo {
|
||||
platform: string // 平台
|
||||
messageCount: number // 消息数量
|
||||
memberCount: number // 成员数量
|
||||
fileSize?: number // 文件大小(字节)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user