feat: 完善品牌方和代理商前端功能
品牌方功能: - 项目看板: 添加截止日期编辑功能 - 项目详情: 添加代理商管理、截止日期编辑、最近任务显示代理商 - 项目创建: 代理商选择支持搜索(名称/ID/公司名) - 代理商管理: 通过ID邀请、添加备注/分配项目/移除操作 - Brief配置: 新增项目级Brief和规则配置页面 - 系统设置: 完善账户安全(密码/2FA/邮箱/手机/设备管理)、数据导出、退出登录 代理商功能: - 个人中心: 新增代理商ID展示、公司信息(企业验证)、个人信息编辑 - 账户设置: 密码修改、手机/邮箱绑定、两步验证 - 通知设置: 分类型和渠道的通知开关 - 审核历史: 搜索筛选和统计展示 - 帮助反馈: FAQ分类搜索和客服联系 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.5
parent
ae74c515c7
commit
964797d2e9
@@ -12,15 +12,19 @@ import {
|
||||
FileText,
|
||||
CheckCircle,
|
||||
X,
|
||||
Users
|
||||
Users,
|
||||
Search,
|
||||
Building2
|
||||
} from 'lucide-react'
|
||||
|
||||
// 模拟代理商列表
|
||||
// 模拟品牌方已添加的代理商(来自代理商管理)
|
||||
const mockAgencies = [
|
||||
{ id: 'agency-001', name: '星耀传媒', creatorCount: 50, passRate: 92 },
|
||||
{ id: 'agency-002', name: '创意无限', creatorCount: 35, passRate: 88 },
|
||||
{ id: 'agency-003', name: '美妆达人MCN', creatorCount: 28, passRate: 82 },
|
||||
{ id: 'agency-004', name: '时尚风向标', creatorCount: 42, passRate: 85 },
|
||||
{ id: 'AG789012', name: '星耀传媒', companyName: '上海星耀文化传媒有限公司', creatorCount: 50, passRate: 92 },
|
||||
{ id: 'AG456789', name: '创意无限', companyName: '深圳创意无限广告有限公司', creatorCount: 35, passRate: 88 },
|
||||
{ id: 'AG123456', name: '美妆达人MCN', companyName: '杭州美妆达人网络科技有限公司', creatorCount: 28, passRate: 82 },
|
||||
{ id: 'AG111111', name: '蓝海科技', companyName: '北京蓝海数字科技有限公司', creatorCount: 42, passRate: 85 },
|
||||
{ id: 'AG222222', name: '云创网络', companyName: '杭州云创网络技术有限公司', creatorCount: 30, passRate: 90 },
|
||||
{ id: 'AG333333', name: '天府传媒', companyName: '成都天府传媒集团有限公司', creatorCount: 25, passRate: 87 },
|
||||
]
|
||||
|
||||
export default function CreateProjectPage() {
|
||||
@@ -30,6 +34,15 @@ export default function CreateProjectPage() {
|
||||
const [briefFile, setBriefFile] = useState<File | null>(null)
|
||||
const [selectedAgencies, setSelectedAgencies] = useState<string[]>([])
|
||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||
const [agencySearch, setAgencySearch] = useState('')
|
||||
|
||||
// 搜索过滤代理商
|
||||
const filteredAgencies = mockAgencies.filter(agency =>
|
||||
agencySearch === '' ||
|
||||
agency.name.toLowerCase().includes(agencySearch.toLowerCase()) ||
|
||||
agency.id.toLowerCase().includes(agencySearch.toLowerCase()) ||
|
||||
agency.companyName.toLowerCase().includes(agencySearch.toLowerCase())
|
||||
)
|
||||
|
||||
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = e.target.files?.[0]
|
||||
@@ -145,41 +158,76 @@ export default function CreateProjectPage() {
|
||||
已选择 {selectedAgencies.length} 个
|
||||
</span>
|
||||
</label>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
{mockAgencies.map((agency) => {
|
||||
const isSelected = selectedAgencies.includes(agency.id)
|
||||
return (
|
||||
<button
|
||||
key={agency.id}
|
||||
type="button"
|
||||
onClick={() => toggleAgency(agency.id)}
|
||||
className={`p-4 rounded-lg border-2 text-left transition-all ${
|
||||
isSelected
|
||||
? 'border-accent-indigo bg-accent-indigo/10'
|
||||
: 'border-border-subtle hover:border-accent-indigo/50'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-start justify-between">
|
||||
<div>
|
||||
<div className="font-medium text-text-primary">{agency.name}</div>
|
||||
<div className="flex items-center gap-4 mt-1 text-sm text-text-secondary">
|
||||
<span className="flex items-center gap-1">
|
||||
<Users size={14} />
|
||||
{agency.creatorCount} 达人
|
||||
</span>
|
||||
<span className={agency.passRate >= 90 ? 'text-accent-green' : agency.passRate >= 80 ? 'text-accent-indigo' : 'text-orange-400'}>
|
||||
通过率 {agency.passRate}%
|
||||
</span>
|
||||
|
||||
{/* 搜索框 */}
|
||||
<div className="relative mb-4">
|
||||
<Search size={18} className="absolute left-4 top-1/2 -translate-y-1/2 text-text-tertiary" />
|
||||
<input
|
||||
type="text"
|
||||
value={agencySearch}
|
||||
onChange={(e) => setAgencySearch(e.target.value)}
|
||||
placeholder="搜索代理商名称、ID或公司名..."
|
||||
className="w-full pl-11 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 className="grid grid-cols-1 md:grid-cols-2 gap-3 max-h-80 overflow-y-auto">
|
||||
{filteredAgencies.length > 0 ? (
|
||||
filteredAgencies.map((agency) => {
|
||||
const isSelected = selectedAgencies.includes(agency.id)
|
||||
return (
|
||||
<button
|
||||
key={agency.id}
|
||||
type="button"
|
||||
onClick={() => toggleAgency(agency.id)}
|
||||
className={`p-4 rounded-xl border-2 text-left transition-all ${
|
||||
isSelected
|
||||
? 'border-accent-indigo bg-accent-indigo/10'
|
||||
: 'border-border-subtle hover:border-accent-indigo/50'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-start gap-3">
|
||||
<div className={`w-10 h-10 rounded-lg flex items-center justify-center flex-shrink-0 ${
|
||||
isSelected ? 'bg-accent-indigo' : 'bg-accent-indigo/15'
|
||||
}`}>
|
||||
{isSelected ? (
|
||||
<CheckCircle 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">
|
||||
<span className="font-medium text-text-primary">{agency.name}</span>
|
||||
<span className="text-xs text-text-tertiary font-mono">{agency.id}</span>
|
||||
</div>
|
||||
<p className="text-sm text-text-secondary truncate mt-0.5">{agency.companyName}</p>
|
||||
<div className="flex items-center gap-4 mt-1.5 text-xs text-text-tertiary">
|
||||
<span className="flex items-center gap-1">
|
||||
<Users size={12} />
|
||||
{agency.creatorCount} 达人
|
||||
</span>
|
||||
<span className={agency.passRate >= 90 ? 'text-accent-green' : agency.passRate >= 80 ? 'text-accent-indigo' : 'text-orange-400'}>
|
||||
通过率 {agency.passRate}%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{isSelected && (
|
||||
<CheckCircle size={20} className="text-accent-indigo" />
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
</button>
|
||||
)
|
||||
})
|
||||
) : (
|
||||
<div className="col-span-2 text-center py-8 text-text-tertiary">
|
||||
<Search size={32} className="mx-auto mb-2 opacity-50" />
|
||||
<p>未找到匹配的代理商</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<p className="text-xs text-text-tertiary mt-3">
|
||||
仅显示已在"代理商管理"中添加的代理商
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* 操作按钮 */}
|
||||
|
||||
Reference in New Issue
Block a user