From ad45da52861e2b406d8f2246bcd4878e7d7f2d5c Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 6 Feb 2026 16:26:58 +0800 Subject: [PATCH] =?UTF-8?q?feat(agency):=20=E4=BC=98=E5=8C=96=E8=BE=BE?= =?UTF-8?q?=E4=BA=BA=E7=AE=A1=E7=90=86=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 邀请达人改为使用达人ID(CR+6位数字格式) - 达人列表新增达人ID列,支持复制 - 每个达人的任务显示当前进度阶段: - 脚本阶段:待提交/AI审核/代理商审核/品牌方终审 - 视频阶段:待提交/AI审核/代理商审核/品牌方终审/已完成 - 展开任务可查看申诉次数并增加配额 - 搜索支持按达人名称或达人ID搜索 Co-Authored-By: Claude Opus 4.5 --- frontend/app/agency/creators/page.tsx | 273 +++++++++++++++++--------- 1 file changed, 179 insertions(+), 94 deletions(-) diff --git a/frontend/app/agency/creators/page.tsx b/frontend/app/agency/creators/page.tsx index 434e0f8..364e659 100644 --- a/frontend/app/agency/creators/page.tsx +++ b/frontend/app/agency/creators/page.tsx @@ -11,7 +11,6 @@ import { Users, TrendingUp, TrendingDown, - Mail, Copy, CheckCircle, Clock, @@ -20,30 +19,50 @@ import { Video, ChevronDown, ChevronRight, - PlusCircle + PlusCircle, + UserPlus, + AlertCircle } from 'lucide-react' +// 任务进度阶段 +type TaskStage = 'script_pending' | 'script_ai_review' | 'script_agency_review' | 'script_brand_review' | + 'video_pending' | 'video_ai_review' | 'video_agency_review' | 'video_brand_review' | 'completed' + +// 任务阶段配置 +const stageConfig: Record = { + script_pending: { label: '待提交脚本', color: 'text-text-tertiary', bgColor: 'bg-bg-elevated' }, + script_ai_review: { label: '脚本AI审核中', color: 'text-accent-indigo', bgColor: 'bg-accent-indigo/15' }, + script_agency_review: { label: '脚本代理商审核', color: 'text-purple-400', bgColor: 'bg-purple-500/15' }, + script_brand_review: { label: '脚本品牌方终审', color: 'text-accent-blue', bgColor: 'bg-accent-blue/15' }, + video_pending: { label: '待提交视频', color: 'text-accent-amber', bgColor: 'bg-accent-amber/15' }, + video_ai_review: { label: '视频AI审核中', color: 'text-accent-indigo', bgColor: 'bg-accent-indigo/15' }, + video_agency_review: { label: '视频代理商审核', color: 'text-purple-400', bgColor: 'bg-purple-500/15' }, + video_brand_review: { label: '视频品牌方终审', color: 'text-accent-blue', bgColor: 'bg-accent-blue/15' }, + completed: { label: '已完成', color: 'text-accent-green', bgColor: 'bg-accent-green/15' }, +} + // 任务类型 interface CreatorTask { id: string name: string + projectName: string + stage: TaskStage appealRemaining: number appealUsed: number - status: 'in_progress' | 'completed' } // 达人类型 interface Creator { id: string + creatorId: string // 达人ID(用于邀请和显示) name: string - email: string - avatar: null - status: string + avatar: string + status: 'active' | 'pending' | 'paused' projectCount: number scriptCount: { total: number; passed: number } videoCount: { total: number; passed: number } passRate: number - trend: string + trend: 'up' | 'down' | 'stable' joinedAt: string tasks: CreatorTask[] } @@ -51,10 +70,10 @@ interface Creator { // 模拟达人列表 const mockCreators: Creator[] = [ { - id: 'creator-001', + id: 'c-001', + creatorId: 'CR123456', name: '小美护肤', - email: 'xiaomei@example.com', - avatar: null, + avatar: '小', status: 'active', projectCount: 5, scriptCount: { total: 12, passed: 10 }, @@ -63,15 +82,15 @@ const mockCreators: Creator[] = [ trend: 'up', joinedAt: '2025-08-15', tasks: [ - { id: 'task-001', name: '夏日护肤推广', appealRemaining: 1, appealUsed: 0, status: 'in_progress' }, - { id: 'task-002', name: '防晒霜测评', appealRemaining: 0, appealUsed: 1, status: 'in_progress' }, + { id: 'task-001', name: '夏日护肤推广', projectName: 'XX品牌618', stage: 'video_agency_review', appealRemaining: 1, appealUsed: 0 }, + { id: 'task-002', name: '防晒霜测评', projectName: 'XX品牌618', stage: 'script_brand_review', appealRemaining: 0, appealUsed: 1 }, ], }, { - id: 'creator-002', + id: 'c-002', + creatorId: 'CR789012', name: '美妆Lisa', - email: 'lisa@example.com', - avatar: null, + avatar: 'L', status: 'active', projectCount: 3, scriptCount: { total: 8, passed: 7 }, @@ -80,14 +99,14 @@ const mockCreators: Creator[] = [ trend: 'stable', joinedAt: '2025-10-20', tasks: [ - { id: 'task-003', name: '新品口红试色', appealRemaining: 2, appealUsed: 0, status: 'in_progress' }, + { id: 'task-003', name: '新品口红试色', projectName: '口红系列推广', stage: 'video_pending', appealRemaining: 2, appealUsed: 0 }, ], }, { - id: 'creator-003', + id: 'c-003', + creatorId: 'CR345678', name: '健身教练王', - email: 'wang@example.com', - avatar: null, + avatar: '王', status: 'active', projectCount: 2, scriptCount: { total: 5, passed: 5 }, @@ -96,14 +115,14 @@ const mockCreators: Creator[] = [ trend: 'up', joinedAt: '2025-12-01', tasks: [ - { id: 'task-004', name: '健身器材使用教程', appealRemaining: 1, appealUsed: 0, status: 'in_progress' }, + { id: 'task-004', name: '健身器材使用教程', projectName: 'XX运动品牌', stage: 'script_ai_review', appealRemaining: 1, appealUsed: 0 }, ], }, { - id: 'creator-004', + id: 'c-004', + creatorId: 'CR901234', name: '时尚达人', - email: 'fashion@example.com', - avatar: null, + avatar: '时', status: 'pending', projectCount: 0, scriptCount: { total: 0, passed: 0 }, @@ -121,17 +140,27 @@ function StatusTag({ status }: { status: string }) { return 已暂停 } +function StageTag({ stage }: { stage: TaskStage }) { + const config = stageConfig[stage] + return ( + + {config.label} + + ) +} + export default function AgencyCreatorsPage() { const [searchQuery, setSearchQuery] = useState('') const [showInviteModal, setShowInviteModal] = useState(false) - const [inviteEmail, setInviteEmail] = useState('') - const [inviteLink, setInviteLink] = useState('') + const [inviteCreatorId, setInviteCreatorId] = useState('') + const [inviteResult, setInviteResult] = useState<{ success: boolean; message: string } | null>(null) const [expandedCreators, setExpandedCreators] = useState([]) const [creators, setCreators] = useState(mockCreators) + const [copiedId, setCopiedId] = useState(null) const filteredCreators = creators.filter(creator => creator.name.toLowerCase().includes(searchQuery.toLowerCase()) || - creator.email.toLowerCase().includes(searchQuery.toLowerCase()) + creator.creatorId.toLowerCase().includes(searchQuery.toLowerCase()) ) // 切换展开状态 @@ -143,6 +172,13 @@ export default function AgencyCreatorsPage() { ) } + // 复制达人ID + const handleCopyCreatorId = async (creatorId: string) => { + await navigator.clipboard.writeText(creatorId) + setCopiedId(creatorId) + setTimeout(() => setCopiedId(null), 2000) + } + // 增加申诉次数 const handleAddAppealQuota = (creatorId: string, taskId: string) => { setCreators(prev => prev.map(creator => { @@ -161,25 +197,34 @@ export default function AgencyCreatorsPage() { })) } + // 邀请达人 const handleInvite = () => { - if (!inviteEmail.trim()) { - alert('请输入达人邮箱') + if (!inviteCreatorId.trim()) { + setInviteResult({ success: false, message: '请输入达人ID' }) return } - const link = `https://miaosi.app/invite/creator/${Date.now()}` - setInviteLink(link) + + // 模拟检查达人ID是否存在 + const idPattern = /^CR\d{6}$/ + if (!idPattern.test(inviteCreatorId.toUpperCase())) { + setInviteResult({ success: false, message: '达人ID格式错误,应为CR+6位数字' }) + return + } + + // 检查是否已邀请 + if (creators.some(c => c.creatorId === inviteCreatorId.toUpperCase())) { + setInviteResult({ success: false, message: '该达人已在您的列表中' }) + return + } + + // 模拟发送邀请成功 + setInviteResult({ success: true, message: `已向达人 ${inviteCreatorId.toUpperCase()} 发送邀请` }) } - const handleCopyLink = () => { - navigator.clipboard.writeText(inviteLink) - alert('链接已复制') - } - - const handleSendInvite = () => { - alert(`邀请已发送至 ${inviteEmail}`) + const handleCloseInviteModal = () => { setShowInviteModal(false) - setInviteEmail('') - setInviteLink('') + setInviteCreatorId('') + setInviteResult(null) } return ( @@ -188,7 +233,7 @@ export default function AgencyCreatorsPage() {

达人管理

-

管理合作达人,查看达人绩效数据

+

管理合作达人,查看任务进度和申诉次数

@@ -271,8 +316,8 @@ export default function AgencyCreatorsPage() { 达人 + 达人ID 状态 - 项目数 脚本 视频 通过率 @@ -283,7 +328,7 @@ export default function AgencyCreatorsPage() { {filteredCreators.map((creator) => { const isExpanded = expandedCreators.includes(creator.id) - const hasActiveTasks = creator.tasks.filter(t => t.status === 'in_progress').length > 0 + const hasActiveTasks = creator.tasks.length > 0 return ( <> @@ -306,19 +351,34 @@ export default function AgencyCreatorsPage() { ) : (
)} -
- {creator.name[0]} -
-
-
{creator.name}
-
{creator.email}
+
+ {creator.avatar}
+
{creator.name}
+
+ + +
+ + {creator.creatorId} + +
- {creator.projectCount} {creator.scriptCount.passed} /{creator.scriptCount.total} @@ -347,31 +407,38 @@ export default function AgencyCreatorsPage() { - {/* 展开的任务申诉次数管理区域 */} + {/* 展开的任务列表 */} {isExpanded && hasActiveTasks && (
-
任务申诉次数管理
+
进行中的任务
- {creator.tasks.filter(t => t.status === 'in_progress').map(task => ( -
+ {creator.tasks.map(task => ( +
- {task.name} -
- 剩余: {task.appealRemaining} - | - 已用: {task.appealUsed} +
+
{task.name}
+
项目: {task.projectName}
+ +
+
+
+ 申诉次数: + {task.appealRemaining} + / + 已用 {task.appealUsed} +
+
-
))}
@@ -384,53 +451,71 @@ export default function AgencyCreatorsPage() { })} + + {filteredCreators.length === 0 && ( +
+ +

没有找到匹配的达人

+
+ )} {/* 邀请达人弹窗 */} - { setShowInviteModal(false); setInviteEmail(''); setInviteLink(''); }} title="邀请达人"> +
-

输入达人邮箱,系统将发送邀请链接。

+

+ 输入达人ID邀请合作。达人ID可在达人的个人中心查看。 +

- +
setInviteEmail(e.target.value)} - placeholder="creator@example.com" - className="flex-1 px-4 py-2 border border-border-subtle rounded-lg bg-bg-elevated text-text-primary focus:outline-none focus:ring-2 focus:ring-accent-indigo" + type="text" + value={inviteCreatorId} + onChange={(e) => { + setInviteCreatorId(e.target.value.toUpperCase()) + setInviteResult(null) + }} + placeholder="例如: CR123456" + className="flex-1 px-4 py-2.5 border border-border-subtle rounded-xl bg-bg-elevated text-text-primary font-mono focus:outline-none focus:ring-2 focus:ring-accent-indigo" />
+

达人ID格式:CR + 6位数字

- {inviteLink && ( -
-
- 邀请链接 - -
-

{inviteLink}

+ {inviteResult && ( +
+ {inviteResult.success ? ( + + ) : ( + + )} + + {inviteResult.message} +
)}
- -