feat: add teacher list and profile API

This commit is contained in:
2026-07-06 15:33:12 +08:00
parent 1c097dc230
commit 9e0d9ff39c
2 changed files with 107 additions and 1 deletions

View File

@@ -6,6 +6,7 @@ import {
Delete,
Body,
Param,
Query,
UseGuards,
Request,
BadRequestException,
@@ -259,4 +260,43 @@ export class RbacController {
async getTeacherWorkspace(@Request() req: any) {
return this.rbacService.getTeacherWorkspace(req.user?.id);
}
// ---- 教师管理 ----
@Get('teachers')
@RequirePermission('user:view')
async getTeachers(
@Query('search') search?: string,
@Query('page') page?: string,
@Query('pageSize') pageSize?: string,
) {
return this.rbacService.getTeachers({
search,
page: page ? +page : undefined,
pageSize: pageSize ? +pageSize : undefined,
});
}
@Put('teachers/:id/profile')
@RequirePermission('user:edit')
async updateTeacherProfile(
@Param('id') id: string,
@Body() profile: UpdateProfileDto,
@Request() req: { user?: { id: number; username: string } },
) {
const { ipAddress, userAgent } = extractRequestInfo(req);
const result = await this.rbacService.updateTeacherProfile(+id, profile);
await this.logService.log({
userId: req.user?.id,
username: req.user?.username,
module: '教师管理',
action: '编辑档案',
targetId: +id,
targetType: 'user',
detail: '更新教师档案',
ipAddress,
userAgent,
});
return result;
}
}

View File

@@ -1,4 +1,4 @@
import { Injectable, Logger } from '@nestjs/common';
import { Injectable, Logger, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, In } from 'typeorm';
import * as bcrypt from 'bcryptjs';
@@ -454,4 +454,70 @@ export class RbacService {
myStudents,
};
}
async getTeachers(query?: { search?: string; page?: number; pageSize?: number }) {
const qb = this.userRepo
.createQueryBuilder('u')
.leftJoin('u.roles', 'role')
.leftJoin(ClassTeacher, 'ct', 'ct.userId = u.id')
.leftJoin('ct.class', 'c')
.select([
'u.id', 'u.username', 'u.name', 'u.isActive', 'u.profile', 'u.lastLoginAt',
'role.code', 'role.name',
'ct.roleType', 'ct.subject', 'ct.id',
'c.id', 'c.name',
])
.where('role.code IN (:...roles)', { roles: ['teacher', 'class_teacher', 'dormitory_supervisor', 'super_admin'] });
if (query?.search) {
qb.andWhere('(u.name LIKE :s OR u.username LIKE :s)', { s: `%${query.search}%` });
}
const total = await qb.getCount();
const users = await qb
.orderBy('u.name', 'ASC')
.skip(((query?.page || 1) - 1) * (query?.pageSize || 20))
.take(query?.pageSize || 20)
.getMany();
const list = users.map((u) => {
// TypeORM injects __ct__ and __class__ via leftJoin on non-entity relations
const raw = u as unknown as Record<string, unknown>;
const classAssignments: Array<{ roleType?: string; subject?: string; className: string | null }> = [];
const rawCt = raw['__ct__'];
if (Array.isArray(rawCt)) {
for (const ct of rawCt) {
const ctRaw = ct as Record<string, unknown>;
const cls = ctRaw['__class__'] as Record<string, unknown> | undefined;
classAssignments.push({
roleType: typeof ctRaw['roleType'] === 'string' ? ctRaw['roleType'] : undefined,
subject: typeof ctRaw['subject'] === 'string' ? ctRaw['subject'] : undefined,
className: cls && typeof cls['name'] === 'string' ? cls['name'] : null,
});
}
}
return {
id: u.id,
username: u.username,
name: u.name,
isActive: u.isActive,
profile: u.profile,
lastLoginAt: u.lastLoginAt,
roles: u.roles || [],
classAssignments,
};
});
return { list, total };
}
async updateTeacherProfile(
id: number,
profile: { subjects?: string[]; joinedAt?: string; qualifications?: string },
) {
const user = await this.userRepo.findOne({ where: { id } });
if (!user) throw new NotFoundException('用户不存在');
user.profile = { ...user.profile, ...profile };
return this.userRepo.save(user);
}
}