- 新增申诉中心页面(列表、详情、新建申诉) - 新增申诉次数管理页面(按任务显示配额,支持向代理商申请) - 新增个人中心页面(达人ID复制、菜单导航) - 新增个人信息编辑、账户设置、消息通知设置页面 - 新增帮助中心和历史记录页面 - 新增脚本提交和视频提交页面 - 优化消息中心页面(消息详情跳转) - 优化任务详情页面布局和交互 - 更新 ResponsiveLayout、Sidebar、ReviewSteps 通用组件 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
204 lines
7.1 KiB
TypeScript
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>
|
|
)
|
|
}
|