!63 feat: 添加管线阶段可视化展示并改进任务日志
Merge pull request !63 from 何朝晖/fix/task-running
This commit is contained in:
@@ -74,9 +74,11 @@ func Generate(c *gin.Context) {
|
||||
// runPipelineBg 后台执行生成管线,更新任务状态。
|
||||
func runPipelineBg(ctx context.Context, projectID, taskID string, req GenerateRequest) {
|
||||
l := logger.With("task_id", taskID, "project_id", projectID)
|
||||
l.Info("task started", "asset_type", req.AssetType, "prompt", req.Prompt)
|
||||
|
||||
// 注入进度上报回调
|
||||
ctx = service.WithProgressReporter(ctx, func(stage string, progress int) {
|
||||
l.Info("progress update", "stage", stage, "progress", progress)
|
||||
updateTaskInDB(ctx, taskID, "running", stage, "", progress)
|
||||
})
|
||||
|
||||
@@ -101,12 +103,14 @@ func runPipelineBg(ctx context.Context, projectID, taskID string, req GenerateRe
|
||||
},
|
||||
}
|
||||
|
||||
l.Info("calling pipeline", "input_tags", in.Tags, "user_note", in.UserNote)
|
||||
output, err := service.RunPipeline(ctx, in)
|
||||
if err != nil {
|
||||
l.Error("task pipeline failed", "error", err)
|
||||
updateTaskInDB(ctx, taskID, "failed", "", err.Error(), 0)
|
||||
return
|
||||
}
|
||||
l.Info("pipeline completed", "asset_count", len(output.Assets))
|
||||
|
||||
updateTaskInDB(ctx, taskID, "saving", "format_adapter", "", 90)
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
const STAGES = [
|
||||
{ key: 'prompt_builder', label: '提示词' },
|
||||
{ key: 'asset_generator', label: '生成中' },
|
||||
{ key: 'quality_supervisor', label: '质检中' },
|
||||
{ key: 'format_adapter', label: '格式转换' },
|
||||
] as const
|
||||
|
||||
type Stage = typeof STAGES[number]['key']
|
||||
|
||||
interface PipelineStagesProps {
|
||||
currentStage: Stage | null
|
||||
status: string
|
||||
}
|
||||
|
||||
export default function PipelineStages({ currentStage, status }: PipelineStagesProps) {
|
||||
if (!currentStage || status !== 'running') {
|
||||
return null
|
||||
}
|
||||
|
||||
const currentIndex = STAGES.findIndex(s => s.key === currentStage)
|
||||
|
||||
return (
|
||||
<div style={{ marginTop: 8, display: 'flex', alignItems: 'center', gap: 4 }}>
|
||||
{STAGES.map((stage, index) => {
|
||||
let bgColor: string
|
||||
let textColor: string
|
||||
|
||||
if (index < currentIndex) {
|
||||
bgColor = 'rgba(74, 222, 128, 0.15)'
|
||||
textColor = '#4ade80'
|
||||
} else if (index === currentIndex) {
|
||||
bgColor = 'rgba(251, 146, 60, 0.15)'
|
||||
textColor = '#fb923c'
|
||||
} else {
|
||||
bgColor = 'rgba(156, 163, 175, 0.1)'
|
||||
textColor = '#9ca3af'
|
||||
}
|
||||
|
||||
return (
|
||||
<div key={stage.key} style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<span
|
||||
style={{
|
||||
padding: '4px 8px',
|
||||
borderRadius: 6,
|
||||
fontSize: 11,
|
||||
fontWeight: 500,
|
||||
backgroundColor: bgColor,
|
||||
color: textColor,
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
{stage.label}
|
||||
</span>
|
||||
{index < STAGES.length - 1 && (
|
||||
<span
|
||||
style={{
|
||||
marginLeft: 4,
|
||||
marginRight: 4,
|
||||
fontSize: 12,
|
||||
color: '#9ca3af',
|
||||
}}
|
||||
>
|
||||
→
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { useParams } from 'react-router-dom'
|
||||
import { getTasks } from '../api/project'
|
||||
import type { Task } from '../api/types'
|
||||
import StatusBadge from './StatusBadge'
|
||||
import PipelineStages from './PipelineStages'
|
||||
import Skeleton from './Skeleton'
|
||||
|
||||
const ASSET_TYPE_LABELS: Record<string, string> = {
|
||||
@@ -103,9 +104,17 @@ export default function TaskListPanel() {
|
||||
>
|
||||
{task.prompt}
|
||||
</p>
|
||||
<span style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 4, display: 'block' }}>
|
||||
{formatRelativeTime(task.createdAt)}
|
||||
</span>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginTop: 4 }}>
|
||||
<span style={{ fontSize: 11, color: 'var(--text-muted)' }}>
|
||||
{formatRelativeTime(task.createdAt)}
|
||||
</span>
|
||||
{task.progress !== undefined && task.status === 'running' && (
|
||||
<span style={{ fontSize: 11, color: 'var(--text-muted)' }}>
|
||||
{task.progress}%
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<PipelineStages currentStage={task.stage ?? null} status={task.status} />
|
||||
</a>
|
||||
))
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user