import { useState, useEffect } from 'react'; import { Button, Modal, Form, Input, Select, message, Row, Col, Empty, Tabs, Divider, Typography, Space, InputNumber } from 'antd'; import { ThunderboltOutlined, UserOutlined, TeamOutlined, PlusOutlined } from '@ant-design/icons'; import { useStore } from '../store'; import { useCharacterSync } from '../store/hooks'; import { characterGridConfig } from '../components/CardStyles'; import { CharacterCard } from '../components/CharacterCard'; import { SSELoadingOverlay } from '../components/SSELoadingOverlay'; import type { Character, CharacterUpdate } from '../types'; import { characterApi } from '../services/api'; import { SSEPostClient } from '../utils/sseClient'; const { Title } = Typography; const { TextArea } = Input; export default function Characters() { const { currentProject, characters } = useStore(); const [isGenerating, setIsGenerating] = useState(false); const [progress, setProgress] = useState(0); const [progressMessage, setProgressMessage] = useState(''); const [activeTab, setActiveTab] = useState<'all' | 'character' | 'organization'>('all'); const [generateForm] = Form.useForm(); const [generateOrgForm] = Form.useForm(); const [createForm] = Form.useForm(); const [editForm] = Form.useForm(); const [isEditModalOpen, setIsEditModalOpen] = useState(false); const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); const [createType, setCreateType] = useState<'character' | 'organization'>('character'); const [editingCharacter, setEditingCharacter] = useState(null); const { refreshCharacters, deleteCharacter } = useCharacterSync(); useEffect(() => { if (currentProject?.id) { refreshCharacters(); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [currentProject?.id]); const [modal, contextHolder] = Modal.useModal(); if (!currentProject) return null; const handleDeleteCharacter = async (id: string) => { try { await deleteCharacter(id); message.success('删除成功'); } catch { message.error('删除失败'); } }; const handleGenerate = async (values: { name?: string; role_type: string; background?: string }) => { try { setIsGenerating(true); setProgress(0); setProgressMessage('准备生成角色...'); const client = new SSEPostClient( '/api/characters/generate-stream', { project_id: currentProject.id, name: values.name, role_type: values.role_type, background: values.background, }, { onProgress: (msg, prog) => { setProgress(prog); setProgressMessage(msg); }, onResult: (data) => { console.log('角色生成完成:', data); }, onError: (error) => { message.error(`生成失败: ${error}`); }, onComplete: () => { setProgress(100); setProgressMessage('生成完成!'); } } ); await client.connect(); message.success('AI生成角色成功'); Modal.destroyAll(); await refreshCharacters(); } catch (error: any) { message.error(error.message || 'AI生成失败'); } finally { setTimeout(() => { setIsGenerating(false); setProgress(0); setProgressMessage(''); }, 500); } }; const handleGenerateOrganization = async (values: { name?: string; organization_type?: string; background?: string; requirements?: string; }) => { try { setIsGenerating(true); setProgress(0); setProgressMessage('准备生成组织...'); const client = new SSEPostClient( '/api/organizations/generate-stream', { project_id: currentProject.id, name: values.name, organization_type: values.organization_type, background: values.background, requirements: values.requirements, }, { onProgress: (msg, prog) => { setProgress(prog); setProgressMessage(msg); }, onResult: (data) => { console.log('组织生成完成:', data); }, onError: (error) => { message.error(`生成失败: ${error}`); }, onComplete: () => { setProgress(100); setProgressMessage('生成完成!'); } } ); await client.connect(); message.success('AI生成组织成功'); Modal.destroyAll(); await refreshCharacters(); } catch (error: any) { message.error(error.message || 'AI生成失败'); } finally { setTimeout(() => { setIsGenerating(false); setProgress(0); setProgressMessage(''); }, 500); } }; const handleCreateCharacter = async (values: any) => { try { const createData: any = { project_id: currentProject.id, name: values.name, is_organization: createType === 'organization', }; if (createType === 'character') { // 角色字段 createData.age = values.age; createData.gender = values.gender; createData.role_type = values.role_type || 'supporting'; createData.personality = values.personality; createData.appearance = values.appearance; createData.relationships = values.relationships; createData.background = values.background; } else { // 组织字段 createData.organization_type = values.organization_type; createData.organization_purpose = values.organization_purpose; createData.organization_members = values.organization_members; createData.background = values.background; createData.power_level = values.power_level; createData.location = values.location; createData.motto = values.motto; createData.color = values.color; createData.role_type = 'supporting'; // 组织默认为配角 } await characterApi.createCharacter(createData); message.success(`${createType === 'character' ? '角色' : '组织'}创建成功`); setIsCreateModalOpen(false); createForm.resetFields(); await refreshCharacters(); } catch { message.error('创建失败'); } }; const handleEditCharacter = (character: Character) => { setEditingCharacter(character); editForm.setFieldsValue(character); setIsEditModalOpen(true); }; const handleUpdateCharacter = async (values: CharacterUpdate) => { if (!editingCharacter) return; try { await characterApi.updateCharacter(editingCharacter.id, values); message.success('更新成功'); setIsEditModalOpen(false); editForm.resetFields(); setEditingCharacter(null); await refreshCharacters(); } catch { message.error('更新失败'); } }; const handleDeleteCharacterWrapper = (id: string) => { handleDeleteCharacter(id); }; const showGenerateModal = () => { modal.confirm({ title: 'AI生成角色', width: 600, centered: true, content: (