feat: add student archive module with full CRUD APIs

This commit is contained in:
2026-07-06 15:46:57 +08:00
parent 9eec7c34be
commit b6990dd11b
5 changed files with 655 additions and 2 deletions

View File

@@ -0,0 +1,349 @@
import {
Controller,
Get,
Post,
Put,
Delete,
Body,
Param,
UseGuards,
Request,
UseInterceptors,
UploadedFile,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import type { Request as ExpressRequest } from 'express';
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,
) {}
@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<CreateEnrollmentDto>,
@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<CreateExamScoreDto>,
@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<CreateLearningRecordDto>,
@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;
}
@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')
@RequirePermission('student:view')
async generateReport(@Param('studentId') studentId: string) {
return {
studentId: +studentId,
message: '学生档案报告功能开发中',
generatedAt: new Date().toISOString(),
};
}
}