'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 ? : }
{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}
)}
{/* 终审决策 */}
终审决策
{/* 决策按钮 */}
{/* 终审意见 */}
)
}