import { Injectable, NotFoundException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import * as fs from 'fs'; import * as path from 'path'; import { CampusScope } from '../common/campus-scope'; import { NotificationsService } from '../notifications/notifications.service'; import { Student } from '../entities/student.entity'; import { StudentProfile } from '../entities/student-profile.entity'; import { StudentEnrollment } from '../entities/student-enrollment.entity'; import { ExamScore } from '../entities/exam-score.entity'; import { LearningRecord } from '../entities/learning-record.entity'; import { ResultArchive } from '../entities/result-archive.entity'; import { ArchiveAttachment } from '../entities/archive-attachment.entity'; import { UpsertProfileDto, CreateEnrollmentDto, CreateExamScoreDto, CreateLearningRecordDto, UpsertResultDto, } from './dto/archive.dto'; @Injectable() export class ArchiveService { constructor( @InjectRepository(Student) private studentRepo: Repository, @InjectRepository(StudentProfile) private profileRepo: Repository, @InjectRepository(StudentEnrollment) private enrollmentRepo: Repository, @InjectRepository(ExamScore) private examScoreRepo: Repository, @InjectRepository(LearningRecord) private learningRecordRepo: Repository, @InjectRepository(ResultArchive) private resultRepo: Repository, @InjectRepository(ArchiveAttachment) private attachmentRepo: Repository, private readonly scope: CampusScope, private readonly notificationsService: NotificationsService, ) {} async getProfile(studentId: number) { const student = await this.studentRepo.findOne({ where: { id: studentId } }); if (!student) throw new NotFoundException('学生不存在'); const [ profileRaw, enrollments, examScores, learningRecords, resultArchive, attachments, ] = await Promise.all([ this.profileRepo.findOne({ where: await this.scope.filter({ studentId }) }), this.enrollmentRepo.find({ where: await this.scope.filter({ studentId }), order: { createdAt: 'DESC' }, }), this.examScoreRepo.find({ where: await this.scope.filter({ studentId }), order: { examDate: 'DESC' }, }), this.learningRecordRepo.find({ where: await this.scope.filter({ studentId }), order: { recordDate: 'DESC' }, }), this.resultRepo.findOne({ where: await this.scope.filter({ studentId }) }), this.attachmentRepo.find({ where: await this.scope.filter({ studentId }), order: { createdAt: 'DESC' }, }), ]); return { student, profile: profileRaw, enrollments, examScores, learningRecords, resultArchive, attachments, }; } async upsertProfile(studentId: number, dto: UpsertProfileDto) { const student = await this.studentRepo.findOne({ where: { id: studentId } }); if (!student) throw new NotFoundException('学生不存在'); let profile = await this.profileRepo.findOne({ where: { studentId } }); if (profile) { Object.assign(profile, dto); } else { profile = this.profileRepo.create({ ...dto, studentId }); } return this.profileRepo.save(profile); } async addEnrollment(studentId: number, dto: CreateEnrollmentDto) { const student = await this.studentRepo.findOne({ where: { id: studentId } }); if (!student) throw new NotFoundException('学生不存在'); const entity = this.enrollmentRepo.create({ ...dto, studentId }); return this.enrollmentRepo.save(entity); } async updateEnrollment(id: number, dto: Partial) { const entity = await this.enrollmentRepo.findOne({ where: { id } }); if (!entity) throw new NotFoundException('报名记录不存在'); Object.assign(entity, dto); return this.enrollmentRepo.save(entity); } async deleteEnrollment(id: number) { const entity = await this.enrollmentRepo.findOne({ where: { id } }); if (!entity) throw new NotFoundException('报名记录不存在'); await this.enrollmentRepo.remove(entity); return { message: '已删除' }; } async addExamScore(studentId: number, dto: CreateExamScoreDto) { const student = await this.studentRepo.findOne({ where: { id: studentId } }); if (!student) throw new NotFoundException('学生不存在'); const entity = this.examScoreRepo.create({ ...dto, studentId }); return this.examScoreRepo.save(entity); } async updateExamScore(id: number, dto: Partial) { const entity = await this.examScoreRepo.findOne({ where: { id } }); if (!entity) throw new NotFoundException('考试成绩不存在'); Object.assign(entity, dto); return this.examScoreRepo.save(entity); } async deleteExamScore(id: number) { const entity = await this.examScoreRepo.findOne({ where: { id } }); if (!entity) throw new NotFoundException('考试成绩不存在'); await this.examScoreRepo.remove(entity); return { message: '已删除' }; } async addLearningRecord(studentId: number, dto: CreateLearningRecordDto) { const student = await this.studentRepo.findOne({ where: { id: studentId } }); if (!student) throw new NotFoundException('学生不存在'); const entity = this.learningRecordRepo.create({ ...dto, studentId }); return this.learningRecordRepo.save(entity); } async updateLearningRecord(id: number, dto: Partial) { const entity = await this.learningRecordRepo.findOne({ where: { id } }); if (!entity) throw new NotFoundException('学习记录不存在'); Object.assign(entity, dto); return this.learningRecordRepo.save(entity); } async deleteLearningRecord(id: number) { const entity = await this.learningRecordRepo.findOne({ where: { id } }); if (!entity) throw new NotFoundException('学习记录不存在'); await this.learningRecordRepo.remove(entity); return { message: '已删除' }; } async upsertResult(studentId: number, dto: UpsertResultDto) { const student = await this.studentRepo.findOne({ where: { id: studentId } }); if (!student) throw new NotFoundException('学生不存在'); let result = await this.resultRepo.findOne({ where: { studentId } }); if (result) { Object.assign(result, dto); } else { result = this.resultRepo.create({ ...dto, studentId }); } return this.resultRepo.save(result); } async addAttachment(studentId: number, file: Express.Multer.File, category: string) { const student = await this.studentRepo.findOne({ where: { id: studentId } }); if (!student) throw new NotFoundException('学生不存在'); const uploadDir = path.join(process.cwd(), 'uploads', 'archive'); if (!fs.existsSync(uploadDir)) { fs.mkdirSync(uploadDir, { recursive: true }); } const ext = path.extname(file.originalname); const filename = `${studentId}_${Date.now()}${ext}`; const filePath = path.join(uploadDir, filename); fs.writeFileSync(filePath, file.buffer); const entity = this.attachmentRepo.create({ studentId, category, fileName: file.originalname, filePath: `uploads/archive/${filename}`, fileSize: file.size, mimeType: file.mimetype, }); return this.attachmentRepo.save(entity); } async deleteAttachment(id: number) { const entity = await this.attachmentRepo.findOne({ where: { id } }); if (!entity) throw new NotFoundException('附件不存在'); const absPath = path.join(process.cwd(), entity.filePath); if (fs.existsSync(absPath)) { fs.unlinkSync(absPath); } await this.attachmentRepo.remove(entity); return { message: '已删除' }; } }