feat: hash路由 + 插件页面内联加载 + 侧边栏插件面板展开项

- Hash路由: #/dashboard #/files #/plugins/xxx 支持刷新保持/前进后退
- 登录过期保留hash,登录后自动跳回原页面
- 插件WebUI页面内联加载到page-container(不再弹新窗)
- 插件页面HTML自动处理: style提取/body剥离/script执行/padding归零
- 侧边栏新增「插件面板」可折叠项,展开列出所有已注册插件页面
- 内存卡片显示 已用/总容量(百分比右侧)
- 插件开发指南新增 2.6 WebUI页面开发章节

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
qinglong
2026-06-11 20:56:39 +08:00
parent eeca8e37e1
commit 99c3e3e853
10 changed files with 330 additions and 82 deletions
+21
View File
@@ -8,6 +8,7 @@ logger = logging.getLogger(__name__)
def setup_routes(app, prefix=''):
app.router.add_get(f'{prefix}/api/plugins', panel_auth(list_plugins))
app.router.add_get(f'{prefix}/api/plugin-pages', panel_auth(list_plugin_web_pages))
app.router.add_post(f'{prefix}/api/plugins/{{name}}/{{action}}', panel_auth(manage_plugin))
app.router.add_get(f'{prefix}/api/plugins/{{name}}/perms', panel_auth(get_perms))
app.router.add_post(f'{prefix}/api/plugins/{{name}}/perms', panel_auth(set_perms))
@@ -54,6 +55,26 @@ async def manage_plugin(req):
logger.error(f"插件操作失败: {e}")
return web.json_response({"success": False, "error": str(e)})
async def list_plugin_web_pages(req):
"""Return all registered plugin web UI pages for sidebar listing."""
sm = req.app.get('service_manager')
if not sm:
return web.json_response({"pages": []})
ps = sm.get_service("plugin")
if not ps:
return web.json_response({"pages": []})
pages = []
for name, plugin in ps.plugins.items():
if hasattr(plugin, "get_web_pages"):
for path, info in plugin.get_web_pages().items():
pages.append({
"plugin": name,
"path": "/plugin/" + name,
"title": info.get("title", name),
"icon": info.get("icon", "P"),
})
return web.json_response({"pages": pages})
async def get_perms(req):
return web.json_response({"plugin": req.match_info['name'], "permissions": ["read", "write"]})