759 lines
32 KiB
TypeScript
759 lines
32 KiB
TypeScript
import React, { useState } from 'react';
|
|
import {
|
|
Search,
|
|
Bookmark,
|
|
BookmarkCheck,
|
|
Copy,
|
|
Download,
|
|
MessageSquare,
|
|
Bot,
|
|
History,
|
|
Calendar,
|
|
Filter,
|
|
ChevronDown,
|
|
GitCompare,
|
|
FileText,
|
|
ArrowRight,
|
|
X,
|
|
Star,
|
|
CheckCircle,
|
|
AlertCircle,
|
|
Send,
|
|
} from 'lucide-react';
|
|
import { useTheme } from '../contexts/ThemeContext';
|
|
import { PageType } from '../components/Sidebar';
|
|
|
|
type RecordType = 'all' | 'general' | 'agent';
|
|
type ModeType = 'all' | 'single-round' | 'multi-round' | 'deep-search' | 'compare';
|
|
type CollectionStatus = 'all' | 'collected';
|
|
|
|
interface QARecord {
|
|
id: string;
|
|
type: 'general' | 'agent';
|
|
mode: 'single-round' | 'multi-round' | 'deep-search' | 'compare';
|
|
question: string;
|
|
answer: string;
|
|
agentName?: string;
|
|
createTime: Date;
|
|
isCollected: boolean;
|
|
isHighValue: boolean;
|
|
isReusable: boolean;
|
|
isConvertible: boolean;
|
|
notes?: string;
|
|
evaluation?: string;
|
|
sources?: string[];
|
|
}
|
|
|
|
const QARecords: React.FC<{ onNavigate: (page: PageType) => void }> = ({ onNavigate }) => {
|
|
const { theme } = useTheme();
|
|
const isDark = theme === 'dark';
|
|
|
|
// 模拟问答记录数据
|
|
const mockRecords: QARecord[] = [
|
|
{
|
|
id: '1',
|
|
type: 'general',
|
|
mode: 'compare',
|
|
question: 'RAG技术的工作原理是什么?',
|
|
answer: '单轮RAG回答:直接检索并生成答案,响应速度快...',
|
|
createTime: new Date('2026-03-19 14:30'),
|
|
isCollected: true,
|
|
isHighValue: true,
|
|
isReusable: true,
|
|
isConvertible: true,
|
|
sources: ['RAG技术白皮书', 'LLM应用实践'],
|
|
},
|
|
{
|
|
id: '2',
|
|
type: 'agent',
|
|
mode: 'single-round',
|
|
question: '目标受众应如何分层?',
|
|
answer: '基于受众分析智能体的专业能力,识别出核心受众特征...',
|
|
agentName: 'AudienceAgent',
|
|
createTime: new Date('2026-03-19 10:20'),
|
|
isCollected: false,
|
|
isHighValue: true,
|
|
isReusable: true,
|
|
isConvertible: true,
|
|
},
|
|
{
|
|
id: '3',
|
|
type: 'general',
|
|
mode: 'deep-search',
|
|
question: '品牌年轻化传播策略有哪些?',
|
|
answer: '通过深度检索分析,总结出以下品牌年轻化传播策略...',
|
|
createTime: new Date('2026-03-18 16:45'),
|
|
isCollected: true,
|
|
isHighValue: false,
|
|
isReusable: false,
|
|
isConvertible: false,
|
|
notes: '需要进一步补充具体案例',
|
|
},
|
|
{
|
|
id: '4',
|
|
type: 'agent',
|
|
mode: 'multi-round',
|
|
question: '如何制定有效的用户激活策略?',
|
|
answer: '通过多轮对话深入分析,制定以下用户激活策略...',
|
|
agentName: 'ChannelAgent',
|
|
createTime: new Date('2026-03-18 11:15'),
|
|
isCollected: false,
|
|
isHighValue: true,
|
|
isReusable: true,
|
|
isConvertible: true,
|
|
evaluation: '策略实用性强,建议转化任务执行',
|
|
},
|
|
{
|
|
id: '5',
|
|
type: 'general',
|
|
mode: 'single-round',
|
|
question: '内容营销的最佳实践是什么?',
|
|
answer: '内容营销最佳实践包括:明确目标受众、创造高质量内容...',
|
|
createTime: new Date('2026-03-17 09:00'),
|
|
isCollected: false,
|
|
isHighValue: false,
|
|
isReusable: true,
|
|
isConvertible: false,
|
|
},
|
|
];
|
|
|
|
// 状态
|
|
const [records, setRecords] = useState<QARecord[]>(mockRecords);
|
|
const [selectedRecord, setSelectedRecord] = useState<QARecord | null>(mockRecords[0]);
|
|
const [searchQuery, setSearchQuery] = useState('');
|
|
const [recordType, setRecordType] = useState<RecordType>('all');
|
|
const [modeType, setModeType] = useState<ModeType>('all');
|
|
const [collectionStatus, setCollectionStatus] = useState<CollectionStatus>('all');
|
|
const [timeRange, setTimeRange] = useState('all');
|
|
const [notesInput, setNotesInput] = useState('');
|
|
|
|
// 筛选记录
|
|
const filteredRecords = records.filter((record) => {
|
|
// 搜索过滤
|
|
if (searchQuery && !record.question.toLowerCase().includes(searchQuery.toLowerCase())) {
|
|
return false;
|
|
}
|
|
// 类型过滤
|
|
if (recordType !== 'all' && record.type !== recordType) {
|
|
return false;
|
|
}
|
|
// 模式过滤
|
|
if (modeType !== 'all' && record.mode !== modeType) {
|
|
return false;
|
|
}
|
|
// 收藏状态过滤
|
|
if (collectionStatus === 'collected' && !record.isCollected) {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
|
|
// 获取模式标签
|
|
const getModeLabel = (mode: QARecord['mode']) => {
|
|
switch (mode) {
|
|
case 'single-round': return '单轮RAG';
|
|
case 'multi-round': return '多轮RAG';
|
|
case 'deep-search': return '深度检索';
|
|
case 'compare': return '对比';
|
|
}
|
|
};
|
|
|
|
// 获取模式颜色
|
|
const getModeColor = (mode: QARecord['mode']) => {
|
|
switch (mode) {
|
|
case 'single-round':
|
|
return isDark ? 'bg-blue-600/30 text-blue-400' : 'bg-blue-100 text-blue-600';
|
|
case 'multi-round':
|
|
return isDark ? 'bg-green-600/30 text-green-400' : 'bg-green-100 text-green-600';
|
|
case 'deep-search':
|
|
return isDark ? 'bg-purple-600/30 text-purple-400' : 'bg-purple-100 text-purple-600';
|
|
case 'compare':
|
|
return isDark ? 'bg-orange-600/30 text-orange-400' : 'bg-orange-100 text-orange-600';
|
|
}
|
|
};
|
|
|
|
// 切换收藏
|
|
const toggleCollect = (recordId: string) => {
|
|
setRecords(records.map(record =>
|
|
record.id === recordId ? { ...record, isCollected: !record.isCollected } : record
|
|
));
|
|
if (selectedRecord?.id === recordId) {
|
|
setSelectedRecord({ ...selectedRecord, isCollected: !selectedRecord.isCollected });
|
|
}
|
|
};
|
|
|
|
// 复制问题
|
|
const copyQuestion = (question: string) => {
|
|
navigator.clipboard.writeText(question);
|
|
alert('问题已复制');
|
|
};
|
|
|
|
// 导出记录
|
|
const exportRecord = (record: QARecord) => {
|
|
alert(`导出记录: ${record.question.substring(0, 20)}...`);
|
|
};
|
|
|
|
// 转到任务
|
|
const convertToTask = (record: QARecord, taskType: 'single' | 'consult' | 'scene') => {
|
|
const messages = {
|
|
single: '单智能体任务',
|
|
consult: '多智能体会商',
|
|
scene: '场景任务',
|
|
};
|
|
alert(`已转为${messages[taskType]}`);
|
|
};
|
|
|
|
// 格式化时间
|
|
const formatTime = (date: Date) => {
|
|
const now = new Date();
|
|
const diff = now.getTime() - date.getTime();
|
|
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
|
|
|
|
if (days === 0) {
|
|
return `今天 ${date.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' })}`;
|
|
} else if (days === 1) {
|
|
return `昨天 ${date.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' })}`;
|
|
} else if (days < 7) {
|
|
return `${days}天前`;
|
|
} else {
|
|
return date.toLocaleDateString('zh-CN', { month: 'short', day: 'numeric' });
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className={`h-[calc(100vh-120px)] flex flex-col theme-bg rounded-xl ${isDark ? 'bg-slate-800/50' : 'bg-white'} border ${isDark ? 'border-slate-700/50' : 'border-red-100'}`}>
|
|
{/* 顶部筛选栏 */}
|
|
<div className={`flex items-center justify-between px-6 py-4 border-b ${isDark ? 'border-slate-700/50' : 'border-red-100'}`}>
|
|
<div className="flex items-center gap-4">
|
|
<h1 className={`text-lg font-semibold ${isDark ? 'text-white' : 'text-gray-900'}`}>
|
|
问答记录
|
|
</h1>
|
|
<span className={`text-sm ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>
|
|
查看历史问答、对比结果与高价值记录
|
|
</span>
|
|
</div>
|
|
|
|
{/* 筛选控件 */}
|
|
<div className="flex items-center gap-3">
|
|
{/* 搜索框 */}
|
|
<div className={`relative ${isDark ? 'bg-slate-700/50' : 'bg-gray-100'} rounded-lg`}>
|
|
<Search className={`absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 ${isDark ? 'text-slate-400' : 'text-gray-400'}`} />
|
|
<input
|
|
type="text"
|
|
value={searchQuery}
|
|
onChange={(e) => setSearchQuery(e.target.value)}
|
|
placeholder="搜索问题关键词..."
|
|
className={`w-64 pl-10 pr-4 py-2 rounded-lg text-sm focus:outline-none ${
|
|
isDark
|
|
? 'bg-transparent text-white placeholder-slate-500'
|
|
: 'bg-transparent text-gray-800 placeholder-gray-400'
|
|
}`}
|
|
/>
|
|
</div>
|
|
|
|
{/* 记录类型 */}
|
|
<div className="relative">
|
|
<select
|
|
value={recordType}
|
|
onChange={(e) => setRecordType(e.target.value as RecordType)}
|
|
className={`appearance-none px-4 py-2 pr-10 rounded-lg text-sm cursor-pointer ${
|
|
isDark
|
|
? 'bg-slate-700/50 text-slate-300 border border-slate-600'
|
|
: 'bg-gray-100 text-gray-700 border border-gray-200'
|
|
}`}
|
|
>
|
|
<option value="all">全部类型</option>
|
|
<option value="general">通用问答</option>
|
|
<option value="agent">智能体问答</option>
|
|
</select>
|
|
<ChevronDown className={`absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 pointer-events-none ${
|
|
isDark ? 'text-slate-400' : 'text-gray-400'
|
|
}`} />
|
|
</div>
|
|
|
|
{/* 模式 */}
|
|
<div className="relative">
|
|
<select
|
|
value={modeType}
|
|
onChange={(e) => setModeType(e.target.value as ModeType)}
|
|
className={`appearance-none px-4 py-2 pr-10 rounded-lg text-sm cursor-pointer ${
|
|
isDark
|
|
? 'bg-slate-700/50 text-slate-300 border border-slate-600'
|
|
: 'bg-gray-100 text-gray-700 border border-gray-200'
|
|
}`}
|
|
>
|
|
<option value="all">全部模式</option>
|
|
<option value="single-round">单轮RAG</option>
|
|
<option value="multi-round">多轮RAG</option>
|
|
<option value="deep-search">深度检索</option>
|
|
<option value="compare">对比记录</option>
|
|
</select>
|
|
<ChevronDown className={`absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 pointer-events-none ${
|
|
isDark ? 'text-slate-400' : 'text-gray-400'
|
|
}`} />
|
|
</div>
|
|
|
|
{/* 收藏状态 */}
|
|
<div className="relative">
|
|
<select
|
|
value={collectionStatus}
|
|
onChange={(e) => setCollectionStatus(e.target.value as CollectionStatus)}
|
|
className={`appearance-none px-4 py-2 pr-10 rounded-lg text-sm cursor-pointer ${
|
|
isDark
|
|
? 'bg-slate-700/50 text-slate-300 border border-slate-600'
|
|
: 'bg-gray-100 text-gray-700 border border-gray-200'
|
|
}`}
|
|
>
|
|
<option value="all">全部</option>
|
|
<option value="collected">已收藏</option>
|
|
</select>
|
|
<ChevronDown className={`absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 pointer-events-none ${
|
|
isDark ? 'text-slate-400' : 'text-gray-400'
|
|
}`} />
|
|
</div>
|
|
|
|
{/* 时间范围 */}
|
|
<div className="relative">
|
|
<select
|
|
value={timeRange}
|
|
onChange={(e) => setTimeRange(e.target.value)}
|
|
className={`appearance-none px-4 py-2 pr-10 rounded-lg text-sm cursor-pointer ${
|
|
isDark
|
|
? 'bg-slate-700/50 text-slate-300 border border-slate-600'
|
|
: 'bg-gray-100 text-gray-700 border border-gray-200'
|
|
}`}
|
|
>
|
|
<option value="all">全部时间</option>
|
|
<option value="today">今天</option>
|
|
<option value="week">本周</option>
|
|
<option value="month">本月</option>
|
|
</select>
|
|
<ChevronDown className={`absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 pointer-events-none ${
|
|
isDark ? 'text-slate-400' : 'text-gray-400'
|
|
}`} />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 主体内容区 */}
|
|
<div className="flex-1 flex overflow-hidden">
|
|
{/* 左侧记录列表 */}
|
|
<div className={`w-80 border-r flex-shrink-0 overflow-y-auto ${isDark ? 'border-slate-700/50' : 'border-red-100'}`}>
|
|
<div className="p-4">
|
|
<div className="space-y-2">
|
|
{filteredRecords.map((record) => (
|
|
<button
|
|
key={record.id}
|
|
onClick={() => {
|
|
setSelectedRecord(record);
|
|
setNotesInput(record.notes || '');
|
|
}}
|
|
className={`w-full text-left p-3 rounded-lg transition-all ${
|
|
selectedRecord?.id === record.id
|
|
? isDark
|
|
? 'bg-blue-600/20 border border-blue-500/50'
|
|
: 'bg-red-50 border border-red-200'
|
|
: isDark
|
|
? 'bg-slate-700/30 border border-transparent hover:bg-slate-700/50'
|
|
: 'bg-white border border-gray-200 hover:bg-gray-50'
|
|
}`}
|
|
>
|
|
<div className="flex items-start gap-2 mb-2">
|
|
<span className={`px-1.5 py-0.5 rounded text-xs font-medium ${
|
|
record.type === 'general'
|
|
? isDark
|
|
? 'bg-blue-600/30 text-blue-400'
|
|
: 'bg-blue-100 text-blue-600'
|
|
: isDark
|
|
? 'bg-purple-600/30 text-purple-400'
|
|
: 'bg-purple-100 text-purple-600'
|
|
}`}>
|
|
{record.type === 'general' ? '通用问答' : '智能体'}
|
|
</span>
|
|
<span className={`px-1.5 py-0.5 rounded text-xs font-medium ${getModeColor(record.mode)}`}>
|
|
{getModeLabel(record.mode)}
|
|
</span>
|
|
{record.isCollected && (
|
|
<BookmarkCheck className={`w-3.5 h-3.5 ${isDark ? 'text-yellow-400' : 'text-yellow-500'}`} />
|
|
)}
|
|
</div>
|
|
|
|
<p className={`text-sm line-clamp-2 ${isDark ? 'text-slate-200' : 'text-gray-800'}`}>
|
|
{record.question}
|
|
</p>
|
|
|
|
<div className={`flex items-center gap-2 mt-2 text-xs ${isDark ? 'text-slate-500' : 'text-gray-400'}`}>
|
|
<Calendar className="w-3 h-3" />
|
|
<span>{formatTime(record.createTime)}</span>
|
|
{record.agentName && (
|
|
<>
|
|
<span>·</span>
|
|
<Bot className="w-3 h-3" />
|
|
<span>{record.agentName}</span>
|
|
</>
|
|
)}
|
|
</div>
|
|
|
|
{/* 标签 */}
|
|
<div className="flex items-center gap-1 mt-2">
|
|
{record.isHighValue && (
|
|
<span className={`px-1.5 py-0.5 rounded text-xs ${
|
|
isDark ? 'bg-yellow-600/30 text-yellow-400' : 'bg-yellow-100 text-yellow-600'
|
|
}`}>
|
|
高价值
|
|
</span>
|
|
)}
|
|
{record.isReusable && (
|
|
<span className={`px-1.5 py-0.5 rounded text-xs ${
|
|
isDark ? 'bg-green-600/30 text-green-400' : 'bg-green-100 text-green-600'
|
|
}`}>
|
|
可复用
|
|
</span>
|
|
)}
|
|
{record.isConvertible && (
|
|
<span className={`px-1.5 py-0.5 rounded text-xs ${
|
|
isDark ? 'bg-blue-600/30 text-blue-400' : 'bg-blue-100 text-blue-600'
|
|
}`}>
|
|
可转任务
|
|
</span>
|
|
)}
|
|
</div>
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
{filteredRecords.length === 0 && (
|
|
<div className={`text-center py-8 ${isDark ? 'text-slate-500' : 'text-gray-400'}`}>
|
|
<History className="w-12 h-12 mx-auto mb-3 opacity-50" />
|
|
<p>暂无匹配记录</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* 中间记录详情 */}
|
|
<div className="flex-1 overflow-y-auto p-6">
|
|
{selectedRecord ? (
|
|
<div className="max-w-3xl mx-auto">
|
|
{/* 问题 */}
|
|
<div className={`p-4 rounded-xl mb-4 ${isDark ? 'bg-slate-700/50' : 'bg-gray-50'}`}>
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<span className={`px-1.5 py-0.5 rounded text-xs font-medium ${
|
|
isDark ? 'bg-slate-600 text-slate-300' : 'bg-gray-200 text-gray-600'
|
|
}`}>
|
|
问题
|
|
</span>
|
|
</div>
|
|
<p className={`text-lg ${isDark ? 'text-white' : 'text-gray-900'}`}>
|
|
{selectedRecord.question}
|
|
</p>
|
|
</div>
|
|
|
|
{/* 回答 */}
|
|
<div className={`p-4 rounded-xl mb-4 ${isDark ? 'bg-slate-700/50' : 'bg-gray-50'}`}>
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<span className={`px-1.5 py-0.5 rounded text-xs font-medium ${
|
|
isDark ? 'bg-blue-600/30 text-blue-400' : 'bg-blue-100 text-blue-600'
|
|
}`}>
|
|
{selectedRecord.type === 'general' ? 'RAG回答' : '智能体回答'}
|
|
</span>
|
|
<span className={`px-1.5 py-0.5 rounded text-xs font-medium ${getModeColor(selectedRecord.mode)}`}>
|
|
{getModeLabel(selectedRecord.mode)}
|
|
</span>
|
|
{selectedRecord.agentName && (
|
|
<span className={`px-1.5 py-0.5 rounded text-xs font-medium ${
|
|
isDark ? 'bg-purple-600/30 text-purple-400' : 'bg-purple-100 text-purple-600'
|
|
}`}>
|
|
{selectedRecord.agentName}
|
|
</span>
|
|
)}
|
|
</div>
|
|
<p className={`whitespace-pre-wrap ${isDark ? 'text-slate-300' : 'text-gray-700'}`}>
|
|
{selectedRecord.answer}
|
|
</p>
|
|
</div>
|
|
|
|
{/* 来源摘要 */}
|
|
{selectedRecord.sources && selectedRecord.sources.length > 0 && (
|
|
<div className={`p-4 rounded-xl mb-4 ${isDark ? 'bg-slate-700/50' : 'bg-gray-50'}`}>
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<FileText className={`w-4 h-4 ${isDark ? 'text-slate-400' : 'text-gray-500'}`} />
|
|
<span className={`text-sm font-medium ${isDark ? 'text-slate-300' : 'text-gray-700'}`}>
|
|
来源摘要
|
|
</span>
|
|
</div>
|
|
<div className="flex flex-wrap gap-2">
|
|
{selectedRecord.sources.map((source, idx) => (
|
|
<span
|
|
key={idx}
|
|
className={`px-3 py-1 rounded-lg text-sm ${
|
|
isDark ? 'bg-slate-600/50 text-slate-300' : 'bg-white text-gray-600 border border-gray-200'
|
|
}`}
|
|
>
|
|
{source}
|
|
</span>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* 评价 */}
|
|
{selectedRecord.evaluation && (
|
|
<div className={`p-4 rounded-xl mb-4 ${isDark ? 'bg-yellow-600/20 border border-yellow-600/30' : 'bg-yellow-50 border border-yellow-200'}`}>
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<Star className={`w-4 h-4 ${isDark ? 'text-yellow-400' : 'text-yellow-500'}`} />
|
|
<span className={`text-sm font-medium ${isDark ? 'text-yellow-400' : 'text-yellow-700'}`}>
|
|
人工评价
|
|
</span>
|
|
</div>
|
|
<p className={`text-sm ${isDark ? 'text-yellow-300' : 'text-yellow-700'}`}>
|
|
{selectedRecord.evaluation}
|
|
</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
) : (
|
|
<div className={`h-full flex flex-col items-center justify-center ${isDark ? 'text-slate-500' : 'text-gray-400'}`}>
|
|
<MessageSquare className="w-16 h-16 mb-4 opacity-50" />
|
|
<p className="text-lg">选择一条记录查看详情</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* 右侧操作与标签区 */}
|
|
<div className={`w-72 border-l flex-shrink-0 overflow-y-auto p-4 ${isDark ? 'border-slate-700/50 bg-slate-800/30' : 'border-red-100 bg-gray-50/50'}`}>
|
|
{selectedRecord ? (
|
|
<>
|
|
{/* 记录标签 */}
|
|
<div className="mb-6">
|
|
<h3 className={`text-sm font-medium mb-3 ${isDark ? 'text-slate-300' : 'text-gray-700'}`}>
|
|
记录标签
|
|
</h3>
|
|
<div className="space-y-2">
|
|
<button
|
|
onClick={() => toggleCollect(selectedRecord.id)}
|
|
className={`w-full flex items-center gap-3 p-3 rounded-lg transition-all ${
|
|
selectedRecord.isCollected
|
|
? isDark
|
|
? 'bg-yellow-600/20 border border-yellow-600/50'
|
|
: 'bg-yellow-50 border border-yellow-200'
|
|
: isDark
|
|
? 'bg-slate-700/50 border border-transparent hover:bg-slate-600/50'
|
|
: 'bg-white border border-gray-200 hover:bg-gray-50'
|
|
}`}
|
|
>
|
|
{selectedRecord.isCollected ? (
|
|
<BookmarkCheck className={`w-5 h-5 ${isDark ? 'text-yellow-400' : 'text-yellow-500'}`} />
|
|
) : (
|
|
<Bookmark className={`w-5 h-5 ${isDark ? 'text-slate-400' : 'text-gray-400'}`} />
|
|
)}
|
|
<span className={`text-sm ${isDark ? 'text-slate-300' : 'text-gray-700'}`}>
|
|
{selectedRecord.isCollected ? '已收藏' : '收藏'}
|
|
</span>
|
|
</button>
|
|
|
|
<button
|
|
className={`w-full flex items-center gap-3 p-3 rounded-lg transition-all ${
|
|
selectedRecord.isHighValue
|
|
? isDark
|
|
? 'bg-yellow-600/20 border border-yellow-600/50'
|
|
: 'bg-yellow-50 border border-yellow-200'
|
|
: isDark
|
|
? 'bg-slate-700/50 border border-transparent hover:bg-slate-600/50'
|
|
: 'bg-white border border-gray-200 hover:bg-gray-50'
|
|
}`}
|
|
>
|
|
<Star className={`w-5 h-5 ${selectedRecord.isHighValue ? (isDark ? 'text-yellow-400' : 'text-yellow-500') : (isDark ? 'text-slate-400' : 'text-gray-400')}`} />
|
|
<span className={`text-sm ${isDark ? 'text-slate-300' : 'text-gray-700'}`}>
|
|
高价值
|
|
</span>
|
|
</button>
|
|
|
|
<button
|
|
className={`w-full flex items-center gap-3 p-3 rounded-lg transition-all ${
|
|
selectedRecord.isReusable
|
|
? isDark
|
|
? 'bg-green-600/20 border border-green-600/50'
|
|
: 'bg-green-50 border border-green-200'
|
|
: isDark
|
|
? 'bg-slate-700/50 border border-transparent hover:bg-slate-600/50'
|
|
: 'bg-white border border-gray-200 hover:bg-gray-50'
|
|
}`}
|
|
>
|
|
<Copy className={`w-5 h-5 ${selectedRecord.isReusable ? (isDark ? 'text-green-400' : 'text-green-500') : (isDark ? 'text-slate-400' : 'text-gray-400')}`} />
|
|
<span className={`text-sm ${isDark ? 'text-slate-300' : 'text-gray-700'}`}>
|
|
可复用
|
|
</span>
|
|
</button>
|
|
|
|
<button
|
|
className={`w-full flex items-center gap-3 p-3 rounded-lg transition-all ${
|
|
selectedRecord.isConvertible
|
|
? isDark
|
|
? 'bg-blue-600/20 border border-blue-600/50'
|
|
: 'bg-blue-50 border border-blue-200'
|
|
: isDark
|
|
? 'bg-slate-700/50 border border-transparent hover:bg-slate-600/50'
|
|
: 'bg-white border border-gray-200 hover:bg-gray-50'
|
|
}`}
|
|
>
|
|
<ArrowRight className={`w-5 h-5 ${selectedRecord.isConvertible ? (isDark ? 'text-blue-400' : 'text-blue-500') : (isDark ? 'text-slate-400' : 'text-gray-400')}`} />
|
|
<span className={`text-sm ${isDark ? 'text-slate-300' : 'text-gray-700'}`}>
|
|
可转任务
|
|
</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 操作按钮 */}
|
|
<div className="mb-6">
|
|
<h3 className={`text-sm font-medium mb-3 ${isDark ? 'text-slate-300' : 'text-gray-700'}`}>
|
|
操作
|
|
</h3>
|
|
<div className="space-y-2">
|
|
<button
|
|
onClick={() => toggleCollect(selectedRecord.id)}
|
|
className={`w-full flex items-center gap-3 p-3 rounded-lg transition-all ${
|
|
isDark
|
|
? 'bg-slate-700/50 hover:bg-slate-600/50 text-slate-300'
|
|
: 'bg-white hover:bg-gray-50 text-gray-700 border border-gray-200'
|
|
}`}
|
|
>
|
|
{selectedRecord.isCollected ? (
|
|
<>
|
|
<BookmarkCheck className="w-5 h-5 text-yellow-500" />
|
|
<span className="text-sm">取消收藏</span>
|
|
</>
|
|
) : (
|
|
<>
|
|
<Bookmark className="w-5 h-5" />
|
|
<span className="text-sm">收藏</span>
|
|
</>
|
|
)}
|
|
</button>
|
|
|
|
<button
|
|
onClick={() => exportRecord(selectedRecord)}
|
|
className={`w-full flex items-center gap-3 p-3 rounded-lg transition-all ${
|
|
isDark
|
|
? 'bg-slate-700/50 hover:bg-slate-600/50 text-slate-300'
|
|
: 'bg-white hover:bg-gray-50 text-gray-700 border border-gray-200'
|
|
}`}
|
|
>
|
|
<Download className="w-5 h-5" />
|
|
<span className="text-sm">导出</span>
|
|
</button>
|
|
|
|
<button
|
|
onClick={() => copyQuestion(selectedRecord.question)}
|
|
className={`w-full flex items-center gap-3 p-3 rounded-lg transition-all ${
|
|
isDark
|
|
? 'bg-slate-700/50 hover:bg-slate-600/50 text-slate-300'
|
|
: 'bg-white hover:bg-gray-50 text-gray-700 border border-gray-200'
|
|
}`}
|
|
>
|
|
<Copy className="w-5 h-5" />
|
|
<span className="text-sm">复制问题</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 转任务 */}
|
|
{selectedRecord.isConvertible && (
|
|
<div className="mb-6">
|
|
<h3 className={`text-sm font-medium mb-3 ${isDark ? 'text-slate-300' : 'text-gray-700'}`}>
|
|
转为任务
|
|
</h3>
|
|
<div className="space-y-2">
|
|
<button
|
|
onClick={() => convertToTask(selectedRecord, 'single')}
|
|
className={`w-full flex items-center gap-3 p-3 rounded-lg transition-all ${
|
|
isDark
|
|
? 'bg-blue-600/20 hover:bg-blue-600/30 text-blue-400 border border-blue-600/50'
|
|
: 'bg-blue-50 hover:bg-blue-100 text-blue-600 border border-blue-200'
|
|
}`}
|
|
>
|
|
<Bot className="w-5 h-5" />
|
|
<span className="text-sm flex-1 text-left">转单智能体任务</span>
|
|
<ArrowRight className="w-4 h-4" />
|
|
</button>
|
|
|
|
<button
|
|
onClick={() => convertToTask(selectedRecord, 'consult')}
|
|
className={`w-full flex items-center gap-3 p-3 rounded-lg transition-all ${
|
|
isDark
|
|
? 'bg-purple-600/20 hover:bg-purple-600/30 text-purple-400 border border-purple-600/50'
|
|
: 'bg-purple-50 hover:bg-purple-100 text-purple-600 border border-purple-200'
|
|
}`}
|
|
>
|
|
<MessageSquare className="w-5 h-5" />
|
|
<span className="text-sm flex-1 text-left">转多智能体会商</span>
|
|
<ArrowRight className="w-4 h-4" />
|
|
</button>
|
|
|
|
<button
|
|
onClick={() => convertToTask(selectedRecord, 'scene')}
|
|
className={`w-full flex items-center gap-3 p-3 rounded-lg transition-all ${
|
|
isDark
|
|
? 'bg-green-600/20 hover:bg-green-600/30 text-green-400 border border-green-600/50'
|
|
: 'bg-green-50 hover:bg-green-100 text-green-600 border border-green-200'
|
|
}`}
|
|
>
|
|
<GitCompare className="w-5 h-5" />
|
|
<span className="text-sm flex-1 text-left">转场景任务</span>
|
|
<ArrowRight className="w-4 h-4" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* 备注 */}
|
|
<div>
|
|
<h3 className={`text-sm font-medium mb-3 ${isDark ? 'text-slate-300' : 'text-gray-700'}`}>
|
|
备注
|
|
</h3>
|
|
<textarea
|
|
value={notesInput}
|
|
onChange={(e) => setNotesInput(e.target.value)}
|
|
placeholder="添加人工评价或后续处理建议..."
|
|
rows={4}
|
|
className={`w-full p-3 rounded-lg text-sm resize-none focus:outline-none ${
|
|
isDark
|
|
? 'bg-slate-700/50 text-slate-300 placeholder-slate-500 border border-slate-600'
|
|
: 'bg-white text-gray-700 placeholder-gray-400 border border-gray-200'
|
|
}`}
|
|
/>
|
|
{notesInput !== (selectedRecord.notes || '') && (
|
|
<button
|
|
onClick={() => {
|
|
setRecords(records.map(r =>
|
|
r.id === selectedRecord.id ? { ...r, notes: notesInput } : r
|
|
));
|
|
setSelectedRecord({ ...selectedRecord, notes: notesInput });
|
|
alert('备注已保存');
|
|
}}
|
|
className={`w-full mt-2 px-4 py-2 rounded-lg text-sm font-medium transition-all ${
|
|
isDark
|
|
? 'bg-blue-600 hover:bg-blue-700 text-white'
|
|
: 'bg-red-500 hover:bg-red-600 text-white'
|
|
}`}
|
|
>
|
|
保存备注
|
|
</button>
|
|
)}
|
|
</div>
|
|
</>
|
|
) : (
|
|
<div className={`h-full flex flex-col items-center justify-center ${isDark ? 'text-slate-500' : 'text-gray-400'}`}>
|
|
<MessageSquare className="w-12 h-12 mb-3 opacity-50" />
|
|
<p className="text-sm">选择记录后可操作</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default QARecords;
|