From 2077f871f8c32d3e7d40657a7e090a79e17b0a0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E8=87=AA=E8=BE=BE?= <980324341@qq.com> Date: Sat, 5 Sep 2026 15:07:57 +0800 Subject: [PATCH] =?UTF-8?q?task-50(=E8=B4=A6=E5=8F=B7/=E6=9D=83=E9=99=90?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2):=20=E5=AE=9E=E7=8E=B0=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E6=8E=88=E6=9D=83=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit buildUserColumnPermissionPayload 序列化勾选 id 为 {columnIds}(去重升序、空=清空), 镜像 Java UserColumnPermissionUpdateRequest;submitUserMenuAuth PUT /api/admin/ permission-users/{userId}/columns(menuType=admin) 整树替换,success=false 由 unwrap 抛后端 message。 8 用例全过,363 单测 + build 绿。 --- .../src/pages/account/user-menu-auth-api.ts | 11 ++++ .../src/pages/account/user-menu-auth.ts | 5 ++ admin-frontend-vue/tests/task-50.test.ts | 56 +++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 admin-frontend-vue/tests/task-50.test.ts diff --git a/admin-frontend-vue/src/pages/account/user-menu-auth-api.ts b/admin-frontend-vue/src/pages/account/user-menu-auth-api.ts index a846a9ed..5ec67f20 100644 --- a/admin-frontend-vue/src/pages/account/user-menu-auth-api.ts +++ b/admin-frontend-vue/src/pages/account/user-menu-auth-api.ts @@ -1,8 +1,10 @@ /** 用户菜单授权数据加载适配(任务 49):拉取可授权菜单树 + 用户已授权 id。 */ import { http } from '@/api/http' +import { unwrap } from '@/api/envelope' import { ADMIN_MENU_TYPE, buildMenuOptionTree, + buildUserColumnPermissionPayload, parseMenuOptionList, parseUserGrantedColumnIds, type MenuOptionNode, @@ -35,3 +37,12 @@ export async function loadUserMenuAuth(userId: number): Promise { + const payload = buildUserColumnPermissionPayload(columnIds) + const { data } = await http.put(`${USER_PERMISSION_COLUMNS_ENDPOINT}/${userId}/columns`, payload, { + params: { menuType: ADMIN_MENU_TYPE }, + }) + unwrap(data) +} diff --git a/admin-frontend-vue/src/pages/account/user-menu-auth.ts b/admin-frontend-vue/src/pages/account/user-menu-auth.ts index b2b71ce7..131e12be 100644 --- a/admin-frontend-vue/src/pages/account/user-menu-auth.ts +++ b/admin-frontend-vue/src/pages/account/user-menu-auth.ts @@ -95,3 +95,8 @@ export function normalizeMenuIds(raw: unknown): number[] { } return [...ids].sort((a, b) => a - b) } + +/** 提交授权请求体(任务 50):{columnIds} 与 Java UserColumnPermissionUpdateRequest 对齐。 */ +export function buildUserColumnPermissionPayload(raw: unknown): { columnIds: number[] } { + return { columnIds: normalizeMenuIds(raw) } +} diff --git a/admin-frontend-vue/tests/task-50.test.ts b/admin-frontend-vue/tests/task-50.test.ts new file mode 100644 index 00000000..9ec62c35 --- /dev/null +++ b/admin-frontend-vue/tests/task-50.test.ts @@ -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/) // 失败仍会向上抛、可提示 +})