'use client' import { useState, useEffect, useCallback } from 'react' import { useRouter } from 'next/navigation' import { ArrowLeft, Check, X, CheckSquare, Video, Clock, Loader2, FileText } from 'lucide-react' import { cn } from '@/lib/utils' import { getPlatformInfo } from '@/lib/platforms' import { useToast } from '@/components/ui/Toast' import { api } from '@/lib/api' import { USE_MOCK } from '@/contexts/AuthContext' import type { TaskResponse } from '@/types/task' // ==================== Mock 数据 ==================== const mockReviewItems: TaskResponse[] = [ { id: 'TK000001', name: '春季护肤新品体验分享', sequence: 1, stage: 'video_brand_review', project: { id: 'PJ000001', name: 'XX品牌618推广' }, agency: { id: 'AG000001', name: '代理商A' }, creator: { id: 'CR000001', name: '小美' }, video_file_url: '/demo/video.mp4', video_file_name: '春季护肤_成片v2.mp4', video_duration: 135, video_ai_score: 88, video_ai_result: { score: 88, violations: [], soft_warnings: [], summary: '视频整体合规,卖点覆盖完整。', }, video_agency_status: 'passed', video_agency_comment: '内容符合Brief要求,卖点覆盖完整,建议通过。', appeal_count: 0, is_appeal: false, created_at: '2026-02-06T14:00:00Z', updated_at: '2026-02-06T16:00:00Z', }, ] // 审核流程进度组件 function ReviewProgressBar({ currentStep }: { currentStep: number }) { 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 const isCurrent = s.step === currentStep return (
{isCompleted && } {isCurrent && }
{s.label}
{index < steps.length - 1 && (
)}
) })}
) } function PageSkeleton() { return (
) } export default function FinalReviewPage() { const router = useRouter() const toast = useToast() const [loading, setLoading] = useState(true) const [tasks, setTasks] = useState([]) const [selectedIndex, setSelectedIndex] = useState(0) const [feedback, setFeedback] = useState('') const [isSubmitting, setIsSubmitting] = useState(false) const loadTasks = useCallback(async () => { if (USE_MOCK) { setTasks(mockReviewItems) setLoading(false) return } try { // 加载品牌方待审任务(脚本 + 视频) const [scriptRes, videoRes] = await Promise.all([ api.listTasks(1, 10, 'script_brand_review'), api.listTasks(1, 10, 'video_brand_review'), ]) setTasks([...scriptRes.items, ...videoRes.items]) } catch (err) { console.error('Failed to load review tasks:', err) toast.error('加载待审任务失败') } finally { setLoading(false) } }, [toast]) useEffect(() => { loadTasks() }, [loadTasks]) if (loading) return if (tasks.length === 0) { return (

暂无待终审的内容

) } const selectedItem = tasks[selectedIndex] const isVideoReview = selectedItem.stage === 'video_brand_review' const aiResult = isVideoReview ? selectedItem.video_ai_result : selectedItem.script_ai_result const aiScore = isVideoReview ? selectedItem.video_ai_score : selectedItem.script_ai_score const agencyComment = isVideoReview ? selectedItem.video_agency_comment : selectedItem.script_agency_comment const agencyStatus = isVideoReview ? selectedItem.video_agency_status : selectedItem.script_agency_status const handleApprove = async () => { setIsSubmitting(true) try { if (USE_MOCK) { await new Promise(resolve => setTimeout(resolve, 1000)) } else { const reviewFn = isVideoReview ? api.reviewVideo : api.reviewScript await reviewFn(selectedItem.id, { action: 'pass', comment: feedback || undefined }) } toast.success('已通过审核') setFeedback('') // 移除已审核任务 const remaining = tasks.filter((_, i) => i !== selectedIndex) setTasks(remaining) if (selectedIndex >= remaining.length && remaining.length > 0) { setSelectedIndex(remaining.length - 1) } } catch (err) { toast.error('操作失败') } finally { setIsSubmitting(false) } } const handleReject = async () => { if (!feedback.trim()) { toast.error('请填写驳回原因') return } setIsSubmitting(true) try { if (USE_MOCK) { await new Promise(resolve => setTimeout(resolve, 1000)) } else { const reviewFn = isVideoReview ? api.reviewVideo : api.reviewScript await reviewFn(selectedItem.id, { action: 'reject', comment: feedback }) } toast.success('已驳回') setFeedback('') const remaining = tasks.filter((_, i) => i !== selectedIndex) setTasks(remaining) if (selectedIndex >= remaining.length && remaining.length > 0) { setSelectedIndex(remaining.length - 1) } } catch (err) { toast.error('操作失败') } finally { setIsSubmitting(false) } } return (
{/* 顶部栏 */}

终审台

{isVideoReview ?

{selectedItem.name} · 达人: {selectedItem.creator.name}

{selectedIndex + 1} / {tasks.length} 待审
{/* 审核流程进度 */}
审核流程 当前:品牌终审
{/* 主内容区 - 两栏布局 */}
{/* 左侧 - 预览 */}
{isVideoReview ? ( selectedItem.video_file_url ? ( ) : (

视频文件不可用

) ) : (

{selectedItem.script_file_name || '脚本预览'}

请在详情页查看完整脚本内容

)}
{/* 右侧 - 分析面板 */}
{/* 代理商初审意见 */}
代理商初审意见 {agencyStatus === 'passed' || agencyStatus === 'force_passed' ? '已通过' : '需修改'}
审核人:{selectedItem.agency.name}

{agencyComment || '无评论'}

{/* AI 分析结果 */}
AI 分析结果 = 80 ? 'bg-accent-green/15 text-accent-green' : 'bg-accent-amber/15 text-accent-amber' )}> 评分: {aiScore || '-'}
{aiResult?.violations && aiResult.violations.length > 0 ? ( aiResult.violations.map((v, idx) => (
{v.type}

{v.content}

{v.suggestion && (

{v.suggestion}

)}
)) ) : (
合规检测通过
)} {aiResult?.summary && (

{aiResult.summary}

)}
{/* 终审决策 */}

终审决策

{/* 决策按钮 */}
{/* 终审意见 */}