diff --git a/frontend/src/assets/iconfont/iconfont.css b/frontend/src/assets/iconfont/iconfont.css index 604025f65..7bcac260d 100644 --- a/frontend/src/assets/iconfont/iconfont.css +++ b/frontend/src/assets/iconfont/iconfont.css @@ -1,9 +1,9 @@ @font-face { font-family: "iconfont"; /* Project id 4776196 */ - src: url('iconfont.woff2?t=1755181498446') format('woff2'), - url('iconfont.woff?t=1755181498446') format('woff'), - url('iconfont.ttf?t=1755181498446') format('truetype'), - url('iconfont.svg?t=1755181498446#iconfont') format('svg'); + src: url('iconfont.woff2?t=1760516880031') format('woff2'), + url('iconfont.woff?t=1760516880031') format('woff'), + url('iconfont.ttf?t=1760516880031') format('truetype'), + url('iconfont.svg?t=1760516880031#iconfont') format('svg'); } .iconfont { @@ -14,6 +14,86 @@ -moz-osx-font-smoothing: grayscale; } +.p-run-menu:before { + content: "\e636"; +} + +.p-ssh-menu:before { + content: "\e668"; +} + +.p-mcp-menu:before { + content: "\e62b"; +} + +.p-ai-menu:before { + content: "\e7bf"; +} + +.p-moxing-menu:before { + content: "\e62c"; +} + +.p-ah-menu:before { + content: "\e6ba"; +} + +.p-tamper-menu:before { + content: "\e61c"; +} + +.p-ssl-menu:before { + content: "\e7b0"; +} + +.p-file-menu:before { + content: "\e609"; +} + +.p-system-monitor-menu:before { + content: "\e621"; +} + +.p-gpu-menu:before { + content: "\e631"; +} + +.p-waf-menu:before { + content: "\e623"; +} + +.p-xsetting-menu:before { + content: "\e624"; +} + +.p-disk-menu:before { + content: "\e6e5"; +} + +.p-exchange-menu:before { + content: "\e625"; +} + +.p-mobile-menu:before { + content: "\e628"; +} + +.p-process-menu:before { + content: "\ec35"; +} + +.p-firewalld-menu:before { + content: "\e798"; +} + +.p-monitor-menu:before { + content: "\e64a"; +} + +.p-node-menu:before { + content: "\e813"; +} + .p-featureshitu:before { content: "\e63e"; } diff --git a/frontend/src/assets/iconfont/iconfont.js b/frontend/src/assets/iconfont/iconfont.js index c21755d94..49172c739 100644 --- a/frontend/src/assets/iconfont/iconfont.js +++ b/frontend/src/assets/iconfont/iconfont.js @@ -1 +1 @@ -window._iconfont_svg_string_4776196='',(a=>{var l=(c=(c=document.getElementsByTagName("script"))[c.length-1]).getAttribute("data-injectcss"),c=c.getAttribute("data-disable-injectsvg");if(!c){var h,t,p,z,v,i=function(l,c){c.parentNode.insertBefore(l,c)};if(l&&!a.__iconfont__svg__cssinject__){a.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(l){console&&console.log(l)}}h=function(){var l,c=document.createElement("div");c.innerHTML=a._iconfont_svg_string_4776196,(c=c.getElementsByTagName("svg")[0])&&(c.setAttribute("aria-hidden","true"),c.style.position="absolute",c.style.width=0,c.style.height=0,c.style.overflow="hidden",c=c,(l=document.body).firstChild?i(c,l.firstChild):l.appendChild(c))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(h,0):(t=function(){document.removeEventListener("DOMContentLoaded",t,!1),h()},document.addEventListener("DOMContentLoaded",t,!1)):document.attachEvent&&(p=h,z=a.document,v=!1,M(),z.onreadystatechange=function(){"complete"==z.readyState&&(z.onreadystatechange=null,d())})}function d(){v||(v=!0,p())}function M(){try{z.documentElement.doScroll("left")}catch(l){return void setTimeout(M,50)}d()}})(window); \ No newline at end of file +window._iconfont_svg_string_4776196='',(c=>{var l=(a=(a=document.getElementsByTagName("script"))[a.length-1]).getAttribute("data-injectcss"),a=a.getAttribute("data-disable-injectsvg");if(!a){var h,t,z,p,v,m=function(l,a){a.parentNode.insertBefore(l,a)};if(l&&!c.__iconfont__svg__cssinject__){c.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(l){console&&console.log(l)}}h=function(){var l,a=document.createElement("div");a.innerHTML=c._iconfont_svg_string_4776196,(a=a.getElementsByTagName("svg")[0])&&(a.setAttribute("aria-hidden","true"),a.style.position="absolute",a.style.width=0,a.style.height=0,a.style.overflow="hidden",a=a,(l=document.body).firstChild?m(a,l.firstChild):l.appendChild(a))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(h,0):(t=function(){document.removeEventListener("DOMContentLoaded",t,!1),h()},document.addEventListener("DOMContentLoaded",t,!1)):document.attachEvent&&(z=h,p=c.document,v=!1,d(),p.onreadystatechange=function(){"complete"==p.readyState&&(p.onreadystatechange=null,M())})}function M(){v||(v=!0,z())}function d(){try{p.documentElement.doScroll("left")}catch(l){return void setTimeout(d,50)}M()}})(window); \ No newline at end of file diff --git a/frontend/src/assets/iconfont/iconfont.json b/frontend/src/assets/iconfont/iconfont.json index 52426c5dc..48ce4458a 100644 --- a/frontend/src/assets/iconfont/iconfont.json +++ b/frontend/src/assets/iconfont/iconfont.json @@ -5,6 +5,146 @@ "css_prefix_text": "p-", "description": "", "glyphs": [ + { + "icon_id": "5041257", + "name": "运行环境", + "font_class": "run-menu", + "unicode": "e636", + "unicode_decimal": 58934 + }, + { + "icon_id": "36768791", + "name": "SSH密钥", + "font_class": "ssh-menu", + "unicode": "e668", + "unicode_decimal": 58984 + }, + { + "icon_id": "44603268", + "name": "MCP服务", + "font_class": "mcp-menu", + "unicode": "e62b", + "unicode_decimal": 58923 + }, + { + "icon_id": "44724034", + "name": "线性- AI建站", + "font_class": "ai-menu", + "unicode": "e7bf", + "unicode_decimal": 59327 + }, + { + "icon_id": "45110983", + "name": "大模型-大", + "font_class": "moxing-menu", + "unicode": "e62c", + "unicode_decimal": 58924 + }, + { + "icon_id": "15170483", + "name": "ahas 应用高可用", + "font_class": "ah-menu", + "unicode": "e6ba", + "unicode_decimal": 59066 + }, + { + "icon_id": "1598478", + "name": "网站防篡改", + "font_class": "tamper-menu", + "unicode": "e61c", + "unicode_decimal": 58908 + }, + { + "icon_id": "3141923", + "name": "SSL数字证书", + "font_class": "ssl-menu", + "unicode": "e7b0", + "unicode_decimal": 59312 + }, + { + "icon_id": "4608954", + "name": "文件夹,文件管理", + "font_class": "file-menu", + "unicode": "e609", + "unicode_decimal": 58889 + }, + { + "icon_id": "5653301", + "name": "监控", + "font_class": "system-monitor-menu", + "unicode": "e621", + "unicode_decimal": 58913 + }, + { + "icon_id": "7082471", + "name": "gpu", + "font_class": "gpu-menu", + "unicode": "e631", + "unicode_decimal": 58929 + }, + { + "icon_id": "7948556", + "name": "WAF", + "font_class": "waf-menu", + "unicode": "e623", + "unicode_decimal": 58915 + }, + { + "icon_id": "18270117", + "name": "界面设置", + "font_class": "xsetting-menu", + "unicode": "e624", + "unicode_decimal": 58916 + }, + { + "icon_id": "35113302", + "name": "磁盘管理", + "font_class": "disk-menu", + "unicode": "e6e5", + "unicode_decimal": 59109 + }, + { + "icon_id": "43864633", + "name": "文件互传", + "font_class": "exchange-menu", + "unicode": "e625", + "unicode_decimal": 58917 + }, + { + "icon_id": "397898", + "name": "移动端,手机端", + "font_class": "mobile-menu", + "unicode": "e628", + "unicode_decimal": 58920 + }, + { + "icon_id": "5767874", + "name": "任务进程", + "font_class": "process-menu", + "unicode": "ec35", + "unicode_decimal": 60469 + }, + { + "icon_id": "14095351", + "name": "防火墙", + "font_class": "firewalld-menu", + "unicode": "e798", + "unicode_decimal": 59288 + }, + { + "icon_id": "15009371", + "name": "监测数据", + "font_class": "monitor-menu", + "unicode": "e64a", + "unicode_decimal": 58954 + }, + { + "icon_id": "22231530", + "name": "Data server", + "font_class": "node-menu", + "unicode": "e813", + "unicode_decimal": 59411 + }, { "icon_id": "18536446", "name": "feature视图", diff --git a/frontend/src/assets/iconfont/iconfont.svg b/frontend/src/assets/iconfont/iconfont.svg index 8c1eacd35..326961f84 100644 --- a/frontend/src/assets/iconfont/iconfont.svg +++ b/frontend/src/assets/iconfont/iconfont.svg @@ -14,6 +14,46 @@ /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/iconfont/iconfont.ttf b/frontend/src/assets/iconfont/iconfont.ttf index af631a232..cf49cabc8 100644 Binary files a/frontend/src/assets/iconfont/iconfont.ttf and b/frontend/src/assets/iconfont/iconfont.ttf differ diff --git a/frontend/src/assets/iconfont/iconfont.woff b/frontend/src/assets/iconfont/iconfont.woff index cd43b036a..d428deb40 100644 Binary files a/frontend/src/assets/iconfont/iconfont.woff and b/frontend/src/assets/iconfont/iconfont.woff differ diff --git a/frontend/src/assets/iconfont/iconfont.woff2 b/frontend/src/assets/iconfont/iconfont.woff2 index 54396194f..de8fd556e 100644 Binary files a/frontend/src/assets/iconfont/iconfont.woff2 and b/frontend/src/assets/iconfont/iconfont.woff2 differ diff --git a/frontend/src/layout/components/Sidebar/components/SubItem.vue b/frontend/src/layout/components/Sidebar/components/SubItem.vue index fe58cbc60..2dc98aa7d 100644 --- a/frontend/src/layout/components/Sidebar/components/SubItem.vue +++ b/frontend/src/layout/components/Sidebar/components/SubItem.vue @@ -7,7 +7,7 @@ {{ $t(subItem.meta?.title as string, 2) }} - + @@ -18,17 +18,22 @@ {{ $t(subItem.meta?.title as string, 2) }} - - - - - + + + + + + + + + @@ -39,7 +44,7 @@ import { RouteRecordRaw } from 'vue-router'; import SvgIcon from '@/components/svg-icon/svg-icon.vue'; -defineProps<{ menuList: RouteRecordRaw[] }>(); +defineProps<{ menuList: RouteRecordRaw[]; level?: number }>(); const goUpage = () => { window.open('https://www.lxware.cn/upage', '_blank', 'noopener,noreferrer'); diff --git a/frontend/src/layout/components/Sidebar/index.vue b/frontend/src/layout/components/Sidebar/index.vue index bb7cea311..8594e4b59 100644 --- a/frontend/src/layout/components/Sidebar/index.vue +++ b/frontend/src/layout/components/Sidebar/index.vue @@ -20,7 +20,7 @@ @select="handleMenuClick" class="custom-menu" > - + @@ -53,7 +53,9 @@ const activeMenu = computed(() => { const isCollapse = computed((): boolean => menuStore.isCollapse); let routerMenus = computed((): RouteRecordRaw[] => { - return menuStore.menuList.filter((route) => route.meta && !route.meta.hideInSidebar) as RouteRecordRaw[]; + const aa = menuStore.menuList.filter((route) => route.meta && !route.meta.hideInSidebar) as RouteRecordRaw[]; + console.log(aa); + return aa; }); const screenWidth = ref(0); @@ -151,49 +153,50 @@ function sortByMap(map: Map) { } function adjustAndCleanMenu(menuItem, list) { - const cleanList = JSON.parse(JSON.stringify(list)); + const menuList = JSON.parse(JSON.stringify(list)); const orderMap = new Map(); menuItem.forEach((item, index) => { orderMap.set(item.label, index); }); - const newRootList = []; const itemMap = new Map(); - cleanList.forEach((parent) => { - if (!parent.children) { - parent.children = []; - } + for (const parent of menuList) { itemMap.set(parent.name, parent); - parent.children.forEach((child) => { - itemMap.set(child.name, child); - }); - }); - - menuItem.forEach((refItem) => { - const refName = refItem.label; - if (orderMap.has(refName)) { - const targetItem = itemMap.get(refName); - - if (targetItem) { - newRootList.push(targetItem); - for (const parent of cleanList) { - if (parent.children && parent.children.length > 0) { - const originalLength = parent.children.length; - parent.children = parent.children.filter((child) => child.name !== refName); - if (parent.children.length < originalLength) { - break; - } - } - } + if (Array.isArray(parent.children)) { + for (const child of parent.children) { + itemMap.set(child.name, child); } } - }); - newRootList.sort((a, b) => { + } + + function buildTree(refList) { + const result = []; + + for (const ref of refList) { + const refName = ref.label; + const matched = itemMap.get(refName); + + if (!matched) continue; + + if (Array.isArray(ref.children) && ref.children.length > 0) { + matched.children = buildTree(ref.children); + } else { + delete matched.children; + } + + result.push(matched); + } + + return result; + } + + const newMenu = buildTree(menuItem); + newMenu.sort((a, b) => { const indexA = orderMap.get(a.name) ?? Infinity; const indexB = orderMap.get(b.name) ?? Infinity; return indexA - indexB; }); - return newRootList; + return newMenu; } onMounted(() => { diff --git a/frontend/src/routers/modules/ai.ts b/frontend/src/routers/modules/ai.ts index 9e09c61ad..c6dfd58ff 100644 --- a/frontend/src/routers/modules/ai.ts +++ b/frontend/src/routers/modules/ai.ts @@ -16,6 +16,7 @@ const databaseRouter = { name: 'OllamaModel', component: () => import('@/views/ai/model/index.vue'), meta: { + icon: 'p-moxing-menu', title: 'aiTools.model.model', requiresAuth: true, }, @@ -25,6 +26,7 @@ const databaseRouter = { name: 'MCPServer', component: () => import('@/views/ai/mcp/server/index.vue'), meta: { + icon: 'p-mcp-menu', title: 'menu.mcp', requiresAuth: true, }, @@ -34,6 +36,7 @@ const databaseRouter = { name: 'GPU', component: () => import('@/views/ai/gpu/index.vue'), meta: { + icon: 'p-gpu-menu', title: 'aiTools.gpu.gpu', requiresAuth: true, }, diff --git a/frontend/src/routers/modules/host.ts b/frontend/src/routers/modules/host.ts index 17d110d93..eab028410 100644 --- a/frontend/src/routers/modules/host.ts +++ b/frontend/src/routers/modules/host.ts @@ -17,6 +17,7 @@ const hostRouter = { props: true, component: () => import('@/views/host/file-management/index.vue'), meta: { + icon: 'p-file-menu', title: 'menu.files', requiresAuth: false, }, @@ -26,6 +27,7 @@ const hostRouter = { name: 'Monitorx', component: () => import('@/views/host/monitor/monitor/index.vue'), meta: { + icon: 'p-system-monitor-menu', title: 'menu.monitor', requiresAuth: false, }, @@ -47,6 +49,7 @@ const hostRouter = { name: 'FirewallPort', component: () => import('@/views/host/firewall/port/index.vue'), meta: { + icon: 'p-firewalld-menu', activeMenu: '/hosts/firewall/port', title: 'menu.firewall', detail: 'firewall.portRule', @@ -83,6 +86,7 @@ const hostRouter = { props: true, component: () => import('@/views/host/disk-management/disk/index.vue'), meta: { + icon: 'p-disk-menu', title: 'menu.disk', requiresAuth: false, }, @@ -92,6 +96,7 @@ const hostRouter = { name: 'Process', component: () => import('@/views/host/process/process/index.vue'), meta: { + icon: 'p-process-menu', title: 'menu.processManage', detail: 'menu.process', activeMenu: '/hosts/process/process', @@ -116,6 +121,7 @@ const hostRouter = { name: 'SSH', component: () => import('@/views/host/ssh/ssh/index.vue'), meta: { + icon: 'p-ssh-menu', title: 'menu.ssh', detail: 'menu.config', activeMenu: '/hosts/ssh/ssh', diff --git a/frontend/src/routers/modules/website.ts b/frontend/src/routers/modules/website.ts index c280ca916..5b50dcd2c 100644 --- a/frontend/src/routers/modules/website.ts +++ b/frontend/src/routers/modules/website.ts @@ -16,6 +16,7 @@ const webSiteRouter = { name: 'Website', component: () => import('@/views/website/website/index.vue'), meta: { + icon: 'p-website', title: 'menu.website', requiresAuth: false, }, @@ -37,6 +38,7 @@ const webSiteRouter = { name: 'SSL', component: () => import('@/views/website/ssl/index.vue'), meta: { + icon: 'p-ssl-menu', title: 'menu.ssl', requiresAuth: false, }, @@ -46,6 +48,7 @@ const webSiteRouter = { name: 'PHP', component: () => import('@/views/website/runtime/php/index.vue'), meta: { + icon: 'p-run-menu', title: 'menu.runtime', detail: 'PHP', activeMenu: '/websites/runtimes/php', diff --git a/frontend/src/views/setting/alert/setting/index.vue b/frontend/src/views/setting/alert/setting/index.vue index f5bbfcec6..e223e3822 100644 --- a/frontend/src/views/setting/alert/setting/index.vue +++ b/frontend/src/views/setting/alert/setting/index.vue @@ -11,7 +11,6 @@