feat: add teacher list and profile API
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user