video-compliance-ai/frontend/lib/taskStageMapper.ts
Your Name 54eaa54966 feat: 前端全面对接后端 API(Phase 1 完成)
- 新增基础设施:useOSSUpload Hook、SSEContext Provider、taskStageMapper 工具
- 达人端4页面:任务列表/详情/脚本上传/视频上传对接真实 API
- 代理商端3页面:工作台/审核队列/审核详情对接真实 API
- 品牌方端4页面:项目列表/创建项目/项目详情/Brief配置对接真实 API
- 保留 USE_MOCK 开关,mock 模式下使用类型安全的 mock 数据
- 所有页面添加 loading 骨架屏、SSE 实时更新、错误处理

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 15:58:47 +08:00

187 lines
6.1 KiB
TypeScript

import type { TaskResponse, TaskStage, TaskStatus } from '@/types/task'
export type StepStatus = 'pending' | 'current' | 'done' | 'error'
export interface StageSteps {
submit: StepStatus
ai: StepStatus
agency: StepStatus
brand: StepStatus
}
export interface TaskUIState {
scriptStage: StageSteps
videoStage: StageSteps
currentPhase: 'script' | 'video' | 'completed'
buttonText: string
buttonType: 'primary' | 'warning' | 'success' | 'disabled'
scriptColor: string
videoColor: string
statusLabel: string
filterCategory: 'pending' | 'reviewing' | 'rejected' | 'completed'
}
const STAGE_ORDER: TaskStage[] = [
'script_upload', 'script_ai_review', 'script_agency_review', 'script_brand_review',
'video_upload', 'video_ai_review', 'video_agency_review', 'video_brand_review',
'completed', 'rejected',
]
function statusToStep(status: TaskStatus | undefined | null): StepStatus {
if (!status || status === 'pending') return 'pending'
if (status === 'processing') return 'current'
if (status === 'passed' || status === 'force_passed') return 'done'
if (status === 'rejected') return 'error'
return 'pending'
}
export function mapTaskToUI(task: TaskResponse): TaskUIState {
const stage = task.stage
const stageIndex = STAGE_ORDER.indexOf(stage)
// 脚本阶段
const scriptStage: StageSteps = {
submit: stageIndex >= 0 ? 'done' : 'pending',
ai: 'pending',
agency: 'pending',
brand: 'pending',
}
// 视频阶段
const videoStage: StageSteps = {
submit: 'pending',
ai: 'pending',
agency: 'pending',
brand: 'pending',
}
// 根据 stage 设置进度
if (stage === 'script_upload') {
scriptStage.submit = 'current'
} else if (stage === 'script_ai_review') {
scriptStage.submit = 'done'
scriptStage.ai = task.script_ai_result ? 'done' : 'current'
} else if (stage === 'script_agency_review') {
scriptStage.submit = 'done'
scriptStage.ai = 'done'
scriptStage.agency = statusToStep(task.script_agency_status)
if (scriptStage.agency === 'pending') scriptStage.agency = 'current'
} else if (stage === 'script_brand_review') {
scriptStage.submit = 'done'
scriptStage.ai = 'done'
scriptStage.agency = 'done'
scriptStage.brand = statusToStep(task.script_brand_status)
if (scriptStage.brand === 'pending') scriptStage.brand = 'current'
} else if (stageIndex >= 4) {
// 已过脚本阶段
scriptStage.submit = 'done'
scriptStage.ai = 'done'
scriptStage.agency = 'done'
scriptStage.brand = 'done'
}
// 处理脚本被驳回的情况
if (task.script_agency_status === 'rejected') {
scriptStage.agency = 'error'
}
if (task.script_brand_status === 'rejected') {
scriptStage.brand = 'error'
}
// 视频阶段
if (stage === 'video_upload') {
videoStage.submit = 'current'
} else if (stage === 'video_ai_review') {
videoStage.submit = 'done'
videoStage.ai = task.video_ai_result ? 'done' : 'current'
} else if (stage === 'video_agency_review') {
videoStage.submit = 'done'
videoStage.ai = 'done'
videoStage.agency = statusToStep(task.video_agency_status)
if (videoStage.agency === 'pending') videoStage.agency = 'current'
} else if (stage === 'video_brand_review') {
videoStage.submit = 'done'
videoStage.ai = 'done'
videoStage.agency = 'done'
videoStage.brand = statusToStep(task.video_brand_status)
if (videoStage.brand === 'pending') videoStage.brand = 'current'
} else if (stage === 'completed') {
videoStage.submit = 'done'
videoStage.ai = 'done'
videoStage.agency = 'done'
videoStage.brand = 'done'
}
// 处理视频被驳回的情况
if (task.video_agency_status === 'rejected') {
videoStage.agency = 'error'
}
if (task.video_brand_status === 'rejected') {
videoStage.brand = 'error'
}
// 当前阶段
let currentPhase: 'script' | 'video' | 'completed' = 'script'
if (stageIndex >= 4 && stageIndex < 8) currentPhase = 'video'
if (stage === 'completed') currentPhase = 'completed'
// 按钮文案和类型
let buttonText = '查看详情'
let buttonType: 'primary' | 'warning' | 'success' | 'disabled' = 'primary'
if (stage === 'script_upload') {
buttonText = '上传脚本'
buttonType = 'primary'
} else if (stage === 'video_upload') {
buttonText = '上传视频'
buttonType = 'primary'
} else if (stage === 'completed') {
buttonText = '已完成'
buttonType = 'success'
} else if (stage === 'rejected') {
buttonText = '重新提交'
buttonType = 'warning'
} else if (stage.includes('review')) {
buttonText = '审核中'
buttonType = 'disabled'
}
// 颜色
const scriptColor = scriptStage.agency === 'error' || scriptStage.brand === 'error'
? 'red' : scriptStage.brand === 'done' ? 'green' : 'blue'
const videoColor = videoStage.agency === 'error' || videoStage.brand === 'error'
? 'red' : videoStage.brand === 'done' ? 'green' : 'blue'
// 状态标签
let statusLabel = '进行中'
if (stage === 'script_upload' || stage === 'video_upload') statusLabel = '待上传'
else if (stage.includes('ai_review')) statusLabel = 'AI 审核中'
else if (stage.includes('agency_review')) statusLabel = '代理商审核中'
else if (stage.includes('brand_review')) statusLabel = '品牌方审核中'
else if (stage === 'completed') statusLabel = '已完成'
else if (stage === 'rejected') statusLabel = '已驳回'
// 筛选分类
let filterCategory: 'pending' | 'reviewing' | 'rejected' | 'completed' = 'reviewing'
if (stage === 'script_upload' || stage === 'video_upload') filterCategory = 'pending'
else if (stage === 'completed') filterCategory = 'completed'
else if (stage === 'rejected') filterCategory = 'rejected'
// 处理驳回后重新提交的情况
if (task.script_agency_status === 'rejected' || task.script_brand_status === 'rejected' ||
task.video_agency_status === 'rejected' || task.video_brand_status === 'rejected') {
if (stage !== 'completed') filterCategory = 'rejected'
}
return {
scriptStage,
videoStage,
currentPhase,
buttonText,
buttonType,
scriptColor,
videoColor,
statusLabel,
filterCategory,
}
}