import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards, Request, } from '@nestjs/common'; import { SchedulesService } from './schedules.service'; import { CreateScheduleDto, UpdateScheduleDto, QueryScheduleDto, WeeklyViewQueryDto, } from './dto/schedule.dto'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { OperationLogsService } from '../operation-logs/operation-logs.service'; import { extractRequestInfo } from '../common/request-utils'; import { ConflictException } from '@nestjs/common'; import { NotificationsService } from '../notifications/notifications.service'; import { NotificationType } from '../entities/notification.entity'; import { RequirePermission } from '../auth/decorators/permission.decorator'; @UseGuards(JwtAuthGuard) @Controller('class-schedules') export class SchedulesController { constructor( private readonly service: SchedulesService, private readonly logService: OperationLogsService, private readonly notificationsService: NotificationsService, ) {} @Get() @RequirePermission('schedule:view') findAll(@Query() query: QueryScheduleDto) { return this.service.findAll(query); } @Get('weekly') @RequirePermission('schedule:view') getWeeklyView(@Query() query: WeeklyViewQueryDto) { return this.service.getWeeklyView(query); } @Get('classroom/:id/occupancy') @RequirePermission('schedule:view') getClassroomOccupancy( @Param('id') id: string, @Query('date') date?: string, ) { return this.service.getClassroomOccupancy(+id, date); } @Get(':id') @RequirePermission('schedule:view') findOne(@Param('id') id: string) { return this.service.findOne(+id); } @Post() @RequirePermission('schedule:create') async create(@Body() dto: CreateScheduleDto, @Request() req: { user?: { id: number; username: string }; headers?: Record }) { const { ipAddress, userAgent } = extractRequestInfo(req); try { 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-schedule', detail: `${result.subject} 周${result.weekDay} ${result.startTime}-${result.endTime}`, ipAddress, userAgent, }); return result; } catch (error) { if (error instanceof ConflictException) { try { const conflicts = await this.service.checkConflict( dto.classroomId, dto.weekDay, dto.startTime, dto.endTime, dto.startDate, dto.endDate, ); const teacherIds = [...new Set(conflicts.map(c => c.teacherId).filter((id): id is number => id != null))]; if (teacherIds.length > 0) { void this.notificationsService.create({ recipientIds: teacherIds, type: NotificationType.SCHEDULE_CONFLICT, title: '排课冲突', content: `教室${dto.classroomId} 周${dto.weekDay} ${dto.startTime}-${dto.endTime} 与已有排课冲突`, }); } } catch {} } throw error; } } @Put(':id') @RequirePermission('schedule:edit') async update( @Param('id') id: string, @Body() dto: UpdateScheduleDto, @Request() req: { user?: { id: number; username: string }; headers?: Record }, ) { const { ipAddress, userAgent } = extractRequestInfo(req); const existing = await this.service.findOne(+id); try { 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-schedule', detail: JSON.stringify(dto), ipAddress, userAgent, }); return result; } catch (error) { if (error instanceof ConflictException) { try { const conflicts = await this.service.checkConflict( existing.classroomId, existing.weekDay, existing.startTime, existing.endTime, existing.startDate, existing.endDate, ); const teacherIds = [...new Set(conflicts.map(c => c.teacherId).filter((id): id is number => id != null))]; if (teacherIds.length > 0) { void this.notificationsService.create({ recipientIds: teacherIds, type: NotificationType.SCHEDULE_CONFLICT, title: '排课冲突', content: `教室${existing.classroomId} 周${existing.weekDay} ${existing.startTime}-${existing.endTime} (更新) 与已有排课冲突`, }); } } catch {} } throw error; } } @Delete(':id') @RequirePermission('schedule:delete') async remove(@Param('id') id: string, @Request() req: { user?: { id: number; username: string }; headers?: Record }) { 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-schedule', ipAddress, userAgent, }); return result; } }