# refactor-messages(Round 2 · Part 03/08)分析备注 负责人:features。产出:`parts-r/03-classisland-baseline.md`、`parts-r/08-messages-lessons.md`。 本文件记录:已读文件清单、口径与默认值表、裁决落点、未决问题。全部为静态阅读,未构建/运行/启动 Electron/截图,未修改 `repos/`。 ## 0. 口径(Lead 最新补充,已落到文档) - 默认风格 `appearance.family='classisland'`:`fixed` **重定义为 ClassIsland 风格信息行**(默认 1 行 = 日期 + 课程表;行高 40、圆角 8、背景不透明度 0.5、底部 3px 进度条;消息到来在同一行内展开 ClassIsland 气泡,保留 ClassHelper 暂存/紧急/叫人/已读/去重规则)。 - `family='winisland'`:保留原「胶囊 + 详情卡」形态;**老用户升级默认 winisland,新安装默认 classisland**。 - `custom`:保留 schemes/rows/nodes 模型,按 ClassIsland 行/组件/编辑/隐藏/动画规格重构。 - 落盘字段名以 `parts-r/05` 为准;本文档统一写作 `appearance.family`(配置键 `islandAppearance.style`)。 ## 1. 已读文件清单 ### 1.1 ClassHelper 文档 | 文件 | 关键内容 | |---|---| | `repos/ClassHelper-master/docs/app/island.md`(79 行) | 两种模式展示矩阵(8-24)、编辑自定义方案(36-48)、外观/位置/输入(50-59)、课程与课件(61-73)、验证纪律(75-79) | | `repos/ClassHelper-master/docs/app/notifications.md`(50 行) | 优先级四档(13-14)、两模式展示表(16-22)、紧急 45s 收起(23)、课堂紧急通知服务端 409(25-29)、已读/撤回(31-35)、接口表(37-49) | | `repos/ClassHelper-master/docs/app/courseware.md`(46 行) | 512MB 上限、可见范围/推送、客户端自动下载与 SHA256 回执、断网缓存、归档路径、服务端归档 | | `repos/ClassHelper-master/docs/dev/winisland-design-tokens.md`(59 行) | 经典几何(268×44、圆角 20、字号 13、边距 8)、`CLASSISLAND_ISLAND_METRICS` 汇总(30-42)、弹簧参数(46-47)、命中与触摸(51-53) | ### 1.2 shared 契约与常量 | 文件 | 关键内容 | |---|---| | `packages/shared/src/types.ts` | `NotificationPriority`(30)、`ScheduleDto`(545-564)、`IslandMode`(1103)、`IslandNotificationKind`(1111)、`IslandLessonReminder`(1114-1128)、`IslandNotification`(1131-1143)、`IslandAppearance`(1146-1188)、`IslandState`(1198-1230) | | `packages/shared/src/constants.ts` | `PRIORITY_LABELS/TAG_TYPES/RANK`(181-208)、`DEFAULT_ISLAND_APPEARANCE`(265-290)、`ISLAND_APPEARANCE_RANGES`(293-302)、`ISLAND_POSITIONS`(305-312)、`ISLAND_SLIVER_WIDTH=6`(336)、`ISLAND_SIZE_DELTA`(344-348)、`ISLAND_SHADOW_PAD=10`(351)、`ISLAND_TYPE_SCALE`(354-367)、`ISLAND_LIST_METRICS`(379-402)、`IslandListLayout`(405-412)、`islandListLayout()`(445-474)、`CLASSISLAND_TIME_TYPES`(513-518)、`buildCallTitle`(571-575) | | `packages/shared/src/island-layout.ts` | `ISLAND_COMPONENTS`(3-18)、`CLASSISLAND_ISLAND_METRICS`(20-36)、`IslandWeather`(38-44)、`IslandComponentNode/Scheme/Settings`(61-139)、`LessonReminderSettings` + `DEFAULT_LESSON_REMINDERS`(141-158)、`defaultIslandLayouts()`(217-255)、`normalizeIslandLayouts()`(256-404,行 12/节点 200/深度 6/方案 20 上限) | | `packages/shared/src/class-plan.ts` | `TimePointType`(4-5)、`TimePointDto`(6-21)、`ClassPlanDto`(39-54)、`ActiveClassPlanDto`(55-63)、`IslandTimePointDto`(76-87) | | `packages/shared/src/courseware.ts` | `COURSEWARE_MAX_BYTES`(2)、`COURSEWARE_TRANSFER_TIMEOUT_MS`(3)、`COURSEWARE_ISLAND_SIZE=424×132`(4)、分类与 `coursewareCategory`(5-27)、`CoursewareTransfer`(82-94) | | `packages/shared/src/motion.ts` | `EASE_OUT (0.16,1,0.3,1)`(24)、`EASE_IN_OUT (0.77,0,0.175,1)`(26)、`EASE_DRAWER (0.32,0.72,0,1)`(28)、SPRING 系列(48-58)、`--ch-*` 注入(211-238) | ### 1.3 主进程与渲染进程 | 文件 | 关键内容 | |---|---| | `packages/desktop-client/src/main/island.ts`(2445 行) | 尺寸常量(81-112)、`CLOSE_ANIMATION_MS=360`(121)、`TIMEOUTS`(124-132)、`pushNotification`(794-867)、`setClassState`(870-915)、`flushQueueAfterClass`(917-927)、`handleAction`(929-1077)、`hide/beginClose/finishClose`(1079-1192)、`removeNotification`(1210)、`activate/scheduleCollapse`(1248-1296)、`isImmediate/isOpenable`(689-702)、`mergeNotification`(713-724)、`pendingNotifications`(738-749)、`listLayout`(755-765)、`refreshViewport`(774-785)、`lessonShowing`(173-185)、`refreshLessonReminder`(192-212)、`coursewareShowing`(667-676)、`BLUR_GRACE_MS=500`/`BLUR_GRACE_TOUCH_MS=1200`(2287-2297)、`PREVIEW_DURATION_MS=30_000`(2300)、`MIN_CARD_HEIGHT=120`(2306)、心跳/重建(2315-2318) | | `packages/desktop-client/src/main/lesson-reminder.ts`(110 行) | 五类提醒判定顺序、5s/12s 窗口、maskUntil/endsAt 公式、id/entered | | `packages/desktop-client/src/main/island-weather.ts`(73 行) | Open-Meteo 固定参数、坐标校验、15min 缓存、60s 退避、8s 超时、64KB 上限、32 条缓存、stale | | `packages/desktop-client/src/main/ipc.ts` | `island:weather` IPC 入口(23) | | `packages/desktop-client/src/island/IslandApp.vue`(683 行) | 状态/胶囊摘要(66-157)、尺寸目标(188-200)、`isClosing`(73-80)、命中上报与穿透(402-516)、外观 CSS 变量(518-529)、模板层叠(573-681) | | `packages/desktop-client/src/island/ClassicNotifications.vue`(234 行) | 排序/列表/尺寸(21-58)、类型徽标(59-83)、列表渲染(162-208)、按钮行(219-231) | | `packages/desktop-client/src/island/LessonReminderContent.vue`(318 行) | 文案与倒计时(13-58)、斜切遮罩多边形/时序(59-102)、模板(126-193)、样式(195-317) | | `packages/desktop-client/src/island/lesson-ending.css`(16 行) | 蓝色秒数徽标 30×30/#0a84ff/12px | | `packages/desktop-client/src/island/CoursewareTransfer.vue`(132 行) | 424×132 定位、四阶段文案、元信息与进度条、样式 | | `packages/desktop-client/src/island/WeatherBrief.vue`(91 行) | 60s 轮询、坐标变化刷新、WMO 文案、建议、缓存标记 | | `packages/desktop-client/src/island/classic-island.css`(757 行) | token(49-90)、连续圆角+1px 描边+常驻投影(102-124)、胶囊固定内容盒(196-216)、收回不显示内容(226-232)、状态色(155-185) | | `packages/desktop-client/src/renderer/stores/notifications.ts`(148 行) | 未读计数、推送去重(87-93)、已读/全部已读(102-122)、缓存隔离 | ### 1.4 ClassIsland 侧(复用上一轮 parts 与源码) - `parts/04-main-window.md`:行模型/模板/几何/可见性/鼠标淡出/分体/隐藏规则/编辑模式/抽屉/动画表(本文 §3.1、3.3、3.4、3.5、3.9 来源)。 - `parts/05-components.md`:11 类组件与课程表组件行为、6 种附加信息、倒计时药丸、进度条 3px、空态与明天课表(本文 §3.2、3.7 来源)。 - `parts/07-notifications.md`(本人上一轮产出):队列/优先级/两阶段/强提醒/音效(本文 §3.8、3.9 来源)。 - `parts/10-settings.md`、`parts/11-other-windows.md`:设置页与窗口行为(本文仅引用术语与入口,不展开)。 - `parts/14-animations.md`:动画别名表/时长常量/A 组岛动效/B 组提醒动效/F 组 ClassHelper 既有动效(本文 §3.12、§8.4.3 来源)。 - ClassIsland 源码(上一轮已读,本文直接引用行号):`Services/LessonsService.cs`、`Services/NotificationHostService.cs`、`Shared/Models/Notification/NotificationPriority.cs`、`Controls/MainWindowLine.axaml(.cs)`、`XamlThemes/FluentTheme/Styles.axaml`、`Controls/SlantedMaskControl.cs`、`Views/TopmostEffectWindow.axaml.cs`、`Controls/NotificationEffects/RippleEffect.axaml.cs`、`Models/Settings.cs`、`Controls/Components/*`、`Controls/LessonsControls/*`、`ClassIsland.Core/Controls/HighlightBox.axaml`。 ## 2. 关键默认值与参数表(交叉校验用) ### 2.1 ClassIsland 基准(Part 03 采用) | 项 | 值 | 来源 | |---|---|---| | 行高 | 40 | `MainWindowLine.axaml:16` | | 行内容内边距 / 最小宽 | 12 / 20 | `FluentTheme/Styles.axaml:110` | | 行间距 | 5(0–150) | `Settings.cs:219` | | 圆角 | 8(0–20) | `Settings.cs:183-184` | | 背景不透明度 | 0.5 | `Settings.cs:64` | | 行不透明度 | 1.0(0.1–1) | `MainWindowLine.axaml:51` | | 字号 | 14/16/18/20 | `Settings.cs:197-200` | | 指针淡出 | 0.05;默认开、不反转 | `Settings.cs:193-194` | | 隐藏三开关 | 全 false | `Settings.cs:45,54,63` | | 排除进程 | `["explorer"]` | `Settings.cs:56-59` | | 遮罩斜切 | 5 区段、360ms、错峰 120ms、60° | `SlantedMaskControl.cs:284,298-308`;`Styles.axaml:175-180` | | 遮罩文字 | 260/250ms、scale 1.1→1 / 750ms | `Styles.axaml:329-352` | | 遮罩退出 | 200ms、scale 1→1.1、`(0.5,0,0.75,0)` | `Styles.axaml:376-398` | | 正文淡入淡出 | 200ms SineEaseIn | `Styles.axaml:419-451` | | 进度条 | 3px、50ms 线性 | `Styles.axaml:137-145` | | 强提醒涟漪 | 600ms 扩散 + 600ms 淡出 + 750ms 移除 | `RippleEffect.axaml.cs:86-109` | | 特效缩放默认 | 1.0 | `Settings.cs:150` | | 行宽过渡 | Fluent 300ms `(0.65,0,0.35,1)` / Classic 550ms `(0,1,0.5,1.1)` | `FluentTheme/Styles.axaml:269`;`ClassicTheme/Styles.axaml:207` | | 课程表设置默认 | 见 Part 03 §3.7.5 | `LessonControlSettings.cs:8-23` | ### 2.2 ClassHelper 既有(Part 08 保留) | 项 | 值 | 来源 | |---|---|---| | 优先级 | LOW/NORMAL/HIGH/URGENT + RANK 0/1/2/3 | `types.ts:30`;`constants.ts:203-208` | | 超时 | pill 15s / afterClass 14s·25s / expanded 20s / urgent 45s / call 90s | `island.ts:124-132` | | 收回动画 | 360ms(随 speed) | `island.ts:121` | | 失焦宽限 | 鼠标 500ms / 触摸 1200ms | `island.ts:2287,2297` | | 预览 | 30s | `island.ts:2300` | | 列表度量 | 前 3 条、最多 20 行、`safetyPad 6`、行高 2.7×fontSize | `constants.ts:379-402` | | 尺寸增量 | expanded +156×186、urgent +172×202、call +188×218 | `constants.ts:344-348` | | 阴影留白 | 10 | `constants.ts:351` | | 细缝宽 | 6 | `constants.ts:336` | | 课程提醒 | 五类、5s/12s 窗口、prepare 60s、ending 60s(5–600) | `lesson-reminder.ts:38-72`;`island-layout.ts:150-158` | | 课程提醒条 | 40 高、min300/max800、圆角 8、bg #20202080、进度 2px | `LessonReminderContent.vue:196-317` | | 徽标 | 30×30 圆、#0a84ff、12px/600、`-N` | `lesson-ending.css:2-16` | | 天气 | Open-Meteo、15min 缓存、60s 退避、8s 超时、64KB、32 条 | `island-weather.ts:35-68` | | 课件卡 | 424×132、圆角 24、padding 17 24、进度 5px | `courseware.ts:4`;`CoursewareTransfer.vue:68-131` | | 弹簧 | stiffness 0.10 / damping 0.68 / 动量 35% / 单帧 ≤20% / snap 0.05 | `spring.ts`(Round1 brief §4 与 `parts/14` F1-F3) | ## 3. 裁决落点(写进文档的确定规则) 1. **fixed 形态重定义**:默认 `family='classisland'` 下 fixed = ClassIsland 信息行(日期+课程表、行高 40、圆角 8、背景 0.5、3px 进度条),气泡行内两阶段;`winisland` 保留胶囊+详情卡;升级/新装默认值不同(升级 winisland / 新装 classisland)。 2. **排序**:ClassHelper 的「业务优先级 → 时间」为第一裁决;ClassIsland 的提供方优先级/通知等级**不引入**,仅允许 `level` 作为稳定次级键(防跨优先级反转)。 3. **上课展示**:暂存规则保留;classisland 信息行上课保持可见(对齐 ClassIsland `HideOnClass=false`),普通通知不展开气泡、显示暂存角标;winisland 维持「上课隐藏整岛」旧规则。 4. **课程提醒**:五类 kind 全保留;`ending` 只显示蓝色秒数徽标,**不实现** ClassIsland「即将下课」遮罩;`custom` 下 `ending/in-class` 不接管岛;徽标显示 `-N`,剩余 1 秒显示 `-1`(`ceil` 语义)。 5. **进度条**:提醒条 2px、组件/行内 3px,两处并存不合并。 6. **动画分工**:岛整体尺寸/圆角用 ClassHelper 弹簧;气泡内部遮罩/文字/进度用 ClassIsland CSS/WAAPI;`speed` 同比缩放,`animations=false` 直跳终态且几何一致。 7. **强提醒**:新增独立 topmost-effect 窗口,600/600/750ms、`effectScale`、多屏、编辑模式不播;**不做音效/TTS**。 8. **天气**:保留 Open-Meteo(15min/缓存标记/无官方预警),ClassIsland 的多模式/预警/预报不实现。 9. **课件优先**:覆盖整岛(424×132);紧急或叫人在播时课件让位且消息不丢。 10. **非目标**:自动化/插件/主题市场/管理端/Excel/音效 TTS/启动闪屏与 OOBE 一律不实现。 ## 4. 未决问题 / 需其它 part 补齐(本 part 已按下列方式处理) 1. **`family` 字段的准确落盘键未定**:Lead 口径同时出现 `appearance.family` 与配置键 `islandAppearance.style`。本文档统一写作 `family`(注明以 parts-r/05 为准)。**需 stack 在 parts-r/05 定稿。** 2. **信息行与气泡的几何关系**:气泡在 40 行内展开时,正文最多两行会导致行高增大。本文档定为「气泡阶段行高仍 40,正文最多 2 行截断」;若 ui-island 在 parts-r/07 决定允许行高临时增高(如 40→64),需同步修改 8.4.2 并更新动画参数。**需 ui-island 确认。** 3. **`effectScale` / `effectEnabled` 字段**:本文档新增外观开关,需 design/stack 在 parts-r/06/05 中给出正式字段名与默认值(现为 `true` / `1.0`)。 4. **`IslandState` 新增字段**(`family/pendingStaged/bubblePhase/bubbleDeadline`)与 `IslandNotification.level`、`IslandLessonReminder.progress/leftSeconds`:需 stack 在 parts-r/05 的 schema 扩展中登记,本文档按「只加不改」处理。 5. **强提醒特效窗口的进程/文件归属**:本文档只定义行为与参数,具体文件(新增 `src/island/effect.*`、`src/main/effect-window.ts`)与 IPC 白名单需 stack 在 parts-r/04 落实。 6. **作业「指纹」实现位置**:`docs/app/island.md:25` 提到本机刚录作业用指纹避免重复提醒自己,源码位置未在本次读取范围内定位;本文档只要求「在推送入口实现」,具体函数需 stack 补读 `src/main/*` 中作业推送链路。 7. **「上课状态」的推送方**:`setClassState` 由主窗口/服务端同步调用,具体调用点在本次阅读范围外;本文档要求「服务端/主窗口下发为准」,需 stack 在 parts-r/02/04 标注现有调用链。 8. **`endingsSeconds` 与 ClassIsland `ClassPrepareNotifySeconds` 的关系**:ClassHelper 用独立 `prepareSeconds/endingSeconds`(默认 60/60),ClassIsland 用 `ClassPrepareNotifySeconds=60`;本文档保留 ClassHelper 两字段,不做合并。 9. **音效/TTS 若未来要做**:本文档明确不实现,并建议作为独立扩展项默认关闭(与 parts/07 的 ClassIsland 规格解耦)。 10. **`custom` 下 `prepare/on-class/break` 临时接管岛内容的表现**:保留「提醒条接管」,但 ClassIsland 规格下 custom 应尽量不打断常驻行。本文档暂定「接管时保留行高 40、不替换常态行的其它行」,需 ui-island 在 parts-r/07 确认多行时接管范围。 ## 5. 与其它 part 的边界 - 像素 token(颜色/圆角/阴影/字号变量):parts-r/06;本文只给业务相关像素(气泡行高、进度条、徽标、课件卡、课程提醒条)。 - 岛/行/组件/编辑模式的结构与逐组件像素:parts-r/07;本文 §3 只给行为与判定顺序。 - 动画总表与降级:parts-r/10;本文给 ms/曲线原始值,建议 parts-r/10 直接引用,避免二次估算。 - schema/迁移/IPC 白名单:parts-r/05。 - 设置页/编辑器 UI:parts-r/09;本文只给消息/课程相关开关的默认值。 - 验收汇总:parts-r/12;本文 §8.14 可直接作为其中的消息与课程子集。