import { Controller, Get, Post, Put, Delete, Body, Param, UseGuards, Request, UseInterceptors, UploadedFile, Res, } from '@nestjs/common'; import { FileInterceptor } from '@nestjs/platform-express'; import type { Request as ExpressRequest, Response } from 'express'; import * as fs from 'fs'; import { ArchiveReportService } from './archive-report.service'; import { ArchiveService } from './archive.service'; import { UpsertProfileDto, CreateEnrollmentDto, CreateExamScoreDto, CreateLearningRecordDto, UpsertResultDto, } from './dto/archive.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'; interface AuthenticatedRequest extends ExpressRequest { user?: { id: number; username?: string }; } @UseGuards(JwtAuthGuard) @Controller('archive') export class ArchiveController { constructor( private readonly archiveService: ArchiveService, private readonly logService: OperationLogsService, private readonly reportService: ArchiveReportService, ) {} @Get(':studentId') @RequirePermission('student:view') async getProfile(@Param('studentId') studentId: string, @Request() req: AuthenticatedRequest) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.archiveService.getProfile(+studentId); await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '学生档案', action: '查看档案', targetId: +studentId, targetType: 'archive', ipAddress, userAgent, }); return result; } @Put(':studentId/profile') @RequirePermission('student:edit') async upsertProfile( @Param('studentId') studentId: string, @Body() dto: UpsertProfileDto, @Request() req: AuthenticatedRequest, ) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.archiveService.upsertProfile(+studentId, dto); await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '学生档案', action: '更新档案信息', targetId: +studentId, targetType: 'student_profile', detail: JSON.stringify(dto), ipAddress, userAgent, }); return result; } @Post(':studentId/enrollments') @RequirePermission('student:edit') async addEnrollment( @Param('studentId') studentId: string, @Body() dto: CreateEnrollmentDto, @Request() req: AuthenticatedRequest, ) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.archiveService.addEnrollment(+studentId, dto); await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '学生档案', action: '添加报名记录', targetId: result.id, targetType: 'student_enrollment', detail: `${dto.courseCategory} - ${dto.classType}`, ipAddress, userAgent, }); return result; } @Put('enrollments/:id') @RequirePermission('student:edit') async updateEnrollment( @Param('id') id: string, @Body() dto: Partial, @Request() req: AuthenticatedRequest, ) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.archiveService.updateEnrollment(+id, dto); await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '学生档案', action: '编辑报名记录', targetId: +id, targetType: 'student_enrollment', detail: JSON.stringify(dto), ipAddress, userAgent, }); return result; } @Delete('enrollments/:id') @RequirePermission('student:edit') async deleteEnrollment(@Param('id') id: string, @Request() req: AuthenticatedRequest) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.archiveService.deleteEnrollment(+id); await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '学生档案', action: '删除报名记录', targetId: +id, targetType: 'student_enrollment', ipAddress, userAgent, }); return result; } @Post(':studentId/exam-scores') @RequirePermission('student:edit') async addExamScore( @Param('studentId') studentId: string, @Body() dto: CreateExamScoreDto, @Request() req: AuthenticatedRequest, ) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.archiveService.addExamScore(+studentId, dto); await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '学生档案', action: '添加考试成绩', targetId: result.id, targetType: 'exam_score', detail: `${dto.examType} - ${dto.subject}: ${dto.score}`, ipAddress, userAgent, }); return result; } @Put('exam-scores/:id') @RequirePermission('student:edit') async updateExamScore( @Param('id') id: string, @Body() dto: Partial, @Request() req: AuthenticatedRequest, ) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.archiveService.updateExamScore(+id, dto); await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '学生档案', action: '编辑考试成绩', targetId: +id, targetType: 'exam_score', detail: JSON.stringify(dto), ipAddress, userAgent, }); return result; } @Delete('exam-scores/:id') @RequirePermission('student:edit') async deleteExamScore(@Param('id') id: string, @Request() req: AuthenticatedRequest) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.archiveService.deleteExamScore(+id); await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '学生档案', action: '删除考试成绩', targetId: +id, targetType: 'exam_score', ipAddress, userAgent, }); return result; } @Post(':studentId/learning-records') @RequirePermission('student:edit') async addLearningRecord( @Param('studentId') studentId: string, @Body() dto: CreateLearningRecordDto, @Request() req: AuthenticatedRequest, ) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.archiveService.addLearningRecord(+studentId, dto); await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '学生档案', action: '添加学习记录', targetId: result.id, targetType: 'learning_record', detail: `${dto.recordType}: ${dto.content.substring(0, 50)}`, ipAddress, userAgent, }); return result; } @Put('learning-records/:id') @RequirePermission('student:edit') async updateLearningRecord( @Param('id') id: string, @Body() dto: Partial, @Request() req: AuthenticatedRequest, ) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.archiveService.updateLearningRecord(+id, dto); await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '学生档案', action: '编辑学习记录', targetId: +id, targetType: 'learning_record', detail: JSON.stringify(dto), ipAddress, userAgent, }); return result; } @Delete('learning-records/:id') @RequirePermission('student:edit') async deleteLearningRecord(@Param('id') id: string, @Request() req: AuthenticatedRequest) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.archiveService.deleteLearningRecord(+id); await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '学生档案', action: '删除学习记录', targetId: +id, targetType: 'learning_record', ipAddress, userAgent, }); return result; } @Put(':studentId/result') @RequirePermission('student:edit') async upsertResult( @Param('studentId') studentId: string, @Body() dto: UpsertResultDto, @Request() req: AuthenticatedRequest, ) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.archiveService.upsertResult(+studentId, dto); await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '学生档案', action: '更新录取结果', targetId: +studentId, targetType: 'result_archive', detail: JSON.stringify(dto), ipAddress, userAgent, }); return result; } @Post(':studentId/attachments') @RequirePermission('student:edit') @UseInterceptors(FileInterceptor('file')) async uploadAttachment( @Param('studentId') studentId: string, @UploadedFile() file: Express.Multer.File, @Body('category') category: string, @Request() req: AuthenticatedRequest, ) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.archiveService.addAttachment(+studentId, file, category || 'other'); await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '学生档案', action: '上传附件', targetId: result.id, targetType: 'archive_attachment', detail: `${file.originalname} (${category || 'other'})`, ipAddress, userAgent, }); return result; } @Get(':studentId/attachments/:id') @RequirePermission('student:view') async downloadAttachment( @Param('studentId') studentId: string, @Param('id') id: string, @Res() res: Response, ) { const { fullPath, fileName, mimeType } = await this.archiveService.getAttachmentFile(+studentId, +id); res.setHeader('Content-Type', mimeType); res.setHeader( 'Content-Disposition', `inline; filename="${encodeURIComponent(fileName)}"`, ); const stream = fs.createReadStream(fullPath); stream.pipe(res); } @Delete('attachments/:id') @RequirePermission('student:edit') async deleteAttachment(@Param('id') id: string, @Request() req: AuthenticatedRequest) { const { ipAddress, userAgent } = extractRequestInfo(req); const result = await this.archiveService.deleteAttachment(+id); await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '学生档案', action: '删除附件', targetId: +id, targetType: 'archive_attachment', ipAddress, userAgent, }); return result; } @Get(':studentId/report-html') @RequirePermission('student:view') async generateReportHtml( @Param('studentId') studentId: string, @Request() req: AuthenticatedRequest, ) { const { ipAddress, userAgent } = extractRequestInfo(req); await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: 'archive', action: 'generate_report_html', targetId: +studentId, targetType: 'student', ipAddress, userAgent, }); const html = await this.reportService.generateReportHtml(+studentId); return { html }; } }