2026-03-13 10:03:05 +08:00
|
|
|
|
import { Controller, Delete, Get, HttpCode, HttpStatus, Param } from '@nestjs/common';
|
|
|
|
|
|
import { ApiParam, ApiProperty, ApiTags } from '@nestjs/swagger';
|
|
|
|
|
|
import { FailResult, OkResult } from '../../common/dto/result.dto';
|
|
|
|
|
|
import { MeetingService } from './meeting.service';
|
|
|
|
|
|
import { NonEmptyStringPipe } from '@/common/pipes/non-empty-string.pipe';
|
|
|
|
|
|
import { Uint32Pipe } from '@/common/pipes/uint32.pipe';
|
|
|
|
|
|
import { ApiCustomOkResponse } from '@/common/decorators/swagger.decorator';
|
2026-03-14 14:52:18 +08:00
|
|
|
|
import { StudentListResponseDto, TokenResponseDto } from './meeting.dto';
|
2026-03-13 10:03:05 +08:00
|
|
|
|
import { MeetingRedisService } from '../websocket/meeting-redis.service';
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 黑名单用户 DTO
|
|
|
|
|
|
*/
|
|
|
|
|
|
class BlacklistUserDto {
|
|
|
|
|
|
@ApiProperty({ description: '短 UID', example: 1001 })
|
|
|
|
|
|
shortUid?: number;
|
|
|
|
|
|
|
|
|
|
|
|
@ApiProperty({ description: '用户名称', example: '张三' })
|
|
|
|
|
|
userName?: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 会议控制器
|
|
|
|
|
|
* 处理会议相关的 API 请求
|
|
|
|
|
|
*/
|
|
|
|
|
|
@ApiTags('Meeting')
|
|
|
|
|
|
@Controller('meeting')
|
|
|
|
|
|
export class MeetingController {
|
|
|
|
|
|
public constructor(
|
|
|
|
|
|
private readonly meetingService: MeetingService,
|
|
|
|
|
|
private readonly redis: MeetingRedisService
|
|
|
|
|
|
) {}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 生成声网 RTC Token
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Get('get-token/:channelName/:uid')
|
|
|
|
|
|
@HttpCode(HttpStatus.OK)
|
|
|
|
|
|
@ApiCustomOkResponse({
|
|
|
|
|
|
summary: '声网 RTC Token',
|
|
|
|
|
|
model: TokenResponseDto,
|
|
|
|
|
|
apiDescription: '声网 RTC Token 信息',
|
|
|
|
|
|
resDescription: '声网 RTC Token 信息包含appid',
|
|
|
|
|
|
})
|
|
|
|
|
|
@ApiParam({ name: 'channelName', description: '需要加入的频道名(格式: `n_课程名称`)', example: 'n_1234567890' })
|
|
|
|
|
|
@ApiParam({ name: 'uid', description: '用户的短 UID(0~4294967295)', example: '1001' })
|
|
|
|
|
|
public async getToken(@Param('channelName', new NonEmptyStringPipe('channelName')) channelName: string, @Param('uid', new Uint32Pipe('uid')) uid: number) {
|
|
|
|
|
|
const result = this.meetingService.generateToken(channelName, uid);
|
|
|
|
|
|
if (!result) {
|
|
|
|
|
|
return new FailResult('生成 Token 失败');
|
|
|
|
|
|
}
|
|
|
|
|
|
return new OkResult(result);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 查询房间黑名单(包含短 UID 和名称的数组)
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Get('blacklist/:roomId')
|
|
|
|
|
|
@HttpCode(HttpStatus.OK)
|
|
|
|
|
|
@ApiParam({ name: 'roomId', description: '服务端房间 ID(Socket.IO 房间名)' })
|
|
|
|
|
|
@ApiCustomOkResponse({
|
|
|
|
|
|
summary: '房间黑名单',
|
|
|
|
|
|
model: [BlacklistUserDto],
|
|
|
|
|
|
apiDescription: '房间黑名单(包含短 UID 和名称的数组)',
|
|
|
|
|
|
resDescription: '房间黑名单(包含短 UID 和名称的数组)',
|
|
|
|
|
|
})
|
|
|
|
|
|
public async getBlacklist(@Param('roomId', new NonEmptyStringPipe('roomId')) roomId: string) {
|
|
|
|
|
|
const list = await this.redis.getBlacklist(roomId);
|
|
|
|
|
|
return new OkResult(list);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-03-14 14:52:18 +08:00
|
|
|
|
* 从房间黑名单移除指定用户 (短 UID)
|
2026-03-13 10:03:05 +08:00
|
|
|
|
*/
|
|
|
|
|
|
@Delete('blacklist/:roomId/:shortUid')
|
|
|
|
|
|
@HttpCode(HttpStatus.OK)
|
|
|
|
|
|
@ApiParam({ name: 'roomId', description: '服务端房间 ID(Socket.IO 房间名)' })
|
|
|
|
|
|
@ApiParam({ name: 'shortUid', description: '用户短 UID', example: '1001' })
|
|
|
|
|
|
@ApiCustomOkResponse({
|
|
|
|
|
|
summary: '从房间黑名单移除用户',
|
|
|
|
|
|
model: Boolean,
|
|
|
|
|
|
apiDescription: '从房间黑名单移除指定用户(短 UID)',
|
|
|
|
|
|
resDescription: '是否成功移除用户',
|
|
|
|
|
|
})
|
|
|
|
|
|
public async removeFromBlacklist(
|
|
|
|
|
|
@Param('roomId', new NonEmptyStringPipe('roomId')) roomId: string,
|
|
|
|
|
|
@Param('shortUid', new Uint32Pipe('shortUid')) shortUid: number
|
|
|
|
|
|
) {
|
|
|
|
|
|
await this.redis.removeFromBlacklist(roomId, shortUid);
|
|
|
|
|
|
return new OkResult(true);
|
|
|
|
|
|
}
|
2026-03-14 14:52:18 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 通过作业 ID 查询学生详细信息列表
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Get('students/:homeworkId')
|
|
|
|
|
|
@HttpCode(HttpStatus.OK)
|
|
|
|
|
|
@ApiParam({ name: 'homeworkId', description: '作业 ID', example: '1234567890' })
|
|
|
|
|
|
@ApiCustomOkResponse({
|
|
|
|
|
|
summary: '学生详细信息列表',
|
|
|
|
|
|
model: StudentListResponseDto,
|
|
|
|
|
|
apiDescription: '学生详细信息列表,包含长 ID、短 ID (可能为 null) 和姓名',
|
|
|
|
|
|
resDescription: '学生详细信息列表',
|
|
|
|
|
|
})
|
|
|
|
|
|
public async getStudentDetails(@Param('homeworkId', new Uint32Pipe('homeworkId')) homeworkId: number) {
|
|
|
|
|
|
const students = await this.meetingService.getStudentDetailsByHomeworkId(homeworkId);
|
|
|
|
|
|
return new OkResult({
|
|
|
|
|
|
total: students.length,
|
|
|
|
|
|
students,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2026-03-13 10:03:05 +08:00
|
|
|
|
}
|