开屏页面细节增加;聊天页面批量解密/专业补充进度徽章并可在导出页面任务列表查询具体进度
This commit is contained in:
1 parent
301cb5abce
commit
82bce9f784
7 files changed
+229
-18
No files matched your search
@@ -120,6 +120,7 @@ function ExportPage() {
|
||||
resumeTask: resumeBgTask,
|
||||
cancelTask: cancelBgTask
|
||||
} = useBackgroundTasks()
|
||||
const taskCenterBackgroundTasks = backgroundTasks.filter(task => task.sourcePage === 'export' || task.sourcePage === 'chat')
|
||||
|
||||
// ── 4. Dialog & Exports ──
|
||||
const { dialogState, openDialog, closeDialog } = useExportDialog()
|
||||
@@ -286,13 +287,13 @@ function ExportPage() {
|
||||
/>
|
||||
</section>
|
||||
|
||||
{(exportTasks.length > 0 || backgroundTasks.filter(t => t.sourcePage === 'export').length > 0) && (
|
||||
{(exportTasks.length > 0 || taskCenterBackgroundTasks.length > 0) && (
|
||||
<section className="export-v2-task-panel">
|
||||
<TaskCenter
|
||||
exportTasks={exportTasks}
|
||||
onCancelExportTask={cancelExportTask}
|
||||
onClearCompletedExportTasks={clearCompletedExportTasks}
|
||||
backgroundTasks={backgroundTasks.filter(t => t.sourcePage === 'export')}
|
||||
backgroundTasks={taskCenterBackgroundTasks}
|
||||
onPauseBackgroundTask={pauseBgTask}
|
||||
onResumeBackgroundTask={resumeBgTask}
|
||||
onCancelBackgroundTask={cancelBgTask}
|
||||
|
||||
@@ -87,6 +87,20 @@
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--text-primary);
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.task-source-badge {
|
||||
flex-shrink: 0;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
background: color-mix(in srgb, var(--border-color) 55%, transparent);
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
.task-status-badge {
|
||||
@@ -164,11 +178,23 @@
|
||||
.progress-stats {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 11px;
|
||||
color: var(--text-secondary);
|
||||
white-space: nowrap;
|
||||
min-width: 80px;
|
||||
justify-content: flex-end;
|
||||
|
||||
.phase {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.count {
|
||||
flex-shrink: 0;
|
||||
white-space: nowrap;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,6 +237,38 @@
|
||||
background: #ef4444;
|
||||
}
|
||||
}
|
||||
|
||||
&.status-completed {
|
||||
border-color: color-mix(in srgb, #10b981 30%, var(--border-color));
|
||||
.task-status-badge {
|
||||
background: color-mix(in srgb, #10b981 15%, transparent);
|
||||
color: #10b981;
|
||||
}
|
||||
.progress-bar-fill {
|
||||
background: #10b981;
|
||||
}
|
||||
}
|
||||
|
||||
&.status-failed,
|
||||
&.status-canceled {
|
||||
border-color: color-mix(in srgb, #ef4444 30%, var(--border-color));
|
||||
.task-status-badge {
|
||||
background: color-mix(in srgb, #ef4444 15%, transparent);
|
||||
color: #ef4444;
|
||||
}
|
||||
.progress-bar-fill {
|
||||
background: #ef4444;
|
||||
}
|
||||
}
|
||||
|
||||
&.status-pause_requested,
|
||||
&.status-paused,
|
||||
&.status-cancel_requested {
|
||||
.task-status-badge {
|
||||
background: color-mix(in srgb, #f59e0b 15%, transparent);
|
||||
color: #d97706;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bg-tasks-section {
|
||||
@@ -229,9 +287,20 @@
|
||||
}
|
||||
|
||||
.bg-task {
|
||||
.task-progress-text {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
.task-info {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.bg-progress-area {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 6px;
|
||||
|
||||
.progress-stats {
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
backgroundTaskSourceLabels,
|
||||
backgroundTaskStatusLabels
|
||||
} from '../../constants'
|
||||
import { formatDurationMs } from '../../utils/format'
|
||||
import './TaskCenter.scss'
|
||||
|
||||
interface TaskCenterProps {
|
||||
@@ -20,6 +19,20 @@ interface TaskCenterProps {
|
||||
onCancelBackgroundTask: (taskId: string) => void
|
||||
}
|
||||
|
||||
const parseBackgroundTaskProgress = (progressText?: string): { current: number; total: number; percent: number } | null => {
|
||||
const match = String(progressText || '').match(/(\d[\d,]*)\s*\/\s*(\d[\d,]*)/)
|
||||
if (!match) return null
|
||||
const current = Number(match[1].replace(/,/g, ''))
|
||||
const total = Number(match[2].replace(/,/g, ''))
|
||||
if (!Number.isFinite(current) || !Number.isFinite(total) || total <= 0) return null
|
||||
const safeCurrent = Math.max(0, Math.min(current, total))
|
||||
return {
|
||||
current: safeCurrent,
|
||||
total,
|
||||
percent: Math.max(0, Math.min(100, Math.round((safeCurrent / total) * 100)))
|
||||
}
|
||||
}
|
||||
|
||||
const TaskCenter: React.FC<TaskCenterProps> = ({
|
||||
exportTasks,
|
||||
onCancelExportTask,
|
||||
@@ -104,13 +117,22 @@ const TaskCenter: React.FC<TaskCenterProps> = ({
|
||||
const isPausable = bgTask.status === 'running'
|
||||
const isResumable = bgTask.status === 'paused'
|
||||
const isCancelable = bgTask.status !== 'completed' && bgTask.status !== 'canceled' && bgTask.status !== 'failed'
|
||||
const progress = parseBackgroundTaskProgress(bgTask.progressText)
|
||||
const sourceLabel = backgroundTaskSourceLabels[bgTask.sourcePage] || '后台任务'
|
||||
|
||||
return (
|
||||
<div key={bgTask.id} className={`task-card bg-task status-${bgTask.status}`}>
|
||||
<div className="task-card-header">
|
||||
<div className="task-info">
|
||||
<span className="task-title">{backgroundTaskSourceLabels[bgTask.sourcePage] || '后台任务'}</span>
|
||||
<span className="task-status-badge">{backgroundTaskStatusLabels[bgTask.status]}</span>
|
||||
<span className="task-title">{bgTask.title || sourceLabel}</span>
|
||||
<span className="task-source-badge">{sourceLabel}</span>
|
||||
<span className="task-status-badge">
|
||||
{bgTask.status === 'running' && <Loader2 className="spin" size={12} />}
|
||||
{(bgTask.status === 'completed') && <CheckCircle2 size={12} />}
|
||||
{(bgTask.status === 'failed' || bgTask.status === 'canceled') && <XCircle size={12} />}
|
||||
{(bgTask.status === 'pause_requested' || bgTask.status === 'cancel_requested') && <Loader2 className="spin" size={12} />}
|
||||
{backgroundTaskStatusLabels[bgTask.status]}
|
||||
</span>
|
||||
</div>
|
||||
<div className="task-actions">
|
||||
{isPausable && (
|
||||
@@ -130,9 +152,20 @@ const TaskCenter: React.FC<TaskCenterProps> = ({
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{bgTask.progressText && (
|
||||
<div className="task-progress-text">
|
||||
{bgTask.progressText}
|
||||
{(bgTask.detail || bgTask.progressText) && (
|
||||
<div className="task-progress-area bg-progress-area">
|
||||
{progress && (
|
||||
<div className="progress-bar-bg">
|
||||
<div
|
||||
className="progress-bar-fill"
|
||||
style={{ width: `${progress.percent}%` }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="progress-stats">
|
||||
{bgTask.detail && <span className="phase">{bgTask.detail}</span>}
|
||||
{bgTask.progressText && <span className="count">{bgTask.progressText}</span>}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user