+
+
+ AI 分析结果
+
+
+ {characterConfirmData.reason}
+
+
{characterConfirmData.chapter_range}
+
{characterConfirmData.predicted_characters.length} 个预测角色
+
+
+
+
+
+
+
+
+
+
(
+ {
+ if (selectedCharacterIndices.includes(index)) {
+ setSelectedCharacterIndices(selectedCharacterIndices.filter(i => i !== index));
+ } else {
+ setSelectedCharacterIndices([...selectedCharacterIndices, index]);
+ }
+ }}
+ >
+
+
+
+ { }}
+ style={{ cursor: 'pointer' }}
+ />
+
+ {character.name || character.role_description}
+
+ {character.suggested_role_type}
+ {character.importance}
+
+ 第{character.appearance_chapter}章登场
+
+
+
+ 剧情作用:{character.plot_function}
+
+
+ {character.key_abilities && character.key_abilities.length > 0 && (
+
+ 关键能力:
+
+ {character.key_abilities.map((ability, idx) => (
+ {ability}
+ ))}
+
+
+ )}
+
+ {character.relationship_suggestions && character.relationship_suggestions.length > 0 && (
+
+ 建议关系:
+
+ {character.relationship_suggestions.map((rel, idx) => (
+
+ {rel.target_character_name} - {rel.relationship_type}
+
+ ))}
+
+
+ )}
+
+
+ )}
+ />
+
+
+ );
+ };
+
return (
<>
+ {/* 角色确认对话框 */}
+ {renderCharacterConfirmModal()}
+
{/* 批量展开预览 Modal */}
- {/* 固定头部 */}
-
-
-
故事大纲
- {currentProject?.outline_mode && (
-
- {currentProject.outline_mode === 'one-to-one' ? '传统模式 (1→1)' : '细化模式 (1→N)'}
-
- )}
+ {/* 固定头部 */}
+
+
+
故事大纲
+ {currentProject?.outline_mode && (
+
+ {currentProject.outline_mode === 'one-to-one' ? '传统模式 (1→1)' : '细化模式 (1→N)'}
+
+ )}
+
+
+ }
+ onClick={showManualCreateOutlineModal}
+ block={isMobile}
+ >
+ 手动创建
+
+ }
+ onClick={showGenerateModal}
+ loading={isGenerating}
+ block={isMobile}
+ >
+ {isMobile ? 'AI生成/续写' : 'AI生成/续写大纲'}
+
+ {outlines.length > 0 && currentProject?.outline_mode === 'one-to-many' && (
+
+ }
+ onClick={handleBatchExpandOutlines}
+ loading={isExpanding}
+ disabled={isGenerating}
+ >
+ {isMobile ? '批量展开' : '批量展开为多章'}
+
+
+ )}
+
-
- }
- onClick={showManualCreateOutlineModal}
- block={isMobile}
- >
- 手动创建
-
- }
- onClick={showGenerateModal}
- loading={isGenerating}
- block={isMobile}
- >
- {isMobile ? 'AI生成/续写' : 'AI生成/续写大纲'}
-
- {outlines.length > 0 && currentProject?.outline_mode === 'one-to-many' && (
-
- }
- onClick={handleBatchExpandOutlines}
- loading={isExpanding}
- disabled={isGenerating}
- >
- {isMobile ? '批量展开' : '批量展开为多章'}
-
-
- )}
-
-
- {/* 可滚动内容区域 */}
-
- {outlines.length === 0 ? (
-
- ) : (
-
- (
-
- }
- onClick={() => handleExpandOutline(item.id, item.title)}
- loading={isExpanding}
- >
- 展开
-
-
- ] : []), // 一对一模式:不显示任何展开/创建按钮
- }
- onClick={() => handleOpenEditModal(item.id)}
- >
- 编辑
- ,
- handleDeleteOutline(item.id)}
- okText="确定"
- cancelText="取消"
- >
- }>
- 删除
-
- ,
- ]}
- >
-
-
-
- {currentProject?.outline_mode === 'one-to-one'
- ? `第${item.order_index || '?'}章`
- : `第${item.order_index || '?'}卷`
- }
-
- {item.title}
- {/* ✅ 新增:展开状态标识 - 仅在一对多模式显示 */}
- {currentProject?.outline_mode === 'one-to-many' && (
- outlineExpandStatus[item.id] ? (
- }>已展开
- ) : (
- 未展开
- )
- )}
-
- }
- description={
-
- {item.content}
-
- }
- />
-
- {/* 移动端:按钮显示在内容下方 */}
- {isMobile && (
-
- }
- onClick={() => handleOpenEditModal(item.id)}
- size="small"
- />
- {/* 一对多模式:显示展开按钮 */}
- {currentProject?.outline_mode === 'one-to-many' && (
+ {/* 可滚动内容区域 */}
+
+ {outlines.length === 0 ? (
+
+ ) : (
+
+ (
+
}
onClick={() => handleExpandOutline(item.id, item.title)}
loading={isExpanding}
- size="small"
- />
+ >
+ 展开
+
- )}
- {/* 一对一模式:不显示任何展开/创建按钮 */}
+ ] : []), // 一对一模式:不显示任何展开/创建按钮
+ }
+ onClick={() => handleOpenEditModal(item.id)}
+ >
+ 编辑
+ ,
handleDeleteOutline(item.id)}
okText="确定"
cancelText="取消"
>
- } size="small" />
-
-
- )}
-
-
- )}
- />
-
- )}
-
+ }>
+ 删除
+
+ ,
+ ]}
+ >
+
+
+
+ {currentProject?.outline_mode === 'one-to-one'
+ ? `第${item.order_index || '?'}章`
+ : `第${item.order_index || '?'}卷`
+ }
+
+ {item.title}
+ {/* ✅ 新增:展开状态标识 - 仅在一对多模式显示 */}
+ {currentProject?.outline_mode === 'one-to-many' && (
+ outlineExpandStatus[item.id] ? (
+ }>已展开
+ ) : (
+ 未展开
+ )
+ )}
+
+ }
+ description={
+
+ {item.content}
+
+ }
+ />
+
+ {/* 移动端:按钮显示在内容下方 */}
+ {isMobile && (
+
+ }
+ onClick={() => handleOpenEditModal(item.id)}
+ size="small"
+ />
+ {/* 一对多模式:显示展开按钮 */}
+ {currentProject?.outline_mode === 'one-to-many' && (
+
+ }
+ onClick={() => handleExpandOutline(item.id, item.title)}
+ loading={isExpanding}
+ size="small"
+ />
+
+ )}
+ {/* 一对一模式:不显示任何展开/创建按钮 */}
+ handleDeleteOutline(item.id)}
+ okText="确定"
+ cancelText="取消"
+ >
+ } size="small" />
+
+
+ )}
+
+
+ )}
+ />
+
+ )}
+
>
);
diff --git a/frontend/src/pages/ProjectDetail.tsx b/frontend/src/pages/ProjectDetail.tsx
index 137aaea..31bf035 100644
--- a/frontend/src/pages/ProjectDetail.tsx
+++ b/frontend/src/pages/ProjectDetail.tsx
@@ -14,6 +14,7 @@ import {
BankOutlined,
EditOutlined,
FundOutlined,
+ HeartOutlined,
} from '@ant-design/icons';
import { useStore } from '../store';
import { useCharacterSync, useOutlineSync, useChapterSync } from '../store/hooks';
@@ -66,7 +67,7 @@ export default function ProjectDetail() {
// 加载项目基本信息
const project = await projectApi.getProject(id);
setCurrentProject(project);
-
+
// 并行加载其他数据
await Promise.all([
refreshOutlines(id),
@@ -138,6 +139,11 @@ export default function ProjectDetail() {
// icon:
,
// label:
AI去味,
// },
+ {
+ key: 'sponsor',
+ icon:
,
+ label:
赞助支持,
+ },
];
// 根据当前路径动态确定选中的菜单项
@@ -151,6 +157,7 @@ export default function ProjectDetail() {
if (path.includes('/chapter-analysis')) return 'chapter-analysis';
if (path.includes('/chapters')) return 'chapters';
if (path.includes('/writing-styles')) return 'writing-styles';
+ if (path.includes('/sponsor')) return 'sponsor';
// if (path.includes('/polish')) return 'polish';
return 'world-setting'; // 默认选中世界设定
}, [location.pathname]);
@@ -227,7 +234,7 @@ export default function ProjectDetail() {
)}
-
+