import { useState, useCallback } from 'react' import { toast } from 'sonner' import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import { Scale, Loader2, Plus, Trash2, Save, History } from 'lucide-react' import { aiApi, employeeApi } from '../../lib/api-services' import Card from '../../components/ui/Card' import Button from '../../components/ui/Button' import { Input, Label, Select } from '../../components/ui/Input' import Modal from '../../components/ui/Modal' /** 解析 markdown 内联格式(**bold** 和 `code`)为 TextRun 数组 */ // 通用 AI 历史记录 hook function useAIHistory(type: 'predict' | 'review' | 'case') { const queryClient = useQueryClient() const queryKey = [`ai-history-${type}`] const { data: history } = useQuery({ queryKey, queryFn: async () => { return await aiApi.conversations(type) }, }) const saveMutation = useMutation({ mutationFn: async ({ title, input, result }: { title: string; input: string; result: string }) => { const res = await aiApi.createConversation({ title: `${type}:${title}`, messages: [{ role: 'user', content: input }, { role: 'assistant', content: result }], }) as any return res }, onSuccess: () => queryClient.invalidateQueries({ queryKey }), }) const deleteMutation = useMutation({ mutationFn: (id: string) => aiApi.removeConversation(id), onSuccess: () => queryClient.invalidateQueries({ queryKey }), }) const loadHistory = useCallback(async (id: string) => { return await aiApi.conversation(id) }, []) return { history, saveMutation, deleteMutation, loadHistory } } // 通用历史记录栏组件 function HistoryBar({ history, onLoad, onDelete }: { history: any[] onLoad: (id: string) => void onDelete: (id: string) => void }) { return (
{history.length > 0 ? history.map((c: any) => (
onLoad(c.id)}> {c.title.replace(/^(predict:|review:|case:)/, '')} {new Date(c.updatedAt).toLocaleDateString('zh-CN', { month: '2-digit', day: '2-digit' })}
)) :
暂无历史记录
}
) } export function CaseTab() { const [scenario, setScenario] = useState('') const [result, setResult] = useState('') const [loading, setLoading] = useState(false) const [showSaveModal, setShowSaveModal] = useState(false) const [saveEmployeeId, setSaveEmployeeId] = useState('') const [showHistory, setShowHistory] = useState(false) const [showTodoModal, setShowTodoModal] = useState(false) const [todoEmployeeId, setTodoEmployeeId] = useState('') const [todoTitle, setTodoTitle] = useState('') const [todoLevel, setTodoLevel] = useState('MEDIUM') const [todoType, setTodoType] = useState('TERMINATION') const [creatingTodo, setCreatingTodo] = useState(false) const { history, saveMutation, deleteMutation, loadHistory } = useAIHistory('case') const { data: employees } = useQuery({ queryKey: ['employee-list'], queryFn: () => employeeApi.list({ status: 'ACTIVE' }), }) const handleMatch = async () => { if (!scenario.trim()) return setLoading(true) setResult('') try { const res = await aiApi.matchCase(scenario) as any setResult(res.result) // 自动保存到历史 if (res?.result && !res.result.startsWith('出错了')) { const title = scenario.slice(0, 30).replace(/\n/g, ' ') saveMutation.mutate({ title, input: scenario, result: res.data.result }) } } catch (err: any) { setResult(`出错了:${err.response?.data?.error?.message || '请稍后重试'}`) } finally { setLoading(false) } } const handleLoadHistory = async (id: string) => { const data = await loadHistory(id) if (data?.messages) { const userMsg = data.messages.find((m: any) => m.role === 'user') const assistantMsg = data.messages.find((m: any) => m.role === 'assistant') if (userMsg) setScenario(userMsg.content) if (assistantMsg) setResult(assistantMsg.content) setShowHistory(false) } } const handleSave = async () => { if (!saveEmployeeId || !result) return try { await aiApi.reviewSave({ employeeId: saveEmployeeId, type: 'CASE', input: scenario, result }) setShowSaveModal(false) setSaveEmployeeId('') toast.success('已保存到员工档案') } catch (err: any) { toast.error('保存失败:' + (err.response?.data?.error?.message || '请稍后重试')) } } const handleCreateTodo = async () => { if (!todoEmployeeId || !todoTitle) return setCreatingTodo(true) try { await aiApi.caseToTodo({ employeeId: todoEmployeeId, title: todoTitle, description: result.slice(0, 500), level: todoLevel, type: todoType, }) setShowTodoModal(false) setTodoEmployeeId('') setTodoTitle('') toast.success('已创建待办风险项') } catch (err: any) { toast.error('创建失败:' + (err.response?.data?.error?.message || '请稍后重试')) } finally { setCreatingTodo(false) } } return (

案例匹配

{showHistory && (
deleteMutation.mutate(id)} />
)}