fix: UI improvements and DingTalk attendance refresh for completed sessions
All checks were successful
CI / check (pull_request) Successful in 1m33s
All checks were successful
CI / check (pull_request) Successful in 1m33s
- DatePicker editors open immediately on double-click - Student archive drawer hides empty studentNo parentheses - Student add/edit form uses 2-column grid layout - Table horizontal scrollbars show only on hover/focus - Remove fake 近7日趋势 stats from attendance student detail - Allow DingTalk refresh to update completed attendance sessions (late-arriving punches can now change absent → present) - Switch dev command from concurrently to turbo run dev - Remove concurrently/wait-on dependencies
This commit is contained in:
53
apps/server/src/attendance/lesson-attendance-sync.service.ts
Normal file
53
apps/server/src/attendance/lesson-attendance-sync.service.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||
import { AttendanceImportService } from './attendance-import.service';
|
||||
import { AttendanceService } from './attendance.service';
|
||||
|
||||
export type LessonAttendanceSyncMode = 'refresh' | 'finalize';
|
||||
|
||||
export interface LessonAttendanceSyncOptions {
|
||||
scheduleId: number;
|
||||
lessonDate: string;
|
||||
actorId: number;
|
||||
canManageAll: boolean;
|
||||
mode: LessonAttendanceSyncMode;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class LessonAttendanceSyncService {
|
||||
constructor(
|
||||
private readonly attendanceService: AttendanceService,
|
||||
private readonly importService: AttendanceImportService,
|
||||
) {}
|
||||
|
||||
async syncLesson(options: LessonAttendanceSyncOptions) {
|
||||
const { scheduleId, lessonDate, actorId, canManageAll, mode } = options;
|
||||
const { schedule } = await this.attendanceService.getLessonAttendance(scheduleId, lessonDate);
|
||||
const userIds = await this.attendanceService.getTeacherClassDingUserIds(
|
||||
actorId,
|
||||
schedule.classId!,
|
||||
canManageAll,
|
||||
lessonDate,
|
||||
);
|
||||
const dateRange = this.attendanceService.getLessonAttendanceImportDateRange(
|
||||
schedule,
|
||||
lessonDate,
|
||||
);
|
||||
const imported = await this.importService.importFromDingTalk({
|
||||
...dateRange,
|
||||
userIds,
|
||||
autoMatch: true,
|
||||
userId: actorId,
|
||||
});
|
||||
if (!imported.success || imported.errors.length > 0) {
|
||||
throw new BadRequestException(imported.errors.join('; ') || '钉钉考勤拉取失败');
|
||||
}
|
||||
|
||||
const attendance = await this.attendanceService.createLessonAttendanceFromDingTalk(
|
||||
scheduleId,
|
||||
lessonDate,
|
||||
actorId,
|
||||
mode === 'finalize',
|
||||
);
|
||||
return { attendance, imported: imported.imported, matched: imported.matched };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user