feat: 考勤模块重构与钉钉考勤同步

This commit is contained in:
2026-08-05 17:11:23 +08:00
parent c622e40a12
commit e9c8a1085d
36 changed files with 5122 additions and 3458 deletions

View File

@@ -0,0 +1,57 @@
import { UseGuards } from '@nestjs/common';
import { AttendanceService } from './attendance.service';
import { AttendanceImportService } from './attendance-import.service';
import { OperationLogsService } from '../operation-logs/operation-logs.service';
import { AuthorizationService, CaslAction, SubjectName } from '../authorization';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
/** Minimal request user shape for type safety */
export interface RequestUser {
id: number;
username: string;
permissions: string[];
isSuperAdmin: boolean;
roles: string[];
}
/** SSE event shape for @Sse() decorator */
export interface SseEvent {
data: string | Record<string, unknown>;
id?: string;
type?: string;
retry?: number;
}
@UseGuards(JwtAuthGuard)
export abstract class AttendanceControllerBase {
constructor(
protected readonly service: AttendanceService,
protected readonly importService: AttendanceImportService,
protected readonly logService: OperationLogsService,
protected readonly authz: AuthorizationService,
) {}
protected getTodayDateOnly(): string {
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, '0');
const day = String(today.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
protected canManageAllAttendance(req: { user: RequestUser }): boolean {
return (
this.authz.can(req, CaslAction.Manage, SubjectName.Attendance) ||
// Legacy: class:edit grants broad attendance access for teacher scoping
this.authz.can(req, CaslAction.Update, SubjectName.Class)
);
}
protected getAccessibleClassIds(req: { user: RequestUser }) {
return this.service.getAccessibleClassIds(req.user.id, this.canManageAllAttendance(req));
}
protected assertClassAccess(req: { user: RequestUser }, classId: number) {
return this.service.assertClassAccess(req.user.id, classId, this.canManageAllAttendance(req));
}
}