align(用户菜单授权): 创建/编辑用户菜单权限补齐前端客户端(app)菜单并按类型分区落库

用户管理菜单权限此前只含后台 admin(单类型):前端授权树/回显仅拉 menuType=admin,
后端 replaceDirectPermissions 也固定用 ADMIN 作用域写。现改为同时覆盖 后台(admin)+前端客户端(app):
- 前端 user-menu-auth 节点携带 type,api 并行拉取 admin/app 两类可授权树与已授权 id 合并去重,树内两类根并存(账号与权限/视频/前端工具/运营工具/后勤工具等)
- 后端 PermissionMenuService 新增 resolveMenuTypes(按 id 解析类型);AdminUserService create/update 把勾选 id 拆 admin/app 分区整树替换(internal 不纳入)
- 前端 1556 测试全绿 + build 通过;后端单测(AdminUserServiceTest/PermissionMenuServiceTest/Controller/PermissionMenuResolveTypeTest) EXIT 0
- 本地 E2E:创建用户写入 admin=7+app=3 → 按类型回读 admin[7]/app[3],删除正常
This commit is contained in:
2026-09-06 15:32:43 +08:00
parent 8034d916bc
commit 898fae4cb3
7 changed files with 184 additions and 19 deletions
@@ -0,0 +1,38 @@
import test from 'node:test'
import assert from 'node:assert/strict'
import { readSource } from './helpers.ts'
import {
ADMIN_MENU_TYPE,
APP_MENU_TYPE,
parseMenuOptionList,
parsePermissionMenuItem,
} from '../src/pages/account/user-menu-auth.ts'
// 验收反馈:用户创建/编辑的菜单权限配置要同时包含 后台(admin) 与 前端客户端(app) 两类菜单,
// 并按类型分区落库(internal 不纳入)。
test('align_user_menu_auth_both_types_tree_nodes', () => {
// 授权节点携带 type:admin/app 两类菜单都能进同一棵树。
assert.equal(APP_MENU_TYPE, 'app')
const admin = parsePermissionMenuItem({ id: 1, name: '账号权限', parent_id: null, sort_order: 1 }, ADMIN_MENU_TYPE)
assert.equal(admin?.type, ADMIN_MENU_TYPE)
const app = parseMenuOptionList(
[{ id: 2, name: '视频', parent_id: null, sort_order: 1, column_key: 'wb' }],
APP_MENU_TYPE,
)
assert.equal(app[0].type, APP_MENU_TYPE)
})
test('align_user_menu_auth_both_types_fetch_and_submit_source', () => {
const api = readSource('src/pages/account/user-menu-auth-api.ts')
assert.match(api, /APP_MENU_TYPE/, '拉取/回显含客户端类型')
assert.match(api, /Promise\.all/, '两类菜单并行拉取')
assert.match(api, /normalizeMenuIds/, '两类已授权 id 合并去重')
// 提交仍由后端把勾选 id 按类型分区写(user PUT),前端不再限定单类型。
const service = readSource('../backend-java/src/main/java/com/nanri/aiimage/modules/admin/service/AdminUserService.java')
assert.match(service, /resolveMenuTypes/, '后端按菜单 id 解析类型')
assert.match(service, /MENU_TYPE_ADMIN/, 'admin 分区写')
assert.match(service, /MENU_TYPE_APP/, 'app 分区写')
const auth = readSource('src/pages/account/user-menu-auth.ts')
assert.match(auth, /type: string/, '授权节点携带 type')
})