diff --git a/apps/admin/src/pages/Users/index.tsx b/apps/admin/src/pages/Users/index.tsx index b6684d1..a4802b2 100644 --- a/apps/admin/src/pages/Users/index.tsx +++ b/apps/admin/src/pages/Users/index.tsx @@ -10,7 +10,7 @@ import { Tag, Popconfirm, } from 'antd'; -import { PlusOutlined, EditOutlined, DeleteOutlined, KeyOutlined, IdcardOutlined, InboxOutlined } from '@ant-design/icons'; +import { PlusOutlined, EditOutlined, KeyOutlined, IdcardOutlined, InboxOutlined } from '@ant-design/icons'; import dayjs from 'dayjs'; import api from '../../api'; import PermissionButton from '../../components/PermissionButton'; @@ -141,18 +141,6 @@ const UsersPage: React.FC = () => { } }; - const handleDelete = async (id: number) => { - try { - await api.delete(`/rbac/users/${id}`); - message.success('已删除'); - fetchData(); - } catch (e: unknown) { - const err = e as { message?: string }; - message.error(err?.message || '删除失败'); - } - }; - - const handleResetPwd = (record: any) => { setResetTarget(record); pwdForm.resetFields(); @@ -253,13 +241,6 @@ const UsersPage: React.FC = () => { 归档 )} - {record.username !== 'admin' && ( - handleDelete(record.id)}> - }> - 删除 - - - )} ), }, diff --git a/apps/admin/src/test/fixtures.ts b/apps/admin/src/test/fixtures.ts index 9d54a01..fb0aa9f 100644 --- a/apps/admin/src/test/fixtures.ts +++ b/apps/admin/src/test/fixtures.ts @@ -220,6 +220,6 @@ export const PERMISSION_NODES = [ 'report:generate', 'log:view', 'role:view', 'role:add', 'role:update', 'role:delete', - 'user:view', 'user:add', 'user:update', 'user:delete', + 'user:view', 'user:add', 'user:update', 'dashboard:view', ] as const; diff --git a/apps/server/src/rbac/rbac.controller.ts b/apps/server/src/rbac/rbac.controller.ts index 95b022d..6aa95e2 100644 --- a/apps/server/src/rbac/rbac.controller.ts +++ b/apps/server/src/rbac/rbac.controller.ts @@ -198,28 +198,6 @@ export class RbacController { } } - @Delete('users/:id') - @RequirePermission('user:delete') - async deleteUser(@Param('id') id: string, @Request() req: any) { - const { ipAddress, userAgent } = extractRequestInfo(req); - try { - const result = await this.rbacService.deleteUser(+id); - await this.logService.log({ - userId: req.user?.id, - username: req.user?.username, - module: '账号', - action: '删除账号', - targetId: +id, - targetType: 'user', - ipAddress, - userAgent, - }); - return result; - } catch (e: any) { - throw new BadRequestException(e.message); - } - } - @Put('users/:id/archive') @RequirePermission('user:edit') async archiveUser(@Param('id') id: string) { diff --git a/apps/server/src/rbac/rbac.service.ts b/apps/server/src/rbac/rbac.service.ts index 4343dda..efc3e79 100644 --- a/apps/server/src/rbac/rbac.service.ts +++ b/apps/server/src/rbac/rbac.service.ts @@ -70,7 +70,6 @@ const PRESET_PERMISSIONS: Array<{ code: string; name: string; group: string }> = { code: 'user:view', name: '查看用户', group: 'user' }, { code: 'user:create', name: '创建用户', group: 'user' }, { code: 'user:edit', name: '编辑用户', group: 'user' }, - { code: 'user:delete', name: '删除用户', group: 'user' }, { code: 'user:reset-password', name: '重置密码', group: 'user' }, { code: 'role:view', name: '查看角色', group: 'role' }, { code: 'role:create', name: '创建角色', group: 'role' }, @@ -250,7 +249,12 @@ export class RbacService { await this.permRepo.save(this.permRepo.create(p)); } } - const allPerms = await this.permRepo.find(); + const deprecatedUserDeletePermission = await this.permRepo.findOne({ + where: { code: 'user:delete' }, + }); + const allPerms = (await this.permRepo.find()).filter( + (permission) => permission.code !== 'user:delete', + ); // Step 2: 幂等插入预置角色 for (const r of PRESET_ROLES) { @@ -271,6 +275,19 @@ export class RbacService { } const allRoles = await this.roleRepo.find({ relations: ['permissions', 'users'] }); + if (deprecatedUserDeletePermission) { + for (const role of allRoles) { + const permissions = role.permissions ?? []; + if (permissions.some((permission) => permission.id === deprecatedUserDeletePermission.id)) { + role.permissions = permissions.filter( + (permission) => permission.id !== deprecatedUserDeletePermission.id, + ); + await this.roleRepo.save(role); + } + } + await this.permRepo.remove(deprecatedUserDeletePermission); + } + // Step 3: 合并旧角色并构建新的职责权限矩阵 for (const preset of PRESET_ROLES) { const matchesPreset = (role: Role) => @@ -564,15 +581,6 @@ export class RbacService { 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: '用户已删除' }; - } - // ---- 用户资料 ---- async getUserProfile(id: number) { diff --git a/技术文档.md b/技术文档.md index cdf614c..13c3d69 100644 --- a/技术文档.md +++ b/技术文档.md @@ -169,7 +169,8 @@ | GET | /api/auth/users | 用户列表 | | PUT | /api/auth/users/:id | 编辑用户 | | PUT | /api/auth/users/:id/password | 重置密码 | -| DELETE | /api/auth/users/:id | 删除用户 | +| PUT | /api/rbac/users/:id/archive | 归档用户 | +| PUT | /api/rbac/users/:id/restore | 恢复用户 | ### 业务模块 | 方法 | 路径 | 说明 |