fix(island,server): 连续圆角四角修正 + 叫人分紧急/普通两级
灵动岛圆角(用户反馈"左上角和右下角缺一块 / 圆角边缘割裂"): - squircle.ts 改为"每个角独立圆心 + 角度参数"的超椭圆采样(原本四角共用同一个偏移向量, 左上/右下被切掉一块);四角几何与 WinIsland 的连续超椭圆一致,r 与 h/2、w/2 自动收敛。 - verify:desktop 新增像素级断言「连续圆角四角一致」:从四角沿对角线找岛体边界, 四角步进必须两两一致(展开 15/15/15/15、紧急 14/14/14/14、胶囊 5/5/5/5), 并保留路径绕行 |winding|≈2π 断言(抓"角上往回折")。该断言即本次回归的守卫。 - 截图留档同时写入裁剪图与整窗图,便于人工复核角形。 叫人分紧急 / 普通两级(用户要求"叫人也分为紧急和普通"): - shared:CreateCallRequest 新增 urgent;紧急叫人 → URGENT(无视上课时段立即展开), 普通叫人(默认)→ HIGH(按普通通知排队)。 - desktop:isImmediate 只认 priority=URGENT,不再把 kind=call 一律视为立即消息; 普通叫人回到与普通通知相同的排队 / 隐藏 / 下课弹出路径。 - web:通知发布 → 叫人、学生管理 → 叫人 两个弹窗新增"级别"单选(默认普通)+ 联动提示文案。 验证:verify:e2e 135/135(新增普通 / 紧急叫人级别断言)、verify:web 20/20(新增级别单选断言)、 verify:desktop 59/59 + 离线复跑 53/53、typecheck / lint / format 全绿。
This commit is contained in:
1 parent
1b4dd14e4a
commit
0690546307
13 files changed
+553
-205
No files matched your search
@@ -13,6 +13,8 @@ export const createCallSchema = z
|
||||
quickPhrase: z.string().trim().max(64).optional(),
|
||||
/** 自定义消息(可选;与 quickPhrase 至少填一个) */
|
||||
message: z.string().trim().max(200).optional(),
|
||||
/** 紧急叫人:落库 URGENT,学生端无视上课时段立即展开;默认普通(只进队列) */
|
||||
urgent: z.boolean().optional(),
|
||||
})
|
||||
.refine((data) => Boolean(data.studentId), { message: '请选择学生', path: ['studentId'] })
|
||||
.refine((data) => Boolean(data.message || data.quickPhrase), {
|
||||
|
||||
@@ -15,7 +15,11 @@ const creatorSelect = { select: { id: true, name: true, username: true } } as co
|
||||
*
|
||||
* 设计:复用通知表落库(学生端通知中心可见、已读状态天然可用、离线也能看到历史),
|
||||
* 同时额外广播 `call:new` 到该学生的 user 房间 —— 客户端据此把消息标记为
|
||||
* "叫人"类型,无论是否在上课都立即展开显示。
|
||||
* "叫人"类型(徽标/按钮/尺寸),**是否立即展开则由 priority 决定**:
|
||||
* - 紧急叫人(urgent=true → URGENT):无视上课时段立即展开;
|
||||
* - 普通叫人(默认 → HIGH):按普通通知处理,上课时段只进队列、下课后弹出,
|
||||
* 课间则先显示胶囊、点击后展开。
|
||||
* 两种情况都不会被"上课时段发布紧急通知"的 409 拦截(老师确实需要学生过来)。
|
||||
*/
|
||||
export async function createCall(user: TokenPayload, input: CreateCallInput): Promise<NotificationDto> {
|
||||
await assertCanPublishContent(user, input.classId);
|
||||
@@ -42,8 +46,9 @@ export async function createCall(user: TokenPayload, input: CreateCallInput): Pr
|
||||
classId: input.classId,
|
||||
title: buildCallTitle(studentName, teacherName),
|
||||
content: message,
|
||||
// 叫人属于需要立即响应的消息,用 HIGH 级别(不会触发上课时段 409 拦截)
|
||||
priority: 'HIGH',
|
||||
// 紧急叫人 → URGENT(客户端无视上课时段立即展开);普通叫人 → HIGH
|
||||
// (不会触发上课时段 409 拦截,但学生端按普通通知排队处理)
|
||||
priority: input.urgent ? 'URGENT' : 'HIGH',
|
||||
createdBy: user.sub,
|
||||
},
|
||||
include: { creator: creatorSelect, reads: true },
|
||||
@@ -58,6 +63,6 @@ export async function createCall(user: TokenPayload, input: CreateCallInput): Pr
|
||||
// 因此"叫人"消息在班级设备上也会立即展开(学生姓名在标题里,全班都能看到叫谁)
|
||||
emitToUser(created.classId, SOCKET_EVENTS.callNew, dto);
|
||||
|
||||
logger.info(`叫人:${teacherName} → ${studentName}(${message})`);
|
||||
logger.info(`${input.urgent ? '紧急叫人' : '叫人'}:${teacherName} → ${studentName}(${message})`);
|
||||
return dto;
|
||||
}
|
||||
Reference in new issue
Block a user