From 048a6ec969cacc03d861fcd45920fe97a00a2b75 Mon Sep 17 00:00:00 2001 From: QiuSW <105186638@qq.com> Date: Thu, 13 Aug 2026 09:25:26 +0800 Subject: [PATCH] fix: restore Sense permission navigation (#44) --- Sense/ui/package.json | 4 +-- Sense/ui/src/layout/AppLayout.vue | 14 +++-------- Sense/ui/src/layout/navigation.js | 18 ++++++++++++++ Sense/ui/tests/navigation.test.cjs | 39 ++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 13 deletions(-) create mode 100644 Sense/ui/src/layout/navigation.js create mode 100644 Sense/ui/tests/navigation.test.cjs diff --git a/Sense/ui/package.json b/Sense/ui/package.json index 8ff77bd..11f00ba 100644 --- a/Sense/ui/package.json +++ b/Sense/ui/package.json @@ -10,7 +10,8 @@ "scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build", - "lint": "eslint \"src/**/*.{js,vue}\"" + "lint": "eslint \"src/**/*.{js,vue}\"", + "test:navigation": "node --test tests/navigation.test.cjs" }, "dependencies": { "@element-plus/icons-vue": "2.3.2", @@ -50,4 +51,3 @@ "not dead" ] } - diff --git a/Sense/ui/src/layout/AppLayout.vue b/Sense/ui/src/layout/AppLayout.vue index fbe0b96..d826b52 100644 --- a/Sense/ui/src/layout/AppLayout.vue +++ b/Sense/ui/src/layout/AppLayout.vue @@ -58,22 +58,14 @@ import { computed, ref } from 'vue' import { useRouter } from 'vue-router' import { useStore } from 'vuex' +import { buildNavigation } from './navigation' + const router = useRouter() const store = useStore() const collapsed = ref(false) const navigation = computed(() => { - const root = router.getRoutes().find((route) => route.path === '/') const permissions = store.getters['sense-identity/permissions'] || [] - return (root?.children || []) - .filter((route) => route.meta?.title && !route.meta?.hidden) - .filter((route) => !route.meta?.permission || permissions.includes(route.meta.permission)) - .map((route) => ({ - path: route.path ? `/${route.path}`.replace('//', '/') : '/', - title: route.meta.title, - icon: route.meta.icon, - order: route.meta.order || 0 - })) - .sort((left, right) => left.order - right.order) + return buildNavigation(router.getRoutes(), permissions) }) async function logout() { diff --git a/Sense/ui/src/layout/navigation.js b/Sense/ui/src/layout/navigation.js new file mode 100644 index 0000000..a8cd0f0 --- /dev/null +++ b/Sense/ui/src/layout/navigation.js @@ -0,0 +1,18 @@ +function buildNavigation(routes, permissions = []) { + const layout = routes + .filter((route) => route.path === '/' && Array.isArray(route.children) && route.children.length > 0) + .sort((left, right) => right.children.length - left.children.length)[0] + + return (layout?.children || []) + .filter((route) => route.meta?.title && !route.meta?.hidden) + .filter((route) => !route.meta?.permission || permissions.includes(route.meta.permission)) + .map((route) => ({ + path: route.path ? `/${route.path}`.replace('//', '/') : '/', + title: route.meta.title, + icon: route.meta.icon, + order: route.meta.order || 0 + })) + .sort((left, right) => left.order - right.order) +} + +module.exports = { buildNavigation } diff --git a/Sense/ui/tests/navigation.test.cjs b/Sense/ui/tests/navigation.test.cjs new file mode 100644 index 0000000..c0cf2d2 --- /dev/null +++ b/Sense/ui/tests/navigation.test.cjs @@ -0,0 +1,39 @@ +const assert = require('node:assert/strict') +const test = require('node:test') + +const { buildNavigation } = require('../src/layout/navigation.js') + +test('selects the layout record when normalized routes contain duplicate root paths', () => { + const routes = [ + { path: '/', name: 'sense-dashboard', children: [], meta: { title: '工作台' } }, + { path: '/devices', name: 'sense-devices', children: [], meta: { title: '设备管理' } }, + { + path: '/', + children: [ + { path: 'devices', meta: { title: '设备管理', permission: 'device.read', order: 10 } }, + { path: '', meta: { title: '工作台', order: 0 } }, + { path: 'users', meta: { title: '用户与权限', permission: 'identity.users.read', order: 90 } } + ] + } + ] + + assert.deepEqual(buildNavigation(routes, ['device.read']), [ + { path: '/', title: '工作台', icon: undefined, order: 0 }, + { path: '/devices', title: '设备管理', icon: undefined, order: 10 } + ]) +}) + +test('returns no unauthorized or hidden entries', () => { + const routes = [{ + path: '/', + children: [ + { path: '', meta: { title: '工作台' } }, + { path: 'users', meta: { title: '用户与权限', permission: 'identity.users.read' } }, + { path: 'internal', meta: { title: '内部页', hidden: true } } + ] + }] + + assert.deepEqual(buildNavigation(routes), [ + { path: '/', title: '工作台', icon: undefined, order: 0 } + ]) +})