align(菜单管理): 同级拖拽排序接线(手柄列+类型/父级分组+reorder带menu_type)、列表拉全量类型、类型文案后台/软件、弹窗补菜单类型下拉、父菜单候选按类型过滤(对齐 admin.js loadColumns/bindColumnDragSort/persistColumnOrder)
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
import test from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { readSource } from './helpers.ts'
|
||||
import {
|
||||
MENU_TYPE_OPTIONS,
|
||||
menuParentCandidates,
|
||||
menuSiblingGroupKey,
|
||||
menuTypeLabel,
|
||||
siblingOrderAfterDrop,
|
||||
toMenuReorderRequest,
|
||||
type MenuManageNode,
|
||||
} from '../src/pages/account/menu-manage-model.ts'
|
||||
|
||||
/** 对齐 admin.js:6799-6830(全量列/类型文案 后台|软件)与 6882-6964(同级拖拽 + reorder 载荷)。 */
|
||||
|
||||
function node(id: number, menuType = 'admin', parentId: number | null = null): MenuManageNode {
|
||||
return { id, name: `菜单${id}`, columnKey: `k${id}`, parentId, menuType, routePath: `/r/${id}`, sortOrder: id }
|
||||
}
|
||||
|
||||
test('align_menu_type_label_matches_reference', () => {
|
||||
// 参考:admin → 后台,其余一律 → 软件(含空值)。
|
||||
assert.equal(menuTypeLabel('admin'), '后台')
|
||||
assert.equal(menuTypeLabel('app'), '软件')
|
||||
assert.equal(menuTypeLabel('APP'), '软件')
|
||||
assert.equal(menuTypeLabel(null), '软件')
|
||||
assert.equal(menuTypeLabel(undefined), '软件')
|
||||
})
|
||||
|
||||
test('align_menu_type_options_backend_software', () => {
|
||||
assert.deepEqual(MENU_TYPE_OPTIONS, [
|
||||
{ value: 'admin', label: '后台' },
|
||||
{ value: 'app', label: '软件' },
|
||||
])
|
||||
})
|
||||
|
||||
test('align_menu_sibling_group_key_is_type_plus_parent', () => {
|
||||
assert.equal(menuSiblingGroupKey(node(1, 'admin', 5)), 'admin|5')
|
||||
assert.equal(menuSiblingGroupKey(node(2, 'app', null)), 'app|')
|
||||
assert.equal(menuSiblingGroupKey(node(3, 'app', 5)), 'app|5')
|
||||
})
|
||||
|
||||
test('align_menu_sibling_order_after_drop_before_target', () => {
|
||||
const group = [1, 2, 3, 4]
|
||||
assert.deepEqual(siblingOrderAfterDrop(group, 4, 2, false), [1, 4, 2, 3])
|
||||
})
|
||||
|
||||
test('align_menu_sibling_order_after_drop_after_target', () => {
|
||||
const group = [1, 2, 3, 4]
|
||||
assert.deepEqual(siblingOrderAfterDrop(group, 4, 2, true), [1, 2, 4, 3])
|
||||
})
|
||||
|
||||
test('align_menu_sibling_order_after_drop_invalid_returns_original', () => {
|
||||
const group = [1, 2, 3]
|
||||
assert.deepEqual(siblingOrderAfterDrop(group, 9, 2, false), group)
|
||||
assert.deepEqual(siblingOrderAfterDrop(group, 1, 9, true), group)
|
||||
assert.deepEqual(siblingOrderAfterDrop(group, 2, 2, false), group)
|
||||
assert.deepEqual(siblingOrderAfterDrop([], 1, 2, false), [])
|
||||
})
|
||||
|
||||
test('align_menu_parent_candidates_same_type_only', () => {
|
||||
const nodes = [node(1, 'admin', null), node(2, 'app', null), node(3, 'admin', 1), node(4, 'app', 2)]
|
||||
assert.deepEqual(menuParentCandidates(nodes, 'admin').map((n) => n.id), [1, 3])
|
||||
assert.deepEqual(menuParentCandidates(nodes, 'app').map((n) => n.id), [2, 4])
|
||||
})
|
||||
|
||||
test('align_menu_reorder_request_includes_menu_type', () => {
|
||||
// 参考 persistColumnOrder 载荷:{ menu_type, ordered_ids }。
|
||||
assert.deepEqual(toMenuReorderRequest('admin', [1, 2, 3]), { menu_type: 'admin', ordered_ids: [1, 2, 3] })
|
||||
assert.deepEqual(toMenuReorderRequest('', [1]), { menu_type: 'app', ordered_ids: [1] })
|
||||
})
|
||||
|
||||
test('align_menu_list_loads_all_types_no_filter', () => {
|
||||
// 参考 loadColumns 拉全量列(无 menuType 过滤),类型由列内区分。
|
||||
const api = readSource('src/pages/account/menu-manage-api.ts')
|
||||
assert.doesNotMatch(api, /params:\s*\{\s*menuType/, '列表请求不再按 admin 过滤')
|
||||
assert.match(api, /ordered_ids/, '重排载荷带 ordered_ids')
|
||||
assert.match(api, /menu_type/, '重排载荷带 menu_type')
|
||||
})
|
||||
|
||||
test('align_menu_page_drag_and_type_wiring', () => {
|
||||
const page = readSource('src/pages/account/MenusPage.vue')
|
||||
assert.match(page, /拖动每行左侧的手柄可调整同级菜单的显示顺序,松开后自动保存/, '顶部拖拽提示文案对齐')
|
||||
assert.match(page, /draggable/, '行手柄可拖拽')
|
||||
assert.match(page, /menuSiblingGroupKey/, '拖拽分组按类型+父级')
|
||||
assert.match(page, /MENU_TYPE_OPTIONS|菜单类型/, '新建/编辑弹窗含菜单类型下拉')
|
||||
assert.match(page, /menuParentCandidates/, '父菜单候选按类型过滤')
|
||||
})
|
||||
@@ -24,16 +24,16 @@ test('test_task_252_menus_list_normal_variant_input', () => {
|
||||
})
|
||||
|
||||
test('test_task_252_menus_list_normal_repeated_operation_is_idempotent', () => {
|
||||
// 类型映射幂等。
|
||||
assert.equal(menuTypeLabel('admin'), '后台菜单')
|
||||
assert.equal(menuTypeLabel('APP'), '应用菜单')
|
||||
// 类型映射幂等(对齐 admin.js:admin→后台,其余→软件)。
|
||||
assert.equal(menuTypeLabel('admin'), '后台')
|
||||
assert.equal(menuTypeLabel('APP'), '软件')
|
||||
assert.equal(menuTypeLabel('app'), menuTypeLabel('app'))
|
||||
})
|
||||
|
||||
test('test_task_252_menus_list_boundary_empty_input', () => {
|
||||
// 边界:未知类型归后台菜单;创建/编辑标题区分。
|
||||
assert.equal(menuTypeLabel(null), '后台菜单')
|
||||
assert.equal(menuTypeLabel(undefined), '后台菜单')
|
||||
// 边界:未知类型归软件;创建/编辑标题区分。
|
||||
assert.equal(menuTypeLabel(null), '软件')
|
||||
assert.equal(menuTypeLabel(undefined), '软件')
|
||||
const page = readSource('src/pages/account/MenusPage.vue')
|
||||
assert.match(page, /新增菜单/, '页头新增菜单入口')
|
||||
assert.match(page, /editingNode.*编辑菜单|编辑菜单/, '编辑态标题')
|
||||
|
||||
@@ -79,5 +79,7 @@ test('test_task_054_menu_manage_list_dependency_failure_returns_actionable_messa
|
||||
assert.match(api, /permission-menus/)
|
||||
assert.match(api, /parseMenuManageList/)
|
||||
assert.match(api, /buildMenuManageTree/)
|
||||
assert.match(api, /menuType:\s*ADMIN_MENU_TYPE|ADMIN_MENU_TYPE/)
|
||||
// 对齐 admin.js loadColumns:列表拉全量菜单(不再按 admin 类型过滤),类型在行内区分。
|
||||
assert.doesNotMatch(api, /menuType:\s*ADMIN_MENU_TYPE/, '列表请求不再过滤 menuType')
|
||||
assert.match(api, /menu_type/, '重排载荷带 menu_type')
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user