- 新增 frontend/lib/platforms.ts 共享平台配置模块 - 支持6个平台: 抖音、小红书、B站、快手、微博、微信视频号 - 品牌方终端: 项目看板、项目详情、终审台列表添加平台显示 - 代理商终端: 工作台概览、审核台、Brief配置、达人管理、 数据报表、消息中心、申诉处理添加平台显示 - 达人端: 任务列表添加平台显示 - 统一使用彩色头部条样式展示平台信息 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
616 lines
25 KiB
TypeScript
616 lines
25 KiB
TypeScript
'use client'
|
||
|
||
import { useState } from 'react'
|
||
import { useRouter, useParams } from 'next/navigation'
|
||
import Link from 'next/link'
|
||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card'
|
||
import { Button } from '@/components/ui/Button'
|
||
import { Input } from '@/components/ui/Input'
|
||
import { Modal } from '@/components/ui/Modal'
|
||
import { SuccessTag, PendingTag, ErrorTag } from '@/components/ui/Tag'
|
||
import {
|
||
ArrowLeft,
|
||
Calendar,
|
||
Users,
|
||
FileText,
|
||
Video,
|
||
Clock,
|
||
CheckCircle,
|
||
XCircle,
|
||
ChevronRight,
|
||
Plus,
|
||
Settings,
|
||
Search,
|
||
Building2,
|
||
MoreHorizontal,
|
||
Trash2,
|
||
Check,
|
||
Pencil
|
||
} from 'lucide-react'
|
||
import { getPlatformInfo } from '@/lib/platforms'
|
||
|
||
// 模拟项目详情数据
|
||
const mockProject = {
|
||
id: 'proj-001',
|
||
name: 'XX品牌618推广',
|
||
platform: 'douyin',
|
||
status: 'active',
|
||
deadline: '2026-06-18',
|
||
createdAt: '2026-02-01',
|
||
description: '618大促活动营销内容审核项目',
|
||
stats: {
|
||
scriptTotal: 20,
|
||
scriptPassed: 15,
|
||
scriptPending: 3,
|
||
scriptRejected: 2,
|
||
videoTotal: 20,
|
||
videoPassed: 12,
|
||
videoPending: 5,
|
||
videoRejected: 3,
|
||
},
|
||
agencies: [
|
||
{ id: 'AG789012', name: '星耀传媒', creatorCount: 8, passRate: 92 },
|
||
{ id: 'AG456789', name: '创意无限', creatorCount: 5, passRate: 88 },
|
||
],
|
||
recentTasks: [
|
||
{ id: 'task-001', type: 'video', creatorName: '小美护肤', agencyId: 'AG789012', agencyName: '星耀传媒', status: 'pending', submittedAt: '2026-02-06 14:30' },
|
||
{ id: 'task-002', type: 'script', creatorName: '美妆Lisa', agencyId: 'AG789012', agencyName: '星耀传媒', status: 'approved', submittedAt: '2026-02-06 12:15' },
|
||
{ id: 'task-003', type: 'video', creatorName: '健身王', agencyId: 'AG456789', agencyName: '创意无限', status: 'rejected', submittedAt: '2026-02-06 10:00' },
|
||
{ id: 'task-004', type: 'script', creatorName: '时尚达人', agencyId: 'AG456789', agencyName: '创意无限', status: 'pending', submittedAt: '2026-02-05 16:45' },
|
||
],
|
||
}
|
||
|
||
// 模拟品牌方已添加的代理商(来自代理商管理)
|
||
const mockManagedAgencies = [
|
||
{ id: 'AG789012', name: '星耀传媒', companyName: '上海星耀文化传媒有限公司' },
|
||
{ id: 'AG456789', name: '创意无限', companyName: '深圳创意无限广告有限公司' },
|
||
{ id: 'AG123456', name: '美妆达人MCN', companyName: '杭州美妆达人网络科技有限公司' },
|
||
{ id: 'AG111111', name: '蓝海科技', companyName: '北京蓝海数字科技有限公司' },
|
||
{ id: 'AG222222', name: '云创网络', companyName: '杭州云创网络技术有限公司' },
|
||
{ id: 'AG333333', name: '天府传媒', companyName: '成都天府传媒集团有限公司' },
|
||
]
|
||
|
||
function StatCard({ title, value, icon: Icon, color }: { title: string; value: number | string; icon: React.ElementType; color: string }) {
|
||
return (
|
||
<Card>
|
||
<CardContent className="py-4">
|
||
<div className="flex items-center justify-between">
|
||
<div>
|
||
<p className="text-sm text-text-secondary">{title}</p>
|
||
<p className={`text-2xl font-bold ${color}`}>{value}</p>
|
||
</div>
|
||
<div className={`w-10 h-10 rounded-lg ${color.replace('text-', 'bg-')}/20 flex items-center justify-center`}>
|
||
<Icon size={20} className={color} />
|
||
</div>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
)
|
||
}
|
||
|
||
function TaskStatusTag({ status }: { status: string }) {
|
||
switch (status) {
|
||
case 'approved': return <SuccessTag>已通过</SuccessTag>
|
||
case 'pending': return <PendingTag>待审核</PendingTag>
|
||
case 'rejected': return <ErrorTag>已驳回</ErrorTag>
|
||
default: return <PendingTag>未知</PendingTag>
|
||
}
|
||
}
|
||
|
||
export default function ProjectDetailPage() {
|
||
const router = useRouter()
|
||
const params = useParams()
|
||
const projectId = params.id as string
|
||
const [project, setProject] = useState(mockProject)
|
||
|
||
// 添加代理商相关状态
|
||
const [showAddModal, setShowAddModal] = useState(false)
|
||
const [searchQuery, setSearchQuery] = useState('')
|
||
const [selectedAgencies, setSelectedAgencies] = useState<string[]>([])
|
||
|
||
// 代理商操作菜单
|
||
const [activeAgencyMenu, setActiveAgencyMenu] = useState<string | null>(null)
|
||
|
||
// 删除确认
|
||
const [showDeleteModal, setShowDeleteModal] = useState(false)
|
||
const [agencyToDelete, setAgencyToDelete] = useState<typeof project.agencies[0] | null>(null)
|
||
|
||
// 编辑截止日期
|
||
const [showDeadlineModal, setShowDeadlineModal] = useState(false)
|
||
const [newDeadline, setNewDeadline] = useState(project.deadline)
|
||
|
||
// 保存截止日期
|
||
const handleSaveDeadline = () => {
|
||
if (!newDeadline) return
|
||
setProject({ ...project, deadline: newDeadline })
|
||
setShowDeadlineModal(false)
|
||
}
|
||
|
||
const scriptPassRate = Math.round((project.stats.scriptPassed / project.stats.scriptTotal) * 100)
|
||
const videoPassRate = Math.round((project.stats.videoPassed / project.stats.videoTotal) * 100)
|
||
|
||
// 过滤可添加的代理商(排除已在项目中的)
|
||
const availableAgencies = mockManagedAgencies.filter(
|
||
agency => !project.agencies.some(a => a.id === agency.id)
|
||
)
|
||
|
||
// 搜索过滤
|
||
const filteredAgencies = availableAgencies.filter(agency =>
|
||
searchQuery === '' ||
|
||
agency.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||
agency.id.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||
agency.companyName.toLowerCase().includes(searchQuery.toLowerCase())
|
||
)
|
||
|
||
// 切换选择
|
||
const toggleSelectAgency = (agencyId: string) => {
|
||
setSelectedAgencies(prev =>
|
||
prev.includes(agencyId)
|
||
? prev.filter(id => id !== agencyId)
|
||
: [...prev, agencyId]
|
||
)
|
||
}
|
||
|
||
// 确认添加
|
||
const handleAddAgencies = () => {
|
||
const newAgencies = mockManagedAgencies
|
||
.filter(a => selectedAgencies.includes(a.id))
|
||
.map(a => ({ id: a.id, name: a.name, creatorCount: 0, passRate: 0 }))
|
||
|
||
setProject({
|
||
...project,
|
||
agencies: [...project.agencies, ...newAgencies]
|
||
})
|
||
|
||
setShowAddModal(false)
|
||
setSelectedAgencies([])
|
||
setSearchQuery('')
|
||
}
|
||
|
||
// 移除代理商
|
||
const handleRemoveAgency = async () => {
|
||
if (!agencyToDelete) return
|
||
|
||
setProject({
|
||
...project,
|
||
agencies: project.agencies.filter(a => a.id !== agencyToDelete.id)
|
||
})
|
||
setShowDeleteModal(false)
|
||
setAgencyToDelete(null)
|
||
}
|
||
|
||
const platform = getPlatformInfo(project.platform)
|
||
|
||
return (
|
||
<div className="space-y-6">
|
||
{/* 顶部导航 */}
|
||
<div className="flex items-center gap-4">
|
||
<button type="button" onClick={() => router.back()} className="p-2 hover:bg-bg-elevated rounded-full">
|
||
<ArrowLeft size={20} className="text-text-primary" />
|
||
</button>
|
||
<div className="flex-1">
|
||
<div className="flex items-center gap-3">
|
||
<h1 className="text-2xl font-bold text-text-primary">{project.name}</h1>
|
||
{platform && (
|
||
<span className={`inline-flex items-center gap-1.5 px-2.5 py-1 rounded-lg text-xs font-medium ${platform.bgColor} ${platform.textColor} border ${platform.borderColor}`}>
|
||
<span>{platform.icon}</span>
|
||
{platform.name}
|
||
</span>
|
||
)}
|
||
</div>
|
||
<p className="text-sm text-text-secondary">{project.description}</p>
|
||
</div>
|
||
<SuccessTag>进行中</SuccessTag>
|
||
</div>
|
||
|
||
{/* 项目信息 */}
|
||
<div className="flex items-center gap-6 text-sm text-text-secondary">
|
||
<span className="flex items-center gap-2">
|
||
<Calendar size={16} />
|
||
截止日期: {project.deadline}
|
||
<button
|
||
type="button"
|
||
onClick={() => {
|
||
setNewDeadline(project.deadline)
|
||
setShowDeadlineModal(true)
|
||
}}
|
||
className="p-1 rounded hover:bg-bg-elevated transition-colors"
|
||
title="修改截止日期"
|
||
>
|
||
<Pencil size={14} className="text-text-tertiary hover:text-accent-indigo" />
|
||
</button>
|
||
</span>
|
||
<span className="flex items-center gap-2">
|
||
<Clock size={16} />
|
||
创建时间: {project.createdAt}
|
||
</span>
|
||
</div>
|
||
|
||
{/* Brief和规则配置 - 大按钮 */}
|
||
<Link href={`/brand/projects/${projectId}/config`}>
|
||
<Card className="hover:border-accent-indigo transition-colors cursor-pointer">
|
||
<CardContent className="py-5">
|
||
<div className="flex items-center justify-between">
|
||
<div className="flex items-center gap-4">
|
||
<div className="w-12 h-12 rounded-xl bg-accent-indigo/15 flex items-center justify-center">
|
||
<Settings size={24} className="text-accent-indigo" />
|
||
</div>
|
||
<div>
|
||
<p className="font-semibold text-text-primary">Brief和规则配置</p>
|
||
<p className="text-sm text-text-secondary">配置项目Brief、审核规则、AI检测项等</p>
|
||
</div>
|
||
</div>
|
||
<ChevronRight size={20} className="text-text-tertiary" />
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</Link>
|
||
|
||
{/* 统计卡片 */}
|
||
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||
<StatCard title="脚本通过率" value={`${scriptPassRate}%`} icon={FileText} color="text-accent-green" />
|
||
<StatCard title="视频通过率" value={`${videoPassRate}%`} icon={Video} color="text-accent-indigo" />
|
||
<StatCard title="参与代理商" value={project.agencies.length} icon={Users} color="text-purple-400" />
|
||
<StatCard title="待审核任务" value={project.stats.scriptPending + project.stats.videoPending} icon={Clock} color="text-orange-400" />
|
||
</div>
|
||
|
||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||
{/* 审核进度 */}
|
||
<Card className="lg:col-span-2">
|
||
<CardHeader>
|
||
<CardTitle>审核进度</CardTitle>
|
||
</CardHeader>
|
||
<CardContent className="space-y-6">
|
||
{/* 脚本审核 */}
|
||
<div>
|
||
<div className="flex items-center justify-between mb-3">
|
||
<span className="flex items-center gap-2 text-text-primary font-medium">
|
||
<FileText size={16} />
|
||
脚本审核
|
||
</span>
|
||
<span className="text-sm text-text-secondary">
|
||
{project.stats.scriptPassed}/{project.stats.scriptTotal} 已通过
|
||
</span>
|
||
</div>
|
||
<div className="flex h-4 rounded-full overflow-hidden bg-bg-elevated">
|
||
<div className="bg-accent-green" style={{ width: `${(project.stats.scriptPassed / project.stats.scriptTotal) * 100}%` }} />
|
||
<div className="bg-yellow-500" style={{ width: `${(project.stats.scriptPending / project.stats.scriptTotal) * 100}%` }} />
|
||
<div className="bg-accent-coral" style={{ width: `${(project.stats.scriptRejected / project.stats.scriptTotal) * 100}%` }} />
|
||
</div>
|
||
<div className="flex gap-6 mt-2 text-xs">
|
||
<span className="flex items-center gap-1 text-accent-green">
|
||
<CheckCircle size={12} /> 通过 {project.stats.scriptPassed}
|
||
</span>
|
||
<span className="flex items-center gap-1 text-yellow-500">
|
||
<Clock size={12} /> 待审 {project.stats.scriptPending}
|
||
</span>
|
||
<span className="flex items-center gap-1 text-accent-coral">
|
||
<XCircle size={12} /> 驳回 {project.stats.scriptRejected}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 视频审核 */}
|
||
<div>
|
||
<div className="flex items-center justify-between mb-3">
|
||
<span className="flex items-center gap-2 text-text-primary font-medium">
|
||
<Video size={16} />
|
||
视频审核
|
||
</span>
|
||
<span className="text-sm text-text-secondary">
|
||
{project.stats.videoPassed}/{project.stats.videoTotal} 已通过
|
||
</span>
|
||
</div>
|
||
<div className="flex h-4 rounded-full overflow-hidden bg-bg-elevated">
|
||
<div className="bg-accent-green" style={{ width: `${(project.stats.videoPassed / project.stats.videoTotal) * 100}%` }} />
|
||
<div className="bg-yellow-500" style={{ width: `${(project.stats.videoPending / project.stats.videoTotal) * 100}%` }} />
|
||
<div className="bg-accent-coral" style={{ width: `${(project.stats.videoRejected / project.stats.videoTotal) * 100}%` }} />
|
||
</div>
|
||
<div className="flex gap-6 mt-2 text-xs">
|
||
<span className="flex items-center gap-1 text-accent-green">
|
||
<CheckCircle size={12} /> 通过 {project.stats.videoPassed}
|
||
</span>
|
||
<span className="flex items-center gap-1 text-yellow-500">
|
||
<Clock size={12} /> 待审 {project.stats.videoPending}
|
||
</span>
|
||
<span className="flex items-center gap-1 text-accent-coral">
|
||
<XCircle size={12} /> 驳回 {project.stats.videoRejected}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* 代理商列表 */}
|
||
<Card>
|
||
<CardHeader>
|
||
<CardTitle className="flex items-center gap-2">
|
||
<Users size={16} />
|
||
参与代理商
|
||
<span className="text-sm font-normal text-text-tertiary">({project.agencies.length})</span>
|
||
</CardTitle>
|
||
</CardHeader>
|
||
<CardContent className="space-y-2">
|
||
{project.agencies.map((agency) => (
|
||
<div key={agency.id} className="flex items-center justify-between p-3 rounded-lg bg-bg-elevated">
|
||
<div className="flex items-center gap-3">
|
||
<div className="w-9 h-9 rounded-lg bg-accent-indigo/15 flex items-center justify-center">
|
||
<Building2 size={18} className="text-accent-indigo" />
|
||
</div>
|
||
<div>
|
||
<p className="font-medium text-text-primary text-sm">{agency.name}</p>
|
||
<p className="text-xs text-text-tertiary">{agency.creatorCount} 位达人 · 通过率 {agency.passRate}%</p>
|
||
</div>
|
||
</div>
|
||
<div className="relative">
|
||
<button
|
||
type="button"
|
||
onClick={() => setActiveAgencyMenu(activeAgencyMenu === agency.id ? null : agency.id)}
|
||
className="p-1.5 rounded hover:bg-bg-page transition-colors"
|
||
>
|
||
<MoreHorizontal size={16} className="text-text-tertiary" />
|
||
</button>
|
||
{activeAgencyMenu === agency.id && (
|
||
<div className="absolute right-0 top-8 z-10 w-32 py-1 bg-bg-card rounded-lg shadow-lg border border-border-subtle">
|
||
<button
|
||
type="button"
|
||
onClick={() => {
|
||
setAgencyToDelete(agency)
|
||
setShowDeleteModal(true)
|
||
setActiveAgencyMenu(null)
|
||
}}
|
||
className="w-full px-3 py-2 text-left text-sm text-accent-coral hover:bg-bg-elevated flex items-center gap-2"
|
||
>
|
||
<Trash2 size={14} />
|
||
移除
|
||
</button>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
))}
|
||
|
||
{/* 添加代理商按钮 */}
|
||
<button
|
||
type="button"
|
||
onClick={() => setShowAddModal(true)}
|
||
className="w-full p-3 rounded-lg border-2 border-dashed border-border-subtle hover:border-accent-indigo hover:bg-accent-indigo/5 transition-all flex items-center justify-center gap-2 text-text-tertiary hover:text-accent-indigo"
|
||
>
|
||
<Plus size={18} />
|
||
<span className="text-sm font-medium">添加代理商</span>
|
||
</button>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
|
||
{/* 最近任务 */}
|
||
<Card>
|
||
<CardHeader>
|
||
<CardTitle className="flex items-center justify-between">
|
||
<span>最近提交</span>
|
||
<Link href="/brand/review">
|
||
<Button variant="ghost" size="sm">
|
||
查看全部 <ChevronRight size={16} />
|
||
</Button>
|
||
</Link>
|
||
</CardTitle>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<div className="overflow-x-auto">
|
||
<table className="w-full">
|
||
<thead>
|
||
<tr className="border-b border-border-subtle text-left text-sm text-text-secondary">
|
||
<th className="pb-3 font-medium">类型</th>
|
||
<th className="pb-3 font-medium">达人</th>
|
||
<th className="pb-3 font-medium">所属代理商</th>
|
||
<th className="pb-3 font-medium">状态</th>
|
||
<th className="pb-3 font-medium">提交时间</th>
|
||
<th className="pb-3 font-medium">操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{project.recentTasks.map((task) => (
|
||
<tr key={task.id} className="border-b border-border-subtle last:border-0 hover:bg-bg-elevated">
|
||
<td className="py-4">
|
||
<span className="flex items-center gap-2">
|
||
{task.type === 'script' ? <FileText size={16} className="text-accent-indigo" /> : <Video size={16} className="text-purple-400" />}
|
||
{task.type === 'script' ? '脚本' : '视频'}
|
||
</span>
|
||
</td>
|
||
<td className="py-4 text-text-primary">{task.creatorName}</td>
|
||
<td className="py-4">
|
||
<span className="inline-flex items-center gap-1.5 px-2 py-1 rounded-md bg-bg-elevated text-sm">
|
||
<Building2 size={14} className="text-accent-indigo" />
|
||
<span className="text-text-secondary">{task.agencyName}</span>
|
||
</span>
|
||
</td>
|
||
<td className="py-4"><TaskStatusTag status={task.status} /></td>
|
||
<td className="py-4 text-sm text-text-tertiary">{task.submittedAt}</td>
|
||
<td className="py-4">
|
||
<Link href={`/brand/review/${task.type}/${task.id}`}>
|
||
<Button size="sm" variant={task.status === 'pending' ? 'primary' : 'secondary'}>
|
||
{task.status === 'pending' ? '审核' : '查看'}
|
||
</Button>
|
||
</Link>
|
||
</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* 添加代理商弹窗 */}
|
||
<Modal
|
||
isOpen={showAddModal}
|
||
onClose={() => {
|
||
setShowAddModal(false)
|
||
setSearchQuery('')
|
||
setSelectedAgencies([])
|
||
}}
|
||
title="添加代理商"
|
||
size="lg"
|
||
>
|
||
<div className="space-y-4">
|
||
{/* 搜索框 */}
|
||
<div className="relative">
|
||
<Search size={18} className="absolute left-3 top-1/2 -translate-y-1/2 text-text-tertiary" />
|
||
<Input
|
||
value={searchQuery}
|
||
onChange={(e) => setSearchQuery(e.target.value)}
|
||
placeholder="搜索代理商名称或ID..."
|
||
className="pl-10"
|
||
/>
|
||
</div>
|
||
|
||
{/* 代理商列表 */}
|
||
<div className="max-h-80 overflow-y-auto space-y-2">
|
||
{filteredAgencies.length > 0 ? (
|
||
filteredAgencies.map((agency) => {
|
||
const isSelected = selectedAgencies.includes(agency.id)
|
||
return (
|
||
<button
|
||
key={agency.id}
|
||
type="button"
|
||
onClick={() => toggleSelectAgency(agency.id)}
|
||
className={`w-full flex items-center gap-3 p-3 rounded-xl border-2 transition-all text-left ${
|
||
isSelected
|
||
? 'border-accent-indigo bg-accent-indigo/5'
|
||
: 'border-transparent bg-bg-elevated hover:bg-bg-page'
|
||
}`}
|
||
>
|
||
<div className={`w-10 h-10 rounded-lg flex items-center justify-center ${
|
||
isSelected ? 'bg-accent-indigo' : 'bg-accent-indigo/15'
|
||
}`}>
|
||
{isSelected ? (
|
||
<Check size={20} className="text-white" />
|
||
) : (
|
||
<Building2 size={20} className="text-accent-indigo" />
|
||
)}
|
||
</div>
|
||
<div className="flex-1 min-w-0">
|
||
<div className="flex items-center gap-2">
|
||
<p className="font-medium text-text-primary">{agency.name}</p>
|
||
<span className="text-xs text-text-tertiary font-mono">{agency.id}</span>
|
||
</div>
|
||
<p className="text-sm text-text-secondary truncate">{agency.companyName}</p>
|
||
</div>
|
||
</button>
|
||
)
|
||
})
|
||
) : (
|
||
<div className="text-center py-8 text-text-tertiary">
|
||
{availableAgencies.length === 0 ? (
|
||
<>
|
||
<Users size={32} className="mx-auto mb-2 opacity-50" />
|
||
<p>所有代理商都已添加到此项目</p>
|
||
</>
|
||
) : (
|
||
<>
|
||
<Search size={32} className="mx-auto mb-2 opacity-50" />
|
||
<p>未找到匹配的代理商</p>
|
||
</>
|
||
)}
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{/* 已选择提示 */}
|
||
{selectedAgencies.length > 0 && (
|
||
<div className="flex items-center justify-between pt-3 border-t border-border-subtle">
|
||
<span className="text-sm text-text-secondary">
|
||
已选择 <span className="text-accent-indigo font-medium">{selectedAgencies.length}</span> 个代理商
|
||
</span>
|
||
<Button variant="primary" onClick={handleAddAgencies}>
|
||
<Plus size={16} />
|
||
确认添加
|
||
</Button>
|
||
</div>
|
||
)}
|
||
|
||
{/* 底部提示 */}
|
||
<p className="text-xs text-text-tertiary pt-2">
|
||
仅显示已在"代理商管理"中添加的代理商,如需添加新代理商请先前往代理商管理
|
||
</p>
|
||
</div>
|
||
</Modal>
|
||
|
||
{/* 删除确认弹窗 */}
|
||
<Modal
|
||
isOpen={showDeleteModal}
|
||
onClose={() => { setShowDeleteModal(false); setAgencyToDelete(null) }}
|
||
title="移除代理商"
|
||
>
|
||
<div className="space-y-4">
|
||
<p className="text-text-secondary">
|
||
确定要将 <span className="text-text-primary font-medium">{agencyToDelete?.name}</span> 从此项目中移除吗?
|
||
</p>
|
||
<p className="text-sm text-accent-coral">
|
||
移除后,该代理商下的达人将无法继续参与此项目的任务。
|
||
</p>
|
||
<div className="flex gap-3">
|
||
<Button variant="secondary" className="flex-1" onClick={() => { setShowDeleteModal(false); setAgencyToDelete(null) }}>
|
||
取消
|
||
</Button>
|
||
<Button
|
||
variant="primary"
|
||
className="flex-1 bg-accent-coral hover:bg-accent-coral/80"
|
||
onClick={handleRemoveAgency}
|
||
>
|
||
确认移除
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</Modal>
|
||
|
||
{/* 编辑截止日期弹窗 */}
|
||
<Modal
|
||
isOpen={showDeadlineModal}
|
||
onClose={() => setShowDeadlineModal(false)}
|
||
title="修改截止日期"
|
||
>
|
||
<div className="space-y-4">
|
||
<div className="p-3 rounded-lg bg-bg-elevated">
|
||
<p className="text-sm text-text-secondary">项目名称</p>
|
||
<p className="font-medium text-text-primary">{project.name}</p>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="block text-sm font-medium text-text-primary mb-2">
|
||
新截止日期
|
||
</label>
|
||
<div className="relative">
|
||
<Calendar size={18} className="absolute left-4 top-1/2 -translate-y-1/2 text-text-tertiary" />
|
||
<input
|
||
type="date"
|
||
value={newDeadline}
|
||
onChange={(e) => setNewDeadline(e.target.value)}
|
||
className="w-full pl-12 pr-4 py-3 border border-border-subtle rounded-lg bg-bg-elevated text-text-primary focus:outline-none focus:ring-2 focus:ring-accent-indigo"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="flex gap-3 pt-2">
|
||
<Button
|
||
variant="secondary"
|
||
className="flex-1"
|
||
onClick={() => setShowDeadlineModal(false)}
|
||
>
|
||
取消
|
||
</Button>
|
||
<Button
|
||
variant="primary"
|
||
className="flex-1"
|
||
onClick={handleSaveDeadline}
|
||
disabled={!newDeadline}
|
||
>
|
||
保存
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</Modal>
|
||
</div>
|
||
)
|
||
}
|