716 lines
32 KiB
TypeScript
716 lines
32 KiB
TypeScript
import React, { useState } from 'react';
|
|
import {
|
|
ArrowLeft,
|
|
Bot,
|
|
CheckCircle,
|
|
Clock,
|
|
User,
|
|
Download,
|
|
FileText,
|
|
Send,
|
|
Zap,
|
|
Sparkles,
|
|
Lightbulb,
|
|
Copy,
|
|
Edit3,
|
|
ChevronDown,
|
|
ChevronRight,
|
|
Database,
|
|
Brain,
|
|
MessageSquare,
|
|
ExternalLink,
|
|
BookOpen,
|
|
Info,
|
|
Eye,
|
|
} from 'lucide-react';
|
|
import { useTheme } from '@/contexts/ThemeContext';
|
|
import { PageType } from '@/components/Sidebar';
|
|
|
|
interface TaskSingleProps {
|
|
onNavigate: (page: PageType) => void;
|
|
}
|
|
|
|
interface ChatMessage {
|
|
id: string;
|
|
role: 'user' | 'agent';
|
|
content: string;
|
|
timestamp: string;
|
|
citations?: { title: string; source: string; page?: number }[];
|
|
}
|
|
|
|
const TaskSingle: React.FC<TaskSingleProps> = ({ onNavigate }) => {
|
|
const { theme } = useTheme();
|
|
const isDark = theme === 'dark';
|
|
|
|
const [taskStatus, setTaskStatus] = useState<'pending' | 'running' | 'completed'>('completed');
|
|
const [input, setInput] = useState('请分析五四青年节宣传活动的目标受众');
|
|
const [isRunning, setIsRunning] = useState(false);
|
|
const [showCitations, setShowCitations] = useState<string | null>(null);
|
|
const [isEditing, setIsEditing] = useState(false);
|
|
const [editedContent, setEditedContent] = useState('');
|
|
|
|
const [messages, setMessages] = useState<ChatMessage[]>([
|
|
{
|
|
id: '1',
|
|
role: 'user',
|
|
content: '请分析五四青年节宣传活动的目标受众',
|
|
timestamp: '14:00',
|
|
},
|
|
{
|
|
id: '2',
|
|
role: 'agent',
|
|
content: `根据您的任务要求,我对五四青年节宣传活动的目标受众进行了全面分析,以下是详细报告:
|
|
|
|
## 一、核心受众画像
|
|
|
|
**基本信息**
|
|
- 年龄段:18-25岁
|
|
- 身份定位:基层青年(学生、职场新人)
|
|
- 地域分布:一二线城市为主
|
|
|
|
**用户特征**
|
|
- 社交媒体重度用户,日均使用时长超过3小时
|
|
- 短视频内容消费主力,偏好竖屏内容
|
|
- 注重"真实感"和"态度感",反感过度营销
|
|
- 追求个性化表达和群体认同
|
|
|
|
## 二、行为洞察
|
|
|
|
**媒体习惯**
|
|
- 主要平台:抖音、小红书、微博、B站
|
|
- 内容偏好:真实故事、情感共鸣、实用价值
|
|
- 互动方式:点赞、评论、转发、UGC创作
|
|
|
|
**决策因素**
|
|
- 社交认同 > 品牌声誉 > 产品功能
|
|
- 性价比 > 品牌溢价
|
|
- 真实体验 > 官方宣传
|
|
|
|
## 三、核心需求
|
|
|
|
1. **归属感需求** - 希望被看见、被认可,参与活动获得身份认同
|
|
2. **表达欲驱动** - 有态度的内容激发创作冲动
|
|
3. **社交认同激励** - 优质内容获得曝光和认可
|
|
|
|
## 结论
|
|
|
|
核心受众应聚焦18-25岁基层青年群体,这部分用户与品牌年轻化战略高度契合。`,
|
|
timestamp: '14:03',
|
|
citations: [
|
|
{ title: 'Z世代消费行为研究报告', source: '市场研究数据库', page: 23 },
|
|
{ title: '短视频平台用户画像', source: 'Y系统-用户标签', page: 5 },
|
|
{ title: '品牌年轻化营销案例集', source: '宣传知识库', page: 45 },
|
|
],
|
|
},
|
|
]);
|
|
|
|
const agentConfig = {
|
|
name: 'AudienceAgent',
|
|
role: '受众分析专家',
|
|
description: '分析目标受众画像、行为特征和核心需求,为策略制定提供数据支持',
|
|
skills: [
|
|
{ name: '受众分层', type: '分析类', status: 'enabled' },
|
|
{ name: '核心受众识别', type: '推断类', status: 'enabled' },
|
|
{ name: '受众画像抽取', type: '抽取类', status: 'enabled' },
|
|
{ name: '阻力因素提炼', type: '分析类', status: 'enabled' },
|
|
],
|
|
databases: [
|
|
{ name: '宣传知识库', type: '知识库', access: '品牌案例、活动方法论', status: 'connected' },
|
|
{ name: 'Y系统', type: '业务系统', access: '用户标签、传播数据', status: 'connected' },
|
|
{ name: '市场数据库', type: '外部数据源', access: '市场报告、用户研究', status: 'connected' },
|
|
],
|
|
outputFields: ['core_audience', 'key_traits', 'concerns', 'barriers'],
|
|
};
|
|
|
|
const analysisResult = {
|
|
title: '五四青年节宣传活动目标受众分析报告',
|
|
agent: 'AudienceAgent',
|
|
completionTime: '2026-03-19 14:03',
|
|
status: '已完成',
|
|
summary: '核心受众聚焦18-25岁基层青年群体,需用"真实、有态度"的内容打动',
|
|
};
|
|
|
|
const handleSend = () => {
|
|
if (!input.trim()) return;
|
|
|
|
const userMessage: ChatMessage = {
|
|
id: Date.now().toString(),
|
|
role: 'user',
|
|
content: input,
|
|
timestamp: new Date().toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' }),
|
|
};
|
|
|
|
setMessages([...messages, userMessage]);
|
|
setInput('');
|
|
setIsRunning(true);
|
|
|
|
setTimeout(() => {
|
|
const agentMessage: ChatMessage = {
|
|
id: (Date.now() + 1).toString(),
|
|
role: 'agent',
|
|
content: '分析结果已生成,请查看上方报告详情。',
|
|
timestamp: new Date().toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' }),
|
|
citations: [
|
|
{ title: '青年消费趋势报告', source: '市场数据库', page: 12 },
|
|
],
|
|
};
|
|
setMessages(prev => [...prev, agentMessage]);
|
|
setIsRunning(false);
|
|
setTaskStatus('completed');
|
|
}, 2000);
|
|
};
|
|
|
|
const handleCopyResult = () => {
|
|
const content = messages.filter(m => m.role === 'agent').map(m => m.content).join('\n\n');
|
|
navigator.clipboard.writeText(content);
|
|
};
|
|
|
|
const handleEditResult = () => {
|
|
if (isEditing) {
|
|
setIsEditing(false);
|
|
} else {
|
|
setEditedContent(messages.filter(m => m.role === 'agent').map(m => m.content).join('\n\n'));
|
|
setIsEditing(true);
|
|
}
|
|
};
|
|
|
|
const handleExport = () => {
|
|
const content = `# ${analysisResult.title}\n\n智能体:${analysisResult.agent}\n完成时间:${analysisResult.completionTime}\n状态:${analysisResult.status}\n\n---\n\n${messages.filter(m => m.role === 'agent').map(m => m.content).join('\n\n')}`;
|
|
const blob = new Blob([content], { type: 'text/markdown' });
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = 'audience_analysis_report.md';
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
};
|
|
|
|
return (
|
|
<div className="h-[calc(100vh-140px)] flex flex-col">
|
|
{/* 顶部工具栏 */}
|
|
<div className={`rounded-xl p-4 flex-shrink-0 theme-card border ${
|
|
isDark
|
|
? 'bg-slate-800/30 backdrop-blur-xl border-blue-800/30'
|
|
: 'bg-white border-red-100 shadow-sm'
|
|
}`}>
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex items-center gap-4">
|
|
<button
|
|
onClick={() => onNavigate('task-list')}
|
|
className={`flex items-center gap-2 px-3 py-2 rounded-lg text-sm transition-colors ${
|
|
isDark
|
|
? 'bg-slate-700/50 hover:bg-slate-600/50 border border-blue-800/30 text-slate-300'
|
|
: 'bg-red-50 hover:bg-red-100 border border-red-200 text-red-600'
|
|
}`}
|
|
>
|
|
<ArrowLeft className="w-4 h-4" />
|
|
返回
|
|
</button>
|
|
<div className={`h-8 w-px ${isDark ? 'bg-blue-800/30' : 'bg-red-200'}`} />
|
|
<div>
|
|
<h1 className={`font-bold ${isDark ? 'text-white' : 'text-gray-900'}`}>五四青年节受众分析</h1>
|
|
<p className={`text-xs ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>单智能体任务 · AudienceAgent</p>
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
<span className={`px-3 py-1.5 rounded-full text-xs font-medium flex items-center gap-1.5 ${
|
|
taskStatus === 'completed'
|
|
? isDark
|
|
? 'bg-green-500/20 text-green-400'
|
|
: 'bg-green-100 text-green-600'
|
|
: taskStatus === 'running'
|
|
? isDark
|
|
? 'bg-blue-500/20 text-blue-400'
|
|
: 'bg-red-100 text-red-600'
|
|
: isDark
|
|
? 'bg-slate-500/20 text-slate-400'
|
|
: 'bg-gray-100 text-gray-600'
|
|
}`}>
|
|
{taskStatus === 'completed' ? (
|
|
<><CheckCircle className="w-3 h-3" /> 已完成</>
|
|
) : taskStatus === 'running' ? (
|
|
<><Clock className="w-3 h-3" /> 运行中</>
|
|
) : (
|
|
<><Clock className="w-3 h-3" /> 待运行</>
|
|
)}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 主内容区:三栏布局 - 中间栏加宽,右侧栏变窄 */}
|
|
<div className="flex-1 grid grid-cols-12 gap-4 mt-4 min-h-0">
|
|
{/* 左侧栏 (15%) - 任务信息 + 智能体配置 */}
|
|
<div className={`col-span-2 flex flex-col gap-4 min-h-0 overflow-y-auto ${
|
|
isDark ? '' : 'pr-2'
|
|
}`}>
|
|
{/* 任务信息卡片 */}
|
|
<div className={`rounded-xl p-4 flex-shrink-0 border ${
|
|
isDark
|
|
? 'bg-slate-800/30 backdrop-blur-xl border-blue-800/30'
|
|
: 'bg-white border-red-100 shadow-sm'
|
|
}`}>
|
|
<h3 className={`font-semibold text-sm mb-3 flex items-center gap-2 ${isDark ? 'text-white' : 'text-gray-900'}`}>
|
|
<span className={isDark ? 'text-blue-400' : 'text-red-500'}>
|
|
<FileText className="w-4 h-4" />
|
|
</span>
|
|
任务信息
|
|
</h3>
|
|
<div className="space-y-3 text-sm">
|
|
<div className="flex items-center justify-between">
|
|
<span className={isDark ? 'text-slate-500' : 'text-gray-500'}>任务类型</span>
|
|
<span className={`px-2 py-0.5 rounded text-xs ${
|
|
isDark
|
|
? 'bg-blue-500/20 text-blue-400'
|
|
: 'bg-red-100 text-red-600'
|
|
}`}>单智能体</span>
|
|
</div>
|
|
<div className="flex items-center justify-between">
|
|
<span className={isDark ? 'text-slate-500' : 'text-gray-500'}>执行智能体</span>
|
|
<span className={isDark ? 'text-cyan-400' : 'text-red-600'}>AudienceAgent</span>
|
|
</div>
|
|
<div className="flex items-center justify-between">
|
|
<span className={isDark ? 'text-slate-500' : 'text-gray-500'}>创建时间</span>
|
|
<span className={isDark ? 'text-slate-400' : 'text-gray-600'}>14:00</span>
|
|
</div>
|
|
<div className="flex items-center justify-between">
|
|
<span className={isDark ? 'text-slate-500' : 'text-gray-500'}>完成时间</span>
|
|
<span className={isDark ? 'text-slate-400' : 'text-gray-600'}>14:03</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 智能体配置卡片 */}
|
|
<div className={`rounded-xl p-4 flex-1 overflow-y-auto border theme-card scrollbar-thin ${
|
|
isDark
|
|
? 'bg-slate-800/30 backdrop-blur-xl border-blue-800/30'
|
|
: 'bg-white border-red-100 shadow-sm'
|
|
}`}>
|
|
<h3 className={`font-semibold text-sm mb-3 flex items-center gap-2 ${isDark ? 'text-white' : 'text-gray-900'}`}>
|
|
<span className={isDark ? 'text-cyan-400' : 'text-red-500'}>
|
|
<Bot className="w-4 h-4" />
|
|
</span>
|
|
智能体配置
|
|
</h3>
|
|
|
|
{/* 智能体简介 */}
|
|
<div className={`mb-4 p-3 rounded-lg ${
|
|
isDark ? 'bg-slate-900/50' : 'bg-red-50'
|
|
}`}>
|
|
<p className={`text-sm font-medium mb-1 ${isDark ? 'text-cyan-400' : 'text-red-600'}`}>{agentConfig.name}</p>
|
|
<p className={`text-xs mb-2 ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>{agentConfig.role}</p>
|
|
<p className={`text-xs ${isDark ? 'text-slate-500' : 'text-gray-400'}`}>{agentConfig.description}</p>
|
|
</div>
|
|
|
|
{/* 技能列表 */}
|
|
<div className="mb-4">
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<Brain className={`w-4 h-4 ${isDark ? 'text-purple-400' : 'text-red-500'}`} />
|
|
<span className={`text-xs ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>启用技能</span>
|
|
</div>
|
|
<div className="space-y-1.5">
|
|
{agentConfig.skills.map((skill, index) => (
|
|
<div key={index} className={`flex items-center justify-between p-2 rounded ${
|
|
isDark ? 'bg-slate-900/50' : 'bg-red-50'
|
|
}`}>
|
|
<span className={`text-xs ${isDark ? 'text-slate-300' : 'text-gray-700'}`}>{skill.name}</span>
|
|
<span className={`px-1.5 py-0.5 rounded text-[10px] ${
|
|
isDark
|
|
? 'bg-purple-500/20 text-purple-400'
|
|
: 'bg-red-100 text-red-600'
|
|
}`}>{skill.type}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* 数据源列表 */}
|
|
<div>
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<Database className={`w-4 h-4 ${isDark ? 'text-green-400' : 'text-red-500'}`} />
|
|
<span className={`text-xs ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>可调用数据源</span>
|
|
</div>
|
|
<div className="space-y-1.5">
|
|
{agentConfig.databases.map((db, index) => (
|
|
<div key={index} className={`p-2 rounded ${
|
|
isDark ? 'bg-slate-900/50' : 'bg-red-50'
|
|
}`}>
|
|
<div className="flex items-center justify-between mb-1">
|
|
<span className={`text-xs ${isDark ? 'text-slate-300' : 'text-gray-700'}`}>{db.name}</span>
|
|
<span className={`w-1.5 h-1.5 rounded-full ${
|
|
db.status === 'connected'
|
|
? isDark ? 'bg-green-400' : 'bg-red-500'
|
|
: 'bg-slate-500'
|
|
}`} />
|
|
</div>
|
|
<p className={`text-[10px] ${isDark ? 'text-slate-500' : 'text-gray-400'}`}>{db.access}</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 中间栏 (65%) - 对话式问答 - 加宽 */}
|
|
<div className="col-span-7 flex flex-col min-h-0">
|
|
<div className={`rounded-xl flex-1 flex flex-col min-h-0 border theme-card ${
|
|
isDark
|
|
? 'bg-slate-800/30 backdrop-blur-xl border-blue-800/30'
|
|
: 'bg-white border-red-100 shadow-sm'
|
|
}`}>
|
|
{/* 对话区域头部 */}
|
|
<div className={`p-4 border-b flex-shrink-0 ${
|
|
isDark ? 'border-blue-800/30' : 'border-red-100'
|
|
}`}>
|
|
<h3 className={`font-semibold flex items-center gap-2 ${isDark ? 'text-white' : 'text-gray-900'}`}>
|
|
<span className={isDark ? 'text-blue-400' : 'text-red-500'}>
|
|
<MessageSquare className="w-4 h-4" />
|
|
</span>
|
|
对话分析
|
|
</h3>
|
|
</div>
|
|
|
|
{/* 消息列表 */}
|
|
<div className="flex-1 overflow-y-auto p-4 space-y-4 scrollbar-thin">
|
|
{messages.map((msg) => (
|
|
<div key={msg.id} className={`flex ${msg.role === 'user' ? 'justify-end' : 'justify-start'}`}>
|
|
<div className={`max-w-[85%] rounded-xl p-4 border ${
|
|
msg.role === 'user'
|
|
? isDark
|
|
? 'bg-blue-600/30 border-blue-500/30'
|
|
: 'bg-red-50 border-red-200'
|
|
: isDark
|
|
? 'bg-slate-900/50 border-blue-800/30'
|
|
: 'bg-gray-50 border-gray-200'
|
|
}`}>
|
|
<div className="flex items-center gap-2 mb-2">
|
|
{msg.role === 'agent' ? (
|
|
<Bot className={`w-4 h-4 ${isDark ? 'text-cyan-400' : 'text-red-500'}`} />
|
|
) : (
|
|
<User className={`w-4 h-4 ${isDark ? 'text-blue-400' : 'text-red-500'}`} />
|
|
)}
|
|
<span className={`text-xs font-medium ${
|
|
msg.role === 'user'
|
|
? isDark ? 'text-blue-400' : 'text-red-600'
|
|
: isDark ? 'text-cyan-400' : 'text-red-600'
|
|
}`}>
|
|
{msg.role === 'user' ? '你' : 'AudienceAgent'}
|
|
</span>
|
|
<span className={`text-[10px] ${isDark ? 'text-slate-500' : 'text-gray-400'}`}>{msg.timestamp}</span>
|
|
</div>
|
|
<p className={`text-sm whitespace-pre-wrap ${
|
|
isDark ? 'text-slate-300' : 'text-gray-700'
|
|
}`}>{msg.content}</p>
|
|
|
|
{/* 引用信息 */}
|
|
{msg.citations && msg.citations.length > 0 && (
|
|
<div className={`mt-3 pt-3 border-t ${
|
|
isDark ? 'border-blue-800/30' : 'border-red-200'
|
|
}`}>
|
|
<button
|
|
onClick={() => setShowCitations(showCitations === msg.id ? null : msg.id)}
|
|
className={`flex items-center gap-2 text-xs transition-colors ${
|
|
isDark ? 'text-slate-400 hover:text-blue-400' : 'text-gray-500 hover:text-red-500'
|
|
}`}
|
|
>
|
|
<BookOpen className="w-3 h-3" />
|
|
查看引用 ({msg.citations.length})
|
|
{showCitations === msg.id ? <ChevronDown className="w-3 h-3" /> : <ChevronRight className="w-3 h-3" />}
|
|
</button>
|
|
{showCitations === msg.id && (
|
|
<div className="mt-2 space-y-2">
|
|
{msg.citations.map((citation, index) => (
|
|
<div className={`p-2 rounded flex items-start gap-2 ${
|
|
isDark ? 'bg-slate-800/50' : 'bg-white border border-gray-200'
|
|
}`}>
|
|
<ExternalLink className={`w-3 h-3 mt-0.5 ${isDark ? 'text-slate-500' : 'text-gray-400'}`} />
|
|
<div>
|
|
<p className={`text-xs ${isDark ? 'text-slate-300' : 'text-gray-700'}`}>{citation.title}</p>
|
|
<p className={`text-[10px] ${isDark ? 'text-slate-500' : 'text-gray-400'}`}>{citation.source} {citation.page && `· 第${citation.page}页`}</p>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
))}
|
|
{isRunning && (
|
|
<div className="flex justify-start">
|
|
<div className={`rounded-xl p-4 border ${
|
|
isDark ? 'bg-slate-900/50 border-blue-800/30' : 'bg-gray-50 border-gray-200'
|
|
}`}>
|
|
<div className="flex items-center gap-2">
|
|
<Bot className={`w-4 h-4 ${isDark ? 'text-cyan-400' : 'text-red-500'}`} />
|
|
<span className={`text-sm ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>分析中...</span>
|
|
<div className="flex gap-1">
|
|
<span className={`w-1.5 h-1.5 rounded-full animate-pulse ${
|
|
isDark ? 'bg-cyan-400' : 'bg-red-500'
|
|
}`} />
|
|
<span className={`w-1.5 h-1.5 rounded-full animate-pulse ${
|
|
isDark ? 'bg-cyan-400' : 'bg-red-500'
|
|
}`} style={{ animationDelay: '100ms' }} />
|
|
<span className={`w-1.5 h-1.5 rounded-full animate-pulse ${
|
|
isDark ? 'bg-cyan-400' : 'bg-red-500'
|
|
}`} style={{ animationDelay: '200ms' }} />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* 输入区域 */}
|
|
<div className={`p-4 border-t flex-shrink-0 ${
|
|
isDark ? 'border-blue-800/30' : 'border-red-100'
|
|
}`}>
|
|
<div className="flex gap-2">
|
|
<input
|
|
type="text"
|
|
value={input}
|
|
onChange={(e) => setInput(e.target.value)}
|
|
onKeyDown={(e) => e.key === 'Enter' && handleSend()}
|
|
placeholder="输入问题或任务要求..."
|
|
className={`flex-1 px-4 py-2.5 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-red-500/20 transition-colors ${
|
|
isDark
|
|
? 'bg-slate-900/50 border border-blue-800/30 text-white placeholder-slate-500'
|
|
: 'bg-white border border-red-200 text-gray-900 placeholder-gray-400'
|
|
}`}
|
|
/>
|
|
<button
|
|
onClick={handleSend}
|
|
disabled={isRunning}
|
|
className={`px-4 py-2.5 rounded-lg text-sm transition-colors flex items-center gap-2 ${
|
|
isDark
|
|
? 'bg-blue-600 hover:bg-blue-500 disabled:bg-slate-700 text-white'
|
|
: 'bg-red-600 hover:bg-red-500 disabled:bg-gray-400 text-white shadow-md'
|
|
}`}
|
|
>
|
|
<Send className="w-4 h-4" />
|
|
发送
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 右侧栏 (20%) - 分析结果 - 变窄 */}
|
|
<div className="col-span-3 flex flex-col min-h-0">
|
|
<div className={`rounded-xl flex-1 flex flex-col min-h-0 border theme-card ${
|
|
isDark
|
|
? 'bg-slate-800/30 backdrop-blur-xl border-blue-800/30'
|
|
: 'bg-white border-red-100 shadow-sm'
|
|
}`}>
|
|
{/* 结果区域头部 */}
|
|
<div className={`p-4 border-b flex-shrink-0 ${
|
|
isDark ? 'border-blue-800/30' : 'border-red-100'
|
|
}`}>
|
|
<div className="flex items-center justify-between">
|
|
<h3 className={`font-semibold flex items-center gap-2 ${isDark ? 'text-white' : 'text-gray-900'}`}>
|
|
<span className={isDark ? 'text-purple-400' : 'text-red-500'}>
|
|
<Sparkles className="w-4 h-4" />
|
|
</span>
|
|
分析结果
|
|
</h3>
|
|
<div className="flex items-center gap-1">
|
|
<button
|
|
onClick={handleCopyResult}
|
|
className={`p-2 rounded-lg transition-colors ${
|
|
isDark ? 'hover:bg-slate-700/50' : 'hover:bg-red-50'
|
|
}`}
|
|
title="复制结果"
|
|
>
|
|
<Copy className={`w-4 h-4 ${isDark ? 'text-slate-400' : 'text-red-400'}`} />
|
|
</button>
|
|
<button
|
|
onClick={handleEditResult}
|
|
className={`p-2 rounded-lg transition-colors ${
|
|
isDark ? 'hover:bg-slate-700/50' : 'hover:bg-red-50'
|
|
}`}
|
|
title="编辑结果"
|
|
>
|
|
<Edit3 className={`w-4 h-4 ${isEditing ? (isDark ? 'text-blue-400' : 'text-red-500') : (isDark ? 'text-slate-400' : 'text-red-400')}`} />
|
|
</button>
|
|
<button
|
|
onClick={handleExport}
|
|
className={`p-2 rounded-lg transition-colors ${
|
|
isDark ? 'hover:bg-slate-700/50' : 'hover:bg-red-50'
|
|
}`}
|
|
title="导出结果"
|
|
>
|
|
<Download className={`w-4 h-4 ${isDark ? 'text-slate-400' : 'text-red-400'}`} />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 结果内容 */}
|
|
<div className="flex-1 overflow-y-auto p-4 scrollbar-thin">
|
|
{/* 结果概览 */}
|
|
<div className={`mb-4 p-4 rounded-xl border ${
|
|
isDark
|
|
? 'bg-gradient-to-br from-purple-600/20 to-blue-600/20 border-purple-500/30'
|
|
: 'bg-gradient-to-br from-red-50 to-red-100 border-red-200'
|
|
}`}>
|
|
<h4 className={`font-medium text-sm mb-2 ${isDark ? 'text-white' : 'text-gray-900'}`}>{analysisResult.title}</h4>
|
|
<div className={`flex items-center gap-4 text-xs ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>
|
|
<span className="flex items-center gap-1">
|
|
<Bot className="w-3 h-3" />
|
|
{analysisResult.agent}
|
|
</span>
|
|
<span className="flex items-center gap-1">
|
|
<Clock className="w-3 h-3" />
|
|
{analysisResult.completionTime}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 结论摘要 */}
|
|
<div className="mb-4">
|
|
<h4 className={`text-xs mb-2 flex items-center gap-2 ${
|
|
isDark ? 'text-slate-400' : 'text-gray-500'
|
|
}`}>
|
|
<Lightbulb className={`w-3 h-3 ${isDark ? 'text-yellow-400' : 'text-yellow-500'}`} />
|
|
核心结论
|
|
</h4>
|
|
<div className={`p-3 rounded-lg border ${
|
|
isDark
|
|
? 'bg-blue-500/10 border-blue-500/30'
|
|
: 'bg-red-50 border-red-200'
|
|
}`}>
|
|
<p className={`text-sm ${isDark ? 'text-blue-300' : 'text-red-600'}`}>{analysisResult.summary}</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 关键洞察 */}
|
|
<div className="mb-4">
|
|
<h4 className={`text-xs mb-2 flex items-center gap-2 ${
|
|
isDark ? 'text-slate-400' : 'text-gray-500'
|
|
}`}>
|
|
<Eye className={`w-3 h-3 ${isDark ? 'text-green-400' : 'text-green-500'}`} />
|
|
关键洞察
|
|
</h4>
|
|
<div className="space-y-2">
|
|
<div className={`p-3 rounded-lg border ${
|
|
isDark ? 'bg-slate-900/50 border-blue-800/30' : 'bg-gray-50 border-gray-200'
|
|
}`}>
|
|
<p className={`text-sm font-medium mb-1 ${isDark ? 'text-white' : 'text-gray-900'}`}>核心受众</p>
|
|
<p className={`text-xs ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>18-25岁基层青年群体</p>
|
|
</div>
|
|
<div className={`p-3 rounded-lg border ${
|
|
isDark ? 'bg-slate-900/50 border-blue-800/30' : 'bg-gray-50 border-gray-200'
|
|
}`}>
|
|
<p className={`text-sm font-medium mb-1 ${isDark ? 'text-white' : 'text-gray-900'}`}>核心驱动</p>
|
|
<p className={`text-xs ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>社交认同与真实态度</p>
|
|
</div>
|
|
<div className={`p-3 rounded-lg border ${
|
|
isDark ? 'bg-slate-900/50 border-blue-800/30' : 'bg-gray-50 border-gray-200'
|
|
}`}>
|
|
<p className={`text-sm font-medium mb-1 ${isDark ? 'text-white' : 'text-gray-900'}`}>内容策略</p>
|
|
<p className={`text-xs ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>真实故事 + 情感共鸣 + 实用价值</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 详细信息预览 */}
|
|
<div>
|
|
<h4 className={`text-xs mb-2 flex items-center gap-2 ${
|
|
isDark ? 'text-slate-400' : 'text-gray-500'
|
|
}`}>
|
|
<Info className={`w-3 h-3 ${isDark ? 'text-slate-500' : 'text-gray-400'}`} />
|
|
详细报告
|
|
</h4>
|
|
{isEditing ? (
|
|
<textarea
|
|
value={editedContent}
|
|
onChange={(e) => setEditedContent(e.target.value)}
|
|
className={`w-full h-48 p-3 rounded-lg text-xs resize-none focus:outline-none focus:ring-2 focus:ring-red-500/20 ${
|
|
isDark
|
|
? 'bg-slate-900/50 border border-blue-800/30 text-slate-300'
|
|
: 'bg-white border border-gray-200 text-gray-700'
|
|
}`}
|
|
/>
|
|
) : (
|
|
<div className={`p-3 rounded-lg max-h-48 overflow-y-auto ${
|
|
isDark ? 'bg-slate-900/50 border border-blue-800/30' : 'bg-gray-50 border border-gray-200'
|
|
}`}>
|
|
<div className={`space-y-3 text-xs ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>
|
|
<p>## 核心受众画像</p>
|
|
<p className="pl-2">• 年龄段:18-25岁</p>
|
|
<p className="pl-2">• 身份定位:基层青年(学生、职场新人)</p>
|
|
<p className="pl-2">• 地域分布:一二线城市为主</p>
|
|
<p className="pt-2">## 用户特征</p>
|
|
<p className="pl-2">• 社交媒体重度用户</p>
|
|
<p className="pl-2">• 注重"真实感"和"态度感"</p>
|
|
<p className="pl-2">• 追求个性化表达</p>
|
|
<p className={`pt-2 ${isDark ? 'text-blue-400' : 'text-red-500'}`}>点击编辑按钮可修改报告内容</p>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* 引用来源 */}
|
|
<div className="mt-4">
|
|
<h4 className={`text-xs mb-2 flex items-center gap-2 ${
|
|
isDark ? 'text-slate-400' : 'text-gray-500'
|
|
}`}>
|
|
<BookOpen className={`w-3 h-3 ${isDark ? 'text-slate-500' : 'text-gray-400'}`} />
|
|
引用来源
|
|
</h4>
|
|
<div className="space-y-1.5">
|
|
{[
|
|
{ title: 'Z世代消费行为研究报告', source: '市场研究数据库' },
|
|
{ title: '短视频平台用户画像', source: 'Y系统-用户标签' },
|
|
{ title: '品牌年轻化营销案例集', source: '宣传知识库' },
|
|
].map((item, index) => (
|
|
<div key={index} className={`flex items-center gap-2 p-2 rounded ${
|
|
isDark ? 'bg-slate-900/30' : 'bg-white border border-gray-100'
|
|
}`}>
|
|
<ExternalLink className={`w-3 h-3 ${isDark ? 'text-slate-500' : 'text-gray-400'}`} />
|
|
<div>
|
|
<p className={`text-xs ${isDark ? 'text-slate-300' : 'text-gray-700'}`}>{item.title}</p>
|
|
<p className={`text-[10px] ${isDark ? 'text-slate-500' : 'text-gray-400'}`}>{item.source}</p>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 底部操作 */}
|
|
<div className={`p-4 border-t flex-shrink-0 ${
|
|
isDark ? 'border-blue-800/30' : 'border-red-100'
|
|
}`}>
|
|
<div className="flex gap-2">
|
|
<button
|
|
onClick={handleExport}
|
|
className={`flex-1 flex items-center justify-center gap-2 px-4 py-2.5 rounded-lg text-sm transition-colors ${
|
|
isDark
|
|
? 'bg-blue-600 hover:bg-blue-500 text-white'
|
|
: 'bg-red-600 hover:bg-red-500 text-white shadow-md'
|
|
}`}
|
|
>
|
|
<Download className="w-4 h-4" />
|
|
导出报告
|
|
</button>
|
|
<button className={`flex-1 flex items-center justify-center gap-2 px-4 py-2.5 rounded-lg text-sm transition-colors ${
|
|
isDark
|
|
? 'bg-slate-700/50 hover:bg-slate-600/50 border border-blue-800/30 text-slate-300'
|
|
: 'bg-gray-100 hover:bg-gray-200 border border-gray-200 text-gray-700'
|
|
}`}>
|
|
<Zap className="w-4 h-4" />
|
|
存入知识库
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default TaskSingle;
|