diff --git a/packages/napcat-onebot/network/plugin-manger.ts b/packages/napcat-onebot/network/plugin-manger.ts index 69f5f198..467d0ec0 100644 --- a/packages/napcat-onebot/network/plugin-manger.ts +++ b/packages/napcat-onebot/network/plugin-manger.ts @@ -216,7 +216,7 @@ export class OB11PluginMangerAdapter extends IOB11NetworkAdapter i this.pluginRouters.set(entry.id, routerRegistry); // 创建获取其他插件导出的方法 - const getPluginExports = (pluginId: string): T | undefined => { + const getPluginExports = (pluginId: string): T | undefined => { const targetEntry = this.plugins.get(pluginId); if (!targetEntry || !targetEntry.loaded || targetEntry.runtime.status !== 'loaded') { return undefined; diff --git a/packages/napcat-onebot/network/plugin/manager.ts b/packages/napcat-onebot/network/plugin/manager.ts index 03fadbe3..57918e3d 100644 --- a/packages/napcat-onebot/network/plugin/manager.ts +++ b/packages/napcat-onebot/network/plugin/manager.ts @@ -195,7 +195,7 @@ export class OB11PluginManager extends IOB11NetworkAdapter impleme } // 创建获取其他插件导出的方法 - const getPluginExports = (pluginId: string): T | undefined => { + const getPluginExports = (pluginId: string): T | undefined => { const targetEntry = this.plugins.get(pluginId); if (!targetEntry || !targetEntry.loaded || targetEntry.runtime.status !== 'loaded') { return undefined; diff --git a/packages/napcat-plugin-builtin/index.ts b/packages/napcat-plugin-builtin/index.ts index b438245f..9c0c9b7c 100644 --- a/packages/napcat-plugin-builtin/index.ts +++ b/packages/napcat-plugin-builtin/index.ts @@ -160,7 +160,7 @@ const plugin_init: PluginModule['plugin_init'] = async (ctx) => { }); }); - // 注册扩展页面 + // 注册扩展页面(无需鉴权,可通过 /plugin/{pluginId}/page/dashboard 访问) ctx.router.page({ path: 'dashboard', title: '插件仪表盘', @@ -171,6 +171,7 @@ const plugin_init: PluginModule['plugin_init'] = async (ctx) => { logger.info('WebUI 路由已注册:'); logger.info(' - API 路由: /api/Plugin/ext/' + ctx.pluginName + '/'); + logger.info(' - 扩展页面: /plugin/' + ctx.pluginName + '/page/dashboard'); logger.info(' - 静态资源: /plugin/' + ctx.pluginName + '/files/static/'); logger.info(' - 内存资源: /plugin/' + ctx.pluginName + '/mem/dynamic/'); }; diff --git a/packages/napcat-webui-backend/index.ts b/packages/napcat-webui-backend/index.ts index e45f0dec..b714366d 100644 --- a/packages/napcat-webui-backend/index.ts +++ b/packages/napcat-webui-backend/index.ts @@ -332,6 +332,42 @@ export async function InitWebUi (logger: ILogWrapper, pathWrapper: NapCatPathWra return res.status(404).json({ code: -1, message: 'Memory file not found' }); }); + // 插件页面路由(不需要鉴权) + // 路径格式: /plugin/:pluginId/page/:pagePath + app.get('/plugin/:pluginId/page/:pagePath', (req, res) => { + const { pluginId, pagePath } = req.params; + if (!pluginId) return res.status(400).json({ code: -1, message: 'Plugin ID is required' }); + + const ob11 = WebUiDataRuntime.getOneBotContext() as NapCatOneBot11Adapter | null; + if (!ob11) return res.status(503).json({ code: -1, message: 'OneBot context not available' }); + + const pluginManager = ob11.networkManager.findSomeAdapter('plugin_manager') as OB11PluginMangerAdapter | undefined; + if (!pluginManager) return res.status(503).json({ code: -1, message: 'Plugin manager not available' }); + + const routerRegistry = pluginManager.getPluginRouter(pluginId); + if (!routerRegistry || !routerRegistry.hasPages()) { + return res.status(404).json({ code: -1, message: `Plugin '${pluginId}' has no registered pages` }); + } + + const pages = routerRegistry.getPages(); + const page = pages.find(p => p.path === '/' + pagePath || p.path === pagePath); + if (!page) { + return res.status(404).json({ code: -1, message: `Page '${pagePath}' not found in plugin '${pluginId}'` }); + } + + const pluginPath = routerRegistry.getPluginPath(); + if (!pluginPath) { + return res.status(500).json({ code: -1, message: 'Plugin path not available' }); + } + + const htmlFilePath = join(pluginPath, page.htmlFile); + if (!existsSync(htmlFilePath)) { + return res.status(404).json({ code: -1, message: `HTML file not found: ${page.htmlFile}` }); + } + + return res.sendFile(htmlFilePath); + }); + // 插件文件系统静态资源路由(不需要鉴权) // 路径格式: /plugin/:pluginId/files/* app.use('/plugin/:pluginId/files', (req, res, next) => { diff --git a/packages/napcat-webui-frontend/src/pages/dashboard/extension.tsx b/packages/napcat-webui-frontend/src/pages/dashboard/extension.tsx index 9cbdf414..e61f1de1 100644 --- a/packages/napcat-webui-frontend/src/pages/dashboard/extension.tsx +++ b/packages/napcat-webui-frontend/src/pages/dashboard/extension.tsx @@ -63,13 +63,12 @@ export default function ExtensionPage () { }, [extensionPages]); // 获取当前选中页面的 iframe URL + // 新路由格式不需要鉴权: /plugin/:pluginId/page/:pagePath const currentPageUrl = useMemo(() => { if (!selectedTab) return ''; const [pluginId, ...pathParts] = selectedTab.split(':'); const path = pathParts.join(':').replace(/^\//, ''); - // 获取认证 token - const token = localStorage.getItem('token') || ''; - return `/api/Plugin/page/${pluginId}/${path}?webui_token=${token}`; + return `/plugin/${pluginId}/page/${path}`; }, [selectedTab]); useEffect(() => { @@ -86,11 +85,10 @@ export default function ExtensionPage () { setIframeLoading(false); }; - // 在新窗口打开页面 + // 在新窗口打开页面(新路由不需要鉴权) const openInNewWindow = (pluginId: string, path: string) => { const cleanPath = path.replace(/^\//, ''); - const token = localStorage.getItem('token') || ''; - const url = `/api/Plugin/page/${pluginId}/${cleanPath}?webui_token=${token}`; + const url = `/plugin/${pluginId}/page/${cleanPath}`; window.open(url, '_blank'); };