fix(users): 自己可改显示名、超管可在编辑里提升超管(修「保存失败/禁止修改自己的账户」)

站长反馈:在 admin 模式下仍无法修改用户信息,弹「禁止在用户管理中修改自己的账户」;
另外角色下拉里没有「技术运维」。

1) 自己改自己:原来一律禁止 → 现在**只允许改姓名(显示名)**,其余(账号名/年级/班级/
   状态/角色/密码)只要动了就仍然拒绝。这样站长能在「用户管理」里把 admin 的显示名
   改成自己的名字(登录名仍是 admin,应急登录不受影响)。
   状态比较忽略大小写:库里是 active,客户端历史版本可能发 ACTIVE,不该因此判定"改了状态"。

2) 超管可在通用编辑接口里把别人提升为 SUPER_ADMIN(站长要求下拉里要有「技术运维」):
   新增 allowPromoteBySuper 例外 —— 仅当登录者是 SUPER_ADMIN、目标角色设为 SUPER_ADMIN、
   且目标不是初始账号(ID=1,本来就是超管)时放行;非超管仍被 canChangeRoleOf 拦住。
   与 POST /api/admin/users/{id}/promote-super 效果一致,两条路都能走。
This commit is contained in:
2026-09-30 22:58:10 +08:00
parent dfb4891022
commit deb71875c1
+29 -3
View File
@@ -109,13 +109,30 @@ export default defineEventHandler(async (event) => {
}
}
// 2. 禁止对自身进行任何用户管理操作(包括角色、资料、状态、密码等)
/*
* 2. 自己改自己:**只允许改姓名(显示名)**,其余一律禁止。
*
* 站长要在「用户管理」里把 admin 的显示名改成自己的名字(登录名仍是 admin),
* 原来这里是"自己一律不能改",于是他只看到「禁止在用户管理中修改自己的账户」。
* 放宽到"只有姓名变了、其它字段一个都没动"是安全的:改不了角色/状态/密码/账号名,
* 也提不了权,只是换个显示名而已(等价于个人资料页改名字)。
*/
if (String(userId) === String(user.id)) {
const gradeChanged = String(grade || '').trim() !== String(targetUser.grade || '').trim()
const classChanged = String(userClass || '').trim() !== String(targetUser.class || '').trim()
const statusChanged =
!!status && String(status).toLowerCase() !== String(targetUser.status || '').toLowerCase()
const roleChanged = !!role && role !== targetUser.role
const onlyNameChanged =
nameChanged && !usernameChanged && !gradeChanged && !classChanged && !statusChanged && !roleChanged && !password
if (!onlyNameChanged) {
throw createError({
statusCode: 400,
statusMessage: '禁止在用户管理中修改自己的账户'
statusMessage: '禁止在用户管理中修改自己的账户(自己只能改「姓名」,其它请到「设置」里操作)'
})
}
}
// 3. 非超级管理员必须严格高于目标角色级别
if (user.role !== 'SUPER_ADMIN' && currentLevel <= targetLevel) {
@@ -144,7 +161,16 @@ export default defineEventHandler(async (event) => {
// 角色权限控制(统一使用 canChangeRoleOf 语义化检查)
let validRole = targetUser.role
if (role && role !== targetUser.role) {
if (!canChangeRoleOf(user, targetUser, role)) {
/*
* 站长要求用户编辑表单的角色下拉里要有「技术运维」(SUPER_ADMIN)。
* 原 canChangeRoleOf() 一律禁止提升为 SUPER_ADMIN(网页版也这么设计),
* 这里对**超级管理员**放开这一条:只有超管能把别人提升为超管,且目标不能是初始账号(ID=1,它本来就是)。
* 效果与 POST /api/admin/users/{id}/promote-super 一致,两条路都可用。
*/
const allowPromoteBySuper =
user.role === 'SUPER_ADMIN' && role === 'SUPER_ADMIN' && targetUser.id !== 1
if (!allowPromoteBySuper && !canChangeRoleOf(user, targetUser, role)) {
throw createError({
statusCode: 403,
statusMessage: user.role === 'SUPER_ADMIN'