## 11. 兼容性、性能、平台与测试基线 > 本部分规定「重构不能把原来能用的东西弄坏」,以及如何在不打扰用户的前提下验证。所有验证默认必须无头/离屏执行。 ### 11.1 兼容矩阵(必须逐项通过) | 维度 | 必须保持兼容的内容 | 验证方式 | |---|---|---| | 配置 | 旧 `config.json.islandLayout`(`fixed`/`custom`、`residentEnabled`、`schemes`/`rows`/`nodes`/`expandedRows`/`appearance`/`lessonReminders`/`pointerFade*`)无损升级 | 迁移单测 + fixtures 回放 | | 布局模式 | `fixed` 与 `custom` 均可切换、可保存、可重启恢复;两布局共用一个原生岛窗口,切布局不新开窗口 | 无头集成测试 + 主进程单测 | | 风格 | `family` 只影响 fixed:`winisland` 保持旧胶囊观感,`classisland` 为默认信息行;`custom` 始终 ClassIsland 规格;切换即时生效、可回退 | 截图(仅 `--visual`)+ 视觉回归 | | 消息 | 通知/作业/叫人的类型、优先级、id 去重、排序、上课暂存、紧急展开、叫人可点胶囊、已读回执、安静模式、教师/班级端差异不变 | 状态机单测 + 无头消息场景 | | 课程 | 课表解析结果(`ScheduleDto`/`IslandTimePointDto`)、准备/上课/课间/下课前/课中进度提醒、下课前秒数徽标、当前/下一节/今日时间点显示;**行为变更**:custom 不再临时接管岛显示课程提醒(仅保留 ending 徽标,进度由课程组件显示),fixed 按 ClassIsland 接管 | 时间状态机单测 + 假时钟无头场景 | | 天气 | Open-Meteo 数据、15 分钟刷新、断网缓存标记"缓存"、无官方预警提示 | 无头 mock 网络 + 快照 | | 课件 | 课件传输状态优先覆盖岛内容、SHA256 校验、回执、不自动运行文件 | 无头课件场景 | | 编辑器 | 方案/行/组件/导入导出/预览/重置/新建/复制/删除、12 行/200 节点/6 层/20 方案边界 | 单测 + 组件测试 | | 窗口/输入 | 透明、置顶、不占任务栏、点击穿透、触摸模式、失焦宽限、固定几何护栏、单实例 | 无头窗口参数断言 + 手工触摸说明 | | 平台 | Windows 10/11(主目标)、macOS、Linux X11;DPI 100/125/150/200;多显示器与热插拔 | 平台矩阵 + 无头几何断言 | | 性能 | 启动、空闲 CPU、内存、消息风暴、动画帧率 | 性能脚本 + 采样 | ### 11.2 配置迁移与回滚(硬要求) 1. **版本化**:`IslandLayoutSettings.version` 从 `1`(旧配置缺失视为 1)升级到 `2`;迁移函数必须**幂等**(重复执行结果一致)。 2. **迁移顺序**:读取原始 JSON → 备份到 `config.json.bak.<时间戳>`(或配置目录 `backups/`)→ 应用迁移(只补齐/转换,不删除用户数据)→ `normalizeIslandLayouts()` 校验与夹取 → 原子写(临时文件 + rename)。 3. **必须迁移的字段**: - 顶层新增 `version`、`appearance.family`(老用户默认 `'winisland'`,新安装 `'classisland'`)、`appearance.theme`(`'fluent'`/`'classic'`)、`strongNotification` 开关与参数、`progressBar` 参数、`rowStyle`(行背景/分隔/圆角覆盖); - scheme 新增 `rowHeight`(默认 40)、`componentGap`(默认 12,对应单侧 6)、`showProgress`(默认 true)、`hideRules` 扩展(保留旧 `in-class`/`no-message`/`no-class`,新增 `full-screen`/`max-window` 需按 12 部分验收); - 组件新增字段(如 schedule 的 `display` 扩展、countdown 的 `showProgress`、clock 的 `showSeconds`),旧值必须原样保留。 4. **回滚**:迁移失败或新版启动检测到配置不可用时,必须能恢复备份并启动旧结构(主进程启动早期读 `config.json` 的 `islandLayout` 失败时使用默认值 + 保留原文件为 `.corrupt`),不得清空用户方案。 5. **降级兼容**:若旧版本客户端读到新配置,必须忽略未知字段并使用默认值;禁止因未知字段崩溃。版本号高于当前可识别值时,主进程写日志并走只读模式(不自动覆盖新配置)。 6. **fixtures**:`packages/shared` 测试中必须包含:fixed 默认、custom 多方案/多行/嵌套容器/旧 residentEnabled、极端值(超 12 行/200 节点/6 层/颜色非法/坐标为 null)、旧字段缺失、迁移幂等、迁移失败回滚。 ### 11.3 IPC 与契约兼容 - 保留现有通道:`island:get-schedules`、`island:get-time-points`、`island:get-layout`、`island:save-layout`、`island:edit-layout`、`island:get-editing`、`island:get-visible`、`island:resident-control`、`island:resident-touch`、`island:set-editing`、`island:content-size`、`island:remove-notification`、`island:push`、`island:class-state`、`island:alive`、`island:get-state`、`island:set-appearance`、`island:get-appearance`、`island:set-interactive`、`island:set-hit-rect`、`island:set-touch-mode`、`island:action`。 - 新增通道必须遵守:`ipcMain.handle/on` 前校验 `event.sender === island.getWindow()?.webContents`(或主窗口 webContents),payload 必须是纯数据且做类型/范围校验;preload 白名单同步更新 `src/preload/island.ts` 与 `src/types/desktop.d.ts`。 - 新增通道建议(如需要):`island:strong-notification`(主进程→岛/强提醒窗口)、`island:get-metrics`(渲染层上报行/组件度量)、`island:preview-mode`(编辑器预览)。不得把 Vue Proxy/函数/类实例跨 contextBridge 传递。 - 渲染进程心跳、幽灵窗口检测、渲染崩溃自愈(限流 3 次/10 分钟)与恢复逻辑保持不变。 ### 11.4 性能预算(超预算必须优化) - 岛渲染进程启动 ≤ 500ms(从窗口创建到首帧可见);冷启动到岛可见 ≤ 3s(不含网络)。 - 空闲 CPU 平均 ≤ 1%(岛可见、时钟/课程正常刷新);消息到达/展开瞬间峰值 ≤ 15% 且 ≤ 500ms。 - 主进程 + 岛渲染进程内存 ≤ 250MB(不含可选强提醒窗口);连续运行 24h 增长 ≤ 10%。 - 消息风暴:1 分钟 20 条不丢、不重复、不卡顿;队列长度上限与丢弃策略必须有日志。 - 动画:主界面过渡 ≥ 55fps;消息气泡/强提醒 ≥ 50fps;不得因背景页(主窗口隐藏)继续动画。 - 包体:本次重构不得新增 > 200KB 的运行时依赖;不得引入新 UI 库/图标库(图标仍用现有方案)。 ### 11.5 平台差异与窗口护栏 - Windows:透明/置顶/点击穿透/`setShape`(若用)只在 Windows 分支;Windows 10 不支持 Mica 时退回纯色;高 DPI 下窗口 bounds 用 DIP。 - macOS:透明窗口、置顶、全屏空间行为;不使用 `setBackgroundMaterial`;点击穿透退化为整窗 `setIgnoreMouseEvents(true,{forward:true})` + 命中通道。 - Linux X11:透明窗口与置顶可用;Wayland 明确不支持并给提示(与 ClassHelper 既有说明一致)。 - 多显示器:`position`/`followCursorDisplay`/停靠偏移语义保持不变;显示器热插拔/DPI 变化必须重算包围盒与锚点,节流 ≥100ms。 - 触摸:触摸模式仍以"窗口贴合岛体 + 始终接收输入"为原则;编辑模式与触摸手势不能互相抢占;失焦宽限(鼠标 500ms / 触摸 1200ms)保持不变。 - 强提醒窗口:无边框、置顶、不抢焦点、`skipTaskbar`、独立渲染入口或复用岛窗口的独立层;关闭后释放;不得在编辑器/预览中创建。 ### 11.6 测试基线(无头优先) 1. **单元测试(shared)**:`normalizeIslandLayouts` 边界、迁移幂等、版本识别、颜色/数值夹取、组件树限制(12 行/200 节点/6 层/20 方案)、消息排序/去重、课程状态机(准备/上课/课间/下课前/放学/跨天/跨周)。 2. **主进程测试**:窗口几何计算(6 停靠 × DPI × 多屏)、hit rect/触摸模式切换、消息队列与暂存、课程提醒调度、天气缓存、课件覆盖优先级、配置写入原子性与回滚。 3. **组件测试**:固定数据下 `IslandApp.vue`/`CustomIslandRuntime.vue` 的渲染快照(DOM 结构 + 关键 computed 样式),不创建真实窗口(可用 happy-dom/离屏渲染)。 4. **集成(无头)**:`pnpm verify:desktop` 默认后台快速检查——不得创建可见岛/托盘;覆盖启动、布局切换、消息推送、课程提醒、编辑器保存/读取、迁移。 5. **视觉(显式)**:只有 `pnpm verify:desktop:visual` / `--visual` 才允许真实桌面、动画采样、截图;截图输出目录用临时路径;不得把窗口对照图发布为展示图。 6. **数据纪律**:测试使用临时 SQLite/夹具,禁止使用真实班级、真实密码、真实通知;远控/安装器使用假执行器。 7. **证据**:每次汇报附实际命令输出摘要(通过/失败数量),不得沿用历史数字。 ### 11.7 观测与诊断 - 主进程日志必须记录:配置迁移(旧→新字段、备份路径、结果)、窗口几何重算原因、消息队列变化(入队/出队/丢弃/去重)、课程状态切换、天气刷新/失败、强提醒创建/销毁、渲染崩溃/重建(限流计数)。 - 岛渲染进程必须上报心跳与度量(行/组件尺寸、可见性);主进程对"幽灵窗口"(渲染卡死但窗口在)执行重建(限流)。 - 诊断页/日志中不得包含用户密码、令牌、完整数据库路径;日志轮转与大小上限沿用现有 logger。 - 提供 `docs/dev/island-refactor.md` 的排障章节:黑屏/透明失效/点击穿透/闪烁/动画卡顿/消息不弹/课程不刷新/迁移失败的症状 → 排查步骤 → 回滚方法。 ### 11.8 文档与交付说明 - 更新 `docs/app/island.md`:新默认观感、风格切换、editor 编辑模式、强提醒、行为表(含 fixed 重定义)。 - 更新 `docs/dev/implementation.md`:岛的新架构入口、schema v2、迁移函数位置。 - 新增 `docs/dev/island-refactor.md`:架构图、文件职责、数据契约、动画表、迁移与回滚、测试命令。 - `docs/` 中的展示截图必须来自显式视觉验收且人工确认;不得使用重构中的对照图/失败截图。 - 交付说明必须包含:与 ClassIsland 的差异清单(技术栈/能力取舍)、未实现项及原因、性能数据、回滚步骤。 ### 11.9 本部分验收标准 - [ ] fixtures 覆盖 11.2 全部场景,迁移全部通过且幂等。 - [ ] 旧配置在重构版启动后方案、组件、外观、课程提醒开关全部保留,且可切回 `winisland` 观感。 - [ ] 所有既有 IPC 通道仍可用,新增通道有 sender 校验与类型校验。 - [ ] `pnpm verify:desktop` 无参数运行时**不创建可见岛/托盘/声音**;`--visual` 才创建。 - [ ] 多显示器/DPI 切换后岛位置与尺寸正确,无 1px 抖动。 - [ ] 24h 无内存增长 > 10%、无崩溃、无幽灵窗口。 - [ ] 文档更新完成,含迁移/回滚/差异说明。