From 79266c74ca657b8c14017a9219fd74f8a687d2b8 Mon Sep 17 00:00:00 2001 From: ssongliu Date: Mon, 1 Sep 2025 17:57:21 +0800 Subject: [PATCH] feat: Optimize quick navigation for dashboard --- agent/app/api/v2/dashboard.go | 32 +++++++++ agent/app/dto/dashboard.go | 20 ++++-- agent/app/model/app_launcher.go | 10 +++ agent/app/repo/app_launcher.go | 46 ++++++++++++ agent/app/service/dashboard.go | 93 +++++++++++++++++------- agent/i18n/lang/en.yaml | 3 + agent/i18n/lang/ja.yaml | 3 + agent/i18n/lang/ko.yaml | 3 + agent/i18n/lang/ms.yaml | 3 + agent/i18n/lang/pt-BR.yaml | 3 + agent/i18n/lang/ru.yaml | 3 + agent/i18n/lang/tr.yaml | 3 + agent/i18n/lang/zh-Hant.yaml | 3 + agent/i18n/lang/zh.yaml | 3 + agent/init/migration/migrate.go | 1 + agent/init/migration/migrations/init.go | 25 +++++++ agent/router/ro_dashboard.go | 2 + frontend/src/api/interface/dashboard.ts | 15 ++-- frontend/src/api/modules/dashboard.ts | 6 ++ frontend/src/lang/modules/en.ts | 2 + frontend/src/lang/modules/ja.ts | 4 ++ frontend/src/lang/modules/ko.ts | 4 ++ frontend/src/lang/modules/ms.ts | 4 ++ frontend/src/lang/modules/pt-br.ts | 4 ++ frontend/src/lang/modules/ru.ts | 4 ++ frontend/src/lang/modules/tr.ts | 4 +- frontend/src/lang/modules/zh-Hant.ts | 2 + frontend/src/lang/modules/zh.ts | 2 + frontend/src/views/home/index.vue | 65 ++++++++--------- frontend/src/views/home/quick/index.vue | 95 +++++++++++++++++++++++++ 30 files changed, 394 insertions(+), 73 deletions(-) create mode 100644 frontend/src/views/home/quick/index.vue diff --git a/agent/app/api/v2/dashboard.go b/agent/app/api/v2/dashboard.go index 5816da4491d3..7ccd0ae9ecb1 100644 --- a/agent/app/api/v2/dashboard.go +++ b/agent/app/api/v2/dashboard.go @@ -83,6 +83,38 @@ func (b *BaseApi) UpdateAppLauncher(c *gin.Context) { helper.Success(c) } +// @Tags Dashboard +// @Summary Load quick jump options +// @Success 200 {Array} dto.QuickJump +// @Security ApiKeyAuth +// @Security Timestamp +// @Router /dashboard/quick/option [post] +func (b *BaseApi) LoadQuickOption(c *gin.Context) { + helper.SuccessWithData(c, dashboardService.LoadQuickOptions()) +} + +// @Tags Dashboard +// @Summary Update quick jump +// @Accept json +// @Param request body dto.ChangeQuicks true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Security Timestamp +// @Router /dashboard/quick/change [post] +// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"切换快速跳转","formatEN":"change quick jump"} +func (b *BaseApi) UpdateQuickJump(c *gin.Context) { + var req dto.ChangeQuicks + if err := helper.CheckBindAndValidate(&req, c); err != nil { + return + } + + if err := dashboardService.ChangeQuick(req); err != nil { + helper.InternalServer(c, err) + return + } + helper.Success(c) +} + // @Tags Dashboard // @Summary Load dashboard base info // @Accept json diff --git a/agent/app/dto/dashboard.go b/agent/app/dto/dashboard.go index 2fb82702fae7..5cfd7f150883 100644 --- a/agent/app/dto/dashboard.go +++ b/agent/app/dto/dashboard.go @@ -3,11 +3,6 @@ package dto import "time" type DashboardBase struct { - WebsiteNumber int `json:"websiteNumber"` - DatabaseNumber int `json:"databaseNumber"` - CronjobNumber int `json:"cronjobNumber"` - AppInstalledNumber int `json:"appInstalledNumber"` - Hostname string `json:"hostname"` OS string `json:"os"` Platform string `json:"platform"` @@ -23,9 +18,24 @@ type DashboardBase struct { CPULogicalCores int `json:"cpuLogicalCores"` CPUModelName string `json:"cpuModelName"` + QuickJumps []QuickJump `json:"quickJump"` CurrentInfo DashboardCurrent `json:"currentInfo"` } +type ChangeQuicks struct { + Quicks []QuickJump `json:"quicks"` +} + +type QuickJump struct { + ID uint `json:"id"` + Name string `json:"name"` + Title string `json:"title"` + Detail string `json:"detail"` + Recommend int `json:"recommend"` + IsShow bool `json:"isShow"` + Router string `json:"router"` +} + type OsInfo struct { OS string `json:"os"` Platform string `json:"platform"` diff --git a/agent/app/model/app_launcher.go b/agent/app/model/app_launcher.go index 83457836d669..442781e14ae1 100644 --- a/agent/app/model/app_launcher.go +++ b/agent/app/model/app_launcher.go @@ -4,3 +4,13 @@ type AppLauncher struct { BaseModel Key string `json:"key"` } + +type QuickJump struct { + BaseModel + Name string `json:"name"` + Title string `json:"title"` + Detail string `json:"detail"` + Recommend int `json:"recommend"` + IsShow bool `json:"isShow"` + Router string `json:"router"` +} diff --git a/agent/app/repo/app_launcher.go b/agent/app/repo/app_launcher.go index 0f54cfeb505a..172668e1b64d 100644 --- a/agent/app/repo/app_launcher.go +++ b/agent/app/repo/app_launcher.go @@ -13,6 +13,10 @@ type ILauncherRepo interface { Create(launcher *model.AppLauncher) error Save(launcher *model.AppLauncher) error Delete(opts ...DBOption) error + + GetQuickJump(opts ...DBOption) (model.QuickJump, error) + ListQuickJump(withAll bool) []model.QuickJump + UpdateQuicks(quicks []model.QuickJump) error } func NewILauncherRepo() ILauncherRepo { @@ -57,3 +61,45 @@ func (u *LauncherRepo) Delete(opts ...DBOption) error { } return db.Delete(&model.AppLauncher{}).Error } + +func (u *LauncherRepo) GetQuickJump(opts ...DBOption) (model.QuickJump, error) { + var launcher model.QuickJump + db := global.DB + for _, opt := range opts { + db = opt(db) + } + err := db.First(&launcher).Error + return launcher, err +} +func (u *LauncherRepo) ListQuickJump(withAll bool) []model.QuickJump { + var quicks []model.QuickJump + if withAll { + _ = global.DB.Find(&quicks).Error + } else { + _ = global.DB.Where("is_show = ?", true).Find(&quicks).Error + } + if !withAll && len(quicks) == 0 { + return []model.QuickJump{ + {Name: "Website", Title: "menu.website", Recommend: 10, IsShow: true, Router: "/websites"}, + {Name: "Database", Title: "menu.database", Recommend: 30, IsShow: true, Router: "/databases"}, + {Name: "Cronjob", Title: "menu.cronjob", Recommend: 50, IsShow: true, Router: "/cronjobs"}, + {Name: "AppInstalled", Title: "home.appInstalled", Recommend: 70, IsShow: true, Router: "/apps/installed"}, + } + } + + return quicks +} +func (u *LauncherRepo) UpdateQuicks(quicks []model.QuickJump) error { + tx := global.DB.Begin() + for _, item := range quicks { + if err := tx.Model(&model.QuickJump{}).Where("id = ?", item.ID).Updates(map[string]interface{}{ + "is_show": item.IsShow, + "detail": item.Detail, + }).Error; err != nil { + tx.Rollback() + return err + } + } + tx.Commit() + return nil +} diff --git a/agent/app/service/dashboard.go b/agent/app/service/dashboard.go index 5e9cb6237cbc..db310858a21c 100644 --- a/agent/app/service/dashboard.go +++ b/agent/app/service/dashboard.go @@ -14,6 +14,7 @@ import ( "github.com/1Panel-dev/1Panel/agent/app/dto" "github.com/1Panel-dev/1Panel/agent/app/model" "github.com/1Panel-dev/1Panel/agent/app/repo" + "github.com/1Panel-dev/1Panel/agent/buserr" "github.com/1Panel-dev/1Panel/agent/constant" "github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/utils/ai_tools/gpu" @@ -38,6 +39,9 @@ type IDashboardService interface { LoadCurrentInfoForNode() *dto.NodeCurrent LoadCurrentInfo(ioOption string, netOption string) *dto.DashboardCurrent + LoadQuickOptions() []dto.QuickJump + ChangeQuick(req dto.ChangeQuicks) error + LoadAppLauncher(ctx *gin.Context) ([]dto.AppLauncher, error) ChangeShow(req dto.SettingUpdate) error ListLauncherOption(filter string) ([]dto.LauncherOption, error) @@ -140,7 +144,7 @@ func (u *DashboardService) LoadBaseInfo(ioOption string, netOption string) (*dto baseInfo.KernelVersion = hostInfo.KernelVersion ss, _ := json.Marshal(hostInfo) baseInfo.VirtualizationSystem = string(ss) - baseInfo.IpV4Addr = GetOutboundIP() + baseInfo.IpV4Addr = loadOutboundIP() httpProxy := os.Getenv("http_proxy") if httpProxy == "" { httpProxy = os.Getenv("HTTP_PROXY") @@ -150,30 +154,7 @@ func (u *DashboardService) LoadBaseInfo(ioOption string, netOption string) (*dto } baseInfo.SystemProxy = "noProxy" - appInstall, err := appInstallRepo.ListBy(context.Background()) - if err != nil { - return nil, err - } - baseInfo.AppInstalledNumber = len(appInstall) - postgresqlDbs, err := postgresqlRepo.List() - if err != nil { - return nil, err - } - mysqlDbs, err := mysqlRepo.List() - if err != nil { - return nil, err - } - baseInfo.DatabaseNumber = len(mysqlDbs) + len(postgresqlDbs) - website, err := websiteRepo.GetBy() - if err != nil { - return nil, err - } - baseInfo.WebsiteNumber = len(website) - cronjobs, err := cronjobRepo.List() - if err != nil { - return nil, err - } - baseInfo.CronjobNumber = len(cronjobs) + loadQuickJump(&baseInfo) cpuInfo, err := cpu.Info() if err == nil { @@ -347,6 +328,39 @@ func (u *DashboardService) ChangeShow(req dto.SettingUpdate) error { return nil } +func (u *DashboardService) LoadQuickOptions() []dto.QuickJump { + quicks := launcherRepo.ListQuickJump(true) + var list []dto.QuickJump + for _, quick := range quicks { + var item dto.QuickJump + _ = copier.Copy(&item, &quick) + list = append(list, item) + } + return list +} +func (u *DashboardService) ChangeQuick(req dto.ChangeQuicks) error { + showCount := 0 + var quicks []model.QuickJump + for _, item := range req.Quicks { + var quick model.QuickJump + if item.IsShow { + showCount++ + } + if err := copier.Copy(&quick, &item); err != nil { + return err + } + quicks = append(quicks, quick) + } + if showCount == 0 { + return buserr.New("ErrMinQuickJump") + } + if showCount > 4 { + return buserr.New("ErrMaxQuickJump") + } + + return launcherRepo.UpdateQuicks(quicks) +} + func (u *DashboardService) ListLauncherOption(filter string) ([]dto.LauncherOption, error) { showList, _ := launcherRepo.ListName() var data []dto.LauncherOption @@ -545,7 +559,7 @@ func loadXpuInfo() []dto.XPUInfo { return data } -func GetOutboundIP() string { +func loadOutboundIP() string { conn, err := network.Dial("udp", "8.8.8.8:80") if err != nil { @@ -556,3 +570,30 @@ func GetOutboundIP() string { localAddr := conn.LocalAddr().(*network.UDPAddr) return localAddr.IP.String() } + +func loadQuickJump(base *dto.DashboardBase) { + quicks := launcherRepo.ListQuickJump(false) + for i := 0; i < len(quicks); i++ { + switch quicks[i].Name { + case "Website": + website, _ := websiteRepo.GetBy() + quicks[i].Detail = fmt.Sprintf("%d", len(website)) + case "Database": + postgresqlDbs, _ := postgresqlRepo.List() + mysqlDbs, _ := mysqlRepo.List() + quicks[i].Detail = fmt.Sprintf("%d", len(mysqlDbs)+len(postgresqlDbs)) + case "Cronjob": + cronjobs, _ := cronjobRepo.List() + quicks[i].Detail = fmt.Sprintf("%d", len(cronjobs)) + case "AppInstalled": + appInstall, _ := appInstallRepo.ListBy(context.Background()) + quicks[i].Detail = fmt.Sprintf("%d", len(appInstall)) + } + var item dto.QuickJump + _ = copier.Copy(&item, quicks[i]) + base.QuickJumps = append(base.QuickJumps, item) + } + sort.Slice(quicks, func(i, j int) bool { + return quicks[i].Recommend < quicks[j].Recommend + }) +} diff --git a/agent/i18n/lang/en.yaml b/agent/i18n/lang/en.yaml index d8618c75a6ff..2eef03d6aafe 100644 --- a/agent/i18n/lang/en.yaml +++ b/agent/i18n/lang/en.yaml @@ -15,6 +15,9 @@ ErrApiConfigIPInvalid: 'The IP used to call the API interface is not in the whit ErrApiConfigDisable: 'This interface prohibits the use of API interface calls: {{ .detail }}' ErrApiConfigKeyTimeInvalid: 'API interface timestamp error: {{ .detail }}' +ErrMinQuickJump: "Please set at least one quick jump entry!" +ErrMaxQuickJump: "You can set up to four quick jump entries!" + #common ErrUsernameIsExist: 'Username already exists' ErrNameIsExist: 'Name already exists' diff --git a/agent/i18n/lang/ja.yaml b/agent/i18n/lang/ja.yaml index 1ca5a8172ff6..c646dbb87742 100644 --- a/agent/i18n/lang/ja.yaml +++ b/agent/i18n/lang/ja.yaml @@ -15,6 +15,9 @@ ErrApiConfigIPInvalid: 'API インターフェースの呼び出しに使用さ ErrApiConfigDisable: 'このインターフェースは、API インターフェース呼び出しの使用を禁止しています: {{ .detail }}' ErrApiConfigKeyTimeInvalid: 'API インターフェースのタイムスタンプ エラー: {{ .detail }}' +ErrMinQuickJump: "少なくとも1つのクイックジャンプエントリを設定してください!" +ErrMaxQuickJump: "最大4つのクイックジャンプエントリを設定できます!" + #common ErrUsernameIsExist: 'ユーザー名は既に存在します' ErrNameIsExist: '名前は既に存在します' diff --git a/agent/i18n/lang/ko.yaml b/agent/i18n/lang/ko.yaml index 24fb525a7969..4f316713c572 100644 --- a/agent/i18n/lang/ko.yaml +++ b/agent/i18n/lang/ko.yaml @@ -15,6 +15,9 @@ ErrApiConfigIPInvalid: 'API 인터페이스를 호출하는 데 사용된 IP가 ErrApiConfigDisable: '이 인터페이스는 API 인터페이스 호출 사용을 금지합니다: {{ .detail }}' ErrApiConfigKeyTimeInvalid: 'API 인터페이스 타임스탬프 오류: {{ .detail }}' +ErrMinQuickJump: "최소 하나의 빠른 점프 항목을 설정해 주세요!" +ErrMaxQuickJump: "최대 네 개의 빠른 점프 항목을 설정할 수 있습니다!" + #흔한 ErrUsernameIsExist: '사용자 이름이 이미 존재합니다' ErrNameIsExist: '이름이 이미 존재합니다' diff --git a/agent/i18n/lang/ms.yaml b/agent/i18n/lang/ms.yaml index cbd9201afe7a..0afb80eaf7bf 100644 --- a/agent/i18n/lang/ms.yaml +++ b/agent/i18n/lang/ms.yaml @@ -18,6 +18,9 @@ StartPushSSLToNode: "Mula menolak sijil ke nod" PushSSLToNodeFailed: "Gagal menolak sijil ke nod: {{ .err }}" PushSSLToNodeSuccess: "Berjaya menolak sijil ke nod" +ErrMinQuickJump: "Sila tetapkan sekurang-kurangnya satu entri lompat pantas!" +ErrMaxQuickJump: "Anda boleh menetapkan sehingga empat entri lompat pantas!" + #biasa ErrUsernameIsExist: 'Nama pengguna sudah wujud' ErrNameIsExist: 'Nama sudah wujud' diff --git a/agent/i18n/lang/pt-BR.yaml b/agent/i18n/lang/pt-BR.yaml index 0ac6e7ef7f22..0c7a538dee16 100644 --- a/agent/i18n/lang/pt-BR.yaml +++ b/agent/i18n/lang/pt-BR.yaml @@ -18,6 +18,9 @@ StartPushSSLToNode: "Iniciando o envio do certificado para o nó" PushSSLToNodeFailed: "Falha ao enviar o certificado para o nó: {{ .err }}" PushSSLToNodeSuccess: "Certificado enviado com sucesso para o nó" +ErrMinQuickJump: "Defina pelo menos uma entrada de salto rápido!" +ErrMaxQuickJump: "Você pode definir até quatro entradas de salto rápido!" + #comum ErrUsernameIsExist: 'Nome de usuário já existe' ErrNameIsExist: 'Nome já existe' diff --git a/agent/i18n/lang/ru.yaml b/agent/i18n/lang/ru.yaml index 786b2c6d53a3..ee4361c4b9f0 100644 --- a/agent/i18n/lang/ru.yaml +++ b/agent/i18n/lang/ru.yaml @@ -18,6 +18,9 @@ StartPushSSLToNode: "Начало отправки сертификата на PushSSLToNodeFailed: "Не удалось отправить сертификат на узел: {{ .err }}" PushSSLToNodeSuccess: "Сертификат успешно отправлен на узел" +ErrMinQuickJump: "Пожалуйста, установите хотя бы одну запись быстрого перехода!" +ErrMaxQuickJump: "Можно установить до четырех записей быстрого перехода!" + #общий ErrUsernameIsExist: 'Имя пользователя уже существует' ErrNameIsExist: 'Имя уже существует' diff --git a/agent/i18n/lang/tr.yaml b/agent/i18n/lang/tr.yaml index d1e208fdb822..c5831213c3ac 100644 --- a/agent/i18n/lang/tr.yaml +++ b/agent/i18n/lang/tr.yaml @@ -18,6 +18,9 @@ StartPushSSLToNode: "Sertifika düğüme gönderilmeye başlandı" PushSSLToNodeFailed: "Sertifika düğüme gönderilemedi: {{ .err }}" PushSSLToNodeSuccess: "Sertifika düğüme başarıyla gönderildi" +ErrMinQuickJump: "Lütfen en az bir hızlı atlama girişi ayarlayın!" +ErrMaxQuickJump: "En fazla dört hızlı atlama girişi ayarlayabilirsiniz!" + #common ErrUsernameIsExist: 'Kullanıcı adı zaten mevcut' ErrNameIsExist: 'İsim zaten mevcut' diff --git a/agent/i18n/lang/zh-Hant.yaml b/agent/i18n/lang/zh-Hant.yaml index fc034d6cbb54..9eccdf39bf51 100644 --- a/agent/i18n/lang/zh-Hant.yaml +++ b/agent/i18n/lang/zh-Hant.yaml @@ -15,6 +15,9 @@ ErrApiConfigIPInvalid: '呼叫 API 介面 IP 不在白名單: {{ .detail }}' ErrApiConfigDisable: '此介面禁止使用 API 介面呼叫: {{ .detail }}' ErrApiConfigKeyTimeInvalid: 'API 介面時間戳記錯誤: {{ .detail }}' +ErrMinQuickJump: "請至少設定一個快速跳轉入口!" +ErrMaxQuickJump: "最多可設定四個快速跳轉入口!" + #common ErrUsernameIsExist: '使用者名稱已存在' ErrNameIsExist: '名稱已存在' diff --git a/agent/i18n/lang/zh.yaml b/agent/i18n/lang/zh.yaml index 6fcfbb86a93e..e9da43e9bc97 100644 --- a/agent/i18n/lang/zh.yaml +++ b/agent/i18n/lang/zh.yaml @@ -15,6 +15,9 @@ ErrApiConfigIPInvalid: "调用 API 接口 IP 不在白名单: {{ .detail }}" ErrApiConfigDisable: "此接口禁止使用 API 接口调用: {{ .detail }}" ErrApiConfigKeyTimeInvalid: "API 接口时间戳错误: {{ .detail }}" +ErrMinQuickJump: "请至少设置一个快速跳转入口!" +ErrMaxQuickJump: "最多可设置四个快速跳转入口!" + #common ErrUsernameIsExist: "用户名已存在" ErrNameIsExist: "名称已存在" diff --git a/agent/init/migration/migrate.go b/agent/init/migration/migrate.go index dceebff39825..6a7ed525df4f 100644 --- a/agent/init/migration/migrate.go +++ b/agent/init/migration/migrate.go @@ -37,6 +37,7 @@ func InitAgentDB() { migrations.InitCronjobGroup, migrations.AddColumnToAlert, migrations.UpdateWebsiteSSL, + migrations.AddQuickJump, }) if err := m.Migrate(); err != nil { global.LOG.Error(err) diff --git a/agent/init/migration/migrations/init.go b/agent/init/migration/migrations/init.go index 4b6e9764b577..c60e48573f2a 100644 --- a/agent/init/migration/migrations/init.go +++ b/agent/init/migration/migrations/init.go @@ -471,3 +471,28 @@ var UpdateWebsiteSSL = &gormigrate.Migration{ return nil }, } + +var AddQuickJump = &gormigrate.Migration{ + ID: "20250901-add-quick-jump", + Migrate: func(tx *gorm.DB) error { + if err := tx.AutoMigrate(&model.QuickJump{}); err != nil { + return err + } + if err := tx.Create(&model.QuickJump{Name: "Website", Title: "menu.website", Recommend: 10, IsShow: true, Router: "/websites"}).Error; err != nil { + return err + } + if err := tx.Create(&model.QuickJump{Name: "Database", Title: "home.database", Recommend: 30, IsShow: true, Router: "/databases"}).Error; err != nil { + return err + } + if err := tx.Create(&model.QuickJump{Name: "Cronjob", Title: "menu.cronjob", Recommend: 50, IsShow: true, Router: "/cronjobs"}).Error; err != nil { + return err + } + if err := tx.Create(&model.QuickJump{Name: "AppInstalled", Title: "home.appInstalled", Recommend: 70, IsShow: true, Router: "/apps/installed"}).Error; err != nil { + return err + } + if err := tx.Create(&model.QuickJump{Name: "File", Detail: "/", Title: "home.quickDir", Recommend: 90, IsShow: false, Router: "/hosts/files"}).Error; err != nil { + return err + } + return nil + }, +} diff --git a/agent/router/ro_dashboard.go b/agent/router/ro_dashboard.go index d5700b5c4c67..ea167a9a243b 100644 --- a/agent/router/ro_dashboard.go +++ b/agent/router/ro_dashboard.go @@ -12,6 +12,8 @@ func (s *DashboardRouter) InitRouter(Router *gin.RouterGroup) { baseApi := v2.ApiGroupApp.BaseApi { cmdRouter.GET("/base/os", baseApi.LoadDashboardOsInfo) + cmdRouter.GET("/quick/option", baseApi.LoadQuickOption) + cmdRouter.POST("/quick/change", baseApi.UpdateQuickJump) cmdRouter.GET("/app/launcher", baseApi.LoadAppLauncher) cmdRouter.POST("/app/launcher/show", baseApi.UpdateAppLauncher) cmdRouter.POST("/app/launcher/option", baseApi.LoadAppLauncherOption) diff --git a/frontend/src/api/interface/dashboard.ts b/frontend/src/api/interface/dashboard.ts index d17befcda622..c948aabff3df 100644 --- a/frontend/src/api/interface/dashboard.ts +++ b/frontend/src/api/interface/dashboard.ts @@ -8,6 +8,15 @@ export namespace Dashboard { diskSize: number; } + export interface QuickJump { + id: number; + name: string; + title: string; + detail: string; + recommend: number; + isShow: boolean ; + router: string; + } export interface AppLauncher { key: string; icon: string; @@ -37,11 +46,6 @@ export namespace Dashboard { httpsPort: string; } export interface BaseInfo { - websiteNumber: number; - databaseNumber: number; - cronjobNumber: number; - appInstalledNumber: number; - hostname: string; os: string; platform: string; @@ -58,6 +62,7 @@ export namespace Dashboard { cpuModelName: string; currentInfo: CurrentInfo; + quickJump: Array; } export interface CurrentInfo { uptime: number; diff --git a/frontend/src/api/modules/dashboard.ts b/frontend/src/api/modules/dashboard.ts index 4e3f9f7ff13e..1f1becda5edd 100644 --- a/frontend/src/api/modules/dashboard.ts +++ b/frontend/src/api/modules/dashboard.ts @@ -5,6 +5,12 @@ export const loadOsInfo = () => { return http.get(`/dashboard/base/os`); }; +export const loadQuickOption = () => { + return http.get>(`/dashboard/quick/option`); +}; +export const changeQuick = (quicks: Array) => { + return http.post(`/dashboard/quick/change`, { quicks: quicks }); +}; export const loadAppLauncher = () => { return http.get>(`/dashboard/app/launcher`); }; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 12df9177776d..09c1ae31fe26 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -386,6 +386,8 @@ const message = { home: { recommend: 'recommend', dir: 'dir', + quickDir: 'Quick Dir', + database: 'Database - All', restart_1panel: 'Restart panel', restart_system: 'Restart server', operationSuccess: 'Operation succeeded, rebooting, please refresh the browser manually later!', diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts index b75b5ace8032..f9ee4a9e0315 100644 --- a/frontend/src/lang/modules/ja.ts +++ b/frontend/src/lang/modules/ja.ts @@ -373,6 +373,10 @@ const message = { msgCenter: 'タスクセンター', }, home: { + recommend: 'おすすめ', + dir: 'ディレクトリ', + quickDir: 'クイックディレクトリ', + database: 'データベース - すべて', restart_1panel: 'パネルを再起動します', restart_system: 'サーバーを再起動します', operationSuccess: '操作が成功し、再起動します。後で手動でブラウザを更新してください!', diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts index cd05aa052ed2..a963830520e5 100644 --- a/frontend/src/lang/modules/ko.ts +++ b/frontend/src/lang/modules/ko.ts @@ -375,6 +375,10 @@ const message = { msgCenter: '작업 센터', }, home: { + recommend: '추천', + dir: '디렉토리', + quickDir: '빠른 디렉토리', + database: '데이터베이스 - 전체', restart_1panel: '패널 재시작', restart_system: '서버 재시작', operationSuccess: diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts index 41c4d56b100f..ab7bd45431ad 100644 --- a/frontend/src/lang/modules/ms.ts +++ b/frontend/src/lang/modules/ms.ts @@ -381,6 +381,10 @@ const message = { msgCenter: 'Pusat Tugas', }, home: { + recommend: 'cadangan', + dir: 'direktori', + quickDir: 'Direktori Pantas', + database: 'Pangkalan Data - Semua', restart_1panel: 'Mulakan semula panel', restart_system: 'Mulakan semula pelayan', operationSuccess: 'Operasi berjaya, sedang memulakan semula, sila segarkan pelayar secara manual nanti!', diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts index d538b0c439ae..918746fb6ffe 100644 --- a/frontend/src/lang/modules/pt-br.ts +++ b/frontend/src/lang/modules/pt-br.ts @@ -379,6 +379,10 @@ const message = { msgCenter: 'Central de Tarefas', }, home: { + recommend: 'recomendar', + dir: 'dir', + quickDir: 'Diretório Rápido', + database: 'Banco de Dados - Todos', restart_1panel: 'Reiniciar painel', restart_system: 'Reiniciar servidor', operationSuccess: 'Operação bem-sucedida, reiniciando, por favor, atualize o navegador manualmente mais tarde!', diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts index 6d284e8dbb94..cf19984c5f59 100644 --- a/frontend/src/lang/modules/ru.ts +++ b/frontend/src/lang/modules/ru.ts @@ -376,6 +376,10 @@ const message = { msgCenter: 'Центр задач', }, home: { + recommend: 'рекомендовать', + dir: 'каталог', + quickDir: 'Быстрый каталог', + database: 'База данных - Все', restart_1panel: 'Перезапустить панель', restart_system: 'Перезапустить сервер', operationSuccess: 'Операция выполнена успешно, перезагрузка, пожалуйста, обновите браузер вручную позже!', diff --git a/frontend/src/lang/modules/tr.ts b/frontend/src/lang/modules/tr.ts index fdfdb084669a..2026068a11fe 100644 --- a/frontend/src/lang/modules/tr.ts +++ b/frontend/src/lang/modules/tr.ts @@ -388,8 +388,10 @@ const message = { msgCenter: 'Görev Merkezi', }, home: { - recommend: 'önerilen', + recommend: 'tavsiye etmek', dir: 'dizin', + quickDir: 'Hızlı Dizin', + database: 'Veritabanı - Tümü', restart_1panel: 'Paneli yeniden başlat', restart_system: 'Sunucuyu yeniden başlat', operationSuccess: 'İşlem başarılı, yeniden başlatılıyor, lütfen tarayıcıyı daha sonra manuel olarak yenileyin!', diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts index dd51a96e2a89..258b11a481c5 100644 --- a/frontend/src/lang/modules/zh-Hant.ts +++ b/frontend/src/lang/modules/zh-Hant.ts @@ -376,6 +376,8 @@ const message = { home: { recommend: '推薦', dir: '目錄', + quickDir: '快捷目錄', + database: '資料庫 - 全部', restart_1panel: '重啟面板', restart_system: '重啟服務器', operationSuccess: '操作成功,正在重啟,請稍後手動刷新瀏覽器!', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 07c652e19b2f..186aeb0edfa6 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -374,6 +374,8 @@ const message = { home: { recommend: '推荐', dir: '目录', + quickDir: '快捷目录', + database: '数据库 - 所有', restart_1panel: '重启面板', restart_system: '重启服务器', operationSuccess: '操作成功,正在重启,请稍后手动刷新浏览器!', diff --git a/frontend/src/views/home/index.vue b/frontend/src/views/home/index.vue index b165640b70ee..3ba92f6c50e1 100644 --- a/frontend/src/views/home/index.vue +++ b/frontend/src/views/home/index.vue @@ -43,39 +43,25 @@ + @@ -259,6 +246,7 @@ import Status from '@/views/home/status/index.vue'; import AppLauncher from '@/views/home/app/index.vue'; import VCharts from '@/components/v-charts/index.vue'; import LicenseImport from '@/components/license-import/index.vue'; +import QuickJump from '@/views/home/quick/index.vue'; import CardWithHeader from '@/components/card-with-header/index.vue'; import i18n from '@/lang'; import { Dashboard } from '@/api/interface/dashboard'; @@ -269,6 +257,7 @@ import { getIOOptions, getNetworkOptions } from '@/api/modules/host'; import { getSettingInfo, loadUpgradeInfo } from '@/api/modules/setting'; import { GlobalStore } from '@/store'; import { storeToRefs } from 'pinia'; +import { routerToFileWithPath, routerToPath } from '@/utils/router'; const router = useRouter(); const globalStore = GlobalStore(); @@ -295,6 +284,7 @@ const ioOptions = ref(); const netOptions = ref(); const licenseRef = ref(); +const quickJumpRef = ref(); const { isProductPro } = storeToRefs(globalStore); const searchInfo = reactive({ @@ -303,11 +293,6 @@ const searchInfo = reactive({ }); const baseInfo = ref({ - websiteNumber: 0, - databaseNumber: 0, - cronjobNumber: 0, - appInstalledNumber: 0, - hostname: '', os: '', platform: '', @@ -323,6 +308,8 @@ const baseInfo = ref({ cpuLogicalCores: 0, cpuModelName: '', currentInfo: null, + + quickJump: [], }); const currentInfo = ref({ uptime: 0, @@ -429,6 +416,13 @@ const onLoadBaseInfo = async (isInit: boolean, range: string) => { } }; +const quickJump = (item: any) => { + if (item.name === 'File') { + routerToFileWithPath(item.detail); + } + return routerToPath(item.router); +}; + const onLoadCurrentInfo = async () => { const res = await loadCurrentInfo(searchInfo.ioOption, searchInfo.netOption); currentInfo.value.timeSinceUptime = res.data.timeSinceUptime; @@ -635,9 +629,8 @@ onBeforeUnmount(() => { .count { margin-top: 10px; span { - font-size: 25px; + font-size: 18px; color: $primary-color; - font-weight: 500; line-height: 32px; cursor: pointer; } diff --git a/frontend/src/views/home/quick/index.vue b/frontend/src/views/home/quick/index.vue new file mode 100644 index 000000000000..7d973b2372d4 --- /dev/null +++ b/frontend/src/views/home/quick/index.vue @@ -0,0 +1,95 @@ + +