feat(meeting): 实现学生排序功能并优化Redis存储
- 将Redis中的学生排序存储从长ID改为短ID - 在监控端按studentListForSort顺序重新排列学生列表 - 添加新加入学生的处理逻辑 - 实现WebSocket消息处理学生排序变更事件 - 更新类型定义支持学生排序变更数据结构 - 优化Redis服务注释说明短ID存储格式
This commit is contained in:
@ -97,21 +97,21 @@ export class MeetingService {
|
|||||||
|
|
||||||
// 如果提供了 roomId,从 Redis 获取排序并应用
|
// 如果提供了 roomId,从 Redis 获取排序并应用
|
||||||
if (roomId) {
|
if (roomId) {
|
||||||
const orderedIds = await this.redis.getStudentOrder(roomId);
|
const orderedShortIds = await this.redis.getStudentOrder(roomId);
|
||||||
if (orderedIds.length > 0) {
|
if (orderedShortIds.length > 0) {
|
||||||
// 创建映射表
|
// 创建短 ID 到学生的映射
|
||||||
const studentMap = new Map<number, StudentDetailInfo>();
|
const studentMap = new Map<number, StudentDetailInfo>();
|
||||||
finalResults.forEach((student) => {
|
finalResults.forEach((student) => {
|
||||||
studentMap.set(student.longId, student);
|
studentMap.set(student.shortId, student);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 按 Redis 中的顺序重新排列
|
// 按 Redis 中的短 ID 顺序重新排列
|
||||||
const orderedResults: StudentDetailInfo[] = [];
|
const orderedResults: StudentDetailInfo[] = [];
|
||||||
for (const longId of orderedIds) {
|
for (const shortId of orderedShortIds) {
|
||||||
const student = studentMap.get(longId);
|
const student = studentMap.get(shortId);
|
||||||
if (student) {
|
if (student) {
|
||||||
orderedResults.push(student);
|
orderedResults.push(student);
|
||||||
studentMap.delete(longId); // 移除已添加的学生
|
studentMap.delete(shortId); // 移除已添加的学生
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -74,8 +74,8 @@ export class MeetingRedisService {
|
|||||||
* 用途:存储学生列表的排序顺序
|
* 用途:存储学生列表的排序顺序
|
||||||
* 数据结构:List
|
* 数据结构:List
|
||||||
* Key 格式:meeting:student-order:{roomId}
|
* Key 格式:meeting:student-order:{roomId}
|
||||||
* List 内容:按顺序存储学生的长 ID (字符串)
|
* List 内容:按顺序存储学生的短 ID (数字字符串)
|
||||||
* 适用场景:教师端拖动排序后,监控端按相同顺序显示
|
* 适用场景:教师端拖动排序后,监控端和学生端按相同顺序显示
|
||||||
* 过期时间:24 小时
|
* 过期时间:24 小时
|
||||||
*/
|
*/
|
||||||
STUDENT_ORDER: 'meeting:student-order:',
|
STUDENT_ORDER: 'meeting:student-order:',
|
||||||
@ -518,7 +518,7 @@ export class MeetingRedisService {
|
|||||||
/**
|
/**
|
||||||
* 获取学生排序顺序
|
* 获取学生排序顺序
|
||||||
* @param roomId - 房间 ID
|
* @param roomId - 房间 ID
|
||||||
* @returns 学生长 ID 数组 (按排序顺序),未设置返回空数组
|
* @returns 学生短 ID 数组 (按排序顺序),未设置返回空数组
|
||||||
*/
|
*/
|
||||||
async getStudentOrder(roomId: string): Promise<number[]> {
|
async getStudentOrder(roomId: string): Promise<number[]> {
|
||||||
const key = `${this.KEY_PREFIX.STUDENT_ORDER}${roomId}`;
|
const key = `${this.KEY_PREFIX.STUDENT_ORDER}${roomId}`;
|
||||||
|
|||||||
@ -173,7 +173,31 @@
|
|||||||
*/
|
*/
|
||||||
const studentUsers = computed(() => {
|
const studentUsers = computed(() => {
|
||||||
const users = meeting.remoteUsers.value as (IAgoraRTCRemoteUser & { userName?: string })[];
|
const users = meeting.remoteUsers.value as (IAgoraRTCRemoteUser & { userName?: string })[];
|
||||||
return users.filter((u) => (teacherUid.value ? u.uid !== teacherUid.value : true));
|
const filteredUsers = users.filter((u) => (teacherUid.value ? u.uid !== teacherUid.value : true));
|
||||||
|
|
||||||
|
// 按照 studentListForSort 中的顺序重新排列
|
||||||
|
if (studentListForSort.value.length > 0) {
|
||||||
|
// 创建 shortId -> user 的映射
|
||||||
|
const userMap = new Map<number, typeof filteredUsers[0]>();
|
||||||
|
filteredUsers.forEach((user) => {
|
||||||
|
userMap.set(Number(user.uid), user);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 按照 studentListForSort 的顺序重新排列
|
||||||
|
const sortedUsers: typeof filteredUsers = [];
|
||||||
|
studentListForSort.value.forEach((student) => {
|
||||||
|
const user = userMap.get(student.shortId);
|
||||||
|
if (user) {
|
||||||
|
sortedUsers.push(user);
|
||||||
|
userMap.delete(student.shortId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加 studentListForSort 中没有的用户 (新加入的学生)
|
||||||
|
return [...sortedUsers, ...Array.from(userMap.values())];
|
||||||
|
}
|
||||||
|
|
||||||
|
return filteredUsers;
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -285,14 +309,15 @@
|
|||||||
selectedUserUid.value = packet.data.targetUid;
|
selectedUserUid.value = packet.data.targetUid;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// 学生排序变更事件 (类型定义待添加)
|
// 学生排序变更事件
|
||||||
// case 'sev_student_order_changed': {
|
case 'sev_student_order_changed': {
|
||||||
// const newOrder = packet.data.studentShortIds;
|
const newOrder = packet.data.studentShortIds;
|
||||||
// if (Array.isArray(newOrder) && newOrder.length > 0) {
|
if (Array.isArray(newOrder) && newOrder.length > 0) {
|
||||||
// console.log('[监控端] 学生排序已更新:', newOrder);
|
console.log('[监控端] 学生排序已更新,重新获取学生列表');
|
||||||
// }
|
fetchStudentList();
|
||||||
// break;
|
}
|
||||||
// }
|
break;
|
||||||
|
}
|
||||||
case 'sev_class_started': {
|
case 'sev_class_started': {
|
||||||
classStatus.value = 'in_class';
|
classStatus.value = 'in_class';
|
||||||
console.log('[监控端] 收到上课消息');
|
console.log('[监控端] 收到上课消息');
|
||||||
|
|||||||
@ -518,6 +518,14 @@
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'sev_student_order_changed': {
|
||||||
|
const newOrder = packet.data.studentShortIds;
|
||||||
|
if (Array.isArray(newOrder) && newOrder.length > 0) {
|
||||||
|
console.log('[教师端] 学生排序已更新,重新获取学生列表');
|
||||||
|
fetchStudentList();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'sev_class_started': {
|
case 'sev_class_started': {
|
||||||
classStatus.value = 'in_class';
|
classStatus.value = 'in_class';
|
||||||
|
|
||||||
|
|||||||
@ -323,6 +323,19 @@ export interface OnSetMainVideoData extends OnControlMessageData {
|
|||||||
targetUid: number;
|
targetUid: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 控制消息数据 - 学生排序变更
|
||||||
|
*/
|
||||||
|
export interface OnStudentOrderChangedData extends OnControlMessageData {
|
||||||
|
/** 学生短 ID 数组 (按排序顺序) */
|
||||||
|
studentShortIds: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebSocket 消息包 - 服务端下发:学生排序变更
|
||||||
|
*/
|
||||||
|
export type OnStudentOrderChangedPacket = WebSocketPacket<'sev_student_order_changed', OnStudentOrderChangedData>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WebSocket 消息包 - 客户端接收:加入房间成功响应
|
* WebSocket 消息包 - 客户端接收:加入房间成功响应
|
||||||
*/
|
*/
|
||||||
@ -402,6 +415,7 @@ export type DownlinkControlMessagePacket =
|
|||||||
| OnScreenShareStartedPacket
|
| OnScreenShareStartedPacket
|
||||||
| OnScreenShareStoppedPacket
|
| OnScreenShareStoppedPacket
|
||||||
| OnSetMainVideoPacket
|
| OnSetMainVideoPacket
|
||||||
|
| OnStudentOrderChangedPacket
|
||||||
| OnUnmuteAudioPacket
|
| OnUnmuteAudioPacket
|
||||||
| OnUnmuteVideoPacket;
|
| OnUnmuteVideoPacket;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user