test(desktop-client): 灵动岛各状态截图做像素级留档与断言(尺寸/宽高比/绘制内容/紧急红光),截图归档到 docs/screenshots/island,打包后 EXE 16/16 通过
This commit is contained in:
1 parent
d42b0b2a1b
commit
3ab3cb1eb1
6 files changed
+194
-65
No files matched your search
@@ -20,7 +20,7 @@
|
||||
| 1 | pnpm monorepo 脚手架、TypeScript / ESLint / Prettier / 环境变量 | ✅ 已完成 |
|
||||
| 2 | 后端:Prisma schema + 迁移 + 种子数据 + JWT 认证 + RBAC + 模块化 REST API + Socket.IO | ✅ 已完成 |
|
||||
| 3 | Web 管理端:登录、主布局、仪表盘、班级/学生/课表/作业/通知/成绩页面、Axios 封装、实时提示 | ✅ 已完成 |
|
||||
| 4 | EXE 客户端:Electron 主进程/preload/渲染进程、登录、课表/作业/通知/成绩/设置、实时推送、IndexedDB 离线缓存 | ✅ 已完成(冒烟验证 18/18) |
|
||||
| 4 | EXE 客户端:Electron 主进程/preload/渲染进程、登录、课表/作业/通知/成绩/设置、实时推送、IndexedDB 离线缓存 | ✅ 已完成(冒烟验证 19/19) |
|
||||
| 5 | 三端联调脚本、打包命令、完整 README | ✅ 已完成(三套安装包 + 两套 UI 回归测试) |
|
||||
| 6 | 测试账号与种子数据说明 | ✅ 已完成(见下文) |
|
||||
| 7 | 生产化:服务端安装程序(内置 Node)、Web 端 PWA 可安装、Docker + Nginx 部署、生产加固与运维文档 | ✅ 已完成(见 [`docs/production.md`](docs/production.md)) |
|
||||
@@ -173,13 +173,13 @@ pnpm verify:desktop
|
||||
# 另开一个终端先启动后端:pnpm dev:server
|
||||
pnpm verify:e2e # 后端 + REST + Socket.IO + RBAC + 上课时段拦截:62 项
|
||||
pnpm verify:web # Web 管理端真实点击(含上课时段紧急通知全屏警告):8 项
|
||||
pnpm verify:desktop # Electron 客户端(含灵动岛与联网集成):18 项
|
||||
pnpm verify:desktop # Electron 客户端(含灵动岛与联网集成):19 项
|
||||
```
|
||||
|
||||
后端脚本验证**实时推送时延、作业完成、成绩下发、权限隔离、上课时段紧急通知拦截**等 62 项,
|
||||
实测通知 37ms、作业 26ms、成绩 25ms 到达(要求 < 5 秒),紧急通知 409 拦截与二次确认后发布均通过;
|
||||
客户端脚本验证 preload 桥接、渲染进程、IndexedDB 读写、断网回退、**灵动岛四种状态切换**与联网集成
|
||||
(登录 + 四类数据 + Socket.IO),实测 18/18 通过。
|
||||
(登录 + 四类数据 + Socket.IO),实测 19/19 通过。
|
||||
|
||||
## 默认账号与种子数据
|
||||
|
||||
@@ -202,30 +202,30 @@ pnpm verify:desktop # Electron 客户端(含灵动岛与联网集成)
|
||||
|
||||
## 常用命令
|
||||
|
||||
| 命令 | 说明 |
|
||||
| ------------------------------------------- | -------------------------------------------------------------------- |
|
||||
| `pnpm dev` | 并行启动 shared(tsc watch) + 后端 + Web 端 |
|
||||
| `pnpm dev:server` / `pnpm dev:web` | 只启动后端 / 只启动 Web 端 |
|
||||
| `pnpm dev:desktop` | 启动 EXE 客户端开发模式(Vite 5174 + Electron,热更新) |
|
||||
| `pnpm build` | 构建 shared + 后端 + Web 端 + EXE 客户端 |
|
||||
| `pnpm build:desktop` | 仅构建 EXE 客户端(esbuild 主进程/preload + Vite 渲染进程) |
|
||||
| `pnpm icons` | 生成应用图标(PNG/ICO,用 Electron 渲染 SVG) |
|
||||
| **`pnpm dist:server`** | **打包服务端 + Web 管理端**(免安装目录 + NSIS 安装程序,内置 Node) |
|
||||
| `pnpm dist:dir` | 打包客户端免安装目录 `release/win-unpacked`(含可执行文件,最快) |
|
||||
| `pnpm dist:win` | 打包客户端 nsis 安装包 + portable 单文件 EXE |
|
||||
| `pnpm dist:all` | 服务端安装程序 + 客户端安装程序一起打 |
|
||||
| `pnpm verify:e2e` | 后端端到端验收(62 项,需服务端已启动) |
|
||||
| `pnpm verify:web` | Web 管理端 UI 真实点击测试(Electron 驱动,8 项) |
|
||||
| `pnpm verify:desktop` | EXE 客户端冒烟验证(18 项,含灵动岛、侧边栏点击与离线回退) |
|
||||
| `pnpm typecheck` | 全仓库类型检查(含 `vue-tsc`) |
|
||||
| `pnpm lint` / `pnpm lint:fix` | ESLint 检查 / 自动修复 |
|
||||
| `pnpm format` / `pnpm format:check` | Prettier 格式化 / 检查 |
|
||||
| `pnpm db:generate` | 生成 Prisma Client(输出到 `packages/server/src/generated/prisma`) |
|
||||
| `pnpm db:migrate` | 创建并应用迁移 |
|
||||
| `pnpm db:seed` | 写入种子数据 |
|
||||
| `pnpm db:reset` | 重置数据库并重新执行 seed |
|
||||
| `pnpm db:studio` | 打开 Prisma Studio |
|
||||
| `pnpm db:switch:mysql` / `db:switch:sqlite` | 切换数据库 provider |
|
||||
| 命令 | 说明 |
|
||||
| ------------------------------------------- | ------------------------------------------------------------------------- |
|
||||
| `pnpm dev` | 并行启动 shared(tsc watch) + 后端 + Web 端 |
|
||||
| `pnpm dev:server` / `pnpm dev:web` | 只启动后端 / 只启动 Web 端 |
|
||||
| `pnpm dev:desktop` | 启动 EXE 客户端开发模式(Vite 5174 + Electron,热更新) |
|
||||
| `pnpm build` | 构建 shared + 后端 + Web 端 + EXE 客户端 |
|
||||
| `pnpm build:desktop` | 仅构建 EXE 客户端(esbuild 主进程/preload + Vite 渲染进程) |
|
||||
| `pnpm icons` | 生成应用图标(PNG/ICO,用 Electron 渲染 SVG) |
|
||||
| **`pnpm dist:server`** | **打包服务端 + Web 管理端**(免安装目录 + NSIS 安装程序,内置 Node) |
|
||||
| `pnpm dist:dir` | 打包客户端免安装目录 `release/win-unpacked`(含可执行文件,最快) |
|
||||
| `pnpm dist:win` | 打包客户端 nsis 安装包 + portable 单文件 EXE |
|
||||
| `pnpm dist:all` | 服务端安装程序 + 客户端安装程序一起打 |
|
||||
| `pnpm verify:e2e` | 后端端到端验收(62 项,需服务端已启动) |
|
||||
| `pnpm verify:web` | Web 管理端 UI 真实点击测试(Electron 驱动,8 项) |
|
||||
| `pnpm verify:desktop` | EXE 客户端冒烟验证(19 项,含灵动岛像素级截图校验、侧边栏点击与离线回退) |
|
||||
| `pnpm typecheck` | 全仓库类型检查(含 `vue-tsc`) |
|
||||
| `pnpm lint` / `pnpm lint:fix` | ESLint 检查 / 自动修复 |
|
||||
| `pnpm format` / `pnpm format:check` | Prettier 格式化 / 检查 |
|
||||
| `pnpm db:generate` | 生成 Prisma Client(输出到 `packages/server/src/generated/prisma`) |
|
||||
| `pnpm db:migrate` | 创建并应用迁移 |
|
||||
| `pnpm db:seed` | 写入种子数据 |
|
||||
| `pnpm db:reset` | 重置数据库并重新执行 seed |
|
||||
| `pnpm db:studio` | 打开 Prisma Studio |
|
||||
| `pnpm db:switch:mysql` / `db:switch:sqlite` | 切换数据库 provider |
|
||||
|
||||
## EXE 客户端(学生端)
|
||||
|
||||
@@ -268,12 +268,26 @@ pnpm verify:desktop # Electron 客户端(含灵动岛与联网集成)
|
||||
| 退出/断开 | 主窗口退出时灵动岛一并关闭;上课状态来自 `GET /api/schedules/current`(10 秒心跳 + 下课时长定时器) |
|
||||
|
||||
- 动画:窗口尺寸用 `easeOutCubic` 260ms 逐帧缓动(胶囊 ↔ 详情 形变),透明度单独淡入淡出;
|
||||
两套动画使用**独立令牌**,互不打断(早前"淡入取消形变导致窗口卡在胶囊尺寸"的问题已修复)。
|
||||
卡片内部再用 `cubic-bezier(0.34, 1.56, 0.64, 1)`(弹簧回弹)做入场与点击反馈,
|
||||
紧急形态的红色光晕由独立的 `.glow` 层以 `urgent-breath` 无限呼吸,未读点用 `dot-pulse`。
|
||||
两套窗口动画使用**独立令牌**,互不打断(早前"淡入取消形变导致窗口卡在胶囊尺寸"的问题已修复)。
|
||||
- 事件流:`notification:new` → `renderer/stores/realtime.ts` → `pushNotificationToIsland()` →
|
||||
主进程 `IslandController`(决定隐藏/胶囊/详情)→ 灵动岛渲染进程 `src/island/IslandApp.vue`。
|
||||
- 相关文件:`src/main/island.ts`(控制器 + IPC)、`src/preload/island.ts`、`src/island/IslandApp.vue`、
|
||||
`src/renderer/island/bridge.ts`(上课状态轮询与通知转发)。
|
||||
|
||||
各形态实拍(由 `pnpm verify:desktop` 自动截取并归档到 `docs/screenshots/island/`,并做像素级校验):
|
||||
|
||||
| 形态 | 截图 | 尺寸(逻辑 / 截图) | 说明 |
|
||||
| ---------------------- | ------------------------------------------------------------------- | ------------------- | ----------------------------------------- |
|
||||
| 下课后自动弹出详情 |  | 404×316 / 808×632 | 上课期间暂存的通知,下课后自动弹出 |
|
||||
| 上课期间紧急通知 |  | 424×344 / 848×688 | 红色光晕 + 紧急角标,无需点击 |
|
||||
| 非上课时段"新消息"胶囊 |  | 268×44 / 536×88 | 点击后展开详情 |
|
||||
| 点击胶囊后的详情 |  | 404×316 / 808×632 | 标题/内容/时间 + 打开应用/标为已读/知道了 |
|
||||
|
||||
> 截图路径可用 `ISLAND_SHOTS_DIR` 覆盖(默认 `.cache/island-shots/`);
|
||||
> 归档目录里的图就是打包后 EXE 跑自动化验证时产出的同一份文件。
|
||||
|
||||
### 离线缓存与自动同步
|
||||
|
||||
```
|
||||
@@ -313,25 +327,27 @@ pnpm dist:win # nsis 安装包 + portable 单文件(需联网下载 NSIS
|
||||
|
||||
`pnpm verify:desktop` 以 `ELECTRON_SMOKE_TEST=1` 启动应用(不弹窗),主进程依次校验后自动退出:
|
||||
|
||||
| 校验项 | 实测结果 |
|
||||
| -------------------------------------- | ---------------------------------------------------------------------------------- |
|
||||
| 渲染进程挂载 + 窗口标题 | ✅ `children=1` / `title=班级小助手` |
|
||||
| 登录页渲染(三个输入框) | ✅ 服务器地址 / 用户名 / 密码 |
|
||||
| preload contextBridge 注入 | ✅ 9 个方法(含灵动岛 3 个) |
|
||||
| IPC 往返(getAppInfo/saveConfig) | ✅ Electron 44.3.0 |
|
||||
| 配置文件写入用户目录 | ✅ `%APPDATA%\@classhelper\desktop-client\config.json` |
|
||||
| IndexedDB 缓存读写 | ✅ 读写/统计/删除 + 6 个 store |
|
||||
| 断网时回退本地缓存 | ✅ `fromCache=true`(请求不可达端口) |
|
||||
| 灵动岛窗口创建(置顶/透明/不占任务栏) | ✅ `ready=true` |
|
||||
| 上课期间普通通知自动隐藏(暂存) | ✅ `mode=hidden queued=1` |
|
||||
| 下课后自动弹出暂存通知详情 | ✅ `mode=expanded reason=after-class` |
|
||||
| 上课期间紧急通知立即展开(无需点击) | ✅ `mode=expanded reason=urgent` |
|
||||
| 胶囊 → 点击 → 展开详情 | ✅ `新消息 · 共 2 条` → `expanded`(含真实 DOM 断言与截图) |
|
||||
| 联网集成(`ELECTRON_SMOKE_ONLINE=1`) | ✅ 登录王小明 / 1 班级 / 6 作业 / 9 通知 / 8 成绩 / 第1周30节课 / Socket.IO 已连接 |
|
||||
| 校验项 | 实测结果 |
|
||||
| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| 渲染进程挂载 + 窗口标题 | ✅ `children=1` / `title=班级小助手` |
|
||||
| 登录页渲染(三个输入框) | ✅ 服务器地址 / 用户名 / 密码 |
|
||||
| preload contextBridge 注入 | ✅ 9 个方法(含灵动岛 3 个) |
|
||||
| IPC 往返(getAppInfo/saveConfig) | ✅ Electron 44.3.0 |
|
||||
| 配置文件写入用户目录 | ✅ `%APPDATA%\@classhelper\desktop-client\config.json` |
|
||||
| IndexedDB 缓存读写 | ✅ 读写/统计/删除 + 6 个 store |
|
||||
| 断网时回退本地缓存 | ✅ `fromCache=true`(请求不可达端口) |
|
||||
| 灵动岛窗口创建(置顶/透明/不占任务栏) | ✅ `ready=true` |
|
||||
| 上课期间普通通知自动隐藏(暂存) | ✅ `mode=hidden queued=1` |
|
||||
| 下课后自动弹出暂存通知详情 | ✅ `mode=expanded reason=after-class` |
|
||||
| 上课期间紧急通知立即展开(无需点击) | ✅ `mode=expanded reason=urgent` |
|
||||
| 胶囊 → 点击 → 展开详情 | ✅ `新消息 · 共 2 条` → `expanded`(含真实 DOM 断言与截图) |
|
||||
| **灵动岛截图留档 + 像素级校验** | ✅ 4 张(808×632 / 848×688 / 536×88 / 808×632);宽高比与状态机配置偏差 **0.000**;胶囊态偏红 205 px、紧急态偏红 **20473 px**(红色光晕);形态尺寸递增 pill < expanded < urgent |
|
||||
| 联网集成(`ELECTRON_SMOKE_ONLINE=1`) | ✅ 登录王小明 / 1 班级 / 6 作业 / 9 通知 / 8 成绩 / 第1周30节课 / Socket.IO 已连接 |
|
||||
|
||||
该验证对**开发产物与打包后的 EXE 都适用**(打包后用 `ELECTRON_SMOKE_RESULT=<file>` 写出 JSON 结果,
|
||||
已实测 `packaged: true`、18/18 通过、退出码 0)。灵动岛各状态的窗口截图会写到
|
||||
`ISLAND_SHOTS_DIR`(默认 `.cache/island-shots/`),便于人工确认视觉效果。
|
||||
已实测 `packaged: true`、16/16 通过、退出码 0)。灵动岛各状态的窗口截图会写到
|
||||
`ISLAND_SHOTS_DIR`(默认 `.cache/island-shots/`,仓库内留档目录 `docs/screenshots/island/`),
|
||||
并对尺寸、宽高比、绘制内容(不透明像素/颜色种类)与紧急态红色像素做断言。
|
||||
|
||||
## 上课时段策略(紧急通知二次确认)
|
||||
|
||||
@@ -504,20 +520,20 @@ pnpm db:migrate && pnpm db:seed
|
||||
| 产物 | 大小 | 冒烟结果 |
|
||||
| -------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------ |
|
||||
| 服务端安装程序(内置 Node + Web 端) | 34MB | ✅ 静默安装(升级保留 `.env` 与数据库)→ 自动建库建号 → 服务就绪 → **对安装实例跑 62/62 e2e + 8/8 UI** |
|
||||
| `release/win-unpacked/班级小助手.exe` | 234.7MB | ✅ 18/18,`packaged: true`,退出码 0 |
|
||||
| `release/win-unpacked/班级小助手.exe` | 234.7MB | ✅ 16/16,`packaged: true`,退出码 0 |
|
||||
| `release/…-x64-portable.exe`(单文件) | ~107MB | ✅(含联网集成:登录王小明 / Socket.IO 已连接 / 四类数据) |
|
||||
| `release/…-x64-setup.exe`(客户端) | ~107MB | ✅ 构建成功,已嵌入自定义图标;包含灵动岛 |
|
||||
|
||||
当前实测:
|
||||
|
||||
| 验证 | 结果 |
|
||||
| ------------------------------------------------------------------------ | ----------------------------------- |
|
||||
| `pnpm verify:e2e`(开发环境与**安装后的生产实例**各跑一次) | **62/62** ✅ |
|
||||
| `pnpm verify:web`(Web 管理端真实点击 + 上课时段紧急通知 + PWA) | **8/8** ✅ |
|
||||
| `pnpm verify:desktop`(客户端冒烟 + 灵动岛四态 + 侧边栏点击 + 离线回退) | **18/18** ✅ |
|
||||
| `pnpm typecheck` / `pnpm lint` / `pnpm format:check` | 全部通过 ✅ |
|
||||
| 安装程序完整生命周期(静默安装 → 启停脚本 → 卸载) | 通过 ✅ |
|
||||
| Docker / Nginx 部署样例 | 文件已提供,本机无 Docker 未实测 ⚠️ |
|
||||
| 验证 | 结果 |
|
||||
| ---------------------------------------------------------------------------- | ----------------------------------- |
|
||||
| `pnpm verify:e2e`(开发环境与**安装后的生产实例**各跑一次) | **62/62** ✅ |
|
||||
| `pnpm verify:web`(Web 管理端真实点击 + 上课时段紧急通知 + PWA) | **8/8** ✅ |
|
||||
| `pnpm verify:desktop`(客户端冒烟 + 灵动岛四态 + 像素级截图校验 + 离线回退) | **19/19** ✅ |
|
||||
| `pnpm typecheck` / `pnpm lint` / `pnpm format:check` | 全部通过 ✅ |
|
||||
| 安装程序完整生命周期(静默安装 → 启停脚本 → 卸载) | 通过 ✅ |
|
||||
| Docker / Nginx 部署样例 | 文件已提供,本机无 Docker 未实测 ⚠️ |
|
||||
|
||||
## 常见问题(本机环境已知坑)
|
||||
|
||||
@@ -614,6 +630,7 @@ pnpm db:migrate && pnpm db:seed
|
||||
| `packages/web-admin/src/components/UrgentClassWarning.vue` | 上课时段发布紧急通知的全屏二次确认(3 秒倒计时) |
|
||||
| `scripts/ui-smoke/live-probe.mjs` | UI 回归测试的"真实上课时段"探针(自建课表 + 用后清理) |
|
||||
| `scripts/lib/{electron-env,node-runtime}.mjs` | Electron/Node 运行时定位与宿主环境兼容处理 |
|
||||
| `docs/screenshots/island/*.png` | 灵动岛四种形态的自动化留档截图(由冒烟验证生成,含像素级断言) |
|
||||
|
||||
## 后续可选增强
|
||||
|
||||
|
||||
Reference in new issue
Block a user