import { useState, useEffect } from 'react'; import { Button, Modal, Form, Input, Select, message, Row, Col, Empty, Tabs, Card, Tag, Space, Divider, Typography, InputNumber } from 'antd'; import { ThunderboltOutlined, PlusOutlined, EditOutlined, DeleteOutlined, TrophyOutlined } from '@ant-design/icons'; import { useParams } from 'react-router-dom'; import api from '../services/api'; import SSEProgressModal from '../components/SSEProgressModal'; const { TextArea } = Input; const { Title, Text, Paragraph } = Typography; interface CareerStage { level: number; name: string; description?: string; } interface Career { id: string; project_id: string; name: string; type: 'main' | 'sub'; description?: string; category?: string; stages: CareerStage[]; max_stage: number; requirements?: string; special_abilities?: string; worldview_rules?: string; source: string; } export default function Careers() { const { projectId } = useParams<{ projectId: string }>(); const [mainCareers, setMainCareers] = useState([]); const [subCareers, setSubCareers] = useState([]); const [, setLoading] = useState(true); const [isModalOpen, setIsModalOpen] = useState(false); const [isAIModalOpen, setIsAIModalOpen] = useState(false); const [editingCareer, setEditingCareer] = useState(null); const [form] = Form.useForm(); const [aiForm] = Form.useForm(); // AI生成状态 const [aiGenerating, setAiGenerating] = useState(false); const [aiProgress, setAiProgress] = useState(0); const [aiMessage, setAiMessage] = useState(''); useEffect(() => { if (projectId) { fetchCareers(); } }, [projectId]); const fetchCareers = async () => { try { setLoading(true); const response: any = await api.get('/careers', { params: { project_id: projectId } }); setMainCareers(response.main_careers || []); setSubCareers(response.sub_careers || []); } catch (error: any) { console.error('获取职业列表失败:', error); } finally { setLoading(false); } }; const handleOpenModal = (career?: Career) => { if (career) { setEditingCareer(career); form.setFieldsValue({ ...career, stages: career.stages.map(s => `${s.level}. ${s.name}${s.description ? ` - ${s.description}` : ''}`).join('\n') }); } else { setEditingCareer(null); form.resetFields(); } setIsModalOpen(true); }; const handleSubmit = async (values: any) => { try { // 解析阶段数据 const stagesText = values.stages || ''; const stages: CareerStage[] = stagesText.split('\n') .filter((line: string) => line.trim()) .map((line: string, index: number) => { const match = line.match(/^(\d+)\.\s*([^-]+)(?:\s*-\s*(.*))?$/); if (match) { return { level: parseInt(match[1]), name: match[2].trim(), description: match[3]?.trim() || '' }; } return { level: index + 1, name: line.trim(), description: '' }; }); const data = { ...values, stages, max_stage: stages.length }; if (editingCareer) { await api.put(`/careers/${editingCareer.id}`, data); message.success('职业更新成功'); } else { await api.post('/careers', { ...data, project_id: projectId, source: 'manual' }); message.success('职业创建成功'); } setIsModalOpen(false); form.resetFields(); fetchCareers(); } catch (error: any) { message.error(error.response?.data?.detail || '操作失败'); } }; const handleDelete = async (id: string) => { Modal.confirm({ title: '确认删除', content: '确定要删除这个职业吗?如果有角色使用了该职业,将无法删除。', onOk: async () => { try { await api.delete(`/careers/${id}`); message.success('职业删除成功'); fetchCareers(); } catch (error: any) { message.error(error.response?.data?.detail || '删除失败'); } } }); }; const handleAIGenerate = async (values: any) => { setIsAIModalOpen(false); setAiGenerating(true); setAiProgress(0); setAiMessage('开始生成新职业...'); try { const eventSource = new EventSource( `/api/careers/generate-system?` + new URLSearchParams({ project_id: projectId || '', main_career_count: values.main_career_count.toString(), sub_career_count: values.sub_career_count.toString(), enable_mcp: 'false' }).toString(), { withCredentials: true } ); eventSource.onmessage = (event) => { try { const data = JSON.parse(event.data); if (data.type === 'progress') { setAiProgress(data.progress || 0); setAiMessage(data.message || ''); } else if (data.type === 'done') { eventSource.close(); setTimeout(() => { setAiGenerating(false); message.success('AI新职业生成完成!'); fetchCareers(); }, 1000); } else if (data.type === 'error') { eventSource.close(); setAiGenerating(false); message.error(data.message || '生成失败'); } } catch (e) { console.error('解析SSE数据失败:', e); } }; eventSource.onerror = () => { eventSource.close(); setAiGenerating(false); message.error('连接中断,生成失败'); }; } catch (err: any) { setAiGenerating(false); message.error(err.message || '启动生成失败'); } }; const renderCareerCard = (career: Career) => ( {career.name} {career.source === 'ai' ? 'AI生成' : '手动创建'} {career.category && {career.category}} } extra={ {/* 可滚动的内容区域 */}
{/* 创建/编辑对话框 */} { setIsModalOpen(false); form.resetFields(); }} footer={null} width={700} >