import { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { Card, Table, Button, Select, Tag, Space, Modal, message, Tabs, Typography, Statistic, Row, Col, } from 'antd'; import { CheckOutlined, CloseOutlined, EyeOutlined, PlayCircleOutlined, } from '@ant-design/icons'; import api from '../../../../shared/utils/api'; import { useAuth } from '../../../../shared/hooks/useAuth'; const { Title, Text, Paragraph } = Typography; const EXPERIENCE_TYPES = [ { value: 'COMMON_QUESTION', label: '常见问题' }, { value: 'ANSWER_TEMPLATE', label: '回答模板' }, { value: 'CLARIFICATION', label: '澄清方式' }, { value: 'USER_PATTERN', label: '用户模式' }, { value: 'CONVERSION_TRIGGER', label: '转化触发' }, { value: 'KNOWLEDGE_GAP', label: '知识缺口' }, { value: 'CONVERSATION_SKILL', label: '对话技巧' }, { value: 'OBJECTION_HANDLING', label: '异议处理' }, ]; interface Experience { id: string; experienceType: string; content: string; scenario: string; confidence: number; relatedCategory: string; sourceConversationIds: string[]; verificationStatus: string; usageCount: number; positiveCount: number; negativeCount: number; isActive: boolean; createdAt: string; } export function ExperiencePage() { const [activeTab, setActiveTab] = useState('pending'); const [typeFilter, setTypeFilter] = useState(); const [selectedExperience, setSelectedExperience] = useState(null); const [isModalOpen, setIsModalOpen] = useState(false); const queryClient = useQueryClient(); const admin = useAuth((state) => state.admin); const { data: pendingData, isLoading: pendingLoading } = useQuery({ queryKey: ['pending-experiences', typeFilter], queryFn: async () => { const params = new URLSearchParams(); if (typeFilter) params.append('type', typeFilter); const response = await api.get(`/memory/experience/pending?${params}`); return response.data.data; }, enabled: activeTab === 'pending', }); const { data: stats } = useQuery({ queryKey: ['experience-stats'], queryFn: async () => { const response = await api.get('/memory/experience/statistics'); return response.data.data; }, }); const approveMutation = useMutation({ mutationFn: (id: string) => api.post(`/memory/experience/${id}/approve`, { adminId: admin?.id }), onSuccess: () => { message.success('经验已批准'); queryClient.invalidateQueries({ queryKey: ['pending-experiences'] }); queryClient.invalidateQueries({ queryKey: ['experience-stats'] }); }, }); const rejectMutation = useMutation({ mutationFn: (id: string) => api.post(`/memory/experience/${id}/reject`, { adminId: admin?.id }), onSuccess: () => { message.success('经验已拒绝'); queryClient.invalidateQueries({ queryKey: ['pending-experiences'] }); queryClient.invalidateQueries({ queryKey: ['experience-stats'] }); }, }); const runEvolutionMutation = useMutation({ mutationFn: () => api.post('/evolution/run', { hoursBack: 24, limit: 50 }), onSuccess: (response) => { const result = response.data.data; message.success( `进化任务完成:分析了${result.conversationsAnalyzed}个对话,提取了${result.experiencesExtracted}条经验` ); queryClient.invalidateQueries({ queryKey: ['pending-experiences'] }); queryClient.invalidateQueries({ queryKey: ['experience-stats'] }); }, }); const handleView = (exp: Experience) => { setSelectedExperience(exp); setIsModalOpen(true); }; const getTypeLabel = (type: string) => { return EXPERIENCE_TYPES.find((t) => t.value === type)?.label || type; }; const getStatusTag = (status: string) => { const statusMap: Record = { PENDING: { color: 'orange', label: '待审核' }, APPROVED: { color: 'green', label: '已通过' }, REJECTED: { color: 'red', label: '已拒绝' }, DEPRECATED: { color: 'default', label: '已弃用' }, }; const s = statusMap[status] || { color: 'default', label: status }; return {s.label}; }; const columns = [ { title: '类型', dataIndex: 'experienceType', key: 'experienceType', render: (type: string) => {getTypeLabel(type)}, }, { title: '场景', dataIndex: 'scenario', key: 'scenario', ellipsis: true, }, { title: '内容', dataIndex: 'content', key: 'content', ellipsis: true, render: (text: string) => ( {text} ), }, { title: '置信度', dataIndex: 'confidence', key: 'confidence', render: (confidence: number) => ( = 70 ? 'text-green-600' : confidence >= 40 ? 'text-yellow-600' : 'text-red-600' } > {confidence}% ), }, { title: '来源对话', dataIndex: 'sourceConversationIds', key: 'sources', render: (ids: string[]) => {ids?.length || 0}个, }, { title: '状态', dataIndex: 'verificationStatus', key: 'status', render: getStatusTag, }, { title: '操作', key: 'action', render: (_: unknown, record: Experience) => ( {/* 统计卡片 */}