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:
@@ -391,23 +391,21 @@ export class AttendanceService {
|
||||
});
|
||||
|
||||
if (existing) {
|
||||
if (existing.status === 'completed') {
|
||||
const records = await this.attendanceRepo.find({
|
||||
where: { attendanceSessionId: existing.id },
|
||||
relations: ['student'],
|
||||
order: { studentId: 'ASC' },
|
||||
});
|
||||
return { schedule, session: existing, records: await this.attachAttendanceDeviceMappings(records, schedule.classId) };
|
||||
}
|
||||
if (existing.status !== 'in_progress' && !(finalize && existing.status === 'settling')) {
|
||||
if (
|
||||
existing.status !== 'in_progress' &&
|
||||
existing.status !== 'completed' &&
|
||||
!(finalize && existing.status === 'settling')
|
||||
) {
|
||||
throw new BadRequestException('课程考勤正在结算');
|
||||
}
|
||||
|
||||
// Refresh in_progress session from latest DingTalk data
|
||||
// Refresh latest DingTalk data even after automatic settlement; late-arriving punches
|
||||
// may legitimately change a DingTalk-generated absence to present.
|
||||
return this.dataSource.transaction(async (manager) => {
|
||||
const sessionRepo = manager.getRepository(AttendanceSession);
|
||||
const recordRepo = manager.getRepository(AttendanceRecord);
|
||||
const rawByStudent = await this.fetchDingTalkRawByStudent(schedule.classId!, schedule, lessonDate);
|
||||
const effectiveFinalize = finalize || existing.status === 'completed';
|
||||
const existingRecords = await recordRepo.find({
|
||||
where: { attendanceSessionId: existing.id },
|
||||
order: { studentId: 'ASC' },
|
||||
@@ -433,7 +431,7 @@ export class AttendanceService {
|
||||
schedule,
|
||||
lessonDate,
|
||||
);
|
||||
record.status = this.mapDingTalkStatus(raw, finalize);
|
||||
record.status = this.mapDingTalkStatus(raw, effectiveFinalize);
|
||||
Object.assign(record, this.getLessonPunchMetadata(
|
||||
raw,
|
||||
lessonDate,
|
||||
@@ -441,7 +439,7 @@ export class AttendanceService {
|
||||
));
|
||||
record.remark = raw.some((item) => item.checkInTime || item.checkOutTime)
|
||||
? null
|
||||
: finalize
|
||||
: effectiveFinalize
|
||||
? '课程截止仍未打卡'
|
||||
: '未获取到钉钉打卡结果';
|
||||
return record;
|
||||
@@ -462,7 +460,7 @@ export class AttendanceService {
|
||||
attendanceSessionId: existing.id,
|
||||
attendanceDate: lessonDate,
|
||||
session: lessonSessionKey,
|
||||
status: this.mapDingTalkStatus(raw, finalize),
|
||||
status: this.mapDingTalkStatus(raw, effectiveFinalize),
|
||||
source: 'dingtalk',
|
||||
...this.getLessonPunchMetadata(
|
||||
raw,
|
||||
@@ -471,7 +469,7 @@ export class AttendanceService {
|
||||
),
|
||||
remark: raw.some((item) => item.checkInTime || item.checkOutTime)
|
||||
? undefined
|
||||
: finalize
|
||||
: effectiveFinalize
|
||||
? '课程截止仍未打卡'
|
||||
: '未获取到钉钉打卡结果',
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user