# TDesign 插件前端重构评估 ## 1. 范围与结论 本次只重构独立插件仓库的前端,不修改官方 Sub2API Core 的 Go、Vue、迁移、鉴权或构建配置。 独立插件仓库当前工作目录:`/tmp/sub2api-add-repo.pzrg17` 官方 Core 当前工作目录:`/Users/qiu/Desktop/Sub2API` 建议把 TDesign starter 作为统一插件控制面的 UI 基座,而不是把 starter 合并到 Core 的 `frontend/`。插件控制面只登录一次;订阅是安装后挂载到控制面里的业务模块,不是第二个后台系统。 ## 2. Starter 基线 已拉取:`/Users/qiu/Desktop/tdesign-vue-next-starter-v1` ```text 仓库: https://github.com/Tencent/tdesign-vue-next-starter 分支: develop 提交: d6f8fafad9c1596cac8dfac8d52a88d0ca692acc 版本: package.json 0.14.0 ``` 已确认的技术栈: - Vue 3.5、TypeScript、Vite 8、Pinia 3、Vue Router 5 - `tdesign-vue-next` `^1.20.2` - `tdesign-icons-vue-next` `^0.4.4` - ECharts `^6.1.0` - Node.js `>=22.12.0` Starter 的基线构建已通过:`npm ci --ignore-scripts`、`npm run build`。 ECharts 已在 starter 的 `src/hooks/index.ts` 中通过 `echarts/core` 初始化。starter 没有 `line-icons` 或 `lineicon` 依赖;TDesign Icons 本身是线性图标风格,后续统一使用 `tdesign-icons-vue-next`,避免混用多个图标系统。 ## 3. 当前插件页面清单 ### 3.1 Plugin Admin 入口:`plugins/plugin-admin/ui/index.html`、`plugins/plugin-admin/ui/app.js` 这是通用插件控制面,不是订阅业务页面。现有职责应拆成以下路由: ```text #/overview #/plugins #/plugins/:plugin_id/overview #/plugins/:plugin_id/revisions #/plugins/:plugin_id/config #/plugins/:plugin_id/menu #/plugins/:plugin_id/operations #/marketplace #/operations ``` 页面职责: | 页面 | 主要内容 | TDesign 组件方向 | | --- | --- | --- | | 登录 | Core 管理员账号登录、2FA、会话过期 | `TForm`、`TInput`、`TButton`、`TAlert` | | 概览 | 已登记、运行中、待启用、需关注、最近操作 | `TCard`、`TStatistic`、`TTag`、`TTimeline` | | 已安装插件 | 摘要列表、生命周期主操作、查看详情 | `TTable` 或响应式 `TCard`、`TDropdown` | | 运行概况 | 健康、端点、兼容性、活动 revision | `TDescriptions`、`TProgress`、`TTag` | | 版本与升级 | revision、校验、升级包、回滚 | `TTable`、`TUpload`、`TDialog` | | 配置 | 服务地址、菜单地址、敏感配置提示 | `TForm`、`TInput`、`TAlert` | | 菜单接入 | 菜单声明、预览、应用 | `TDescriptions`、`TDialog`、`TButton` | | 操作历史 | 当前插件或全局审计记录、详情 | `TTable`、`TDrawer`、`TTag` | | 插件市场 | 受控索引、版本、兼容性、哈希、入库 | `TCard`、`TTag`、`TButton` | 现有接口保持不变: ```text GET /api/plugins POST /api/plugins/upload POST /api/plugins/:id/enable POST /api/plugins/:id/disable POST /api/plugins/:id/test POST /api/plugins/:id/ui-session DELETE /api/plugins/:id GET/PUT /api/plugins/:id/config GET /api/marketplace GET /api/audit ``` ### 3.2 订阅业务模块 入口:`plugins/subscription-admin/ui/index.html`、`plugins/subscription-admin/ui/app.js` 订阅管理是可选业务模块,由 Plugin Admin 安装、启用和卸载。它复用控制面的登录态、导航、CSRF 和管理员权限,不再出现第二个登录页。模块后端可以继续作为独立进程运行,但浏览器只访问控制面提供的同源模块路由。 ```text #/modules/subscription/overview #/modules/subscription/plans #/modules/subscription/subscriptions #/modules/subscription/audit ``` 页面职责: | 页面 | 主要内容 | TDesign 组件方向 | | --- | --- | --- | | 概览 | Core 连接状态、套餐数量、订阅数量、余额查询 | `TStatistic`、`TCard`、`TAlert` | | 套餐 | Core 返回的套餐目录和覆盖分组 | `TTable`、`TTag`、`TEmpty` | | 用户订阅 | 用户、状态、分组、服务端分页和筛选 | `TForm`、`TSelect`、`TTable`、`TPagination` | | 操作记录 | 插件会话和只读查询审计 | `TTable`、`TDrawer` | | 模块设置 | 运行模式、allowlist、凭据状态 | 插件详情的“配置/运行概况”页,不重复做模块登录 | 订阅模块现有 Core 代理接口、分页参数、状态枚举和只读边界不变。余额购买、续费、撤销等后续能力仍应通过模块后端 API 增量加入,不能在此次 UI 换肤时偷偷改变业务语义。 ## 4. 推荐前端目录 不要复用官方 Core 的 `frontend/` 目录。建议在独立插件仓库新增一个统一 TDesign 控制面,并把订阅前端作为可挂载模块构建: ```text plugins/ ├── plugin-admin/ │ ├── ui/ # 统一 TDesign 应用、登录、导航和模块路由 │ └── ui-modules/ # 订阅等业务模块的 Vue/TS 源码 └── subscription-admin/ ├── service/ # 可继续独立运行的业务后端 └── ui-module/ # 被 plugin-admin 挂载的订阅模块,不包含登录页 ``` 订阅模块可以独立打包和回滚,但它的浏览器入口由 Plugin Admin 统一托管。Go 的 `embed`、静态文件路径和部署脚本必须在插件仓库内同步,不与 Core 构建耦合。 共享但不跨 Core 的内容: - TDesign 主题 token、字体、间距、移动端断点 - 请求封装、插件会话/CSRF、错误提示 - ECharts 按需注册和 resize composable - TDesign Icons 的图标命名约定 ## 5. 不可改变的系统边界 ```text 浏览器 ↓ 一次登录:Plugin Admin Session Cookie + CSRF 统一 Plugin Admin TDesign Shell ├─ 插件管理页面 └─ 订阅业务模块路由 ↓ 控制面同源 BFF / 内部服务调用 独立插件 Go 服务(订阅模块) ↓ 服务端 allowlist + Bearer Core token 官方 Sub2API Core REST API ``` - 浏览器不能拿到 Core access token、refresh token、Admin Key 或服务密钥。 - 所有模块前端只能使用统一控制面的会话和模块 API,不能直连 Core API、PostgreSQL 或 Redis。 - 订阅模块不得再实现 `/login`、独立 Cookie 或第二套管理员会话。 - `custom_menu_items` 和 Core `/custom/:id` iframe 注入方式保持不变。 - Plugin Admin 的配置 iframe `postMessage` bridge、`ui-session`、step-up 和来源校验保持不变。 - Core 的源码仓库、版本文件、数据库迁移和前端页面不在本次改动范围内。 ## 6. 分阶段实施 ### 阶段 A:基座复制与边界固定 从 starter 复制应用骨架,替换 demo 路由、mock 数据、示例登录和品牌资源;保留 TDesign Layout、主题切换、Pinia、Vue Router、ECharts 基础能力。先让统一控制面独立构建,并定义模块注册契约。 ### 阶段 B:Plugin Admin 先完成登录和应用壳,再按“概览 → 已安装 → 详情页签 → 市场 → 审计”迁移。所有 mutation 仍由现有 Go endpoint 执行,前端只负责表单、状态和操作确认。 ### 阶段 C:订阅业务模块 订阅 UI 作为控制面的一个模块挂载,复用同一套会话、导航、视觉 token 和错误处理。先迁移概览、套餐、订阅列表和操作记录,服务端分页/筛选参数保持原样。订阅后端是否独立进程不影响前端只有一次登录。 ### 阶段 D:图表与响应式 只在概览和需要趋势的页面引入 ECharts;图表容器使用固定最小高度、`resize` observer 和按需导入,避免页面被超长 canvas 撑开。列表在移动端只允许表格容器横向滚动,页面主体不得横向溢出。 ### 阶段 E:接入验收 验证统一控制面一次登录后进入插件管理和订阅模块、Core 菜单 iframe、会话过期、CSRF、管理员权限、插件启停、配置 bridge、市场入库和审计链路。确认官方 Core 工作区没有任何变更。 ## 7. 主要风险与处理 1. **starter 自带 mock/示例权限**:全部删除,改为 Plugin Admin 会话和管理员权限;不把 starter 的演示用户带入生产。 2. **旧 UI 是原生 HTML/JS**:不要强行在同一页面混用原生模板和 TDesign;按应用整体迁移,减少样式优先级冲突。 3. **配置 iframe bridge**:只能替换外层视觉,消息名称、token、来源校验、超时和 step-up 语义不变。 4. **表格移动端**:使用固定列/可滚动列的明确容器,禁止给 `body` 或整个页面设置横向滚动。 5. **图标包选择**:统一 `tdesign-icons-vue-next`;它提供线性图标,不再额外引入未知的 `line-icons` 包。 6. **模块登录分裂**:订阅模块不得复制登录页、Cookie 或权限判断;模块调用统一控制面 BFF,由控制面把管理员身份传给订阅服务。 7. **Core 更新兼容性**:插件只依赖已声明的 HTTP allowlist 和响应 DTO,Core 更新时只做 API 契约兼容检查。 ## 8. 第一版验收标准 - 官方 Core `/Users/qiu/Desktop/Sub2API` 保持干净,版本和源码不被修改。 - 统一 Plugin Admin 前端能独立 `npm run build`,不依赖 Core 的 Vite 配置;订阅模块以模块产物或受控动态入口挂载。 - 管理员只登录一次即可访问插件控制面和已启用订阅模块;直接刷新模块路由仍保持同一插件会话,不把凭据写入 URL。 - 425px、768px、1440px 下无页面级横向溢出;表格需要横向查看时只滚动表格容器。 - 所有管理员 mutation 仍经过插件后端的会话、CSRF、step-up 和幂等校验。 - DOM、网络响应、日志和 URL 不出现 Core token、Admin Key、密码或服务密钥。 - ECharts 图表只展示有数据的系列,容器尺寸稳定,窗口变化后可重绘。 ## 9. 当前状态 已完成: - 拉取官方 TDesign Vue Next starter。 - 固定 starter 基线和依赖版本。 - 完成 starter 基线构建检查。 - 完成独立插件页面、API、组件和迁移边界评估。 - 根据反馈修正页面边界:订阅从“独立后台”改为统一插件控制面内的业务模块,不再单独登录。 已完成第一版落地: - `plugins/plugin-admin/ui-vue` 基于 TDesign Vue Next starter 建立独立 Vue 3/Vite 应用。 - Plugin Admin 登录、统一 Shell、概览、插件列表/详情、市场和审计页面已迁移,图标统一使用 `tdesign-icons-vue-next`,概览趋势图使用 ECharts。 - 订阅作为 Shell 内的 `/modules/subscription/*` 业务模块挂载,不再渲染第二个登录页;控制面新增同源、allowlist 约束的订阅只读 BFF。 - Go 静态资源支持挂载路径、SPA 回退和路径穿越拒绝;`build-ui.sh` 负责可重复构建并复制嵌入产物。 - 已完成 TypeScript/Vite、Go 单元、API 契约和 425/900/1440 多视口浏览器验收;下一轮可继续补充真实业务写操作,但不改变 Core 边界。