diff --git a/backend/internal/handler/generate.go b/backend/internal/handler/generate.go index 7994a52..b5fb767 100755 --- a/backend/internal/handler/generate.go +++ b/backend/internal/handler/generate.go @@ -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) diff --git a/frontend/src/components/PipelineStages.tsx b/frontend/src/components/PipelineStages.tsx new file mode 100644 index 0000000..1fc166d --- /dev/null +++ b/frontend/src/components/PipelineStages.tsx @@ -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 ( +
+ {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 ( +
+ + {stage.label} + + {index < STAGES.length - 1 && ( + + → + + )} +
+ ) + })} +
+ ) +} diff --git a/frontend/src/components/TaskListPanel.tsx b/frontend/src/components/TaskListPanel.tsx index 32347fe..61f55f4 100644 --- a/frontend/src/components/TaskListPanel.tsx +++ b/frontend/src/components/TaskListPanel.tsx @@ -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 = { @@ -103,9 +104,17 @@ export default function TaskListPanel() { > {task.prompt}

- - {formatRelativeTime(task.createdAt)} - +
+ + {formatRelativeTime(task.createdAt)} + + {task.progress !== undefined && task.status === 'running' && ( + + {task.progress}% + + )} +
+ )) )}