diff --git a/apps/server/src/rbac/rbac.controller.ts b/apps/server/src/rbac/rbac.controller.ts index ebd6715..06d1e96 100644 --- a/apps/server/src/rbac/rbac.controller.ts +++ b/apps/server/src/rbac/rbac.controller.ts @@ -127,8 +127,9 @@ export class RbacController { @Get('users') @RequirePermission('user:view') - getUsers() { - return this.rbacService.findAllUsers(); + getUsers(@Query('isArchived') isArchived?: string) { + const archived = isArchived === 'true'; + return this.rbacService.findAllUsers(archived); } @Post('users') @@ -219,6 +220,50 @@ export class RbacController { } } + @Put('users/:id/archive') + @RequirePermission('user:edit') + async archiveUser(@Param('id') id: string) { + try { + return await this.rbacService.archiveUser(+id); + } catch (e: unknown) { + const err = e as { message?: string }; + throw new BadRequestException(err?.message); + } + } + + @Put('users/:id/restore') + @RequirePermission('user:edit') + async restoreUser(@Param('id') id: string) { + try { + return await this.rbacService.restoreUser(+id); + } catch (e: unknown) { + const err = e as { message?: string }; + throw new BadRequestException(err?.message); + } + } + + @Put('users/:id/mark-staff') + @RequirePermission('user:edit') + async markAsStaff(@Param('id') id: string) { + try { + return await this.rbacService.markAsStaff(+id); + } catch (e: unknown) { + const err = e as { message?: string }; + throw new BadRequestException(err?.message); + } + } + + @Put('users/:id/mark-student') + @RequirePermission('user:edit') + async markAsStudent(@Param('id') id: string) { + try { + return await this.rbacService.markAsStudent(+id); + } catch (e: unknown) { + const err = e as { message?: string }; + throw new BadRequestException(err?.message); + } + } + // ---- 用户资料 ---- @Get('users/:id/profile') diff --git a/apps/server/src/rbac/rbac.service.ts b/apps/server/src/rbac/rbac.service.ts index b3549fb..e42d6b5 100644 --- a/apps/server/src/rbac/rbac.service.ts +++ b/apps/server/src/rbac/rbac.service.ts @@ -325,16 +325,25 @@ export class RbacService { // ---- 用户管理 ---- - async findAllUsers() { + async findAllUsers(isArchived = false) { const users = await this.userRepo.find({ + where: { isArchived }, relations: ['roles'], order: { createdAt: 'DESC' }, }); + const userIds = users.map((u) => u.id); + const students = await this.studentRepo.find({ + where: { userId: In(userIds) }, + select: ['userId', 'status'], + }); + const statusMap = new Map(students.map((s) => [s.userId, s.status])); return users.map((u) => ({ id: u.id, username: u.username, name: u.name, isActive: u.isActive, + isArchived: u.isArchived, + studentStatus: statusMap.get(u.id) || null, lastLoginAt: u.lastLoginAt, createdAt: u.createdAt, updatedAt: u.updatedAt, @@ -386,10 +395,42 @@ export class RbacService { return { message: '密码已重置' }; } + async archiveUser(id: number) { + const user = await this.userRepo.findOne({ where: { id } }); + if (!user) throw new Error('用户不存在'); + if (user.username === 'admin') throw new Error('不能归档默认管理员'); + await this.userRepo.update(id, { isArchived: true }); + return { message: '用户已归档' }; + } + + async restoreUser(id: number) { + const user = await this.userRepo.findOne({ where: { id } }); + if (!user) throw new Error('用户不存在'); + await this.userRepo.update(id, { isArchived: false }); + return { message: '用户已恢复' }; + } + + async markAsStaff(userId: number) { + const student = await this.studentRepo.findOne({ where: { userId } }); + if (!student) throw new Error('该用户没有学员记录'); + await this.studentRepo.update(student.id, { status: 'staff' }); + this.logger.log(`User ${userId} Student ${student.id} marked as staff`); + return { message: '已标记为教职工' }; + } + + async markAsStudent(userId: number) { + const student = await this.studentRepo.findOne({ where: { userId } }); + if (!student) throw new Error('该用户没有学员记录'); + await this.studentRepo.update(student.id, { status: 'active' }); + this.logger.log(`User ${userId} Student ${student.id} restored to student`); + return { message: '已恢复为学员' }; + } + async deleteUser(id: number) { const user = await this.userRepo.findOne({ where: { id } }); if (!user) throw new Error('用户不存在'); if (user.username === 'admin') throw new Error('不能删除默认管理员'); + if (!user.isArchived) throw new Error('请先归档再删除'); await this.userRepo.remove(user); return { message: '用户已删除' }; }