feat: Menu supports restoring default values (#10658)

This commit is contained in:
2025-10-16 14:40:09 +08:00 committed by GitHub
parent 2cebb1beca
commit e2efa20582
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 113 additions and 39 deletions

View file

@ -184,6 +184,22 @@ func (b *BaseApi) UpdateMenu(c *gin.Context) {
helper.Success(c) helper.Success(c)
} }
// @Tags Menu Setting
// @Summary Default menu
// @Accept json
// @Success 200
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /core/settings/menu/default [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"初始化菜单","formatEN":"Init menu."}
func (b *BaseApi) DefaultMenu(c *gin.Context) {
if err := settingService.DefaultMenu(); err != nil {
helper.InternalServer(c, err)
return
}
helper.Success(c)
}
// @Tags System Setting // @Tags System Setting
// @Summary Update system password // @Summary Update system password
// @Accept json // @Accept json

View file

@ -4,6 +4,7 @@ import (
"errors" "errors"
"github.com/1Panel-dev/1Panel/core/app/model" "github.com/1Panel-dev/1Panel/core/app/model"
"github.com/1Panel-dev/1Panel/core/global" "github.com/1Panel-dev/1Panel/core/global"
"github.com/1Panel-dev/1Panel/core/init/migration/helper"
"gorm.io/gorm" "gorm.io/gorm"
) )
@ -16,6 +17,7 @@ type ISettingRepo interface {
Create(key, value string) error Create(key, value string) error
Update(key, value string) error Update(key, value string) error
UpdateOrCreate(key, value string) error UpdateOrCreate(key, value string) error
DefaultMenu() error
} }
func NewISettingRepo() ISettingRepo { func NewISettingRepo() ISettingRepo {
@ -73,3 +75,9 @@ func (u *SettingRepo) UpdateOrCreate(key, value string) error {
} }
return global.DB.Model(&setting).UpdateColumn("value", value).Error return global.DB.Model(&setting).UpdateColumn("value", value).Error
} }
func (u *SettingRepo) DefaultMenu() error {
return global.DB.Model(&model.Setting{}).
Where("key = ?", "HideMenu").
Update("value", helper.LoadMenus()).Error
}

View file

@ -63,6 +63,7 @@ type ISettingService interface {
UpdateAppstoreConfig(req dto.AppstoreUpdate) error UpdateAppstoreConfig(req dto.AppstoreUpdate) error
GetAppstoreConfig() (*dto.AppstoreConfig, error) GetAppstoreConfig() (*dto.AppstoreConfig, error)
DefaultMenu() error
} }
func NewISettingService() ISettingService { func NewISettingService() ISettingService {
@ -764,3 +765,7 @@ func checkProxy(req dto.ProxyUpdate) error {
defer resp.Body.Close() defer resp.Body.Close()
return nil return nil
} }
func (u *SettingService) DefaultMenu() error {
return settingRepo.DefaultMenu()
}

View file

@ -3,55 +3,56 @@ package helper
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/1Panel-dev/1Panel/core/app/dto"
"github.com/1Panel-dev/1Panel/core/app/model" "github.com/1Panel-dev/1Panel/core/app/model"
"gorm.io/gorm" "gorm.io/gorm"
"strings" "strings"
"github.com/1Panel-dev/1Panel/core/app/dto"
) )
func LoadMenus() string { func LoadMenus() string {
item := []dto.ShowMenu{ item := []dto.ShowMenu{
{ID: "1", Disabled: true, Title: "menu.home", IsShow: true, Label: "Home-Menu", Path: "/"}, {ID: "1", Disabled: true, Title: "menu.home", IsShow: true, Label: "Home-Menu", Path: "/", Sort: 100},
{ID: "2", Disabled: true, Title: "menu.apps", IsShow: true, Label: "App-Menu", Path: "/apps/all"}, {ID: "2", Disabled: true, Title: "menu.apps", IsShow: true, Label: "App-Menu", Path: "/apps/all", Sort: 200},
{ID: "3", Disabled: false, Title: "menu.website", IsShow: true, Label: "Website-Menu", Path: "/websites", {ID: "3", Disabled: false, Title: "menu.website", IsShow: true, Label: "Website-Menu", Path: "/websites", Sort: 300,
Children: []dto.ShowMenu{ Children: []dto.ShowMenu{
{ID: "31", Disabled: false, Title: "menu.website", IsShow: true, Label: "Website", Path: "/websites"}, {ID: "31", Disabled: false, Title: "menu.website", IsShow: true, Label: "Website", Path: "/websites", Sort: 100},
{ID: "32", Disabled: false, Title: "menu.ssl", IsShow: true, Label: "SSL", Path: "/websites/ssl"}, {ID: "32", Disabled: false, Title: "menu.ssl", IsShow: true, Label: "SSL", Path: "/websites/ssl", Sort: 200},
{ID: "33", Disabled: false, Title: "menu.runtime", IsShow: true, Label: "PHP", Path: "/websites/runtimes/php"}, {ID: "33", Disabled: false, Title: "menu.runtime", IsShow: true, Label: "PHP", Path: "/websites/runtimes/php", Sort: 300},
}}, }},
{ID: "4", Disabled: false, Title: "menu.aiTools", IsShow: true, Label: "AI-Menu", Path: "/ai/model", {ID: "4", Disabled: false, Title: "menu.aiTools", IsShow: true, Label: "AI-Menu", Path: "/ai/model", Sort: 400,
Children: []dto.ShowMenu{ Children: []dto.ShowMenu{
{ID: "41", Disabled: false, Title: "aiTools.model.model", IsShow: true, Label: "OllamaModel", Path: "/ai/model"}, {ID: "41", Disabled: false, Title: "aiTools.model.model", IsShow: true, Label: "OllamaModel", Path: "/ai/model", Sort: 100},
{ID: "42", Disabled: false, Title: "menu.mcp", IsShow: true, Label: "MCPServer", Path: "/ai/mcp"}, {ID: "42", Disabled: false, Title: "menu.mcp", IsShow: true, Label: "MCPServer", Path: "/ai/mcp", Sort: 200},
{ID: "43", Disabled: false, Title: "aiTools.gpu.gpu", IsShow: true, Label: "GPU", Path: "/ai/gpu"}, {ID: "43", Disabled: false, Title: "aiTools.gpu.gpu", IsShow: true, Label: "GPU", Path: "/ai/gpu", Sort: 300},
}}, }},
{ID: "5", Disabled: false, Title: "menu.database", IsShow: true, Label: "Database-Menu", Path: "/databases"}, {ID: "5", Disabled: false, Title: "menu.database", IsShow: true, Label: "Database-Menu", Path: "/databases", Sort: 500},
{ID: "6", Disabled: false, Title: "menu.container", IsShow: true, Label: "Container-Menu", Path: "/containers"}, {ID: "6", Disabled: false, Title: "menu.container", IsShow: true, Label: "Container-Menu", Path: "/containers", Sort: 600},
{ID: "7", Disabled: false, Title: "menu.system", IsShow: true, Label: "System-Menu", Path: "/hosts/files", {ID: "7", Disabled: false, Title: "menu.system", IsShow: true, Label: "System-Menu", Path: "/hosts/files", Sort: 700,
Children: []dto.ShowMenu{ Children: []dto.ShowMenu{
{ID: "71", Disabled: false, Title: "menu.files", IsShow: true, Label: "File", Path: "/hosts/files"}, {ID: "71", Disabled: false, Title: "menu.files", IsShow: true, Label: "File", Path: "/hosts/files", Sort: 100},
{ID: "72", Disabled: false, Title: "menu.monitor", IsShow: true, Label: "Monitorx", Path: "/hosts/monitor/monitor"}, {ID: "72", Disabled: false, Title: "menu.monitor", IsShow: true, Label: "Monitorx", Path: "/hosts/monitor/monitor", Sort: 200},
{ID: "74", Disabled: false, Title: "menu.firewall", IsShow: true, Label: "FirewallPort", Path: "/hosts/firewall/port"}, {ID: "74", Disabled: false, Title: "menu.firewall", IsShow: true, Label: "FirewallPort", Path: "/hosts/firewall/port", Sort: 300},
{ID: "75", Disabled: false, Title: "menu.processManage", IsShow: true, Label: "Process", Path: "/hosts/process/process"}, {ID: "75", Disabled: false, Title: "menu.processManage", IsShow: true, Label: "Process", Path: "/hosts/process/process", Sort: 400},
{ID: "76", Disabled: false, Title: "menu.ssh", IsShow: true, Label: "SSH", Path: "/hosts/ssh/ssh"}, {ID: "76", Disabled: false, Title: "menu.ssh", IsShow: true, Label: "SSH", Path: "/hosts/ssh/ssh", Sort: 500},
{ID: "77", Disabled: false, Title: "menu.disk", IsShow: true, Label: "Disk", Path: "/hosts/disk", Sort: 600},
}}, }},
{ID: "8", Disabled: false, Title: "menu.terminal", IsShow: true, Label: "Terminal-Menu", Path: "/hosts/terminal"}, {ID: "8", Disabled: false, Title: "menu.terminal", IsShow: true, Label: "Terminal-Menu", Path: "/hosts/terminal", Sort: 800},
{ID: "10", Disabled: false, Title: "menu.cronjob", IsShow: true, Label: "Cronjob-Menu", Path: "/cronjobs"}, {ID: "10", Disabled: false, Title: "menu.cronjob", IsShow: true, Label: "Cronjob-Menu", Path: "/cronjobs", Sort: 900},
{ID: "9", Disabled: false, Title: "menu.toolbox", IsShow: true, Label: "Toolbox-Menu", Path: "/toolbox"}, {ID: "9", Disabled: false, Title: "menu.toolbox", IsShow: true, Label: "Toolbox-Menu", Path: "/toolbox", Sort: 1000},
{ID: "11", Disabled: false, Title: "xpack.menu", IsShow: true, Label: "Xpack-Menu", {ID: "11", Disabled: false, Title: "xpack.menu", IsShow: true, Label: "Xpack-Menu", Sort: 1100,
Children: []dto.ShowMenu{ Children: []dto.ShowMenu{
{ID: "118", Disabled: false, Title: "xpack.app.app", IsShow: true, Label: "XApp", Path: "/xpack/app"}, {ID: "118", Disabled: false, Title: "xpack.app.app", IsShow: true, Label: "XApp", Path: "/xpack/app", Sort: 100},
{ID: "112", Disabled: false, Title: "xpack.waf.name", IsShow: true, Label: "Dashboard", Path: "/xpack/waf/dashboard"}, {ID: "112", Disabled: false, Title: "xpack.waf.name", IsShow: true, Label: "Dashboard", Path: "/xpack/waf/dashboard", Sort: 200},
{ID: "111", Disabled: false, Title: "xpack.node.nodeManagement", IsShow: true, Label: "Node", Path: "/xpack/node"}, {ID: "111", Disabled: false, Title: "xpack.node.nodeManagement", IsShow: true, Label: "Node", Path: "/xpack/node", Sort: 300},
{ID: "119", Disabled: false, Title: "xpack.upage", IsShow: true, Label: "Upage", Path: "/xpack/upage"}, {ID: "119", Disabled: false, Title: "xpack.upage", IsShow: true, Label: "Upage", Path: "/xpack/upage", Sort: 400},
{ID: "113", Disabled: false, Title: "xpack.monitor.name", IsShow: true, Label: "MonitorDashboard", Path: "/xpack/monitor/dashboard"}, {ID: "113", Disabled: false, Title: "xpack.monitor.name", IsShow: true, Label: "MonitorDashboard", Path: "/xpack/monitor/dashboard", Sort: 500},
{ID: "114", Disabled: false, Title: "xpack.tamper.tamper", IsShow: true, Label: "Tamper", Path: "/xpack/tamper"}, {ID: "114", Disabled: false, Title: "xpack.tamper.tamper", IsShow: true, Label: "Tamper", Path: "/xpack/tamper", Sort: 600},
{ID: "115", Disabled: false, Title: "xpack.exchange.exchange", IsShow: true, Label: "FileExange", Path: "/xpack/exchange/file"}, {ID: "120", Disabled: false, Title: "xpack.cluster.cluster", IsShow: true, Label: "Cluster", Path: "/xpack/cluster", Sort: 700},
{ID: "117", Disabled: false, Title: "xpack.setting.setting", IsShow: true, Label: "XSetting", Path: "/xpack/setting"}, {ID: "115", Disabled: false, Title: "xpack.exchange.exchange", IsShow: true, Label: "FileExange", Path: "/xpack/exchange/file", Sort: 800},
{ID: "117", Disabled: false, Title: "xpack.setting.setting", IsShow: true, Label: "XSetting", Path: "/xpack/setting", Sort: 900},
}}, }},
{ID: "12", Disabled: false, Title: "menu.logs", IsShow: true, Label: "Log-Menu", Path: "/logs"}, {ID: "12", Disabled: false, Title: "menu.logs", IsShow: true, Label: "Log-Menu", Path: "/logs", Sort: 1200},
{ID: "13", Disabled: true, Title: "menu.settings", IsShow: true, Label: "Setting-Menu", Path: "/settings"}, {ID: "13", Disabled: true, Title: "menu.settings", IsShow: true, Label: "Setting-Menu", Path: "/settings", Sort: 1300},
} }
menu, _ := json.Marshal(item) menu, _ := json.Marshal(item)
return string(menu) return string(menu)

View file

@ -27,6 +27,7 @@ func (s *SettingRouter) InitRouter(Router *gin.RouterGroup) {
settingRouter.POST("/terminal/update", baseApi.UpdateTerminalSetting) settingRouter.POST("/terminal/update", baseApi.UpdateTerminalSetting)
settingRouter.GET("/interface", baseApi.LoadInterfaceAddr) settingRouter.GET("/interface", baseApi.LoadInterfaceAddr)
settingRouter.POST("/menu/update", baseApi.UpdateMenu) settingRouter.POST("/menu/update", baseApi.UpdateMenu)
settingRouter.POST("/menu/default", baseApi.DefaultMenu)
settingRouter.POST("/proxy/update", baseApi.UpdateProxy) settingRouter.POST("/proxy/update", baseApi.UpdateProxy)
settingRouter.POST("/bind/update", baseApi.UpdateBindInfo) settingRouter.POST("/bind/update", baseApi.UpdateBindInfo)
settingRouter.POST("/port/update", baseApi.UpdatePort) settingRouter.POST("/port/update", baseApi.UpdatePort)

View file

@ -94,6 +94,9 @@ export const updateSetting = (param: Setting.SettingUpdate) => {
export const updateMenu = (param: Setting.SettingUpdate) => { export const updateMenu = (param: Setting.SettingUpdate) => {
return http.post(`/core/settings/menu/update`, param); return http.post(`/core/settings/menu/update`, param);
}; };
export const defaultMenu = () => {
return http.post(`/core/settings/menu/default`);
};
export const updateProxy = (params: Setting.ProxyUpdate) => { export const updateProxy = (params: Setting.ProxyUpdate) => {
let request = deepCopy(params) as Setting.ProxyUpdate; let request = deepCopy(params) as Setting.ProxyUpdate;
if (request.proxyPasswd) { if (request.proxyPasswd) {

View file

@ -2045,6 +2045,7 @@ const message = {
ifShow: 'Whether to Show', ifShow: 'Whether to Show',
menu: 'Menu', menu: 'Menu',
confirmMessage: 'The page will be refreshed to update the advanced menu list. Continue?', confirmMessage: 'The page will be refreshed to update the advanced menu list. Continue?',
recoverMessage: 'The page will be refreshed and restore the menu list to its initial state. Continue?',
compressPassword: 'Compression password', compressPassword: 'Compression password',
backupRecoverMessage: 'Please enter the compression or decompression password (leave blank to not set)', backupRecoverMessage: 'Please enter the compression or decompression password (leave blank to not set)',
}, },

View file

@ -2052,6 +2052,8 @@ const message = {
ifShow: 'Mostrar o no', ifShow: 'Mostrar o no',
menu: 'Menú', menu: 'Menú',
confirmMessage: 'La página se actualizará para refrescar la lista de menús avanzados. ¿Deseas continuar?', confirmMessage: 'La página se actualizará para refrescar la lista de menús avanzados. ¿Deseas continuar?',
recoverMessage:
'La página se actualizará y la lista de menús se restaurará a su estado inicial. ¿Desea continuar?',
compressPassword: 'Contraseña de compresión', compressPassword: 'Contraseña de compresión',
backupRecoverMessage: backupRecoverMessage:
'Introduce la contraseña de compresión o descompresión (déjalo en blanco para no establecerla)', 'Introduce la contraseña de compresión o descompresión (déjalo en blanco para no establecerla)',

View file

@ -1960,6 +1960,7 @@ const message = {
ifShow: '表示するかどうか', ifShow: '表示するかどうか',
menu: 'メニュー', menu: 'メニュー',
confirmMessage: 'ページは更新されて高度なメニューリストを更新します続く', confirmMessage: 'ページは更新されて高度なメニューリストを更新します続く',
recoverMessage: 'ページが更新されメニューリストが初期状態に戻ります続行しますか',
compressPassword: '圧縮パスワード', compressPassword: '圧縮パスワード',
backupRecoverMessage: '圧縮または減圧パスワードを入力してください設定しないように空白のままにしてください', backupRecoverMessage: '圧縮または減圧パスワードを入力してください設定しないように空白のままにしてください',
}, },

View file

@ -1928,6 +1928,7 @@ const message = {
ifShow: '표시 여부', ifShow: '표시 여부',
menu: '메뉴', menu: '메뉴',
confirmMessage: '고급 메뉴 목록을 업데이트하려면 페이지가 새로 고쳐집니다. 계속하시겠습니까?', confirmMessage: '고급 메뉴 목록을 업데이트하려면 페이지가 새로 고쳐집니다. 계속하시겠습니까?',
recoverMessage: '페이지가 새로고침되어 메뉴 목록이 초기 상태로 복원됩니다. 계속하시겠습니까?',
compressPassword: '압축 비밀번호', compressPassword: '압축 비밀번호',
backupRecoverMessage: '압축 또는 압축 해제 비밀번호를 입력하세요 (설정하지 않으려면 비워 두세요)', backupRecoverMessage: '압축 또는 압축 해제 비밀번호를 입력하세요 (설정하지 않으려면 비워 두세요)',
}, },

View file

@ -2020,6 +2020,7 @@ const message = {
ifShow: 'Sama ada untuk Dipaparkan', ifShow: 'Sama ada untuk Dipaparkan',
menu: 'Menu', menu: 'Menu',
confirmMessage: 'Halaman akan disegarkan untuk mengemas kini senarai menu lanjutan. Teruskan?', confirmMessage: 'Halaman akan disegarkan untuk mengemas kini senarai menu lanjutan. Teruskan?',
recoverMessage: 'Halaman akan disegarkan dan senarai menu akan dipulihkan ke keadaan asal. Teruskan?',
compressPassword: 'Kata laluan mampatan', compressPassword: 'Kata laluan mampatan',
backupRecoverMessage: backupRecoverMessage:
'Sila masukkan kata laluan mampatan atau nyahmampatan (biarkan kosong jika tidak menetapkan)', 'Sila masukkan kata laluan mampatan atau nyahmampatan (biarkan kosong jika tidak menetapkan)',

View file

@ -2011,6 +2011,8 @@ const message = {
ifShow: 'Exibir?', ifShow: 'Exibir?',
menu: 'Menu', menu: 'Menu',
confirmMessage: 'A página será atualizada para atualizar a lista de menus avançados. Continuar?', confirmMessage: 'A página será atualizada para atualizar a lista de menus avançados. Continuar?',
recoverMessage:
'A página será atualizada e a lista de menus será restaurada ao estado inicial. Deseja continuar?',
compressPassword: 'Senha de compressão', compressPassword: 'Senha de compressão',
backupRecoverMessage: backupRecoverMessage:
'Por favor, insira a senha de compressão ou descompressão (deixe em branco para não definir)', 'Por favor, insira a senha de compressão ou descompressão (deixe em branco para não definir)',

View file

@ -2010,6 +2010,8 @@ const message = {
ifShow: 'Показывать', ifShow: 'Показывать',
menu: 'Меню', menu: 'Меню',
confirmMessage: 'Страница будет обновлена для обновления списка расширенного меню. Продолжить?', confirmMessage: 'Страница будет обновлена для обновления списка расширенного меню. Продолжить?',
recoverMessage:
'Страница будет обновлена, и список меню будет восстановлен до исходного состояния. Продолжить?',
compressPassword: 'Пароль сжатия', compressPassword: 'Пароль сжатия',
backupRecoverMessage: backupRecoverMessage:
'Пожалуйста, введите пароль для сжатия или распаковки (оставьте пустым, чтобы не устанавливать)', 'Пожалуйста, введите пароль для сжатия или распаковки (оставьте пустым, чтобы не устанавливать)',

View file

@ -2066,6 +2066,8 @@ const message = {
ifShow: 'Gösterme Durumu', ifShow: 'Gösterme Durumu',
menu: 'Menü', menu: 'Menü',
confirmMessage: 'Gelişmiş menü listesini güncellemek için sayfa yenilenecek. Devam etmek istiyor musunuz?', confirmMessage: 'Gelişmiş menü listesini güncellemek için sayfa yenilenecek. Devam etmek istiyor musunuz?',
recoverMessage:
'Sayfa yenilenecek ve menü listesi başlangıç durumuna geri yüklenecektir. Devam etmek istiyor musunuz?',
compressPassword: 'Sıkıştırma parolası', compressPassword: 'Sıkıştırma parolası',
backupRecoverMessage: 'Lütfen sıkıştırma veya sıkıştırma açma parolasını girin (ayarlamamak için boş bırakın)', backupRecoverMessage: 'Lütfen sıkıştırma veya sıkıştırma açma parolasını girin (ayarlamamak için boş bırakın)',
}, },

View file

@ -1910,6 +1910,7 @@ const message = {
ifShow: '是否顯示', ifShow: '是否顯示',
menu: '選單', menu: '選單',
confirmMessage: '即將重新整理頁面更新進階功能選單列表是否繼續', confirmMessage: '即將重新整理頁面更新進階功能選單列表是否繼續',
recoverMessage: '即将重新整理頁面並恢復選單列表至初始狀態是否繼續',
compressPassword: '壓縮密碼', compressPassword: '壓縮密碼',
backupRecoverMessage: '請輸入壓縮或解壓縮密碼留空則不設定', backupRecoverMessage: '請輸入壓縮或解壓縮密碼留空則不設定',
}, },

View file

@ -1903,6 +1903,7 @@ const message = {
ifShow: '是否显示', ifShow: '是否显示',
menu: '菜单', menu: '菜单',
confirmMessage: '即将刷新页面更新高级功能菜单列表是否继续', confirmMessage: '即将刷新页面更新高级功能菜单列表是否继续',
recoverMessage: '即将刷新页面恢复菜单列表到初始状态是否继续',
compressPassword: '压缩密码', compressPassword: '压缩密码',
backupRecoverMessage: '请输入压缩或解压缩密码留空则不设置', backupRecoverMessage: '请输入压缩或解压缩密码留空则不设置',
}, },

View file

@ -1,5 +1,5 @@
<template> <template>
<template v-for="subItem in menuList" :key="subItem.path"> <template v-for="subItem in menuList" :key="subItem.name">
<el-sub-menu v-if="subItem?.children?.length > 1" :index="subItem.path" popper-class="sidebar-container-popper"> <el-sub-menu v-if="subItem?.children?.length > 1" :index="subItem.path" popper-class="sidebar-container-popper">
<template #title> <template #title>
<el-icon> <el-icon>
@ -18,6 +18,7 @@
<span>{{ $t(subItem.meta?.title as string, 2) }}</span> <span>{{ $t(subItem.meta?.title as string, 2) }}</span>
</template> </template>
</el-menu-item> </el-menu-item>
<el-menu-item v-else-if="subItem.path === '/xpack/upage'" :index="''" @click="goUpage"> <el-menu-item v-else-if="subItem.path === '/xpack/upage'" :index="''" @click="goUpage">
<el-icon v-if="subItem.meta?.icon && level === 0"> <el-icon v-if="subItem.meta?.icon && level === 0">
<SvgIcon :iconName="(subItem.meta?.icon as string)" /> <SvgIcon :iconName="(subItem.meta?.icon as string)" />

View file

@ -53,8 +53,7 @@ const activeMenu = computed(() => {
const isCollapse = computed((): boolean => menuStore.isCollapse); const isCollapse = computed((): boolean => menuStore.isCollapse);
let routerMenus = computed((): RouteRecordRaw[] => { let routerMenus = computed((): RouteRecordRaw[] => {
const aa = menuStore.menuList.filter((route) => route.meta && !route.meta.hideInSidebar) as RouteRecordRaw[]; return menuStore.menuList.filter((route) => route.meta && !route.meta.hideInSidebar) as RouteRecordRaw[];
return aa;
}); });
const screenWidth = ref(0); const screenWidth = ref(0);
@ -121,6 +120,7 @@ const search = async () => {
.sort(sortByMap(childMap)) || []; .sort(sortByMap(childMap)) || [];
if (itemChildren.length === 1) { if (itemChildren.length === 1) {
menuItem.meta.icon = itemChildren[0].meta.icon;
menuItem.meta.title = itemChildren[0].meta.title; menuItem.meta.title = itemChildren[0].meta.title;
} }
menuItem.children = itemChildren; menuItem.children = itemChildren;
@ -194,6 +194,12 @@ function adjustAndCleanMenu(menuItem, list) {
const indexB = orderMap.get(b.name) ?? Infinity; const indexB = orderMap.get(b.name) ?? Infinity;
return indexA - indexB; return indexA - indexB;
}); });
for (const menu of newMenu) {
if (menu.children?.length === 1) {
menu.meta.icon = menu.children[0].meta.icon;
menu.meta.title = menu.children[0].meta.title;
}
}
return newMenu; return newMenu;
} }

View file

@ -307,7 +307,7 @@
</span> </span>
</el-tooltip> </el-tooltip>
<el-icon <el-icon
class="hidden group-hover:block" class="hidden group-hover:block cursor-pointer"
v-if="!row.isDir" v-if="!row.isDir"
@click="jump(row.path)" @click="jump(row.path)"
> >

View file

@ -31,6 +31,7 @@
</el-tree> </el-tree>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="defaultHideMenus">{{ $t('commons.button.setDefault') }}</el-button>
<el-button @click="drawerVisible = false">{{ $t('commons.button.cancel') }}</el-button> <el-button @click="drawerVisible = false">{{ $t('commons.button.cancel') }}</el-button>
<el-button :disabled="loading" type="primary" @click="saveHideMenus"> <el-button :disabled="loading" type="primary" @click="saveHideMenus">
{{ $t('commons.button.confirm') }} {{ $t('commons.button.confirm') }}
@ -44,7 +45,7 @@
import { reactive, ref } from 'vue'; import { reactive, ref } from 'vue';
import { AllowDropType, ElMessageBox, RenderContentContext } from 'element-plus'; import { AllowDropType, ElMessageBox, RenderContentContext } from 'element-plus';
import i18n from '@/lang'; import i18n from '@/lang';
import { updateMenu } from '@/api/modules/setting'; import { defaultMenu, updateMenu } from '@/api/modules/setting';
import { MsgSuccess } from '@/utils/message'; import { MsgSuccess } from '@/utils/message';
import { GlobalStore } from '@/store'; import { GlobalStore } from '@/store';
import { ArrowRight } from '@element-plus/icons-vue'; import { ArrowRight } from '@element-plus/icons-vue';
@ -201,6 +202,24 @@ const saveHideMenus = async () => {
}); });
}); });
}; };
const defaultHideMenus = async () => {
ElMessageBox.confirm(i18n.global.t('setting.recoverMessage'), i18n.global.t('setting.menuSetting'), {
confirmButtonText: i18n.global.t('commons.button.confirm'),
cancelButtonText: i18n.global.t('commons.button.cancel'),
type: 'info',
}).then(async () => {
await defaultMenu()
.then(async () => {
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
loading.value = false;
drawerVisible.value = false;
window.location.reload();
})
.catch(() => {
loading.value = false;
});
});
};
defineExpose({ defineExpose({
acceptParams, acceptParams,