'use client' import { useState, useEffect } from 'react' import { useParams, useRouter } from 'next/navigation' import { Upload, Check, X, Folder, Bell, Play, MessageCircle, XCircle, CheckCircle, Loader2, Scan, ArrowLeft } from 'lucide-react' import { DesktopLayout } from '@/components/layout/DesktopLayout' import { MobileLayout } from '@/components/layout/MobileLayout' import { cn } from '@/lib/utils' import { api } from '@/lib/api' import type { TaskResponse } from '@/types/task' // 任务状态类型 type TaskStatus = 'pending_script' | 'pending_video' | 'ai_reviewing' | 'agency_reviewing' | 'need_revision' | 'passed' type RequirementProfile = { title?: string platform?: string deadline?: string progress?: number statusHint?: TaskStatus issues?: Array<{ title: string; description: string; timestamp?: string }> reviewLogs?: Array<{ time: string; message: string; status: 'done' | 'loading' | 'pending' }> } type TaskDetail = { id: string title: string platform: string deadline: string status: TaskStatus currentStep: number progress?: number issues?: Array<{ title: string; description: string; timestamp?: string }> reviewLogs?: Array<{ time: string; message: string; status: 'done' | 'loading' | 'pending' }> } // 任务配置(占位数据) const taskRequirementProfiles: Record = { 'task-001': { title: 'XX品牌618推广', platform: '抖音', deadline: '2026-02-10', statusHint: 'pending_script', }, 'task-002': { title: 'YY美妆新品', platform: '小红书', deadline: '2026-02-15', progress: 62, statusHint: 'ai_reviewing', reviewLogs: [ { time: '14:32:01', message: '视频上传完成', status: 'done' }, { time: '14:32:15', message: '任务规则已加载', status: 'done' }, { time: '14:32:28', message: '开始 ASR 语音识别', status: 'done' }, { time: '14:33:45', message: '正在分析视觉合规性问题...', status: 'loading' }, ], }, 'task-003': { title: 'ZZ饮品夏日', platform: '抖音', deadline: '2026-02-08', statusHint: 'need_revision', issues: [ { title: '检测到竞品 Logo', description: '画面中 0:15-0:18 出现竞品「百事可乐」的 Logo,可能造成合规风险。', timestamp: '0:15', }, { title: '禁用词语出现', description: '视频中出现「最好喝」「第一」等绝对化用语,可能违反广告法。', timestamp: '0:42', }, ], }, 'task-004': { title: 'AA数码新品发布', platform: '抖音', deadline: '2026-02-20', statusHint: 'passed', }, 'task-005': { title: 'BB运动饮料', platform: '抖音', deadline: '2026-02-12', statusHint: 'pending_video', }, } const platformLabelMap: Record = { douyin: '抖音', xiaohongshu: '小红书', bilibili: 'B站', kuaishou: '快手', } const getPlatformLabel = (platform?: string) => { if (!platform) return '未知平台' return platformLabelMap[platform] || platform } const deriveTaskStatus = (task: TaskResponse): TaskStatus => { if (!task.has_script) { return 'pending_script' } if (!task.has_video) { return 'pending_video' } if (task.status === 'approved') { return 'passed' } if (task.status === 'rejected' || task.status === 'failed') { return 'need_revision' } if (task.status === 'pending' || task.status === 'processing') { return 'ai_reviewing' } return 'agency_reviewing' } const getCurrentStep = (status: TaskStatus) => { if (status === 'ai_reviewing' || status === 'need_revision') { return 2 } if (status === 'agency_reviewing') { return 3 } if (status === 'passed') { return 4 } return 1 } const buildTaskDetail = (task: TaskResponse): TaskDetail => { const profile = taskRequirementProfiles[task.task_id] const status = deriveTaskStatus(task) const platformLabel = profile?.platform || getPlatformLabel(task.platform) return { id: task.task_id, title: profile?.title || `任务 ${task.task_id}`, platform: platformLabel, deadline: profile?.deadline || '待确认', status, currentStep: getCurrentStep(status), progress: profile?.progress, issues: profile?.issues, reviewLogs: profile?.reviewLogs, } } // 审核进度条组件 function ReviewProgressBar({ currentStep, status }: { currentStep: number; status: TaskStatus }) { const steps = [ { label: '已提交', step: 1 }, { label: 'AI审核', step: 2 }, { label: '代理商审核', step: 3 }, { label: '最终结果', step: 4 }, ] return (
{steps.map((s, index) => { const isCompleted = s.step < currentStep || (s.step === currentStep && status === 'passed') const isCurrent = s.step === currentStep && status !== 'passed' const isError = isCurrent && status === 'need_revision' return (
{isCompleted && } {isCurrent && !isError && } {isError && }
{s.label}
{index < steps.length - 1 && (
)}
) })}
) } // 上传界面 function UploadView({ task }: { task: TaskDetail }) { const [isDragging, setIsDragging] = useState(false) const isScriptStep = task.status === 'pending_script' const title = isScriptStep ? '上传脚本' : '上传视频' const subtitle = isScriptStep ? '支持粘贴文本或上传文档' : '支持 MP4/MOV 格式,≤ 100MB' const actionLabel = isScriptStep ? '选择脚本文档' : '选择视频文件' const hintText = isScriptStep ? '也可以直接粘贴脚本文本后提交' : '上传完成后将自动进入 AI 审核' return (

{title}

{subtitle}

待提交
{ e.preventDefault(); setIsDragging(true) }} onDragLeave={() => setIsDragging(false)} onDrop={(e) => { e.preventDefault(); setIsDragging(false) }} >

点击或拖拽文件到此处

{subtitle}

{hintText}

) } // AI 审核中界面 function ReviewingView({ task }: { task: TaskDetail }) { return (
{/* 任务标签 */}
产品种草视频 · 时长 60-90秒
{/* 扫描动画 */}
{/* 外圈渐变 */}
{/* 中心圆 */}
{/* 进度信息 */}

AI 正在审核您的视频

预计还需 2-3 分钟,可先离开页面

{/* 进度条 */}
{task.progress || 0}%
{/* 日志区 */}
处理日志
{task.reviewLogs?.map((log, index) => (
{log.time} {log.message} {log.status === 'loading' && }
))}
{/* 通知按钮 */}
) } // 审核结果界面 function ResultView({ task }: { task: TaskDetail }) { const isNeedRevision = task.status === 'need_revision' const isPassed = task.status === 'passed' return (
{/* 审核流程进度 */}
审核进度 更新于 5分钟前
{/* 状态横幅 */}
{isNeedRevision ? ( ) : ( )}
{isNeedRevision ? '需要修改' : '审核通过'} {isNeedRevision ? `发现 ${task.issues?.length || 0} 处违规问题,请修改后重新提交` : '恭喜!您的视频已通过所有审核'}
{/* 内容区 */}
{/* 左侧:视频预览 */}
{/* 右侧:问题清单 */} {isNeedRevision && task.issues && task.issues.length > 0 && (

问题清单

{task.issues.map((issue, index) => (
违规 {issue.title}
{issue.timestamp && ( )}

{issue.description}

))}
)}
) } export default function TaskDetailPage() { const params = useParams() const router = useRouter() const taskId = params.id as string const [isMobile, setIsMobile] = useState(true) const [taskDetail, setTaskDetail] = useState(null) const [isLoading, setIsLoading] = useState(true) useEffect(() => { const checkMobile = () => setIsMobile(window.innerWidth < 1024) checkMobile() window.addEventListener('resize', checkMobile) return () => window.removeEventListener('resize', checkMobile) }, []) useEffect(() => { let isMounted = true const fetchTask = async () => { setIsLoading(true) try { const data = await api.getTask(taskId) if (!isMounted) return setTaskDetail(buildTaskDetail(data)) } catch (error) { console.error('加载任务详情失败:', error) if (isMounted) { const fallbackProfile = taskRequirementProfiles[taskId] if (fallbackProfile) { const status = fallbackProfile.statusHint || 'pending_script' setTaskDetail({ id: taskId, title: fallbackProfile.title || `任务 ${taskId}`, platform: fallbackProfile.platform || '未知平台', deadline: fallbackProfile.deadline || '待确认', status, currentStep: getCurrentStep(status), progress: fallbackProfile.progress, issues: fallbackProfile.issues, reviewLogs: fallbackProfile.reviewLogs, }) } } } finally { if (isMounted) { setIsLoading(false) } } } if (taskId) { fetchTask() } return () => { isMounted = false } }, [taskId]) if (isLoading) { return (

正在加载任务...

) } if (!taskDetail) { return (

任务不存在

) } // 根据状态获取页面标题 const getPageTitle = () => { switch (taskDetail.status) { case 'pending_script': return '上传脚本' case 'pending_video': return '上传视频' case 'ai_reviewing': return 'AI 智能审核' case 'agency_reviewing': return '代理商审核中' case 'need_revision': case 'passed': return '审核结果' default: return '任务详情' } } // 根据状态渲染内容 const renderContent = () => { switch (taskDetail.status) { case 'pending_script': case 'pending_video': return case 'ai_reviewing': return case 'need_revision': case 'passed': return default: return
未知状态
} } // 获取顶部操作按钮 const getTopActions = () => { if (taskDetail.status === 'need_revision') { return (
) } if (taskDetail.status === 'ai_reviewing') { return ( ) } return null } // 桌面端内容 const DesktopContent = (
{/* 顶部栏 */}

{getPageTitle()}

{taskDetail.title} · 截止: {taskDetail.deadline}

{getTopActions()} {taskDetail.status === 'pending_video' && (
{taskDetail.platform}
)}
{/* 主内容 */}
{renderContent()}
) // 移动端内容 const MobileContent = (
{/* 头部 */}

{getPageTitle()}

{taskDetail.title}

{/* 简化的移动端内容 */}

请在桌面端查看完整内容

) return isMobile ? MobileContent : DesktopContent }