feat: add exam score management
This commit is contained in:
@@ -412,11 +412,13 @@ ${this.buildLearningAndResult(learnings, result, now)}
|
||||
const highestName = highestExam?.examName ?? '-';
|
||||
|
||||
// Improvement: last exam score minus first exam score
|
||||
const sortedExams = [...cultureExams].filter((e) => e.score != null);
|
||||
const sortedScores = cultureExams
|
||||
.map((exam) => exam.score)
|
||||
.filter((score): score is number => score !== null && score !== undefined);
|
||||
let improvement = '—';
|
||||
if (sortedExams.length >= 2) {
|
||||
const first = sortedExams[0].score;
|
||||
const last = sortedExams[sortedExams.length - 1].score;
|
||||
if (sortedScores.length >= 2) {
|
||||
const first = sortedScores[0];
|
||||
const last = sortedScores[sortedScores.length - 1];
|
||||
improvement = (last - first).toFixed(1);
|
||||
}
|
||||
|
||||
@@ -511,7 +513,7 @@ ${this.buildLearningAndResult(learnings, result, now)}
|
||||
const cultureExams = exams.filter((e) => e.score != null);
|
||||
if (cultureExams.length === 0) return '';
|
||||
|
||||
const scores = cultureExams.map((e) => e.score);
|
||||
const scores = cultureExams.map((e) => Number(e.score));
|
||||
const labels = cultureExams.map((e) => {
|
||||
const d = e.examDate || '-';
|
||||
return d.length > 7 ? d.slice(5) : d;
|
||||
|
||||
@@ -67,6 +67,22 @@ describe('ArchiveService — resource and relationship boundaries', () => {
|
||||
expect(exam.save).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('keeps exam-management scores read-only in the student archive', async () => {
|
||||
const exam = {
|
||||
findOne: jest.fn().mockResolvedValue({ id: 3, studentId: 7, examId: 8 }),
|
||||
save: jest.fn(),
|
||||
update: jest.fn(),
|
||||
};
|
||||
const service = createService({ exam });
|
||||
|
||||
await expect(service.updateExamScore(3, { score: 95 })).rejects.toBeInstanceOf(
|
||||
BadRequestException,
|
||||
);
|
||||
await expect(service.deleteExamScore(3)).rejects.toBeInstanceOf(BadRequestException);
|
||||
expect(exam.save).not.toHaveBeenCalled();
|
||||
expect(exam.update).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('rejects a missing attachment upload before writing to disk', async () => {
|
||||
const service = createService({ student: { findOne: jest.fn() } });
|
||||
await expect(service.addAttachment(7, undefined as never, 'other')).rejects.toBeInstanceOf(
|
||||
|
||||
@@ -75,7 +75,11 @@ export class ArchiveService {
|
||||
] = await Promise.all([
|
||||
this.profileRepo.findOne({ where: { studentId } }),
|
||||
this.enrollmentRepo.find({ where: { studentId, status: 'active' }, order: { createdAt: 'DESC' } }),
|
||||
this.examScoreRepo.find({ where: { studentId, status: 'active' }, order: { examDate: 'DESC' } }),
|
||||
this.examScoreRepo.find({
|
||||
where: { studentId, status: 'active' },
|
||||
relations: ['exam', 'exam.class'],
|
||||
order: { examDate: 'DESC' },
|
||||
}),
|
||||
this.learningRecordRepo.find({ where: { studentId, status: 'active' }, order: { recordDate: 'DESC' } }),
|
||||
this.resultRepo.findOne({ where: { studentId } }),
|
||||
this.attachmentRepo.find({ where: { studentId, status: 'active' }, order: { createdAt: 'DESC' } }),
|
||||
@@ -154,6 +158,7 @@ export class ArchiveService {
|
||||
async updateExamScore(id: number, dto: UpdateExamScoreDto) {
|
||||
const entity = await this.examScoreRepo.findOne({ where: { id } });
|
||||
if (!entity) throw new NotFoundException('考试成绩不存在');
|
||||
if (entity.examId) throw new BadRequestException('考试管理同步成绩请在考试管理中修改');
|
||||
await this.assertEnrollmentBelongsToStudent(entity.studentId, dto.enrollmentId);
|
||||
Object.assign(entity, dto);
|
||||
return this.examScoreRepo.save(entity);
|
||||
@@ -162,6 +167,7 @@ export class ArchiveService {
|
||||
async deleteExamScore(id: number) {
|
||||
const entity = await this.examScoreRepo.findOne({ where: { id } });
|
||||
if (!entity) throw new NotFoundException('考试成绩不存在');
|
||||
if (entity.examId) throw new BadRequestException('考试管理同步成绩不能在学生档案中归档');
|
||||
if (entity.status === 'archived') throw new BadRequestException('考试成绩已归档');
|
||||
await this.examScoreRepo.update(id, { status: 'archived' });
|
||||
return { message: '已归档' };
|
||||
|
||||
Reference in New Issue
Block a user