清理:移除 RDP 遗留资料并纳管产品文档与运维工具
变更详情:清理 RDP 遗留文档与临时文件,纳管产品文档与运维工具脚本
This commit is contained in:
1 parent
26fde0369e
commit
7fdcb53dd9
14 files changed
+759
-100
No files matched your search
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,33 +0,0 @@
|
||||
# FreeRDP 3 客户端 API 参考(Ubuntu 24.04 / freerdp3-dev)
|
||||
|
||||
> 用途:kiosk-shell 内嵌 FreeRDP 客户端时使用,避免拉起外部进程(开发方案 3.2 节)。
|
||||
> 记录时间:2026-10-23
|
||||
|
||||
## 包名
|
||||
- 运行时:`libfreerdp-client3-3`、`libfreerdp3-3`
|
||||
- 开发:`freerdp3-dev`(Ubuntu 24.04 提供 `freerdp3-dev` 与 `libfreerdp-client3-3-dev`)
|
||||
- pkg-config 名称:`freerdp3`、`freerdp3-client`(安装后以 `pkg-config --list-all | grep freerdp` 实测为准)
|
||||
|
||||
## 关键头文件
|
||||
| 头文件 | 用途 |
|
||||
|---|---|
|
||||
| `freerdp/client.h` | 客户端主入口、freerdp_client_context_new / freerdp_client_context_free |
|
||||
| `freerdp/freerdp.h` | 核心上下文 |
|
||||
| `freerdp/settings.h` | 连接参数设置(freerdp_settings_new / set) |
|
||||
| `freerdp/channels/cliprdr.h` | 剪贴板通道 |
|
||||
| `freerdp/gdi/gfx.h` | GFX 图形管线(AVC420/AVC444/RFX 能力) |
|
||||
| `freerdp/crypto/tls.h` | TLS |
|
||||
|
||||
## 最小连接流程(伪代码)
|
||||
```c
|
||||
freerdp_client_context* ctx = freerdp_client_context_new();
|
||||
RdpClientContext* cctx = ...;
|
||||
freerdp_settings_new(0); // 释放: freerdp_settings_free
|
||||
freerdp_set_pointer / freerdp_set_keyboard ... // 输入回调
|
||||
ctx->Connect = ...; // 事件表
|
||||
freerdp_client_context_new / connect
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
- `/gfx` 命令行语法在 3.32.1 上必须用 `|` 分隔的能力组合(如 `progressive|RFX|AVC420|AVC444`),
|
||||
单独 `AVC420` 会解析失败。API 侧对应 `gfx` 能力位设置。
|
||||
@@ -1,67 +0,0 @@
|
||||
# FreeRDP 3 内嵌客户端实现笔记(Ubuntu 24.04 / freerdp3-dev 3.32.1)
|
||||
|
||||
> 对应《VDI 云桌面软件开发方案》3.2 / 3.3 节:以 libfreerdp3 API 内嵌(非拉起外部进程)。
|
||||
> 记录时间:2026-10-23,实测于 RK3528 盒子(Armbian / Ubuntu Noble / aarch64)
|
||||
|
||||
## 1. API 结构(与 FreeRDP 2.x 差异很大)
|
||||
|
||||
| 用途 | FreeRDP 3 写法 |
|
||||
|---|---|
|
||||
| 创建实例 | `freerdp* instance = freerdp_new();` |
|
||||
| 建立上下文 | `freerdp_context_new_ex(instance, settings)` |
|
||||
| 上下文 | `instance->context`(`rdpContext*`,公开结构体) |
|
||||
| 事件回调 | `instance->PostConnect` / `instance->PostDisconnect` / `instance->AuthenticateEx` |
|
||||
| 更新回调 | `instance->context->update->BitmapUpdate` / `->EndPaint` |
|
||||
| GDI | `gdi_init(instance, PIXEL_FORMAT_BGRX32)` |
|
||||
| 取帧 | `context->gdi->primary_buffer` + `context->gdi->stride` |
|
||||
|
||||
设置项键名(与 2.x 不同):
|
||||
`FreeRDP_ServerHostname` / `FreeRDP_Username` / `FreeRDP_Password` / `FreeRDP_Domain` /
|
||||
`FreeRDP_DesktopWidth` / `FreeRDP_DesktopHeight` / `FreeRDP_ColorDepth` / `FreeRDP_Fullscreen` /
|
||||
`FreeRDP_IgnoreCertificate` / `FreeRDP_GfxProgressive` / `FreeRDP_GfxH264` / `FreeRDP_GfxAVC444` …
|
||||
|
||||
## 2. 三个必须踩过才知道的坑
|
||||
|
||||
### 坑一:gdi_init 必须在 PostConnect 里调用
|
||||
在 `freerdp_context_new_ex()` 之后立刻调用 `gdi_init()` 会 **SIGSEGV**
|
||||
(`gdi_init_ex` 段错误)。官方 x11 客户端(`client/X11/xf_client.c` 的 `xf_post_connect`)
|
||||
把 `gdi_init` 放在 PostConnect 回调内,因为 GDI 依赖连接协商后的桌面尺寸与颜色格式。
|
||||
|
||||
### 坑二:不能用 instance->ContextSize 扩展 rdpContext
|
||||
常见做法是把自定义指针塞进扩展的 rdpContext,但 `gdi_init_ex()` 会按 `ContextSize`
|
||||
重新分配 context 缓冲区,扩展字段随即失效 → 段错误。
|
||||
改用静态注册表按 `freerdp*` 记录会话对象;GFX 通道回调则用官方的
|
||||
`RdpgfxClientContext.custom` 字段。
|
||||
|
||||
### 坑三:NLA 认证必须传空字符串而非 nullptr
|
||||
Windows 端启用 NLA(CredSSP)时,认证回调里把密码置为 `nullptr` 会导致
|
||||
`SEC_E_NO_CREDENTIALS [0x8009030e]`。必须传 `strdup("")`。
|
||||
认证回调签名:
|
||||
`BOOL (*pAuthenticateEx)(freerdp*, char** username, char** password, char** domain, rdp_auth_reason)`
|
||||
|
||||
## 3. /gfx 语法(命令行与设置项的对应)
|
||||
FreeRDP 3.32.1 的 `/gfx` **不接受单个管道名**,必须是 `|` 分隔的能力组合:
|
||||
|
||||
```
|
||||
/gfx:progressive|RFX|AVC420|AVC444 ← 可解析
|
||||
/gfx:AVC420 ← parsing failed [-1000]
|
||||
/gfx:AVC444 ← parsing failed [-1000]
|
||||
```
|
||||
|
||||
API 侧对应 `FreeRDP_GfxProgressive` / `FreeRDP_GfxH264` / `FreeRDP_GfxAVC444` 等布尔项。
|
||||
|
||||
## 4. 像素格式
|
||||
`PIXEL_FORMAT_BGRX32` 的内存布局是 **B,G,R,X** 四字节/像素。
|
||||
QImage 没有对应格式,输出前需手动做 BGR→RGB 转换。
|
||||
注意 `PIXEL_FORMAT_*` 是计算宏 `FREERDP_PIXEL_FORMAT(...)`,**不能硬编码数值**。
|
||||
|
||||
## 5. 后续演进(对应 freerdp-rk 分支)
|
||||
当前实现是 CPU 侧 GDI 缓冲 → Qt 绘制。开发方案 3.3 节要求改为:
|
||||
|
||||
```text
|
||||
FreeRDP3 解复用(gfx 通道) → GStreamer h264parse → mppvideodec(VPU硬解, zero-copy DMABuf)
|
||||
→ waylandsink(DRM plane)
|
||||
```
|
||||
|
||||
盒子已具备 `/dev/mpp_service`(VPU)与 `/dev/rga`,但缺 `mppvideodec` GStreamer 插件
|
||||
(Ubuntu 官方源没有,需 Rockchip BSP / Armbian 额外源或自研)。
|
||||
@@ -0,0 +1,39 @@
|
||||
@echo off
|
||||
REM ============================================================
|
||||
REM MttVDD 虚拟显示驱动 - 一键安装(管理员运行)
|
||||
REM 用法:右键本文件 -> 以管理员身份运行
|
||||
REM ============================================================
|
||||
setlocal
|
||||
cd /d "%~dp0"
|
||||
|
||||
echo [1/4] 关闭可能占用驱动的程序...
|
||||
sc stop SunshineService >nul 2>&1
|
||||
taskkill /f /im sunshine.exe >nul 2>&1
|
||||
|
||||
echo [2/4] 安装驱动签名证书...
|
||||
certutil -addstore -f "Root" "Virtual_Display_Driver.cer"
|
||||
if errorlevel 1 (
|
||||
echo [错误] 证书安装失败,请确认以管理员身份运行
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [3/4] 安装 MttVDD 驱动...
|
||||
pnputil /add-driver "MttVDD.inf" /install
|
||||
if errorlevel 1 (
|
||||
echo [警告] 驱动安装返回错误,尝试另一种方式...
|
||||
rundll32.exe setupapi.dll,InstallHinfSection DefaultInstall 132 .\MttVDD.inf
|
||||
)
|
||||
|
||||
echo [4/4] 显示当前虚拟显示器状态...
|
||||
pnputil /enum-devices /class Display
|
||||
|
||||
echo.
|
||||
echo ============================================================
|
||||
echo 安装完成。请重启 Windows 后:
|
||||
echo 1) 设置 - 显示 - 找到 MttVDD 虚拟显示器
|
||||
echo 2) 分辨率选 1920x1080,刷新率选 60Hz
|
||||
echo 3) 重启 SunshineService 服务
|
||||
echo 重启方式:开始菜单搜索 services.msc -> SunshineService -> 重新启动
|
||||
echo ============================================================
|
||||
pause
|
||||
@@ -0,0 +1,82 @@
|
||||
# RDP 与 Moonlight 实测对比(2026-10-28)
|
||||
|
||||
## 测试环境
|
||||
|
||||
```text
|
||||
终端:RK3528 PRO DDR4,Armbian 25.05,aarch64,LightDM + Xorg
|
||||
显示器:1920×1440 @ 75Hz
|
||||
云桌面:VM 100(win10-test),Proxmox VE 9.2.21,节点 starhe
|
||||
终端到云桌面:192.168.1.188 -> 192.168.1.70,同一局域网 WiFi
|
||||
```
|
||||
|
||||
服务端显示环境改造(本次关键前提):
|
||||
|
||||
```text
|
||||
改造前:Microsoft Basic Display Adapter,1920×1080 @ 1Hz
|
||||
改造后:Virtual Display Driver 8.35.11.365,1920×1080 @ 60Hz
|
||||
```
|
||||
|
||||
改造前 Sunshine 抓不到稳定帧(1Hz),改造后可正常编码。
|
||||
|
||||
## 对比数据
|
||||
|
||||
| 指标 | RDP(当前 kiosk-shell) | Moonlight 1080p30 | Moonlight 1080p60 |
|
||||
|---|---|---|---|
|
||||
| 协议/编码 | RDP GFX,CPU 软解 | H.264 / libx264 软编 | H.264 / libx264 软编 |
|
||||
| 分辨率 | 1920×1440 | 1920×1080 | 1920×1080 |
|
||||
| 终端 CPU | 约 111%(单核近满载) | 约 26% | 约 26% |
|
||||
| 终端内存 | 约 232 MB | 约 192 MB | 约 165 MB |
|
||||
| 终端温度 | 约 58~65℃ | 约 56℃ | 约 53℃ |
|
||||
| 实际帧率 | 无可靠统计(观感为低帧+卷帘) | 12.83 FPS | 22.79 FPS |
|
||||
| 网络丢包 | 未测 | 0.00% | 0.00% |
|
||||
| 网络抖动丢帧 | 未测 | 0.08% | 15.28% |
|
||||
| 网络延迟 | 未测 | 2 ms | 6 ms |
|
||||
| 主机处理延迟 | 未测 | 14.4 / 27.6 / 平均 18.1 ms | 18.8 / 78.3 / 平均 38.2 ms |
|
||||
| 平均渲染耗时 | 未测 | 3.34 ms | 46.26 ms |
|
||||
| 画面观感 | 卷帘、翻页 | 完整清晰,无撕裂 | 完整清晰,无撕裂 |
|
||||
|
||||
## 结论
|
||||
|
||||
1. **卷帘问题不是 RDP 协议的限制,是当前 RDP 客户端实现路径的问题。**
|
||||
Moonlight 在同一台盒子、同一台云桌面、同一网络下画面完整清晰,无卷帘无撕裂,
|
||||
抓屏确认 1080p 画面文字锐利、任务栏时间正确。
|
||||
|
||||
2. **Moonlight 的瓶颈在服务端,不在终端,也不���网络。**
|
||||
1080p30 时网络丢包 0.00%、延迟 2 ms、渲染 3.34 ms、终端 CPU 26%,
|
||||
但实际帧率仅 12.83 FPS;1080p60 时主机处理延迟升到平均 38.2 ms、渲染 46.26 ms。
|
||||
服务端当前使用 libx264 软件编码(VM 内无 NVIDIA 直通,`nvidia-smi` 不存在),
|
||||
4 核 CPU 同时承担 1080p 编码与桌面捕获,是帧率上限的真正原因。
|
||||
|
||||
3. **RDP 路径的 CPU 代价约为 Moonlight 的 4 倍**(111% vs 26%),
|
||||
因为 RDP 走 `FreeRDP GDI -> CPU 内存复制 -> QImage/QPixmap -> QLabel -> Xorg`,
|
||||
而 Moonlight 只做一次解码和一次窗口呈现。
|
||||
|
||||
4. **RK3528 VPU 硬解在当前 moonlight-qt 6.2.0 下不可用。**
|
||||
`h264_v4l2m2m` / `hevc_v4l2m2m` / `hevc_v4l2request` 均报
|
||||
`Could not find a valid device`,即使盒子存在 /dev/mpp_service、/dev/rga 和
|
||||
/dev/dri/renderD128。需 Rockchip MPP FFmpeg 补丁或 V4L2 request 驱动。
|
||||
|
||||
## 后续建议
|
||||
|
||||
优先级从高到低:
|
||||
|
||||
1. **服务端 GPU 直通**:将宿主机 GTX 965M(PCI 01:00.0,IOMMU Group 2 独占)
|
||||
直通给 VM 100,使 Sunshine 可用 NVENC 硬编码。预期把 1080p 帧率从 13 FPS
|
||||
提升到 60 FPS,同时释放服务端 CPU。需先确认内核 `intel_iommu=on`、
|
||||
`vfio-pci` 已绑定,以及该笔记本 GPU 的 vBIOS ROM 提取。
|
||||
2. **消除帧率随请求升高而抖动**(60 FPS 时抖动丢帧 15.28%):服务端稳定后复测。
|
||||
3. **RK3528 硬解适配**:解决 V4L2 request/m2m 设备缺失,这是达成 4K 的前提。
|
||||
4. **协议选型建议**:
|
||||
- 若 GPU 直通可行,Moonlight 在 CAD/3D/视频场景优于 RDP,建议按产品方案采用双协议:
|
||||
普通办公用 RDP,GPU/CAD/3D 用 Moonlight;
|
||||
- 同时保留并优化 RDP 路径的 Weston + MPP/VPU + DMABUF/DRM 零拷贝改造,
|
||||
使 RDP 在办公场景达到可接受体验。
|
||||
5. 当前 Moonlight 未接 VPU,1080p 软件解码仅 26% CPU 但 4K 会超出能力,
|
||||
需在 4K 目标确定后优先解决硬解。
|
||||
|
||||
## 附:本次变更
|
||||
|
||||
- VM 100:安装 Virtual Display Driver(MttVDD),提供 1920×1080@60Hz 虚拟显示器。
|
||||
- VM 100:安装 Sunshine v2026.914.233613,Web UI 账号 admin / vdi12345。
|
||||
- 终端:安装 moonlight-qt 6.2.0,已与 Sunshine 完成配对。
|
||||
- 终端:kiosk-shell 自启动已恢复(~/.config/autostart/vdi-kiosk.desktop)。
|
||||
@@ -0,0 +1,74 @@
|
||||
# Sunshine 显卡环境配置指引(转给操作 VM 的同事)
|
||||
|
||||
## 背景
|
||||
|
||||
我们在 VM 100(win10-test,192.168.1.70)里装了 Sunshine 用于 Moonlight 串流验证。当前卡在:VM 没有可用 GPU,Windows 只有「Microsoft 基本显示适配器」,分辨率 1024×768、刷新率 1Hz,Sunshine 无法按 30/60fps 捕获编码。
|
||||
|
||||
不需要动 Proxmox,只需要在 Windows 里完成两件事:装虚拟显示器驱动 + 确认 Sunshine 配置。
|
||||
|
||||
## 第 1 步:安装虚拟显示器驱动(IddSampleDriver)
|
||||
|
||||
让 Windows 出现一个虚拟显卡,可自定义分辨率和刷新率:
|
||||
|
||||
1. 下载虚拟显示驱动包(ParrotGeek 的 IddSampleDriver,或等效的「Virtual Display Driver」)。
|
||||
常用地址:https://github.com/itsmikethetech/Virtual-Display-Driver/releases
|
||||
(如果 GitHub 打不开,用镜像:把链接前面加 https://gh-proxy.com/ )
|
||||
2. 解压后右键 `IddSampleDriver.inf` →「安装」。
|
||||
3. 重启 Windows。
|
||||
4. 装好后设备管理器会出现「IddSampleDriver Device」,显示设置里会多出一个虚拟显示器。
|
||||
5. 把虚拟显示器设置为:
|
||||
- 分辨率:1920×1080(先用 1080p,稳定后再试 2K)
|
||||
- 刷新率:60Hz(关键!当前 1Hz 是主要问题)
|
||||
- 如果看到多显示器,把虚拟屏设为「扩展这些显示器」, Sunshine 默认抓主屏;也可以只保留虚拟屏。
|
||||
|
||||
## 第 2 步:确认 NVIDIA 独显是否可用(如果宿主已直通/有驱动)
|
||||
|
||||
打开 PowerShell 执行:
|
||||
|
||||
```powershell
|
||||
nvidia-smi
|
||||
```
|
||||
|
||||
- 如果能输出显卡信息(GTX 965M):很好,说明 VM 内能用 NVIDIA。
|
||||
- 请安装 GeForce 驱动(如未装),然后告知我们,我们把 Sunshine 切到 NVENC 硬编码。
|
||||
- 如果提示找不到命令或没有 NVIDIA 设备:跳过此步,走纯软件编码 + 虚拟显示器路线(也够验证流畅度)。
|
||||
|
||||
## 第 3 步:检查 Sunshine 服务状态
|
||||
|
||||
Sunshine 已装在 `C:\Program Files\Sunshine\`,服务名 `SunshineService`。
|
||||
|
||||
PowerShell 执行:
|
||||
|
||||
```powershell
|
||||
Get-Service SunshineService
|
||||
Restart-Service SunshineService
|
||||
```
|
||||
|
||||
重启服务后再看日志确认识别到新显示器:
|
||||
|
||||
```powershell
|
||||
Get-Content "C:\Program Files\Sunshine\config\sunshine.log" -Tail 60
|
||||
```
|
||||
|
||||
需要看到的关键行(类似):
|
||||
|
||||
```
|
||||
Desktop resolution [1920x1080]
|
||||
Display refresh rate [60 Hz]
|
||||
```
|
||||
|
||||
## 第 4 步:告知我们结果
|
||||
|
||||
只需回三条信息:
|
||||
|
||||
1. 虚拟显示器是否装好,分辨率/刷新率是多少;
|
||||
2. `nvidia-smi` 是否有输出;
|
||||
3. sunshine.log 最后几十行里的 Desktop resolution / Display refresh rate 数值。
|
||||
|
||||
我们这边会立刻重新发起 Moonlight 串流测试并采集性能数据。
|
||||
|
||||
## 备注
|
||||
|
||||
- Web UI(可选):https://192.168.1.70:47990 账号 admin / 密码 vdi12345
|
||||
- 装驱动需要重启 VM,重启后 SunshineService 会自启,无需其他操作。
|
||||
- Sunshine 的串流端口 47984/47989/47990/48010 已确认开放,防火墙无需改动。
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<display_config>
|
||||
<target_display>
|
||||
<target_x>0</target_x>
|
||||
<target_y>0</target_y>
|
||||
<target_width>1920</target_width>
|
||||
<target_height>1080</target_height>
|
||||
<target_refresh_rate>60</target_refresh_rate>
|
||||
</target_display>
|
||||
<adapter_index>0</adapter_index>
|
||||
<modes>
|
||||
<mode>
|
||||
<width>1920</width>
|
||||
<height>1080</height>
|
||||
<refresh_rate>60</refresh_rate>
|
||||
</mode>
|
||||
</modes>
|
||||
</display_config>
|
||||
</root>
|
||||
@@ -0,0 +1,287 @@
|
||||
# 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、测试保留。
|
||||
Reference in new issue
Block a user