forked from wangziqi/gongxue-base
386 lines
12 KiB
TypeScript
386 lines
12 KiB
TypeScript
import {
|
|
Controller,
|
|
Get,
|
|
Post,
|
|
Put,
|
|
Delete,
|
|
Body,
|
|
Param,
|
|
UseGuards,
|
|
Request,
|
|
UseInterceptors,
|
|
UploadedFile,
|
|
Res,
|
|
ParseIntPipe,
|
|
} 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,
|
|
UpdateEnrollmentDto,
|
|
CreateExamScoreDto,
|
|
UpdateExamScoreDto,
|
|
CreateLearningRecordDto,
|
|
UpdateLearningRecordDto,
|
|
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', ParseIntPipe) studentId: number, @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', ParseIntPipe) studentId: number,
|
|
@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', ParseIntPipe) studentId: number,
|
|
@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', ParseIntPipe) id: number,
|
|
@Body() dto: UpdateEnrollmentDto,
|
|
@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', ParseIntPipe) id: number, @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', ParseIntPipe) studentId: number,
|
|
@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', ParseIntPipe) id: number,
|
|
@Body() dto: UpdateExamScoreDto,
|
|
@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', ParseIntPipe) id: number, @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', ParseIntPipe) studentId: number,
|
|
@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', ParseIntPipe) id: number,
|
|
@Body() dto: UpdateLearningRecordDto,
|
|
@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', ParseIntPipe) id: number, @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', ParseIntPipe) studentId: number,
|
|
@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', ParseIntPipe) studentId: number,
|
|
@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', ParseIntPipe) studentId: number,
|
|
@Param('id', ParseIntPipe) id: number,
|
|
@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', ParseIntPipe) id: number, @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', ParseIntPipe) studentId: number,
|
|
@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 };
|
|
}
|
|
}
|