import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards, Request, Res, } from '@nestjs/common'; import type { Response } from 'express'; import { ClassesService } from './classes.service'; import { CreateClassDto, UpdateClassDto, QueryClassDto, AddStudentsDto, AddTeacherDto, } from './dto/class.dto'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { OperationLogsService } from '../operation-logs/operation-logs.service'; import { extractRequestInfo } from '../common/request-utils'; import { RequirePermission } from '../auth/decorators/permission.decorator'; import { NotificationsService } from '../notifications/notifications.service'; import { NotificationType } from '../entities/notification.entity'; import * as ExcelJS from 'exceljs'; @UseGuards(JwtAuthGuard) @Controller('classes') export class ClassesController { constructor( private readonly service: ClassesService, private readonly logService: OperationLogsService, private readonly notificationsService: NotificationsService, ) {} @Get() @RequirePermission('class:view') findAll(@Query() query: QueryClassDto) { return this.service.findAll(query); } @Get(':id') @RequirePermission('class:view') findOne(@Param('id') id: string) { return this.service.findOne(+id); } @Post() @RequirePermission('class:create') async create(@Body() dto: CreateClassDto, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.create(dto); await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '班级管理', action: '创建班级', targetId: result.id, targetType: 'class', detail: `班级${result.code} ${result.name}`, ipAddress, userAgent, }); return result; } @Put(':id') @RequirePermission('class:edit') async update( @Param('id') id: string, @Body() dto: UpdateClassDto, @Request() req: any, ) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.update(+id, dto); await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '班级管理', action: '编辑班级', targetId: +id, targetType: 'class', detail: JSON.stringify(dto), ipAddress, userAgent, }); return result; } @Delete(':id') @RequirePermission('class:delete') async remove(@Param('id') id: string, @Request() req: any) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.remove(+id); await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '班级管理', action: '删除班级', targetId: +id, targetType: 'class', ipAddress, userAgent, }); return result; } @Get(':id/roster/export') @RequirePermission('class:view') async exportRoster(@Param('id') id: string, @Res() res: Response) { const classEntity = await this.service.findOne(+id); const classStudents = await this.service.getStudents(+id); const workbook = new ExcelJS.Workbook(); const ws = workbook.addWorksheet('班级花名册'); ws.columns = [ { header: '姓名', key: 'name', width: 15 }, { header: '学号', key: 'studentNo', width: 15 }, { header: '加入日期', key: 'joinDate', width: 15 }, { header: '状态', key: 'status', width: 10 }, ]; ws.getRow(1).font = { bold: true }; ws.getRow(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE0E0E0' } }; for (const cs of classStudents) { ws.addRow({ name: cs.student?.name || '', studentNo: cs.student?.idNumber || '', joinDate: cs.joinDate || '', status: cs.status || '', }); } res.setHeader( 'Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', ); res.setHeader( 'Content-Disposition', `attachment; filename=${encodeURIComponent(`班级花名册-${classEntity.name}`)}.xlsx`, ); await workbook.xlsx.write(res); res.end(); } @Get(':id/students') @RequirePermission('class:view') getStudents(@Param('id') id: string) { return this.service.getStudents(+id); } @Post(':id/students') @RequirePermission('class:edit') async addStudents( @Param('id') id: string, @Body() dto: AddStudentsDto, @Request() req: any, ) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.addStudents(+id, dto.studentIds); await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '班级管理', action: '添加学生', targetId: +id, targetType: 'class', detail: `新增${result.added}名学生`, ipAddress, userAgent, }); try { const cls = await this.service.findOne(+id); if (cls.headTeacherId) { void this.notificationsService.create({ recipientIds: [cls.headTeacherId], type: NotificationType.CLASS_CHANGE, title: '学员变动', content: `班级新增${result.added}名学生`, }); } } catch {} return result; } @Delete(':id/students/:studentId') @RequirePermission('class:edit') async removeStudent( @Param('id') id: string, @Param('studentId') studentId: string, @Request() req: any, ) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.removeStudent(+id, +studentId); await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '班级管理', action: '移除学生', targetId: +id, targetType: 'class', detail: `移除学生${studentId}`, ipAddress, userAgent, }); return result; } @Get(':id/teachers') @RequirePermission('class:view') getTeachers(@Param('id') id: string) { return this.service.getTeachers(+id); } @Post(':id/teachers') @RequirePermission('class:edit') async addTeacher( @Param('id') id: string, @Body() dto: AddTeacherDto, @Request() req: any, ) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.addTeacher(+id, dto); await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '班级管理', action: '添加教师', targetId: +id, targetType: 'class', detail: `教师${dto.userId} 角色${dto.roleType}`, ipAddress, userAgent, }); try { void this.notificationsService.create({ recipientIds: [dto.userId], type: NotificationType.CLASS_CHANGE, title: '班级分配', content: `您已被分配到班级担任${dto.roleType}角色`, }); } catch {} return result; } @Delete(':id/teachers/:userId') @RequirePermission('class:edit') async removeTeacher( @Param('id') id: string, @Param('userId') userId: string, @Request() req: any, ) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.service.removeTeacher(+id, +userId); await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '班级管理', action: '移除教师', targetId: +id, targetType: 'class', detail: `移除教师${userId}`, ipAddress, userAgent, }); return result; } }