Your Name 2f9b7f05fd feat(creator): 完成达人端前端页面开发
- 新增申诉中心页面(列表、详情、新建申诉)
- 新增申诉次数管理页面(按任务显示配额,支持向代理商申请)
- 新增个人中心页面(达人ID复制、菜单导航)
- 新增个人信息编辑、账户设置、消息通知设置页面
- 新增帮助中心和历史记录页面
- 新增脚本提交和视频提交页面
- 优化消息中心页面(消息详情跳转)
- 优化任务详情页面布局和交互
- 更新 ResponsiveLayout、Sidebar、ReviewSteps 通用组件

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 15:38:01 +08:00

204 lines
7.1 KiB
TypeScript

'use client'
import { useState } from 'react'
import { useRouter } from 'next/navigation'
import {
ArrowLeft,
CheckCircle,
XCircle,
Clock,
Video,
Filter,
ChevronRight
} from 'lucide-react'
import { ResponsiveLayout } from '@/components/layout/ResponsiveLayout'
import { cn } from '@/lib/utils'
// 历史任务状态类型
type HistoryStatus = 'completed' | 'expired' | 'cancelled'
// 历史任务数据类型
type HistoryTask = {
id: string
title: string
description: string
status: HistoryStatus
completedAt?: string
expiredAt?: string
platform: string
}
// 模拟历史数据
const mockHistory: HistoryTask[] = [
{
id: 'hist-001',
title: 'MM春季护肤品推广',
description: '产品测评 · 已发布',
status: 'completed',
completedAt: '2026-01-20',
platform: '抖音',
},
{
id: 'hist-002',
title: 'NN零食新品试吃',
description: '美食测评 · 已发布',
status: 'completed',
completedAt: '2026-01-15',
platform: '小红书',
},
{
id: 'hist-003',
title: 'OO运动装备测评',
description: '运动视频 · 已过期',
status: 'expired',
expiredAt: '2026-01-10',
platform: '抖音',
},
{
id: 'hist-004',
title: 'PP家居用品展示',
description: '生活vlog · 已取消',
status: 'cancelled',
expiredAt: '2026-01-05',
platform: 'B站',
},
{
id: 'hist-005',
title: 'QQ电子产品开箱',
description: '科技测评 · 已发布',
status: 'completed',
completedAt: '2025-12-28',
platform: '抖音',
},
{
id: 'hist-006',
title: 'RR母婴用品推荐',
description: '种草视频 · 已发布',
status: 'completed',
completedAt: '2025-12-20',
platform: '小红书',
},
]
// 状态配置
const statusConfig: Record<HistoryStatus, { label: string; color: string; bgColor: string; icon: React.ElementType }> = {
completed: { label: '已完成', color: 'text-accent-green', bgColor: 'bg-accent-green/15', icon: CheckCircle },
expired: { label: '已过期', color: 'text-text-tertiary', bgColor: 'bg-bg-elevated', icon: Clock },
cancelled: { label: '已取消', color: 'text-accent-coral', bgColor: 'bg-accent-coral/15', icon: XCircle },
}
// 历史任务卡片
function HistoryCard({ task, onClick }: { task: HistoryTask; onClick: () => void }) {
const status = statusConfig[task.status]
const StatusIcon = status.icon
return (
<div
className="bg-bg-card rounded-2xl p-5 card-shadow cursor-pointer hover:bg-bg-elevated/30 transition-colors"
onClick={onClick}
>
<div className="flex items-center justify-between">
<div className="flex items-center gap-4">
<div className="w-16 h-12 rounded-lg bg-[#1A1A1E] flex items-center justify-center flex-shrink-0">
<Video className="w-5 h-5 text-text-tertiary" />
</div>
<div className="flex flex-col gap-1">
<span className="text-base font-semibold text-text-primary">{task.title}</span>
<span className="text-sm text-text-secondary">{task.description}</span>
<div className="flex items-center gap-3 mt-1">
<span className="text-xs text-text-tertiary">{task.platform}</span>
<span className="text-xs text-text-tertiary">
{task.completedAt || task.expiredAt}
</span>
</div>
</div>
</div>
<div className="flex items-center gap-3">
<div className={cn('px-3 py-1.5 rounded-lg flex items-center gap-1.5', status.bgColor)}>
<StatusIcon className={cn('w-4 h-4', status.color)} />
<span className={cn('text-sm font-medium', status.color)}>{status.label}</span>
</div>
<ChevronRight className="w-5 h-5 text-text-tertiary" />
</div>
</div>
</div>
)
}
export default function CreatorHistoryPage() {
const router = useRouter()
const [filter, setFilter] = useState<HistoryStatus | 'all'>('all')
const filteredHistory = filter === 'all' ? mockHistory : mockHistory.filter(t => t.status === filter)
return (
<ResponsiveLayout role="creator">
<div className="flex flex-col gap-6 h-full">
{/* 顶部栏 */}
<div className="flex items-center justify-between flex-wrap gap-4">
<div className="flex flex-col gap-1">
<button
type="button"
onClick={() => router.back()}
className="flex items-center gap-2 px-3 py-1.5 rounded-lg bg-bg-elevated text-text-secondary text-sm hover:bg-bg-card transition-colors w-fit mb-2"
>
<ArrowLeft className="w-4 h-4" />
</button>
<h1 className="text-xl lg:text-[28px] font-bold text-text-primary"></h1>
<p className="text-sm lg:text-[15px] text-text-secondary"></p>
</div>
<div className="flex items-center gap-2 px-4 py-2.5 bg-bg-card rounded-xl border border-border-subtle">
<Filter className="w-[18px] h-[18px] text-text-secondary" />
<select
value={filter}
onChange={(e) => setFilter(e.target.value as HistoryStatus | 'all')}
className="bg-transparent text-sm text-text-primary focus:outline-none"
>
<option value="all"></option>
<option value="completed"></option>
<option value="expired"></option>
<option value="cancelled"></option>
</select>
</div>
</div>
{/* 统计信息 */}
<div className="flex items-center gap-6 bg-bg-card rounded-2xl p-5 card-shadow">
<div className="flex flex-col items-center gap-1 flex-1">
<span className="text-2xl font-bold text-accent-green">
{mockHistory.filter(t => t.status === 'completed').length}
</span>
<span className="text-xs text-text-tertiary"></span>
</div>
<div className="w-px h-10 bg-border-subtle" />
<div className="flex flex-col items-center gap-1 flex-1">
<span className="text-2xl font-bold text-text-tertiary">
{mockHistory.filter(t => t.status === 'expired').length}
</span>
<span className="text-xs text-text-tertiary"></span>
</div>
<div className="w-px h-10 bg-border-subtle" />
<div className="flex flex-col items-center gap-1 flex-1">
<span className="text-2xl font-bold text-accent-coral">
{mockHistory.filter(t => t.status === 'cancelled').length}
</span>
<span className="text-xs text-text-tertiary"></span>
</div>
</div>
{/* 任务列表 */}
<div className="flex flex-col gap-4 flex-1 overflow-y-auto pr-2">
{filteredHistory.map((task) => (
<HistoryCard
key={task.id}
task={task}
onClick={() => router.push(`/creator/task/${task.id}`)}
/>
))}
</div>
</div>
</ResponsiveLayout>
)
}