feat(integrations,classisland,server,web,desktop): ClassIsland 联动插件——上报课表与上课状态、下发提醒并回执、教室端推送通道

教室机器上的 ClassIsland 现在可以直接和班级小助手互通:插件走 /api/integrations/classisland/*,用设备令牌(X-ClassIsland-Token,库里只存 sha256)独立鉴权,不占用 JWT 通道。

- 服务端:新增 integrations 模块(上报 / 待弹出 / 回执 / 课表镜像 / 回写),两个迁移(设备令牌表、Class.notificationChannel);通知、叫人、联动页下发统一复用 pushToClassIsland,避免"某个页面发的通知不联动"
- 插件:packages/classisland-plugin(.NET 8,独立于 pnpm workspace)——BridgeService 上报与提醒轮询、ScheduleMapper/ClassPlanWriter 课表镜像、Avalonia 设置页、ClassHelperNotificationProvider 在 ClassIsland 上弹出提醒;本地/内网地址强制直连,躲开系统代理返回的假 404
- 客户端:设置页可选提醒通道(both / client / classisland),并订阅相应实时事件
- Web 端:新增「ClassIsland 联动」页(设备管理与提醒下发)
- 校验与打包:verify:classisland(需后端)、verify:classisland-plugin(静态契约 54 项)、build/dist:classisland-plugin 产出 .cipx
- 文档:README 与 AGENTS.md 同步新增联动说明,docs/screenshots/classisland 留三张真机截图

门禁:pnpm lint 0 error、pnpm typecheck 四包通过、verify:classisland-plugin 54/54 通过。运行期仍需在装了 ClassIsland 的机器上实测(步骤见 AGENTS.md §8)。
This commit is contained in:
LoveChengke committed 2026-09-27 14:59:12 +08:00
1 parent fe41ebb7d6
commit d0830f6830
61 files changed
+7026 -93

No files matched your search

+64
View File
@@ -23,6 +23,8 @@ export const API_PATHS = {
teachers: '/teachers',
/** 导入:模板下载 / 表格导入 / ClassIsland 课表时间配置 */
imports: '/imports',
/** ClassIsland 联动:设备接入、状态上报、通知下发 */
integrations: '/integrations',
dashboard: '/dashboard/summary',
} as const;
@@ -214,9 +216,71 @@ export const SOCKET_EVENTS = {
classUpdated: 'class:updated',
/** "叫人":老师点名让某位同学去找他(定向到 user:{studentId} 房间) */
callNew: 'call:new',
/** ClassIsland 联动:设备状态上报(Web 端实时展示当前课程) */
classislandState: 'classisland:state',
/** ClassIsland 联动:教师发起的提醒已下发(插件据此全屏弹出) */
classislandNotification: 'classisland:notification',
connected: 'connected',
} as const;
/** ClassIsland 联动:设备接入令牌的前缀(便于识别与日志排查) */
export const CLASSISLAND_DEVICE_TOKEN_PREFIX = 'chci_';
/** ClassIsland 联动:ClassIsland 的时间点类型(与 TimeLayoutItem.TimeType 一致) */
export const CLASSISLAND_TIME_TYPES = {
class: 0,
break: 1,
divider: 2,
action: 3,
} as const;
/**
* ClassIsland 的时间点类型 -> 本系统的节次类型。
* 3(行动)在本系统里按"分割线"处理:它不占课时,只做视觉分隔。
*/
export const CLASSISLAND_TIME_TYPE_LABELS: Record<number, string> = {
0: '上课',
1: '课间',
2: '分割线',
3: '行动',
};
/** ClassIsland TimeState 字符串 -> 中文(插件上报 → Web 端展示) */
export const CLASSISLAND_TIME_STATE_LABELS: Record<string, string> = {
None: '空闲',
OnClass: '上课中',
PrepareOnClass: '预备铃',
Breaking: '课间休息',
AfterSchool: '已放学',
};
/**
* 通知的显示位置(由**教室的班级客户端**在设置页里选,存在班级上)。
*
* - `both`:ClassHelper 客户端弹(弹窗 + 灵动岛),同时推给教室的 ClassIsland;
* - `client`:只在 ClassHelper 客户端弹,不打扰 ClassIsland;
* - `classisland`:只在 ClassIsland 上弹(客户端只进通知中心,不弹窗、不上岛)。
*/
export const CLASSISLAND_NOTIFICATION_CHANNELS = ['both', 'client', 'classisland'] as const;
export const CLASSISLAND_NOTIFICATION_CHANNEL_LABELS: Record<string, string> = {
both: 'ClassHelper 与 ClassIsland 都弹',
client: '只在 ClassHelper 客户端弹',
classisland: '只在 ClassIsland 上弹',
};
export const CLASSISLAND_NOTIFICATION_CHANNEL_HINTS: Record<string, string> = {
both: '教室的 ClassHelper 客户端与 ClassIsland 都会提醒(默认)',
client: '提醒只在 ClassHelper 客户端显示,不推送到 ClassIsland',
classisland: '提醒只推送到 ClassIsland,ClassHelper 客户端只留记录、不弹窗',
};
/** 默认显示位置:两端都弹 */
export const DEFAULT_CLASSISLAND_NOTIFICATION_CHANNEL = 'both';
/** 默认提醒显示时长(秒),后端与插件共用同一口径 */
export const CLASSISLAND_NOTIFICATION_DEFAULT_DURATION = 8;
export const CLASSISLAND_NOTIFICATION_MAX_DURATION = 120;
/**
* "叫人"快捷短语(Web 管理端一键选择,学生端灵动岛同步展示)。
* 自定义消息会替换/补全这些短语;`message` 为空时用短语本身。