'use client' import { useState } from 'react' import { useParams, useRouter } from 'next/navigation' import { Upload, Check, X, Folder, Bell, MessageCircle, XCircle, CheckCircle, Loader2, Scan, ArrowLeft, Bot, Users, Building2, Clock, FileText, Video, ChevronRight, AlertTriangle } from 'lucide-react' import { ResponsiveLayout } from '@/components/layout/ResponsiveLayout' import { cn } from '@/lib/utils' // 详细的任务状态类型 type TaskPhase = 'script' | 'video' type TaskStage = | 'upload' // 待上传 | 'ai_reviewing' // AI审核中 | 'ai_result' // AI审核结果(有问题需修改) | 'agency_reviewing' // 代理商审核中 | 'agency_rejected' // 代理商驳回 | 'brand_reviewing' // 品牌终审中 | 'brand_approved' // 品牌通过 | 'brand_rejected' // 品牌驳回 type Issue = { title: string description: string timestamp?: string severity?: 'error' | 'warning' } type ReviewLog = { time: string message: string status: 'done' | 'loading' | 'pending' } type TaskData = { id: string title: string subtitle: string phase: TaskPhase stage: TaskStage progress?: number issues?: Issue[] reviewLogs?: ReviewLog[] rejectionReason?: string submittedAt?: string scriptContent?: string } // 所有15个任务的详细数据 const allTasksData: Record = { 'task-001': { id: 'task-001', title: 'XX品牌618推广', subtitle: '产品种草视频 · 时长要求 60-90秒 · 当前步骤:上传脚本', phase: 'script', stage: 'upload', }, 'task-002': { id: 'task-002', title: 'YY美妆新品', subtitle: '口播测评 · 时长要求 60-90秒 · 当前步骤:AI审核中', phase: 'script', stage: 'ai_reviewing', progress: 62, reviewLogs: [ { time: '14:32:01', message: '脚本上传完成', status: 'done' }, { time: '14:32:15', message: '任务规则已加载', status: 'done' }, { time: '14:32:28', message: '开始内容合规性检测', status: 'done' }, { time: '14:33:45', message: '正在分析品牌调性匹配度...', status: 'loading' }, ], }, 'task-003': { id: 'task-003', title: 'ZZ饮品夏日', subtitle: '探店Vlog · 发现2处问题 · 需修改后重新提交', phase: 'script', stage: 'ai_result', issues: [ { title: '检测到竞品提及', description: '脚本第3段提及了竞品「百事可乐」,可能造成品牌冲突风险。', severity: 'error', }, { title: '禁用词语出现', description: '脚本中出现「最好喝」「第一」等绝对化用语,可能违反广告法。', severity: 'error', }, ], }, 'task-004': { id: 'task-004', title: 'AA数码新品发布', subtitle: '开箱测评 · 时长要求 60-90秒 · 当前步骤:审核通过', phase: 'video', stage: 'brand_approved', submittedAt: '2026-02-01 10:30', }, 'task-005': { id: 'task-005', title: 'BB运动饮料', subtitle: '运动场景 · 时长要求 60-90秒 · 当前步骤:AI审核中', phase: 'script', stage: 'ai_reviewing', progress: 35, reviewLogs: [ { time: '15:10:22', message: '脚本上传完成', status: 'done' }, { time: '15:10:35', message: '任务规则已加载', status: 'done' }, { time: '15:10:48', message: '正在进行内容分析...', status: 'loading' }, ], }, 'task-006': { id: 'task-006', title: 'CC服装春季款', subtitle: '穿搭展示 · 时长要求 60-90秒 · 当前步骤:等待代理商审核', phase: 'script', stage: 'agency_reviewing', submittedAt: '2026-02-03 09:15', scriptContent: '春季新品穿搭指南,展示三套不同风格的搭配...', }, 'task-007': { id: 'task-007', title: 'DD家电测评', subtitle: '开箱视频 · 时长要求 60-90秒 · 当前步骤:等待品牌方终审', phase: 'script', stage: 'brand_reviewing', submittedAt: '2026-02-02 14:20', scriptContent: '智能家电开箱测评,详细介绍产品功能特点...', }, 'task-008': { id: 'task-008', title: 'EE食品试吃', subtitle: '美食测评 · 脚本已通过 · 当前步骤:下一步上传视频', phase: 'video', stage: 'upload', }, 'task-009': { id: 'task-009', title: 'FF护肤品', subtitle: '使用教程 · 时长要求 60-90秒 · 当前步骤:视频AI审核中', phase: 'video', stage: 'ai_reviewing', progress: 78, reviewLogs: [ { time: '16:20:11', message: '视频上传完成', status: 'done' }, { time: '16:20:25', message: '任务规则已加载', status: 'done' }, { time: '16:20:38', message: '开始 ASR 语音识别', status: 'done' }, { time: '16:21:52', message: '视觉合规性检测完成', status: 'done' }, { time: '16:22:30', message: '正在生成审核报告...', status: 'loading' }, ], }, 'task-010': { id: 'task-010', title: 'GG智能手表', subtitle: '功能展示 · 时长要求 60-90秒 · 当前步骤:代理商驳回', phase: 'script', stage: 'agency_rejected', rejectionReason: '脚本内容与品牌调性不符,产品卖点描述不够突出,建议重新调整创意方向。', issues: [ { title: '品牌调性不符', description: '脚本整体风格偏向娱乐化,与品牌科技专业形象不匹配。', severity: 'error', }, { title: '卖点不突出', description: '产品核心功能(健康监测、长续航)未在脚本中重点体现。', severity: 'warning', }, ], }, 'task-011': { id: 'task-011', title: 'HH美妆代言', subtitle: '广告拍摄 · 时长要求 60-90秒 · 当前步骤:品牌驳回', phase: 'script', stage: 'brand_rejected', rejectionReason: '品牌方认为脚本创意不够新颖,希望加入更多互动元素。', issues: [ { title: '创意不够新颖', description: '脚本采用的是常见的口播形式,缺乏创新点和记忆点。', severity: 'error', }, { title: '缺少互动元素', description: '建议加入用户互动环节,如问答、挑战等,增加观众参与感。', severity: 'warning', }, ], }, 'task-012': { id: 'task-012', title: 'II数码配件', subtitle: '配件展示 · 时长要求 60-90秒 · 当前步骤:等待代理商审核', phase: 'video', stage: 'agency_reviewing', submittedAt: '2026-02-04 11:30', }, 'task-013': { id: 'task-013', title: 'JJ旅行vlog', subtitle: '旅行记录 · 时长要求 60-90秒 · 当前步骤:代理商驳回', phase: 'video', stage: 'agency_rejected', rejectionReason: '视频背景音乐存在版权问题,需要更换为无版权音乐后重新提交。', issues: [ { title: '背景音乐版权问题', description: '视频中使用的背景音乐「XXX」存在版权风险,平台可能会限流或下架。', severity: 'error', }, ], }, 'task-014': { id: 'task-014', title: 'KK宠物用品', subtitle: '萌宠日常 · 时长要求 60-90秒 · 当前步骤:等待品牌方终审', phase: 'video', stage: 'brand_reviewing', submittedAt: '2026-02-05 09:45', }, 'task-015': { id: 'task-015', title: 'LL厨房电器', subtitle: '使用演示 · 时长要求 60-90秒 · 当前步骤:品牌驳回', phase: 'video', stage: 'brand_rejected', rejectionReason: '产品使用场景不够真实,希望展示更多日常使用细节。', issues: [ { title: '使用场景不真实', description: '视频中的厨房场景过于整洁,缺乏真实感,建议在真实家庭环境中拍摄。', severity: 'error', }, { title: '产品功能展示不完整', description: '仅展示了基础功能,建议补充展示智能预约、自清洁等特色功能。', severity: 'warning', }, ], }, } // 进度条步骤图标组件 function StepIcon({ status, icon }: { status: 'done' | 'current' | 'error' | 'pending' icon: 'upload' | 'bot' | 'users' | 'building' }) { const IconMap = { upload: Upload, bot: Bot, users: Users, building: Building2, } const Icon = IconMap[icon] const getStyle = () => { switch (status) { case 'done': return 'bg-accent-green' case 'current': return 'bg-accent-indigo' case 'error': return 'bg-accent-coral' default: return 'bg-bg-elevated border-[1.5px] border-border-subtle' } } const iconColor = status === 'pending' ? 'text-text-tertiary' : 'text-white' return (
{status === 'done' && } {status === 'current' && } {status === 'error' && } {status === 'pending' && }
) } // 审核流程进度条 function ReviewProgressBar({ task }: { task: TaskData }) { const { phase, stage } = task const getStepStatus = (stepIndex: number): 'done' | 'current' | 'error' | 'pending' => { // 步骤顺序: 0-提交, 1-AI审核, 2-代理商, 3-品牌 const stageMap: Record = { 'upload': 0, 'ai_reviewing': 1, 'ai_result': 1, 'agency_reviewing': 2, 'agency_rejected': 2, 'brand_reviewing': 3, 'brand_approved': 4, 'brand_rejected': 3, } const currentStepIndex = stageMap[stage] const isError = stage === 'ai_result' || stage === 'agency_rejected' || stage === 'brand_rejected' if (stepIndex < currentStepIndex) return 'done' if (stepIndex === currentStepIndex) { if (isError) return 'error' if (stage === 'brand_approved') return 'done' return 'current' } return 'pending' } const steps = [ { label: '已提交', icon: 'upload' as const }, { label: 'AI审核', icon: 'bot' as const }, { label: '代理商', icon: 'users' as const }, { label: '品牌方', icon: 'building' as const }, ] return (

{phase === 'script' ? '脚本审核流程' : '视频审核流程'}

{steps.map((step, index) => { const status = getStepStatus(index) return (
{step.label}
{index < steps.length - 1 && (
)}
) })}
) } // 上传界面 function UploadView({ task }: { task: TaskData }) { const [isDragging, setIsDragging] = useState(false) const isScript = task.phase === 'script' return (

{isScript ? '上传脚本' : '上传视频'}

{isScript ? '支持粘贴文本或上传文档' : '支持 MP4/MOV 格式,≤ 100MB'}

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

点击或拖拽文件到此处

{isScript ? '支持 .doc、.docx、.txt 格式' : '支持 MP4/MOV 格式,≤ 100MB'}

{isScript ? '也可以直接粘贴脚本文本后提交' : '上传完成后将自动进入 AI 审核'}

) } // AI审核中界面 function AIReviewingView({ task }: { task: TaskData }) { return (
{task.phase === 'script' ? '脚本内容审核' : '视频内容审核'} · 智能分析中

AI 正在审核您的{task.phase === 'script' ? '脚本' : '视频'}

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

{task.progress || 0}%
{task.reviewLogs && task.reviewLogs.length > 0 && (
处理日志
{task.reviewLogs.map((log, index) => (
{log.time} {log.message} {log.status === 'loading' && }
))}
)}
) } // 审核结果/驳回界面(AI结果、代理商驳回、品牌驳回) function RejectionView({ task, onAppeal }: { task: TaskData; onAppeal: () => void }) { const getTitle = () => { switch (task.stage) { case 'ai_result': return 'AI 审核结果' case 'agency_rejected': return '代理商审核结果' case 'brand_rejected': return '品牌方审核结果' default: return '审核结果' } } const getStatusText = () => { switch (task.stage) { case 'ai_result': return 'AI 检测到问题' case 'agency_rejected': return '代理商审核驳回' case 'brand_rejected': return '品牌方审核驳回' default: return '需要修改' } } return (
{/* 进度条 */} {/* 结果卡片 */}
{/* 状态标题 */}
{getTitle()} {getStatusText()}
{/* 驳回原因 */} {task.rejectionReason && (

{task.rejectionReason}

)} {/* 问题列表 */} {task.issues && task.issues.length > 0 && (
发现 {task.issues.length} 处问题
{task.issues.map((issue, index) => (
{issue.severity === 'error' ? '违规' : '建议'} {issue.title}

{issue.description}

))}
)} {/* 操作按钮 */}
) } // 等待审核界面(代理商审核中、品牌终审中) function WaitingReviewView({ task }: { task: TaskData }) { const isAgency = task.stage === 'agency_reviewing' const title = isAgency ? '等待代理商审核' : '等待品牌方终审' const description = isAgency ? '您的内容已进入代理商审核环节,请耐心等待' : '您的内容已进入品牌方终审环节,这是最后一步' return (
{/* 进度条 */} {/* 提交信息卡片 */}
{task.phase === 'script' ? '脚本提交信息' : '视频提交信息'}
提交时间 {task.submittedAt || '刚刚'}
AI审核 已通过
{isAgency && (
代理商审核 审核中...
)} {!isAgency && ( <>
代理商审核 已通过
品牌方终审 审核中...
)}
{/* 等待提示 */}
{title} {description}
温馨提示 {isAgency ? '代理商通常会在 1-2 个工作日内完成审核,审核结果将通过消息中心通知您。' : '品牌方终审通常需要 1-3 个工作日,通过后即可进入下一阶段。'}
) } // 审核通过界面 function ApprovedView({ task }: { task: TaskData }) { const isVideoPhase = task.phase === 'video' return (
{/* 进度条 */} {/* 提交信息 */}
{task.phase === 'script' ? '脚本提交信息' : '视频提交信息'}
提交时间 {task.submittedAt || '2026-02-01 10:30'}
AI审核 已通过
代理商审核 已通过
品牌方终审 已通过
{/* 审核结果 */}
品牌方审核通过
已通过

{isVideoPhase ? '恭喜!视频已通过所有审核,可以发布了' : '脚本已通过品牌方终审,请继续上传视频'}

{/* 通过提示 */}
{isVideoPhase ? '全部审核通过' : '脚本审核通过'} {isVideoPhase ? '可以安排发布了' : '请在 7 天内上传视频'}
{isVideoPhase ? '恭喜完成!' : '下一步'} {isVideoPhase ? '您的视频已通过全部审核流程,可以在平台发布了。发布后记得在消息中心查看数据反馈。' : '脚本已通过审核,请在 7 天内上传对应视频。视频将再次经过 AI 审核 → 代理商审核 → 品牌方终审。'}
{/* 下一步按钮 */} {!isVideoPhase && (
)}
) } export default function TaskDetailPage() { const params = useParams() const router = useRouter() const taskId = params.id as string const taskData = allTasksData[taskId] if (!taskData) { return (

任务不存在

) } // 跳转到申诉页面 const handleAppeal = () => { router.push(`/creator/appeals/new?taskId=${taskId}`) } // 根据状态渲染内容 const renderContent = () => { switch (taskData.stage) { case 'upload': return case 'ai_reviewing': return case 'ai_result': case 'agency_rejected': case 'brand_rejected': return case 'agency_reviewing': case 'brand_reviewing': return case 'brand_approved': return default: return
未知状态
} } // 获取页面标题 const getPageTitle = () => { switch (taskData.stage) { case 'upload': return taskData.phase === 'script' ? '上传脚本' : '上传视频' case 'ai_reviewing': return 'AI 智能审核' case 'ai_result': return 'AI 审核结果' case 'agency_reviewing': return '等待代理商审核' case 'agency_rejected': return '代理商审核驳回' case 'brand_reviewing': return '等待品牌方终审' case 'brand_approved': return '审核通过' case 'brand_rejected': return '品牌方审核驳回' default: return '任务详情' } } return (
{/* 顶部栏 */}

{taskData.title}

{taskData.subtitle}

{/* 主内容 */}
{renderContent()}
) }