'use client' import { useState, useEffect, useCallback } from 'react' import Link from 'next/link' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card' import { Button } from '@/components/ui/Button' import { SuccessTag, PendingTag, WarningTag } from '@/components/ui/Tag' import { FileText, Search, Filter, Clock, CheckCircle, AlertTriangle, ChevronRight, Settings, Loader2 } from 'lucide-react' import { getPlatformInfo } from '@/lib/platforms' import { api } from '@/lib/api' import { USE_MOCK } from '@/contexts/AuthContext' import type { ProjectResponse } from '@/types/project' import type { BriefResponse, SellingPoint, BlacklistWord } from '@/types/brief' // ==================== 本地视图模型 ==================== interface BriefItem { id: string projectId: string projectName: string brandName: string platform: string status: 'configured' | 'pending' uploadedAt: string configuredAt: string | null creatorCount: number sellingPoints: number blacklistWords: number } // ==================== Mock 数据 ==================== const mockBriefs: BriefItem[] = [ { id: 'brief-001', projectId: 'proj-001', projectName: 'XX品牌618推广', brandName: 'XX护肤品牌', platform: 'douyin', status: 'configured', uploadedAt: '2026-02-01', configuredAt: '2026-02-02', creatorCount: 15, sellingPoints: 5, blacklistWords: 12, }, { id: 'brief-002', projectId: 'proj-002', projectName: '新品口红系列', brandName: 'XX美妆品牌', platform: 'xiaohongshu', status: 'pending', uploadedAt: '2026-02-05', configuredAt: null, creatorCount: 0, sellingPoints: 0, blacklistWords: 0, }, { id: 'brief-003', projectId: 'proj-003', projectName: '护肤品秋季活动', brandName: 'XX护肤品牌', platform: 'bilibili', status: 'configured', uploadedAt: '2025-09-15', configuredAt: '2025-09-16', creatorCount: 10, sellingPoints: 4, blacklistWords: 8, }, ] function StatusTag({ status }: { status: string }) { if (status === 'configured') return 已配置 if (status === 'pending') return 待配置 return 处理中 } function BriefsSkeleton() { return (
{[1, 2, 3].map(i => (
))}
) } export default function AgencyBriefsPage() { const [searchQuery, setSearchQuery] = useState('') const [statusFilter, setStatusFilter] = useState('all') const [briefs, setBriefs] = useState([]) const [loading, setLoading] = useState(true) const loadData = useCallback(async () => { if (USE_MOCK) { setBriefs(mockBriefs) setLoading(false) return } try { // 1. 获取所有项目 const projectsData = await api.listProjects(1, 100) const projects = projectsData.items // 2. 对每个项目获取 Brief(并行请求) const briefResults = await Promise.allSettled( projects.map(async (project): Promise => { try { const brief = await api.getBrief(project.id) const hasBrief = !!(brief.selling_points?.length || brief.blacklist_words?.length || brief.brand_tone) return { id: brief.id, projectId: project.id, projectName: project.name, brandName: project.brand_name || '未知品牌', platform: project.platform || 'douyin', status: hasBrief ? 'configured' : 'pending', uploadedAt: project.created_at.split('T')[0], configuredAt: hasBrief ? brief.updated_at.split('T')[0] : null, creatorCount: project.task_count || 0, sellingPoints: brief.selling_points?.length || 0, blacklistWords: brief.blacklist_words?.length || 0, } } catch { // Brief 不存在,标记为待配置 return { id: `no-brief-${project.id}`, projectId: project.id, projectName: project.name, brandName: project.brand_name || '未知品牌', platform: project.platform || 'douyin', status: 'pending', uploadedAt: project.created_at.split('T')[0], configuredAt: null, creatorCount: project.task_count || 0, sellingPoints: 0, blacklistWords: 0, } } }) ) const items: BriefItem[] = briefResults .filter((r): r is PromiseFulfilledResult => r.status === 'fulfilled') .map(r => r.value) setBriefs(items) } catch (err) { console.error('加载 Brief 列表失败:', err) setBriefs([]) } finally { setLoading(false) } }, []) useEffect(() => { loadData() }, [loadData]) if (loading) { return } const filteredBriefs = briefs.filter(brief => { const matchesSearch = brief.projectName.toLowerCase().includes(searchQuery.toLowerCase()) || brief.brandName.toLowerCase().includes(searchQuery.toLowerCase()) const matchesStatus = statusFilter === 'all' || brief.status === statusFilter return matchesSearch && matchesStatus }) const pendingCount = briefs.filter(b => b.status === 'pending').length const configuredCount = briefs.filter(b => b.status === 'configured').length return (
{/* 页面标题 */}

Brief 配置

配置项目 Brief,设置审核规则

{pendingCount} 待配置 {configuredCount} 已配置
{/* 搜索和筛选 */}
setSearchQuery(e.target.value)} className="w-full pl-10 pr-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" />
{/* Brief 列表 */}
{filteredBriefs.map((brief) => { const platform = getPlatformInfo(brief.platform) return ( {/* 平台顶部条 */} {platform && (
{platform.icon} {platform.name}
)}
{brief.status === 'configured' ? ( ) : ( )}

{brief.projectName}

{brief.brandName} 上传于 {brief.uploadedAt}
{brief.status === 'configured' && (
{brief.sellingPoints}
卖点
{brief.blacklistWords}
违禁词
{brief.creatorCount}
达人
)}
) })}
{filteredBriefs.length === 0 && (

暂无匹配的 Brief

)}
) }