feat(websocket): 优化投屏状态管理并新增全员禁麦功能

- 重构 Redis 投屏状态存储,统一使用 screenShareOwnerUid 字段
- 移除冗余的 screenShareUid 字段,简化房间状态数据结构
- 新增 client_mute_all_students 消息类型支持全员禁麦功能
- 实现创建者权限验证的全员禁麦逻辑,排除老师角色用户
- 优化 Tauri 桌面应用悬浮窗创建接口,支持状态参数传递
- 添加悬浮窗关闭功能及教师端静音状态同步机制
- 修复学生端界面中投屏状态变量命名不一致问题
- 统一按钮样式规范,提升界面组件一致性
This commit is contained in:
2026-03-15 18:21:15 +08:00
parent cddb2d65a4
commit bfaad97f61
17 changed files with 610 additions and 299 deletions

View File

@ -247,19 +247,14 @@ export class MeetingRedisService {
/**
* 设置投屏状态
* @param roomId - 房间 ID
* @param screenShareUid - 投屏人短 UIDnull 表示停止投屏
* @param screenShareOwnerUid - 投屏人短 UIDnull 表示停止投屏
*/
async setScreenSharing(roomId: string, screenShareUid: number | null, screenShareOwnerUid?: number | null): Promise<void> {
async setScreenSharing(roomId: string, screenShareOwnerUid: number | null): Promise<void> {
const key = `${this.KEY_PREFIX.ROOM_STATE}${roomId}`;
if (screenShareUid === null) {
await this.getClient().hdel(key, 'screenShareUid');
if (screenShareOwnerUid === null) {
await this.getClient().hdel(key, 'screenShareOwnerUid');
} else {
const hm: Record<string, string> = { screenShareUid: String(screenShareUid) };
if (typeof screenShareOwnerUid === 'number' && Number.isFinite(screenShareOwnerUid) && screenShareOwnerUid > 0) {
hm.screenShareOwnerUid = String(screenShareOwnerUid);
}
await this.getClient().hset(key, hm);
await this.getClient().hset(key, { screenShareOwnerUid: String(screenShareOwnerUid) });
await this.getClient().expire(key, 24 * 60 * 60);
}
}
@ -297,7 +292,6 @@ export class MeetingRedisService {
async getRoomState(roomId: string): Promise<{
classStatus: 'finished' | 'in_class' | 'not_started';
speakerUid?: number;
screenShareUid?: number;
screenShareOwnerUid?: number;
teacherUid?: number;
endTimestamp?: number;
@ -306,14 +300,12 @@ export class MeetingRedisService {
const map = await this.getClient().hgetall(key);
const status = (map?.classStatus as any) || 'not_started';
const speakerUid = map?.speakerUid ? Number(map.speakerUid) : undefined;
const screenShareUid = map?.screenShareUid ? Number(map.screenShareUid) : undefined;
const screenShareOwnerUid = map?.screenShareOwnerUid ? Number(map.screenShareOwnerUid) : undefined;
const teacherUid = map?.teacherUid ? Number(map.teacherUid) : undefined;
const endTimestamp = map?.endTimestamp ? Number(map.endTimestamp) : undefined;
return {
classStatus: status,
...(Number.isFinite(speakerUid) ? { speakerUid } : {}),
...(Number.isFinite(screenShareUid) ? { screenShareUid } : {}),
...(Number.isFinite(screenShareOwnerUid) ? { screenShareOwnerUid } : {}),
...(Number.isFinite(teacherUid) ? { teacherUid } : {}),
...(Number.isFinite(endTimestamp) ? { endTimestamp } : {}),