vdi-cloud/docs/web-console-mvp-plan-20261028.md
宋一鸣 7fdcb53dd9 清理:移除 RDP 遗留资料并纳管产品文档与运维工具
变更详情:清理 RDP 遗留文档与临时文件,纳管产品文档与运维工具脚本
2026-10-29 17:44:25 +08:00

288 lines
9.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# VDI Web 管理控制台 MVP 实施方案
> 版本:v0.1(功能先行,UI 稿待项目经理提供)
> 日期:2026-10-28
> 依据:`VDI云桌面软件开发方案(1).docx` 第 2、4、5 节及 `VDI云桌面完整方案-云管端.docx` 管理平台模块表。
## 1. 先明确两个“登录”
本项目有两个不同的界面,必须分开:
| 界面 | 使用者 | 运行位置 | 职责 |
|---|---|---|---|
| 终端 kiosk-shell | 云桌面最终用户 | RK3528 盒子本地全屏 | 首配、设备绑定、用户登录、选择/进入被授权桌面、会话状态 |
| Web 管理控制台 console | 超级管理员、运维、只读人员 | PC 浏览器 | 终端、桌面池、用户绑定、GPU、监控、OTA、审计管理 |
正式文档中的 `console/` 指第二项。它不应运行在盒子上,也不应直接发起 RDP/Moonlight;它通过平台 API 管理资源和下发策略。
“盒子开机直连 Moonlight”只能作为当前串流技术验证,不是最终产品登录流程。最终终端流程应恢复为:
```text
盒子开机
-> kiosk-shell 全屏终端登录/首配页
-> vdt-agent 注册并获取终端身份
-> 用户登录或终端绑定校验
-> 平台返回该用户可用的桌面列表及短期连接信息
-> 用户选择桌面
-> kiosk-shell 按 protocol=rdp|moonlight 启动会话
-> 断开后回桌面列表/登录页
```
## 2. Web 控制台 MVP 目标
第一版目标不是做漂亮的大屏,而是跑通一个可演示、可替换 UI、可接真实后端的后台系统:
1. 用户能登录和退出;
2. 根据角色控制菜单和按钮;
3. 管理员能查看终端、桌面、用户及绑定关系;
4. 能对终端下发命令、对桌面执行开关机/重置;
5. 能查看基础状态、操作结果和审计记录;
6. 后端未完成时使用 Mock API,后端接口上线后不改页面业务逻辑即可切换。
## 3. 技术栈与工程结构
按定版文档执行:Vue 3 + Vite + TypeScript 严格模式 + Element Plus。
建议补充:Pinia(状态)、Vue Router、Axios、Vitest、Playwright、MSW(Mock API)。
```text
console/
├─ src/
│ ├─ api/ # OpenAPI 生成 SDK 的薄封装
│ ├─ assets/
│ ├─ components/ # 领域无关组件
│ ├─ layouts/ # 登录布局、控制台布局
│ ├─ mocks/ # MSW handlers 与演示数据
│ ├─ router/ # 路由、鉴权守卫、RBAC meta
│ ├─ stores/ # auth、app、notification
│ ├─ types/ # 页面 ViewModel;API 类型由生成器管理
│ ├─ views/
│ │ ├─ login/
│ │ ├─ dashboard/
│ │ ├─ terminals/
│ │ ├─ desktops/
│ │ ├─ users/
│ │ ├─ gpu/
│ │ ├─ monitoring/
│ │ ├─ ota/
│ │ └─ audit/
│ ├─ App.vue
│ └─ main.ts
├─ e2e/
├─ public/
├─ .env.development
├─ .env.mock
├─ package.json
└─ vite.config.ts
```
约束:页面不能直接拼 URL 或写 Axios;所有网络调用只经过 `api/`。这样 Mock 与真实后端可无感切换。
## 4. 页面与优先级
### M0:登录与应用框架
- 登录页:用户名、密码、登录按钮、错误状态、加载状态;
- 控制台壳:侧边导航、顶部栏、面包屑、当前账号、退出;
- 401 自动清理会话并回登录;
- 403 权限提示;
- 路由级 RBAC:`super_admin`、`operator`、`viewer`;
- 开发环境使用 Mock 登录,生产环境只调用真实 API。
### M1:核心演示闭环
1. 仪表盘:在线终端、活动会话、运行桌面、告警数量;
2. 终端管理:列表、搜索、状态筛选、详情、重启、重置会话;
3. 桌面管理:列表、状态筛选、开机、关机、重启、重置;
4. 用户与绑定:用户列表、用户详情、终端/桌面绑定与解绑;
5. 审计日志:操作者、动作、目标、结果、时间、请求 ID。
M1 完成后已经可以给项目经理演示完整业务流程。
### M2:完整文档范围
- 桌面池:模板、容量、回收策略;
- GPU 池:节点/PCI 地址/型号/状态/绑定桌面;
- 监控:会话在线数、FPS、RTT、节点水位、告警;
- OTA 中心:版本、批次、灰度比例、进度、失败终端;
- CSV 用户/绑定批量导入向导;
- 配置模板与配置版本下发。
## 5. 登录与权限方案
### 登录接口
```http
POST /api/v1/auth/login
Content-Type: application/json
{
"username": "admin",
"password": "******"
}
```
建议响应:
```json
{
"accessToken": "jwt",
"expiresIn": 3600,
"user": {
"id": "usr_001",
"username": "admin",
"displayName": "系统管理员",
"role": "super_admin"
}
}
```
建议第一版 access token 仅存内存;刷新 token 使用 `HttpOnly + Secure + SameSite` Cookie。若后端尚未支持 refresh,MVP 可暂存 `sessionStorage`,但不要长期使用 `localStorage` 保存高权限令牌。
### 权限矩阵
| 能力 | super_admin | operator | viewer |
|---|---:|---:|---:|
| 查看所有页面 | 是 | 是 | 是 |
| 终端远程命令 | 是 | 是 | 否 |
| 桌面生命周期操作 | 是 | 是 | 否 |
| 用户/绑定修改 | 是 | 否 | 否 |
| GPU 绑定 | 是 | 否 | 否 |
| OTA 发布/灰度 | 是 | 是 | 否 |
| 只读监控/审计 | 是 | 是 | 是 |
前端 RBAC 只是交互约束,真正授权必须由 `api-gateway` 再验证,不能只隐藏按钮。
## 6. 第一版 API 契约
文档已明确的接口优先沿用:
```text
POST /api/v1/auth/login
GET /api/v1/users
POST /api/v1/desktop/assign
POST /api/v1/pool/{id}/action
GET /api/v1/gpu/cards
POST /api/v1/gpu/bind
GET /api/v1/monitor/query
```
为控制台 MVP 补齐建议接口(需后端确认并写入 OpenAPI):
```text
GET /api/v1/auth/me
POST /api/v1/auth/logout
GET /api/v1/terminals
GET /api/v1/terminals/{id}
POST /api/v1/terminals/{id}/commands
GET /api/v1/desktops
GET /api/v1/desktops/{id}
POST /api/v1/desktops/{id}/actions
GET /api/v1/bindings
DELETE /api/v1/bindings/{id}
GET /api/v1/audit-logs
```
所有列表统一查询参数:`page`、`pageSize`、`keyword`、`status`、`sort`;统一响应:
```json
{
"items": [],
"page": 1,
"pageSize": 20,
"total": 0,
"requestId": "req_xxx"
}
```
所有命令型接口必须返回 `commandId`,页面展示“已提交”,再轮询或通过 WebSocket/MQTT 网关显示最终结果,不能把 HTTP 200 当作设备已经执行成功。
## 7. Mock 先行策略
后端还没完成时,前端不应硬编码页面数据。使用 MSW 模拟真实 HTTP:
- 固定 3 个测试账号,对应三角色;
- 终端包含在线/离线/会话中/升级中;
- 桌面包含运行/停止/错误/任务中;
- 所有命令先进入 `pending`,1–3 秒后变成 `success` 或 `failed`;
- 登录失败、401、403、网络超时、空列表都要有测试场景;
- `VITE_API_MODE=mock|real` 切换数据源。
项目经理 UI 稿到后,Mock 数据仍然可用于逐页视觉验收。
## 8. 与终端登录流程的接口边界
管理员 Web 控制台不直接把 VM 密码写进终端,也不让终端调用 Proxmox API。
建议终端用户登录流程由 `auth-svc` 单独提供:
```text
POST /api/v1/terminal/session/login
GET /api/v1/terminal/session/desktops
POST /api/v1/terminal/session/connect-ticket
```
`connect-ticket` 返回短期、一次性连接信息:
```json
{
"desktopId": "desk_001",
"protocol": "moonlight",
"endpoint": "192.168.1.70",
"app": "Desktop",
"display": { "width": 1920, "height": 1080, "fps": 60 },
"ticket": "short-lived-token",
"expiresAt": "2026-10-28T16:30:00+08:00"
}
```
这部分不是 `console/` 页面,但必须和 Web 控制台的“用户/终端/桌面绑定”共享同一套后端数据。
## 9. UI 稿到来前的页面设计原则
第一版只做稳定工作台,不做营销式页面:
- 左侧导航 + 顶部工具栏 + 主内容区;
- 列表优先,详情使用独立页或抽屉;
- 状态使用图标/标签,不依赖单一颜色;
- 危险操作二次确认;
- 所有异步操作显示提交、执行中、成功、失败四态;
- 页面级空态、错误态、无权限态必须完整;
- 颜色、字号、间距集中为设计 token,避免 UI 稿到后逐页改 CSS;
- 表格列、筛选区、表单字段以配置驱动,减少视觉改版成本。
## 10. 验收标准
M1 应达到:
1. 三种角色都能登录,菜单/按钮权限正确;
2. 刷新页面仍能恢复会话,令牌过期自动回登录;
3. 终端、桌面、用户/绑定、审计五条流程可演示;
4. 命令有执行中与最终结果,不出现“点击无反馈”;
5. API 全走统一 SDK/适配层,无页面直连 Axios;
6. Vitest 覆盖 auth store、路由守卫、权限判断;
7. Playwright 覆盖登录、终端命令、桌面操作、用户绑定四条主路径;
8. `npm run lint`、`npm run typecheck`、`npm run test`、`npm run build` 全通过。
## 11. 推荐实施顺序
```text
第 1 步:初始化 console 工程、路由、布局、设计 token
第 2 步:OpenAPI 初稿 + API SDK 生成 + MSW Mock
第 3 步:登录、会话恢复、RBAC、错误处理
第 4 步:终端管理 + 桌面管理
第 5 步:用户与绑定 + 审计日志
第 6 步:仪表盘聚合数据
第 7 步:Playwright E2E 与生产构建
第 8 步:项目经理 UI 稿到后替换视觉层
第 9 步:接真实 Go API,关闭 Mock
```
## 12. 当前决策建议
- 现在先开发 `console/` 的 M0 + M1,不等 UI 稿;
- 同时为 `terminal/kiosk-shell` 恢复“登录/桌面列表后连接”的产品流程,不再把开机直连 Moonlight 当最终形态;
- Web 控制台第一版只接 Mock,API 契约先和后端负责人确认;
- Moonlight/RDP 统一抽象成终端连接票据的 `protocol` 字段,Web 控制台只管理策略,不直接操控串流客户端;
- UI 稿到后只调整布局组件与 design tokens,业务路由、权限、API、测试保留。