diff --git a/apps/admin/src/pages/IntegrationConfig/index.tsx b/apps/admin/src/pages/IntegrationConfig/index.tsx index 002f8f0..bb2b6a5 100644 --- a/apps/admin/src/pages/IntegrationConfig/index.tsx +++ b/apps/admin/src/pages/IntegrationConfig/index.tsx @@ -236,13 +236,7 @@ const IntegrationConfigPage: React.FC = () => { const userIds = checkedKeys .filter((k) => String(k).startsWith('user-')) .map((k) => String(k).replace('user-', '')); - const deptKeys = checkedKeys.filter((k) => String(k).startsWith('dept-')); - const deptId = deptKeys.length > 0 - ? Number(String(deptKeys[0]).replace('dept-', '')) - : undefined; - - setImporting(true); - await api.post('/classes', { ...values, dingUserIds: userIds, departmentId: deptId }); + await api.post('/classes', { ...values, dingUserIds: userIds }); message.success('班级创建成功'); setClassModalOpen(false); classForm.resetFields(); diff --git a/apps/server/src/attendance/attendance.service.ts b/apps/server/src/attendance/attendance.service.ts index 2be1d1d..4667b3e 100644 --- a/apps/server/src/attendance/attendance.service.ts +++ b/apps/server/src/attendance/attendance.service.ts @@ -128,7 +128,7 @@ export class AttendanceService { status: 'pending', source: 'schedule', }); - entity.departmentId = cs.student?.departmentId ?? cls.departmentId ?? undefined; + entity.departmentId = cs.student?.departmentId ?? undefined; entities.push(entity); existingKeys.add(key); } diff --git a/apps/server/src/classes/classes.controller.ts b/apps/server/src/classes/classes.controller.ts index 3fcd8bf..ebba85f 100644 --- a/apps/server/src/classes/classes.controller.ts +++ b/apps/server/src/classes/classes.controller.ts @@ -86,27 +86,6 @@ export class ClassesController { return result; } - /** 从钉钉同步部门创建班级 */ - @Post('from-department') - @RequirePermission('class:create') - async createFromDepartment( - @Body() dto: { departmentId: number; name?: string; classType?: string }, - @Request() req: any, - ) { - const result = await this.service.createFromDepartment(dto); - await this.logService.log({ - userId: req.user?.id, - username: req.user?.username, - module: '班级管理', - action: '从部门创建班级', - targetId: result.id, - targetType: 'class', - detail: `班级${result.code} ${result.name}`, - ipAddress: extractRequestInfo(req).ipAddress, - userAgent: extractRequestInfo(req).userAgent, - }); - return result; - } /** 批量导入学生到班级(通过钉钉用户ID) */ @Post(':id/students/import') diff --git a/apps/server/src/classes/classes.service.ts b/apps/server/src/classes/classes.service.ts index c69c0f1..c29a873 100644 --- a/apps/server/src/classes/classes.service.ts +++ b/apps/server/src/classes/classes.service.ts @@ -1,7 +1,7 @@ import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository, In, Like } from 'typeorm'; -import { Class, ClassStudent, ClassTeacher, ClassSchedule, AttendanceRecord, Department, Classroom, Student, StudentDingMapping } from '../entities'; +import { Class, ClassStudent, ClassTeacher, ClassSchedule, AttendanceRecord, Classroom, Student, StudentDingMapping } from '../entities'; import { CreateClassDto, UpdateClassDto, QueryClassDto, AddTeacherDto, QueryClassScheduleDto, QueryClassAttendanceSummaryDto, BatchImportStudentsDto } from './dto/class.dto'; interface RawStudentCount { @@ -22,8 +22,6 @@ export class ClassesService { private scheduleRepo: Repository, @InjectRepository(AttendanceRecord) private attendanceRepo: Repository, - @InjectRepository(Department) - private deptRepo: Repository, @InjectRepository(Student) private studentRepo: Repository, @InjectRepository(StudentDingMapping) @@ -32,7 +30,6 @@ export class ClassesService { async findAll(query: QueryClassDto) { let where: Record = {}; - if (query.departmentId) where.departmentId = query.departmentId; if (query.status) where.status = query.status; if (query.classType) where.classType = query.classType; if (query.keyword) where.name = Like(`%${query.keyword}%`); @@ -99,21 +96,6 @@ export class ClassesService { async create(dto: CreateClassDto) { const { studentIds, teachers, dingUserIds, ...classData } = dto; - // Resolve departmentId: frontend may pass DingTalk dept ID, map to local - if (classData.departmentId) { - const localDept = await this.deptRepo.findOne({ - where: { source: 'dingtalk', sourceId: String(classData.departmentId) }, - }); - if (localDept) { - classData.departmentId = localDept.id; - } else { - // Verify it's a valid local department ID - const exists = await this.deptRepo.findOne({ where: { id: classData.departmentId } }); - if (!exists) { - throw new BadRequestException(`部门 ID ${classData.departmentId} 不存在`); - } - } - } const cls = this.classRepo.create(classData); const saved = await this.classRepo.save(cls); @@ -165,7 +147,7 @@ export class ClassesService { this.studentRepo.create({ name: `dd_${dingUserId}`, status: 'active', - departmentId: classEntity.departmentId ?? undefined, + departmentId: undefined, }) ); const savedStudents = await this.studentRepo.save(newStudents); @@ -240,32 +222,6 @@ export class ClassesService { return { success: true }; } - async createFromDepartment(dto: { departmentId: number; name?: string; classType?: string }) { - const dept = await this.deptRepo.findOne({ - where: { id: dto.departmentId, source: 'dingtalk' }, - }); - - if (!dept) { - throw new BadRequestException('所选部门不存在或非钉钉同步部门'); - } - - const className = dto.name || dept.name; - const code = `DT_${dto.departmentId}`; - - const existing = await this.classRepo.findOne({ where: { code } }); - if (existing) { - throw new BadRequestException(`班级"${className}"已存在(编码: ${code})`); - } - - const cls = this.classRepo.create({ - name: className, - code, - departmentId: dto.departmentId, - classType: dto.classType || 'culture', - status: 'enrolling', - }); - return this.classRepo.save(cls); - } async getStudents(classId: number) { return this.classStudentRepo.find({ diff --git a/apps/server/src/classes/dto/class.dto.ts b/apps/server/src/classes/dto/class.dto.ts index e640184..fd7323d 100644 --- a/apps/server/src/classes/dto/class.dto.ts +++ b/apps/server/src/classes/dto/class.dto.ts @@ -9,8 +9,6 @@ export class CreateClassDto { @IsString() @IsNotEmpty() code: string; - @IsOptional() @IsInt() - departmentId?: number; @IsEnum(ClassType) @IsString() @IsNotEmpty() classType: string; @@ -58,8 +56,6 @@ export class UpdateClassDto { @IsOptional() @IsString() code?: string; - @IsOptional() @IsInt() - departmentId?: number; @IsEnum(ClassType) @IsOptional() @IsString() classType?: string; @@ -90,10 +86,6 @@ export class UpdateClassDto { } export class QueryClassDto { - @IsOptional() - @Type(() => Number) - @IsInt() - departmentId?: number; @IsOptional() @IsString() status?: string; diff --git a/apps/server/src/entities/class.entity.ts b/apps/server/src/entities/class.entity.ts index 171ddc8..242b121 100644 --- a/apps/server/src/entities/class.entity.ts +++ b/apps/server/src/entities/class.entity.ts @@ -4,8 +4,6 @@ import { Column, CreateDateColumn, UpdateDateColumn, - ManyToOne, - JoinColumn, } from 'typeorm'; export enum ClassType { @@ -33,8 +31,6 @@ export class Class { @Column({ name: 'code', length: 50, unique: true }) code: string; - @Column({ name: 'department_id', type: 'integer', nullable: true }) - departmentId: number; @Column({ name: 'class_type', length: 20 }) diff --git a/apps/server/src/integration/dingtalk.service.ts b/apps/server/src/integration/dingtalk.service.ts index 4f3811a..0ab2952 100644 --- a/apps/server/src/integration/dingtalk.service.ts +++ b/apps/server/src/integration/dingtalk.service.ts @@ -11,7 +11,6 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { Department } from '../entities/department.entity'; import { Student } from '../entities/student.entity'; -import { Class } from '../entities/class.entity'; import { StudentDingMapping } from '../entities/student-ding-mapping.entity'; // ── Types ── @@ -189,8 +188,6 @@ export class DingTalkService { private readonly studentRepo: Repository, @InjectRepository(StudentDingMapping) private readonly studentDingMappingRepo: Repository, - @InjectRepository(Class) - private readonly classRepo: Repository, ) {} private get configured(): boolean { @@ -381,26 +378,6 @@ export class DingTalkService { } await this.deptRepo.save(syncedDepts); - // ── Step 2.5: Auto-create Class for leaf departments ── - const parentIds = new Set(syncedDepts.map((d) => d.parentSourceId)); - const leafDepts = syncedDepts.filter((d) => !parentIds.has(d.sourceId)); - let classCreated = 0; - for (const leaf of leafDepts) { - const code = `DT_${leaf.sourceId}`; - const exists = await this.classRepo.findOne({ where: { code } }); - if (!exists) { - const cls = this.classRepo.create({ - name: leaf.name, - code, - departmentId: leaf.id, - classType: 'culture', - status: 'enrolling', - }); - await this.classRepo.save(cls); - classCreated++; - } - } - if (classCreated > 0) this.logger.log(`从钉钉叶子部门自动创建 ${classCreated} 个班级`); // ── Step 3: Sync users per department ── let userCount = 0; diff --git a/apps/server/src/schedules/schedules.service.ts b/apps/server/src/schedules/schedules.service.ts index a448c9d..7e76499 100644 --- a/apps/server/src/schedules/schedules.service.ts +++ b/apps/server/src/schedules/schedules.service.ts @@ -52,9 +52,6 @@ export class SchedulesService { const schedule = this.scheduleRepo.create(dto); if (dto.departmentId) { schedule.departmentId = dto.departmentId; - } else if (dto.classId) { - const cls = await this.classRepo.findOne({ where: { id: dto.classId } }); - if (cls) schedule.departmentId = cls.departmentId; } const saved = await this.scheduleRepo.save(schedule); return this.findOne(saved.id); diff --git a/apps/server/src/students/students.service.ts b/apps/server/src/students/students.service.ts index 5400de4..1e33a76 100644 --- a/apps/server/src/students/students.service.ts +++ b/apps/server/src/students/students.service.ts @@ -42,9 +42,6 @@ export class StudentsService { const entity = this.repo.create(dto); if (dto.departmentId) { entity.departmentId = dto.departmentId; - } else if (dto.classId) { - const cls = await this.classRepo.findOne({ where: { id: dto.classId } }); - if (cls) entity.departmentId = cls.departmentId; } return this.repo.save(entity); }