'use client' import { useState } from 'react' import { useParams, useRouter } from 'next/navigation' import { ArrowLeft, MessageCircle, Clock, CheckCircle, XCircle, FileText, Image, Send, AlertTriangle } from 'lucide-react' import { ResponsiveLayout } from '@/components/layout/ResponsiveLayout' import { cn } from '@/lib/utils' // 申诉状态类型 type AppealStatus = 'pending' | 'processing' | 'approved' | 'rejected' // 申诉详情数据类型 type AppealDetail = { id: string taskId: string taskTitle: string type: 'ai' | 'agency' | 'brand' reason: string content: string status: AppealStatus createdAt: string updatedAt?: string result?: string attachments?: { name: string; type: 'image' | 'document'; url: string }[] timeline?: { time: string; action: string; operator?: string }[] originalIssue?: { title: string; description: string } } // 模拟申诉详情数据 const mockAppealDetails: Record = { 'appeal-001': { id: 'appeal-001', taskId: 'task-003', taskTitle: 'ZZ饮品夏日', type: 'ai', reason: '误判', content: '视频中出现的是我们自家品牌的历史产品,并非竞品。已附上品牌授权证明。', status: 'approved', createdAt: '2026-02-01 10:30', updatedAt: '2026-02-02 15:20', result: '经核实,该产品确为品牌方授权产品,申诉通过。AI已学习此案例,后续将避免类似误判。', attachments: [ { name: '品牌授权书.pdf', type: 'document', url: '#' }, { name: '产品对比图.jpg', type: 'image', url: '#' }, ], timeline: [ { time: '2026-02-01 10:30', action: '提交申诉' }, { time: '2026-02-01 14:15', action: '进入处理队列' }, { time: '2026-02-02 09:00', action: '开始审核', operator: '审核员 A' }, { time: '2026-02-02 15:20', action: '申诉通过', operator: '审核员 A' }, ], originalIssue: { title: '检测到竞品 Logo', description: '画面中 0:15-0:18 出现竞品「百事可乐」的 Logo,可能造成合规风险。', }, }, 'appeal-002': { id: 'appeal-002', taskId: 'task-010', taskTitle: 'GG智能手表', type: 'agency', reason: '审核标准不清晰', content: '代理商反馈品牌调性不符,但Brief中并未明确说明科技专业形象的具体要求。请明确审核标准。', status: 'processing', createdAt: '2026-02-04 09:15', timeline: [ { time: '2026-02-04 09:15', action: '提交申诉' }, { time: '2026-02-04 11:30', action: '进入处理队列' }, { time: '2026-02-05 10:00', action: '开始审核', operator: '审核员 B' }, ], originalIssue: { title: '品牌调性不符', description: '脚本整体风格偏向娱乐化,与品牌科技专业形象不匹配。', }, }, 'appeal-003': { id: 'appeal-003', taskId: 'task-011', taskTitle: 'HH美妆代言', type: 'brand', reason: '创意理解差异', content: '品牌方认为创意不够新颖,但该创意形式在同类型产品推广中效果显著,已附上数据支持。', status: 'pending', createdAt: '2026-02-05 14:00', attachments: [ { name: '同类案例数据.xlsx', type: 'document', url: '#' }, ], timeline: [ { time: '2026-02-05 14:00', action: '提交申诉' }, ], originalIssue: { title: '创意不够新颖', description: '脚本采用的是常见的口播形式,缺乏创新点和记忆点。', }, }, 'appeal-004': { id: 'appeal-004', taskId: 'task-013', taskTitle: 'JJ旅行vlog', type: 'agency', reason: '版权问题异议', content: '使用的背景音乐来自无版权音乐库 Epidemic Sound,已购买商用授权。附上授权证明截图。', status: 'rejected', createdAt: '2026-01-28 11:30', updatedAt: '2026-01-30 16:45', result: '经核实,该音乐虽有授权,但授权范围不包含商业广告用途。建议更换音乐后重新提交。', attachments: [ { name: '授权截图.png', type: 'image', url: '#' }, ], timeline: [ { time: '2026-01-28 11:30', action: '提交申诉' }, { time: '2026-01-28 15:00', action: '进入处理队列' }, { time: '2026-01-29 09:30', action: '开始审核', operator: '审核员 C' }, { time: '2026-01-30 16:45', action: '申诉驳回', operator: '审核员 C' }, ], originalIssue: { title: '背景音乐版权问题', description: '视频中使用的背景音乐「XXX」存在版权风险,平台可能会限流或下架。', }, }, } // 状态配置 const statusConfig: Record = { pending: { label: '待处理', color: 'text-amber-500', bgColor: 'bg-amber-500/15', icon: Clock }, processing: { label: '处理中', color: 'text-accent-indigo', bgColor: 'bg-accent-indigo/15', icon: MessageCircle }, approved: { label: '已通过', color: 'text-accent-green', bgColor: 'bg-accent-green/15', icon: CheckCircle }, rejected: { label: '已驳回', color: 'text-accent-coral', bgColor: 'bg-accent-coral/15', icon: XCircle }, } // 类型配置 const typeConfig: Record = { ai: { label: 'AI审核', color: 'text-accent-indigo' }, agency: { label: '代理商审核', color: 'text-purple-400' }, brand: { label: '品牌方审核', color: 'text-accent-blue' }, } export default function AppealDetailPage() { const params = useParams() const router = useRouter() const appealId = params.id as string const [newComment, setNewComment] = useState('') const appeal = mockAppealDetails[appealId] if (!appeal) { return (

申诉记录不存在

) } const status = statusConfig[appeal.status] const type = typeConfig[appeal.type] const StatusIcon = status.icon return (
{/* 顶部栏 */}

申诉详情

申诉编号: {appeal.id}

{status.label}
{/* 内容区 - 响应式布局 */}
{/* 左侧:申诉信息 */}
{/* 原始问题 */} {appeal.originalIssue && (

原始审核问题

{appeal.originalIssue.title}

{appeal.originalIssue.description}

)} {/* 申诉内容 */}

申诉内容

关联任务: {appeal.taskTitle}
申诉对象: {type.label}
申诉原因: {appeal.reason}

{appeal.content}

{/* 附件 */} {appeal.attachments && appeal.attachments.length > 0 && (

证明材料

{appeal.attachments.map((attachment, index) => (
{attachment.type === 'image' ? ( ) : ( )} {attachment.name}
))}
)} {/* 处理结果 */} {appeal.result && (

处理结果

{appeal.result}

)} {/* 补充说明(处理中状态可用) */} {(appeal.status === 'pending' || appeal.status === 'processing') && (

补充说明

setNewComment(e.target.value)} className="flex-1 px-4 py-3 bg-bg-elevated rounded-xl text-sm text-text-primary placeholder-text-tertiary focus:outline-none focus:ring-2 focus:ring-accent-indigo" />
)}
{/* 右侧:时间线 */}

处理进度

{appeal.timeline?.map((item, index) => (
{index < (appeal.timeline?.length || 0) - 1 && (
)}
{item.time} {item.action} {item.operator && ( {item.operator} )}
))}
) }