feat: add Attendance module with batch, summary, calendar, and dingtalk endpoints

This commit is contained in:
2026-07-05 19:44:10 +08:00
parent 4ededb0338
commit b6e308ae2a
8 changed files with 486 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
ManyToOne,
JoinColumn,
Index,
} from 'typeorm';
import { Student } from './student.entity';
@Entity('ding_attendance_raw')
@Index(['attendanceDate'])
@Index(['matchStatus'])
export class DingAttendanceRaw {
@PrimaryGeneratedColumn()
id: number;
@Column({ name: 'ding_user_id', length: 100 })
dingUserId: string;
@Column({ name: 'user_name', length: 100 })
userName: string;
@Column({ name: 'attendance_date', type: 'date' })
attendanceDate: string;
@Column({ name: 'ding_id', length: 100, unique: true })
dingId: string;
@Column({ name: 'check_in_time', type: 'datetime', nullable: true })
checkInTime: Date;
@Column({ name: 'check_out_time', type: 'datetime', nullable: true })
checkOutTime: Date;
@Column({ name: 'attendance_type', length: 20 })
attendanceType: string;
@Column({ name: 'time_result', length: 20 })
timeResult: string;
@Column({ name: 'location_result', length: 20, nullable: true })
locationResult: string;
@Column({ name: 'match_status', length: 20, default: '未处理' })
matchStatus: string;
@Column({ name: 'matched_student_id', type: 'integer', nullable: true })
matchedStudentId: number;
@ManyToOne(() => Student, { onDelete: 'SET NULL', nullable: true })
@JoinColumn({ name: 'matched_student_id' })
matchedStudent: Student;
@Column({ name: 'raw_data', type: 'text', nullable: true })
rawData: string;
@CreateDateColumn({ name: 'created_at' })
createdAt: Date;
@UpdateDateColumn({ name: 'updated_at' })
updatedAt: Date;
}