mirror of
https://github.com/hicccc77/WeFlow.git
synced 2026-03-25 07:16:51 +00:00
计划优化 P5/5
This commit is contained in:
@@ -3713,6 +3713,36 @@
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.batch-task-switch {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
.batch-task-btn {
|
||||
border: 1px solid var(--border-color);
|
||||
background: var(--bg-secondary);
|
||||
color: var(--text-secondary);
|
||||
border-radius: 8px;
|
||||
padding: 0.55rem 0.75rem;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
border-color: color-mix(in srgb, var(--primary) 50%, var(--border-color));
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
&.active {
|
||||
border-color: var(--primary);
|
||||
color: var(--primary);
|
||||
background: color-mix(in srgb, var(--primary) 10%, var(--bg-primary));
|
||||
box-shadow: 0 0 0 1px color-mix(in srgb, var(--primary) 25%, transparent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.batch-dates-list-wrap {
|
||||
margin-bottom: 1rem;
|
||||
background: var(--bg-tertiary);
|
||||
|
||||
@@ -5,7 +5,7 @@ import { createPortal } from 'react-dom'
|
||||
import { Virtuoso, type VirtuosoHandle } from 'react-virtuoso'
|
||||
import { useShallow } from 'zustand/react/shallow'
|
||||
import { useChatStore } from '../stores/chatStore'
|
||||
import { useBatchTranscribeStore } from '../stores/batchTranscribeStore'
|
||||
import { useBatchTranscribeStore, type BatchVoiceTaskType } from '../stores/batchTranscribeStore'
|
||||
import { useBatchImageDecryptStore } from '../stores/batchImageDecryptStore'
|
||||
import type { ChatSession, Message } from '../types/models'
|
||||
import { getEmojiPath } from 'wechat-emojis'
|
||||
@@ -855,6 +855,7 @@ function ChatPage(props: ChatPageProps) {
|
||||
const visibleMessageRangeRef = useRef<{ startIndex: number; endIndex: number }>({ startIndex: 0, endIndex: 0 })
|
||||
const topRangeLoadLockRef = useRef(false)
|
||||
const bottomRangeLoadLockRef = useRef(false)
|
||||
const suppressAutoLoadLaterRef = useRef(false)
|
||||
const searchInputRef = useRef<HTMLInputElement>(null)
|
||||
const sidebarRef = useRef<HTMLDivElement>(null)
|
||||
const handleMessageListScrollParentRef = useCallback((node: HTMLDivElement | null) => {
|
||||
@@ -939,6 +940,7 @@ function ChatPage(props: ChatPageProps) {
|
||||
// 批量语音转文字相关状态(进度/结果 由全局 store 管理)
|
||||
const {
|
||||
isBatchTranscribing,
|
||||
runningBatchVoiceTaskType,
|
||||
batchTranscribeProgress,
|
||||
startTranscribe,
|
||||
updateProgress,
|
||||
@@ -946,6 +948,7 @@ function ChatPage(props: ChatPageProps) {
|
||||
setShowBatchProgress
|
||||
} = useBatchTranscribeStore(useShallow((state) => ({
|
||||
isBatchTranscribing: state.isBatchTranscribing,
|
||||
runningBatchVoiceTaskType: state.taskType,
|
||||
batchTranscribeProgress: state.progress,
|
||||
startTranscribe: state.startTranscribe,
|
||||
updateProgress: state.updateProgress,
|
||||
@@ -972,6 +975,7 @@ function ChatPage(props: ChatPageProps) {
|
||||
const [batchVoiceMessages, setBatchVoiceMessages] = useState<Message[] | null>(null)
|
||||
const [batchVoiceDates, setBatchVoiceDates] = useState<string[]>([])
|
||||
const [batchSelectedDates, setBatchSelectedDates] = useState<Set<string>>(new Set())
|
||||
const [batchVoiceTaskType, setBatchVoiceTaskType] = useState<BatchVoiceTaskType>('transcribe')
|
||||
const [showBatchDecryptConfirm, setShowBatchDecryptConfirm] = useState(false)
|
||||
const [batchImageMessages, setBatchImageMessages] = useState<BatchImageDecryptCandidate[] | null>(null)
|
||||
const [batchImageDates, setBatchImageDates] = useState<string[]>([])
|
||||
@@ -4054,6 +4058,7 @@ function ChatPage(props: ChatPageProps) {
|
||||
if (
|
||||
range.endIndex >= total - 3 &&
|
||||
!bottomRangeLoadLockRef.current &&
|
||||
!suppressAutoLoadLaterRef.current &&
|
||||
!isLoadingMore &&
|
||||
!isLoadingMessages &&
|
||||
hasMoreLater &&
|
||||
@@ -4122,6 +4127,8 @@ function ChatPage(props: ChatPageProps) {
|
||||
|
||||
if (!effectiveAtBottom) {
|
||||
bottomRangeLoadLockRef.current = false
|
||||
// 用户主动离开底部后,解除“搜索跳转后的自动向后加载抑制”
|
||||
suppressAutoLoadLaterRef.current = false
|
||||
}
|
||||
|
||||
if (
|
||||
@@ -4142,6 +4149,21 @@ function ChatPage(props: ChatPageProps) {
|
||||
setShowScrollToBottom(prev => (prev === shouldShow ? prev : shouldShow))
|
||||
}, [messages.length, isLoadingMessages, isLoadingMore, isSessionSwitching])
|
||||
|
||||
const handleMessageListWheel = useCallback((event: React.WheelEvent<HTMLDivElement>) => {
|
||||
if (event.deltaY <= 18) return
|
||||
if (!currentSessionId || isLoadingMore || isLoadingMessages || !hasMoreLater) return
|
||||
const listEl = messageListRef.current
|
||||
if (!listEl) return
|
||||
const distanceFromBottom = listEl.scrollHeight - (listEl.scrollTop + listEl.clientHeight)
|
||||
if (distanceFromBottom > 96) return
|
||||
if (bottomRangeLoadLockRef.current) return
|
||||
|
||||
// 用户明确向下滚动时允许加载后续消息
|
||||
suppressAutoLoadLaterRef.current = false
|
||||
bottomRangeLoadLockRef.current = true
|
||||
void loadLaterMessages()
|
||||
}, [currentSessionId, hasMoreLater, isLoadingMessages, isLoadingMore, loadLaterMessages])
|
||||
|
||||
const handleMessageAtTopStateChange = useCallback((atTop: boolean) => {
|
||||
if (!atTop) {
|
||||
topRangeLoadLockRef.current = false
|
||||
@@ -4213,6 +4235,8 @@ function ChatPage(props: ChatPageProps) {
|
||||
setCurrentOffset(0)
|
||||
setJumpStartTime(0)
|
||||
setJumpEndTime(anchorEndTime)
|
||||
// 搜索跳转后默认不自动回流到最新消息,仅在用户主动向下滚动时加载后续
|
||||
suppressAutoLoadLaterRef.current = true
|
||||
flashNewMessages([targetMessageKey])
|
||||
void loadMessages(targetSessionId, 0, 0, anchorEndTime, false, {
|
||||
inSessionJumpRequestSeq: requestSeq
|
||||
@@ -5015,6 +5039,7 @@ function ChatPage(props: ChatPageProps) {
|
||||
setBatchVoiceCount(voiceMessages.length)
|
||||
setBatchVoiceDates(sortedDates)
|
||||
setBatchSelectedDates(new Set(sortedDates))
|
||||
setBatchVoiceTaskType('transcribe')
|
||||
setShowBatchConfirm(true)
|
||||
}, [sessions, currentSessionId, isBatchTranscribing])
|
||||
|
||||
@@ -5078,7 +5103,7 @@ function ChatPage(props: ChatPageProps) {
|
||||
})
|
||||
}, [currentSessionId, navigate, isGroupChatSession])
|
||||
|
||||
// 确认批量转写
|
||||
// 确认批量语音任务(解密/转写)
|
||||
const confirmBatchTranscribe = useCallback(async () => {
|
||||
if (!currentSessionId) return
|
||||
|
||||
@@ -5110,23 +5135,35 @@ function ChatPage(props: ChatPageProps) {
|
||||
const session = sessions.find(s => s.username === currentSessionId)
|
||||
if (!session) return
|
||||
|
||||
startTranscribe(voiceMessages.length, session.displayName || session.username)
|
||||
const taskType = batchVoiceTaskType
|
||||
startTranscribe(voiceMessages.length, session.displayName || session.username, taskType)
|
||||
|
||||
// 检查模型状态
|
||||
const modelStatus = await window.electronAPI.whisper.getModelStatus()
|
||||
if (!modelStatus?.exists) {
|
||||
alert('SenseVoice 模型未下载,请先在设置中下载模型')
|
||||
finishTranscribe(0, 0)
|
||||
return
|
||||
if (taskType === 'transcribe') {
|
||||
// 检查模型状态
|
||||
const modelStatus = await window.electronAPI.whisper.getModelStatus()
|
||||
if (!modelStatus?.exists) {
|
||||
alert('SenseVoice 模型未下载,请先在设置中下载模型')
|
||||
finishTranscribe(0, 0)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
let successCount = 0
|
||||
let failCount = 0
|
||||
let completedCount = 0
|
||||
const concurrency = 10
|
||||
const concurrency = taskType === 'decrypt' ? 12 : 10
|
||||
|
||||
const transcribeOne = async (msg: Message) => {
|
||||
const runOne = async (msg: Message) => {
|
||||
try {
|
||||
if (taskType === 'decrypt') {
|
||||
const result = await window.electronAPI.chat.getVoiceData(
|
||||
session.username,
|
||||
String(msg.localId),
|
||||
msg.createTime,
|
||||
msg.serverIdRaw || msg.serverId
|
||||
)
|
||||
return { success: Boolean(result.success && result.data) }
|
||||
}
|
||||
const result = await window.electronAPI.chat.getVoiceTranscript(
|
||||
session.username,
|
||||
String(msg.localId),
|
||||
@@ -5140,7 +5177,7 @@ function ChatPage(props: ChatPageProps) {
|
||||
|
||||
for (let i = 0; i < voiceMessages.length; i += concurrency) {
|
||||
const batch = voiceMessages.slice(i, i + concurrency)
|
||||
const results = await Promise.all(batch.map(msg => transcribeOne(msg)))
|
||||
const results = await Promise.all(batch.map(msg => runOne(msg)))
|
||||
|
||||
results.forEach(result => {
|
||||
if (result.success) successCount++
|
||||
@@ -5151,7 +5188,7 @@ function ChatPage(props: ChatPageProps) {
|
||||
}
|
||||
|
||||
finishTranscribe(successCount, failCount)
|
||||
}, [sessions, currentSessionId, batchSelectedDates, batchVoiceMessages, startTranscribe, updateProgress, finishTranscribe])
|
||||
}, [sessions, currentSessionId, batchSelectedDates, batchVoiceMessages, batchVoiceTaskType, startTranscribe, updateProgress, finishTranscribe])
|
||||
|
||||
// 批量转写:按日期的消息数量
|
||||
const batchCountByDate = useMemo(() => {
|
||||
@@ -5172,6 +5209,12 @@ function ChatPage(props: ChatPageProps) {
|
||||
).length
|
||||
}, [batchVoiceMessages, batchSelectedDates])
|
||||
|
||||
const batchVoiceTaskTitle = batchVoiceTaskType === 'decrypt' ? '批量解密语音' : '批量语音转文字'
|
||||
const batchVoiceTaskVerb = batchVoiceTaskType === 'decrypt' ? '解密' : '转写'
|
||||
const batchVoiceTaskMinutes = Math.ceil(
|
||||
batchSelectedMessageCount * (batchVoiceTaskType === 'decrypt' ? 0.6 : 2) / 60
|
||||
)
|
||||
|
||||
const toggleBatchDate = useCallback((date: string) => {
|
||||
setBatchSelectedDates(prev => {
|
||||
const next = new Set(prev)
|
||||
@@ -5965,7 +6008,9 @@ function ChatPage(props: ChatPageProps) {
|
||||
}
|
||||
}}
|
||||
disabled={!currentSessionId}
|
||||
title={isBatchTranscribing ? `批量转写中 (${batchTranscribeProgress.current}/${batchTranscribeProgress.total}),点击查看进度` : '批量语音转文字'}
|
||||
title={isBatchTranscribing
|
||||
? `${runningBatchVoiceTaskType === 'decrypt' ? '批量语音解密' : '批量转写'}中 (${batchTranscribeProgress.current}/${batchTranscribeProgress.total}),点击查看进度`
|
||||
: '批量语音处理(解密/转文字)'}
|
||||
>
|
||||
{isBatchTranscribing ? (
|
||||
<Loader2 size={18} className="spin" />
|
||||
@@ -6176,6 +6221,7 @@ function ChatPage(props: ChatPageProps) {
|
||||
<div
|
||||
className={`message-list ${hasInitialMessages ? 'loaded' : 'loading'}`}
|
||||
ref={handleMessageListScrollParentRef}
|
||||
onWheel={handleMessageListWheel}
|
||||
>
|
||||
{!isLoadingMessages && messages.length === 0 && !hasMoreMessages ? (
|
||||
<div className="empty-chat-inline">
|
||||
@@ -6583,10 +6629,26 @@ function ChatPage(props: ChatPageProps) {
|
||||
<div className="batch-modal-content batch-confirm-modal" onClick={(e) => e.stopPropagation()}>
|
||||
<div className="batch-modal-header">
|
||||
<Mic size={20} />
|
||||
<h3>批量语音转文字</h3>
|
||||
<h3>{batchVoiceTaskTitle}</h3>
|
||||
</div>
|
||||
<div className="batch-modal-body">
|
||||
<p>选择要转写的日期(仅显示有语音的日期),然后开始转写。</p>
|
||||
<p>先选择任务类型,再选择日期(仅显示有语音的日期),然后开始处理。</p>
|
||||
<div className="batch-task-switch" role="tablist" aria-label="语音批量任务类型">
|
||||
<button
|
||||
type="button"
|
||||
className={`batch-task-btn${batchVoiceTaskType === 'decrypt' ? ' active' : ''}`}
|
||||
onClick={() => setBatchVoiceTaskType('decrypt')}
|
||||
>
|
||||
批量解密语音
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`batch-task-btn${batchVoiceTaskType === 'transcribe' ? ' active' : ''}`}
|
||||
onClick={() => setBatchVoiceTaskType('transcribe')}
|
||||
>
|
||||
批量转文字
|
||||
</button>
|
||||
</div>
|
||||
{batchVoiceDates.length > 0 && (
|
||||
<div className="batch-dates-list-wrap">
|
||||
<div className="batch-dates-actions">
|
||||
@@ -6621,12 +6683,16 @@ function ChatPage(props: ChatPageProps) {
|
||||
</div>
|
||||
<div className="info-item">
|
||||
<span className="label">预计耗时:</span>
|
||||
<span className="value">约 {Math.ceil(batchSelectedMessageCount * 2 / 60)} 分钟</span>
|
||||
<span className="value">约 {batchVoiceTaskMinutes} 分钟</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="batch-warning">
|
||||
<AlertCircle size={16} />
|
||||
<span>批量转写可能需要较长时间,转写过程中可以继续使用其他功能。已转写过的语音会自动跳过。</span>
|
||||
<span>
|
||||
{batchVoiceTaskType === 'decrypt'
|
||||
? '批量解密会预先缓存语音数据,之后播放和转写会更快。解密过程中可以继续使用其他功能。'
|
||||
: '批量转写可能需要较长时间,转写过程中可以继续使用其他功能。已转写过的语音会自动跳过。'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="batch-modal-footer">
|
||||
@@ -6635,7 +6701,7 @@ function ChatPage(props: ChatPageProps) {
|
||||
</button>
|
||||
<button className="btn-primary batch-transcribe-start-btn" onClick={confirmBatchTranscribe}>
|
||||
<Mic size={16} />
|
||||
开始转写
|
||||
开始{batchVoiceTaskVerb}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -109,6 +109,12 @@ interface TaskProgress {
|
||||
estimatedTotalMessages: number
|
||||
collectedMessages: number
|
||||
writtenFiles: number
|
||||
mediaDoneFiles: number
|
||||
mediaCacheHitFiles: number
|
||||
mediaCacheMissFiles: number
|
||||
mediaCacheFillFiles: number
|
||||
mediaDedupReuseFiles: number
|
||||
mediaBytesWritten: number
|
||||
}
|
||||
|
||||
type TaskPerfStage = 'collect' | 'build' | 'write' | 'other'
|
||||
@@ -263,7 +269,13 @@ const createEmptyProgress = (): TaskProgress => ({
|
||||
exportedMessages: 0,
|
||||
estimatedTotalMessages: 0,
|
||||
collectedMessages: 0,
|
||||
writtenFiles: 0
|
||||
writtenFiles: 0,
|
||||
mediaDoneFiles: 0,
|
||||
mediaCacheHitFiles: 0,
|
||||
mediaCacheMissFiles: 0,
|
||||
mediaCacheFillFiles: 0,
|
||||
mediaDedupReuseFiles: 0,
|
||||
mediaBytesWritten: 0
|
||||
})
|
||||
|
||||
const createEmptyTaskPerformance = (): TaskPerformance => ({
|
||||
@@ -1302,6 +1314,17 @@ const TaskCenterModal = memo(function TaskCenterModal({
|
||||
: `已收集 ${collectedMessages.toLocaleString()} 条`
|
||||
const phaseProgress = Math.max(0, Math.floor(task.progress.phaseProgress || 0))
|
||||
const phaseTotal = Math.max(0, Math.floor(task.progress.phaseTotal || 0))
|
||||
const mediaDoneFiles = Math.max(0, Math.floor(task.progress.mediaDoneFiles || 0))
|
||||
const mediaCacheHitFiles = Math.max(0, Math.floor(task.progress.mediaCacheHitFiles || 0))
|
||||
const mediaCacheMissFiles = Math.max(0, Math.floor(task.progress.mediaCacheMissFiles || 0))
|
||||
const mediaDedupReuseFiles = Math.max(0, Math.floor(task.progress.mediaDedupReuseFiles || 0))
|
||||
const mediaCacheTotal = mediaCacheHitFiles + mediaCacheMissFiles
|
||||
const mediaCacheMetricLabel = mediaCacheTotal > 0
|
||||
? `缓存命中 ${mediaCacheHitFiles}/${mediaCacheTotal}`
|
||||
: ''
|
||||
const mediaDedupMetricLabel = mediaDedupReuseFiles > 0
|
||||
? `复用 ${mediaDedupReuseFiles}`
|
||||
: ''
|
||||
const phaseMetricLabel = phaseTotal > 0
|
||||
? (
|
||||
task.progress.phase === 'exporting-media'
|
||||
@@ -1311,6 +1334,9 @@ const TaskCenterModal = memo(function TaskCenterModal({
|
||||
: ''
|
||||
)
|
||||
: ''
|
||||
const mediaLiveMetricLabel = task.progress.phase === 'exporting-media'
|
||||
? (mediaDoneFiles > 0 ? `已处理 ${mediaDoneFiles}` : '')
|
||||
: ''
|
||||
const sessionProgressLabel = completedSessionTotal > 0
|
||||
? `会话 ${completedSessionCount}/${completedSessionTotal}`
|
||||
: '会话处理中'
|
||||
@@ -1336,6 +1362,9 @@ const TaskCenterModal = memo(function TaskCenterModal({
|
||||
<div className="task-progress-text">
|
||||
{`${sessionProgressLabel} · ${effectiveMessageProgressLabel}`}
|
||||
{phaseMetricLabel ? ` · ${phaseMetricLabel}` : ''}
|
||||
{mediaLiveMetricLabel ? ` · ${mediaLiveMetricLabel}` : ''}
|
||||
{mediaCacheMetricLabel ? ` · ${mediaCacheMetricLabel}` : ''}
|
||||
{mediaDedupMetricLabel ? ` · ${mediaDedupMetricLabel}` : ''}
|
||||
{task.status === 'running' && currentSessionRatio !== null
|
||||
? `(当前会话 ${Math.round(currentSessionRatio * 100)}%)`
|
||||
: ''}
|
||||
@@ -4280,6 +4309,42 @@ function ExportPage() {
|
||||
const writtenFiles = Number.isFinite(payload.writtenFiles)
|
||||
? Math.max(task.progress.writtenFiles, Math.max(0, Math.floor(Number(payload.writtenFiles || 0))))
|
||||
: task.progress.writtenFiles
|
||||
const prevMediaDoneFiles = Number.isFinite(task.progress.mediaDoneFiles)
|
||||
? Math.max(0, Math.floor(Number(task.progress.mediaDoneFiles || 0)))
|
||||
: 0
|
||||
const prevMediaCacheHitFiles = Number.isFinite(task.progress.mediaCacheHitFiles)
|
||||
? Math.max(0, Math.floor(Number(task.progress.mediaCacheHitFiles || 0)))
|
||||
: 0
|
||||
const prevMediaCacheMissFiles = Number.isFinite(task.progress.mediaCacheMissFiles)
|
||||
? Math.max(0, Math.floor(Number(task.progress.mediaCacheMissFiles || 0)))
|
||||
: 0
|
||||
const prevMediaCacheFillFiles = Number.isFinite(task.progress.mediaCacheFillFiles)
|
||||
? Math.max(0, Math.floor(Number(task.progress.mediaCacheFillFiles || 0)))
|
||||
: 0
|
||||
const prevMediaDedupReuseFiles = Number.isFinite(task.progress.mediaDedupReuseFiles)
|
||||
? Math.max(0, Math.floor(Number(task.progress.mediaDedupReuseFiles || 0)))
|
||||
: 0
|
||||
const prevMediaBytesWritten = Number.isFinite(task.progress.mediaBytesWritten)
|
||||
? Math.max(0, Math.floor(Number(task.progress.mediaBytesWritten || 0)))
|
||||
: 0
|
||||
const mediaDoneFiles = Number.isFinite(payload.mediaDoneFiles)
|
||||
? Math.max(prevMediaDoneFiles, Math.max(0, Math.floor(Number(payload.mediaDoneFiles || 0))))
|
||||
: prevMediaDoneFiles
|
||||
const mediaCacheHitFiles = Number.isFinite(payload.mediaCacheHitFiles)
|
||||
? Math.max(prevMediaCacheHitFiles, Math.max(0, Math.floor(Number(payload.mediaCacheHitFiles || 0))))
|
||||
: prevMediaCacheHitFiles
|
||||
const mediaCacheMissFiles = Number.isFinite(payload.mediaCacheMissFiles)
|
||||
? Math.max(prevMediaCacheMissFiles, Math.max(0, Math.floor(Number(payload.mediaCacheMissFiles || 0))))
|
||||
: prevMediaCacheMissFiles
|
||||
const mediaCacheFillFiles = Number.isFinite(payload.mediaCacheFillFiles)
|
||||
? Math.max(prevMediaCacheFillFiles, Math.max(0, Math.floor(Number(payload.mediaCacheFillFiles || 0))))
|
||||
: prevMediaCacheFillFiles
|
||||
const mediaDedupReuseFiles = Number.isFinite(payload.mediaDedupReuseFiles)
|
||||
? Math.max(prevMediaDedupReuseFiles, Math.max(0, Math.floor(Number(payload.mediaDedupReuseFiles || 0))))
|
||||
: prevMediaDedupReuseFiles
|
||||
const mediaBytesWritten = Number.isFinite(payload.mediaBytesWritten)
|
||||
? Math.max(prevMediaBytesWritten, Math.max(0, Math.floor(Number(payload.mediaBytesWritten || 0))))
|
||||
: prevMediaBytesWritten
|
||||
return {
|
||||
...task,
|
||||
progress: {
|
||||
@@ -4295,7 +4360,13 @@ function ExportPage() {
|
||||
? Math.max(task.progress.estimatedTotalMessages, aggregatedMessageProgress.estimated)
|
||||
: (task.progress.estimatedTotalMessages > 0 ? task.progress.estimatedTotalMessages : 0),
|
||||
collectedMessages: Math.max(task.progress.collectedMessages, collectedMessages),
|
||||
writtenFiles
|
||||
writtenFiles,
|
||||
mediaDoneFiles,
|
||||
mediaCacheHitFiles,
|
||||
mediaCacheMissFiles,
|
||||
mediaCacheFillFiles,
|
||||
mediaDedupReuseFiles,
|
||||
mediaBytesWritten
|
||||
},
|
||||
settledSessionIds: nextSettledSessionIds,
|
||||
performance
|
||||
@@ -4336,7 +4407,13 @@ function ExportPage() {
|
||||
exportedMessages: payload.total > 0 ? Math.max(0, Math.floor(payload.current || 0)) : task.progress.exportedMessages,
|
||||
estimatedTotalMessages: payload.total > 0 ? Math.max(0, Math.floor(payload.total || 0)) : task.progress.estimatedTotalMessages,
|
||||
collectedMessages: task.progress.collectedMessages,
|
||||
writtenFiles: task.progress.writtenFiles
|
||||
writtenFiles: task.progress.writtenFiles,
|
||||
mediaDoneFiles: task.progress.mediaDoneFiles,
|
||||
mediaCacheHitFiles: task.progress.mediaCacheHitFiles,
|
||||
mediaCacheMissFiles: task.progress.mediaCacheMissFiles,
|
||||
mediaCacheFillFiles: task.progress.mediaCacheFillFiles,
|
||||
mediaDedupReuseFiles: task.progress.mediaDedupReuseFiles,
|
||||
mediaBytesWritten: task.progress.mediaBytesWritten
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user