From dc3dbaaf2cf4cf63ca9774c3e7c059be49233bf5 Mon Sep 17 00:00:00 2001 From: xiamuceer-j Date: Wed, 14 Jan 2026 19:48:18 +0800 Subject: [PATCH] =?UTF-8?q?style:=20=E7=A7=BB=E5=8A=A8=E7=AB=AF=E5=93=8D?= =?UTF-8?q?=E5=BA=94=E5=BC=8F=E4=BC=98=E5=8C=96=EF=BC=9AMCPPlugins?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E5=AE=8C=E6=95=B4=E9=87=8D=E6=9E=84=E3=80=81?= =?UTF-8?q?=E5=A4=9A=E5=A4=84Modal=E5=BC=B9=E7=AA=97=E9=80=82=E9=85=8D?= =?UTF-8?q?=E3=80=81=E9=A1=B9=E7=9B=AE=E5=8D=A1=E7=89=87=E5=8D=95=E5=88=97?= =?UTF-8?q?=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/projects.py | 14 +- frontend/src/components/ChapterAnalysis.tsx | 16 +- frontend/src/pages/Chapters.tsx | 52 +++--- frontend/src/pages/MCPPlugins.tsx | 189 ++++++++++++++------ frontend/src/pages/PromptTemplates.tsx | 3 +- frontend/src/pages/Settings.tsx | 3 +- frontend/src/pages/Sponsor.tsx | 2 +- frontend/src/services/api.ts | 8 +- 8 files changed, 188 insertions(+), 99 deletions(-) diff --git a/backend/app/api/projects.py b/backend/app/api/projects.py index 02eec41..5e35280 100644 --- a/backend/app/api/projects.py +++ b/backend/app/api/projects.py @@ -564,6 +564,11 @@ async def export_project_data( Args: project_id: 项目ID options: 导出选项 + - include_generation_history: 是否包含生成历史 + - include_writing_styles: 是否包含写作风格 + - include_careers: 是否包含职业系统 + - include_memories: 是否包含故事记忆 + - include_plot_analysis: 是否包含剧情分析 Returns: JSON文件下载 @@ -575,7 +580,7 @@ async def export_project_data( logger.warning("未登录用户尝试导出项目数据") raise HTTPException(status_code=401, detail="未登录") - logger.info(f"开始导出项目数据: project_id={project_id}, user_id={user_id}") + logger.info(f"开始导出项目数据: project_id={project_id}, user_id={user_id}, options={options.model_dump()}") # 只查询当前用户的项目 result = await db.execute( @@ -590,12 +595,15 @@ async def export_project_data( logger.warning(f"项目不存在或无权访问: project_id={project_id}, user_id={user_id}") raise HTTPException(status_code=404, detail="项目不存在") - # 导出数据 + # 导出数据(使用所有选项) export_data = await ImportExportService.export_project( project_id=project_id, db=db, include_generation_history=options.include_generation_history, - include_writing_styles=options.include_writing_styles + include_writing_styles=options.include_writing_styles, + include_careers=options.include_careers, + include_memories=options.include_memories, + include_plot_analysis=options.include_plot_analysis ) # 转换为JSON diff --git a/frontend/src/components/ChapterAnalysis.tsx b/frontend/src/components/ChapterAnalysis.tsx index af006f2..9810eab 100644 --- a/frontend/src/components/ChapterAnalysis.tsx +++ b/frontend/src/components/ChapterAnalysis.tsx @@ -635,21 +635,19 @@ export default function ChapterAnalysis({ chapterId, visible, onClose }: Chapter title="章节分析" open={visible} onCancel={onClose} - width={isMobile ? '100%' : '90%'} - centered={!isMobile} + width={isMobile ? 'calc(100vw - 32px)' : '90%'} + centered style={{ - maxWidth: isMobile ? '100%' : '1400px', - paddingBottom: 0, - top: isMobile ? 0 : undefined, - margin: isMobile ? 0 : undefined, - maxHeight: isMobile ? '100vh' : undefined + maxWidth: isMobile ? 'calc(100vw - 32px)' : '1400px', + margin: isMobile ? '0 auto' : undefined, + padding: isMobile ? '0 16px' : undefined }} styles={{ body: { padding: isMobile ? '12px' : '24px', paddingBottom: 0, - maxHeight: isMobile ? 'calc(100vh - 110px)' : undefined, - overflowY: isMobile ? 'auto' : undefined + maxHeight: isMobile ? 'calc(100vh - 200px)' : 'calc(90vh - 150px)', + overflowY: 'auto' } }} footer={[ diff --git a/frontend/src/pages/Chapters.tsx b/frontend/src/pages/Chapters.tsx index f19a1e2..dbef5a2 100644 --- a/frontend/src/pages/Chapters.tsx +++ b/frontend/src/pages/Chapters.tsx @@ -1230,16 +1230,16 @@ export default function Chapters() { 第{chapter.chapter_number}章展开规划 ), - width: isMobile ? '95%' : 800, + width: isMobile ? 'calc(100vw - 32px)' : 800, centered: true, style: isMobile ? { - top: 20, - maxWidth: 'calc(100vw - 16px)', - margin: '0 8px' + maxWidth: 'calc(100vw - 32px)', + margin: '0 auto', + padding: '0 16px' } : undefined, styles: { body: { - maxHeight: isMobile ? 'calc(100vh - 150px)' : 'calc(80vh - 110px)', + maxHeight: isMobile ? 'calc(100vh - 200px)' : 'calc(80vh - 110px)', overflowY: 'auto' } }, @@ -2006,17 +2006,16 @@ export default function Chapters() { open={isModalOpen} onCancel={() => setIsModalOpen(false)} footer={null} - centered={!isMobile} - width={isMobile ? 'calc(100% - 32px)' : 520} + centered + width={isMobile ? 'calc(100vw - 32px)' : 520} style={isMobile ? { - top: 20, - paddingBottom: 0, maxWidth: 'calc(100vw - 32px)', - margin: '0 16px' + margin: '0 auto', + padding: '0 16px' } : undefined} styles={{ body: { - maxHeight: isMobile ? 'calc(100vh - 150px)' : 'calc(80vh - 110px)', + maxHeight: isMobile ? 'calc(100vh - 200px)' : 'calc(80vh - 110px)', overflowY: 'auto' } }} @@ -2082,17 +2081,16 @@ export default function Chapters() { closable={!isGenerating} maskClosable={!isGenerating} keyboard={!isGenerating} - width={isMobile ? 'calc(100% - 32px)' : '85%'} - centered={!isMobile} + width={isMobile ? 'calc(100vw - 32px)' : '85%'} + centered style={isMobile ? { - top: 20, - paddingBottom: 0, maxWidth: 'calc(100vw - 32px)', - margin: '0 16px' + margin: '0 auto', + padding: '0 16px' } : undefined} styles={{ body: { - maxHeight: isMobile ? 'calc(100vh - 150px)' : 'calc(100vh - 110px)', + maxHeight: isMobile ? 'calc(100vh - 200px)' : 'calc(100vh - 110px)', overflowY: 'auto', padding: isMobile ? '16px 12px' : '8px' } @@ -2366,6 +2364,7 @@ export default function Chapters() { content: '批量生成正在进行中,确定要取消吗?', okText: '确定取消', cancelText: '继续生成', + centered: true, onOk: () => { handleCancelBatchGenerate(); setBatchGenerateVisible(false); @@ -2376,7 +2375,7 @@ export default function Chapters() { } }} footer={!batchGenerating ? ( - + @@ -2385,13 +2384,18 @@ export default function Chapters() { ) : null} - width={700} + width={isMobile ? 'calc(100vw - 32px)' : 700} centered closable={!batchGenerating} maskClosable={!batchGenerating} + style={isMobile ? { + maxWidth: 'calc(100vw - 32px)', + margin: '0 auto', + padding: '0 16px' + } : undefined} styles={{ body: { - maxHeight: 'calc(100vh - 260px)', + maxHeight: isMobile ? 'calc(100vh - 200px)' : 'calc(100vh - 260px)', overflowY: 'auto', overflowX: 'hidden' } @@ -2419,7 +2423,7 @@ export default function Chapters() { /> {/* 第一行:起始章节 + 生成数量 */} -
+
- + 5章 10章 15章 @@ -2454,7 +2458,7 @@ export default function Chapters() {
{/* 第二行:写作风格 + 目标字数 */} -
+
{/* 第三行:AI模型 + 同步分析 */} -
+
{ + const handleResize = () => { + setIsMobile(window.innerWidth <= 768); + }; + window.addEventListener('resize', handleResize); + return () => window.removeEventListener('resize', handleResize); + }, []); const [modal, contextHolder] = Modal.useModal(); const [loading, setLoading] = useState(false); const [plugins, setPlugins] = useState([]); @@ -591,10 +600,9 @@ export default function MCPPluginsPage() {
-
+
-
- +
+
{modelSupportStatus === 'supported' ? ( - + ) : modelSupportStatus === 'unsupported' ? ( - + ) : ( - + )}
-
- 模型能力检查 - +
+ 模型能力检查 + {modelSupportStatus === 'supported' ? '当前模型支持 Function Calling,可正常使用 MCP 插件' : modelSupportStatus === 'unsupported' @@ -702,7 +719,8 @@ export default function MCPPluginsPage() { icon={} onClick={handleCheckFunctionCalling} loading={checkingFunctionCalling} - style={{ borderRadius: 8 }} + style={{ borderRadius: 8, width: isMobile ? '100%' : 'auto' }} + size={isMobile ? 'middle' : 'middle'} > {modelSupportStatus === 'unknown' ? '开始检测' : '重新检测'} @@ -719,13 +737,13 @@ export default function MCPPluginsPage() { backdropFilter: 'blur(10px)', boxShadow: '0 4px 12px rgba(0, 0, 0, 0.03)' }} - styles={{ body: { padding: 20 } }} + styles={{ body: { padding: isMobile ? 14 : 20 } }} > - -
- 什么是 MCP 插件? - + +
+ 什么是 MCP 插件? + MCP (Model Context Protocol) 协议允许 AI 调用外部工具获取数据。通过添加插件,AI 可以访问搜索引擎、数据库、API 等服务,大幅增强创作能力。
@@ -769,7 +787,7 @@ export default function MCPPluginsPage() { ) : ( - + {plugins.map((plugin) => (
+ {/* 插件信息区域 */}
-
- - {plugin.display_name || plugin.plugin_name} - - {getStatusTag(plugin)} - + {/* 标题和状态标签 */} +
+
+ + {plugin.display_name || plugin.plugin_name} + + {getStatusTag(plugin)} +
+ {/* 移动端:开关放在标题行右侧 */} + {isMobile && ( + handleToggle(plugin, checked)} + disabled={modelSupportStatus !== 'supported'} + size="small" + checkedChildren="开" + unCheckedChildren="关" + style={{ + flexShrink: 0, + height: 16, + minHeight: 16, + lineHeight: '16px' + }} + /> + )} +
+ + {/* 类型和分类标签 */} +
+ {plugin.plugin_type?.toUpperCase() || 'UNKNOWN'} {plugin.category && plugin.category !== 'general' && ( - {plugin.category} + {plugin.category} )}
+ {plugin.description && ( - +
+ {(() => { // 脱敏处理:隐藏URL中的API Key const url = plugin.server_url; @@ -849,8 +904,13 @@ export default function MCPPluginsPage() { )} {plugin.plugin_type === 'stdio' && plugin.command && ( -
- +
+ {plugin.command} {plugin.args?.join(' ')}
@@ -865,20 +925,27 @@ export default function MCPPluginsPage() {
- - handleToggle(plugin, checked)} - disabled={modelSupportStatus !== 'supported'} - size={isMobile ? 'small' : 'default'} - style={{ - flexShrink: 0, - height: isMobile ? 16 : 22, - minHeight: isMobile ? 16 : 22, - lineHeight: isMobile ? '16px' : '22px' - }} - /> + {/* 操作按钮区域 */} +
+ {/* 桌面端显示开关 */} + {!isMobile && ( + handleToggle(plugin, checked)} + disabled={modelSupportStatus !== 'supported'} + checkedChildren="开" + unCheckedChildren="关" + /> + )} +
))} @@ -942,7 +1017,7 @@ export default function MCPPluginsPage() { extra="粘贴标准MCP配置,系统自动提取插件名称。支持HTTP和Stdio类型" >