Files
deerflow-code/web-code/pages/QARecords.tsx
T
2026-05-27 19:43:15 +08:00

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;