diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 7a86cda..b8356fa 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -16,6 +16,7 @@ import ChapterReader from './pages/ChapterReader'; import ChapterAnalysis from './pages/ChapterAnalysis'; import Foreshadows from './pages/Foreshadows'; import WritingStyles from './pages/WritingStyles'; +import PromptWorkshop from './pages/PromptWorkshop'; import Settings from './pages/Settings'; import MCPPlugins from './pages/MCPPlugins'; import UserManagement from './pages/UserManagement'; @@ -62,6 +63,7 @@ function App() { } /> } /> } /> + } /> } /> {/* } /> */} diff --git a/frontend/src/pages/ProjectDetail.tsx b/frontend/src/pages/ProjectDetail.tsx index e8ec7da..71c2450 100644 --- a/frontend/src/pages/ProjectDetail.tsx +++ b/frontend/src/pages/ProjectDetail.tsx @@ -17,6 +17,7 @@ import { HeartOutlined, TrophyOutlined, BulbOutlined, + CloudOutlined, } from '@ant-design/icons'; import { useStore } from '../store'; import { useCharacterSync, useOutlineSync, useChapterSync } from '../store/hooks'; @@ -151,6 +152,11 @@ export default function ProjectDetail() { icon: , label: 写作风格, }, + { + key: 'prompt-workshop', + icon: , + label: 提示词工坊, + }, // { // key: 'polish', // icon: , @@ -171,6 +177,7 @@ export default function ProjectDetail() { if (path.includes('/foreshadows')) return 'foreshadows'; if (path.includes('/chapters')) return 'chapters'; if (path.includes('/writing-styles')) return 'writing-styles'; + if (path.includes('/prompt-workshop')) return 'prompt-workshop'; if (path.includes('/sponsor')) return 'sponsor'; // if (path.includes('/polish')) return 'polish'; return 'sponsor'; // 默认选中赞助支持 diff --git a/frontend/src/components/PromptWorkshop.tsx b/frontend/src/pages/PromptWorkshop.tsx similarity index 84% rename from frontend/src/components/PromptWorkshop.tsx rename to frontend/src/pages/PromptWorkshop.tsx index c48a47f..b8ffb02 100644 --- a/frontend/src/components/PromptWorkshop.tsx +++ b/frontend/src/pages/PromptWorkshop.tsx @@ -51,11 +51,7 @@ import { PROMPT_CATEGORIES } from '../types'; const { TextArea } = Input; const { Text, Paragraph } = Typography; -interface PromptWorkshopProps { - onImportSuccess?: () => void; -} - -export default function PromptWorkshop({ onImportSuccess }: PromptWorkshopProps) { +export default function PromptWorkshop() { const [items, setItems] = useState([]); const [loading, setLoading] = useState(false); const [total, setTotal] = useState(0); @@ -120,11 +116,24 @@ export default function PromptWorkshop({ onImportSuccess }: PromptWorkshopProps) const [editForm] = Form.useForm(); const [editLoading, setEditLoading] = useState(false); + // 当前活动的 Tab + const [activeTab, setActiveTab] = useState('browse'); + const isMobile = window.innerWidth <= 768; // 判断是否为服务端管理员 const isServerAdmin = serviceStatus?.mode === 'server' && currentUser?.is_admin; + // 卡片网格配置 - 与 WritingStyles 保持一致 + const gridConfig = { + gutter: isMobile ? 8 : 16, + xs: 24, + sm: 24, + md: 12, + lg: 8, + xl: 6, + }; + // 加载服务状态和用户信息 useEffect(() => { const init = async () => { @@ -186,7 +195,6 @@ export default function PromptWorkshop({ onImportSuccess }: PromptWorkshopProps) try { await promptWorkshopApi.importItem(item.id); message.success(`已导入「${item.name}」到本地写作风格`); - onImportSuccess?.(); // 刷新列表更新下载计数 loadItems(); } catch (error) { @@ -296,19 +304,9 @@ export default function PromptWorkshop({ onImportSuccess }: PromptWorkshopProps) return {cfg.text}; }; - // 网格配置 - const gridConfig = { - gutter: isMobile ? 8 : 16, - xs: 24, - sm: 12, - md: 8, - lg: 6, - xl: 6, - }; - - // 渲染工坊列表 - const renderWorkshopList = () => ( - + // 渲染筛选区域(固定在顶部) + const renderFilterBar = () => ( + {/* 服务状态 */} {serviceStatus && !serviceStatus.cloud_connected && serviceStatus.mode === 'client' && ( 最受欢迎 下载最多 - } + } onClick={() => { setCurrentPage(1); loadItems(); }} > 刷新 + + ); - {/* 列表区域 */} - - {items.length === 0 ? ( - - ) : ( - <> - + // 渲染工坊列表(只有卡片部分,用于滚动区域) + const renderWorkshopList = () => ( + + {items.length === 0 ? ( + + ) : ( + <> + {items.map(item => ( handleViewDetail(item)} /> @@ -413,9 +432,9 @@ export default function PromptWorkshop({ onImportSuccess }: PromptWorkshopProps) , ]} > - - - {item.name} + + + {item.name} {getCategoryName(item.category)} @@ -424,28 +443,31 @@ export default function PromptWorkshop({ onImportSuccess }: PromptWorkshopProps) {item.description && ( {item.description} )} {item.prompt_content} {item.tags && item.tags.length > 0 && ( - + {item.tags.slice(0, 3).map(tag => ( {tag} ))} @@ -464,24 +486,23 @@ export default function PromptWorkshop({ onImportSuccess }: PromptWorkshopProps) ))} - - - {total > pageSize && ( - - setCurrentPage(page)} - showSizeChanger={false} - showTotal={t => `共 ${t} 个提示词`} - /> - - )} - > - )} - - + + + {total > pageSize && ( + + setCurrentPage(page)} + showSizeChanger={false} + showTotal={t => `共 ${t} 个提示词`} + /> + + )} + > + )} + ); // 渲染我的提交 @@ -495,14 +516,26 @@ export default function PromptWorkshop({ onImportSuccess }: PromptWorkshopProps) - {mySubmissions.length === 0 ? ( - - ) : ( - - {mySubmissions.map(sub => ( - + {mySubmissions.length === 0 ? ( + + ) : ( + + {mySubmissions.map(sub => ( + @@ -551,8 +584,8 @@ export default function PromptWorkshop({ onImportSuccess }: PromptWorkshopProps) ))} - - )} + + )} ); @@ -754,11 +787,23 @@ export default function PromptWorkshop({ onImportSuccess }: PromptWorkshopProps) {adminSubmissions.length === 0 ? ( ) : ( - + {adminSubmissions.map(sub => ( - + ) : ( - + {publishedItems.map(item => ( - + @@ -875,68 +932,79 @@ export default function PromptWorkshop({ onImportSuccess }: PromptWorkshopProps) ); return ( - - {/* 标题和操作区 */} - - - - 提示词工坊 - {serviceStatus?.mode === 'server' && ( - - )} - - } - onClick={() => setIsSubmitModalOpen(true)} - > - 分享我的提示词 - + + {/* 固定区域:标题 + Tabs切换栏 + 筛选栏 */} + + {/* 标题和操作区 */} + + + + 提示词工坊 + {serviceStatus?.mode === 'server' && ( + + )} + + } + onClick={() => setIsSubmitModalOpen(true)} + > + 分享我的提示词 + + + + {/* Tabs 切换栏(不含内容) */} + { + setActiveTab(key); + if (key === 'submissions') loadMySubmissions(); + if (key === 'admin') { + loadAdminSubmissions(); + loadPublishedItems(); + } + }} + items={[ + { key: 'browse', label: '浏览工坊' }, + { + key: 'submissions', + label: ( + s.status === 'pending').length} size="small"> + 我的提交 + + ), + }, + ...(isServerAdmin ? [{ + key: 'admin', + label: ( + + 管理审核 + + ), + }] : []), + ]} + tabBarStyle={{ marginBottom: 16 }} + /> + + {/* 筛选栏(仅在浏览工坊时显示) */} + {activeTab === 'browse' && renderFilterBar()} - {/* 标签页 */} - { - if (key === 'submissions') loadMySubmissions(); - if (key === 'admin') { - loadAdminSubmissions(); - loadPublishedItems(); - } - }} - items={[ - { - key: 'browse', - label: '浏览工坊', - children: renderWorkshopList(), - }, - { - key: 'submissions', - label: ( - s.status === 'pending').length} size="small"> - 我的提交 - - ), - children: renderMySubmissions(), - }, - ...(isServerAdmin ? [{ - key: 'admin', - label: ( - - 管理审核 - - ), - children: renderAdminPanel(), - }] : []), - ]} - /> + {/* 滚动区域:只有卡片列表滚动 */} + + {activeTab === 'browse' && renderWorkshopList()} + {activeTab === 'submissions' && renderMySubmissions()} + {activeTab === 'admin' && renderAdminPanel()} + {/* 提交弹窗 */} ( - + return ( + + + + 写作风格管理 + } @@ -184,7 +190,7 @@ export default function WritingStyles() { 创建自定义风格 - + {styles.length === 0 ? ( @@ -303,54 +309,6 @@ export default function WritingStyles() { )} - - ); - - return ( - - - - - 写作风格管理 - - - - - - 我的风格 - - ), - children: renderLocalStyles(), - }, - { - key: 'workshop', - label: ( - - - - 提示词工坊 - - - ), - children: , - }, - ]} - /> {/* 创建自定义风格 Modal */}