task-50(账号/权限页面): 实现用户菜单授权提交
buildUserColumnPermissionPayload 序列化勾选 id 为 {columnIds}(去重升序、空=清空),
镜像 Java UserColumnPermissionUpdateRequest;submitUserMenuAuth PUT /api/admin/
permission-users/{userId}/columns(menuType=admin) 整树替换,success=false 由 unwrap 抛后端 message。
8 用例全过,363 单测 + build 绿。
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
/** 用户菜单授权数据加载适配(任务 49):拉取可授权菜单树 + 用户已授权 id。 */
|
/** 用户菜单授权数据加载适配(任务 49):拉取可授权菜单树 + 用户已授权 id。 */
|
||||||
import { http } from '@/api/http'
|
import { http } from '@/api/http'
|
||||||
|
import { unwrap } from '@/api/envelope'
|
||||||
import {
|
import {
|
||||||
ADMIN_MENU_TYPE,
|
ADMIN_MENU_TYPE,
|
||||||
buildMenuOptionTree,
|
buildMenuOptionTree,
|
||||||
|
buildUserColumnPermissionPayload,
|
||||||
parseMenuOptionList,
|
parseMenuOptionList,
|
||||||
parseUserGrantedColumnIds,
|
parseUserGrantedColumnIds,
|
||||||
type MenuOptionNode,
|
type MenuOptionNode,
|
||||||
@@ -35,3 +37,12 @@ export async function loadUserMenuAuth(userId: number): Promise<UserMenuAuthData
|
|||||||
const [tree, checkedIds] = await Promise.all([fetchGrantableMenus(), fetchUserGrantedColumnIds(userId)])
|
const [tree, checkedIds] = await Promise.all([fetchGrantableMenus(), fetchUserGrantedColumnIds(userId)])
|
||||||
return { tree, checkedIds }
|
return { tree, checkedIds }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 提交某用户的直接授权菜单 id(整树替换);success=false 由 unwrap 抛后端 message。 */
|
||||||
|
export async function submitUserMenuAuth(userId: number, columnIds: unknown): Promise<void> {
|
||||||
|
const payload = buildUserColumnPermissionPayload(columnIds)
|
||||||
|
const { data } = await http.put<unknown>(`${USER_PERMISSION_COLUMNS_ENDPOINT}/${userId}/columns`, payload, {
|
||||||
|
params: { menuType: ADMIN_MENU_TYPE },
|
||||||
|
})
|
||||||
|
unwrap<unknown>(data)
|
||||||
|
}
|
||||||
|
|||||||
@@ -95,3 +95,8 @@ export function normalizeMenuIds(raw: unknown): number[] {
|
|||||||
}
|
}
|
||||||
return [...ids].sort((a, b) => a - b)
|
return [...ids].sort((a, b) => a - b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 提交授权请求体(任务 50):{columnIds} 与 Java UserColumnPermissionUpdateRequest 对齐。 */
|
||||||
|
export function buildUserColumnPermissionPayload(raw: unknown): { columnIds: number[] } {
|
||||||
|
return { columnIds: normalizeMenuIds(raw) }
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import test from 'node:test'
|
||||||
|
import assert from 'node:assert/strict'
|
||||||
|
import { readSource } from './helpers.ts'
|
||||||
|
import { ADMIN_MENU_TYPE, buildUserColumnPermissionPayload } from '../src/pages/account/user-menu-auth.ts'
|
||||||
|
|
||||||
|
test('test_task_050_user_menu_auth_submit_normal_primary_path', () => {
|
||||||
|
// 正常主路径:勾选的 column id 序列化为 {columnIds}(去重升序),镜像后端请求体。
|
||||||
|
assert.deepEqual(buildUserColumnPermissionPayload([3, 1, 2]), { columnIds: [1, 2, 3] })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_task_050_user_menu_auth_submit_normal_variant_input', () => {
|
||||||
|
// 正常变体:空勾选 = 清空授权(合法提交 {columnIds: []})。
|
||||||
|
assert.deepEqual(buildUserColumnPermissionPayload([]), { columnIds: [] })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_task_050_user_menu_auth_submit_normal_repeated_operation_is_idempotent', () => {
|
||||||
|
// 正常重复:序列化不改输入、每次产出独立数组不共享引用。
|
||||||
|
const input = [5, 4]
|
||||||
|
const first = buildUserColumnPermissionPayload(input)
|
||||||
|
assert.deepEqual(buildUserColumnPermissionPayload(input), first)
|
||||||
|
input.push(6)
|
||||||
|
assert.deepEqual(first.columnIds, [4, 5])
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_task_050_user_menu_auth_submit_boundary_empty_input', () => {
|
||||||
|
// 边界空值:null/undefined 输入视为清空,不崩溃。
|
||||||
|
assert.deepEqual(buildUserColumnPermissionPayload(null), { columnIds: [] })
|
||||||
|
assert.deepEqual(buildUserColumnPermissionPayload(undefined), { columnIds: [] })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_task_050_user_menu_auth_submit_boundary_single_item', () => {
|
||||||
|
// 边界单元素:单 id 提交。
|
||||||
|
assert.deepEqual(buildUserColumnPermissionPayload([7]), { columnIds: [7] })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_task_050_user_menu_auth_submit_boundary_limit_or_missing_field', () => {
|
||||||
|
// 边界上限/非法项:负数/0/小数/非数字被过滤,重复去重。
|
||||||
|
assert.deepEqual(buildUserColumnPermissionPayload([2, 1, 2, -1, 0, 3.7, 'x' as never]), {
|
||||||
|
columnIds: [1, 2, 3],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_task_050_user_menu_auth_submit_invalid_input_rejected', () => {
|
||||||
|
// 异常输入:请求体只含 columnIds(admin 菜单 id),不含越权字段。
|
||||||
|
assert.deepEqual(Object.keys(buildUserColumnPermissionPayload([1])).sort(), ['columnIds'])
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_task_050_user_menu_auth_submit_dependency_failure_returns_actionable_message', () => {
|
||||||
|
// 依赖失败/提交走 adapter:PUT permission-users/{id}/columns(menuType=admin),后端失败消息不被吞。
|
||||||
|
const api = readSource('src/pages/account/user-menu-auth-api.ts')
|
||||||
|
assert.match(api, /http\.put/)
|
||||||
|
assert.match(api, /permission-users/)
|
||||||
|
assert.match(api, /buildUserColumnPermissionPayload/)
|
||||||
|
assert.match(api, /menuType:\s*ADMIN_MENU_TYPE/)
|
||||||
|
assert.match(api, /unwrap|parseUserGranted|Promise\.reject|throw/) // 失败仍会向上抛、可提示
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user