From 23e991722cf4009b4258de433a1f208237103ebf Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Fri, 11 Sep 2026 11:15:04 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/components/AdminSidebarMenu.test.ts | 3 +- src/core/navigation/adminNavigation.test.ts | 12 ++-- src/core/navigation/adminNavigation.ts | 14 +---- src/modules/iam/pages/RolesView.test.ts | 6 +- src/modules/iam/pages/RolesView.vue | 18 ++++-- src/modules/iam/utils/permissionTree.test.ts | 23 ++++++- src/modules/iam/utils/permissionTree.ts | 66 ++++++++++++++++++++ src/modules/suppliers/routes.ts | 2 +- 8 files changed, 115 insertions(+), 29 deletions(-) diff --git a/src/app/components/AdminSidebarMenu.test.ts b/src/app/components/AdminSidebarMenu.test.ts index 116661c4..0c1babf0 100644 --- a/src/app/components/AdminSidebarMenu.test.ts +++ b/src/app/components/AdminSidebarMenu.test.ts @@ -60,7 +60,8 @@ describe('AdminSidebarMenu', () => { const paths = wrapper.findAll('[data-kind="item"]').map((node) => node.attributes('data-index')) expect(groupTitles).toContain('客户管理') - expect(groupTitles).toContain('供应商中心') + expect(groupTitles).not.toContain('供应商中心') + expect(groupTitles).toContain('通用') expect(groupTitles).toContain('系统管理') expect(groupTitles).not.toContain('财务管理') expect(paths).toContain('/dashboard') diff --git a/src/core/navigation/adminNavigation.test.ts b/src/core/navigation/adminNavigation.test.ts index 56ff127c..eec419ae 100644 --- a/src/core/navigation/adminNavigation.test.ts +++ b/src/core/navigation/adminNavigation.test.ts @@ -14,7 +14,6 @@ describe('adminNavigation', () => { '客户管理', '国内仓', '海外派送', - '供应商中心', '货柜管理', '海外业务', '海外仓', @@ -38,11 +37,7 @@ describe('adminNavigation', () => { '整柜业务', ]) expect(adminNavigation.find((item) => item.key === 'customer-service')?.children?.map((item) => item.title)).toEqual(['异常订单', '客户回访']) - expect(adminNavigation.find((item) => item.key === 'supplier-center')?.children?.map((item) => item.title)).toEqual([ - '供应商列表', - '快递公司', - '往来单位', - ]) + expect(adminNavigation.find((item) => item.key === 'supplier-center')).toBeUndefined() expect(adminNavigation.find((item) => item.key === 'container-management')?.children?.map((item) => item.title)).toEqual([ '订舱列表', '拖车列表', @@ -63,6 +58,9 @@ describe('adminNavigation', () => { ]) expect(adminNavigation.find((item) => item.key === 'general')?.children?.map((item) => item.title)).toEqual([ '产品信息', + '供应商列表', + '快递公司', + '往来单位', '费用项目', '汇率管理', '仓库管理', @@ -211,7 +209,7 @@ describe('adminNavigation', () => { ])) const paths = getNavigationLeaves(filtered).map((item) => item.path) - expect(filtered.map((item) => item.title)).toEqual(['首页数据看板', '国内仓', '供应商中心', '通用']) + expect(filtered.map((item) => item.title)).toEqual(['首页数据看板', '国内仓', '通用']) expect(paths).toEqual([ '/dashboard', '/orders', diff --git a/src/core/navigation/adminNavigation.ts b/src/core/navigation/adminNavigation.ts index 9e0102c9..e4c2b908 100644 --- a/src/core/navigation/adminNavigation.ts +++ b/src/core/navigation/adminNavigation.ts @@ -25,7 +25,6 @@ import { PrototypeOverseasBusinessIcon, PrototypeOverseasWarehouseIcon, PrototypeSalesIcon, - PrototypeSupplierIcon, PrototypeSystemIcon, } from './prototypeMenuIcons' @@ -85,16 +84,6 @@ export const adminNavigation: AdminNavigationNode[] = [ { key: 'outbound-selfpick', title: '自提单', icon: ClipboardList, path: '/prototype/overseas-delivery/self-pickup' }, ], }, - { - key: 'supplier-center', - title: '供应商中心', - icon: PrototypeSupplierIcon, - children: [ - { key: 'supplier-list', title: '供应商列表', icon: ContactRound, path: '/suppliers', permission: 'platform:supplier:list' }, - { key: 'express-companies', title: '快递公司', icon: Truck, path: '/master-data/express-companies', permission: 'platform:express:list' }, - { key: 'counterparties', title: '往来单位', icon: ContactRound, path: '/master-data/counterparties', permission: 'platform:counterparty:list' }, - ], - }, { key: 'container-management', title: '货柜管理', @@ -171,6 +160,9 @@ export const adminNavigation: AdminNavigationNode[] = [ icon: PrototypeGeneralIcon, children: [ { key: 'general-product', title: '产品信息', icon: Database, path: '/prototype/general/product-information', hidden: true }, + { key: 'supplier-list', title: '供应商列表', icon: ContactRound, path: '/suppliers', permission: 'platform:supplier:list' }, + { key: 'express-companies', title: '快递公司', icon: Truck, path: '/master-data/express-companies', permission: 'platform:express:list' }, + { key: 'counterparties', title: '往来单位', icon: ContactRound, path: '/master-data/counterparties', permission: 'platform:counterparty:list' }, { key: 'general-fee', title: '费用项目', icon: Database, path: '/master-data/fee-items', permission: 'firstleg:fee-item:view' }, { key: 'exchange-rates', title: '汇率管理', icon: CircleDollarSign, path: '/overseas-master-data/exchange-rates', permission: 'platform:overseas-master-data:exchange-rate:list' }, { key: 'warehouses', title: '仓库管理', icon: WarehouseIcon, path: '/warehouses', permission: 'platform:warehouse:list' }, diff --git a/src/modules/iam/pages/RolesView.test.ts b/src/modules/iam/pages/RolesView.test.ts index 2ee54fdf..a6abbfc4 100644 --- a/src/modules/iam/pages/RolesView.test.ts +++ b/src/modules/iam/pages/RolesView.test.ts @@ -93,10 +93,12 @@ describe('RolesView', () => { vi.mocked(createPlatformRole).mockReset() }) - it('keeps directory, menu, and action permissions independently checkable', () => { + it('links menu groups and permissions so partial selections use the half-checked state', () => { const wrapper = mountView() - expect(wrapper.get('[data-testid="permission-tree"]').attributes('data-check-strictly')).toBe('true') + expect(wrapper.get('[data-testid="permission-tree"]').attributes('data-check-strictly')).toBe('false') + expect(rolesSource).not.toContain('check-strictly') + expect(rolesSource).not.toContain("disabled: 'disabled'") }) it('shows the role code in the default list layout', () => { diff --git a/src/modules/iam/pages/RolesView.vue b/src/modules/iam/pages/RolesView.vue index f3c0ad48..9ed4ebbf 100644 --- a/src/modules/iam/pages/RolesView.vue +++ b/src/modules/iam/pages/RolesView.vue @@ -24,8 +24,9 @@ import ListPageLayout from '@/shared/components/ListPageLayout.vue' import LoadErrorState from '@/shared/components/LoadErrorState.vue' import { useUnsavedWorkRegistration } from '@/core/unsaved-work/useUnsavedWorkRegistration' import { useAccessPreviewStore } from '@/core/access/accessPreview' +import { adminNavigation } from '@/core/navigation/adminNavigation' import type { Permission, Role } from '@/modules/iam/types' -import { buildPermissionTree, summarizePermissionSelection } from '@/modules/iam/utils/permissionTree' +import { buildNavigationPermissionTree, summarizePermissionSelection } from '@/modules/iam/utils/permissionTree' import { mapPlatformPermission } from '@/modules/iam/utils/platformPermission' interface TreeController { @@ -88,7 +89,9 @@ const roleColumns: DataTableColumn[] = [ { key: 'status', label: '状态', width: 88, slotName: 'status' }, ] const availablePermissions = computed(() => serverPermissions.value) -const permissionTree = computed(() => buildPermissionTree(availablePermissions.value)) +const permissionTree = computed(() => buildNavigationPermissionTree(availablePermissions.value, adminNavigation)) +const permissionGroupIds = computed(() => permissionTree.value.map((node) => node.id)) +const assignablePermissionIds = computed(() => new Set(availablePermissions.value.map((permission) => permission.id))) function applyFilters() { appliedFilters.value = { ...filters.value } @@ -144,8 +147,8 @@ function openEdit(row: Role) { } function selectedPermissionIds() { - const checked = treeRef.value?.getCheckedKeys(false).map(String) || [] - const halfChecked = treeRef.value?.getHalfCheckedKeys().map(String) || [] + const checked = treeRef.value?.getCheckedKeys(false).map(String).filter((id) => assignablePermissionIds.value.has(id)) || [] + const halfChecked = treeRef.value?.getHalfCheckedKeys().map(String).filter((id) => assignablePermissionIds.value.has(id)) || [] return [...new Set([...checked, ...halfChecked])] } @@ -258,7 +261,7 @@ onMounted(loadRoles) - + @@ -268,7 +271,10 @@ onMounted(loadRoles)