import { useState, useEffect } from 'react'; import { Button, List, Modal, Form, Input, message, Empty, Space, Popconfirm, Card, Select, Radio, Tag, InputNumber, Tooltip, Tabs } from 'antd'; import { EditOutlined, DeleteOutlined, ThunderboltOutlined, BranchesOutlined, AppstoreAddOutlined, CheckCircleOutlined, ExclamationCircleOutlined } from '@ant-design/icons'; import { useStore } from '../store'; import { useOutlineSync } from '../store/hooks'; import { cardStyles } from '../components/CardStyles'; import { SSEPostClient } from '../utils/sseClient'; import { SSEProgressModal } from '../components/SSEProgressModal'; import { outlineApi, chapterApi } from '../services/api'; import type { OutlineExpansionResponse, BatchOutlineExpansionResponse } from '../types'; const { TextArea } = Input; export default function Outline() { const { currentProject, outlines } = useStore(); const [isGenerating, setIsGenerating] = useState(false); const [editForm] = Form.useForm(); const [generateForm] = Form.useForm(); const [expansionForm] = Form.useForm(); const [batchExpansionForm] = Form.useForm(); const [isMobile, setIsMobile] = useState(window.innerWidth <= 768); const [isExpanding, setIsExpanding] = useState(false); // ✅ 新增:记录每个大纲的展开状态 const [outlineExpandStatus, setOutlineExpandStatus] = useState>({}); // 缓存批量展开的规划数据,避免重复AI调用 const [cachedBatchExpansionResponse, setCachedBatchExpansionResponse] = useState(null); // 批量展开预览的状态 const [batchPreviewVisible, setBatchPreviewVisible] = useState(false); const [batchPreviewData, setBatchPreviewData] = useState(null); const [selectedOutlineIdx, setSelectedOutlineIdx] = useState(0); const [selectedChapterIdx, setSelectedChapterIdx] = useState(0); // SSE进度状态 const [sseProgress, setSSEProgress] = useState(0); const [sseMessage, setSSEMessage] = useState(''); const [sseModalVisible, setSSEModalVisible] = useState(false); useEffect(() => { const handleResize = () => { setIsMobile(window.innerWidth <= 768); }; window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, []); // 使用同步 hooks const { refreshOutlines, updateOutline, deleteOutline } = useOutlineSync(); // 初始加载大纲列表 useEffect(() => { if (currentProject?.id) { refreshOutlines(); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [currentProject?.id]); // 只依赖 ID,不依赖函数 // ✅ 新增:加载所有大纲的展开状态 useEffect(() => { const loadExpandStatus = async () => { if (outlines.length === 0) return; const statusMap: Record = {}; for (const outline of outlines) { try { const chapters = await outlineApi.getOutlineChapters(outline.id); statusMap[outline.id] = chapters.has_chapters; } catch (error) { console.error(`加载大纲 ${outline.id} 状态失败:`, error); statusMap[outline.id] = false; } } setOutlineExpandStatus(statusMap); }; loadExpandStatus(); }, [outlines]); // 移除事件监听,避免无限循环 // Hook 内部已经更新了 store,不需要再次刷新 if (!currentProject) return null; // 确保大纲按 order_index 排序 const sortedOutlines = [...outlines].sort((a, b) => a.order_index - b.order_index); const handleOpenEditModal = (id: string) => { const outline = outlines.find(o => o.id === id); if (outline) { editForm.setFieldsValue(outline); Modal.confirm({ title: '编辑大纲', width: 600, centered: true, content: (