Files
deerflow-code/web-code/pages/FinalPlan.tsx
T
2026-05-28 18:29:37 +08:00

530 lines
26 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useState } from 'react';
import { useTheme } from '../contexts/ThemeContext';
import { PageType } from '../components/Sidebar';
import {
FileText,
Download,
Printer,
RefreshCw,
ArrowLeft,
ChevronRight,
Target,
Users,
TrendingUp,
MessageSquare,
Megaphone,
Shield,
BarChart3,
Link2,
Clock,
AlertTriangle,
CheckCircle,
XCircle,
History,
FileUp,
Send,
Eye,
} from 'lucide-react';
interface FinalPlanProps {
onNavigate: (page: PageType) => void;
}
const FinalPlan: React.FC<FinalPlanProps> = ({ onNavigate }) => {
const { theme } = useTheme();
const isDark = theme === 'dark';
// 主题颜色类
const cardBg = isDark ? 'bg-slate-800/30' : 'bg-white';
const cardBorder = isDark ? 'border-blue-800/30' : 'border-red-200';
const textPrimary = isDark ? 'text-white' : 'text-gray-900';
const textSecondary = isDark ? 'text-slate-400' : 'text-gray-600';
const textMuted = isDark ? 'text-slate-500' : 'text-gray-500';
const btnSecondary = isDark ? 'bg-slate-700/50 hover:bg-slate-600/50 border-blue-800/30 text-slate-300' : 'bg-gray-100 hover:bg-gray-200 border-gray-300 text-gray-700';
const btnPrimary = isDark ? 'bg-blue-600 hover:bg-blue-500' : 'bg-red-600 hover:bg-red-500';
const inputBg = isDark ? 'bg-slate-900/50' : 'bg-gray-50';
const inputBorder = isDark ? 'border-blue-800/30' : 'border-gray-300';
const [activeSection, setActiveSection] = useState('background');
const [reviewStatus, setReviewStatus] = useState<'draft' | 'pending' | 'approved' | 'rejected'>('pending');
const [showVersionHistory, setShowVersionHistory] = useState(false);
// 版本历史数据
const versionHistory = [
{ version: 'V3', date: '2026-03-19 16:00', author: '张策略', changes: '完成驱动分析与叙事策略优化' },
{ version: 'V2', date: '2026-03-19 14:30', author: '李智能', changes: '修正受众细分,补充渠道安排' },
{ version: 'V1', date: '2026-03-19 10:00', author: '张策略', changes: '初始版本生成' },
];
const sections = [
{ id: 'background', label: '一、任务背景', icon: FileText },
{ id: 'goal', label: '二、宣传目标', icon: Target },
{ id: 'audience', label: '三、目标受众', icon: Users },
{ id: 'behavior', label: '四、预期行为', icon: TrendingUp },
{ id: 'driver', label: '五、驱动因素', icon: MessageSquare },
{ id: 'narrative', label: '六、叙事策略', icon: Megaphone },
{ id: 'channel', label: '七、渠道安排', icon: Link2 },
{ id: 'risk', label: '八、风险控制', icon: Shield },
{ id: 'evaluation', label: '九、效果评估', icon: BarChart3 },
];
return (
<div className="space-y-6">
{/* 顶部操作栏 */}
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-4`}>
<div className="flex items-center justify-between">
<div className="flex items-center gap-4">
<button
onClick={() => onNavigate('strategy-result')}
className={`flex items-center gap-2 px-3 py-2 ${btnSecondary} rounded-lg text-sm transition-colors`}
>
<ArrowLeft className="w-4 h-4" />
返回
</button>
<div className={`h-8 w-px ${isDark ? 'bg-blue-800/30' : 'bg-gray-200'}`} />
<div>
<h1 className={`${textPrimary} font-bold text-lg`}>五四青年节宣传活动策略方案</h1>
<p className={`${textSecondary} text-sm`}>最终版方案 · V3 · 2026-03-19</p>
</div>
</div>
<div className="flex items-center gap-4">
{/* 审核状态 */}
<div className="flex items-center gap-2">
<span className={`${textSecondary} text-sm`}>审核状态:</span>
<div className={`flex items-center gap-1.5 px-3 py-1.5 rounded-full text-sm font-medium ${
reviewStatus === 'approved'
? 'bg-green-500/20 text-green-400'
: reviewStatus === 'pending'
? 'bg-yellow-500/20 text-yellow-400'
: reviewStatus === 'rejected'
? 'bg-red-500/20 text-red-400'
: `${inputBg} ${textSecondary}`
}`}>
{reviewStatus === 'approved' ? (
<><CheckCircle className="w-4 h-4" /> 已通过</>
) : reviewStatus === 'pending' ? (
<><Clock className="w-4 h-4" /> 审核中</>
) : reviewStatus === 'rejected' ? (
<><XCircle className="w-4 h-4" /> 未通过</>
) : (
<><FileText className="w-4 h-4" /> 草稿</>
)}
</div>
</div>
{/* 版本历史按钮 */}
<button
onClick={() => setShowVersionHistory(!showVersionHistory)}
className={`flex items-center gap-2 px-3 py-2 ${btnSecondary} rounded-lg text-sm transition-colors`}
>
<History className="w-4 h-4" />
版本历史
</button>
<div className={`h-8 w-px ${isDark ? 'bg-blue-800/30' : 'bg-gray-200'}`} />
<button className={`flex items-center gap-2 px-4 py-2.5 ${btnSecondary} rounded-lg text-sm transition-colors`}>
<Printer className="w-4 h-4" />
打印
</button>
<button className={`flex items-center gap-2 px-4 py-2.5 ${btnSecondary} rounded-lg text-sm transition-colors`}>
<Download className="w-4 h-4" />
导出Word
</button>
<button className={`flex items-center gap-2 px-4 py-2.5 ${btnSecondary} rounded-lg text-sm transition-colors`}>
<Download className="w-4 h-4" />
导出PDF
</button>
<button className={`flex items-center gap-2 px-4 py-2.5 ${btnPrimary} text-white rounded-lg text-sm transition-colors`}>
<FileUp className="w-4 h-4" />
导出汇报提纲
</button>
{/* 审核操作 */}
{reviewStatus === 'pending' ? (
<div className="flex items-center gap-2">
<button
onClick={() => setReviewStatus('approved')}
className={`flex items-center gap-2 px-4 py-2.5 ${btnPrimary} text-white rounded-lg text-sm transition-colors`}
>
<CheckCircle className="w-4 h-4" />
通过
</button>
<button
onClick={() => setReviewStatus('rejected')}
className="flex items-center gap-2 px-4 py-2.5 bg-red-600/20 hover:bg-red-600/30 border border-red-500/30 text-red-400 rounded-lg text-sm transition-colors"
>
<XCircle className="w-4 h-4" />
驳回
</button>
</div>
) : reviewStatus === 'draft' ? (
<button className={`flex items-center gap-2 px-4 py-2.5 ${btnPrimary} text-white rounded-lg text-sm transition-colors`}>
<Send className="w-4 h-4" />
提交审核
</button>
) : (
<button className={`flex items-center gap-2 px-4 py-2.5 ${btnPrimary} text-white rounded-lg text-sm transition-colors`}>
<RefreshCw className="w-4 h-4" />
发起修订
</button>
)}
</div>
</div>
{/* 版本历史面板 */}
{showVersionHistory && (
<div className={`mt-4 pt-4 border-t ${cardBorder}`}>
<div className="grid grid-cols-3 gap-4">
{versionHistory.map((v, i) => (
<div
key={v.version}
className={`p-4 rounded-lg border ${
i === 0
? 'bg-blue-500/10 border-blue-500/30'
: `${inputBg} ${cardBorder}`
}`}
>
<div className="flex items-center justify-between mb-2">
<span className={`text-sm font-bold ${
i === 0 ? 'text-blue-400' : textSecondary
}`}>
{v.version}
</span>
{i === 0 && (
<span className="px-2 py-0.5 bg-blue-500/20 text-blue-400 rounded text-xs">
当前
</span>
)}
</div>
<p className={`${textSecondary} text-xs mb-1`}>{v.date}</p>
<p className={`${textPrimary} text-sm`}>{v.changes}</p>
<p className={`${textMuted} text-xs mt-1`}>作者:{v.author}</p>
</div>
))}
</div>
</div>
)}
</div>
<div className="grid grid-cols-4 gap-6">
{/* 左侧导航目录 (20%) */}
<div className="col-span-1">
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-4 sticky top-6`}>
<h3 className={`${textPrimary} font-semibold mb-4`}>目录导航</h3>
<nav className="space-y-1">
{sections.map((section) => (
<button
key={section.id}
onClick={() => setActiveSection(section.id)}
className={`w-full flex items-center gap-2 px-3 py-2 rounded-lg text-left text-sm transition-colors ${
activeSection === section.id
? 'bg-blue-600/20 text-blue-400 border border-blue-500/30'
: `${textSecondary} hover:${isDark ? 'bg-slate-700/50' : 'bg-gray-100'} hover:${textPrimary}`
}`}
>
<span className="text-xs opacity-50">{section.label.split('、')[0]}</span>
<span>{section.label.split('、')[1]}</span>
</button>
))}
</nav>
{/* 版本信息 */}
<div className={`mt-6 pt-4 border-t ${cardBorder}`}>
<div className={`flex items-center gap-2 ${textSecondary} text-xs mb-2`}>
<Clock className="w-3 h-3" />
版本信息
</div>
<div className="space-y-1 text-xs">
<p className={textSecondary}>当前版本:<span className={isDark ? 'text-cyan-400' : 'text-red-500'}>V3</span></p>
<p className={textSecondary}>生成时间:2026-03-19 16:00</p>
<p className={textSecondary}>关联任务:TASK-2026-0319-001</p>
</div>
</div>
{/* 风险提示 */}
<div className={`mt-4 p-3 bg-amber-500/10 border border-amber-500/30 rounded-lg`}>
<div className={`flex items-center gap-2 text-amber-400 text-xs font-medium mb-1`}>
<AlertTriangle className="w-3 h-3" />
风险提示
</div>
<p className={`${textSecondary} text-xs`}>需关注预算控制和内容质量</p>
</div>
</div>
</div>
{/* 中间正文区 (60%) */}
<div className="col-span-2">
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-8`}>
{/* 标题 */}
<div className={`text-center mb-8 pb-6 border-b ${cardBorder}`}>
<h1 className={`text-2xl font-bold ${textPrimary} mb-2`}>五四青年节宣传活动策略方案</h1>
<p className={textSecondary}>最终版 · V3</p>
</div>
{/* 逻辑总括 - 高亮显示 */}
<div className="mb-8 p-6 bg-gradient-to-r from-blue-600/20 to-cyan-600/20 border border-blue-500/30 rounded-xl">
<p className={`${textSecondary} leading-relaxed`}>
<strong className="text-cyan-400">逻辑总括:</strong>
本次宣传拟面向<span className="text-cyan-400 font-medium">【18-25岁基层青年】</span>,
围绕其<span className="text-yellow-400 font-medium">【社交认同与自我表达】</span>驱动,
传播<span className="text-purple-400 font-medium">【真实、有态度的青年故事】</span>叙事,
促使其产生<span className="text-green-400 font-medium">【主动参与互动并生成UGC内容】</span>行为,
从而实现<span className="text-blue-400 font-medium">【提升品牌在Z世代用户中的认知度】</span>目标。
</p>
</div>
{/* 正文内容 */}
<div className="space-y-8">
{/* 一、任务背景 */}
<section>
<h2 className={`${textPrimary} font-bold text-lg mb-4 flex items-center gap-2`}>
<FileText className="w-5 h-5 text-blue-400" />
一、任务背景
</h2>
<div className={`${textSecondary} leading-relaxed space-y-3 pl-7`}>
<p>五四青年节将至,公司希望借此契机开展一次面向年轻群体的品牌宣传活动,提升品牌在Z世代用户中的认知度和好感度。</p>
<p>本次活动需要制定一套完整的宣传策略,包括目标受众分析、行为设计、叙事框架、渠道安排等内容。</p>
<div className={`p-4 ${inputBg} ${cardBorder} rounded-lg`}>
<p className={`${textMuted} text-sm mb-2`}>特殊约束</p>
<p>• 预算有限,需注重性价比</p>
<p>• 需在5月1日前完成所有准备工作</p>
<p>• 传播效果需可量化评估</p>
</div>
</div>
</section>
{/* 二、宣传目标 */}
<section>
<h2 className={`${textPrimary} font-bold text-lg mb-4 flex items-center gap-2`}>
<Target className="w-5 h-5 text-blue-400" />
二、宣传目标
</h2>
<div className="pl-7 space-y-4">
<div className="p-4 bg-blue-500/10 border border-blue-500/30 rounded-lg">
<p className="text-blue-400 text-sm font-medium mb-2">主目标</p>
<p className={textPrimary}>提升品牌在Z世代用户中的认知度</p>
<p className={`${textSecondary} text-sm mt-2`}>具体指标:活动期间品牌相关话题曝光量达500万+</p>
</div>
<div className="p-4 bg-green-500/10 border border-green-500/30 rounded-lg">
<p className="text-green-400 text-sm font-medium mb-2">次目标</p>
<p className={textPrimary}>建立品牌年轻化形象,增强用户情感连接</p>
</div>
</div>
</section>
{/* 三、目标受众 */}
<section>
<h2 className={`${textPrimary} font-bold text-lg mb-4 flex items-center gap-2`}>
<Users className="w-5 h-5 text-cyan-400" />
三、目标受众
</h2>
<div className="pl-7 space-y-4">
<div className="p-4 bg-cyan-500/10 border border-cyan-500/30 rounded-lg">
<p className="text-cyan-400 text-sm font-medium mb-2">核心受众</p>
<p className={`${textPrimary} font-medium`}>18-25岁基层青年</p>
<div className="mt-3 grid grid-cols-2 gap-4">
<div>
<p className={`${textMuted} text-xs mb-1`}>人口特征</p>
<p className={`${textSecondary} text-sm`}>学生、基层工作者为主</p>
</div>
<div>
<p className={`${textMuted} text-xs mb-1`}>媒体习惯</p>
<p className={`${textSecondary} text-sm`}>短视频、社交平台重度用户</p>
</div>
</div>
</div>
<div className={`p-4 ${inputBg} ${isDark ? 'border-slate-700/30' : 'border-gray-200'} rounded-lg`}>
<p className={`${textSecondary} text-sm font-medium mb-2`}>次级受众</p>
<p className={textSecondary}>25-30岁职场新人</p>
</div>
</div>
</section>
{/* 四、预期行为及关键驱动 */}
<section>
<h2 className={`${textPrimary} font-bold text-lg mb-4 flex items-center gap-2`}>
<TrendingUp className="w-5 h-5 text-green-400" />
四、预期行为及关键驱动
</h2>
<div className="pl-7 space-y-4">
<div className="p-4 bg-green-500/10 border border-green-500/30 rounded-lg">
<p className="text-green-400 text-sm font-medium mb-2">目标行为</p>
<p className={textPrimary}>主动参与话题讨论、生成UGC内容</p>
<div className="mt-3 flex items-center gap-2">
<span className={`${textSecondary} text-sm`}>转化路径:</span>
{['浏览', '点赞', '评论', '转发', '创作'].map((step, i) => (
<React.Fragment key={step}>
<span className={`px-2 py-1 rounded text-xs ${
i < 2 ? 'bg-green-500/20 text-green-400' : `${inputBg} ${textSecondary}`
}`}>
{step}
</span>
{i < 4 && <span className={isDark ? 'text-slate-600' : 'text-gray-400'}>→</span>}
</React.Fragment>
))}
</div>
</div>
<div className="p-4 bg-yellow-500/10 border border-yellow-500/30 rounded-lg">
<p className="text-yellow-400 text-sm font-medium mb-2">核心驱动</p>
<p className={textPrimary}>社交认同与自我表达</p>
<div className="mt-2 flex gap-2">
{['归属感需求', '表达欲驱动', '群体认同激励'].map((item) => (
<span key={item} className="px-2 py-1 bg-yellow-500/20 text-yellow-400 rounded text-xs">
{item}
</span>
))}
</div>
</div>
</div>
</section>
{/* 五、叙事策略 */}
<section>
<h2 className={`${textPrimary} font-bold text-lg mb-4 flex items-center gap-2`}>
<Megaphone className="w-5 h-5 text-purple-400" />
五、叙事策略
</h2>
<div className="pl-7 space-y-4">
<div className="p-4 bg-purple-500/10 border border-purple-500/30 rounded-lg">
<p className="text-purple-400 text-sm font-medium mb-2">主叙事模式</p>
<p className={textPrimary}>真实、有态度的青年故事</p>
</div>
<div className={`p-4 ${inputBg} ${isDark ? 'border-slate-700/30' : 'border-gray-200'} rounded-lg`}>
<p className={`${textSecondary} text-sm font-medium mb-2`}>叙事策略</p>
<p className={textSecondary}>人物+事件结合,以真实故事传递品牌价值观。讲述年轻人自己的故事,引发情感共鸣。</p>
</div>
</div>
</section>
{/* 六、渠道与执行安排 */}
<section>
<h2 className={`${textPrimary} font-bold text-lg mb-4 flex items-center gap-2`}>
<Link2 className="w-5 h-5 text-pink-400" />
六、渠道与执行安排
</h2>
<div className="pl-7">
<div className="grid grid-cols-3 gap-4">
{[
{ platform: '抖音', role: '主战场,短视频传播', weight: '40%' },
{ platform: '微博', role: '话题引爆,社交传播', weight: '30%' },
{ platform: '小红书', role: '种草转化,UGC沉淀', weight: '30%' },
].map((channel) => (
<div key={channel.platform} className="p-4 bg-pink-500/10 border border-pink-500/30 rounded-lg">
<p className="text-pink-400 font-medium">{channel.platform}</p>
<p className={`${textSecondary} text-sm mt-1`}>{channel.role}</p>
<p className={`${textMuted} text-xs mt-2`}>预算占比:{channel.weight}</p>
</div>
))}
</div>
</div>
</section>
{/* 七、风险控制 */}
<section>
<h2 className={`${textPrimary} font-bold text-lg mb-4 flex items-center gap-2`}>
<Shield className="w-5 h-5 text-red-400" />
七、风险控制
</h2>
<div className="pl-7 space-y-3">
{[
{ risk: '预算有限,需控制成本', mitigation: '提前布局预热,优化投放策略' },
{ risk: '青年群体注意力分散', mitigation: '内容差异化,强调情感共鸣' },
{ risk: 'UGC质量难以保证', mitigation: '设置激励机制,建立内容审核' },
].map((item, i) => (
<div key={i} className={`flex gap-4 p-3 ${inputBg} ${isDark ? 'border-slate-700/30' : 'border-gray-200'} rounded-lg`}>
<div className="flex-1">
<p className="text-red-400 text-xs font-medium">风险{i + 1}</p>
<p className={`${textPrimary} text-sm`}>{item.risk}</p>
</div>
<div className="flex-1">
<p className="text-green-400 text-xs font-medium">应对措施</p>
<p className={`${textSecondary} text-sm`}>{item.mitigation}</p>
</div>
</div>
))}
</div>
</section>
{/* 八、效果评估 */}
<section>
<h2 className={`${textPrimary} font-bold text-lg mb-4 flex items-center gap-2`}>
<BarChart3 className="w-5 h-5 text-amber-400" />
八、效果评估
</h2>
<div className="pl-7">
<div className="grid grid-cols-4 gap-4">
{[
{ metric: '曝光量', target: '500万+', current: '0' },
{ metric: '互动率', target: '5%', current: '0%' },
{ metric: 'UGC数量', target: '1000+', current: '0' },
{ metric: '话题热度', target: 'TOP 20', current: '-' },
].map((item) => (
<div key={item.metric} className="p-4 bg-amber-500/10 border border-amber-500/30 rounded-lg text-center">
<p className="text-amber-400 text-xs">{item.metric}</p>
<p className={`${textPrimary} font-bold text-lg mt-1`}>{item.target}</p>
<p className={`${textMuted} text-xs mt-1`}>目标值</p>
</div>
))}
</div>
</div>
</section>
</div>
</div>
</div>
{/* 右侧辅助区 (20%) */}
<div className="col-span-1 space-y-6">
{/* 关联讨论记录 */}
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-4`}>
<h3 className={`${textPrimary} font-semibold mb-4`}>关联讨论记录</h3>
<button className={`w-full flex items-center justify-between p-3 ${inputBg} hover:${isDark ? 'bg-slate-800/50' : 'bg-gray-200'} ${cardBorder} rounded-lg transition-colors`}>
<div className="flex items-center gap-2 text-blue-400 text-sm">
<FileText className="w-4 h-4" />
TASK-2026-0319-001
</div>
<ChevronRight className={`w-4 h-4 ${textSecondary}`} />
</button>
</div>
{/* 快速操作 */}
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-4`}>
<h3 className={`${textPrimary} font-semibold mb-4`}>快速操作</h3>
<div className="space-y-2">
<button className={`w-full flex items-center gap-3 p-3 ${inputBg} hover:${isDark ? 'bg-slate-800/50' : 'bg-gray-200'} ${cardBorder} rounded-lg transition-colors text-left`}>
<Download className="w-4 h-4 text-green-400" />
<div>
<p className={`${textPrimary} text-sm`}>导出完整方案</p>
<p className={`${textMuted} text-xs`}>Word格式</p>
</div>
</button>
<button className={`w-full flex items-center gap-3 p-3 ${inputBg} hover:${isDark ? 'bg-slate-800/50' : 'bg-gray-200'} ${cardBorder} rounded-lg transition-colors text-left`}>
<RefreshCw className="w-4 h-4 text-blue-400" />
<div>
<p className={`${textPrimary} text-sm`}>发起新版本修订</p>
<p className={`${textMuted} text-xs`}>基于当前版本</p>
</div>
</button>
</div>
</div>
{/* 分享 */}
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-4`}>
<h3 className={`${textPrimary} font-semibold mb-4`}>分享方案</h3>
<div className="flex gap-2">
<button className={`flex-1 p-2 ${inputBg} hover:${isDark ? 'bg-slate-800/50' : 'bg-gray-200'} ${cardBorder} rounded-lg transition-colors`}>
<p className={`${textSecondary} text-xs`}>复制链接</p>
</button>
<button className={`flex-1 p-2 ${inputBg} hover:${isDark ? 'bg-slate-800/50' : 'bg-gray-200'} ${cardBorder} rounded-lg transition-colors`}>
<p className={`${textSecondary} text-xs`}>发送邮件</p>
</button>
</div>
</div>
</div>
</div>
</div>
);
};
export default FinalPlan;