mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-31 14:08:06 +08:00
parent
ef793f278a
commit
f79adc9bc0
@ -4,6 +4,8 @@ import (
|
||||
"errors"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/api/v2/helper"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@ -23,6 +25,43 @@ func (b *BaseApi) LoadDashboardOsInfo(c *gin.Context) {
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags Dashboard
|
||||
// @Summary Load app launcher
|
||||
// @Description 获取应用展示列表
|
||||
// @Accept json
|
||||
// @Success 200 {Array} dto.dto.AppLauncher
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /dashboard/app/launcher [get]
|
||||
func (b *BaseApi) LoadAppLauncher(c *gin.Context) {
|
||||
data, err := dashboardService.LoadAppLauncher()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags Dashboard
|
||||
// @Summary Load app launcher options
|
||||
// @Description 获取应用展示选项
|
||||
// @Accept json
|
||||
// @Param request body dto.SearchByFilter true "request"
|
||||
// @Success 200 {Array} dto.LauncherOption
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /dashboard/app/launcher/option [post]
|
||||
func (b *BaseApi) LoadAppLauncherOption(c *gin.Context) {
|
||||
var req dto.SearchByFilter
|
||||
if err := helper.CheckBind(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
data, err := dashboardService.ListLauncherOption(req.Filter)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags Dashboard
|
||||
// @Summary Load dashboard base info
|
||||
// @Description 获取首页基础数据
|
||||
|
@ -27,6 +27,10 @@ type Operate struct {
|
||||
Operation string `json:"operation" validate:"required"`
|
||||
}
|
||||
|
||||
type SearchByFilter struct {
|
||||
Filter string `json:"filter"`
|
||||
}
|
||||
|
||||
type BatchDeleteReq struct {
|
||||
Ids []uint `json:"ids" validate:"required"`
|
||||
}
|
||||
|
@ -126,3 +126,33 @@ type GPUInfo struct {
|
||||
MemTotal string `json:"memTotal"`
|
||||
FanSpeed string `json:"fanSpeed"`
|
||||
}
|
||||
|
||||
type AppLauncher struct {
|
||||
Key string `json:"key"`
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Icon string `json:"icon"`
|
||||
Limit int `json:"limit"`
|
||||
ShortDescZh string `json:"shortDescZh"`
|
||||
ShortDescEn string `json:"shortDescEn"`
|
||||
Recommend int `json:"recomend"`
|
||||
|
||||
IsInstall bool `json:"isInstall"`
|
||||
IsRecommend bool `json:"isRecommend"`
|
||||
Detail []InstallDetail `json:"detail"`
|
||||
}
|
||||
type InstallDetail struct {
|
||||
InstallID uint `json:"installID"`
|
||||
DetailID uint `json:"detailID"`
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Path string `json:"path"`
|
||||
Status string `json:"status"`
|
||||
WebUI string `json:"webUI"`
|
||||
HttpPort int `json:"httpPort"`
|
||||
HttpsPort int `json:"httpsPort"`
|
||||
}
|
||||
type LauncherOption struct {
|
||||
Key string `json:"key"`
|
||||
IsShow bool `json:"isShow"`
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package service
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -12,6 +13,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/copier"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/xpack"
|
||||
"github.com/shirou/gopsutil/v3/cpu"
|
||||
@ -30,6 +32,8 @@ type IDashboardService interface {
|
||||
LoadCurrentInfoForNode() *dto.NodeCurrent
|
||||
LoadCurrentInfo(ioOption string, netOption string) *dto.DashboardCurrent
|
||||
|
||||
LoadAppLauncher() ([]dto.AppLauncher, error)
|
||||
ListLauncherOption(filter string) ([]dto.LauncherOption, error)
|
||||
Restart(operation string) error
|
||||
}
|
||||
|
||||
@ -240,6 +244,109 @@ func (u *DashboardService) LoadCurrentInfo(ioOption string, netOption string) *d
|
||||
return ¤tInfo
|
||||
}
|
||||
|
||||
func (u *DashboardService) LoadAppLauncher() ([]dto.AppLauncher, error) {
|
||||
var (
|
||||
data []dto.AppLauncher
|
||||
recommendList []dto.AppLauncher
|
||||
)
|
||||
appInstalls, err := appInstallRepo.ListBy()
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
apps, err := appRepo.GetBy()
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
|
||||
showList := loadShowList()
|
||||
defaultList := []string{"openresty", "mysql", "halo", "redis", "maxkb", "wordpress"}
|
||||
allList := common.RemoveRepeatStr(append(defaultList, showList...))
|
||||
for _, showItem := range allList {
|
||||
var itemData dto.AppLauncher
|
||||
for _, app := range apps {
|
||||
if showItem == app.Key {
|
||||
itemData.Key = app.Key
|
||||
itemData.Type = app.Type
|
||||
itemData.Name = app.Name
|
||||
itemData.Icon = app.Icon
|
||||
itemData.Limit = app.Limit
|
||||
itemData.ShortDescEn = app.ShortDescEn
|
||||
itemData.ShortDescZh = app.ShortDescZh
|
||||
itemData.Recommend = app.Recommend
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(itemData.Icon) == 0 {
|
||||
continue
|
||||
}
|
||||
for _, install := range appInstalls {
|
||||
if install.App.Key == showItem {
|
||||
itemData.IsInstall = true
|
||||
itemData.Detail = append(itemData.Detail, dto.InstallDetail{
|
||||
InstallID: install.ID,
|
||||
DetailID: install.AppDetailId,
|
||||
Name: install.Name,
|
||||
Version: install.Version,
|
||||
Status: install.Status,
|
||||
Path: install.GetPath(),
|
||||
WebUI: install.WebUI,
|
||||
HttpPort: install.HttpPort,
|
||||
HttpsPort: install.HttpsPort,
|
||||
})
|
||||
}
|
||||
}
|
||||
if ArryContains(defaultList, showItem) && len(itemData.Detail) == 0 {
|
||||
itemData.IsRecommend = true
|
||||
recommendList = append(recommendList, itemData)
|
||||
continue
|
||||
}
|
||||
if !ArryContains(showList, showItem) && len(itemData.Detail) != 0 {
|
||||
continue
|
||||
}
|
||||
data = append(data, itemData)
|
||||
}
|
||||
|
||||
sort.Slice(recommendList, func(i, j int) bool {
|
||||
return recommendList[i].Recommend < recommendList[j].Recommend
|
||||
})
|
||||
sort.Slice(data, func(i, j int) bool {
|
||||
return data[i].Name < data[j].Name
|
||||
})
|
||||
data = append(data, recommendList...)
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (u *DashboardService) ListLauncherOption(filter string) ([]dto.LauncherOption, error) {
|
||||
showList := loadShowList()
|
||||
var data []dto.LauncherOption
|
||||
optionMap := make(map[string]bool)
|
||||
appInstalls, err := appInstallRepo.ListBy()
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
|
||||
for _, install := range appInstalls {
|
||||
isShow := false
|
||||
for _, item := range showList {
|
||||
if install.App.Key == item {
|
||||
isShow = true
|
||||
break
|
||||
}
|
||||
}
|
||||
optionMap[install.App.Key] = isShow
|
||||
}
|
||||
for key, val := range optionMap {
|
||||
if len(filter) != 0 && !strings.Contains(key, filter) {
|
||||
continue
|
||||
}
|
||||
data = append(data, dto.LauncherOption{Key: key, IsShow: val})
|
||||
}
|
||||
sort.Slice(data, func(i, j int) bool {
|
||||
return data[i].Key < data[j].Key
|
||||
})
|
||||
return data, nil
|
||||
}
|
||||
|
||||
type diskInfo struct {
|
||||
Type string
|
||||
Mount string
|
||||
@ -355,3 +462,42 @@ func loadGPUInfo() []dto.GPUInfo {
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func loadShowList() []string {
|
||||
var data []string
|
||||
if global.IsMaster {
|
||||
var list []AppLauncher
|
||||
if err := global.CoreDB.Model(AppLauncher{}).Where("1 == 1").Find(&list).Error; err != nil {
|
||||
return []string{}
|
||||
}
|
||||
for _, item := range list {
|
||||
data = append(data, item.Key)
|
||||
}
|
||||
return data
|
||||
}
|
||||
res, err := xpack.RequestToMaster("/api/v2/core/launcher/search", http.MethodGet, nil)
|
||||
if err != nil {
|
||||
return data
|
||||
}
|
||||
item, err := json.Marshal(res)
|
||||
if err != nil {
|
||||
return data
|
||||
}
|
||||
if err := json.Unmarshal(item, &data); err != nil {
|
||||
return data
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
type AppLauncher struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
func ArryContains(arr []string, element string) bool {
|
||||
for _, v := range arr {
|
||||
if v == element {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -12,6 +12,8 @@ func (s *DashboardRouter) InitRouter(Router *gin.RouterGroup) {
|
||||
baseApi := v2.ApiGroupApp.BaseApi
|
||||
{
|
||||
cmdRouter.GET("/base/os", baseApi.LoadDashboardOsInfo)
|
||||
cmdRouter.GET("/app/launcher", baseApi.LoadAppLauncher)
|
||||
cmdRouter.POST("/app/launcher/option", baseApi.LoadAppLauncherOption)
|
||||
cmdRouter.GET("/base/:ioOption/:netOption", baseApi.LoadDashboardBaseInfo)
|
||||
cmdRouter.GET("/current/node", baseApi.LoadCurrentInfoForNode)
|
||||
cmdRouter.GET("/current/:ioOption/:netOption", baseApi.LoadDashboardCurrentInfo)
|
||||
|
@ -229,6 +229,17 @@ func RemoveRepeatElement(a interface{}) (ret []interface{}) {
|
||||
return ret
|
||||
}
|
||||
|
||||
func RemoveRepeatStr(list []string) (ret []string) {
|
||||
mapItem := make(map[string]struct{})
|
||||
for _, item := range list {
|
||||
mapItem[item] = struct{}{}
|
||||
}
|
||||
for key := range mapItem {
|
||||
ret = append(ret, key)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func LoadSizeUnit(value float64) string {
|
||||
val := int64(value)
|
||||
if val%1024 != 0 {
|
||||
|
39
core/app/api/v2/app_launcher.go
Normal file
39
core/app/api/v2/app_launcher.go
Normal file
@ -0,0 +1,39 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/core/app/api/v2/helper"
|
||||
"github.com/1Panel-dev/1Panel/core/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/core/constant"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func (b *BaseApi) SearchAppLauncher(c *gin.Context) {
|
||||
data, err := appLauncherService.Search()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags App Launcher
|
||||
// @Summary Update app Launcher
|
||||
// @Description 更新首页显示应用
|
||||
// @Accept json
|
||||
// @Param request body dto.ChangeShow true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /core/app/launcher/show [post]
|
||||
// @x-panel-log {"bodyKeys":["key", "value"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"首页应用 [key] => 显示:[value]","formatEN":"app launcher [key] => show: [value]"}
|
||||
func (b *BaseApi) UpdateAppLauncher(c *gin.Context) {
|
||||
var req dto.SettingUpdate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := appLauncherService.ChangeShow(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
@ -9,12 +9,13 @@ type ApiGroup struct {
|
||||
var ApiGroupApp = new(ApiGroup)
|
||||
|
||||
var (
|
||||
hostService = service.NewIHostService()
|
||||
authService = service.NewIAuthService()
|
||||
backupService = service.NewIBackupService()
|
||||
settingService = service.NewISettingService()
|
||||
logService = service.NewILogService()
|
||||
upgradeService = service.NewIUpgradeService()
|
||||
groupService = service.NewIGroupService()
|
||||
commandService = service.NewICommandService()
|
||||
hostService = service.NewIHostService()
|
||||
authService = service.NewIAuthService()
|
||||
backupService = service.NewIBackupService()
|
||||
settingService = service.NewISettingService()
|
||||
logService = service.NewILogService()
|
||||
upgradeService = service.NewIUpgradeService()
|
||||
groupService = service.NewIGroupService()
|
||||
commandService = service.NewICommandService()
|
||||
appLauncherService = service.NewIAppLauncher()
|
||||
)
|
||||
|
6
core/app/model/app_launcher.go
Normal file
6
core/app/model/app_launcher.go
Normal file
@ -0,0 +1,6 @@
|
||||
package model
|
||||
|
||||
type AppLauncher struct {
|
||||
BaseModel
|
||||
Key string `json:"key"`
|
||||
}
|
50
core/app/repo/app_launcher.go
Normal file
50
core/app/repo/app_launcher.go
Normal file
@ -0,0 +1,50 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/core/app/model"
|
||||
"github.com/1Panel-dev/1Panel/core/global"
|
||||
)
|
||||
|
||||
type LauncherRepo struct{}
|
||||
|
||||
type ILauncherRepo interface {
|
||||
Get(opts ...DBOption) (model.AppLauncher, error)
|
||||
List(opts ...DBOption) ([]model.AppLauncher, error)
|
||||
Create(launcher *model.AppLauncher) error
|
||||
Delete(opts ...DBOption) error
|
||||
}
|
||||
|
||||
func NewILauncherRepo() ILauncherRepo {
|
||||
return &LauncherRepo{}
|
||||
}
|
||||
|
||||
func (u *LauncherRepo) Get(opts ...DBOption) (model.AppLauncher, error) {
|
||||
var launcher model.AppLauncher
|
||||
db := global.DB
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
err := db.First(&launcher).Error
|
||||
return launcher, err
|
||||
}
|
||||
func (u *LauncherRepo) List(opts ...DBOption) ([]model.AppLauncher, error) {
|
||||
var ops []model.AppLauncher
|
||||
db := global.DB.Model(&model.AppLauncher{})
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
err := db.Find(&ops).Error
|
||||
return ops, err
|
||||
}
|
||||
|
||||
func (u *LauncherRepo) Create(launcher *model.AppLauncher) error {
|
||||
return global.DB.Create(launcher).Error
|
||||
}
|
||||
|
||||
func (u *LauncherRepo) Delete(opts ...DBOption) error {
|
||||
db := global.DB
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
return db.Delete(&model.AppLauncher{}).Error
|
||||
}
|
@ -15,6 +15,7 @@ type ICommonRepo interface {
|
||||
WithByName(name string) DBOption
|
||||
WithLikeName(name string) DBOption
|
||||
WithByType(ty string) DBOption
|
||||
WithByKey(key string) DBOption
|
||||
WithOrderBy(orderStr string) DBOption
|
||||
|
||||
WithOrderRuleBy(orderBy, order string) DBOption
|
||||
@ -60,6 +61,11 @@ func (c *CommonRepo) WithByType(ty string) DBOption {
|
||||
return g.Where("`type` = ?", ty)
|
||||
}
|
||||
}
|
||||
func (c *CommonRepo) WithByKey(key string) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
return g.Where("key = ?", key)
|
||||
}
|
||||
}
|
||||
func (c *CommonRepo) WithOrderBy(orderStr string) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
return g.Order(orderStr)
|
||||
|
@ -3,7 +3,6 @@ package repo
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/core/app/model"
|
||||
"github.com/1Panel-dev/1Panel/core/global"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type SettingRepo struct{}
|
||||
@ -13,7 +12,6 @@ type ISettingRepo interface {
|
||||
Get(opts ...DBOption) (model.Setting, error)
|
||||
Create(key, value string) error
|
||||
Update(key, value string) error
|
||||
WithByKey(key string) DBOption
|
||||
}
|
||||
|
||||
func NewISettingRepo() ISettingRepo {
|
||||
@ -48,12 +46,6 @@ func (u *SettingRepo) Get(opts ...DBOption) (model.Setting, error) {
|
||||
return settings, err
|
||||
}
|
||||
|
||||
func (c *SettingRepo) WithByKey(key string) DBOption {
|
||||
return func(g *gorm.DB) *gorm.DB {
|
||||
return g.Where("key = ?", key)
|
||||
}
|
||||
}
|
||||
|
||||
func (u *SettingRepo) Update(key, value string) error {
|
||||
return global.DB.Model(&model.Setting{}).Where("key = ?", key).Updates(map[string]interface{}{"value": value}).Error
|
||||
}
|
||||
|
45
core/app/service/app_launcher.go
Normal file
45
core/app/service/app_launcher.go
Normal file
@ -0,0 +1,45 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/core/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/core/constant"
|
||||
)
|
||||
|
||||
type LauncherService struct{}
|
||||
|
||||
type IAppLauncher interface {
|
||||
Search() ([]string, error)
|
||||
ChangeShow(req dto.SettingUpdate) error
|
||||
}
|
||||
|
||||
func NewIAppLauncher() IAppLauncher {
|
||||
return &LauncherService{}
|
||||
}
|
||||
|
||||
func (u *LauncherService) Search() ([]string, error) {
|
||||
launchers, err := launcherRepo.List(commonRepo.WithOrderBy("created_at"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var data []string
|
||||
for _, launcher := range launchers {
|
||||
data = append(data, launcher.Key)
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (u *LauncherService) ChangeShow(req dto.SettingUpdate) error {
|
||||
launcher, _ := launcherRepo.Get(commonRepo.WithByKey(req.Key))
|
||||
if req.Value == constant.StatusEnable {
|
||||
if launcher.ID != 0 {
|
||||
return nil
|
||||
}
|
||||
launcher.Key = req.Key
|
||||
return launcherRepo.Create(&launcher)
|
||||
}
|
||||
if launcher.ID == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return launcherRepo.Delete(commonRepo.WithByKey(req.Key))
|
||||
}
|
@ -32,11 +32,11 @@ func NewIAuthService() IAuthService {
|
||||
}
|
||||
|
||||
func (u *AuthService) Login(c *gin.Context, info dto.Login, entrance string) (*dto.UserLoginInfo, error) {
|
||||
nameSetting, err := settingRepo.Get(settingRepo.WithByKey("UserName"))
|
||||
nameSetting, err := settingRepo.Get(commonRepo.WithByKey("UserName"))
|
||||
if err != nil {
|
||||
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
|
||||
}
|
||||
passwordSetting, err := settingRepo.Get(settingRepo.WithByKey("Password"))
|
||||
passwordSetting, err := settingRepo.Get(commonRepo.WithByKey("Password"))
|
||||
if err != nil {
|
||||
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
|
||||
}
|
||||
@ -47,14 +47,14 @@ func (u *AuthService) Login(c *gin.Context, info dto.Login, entrance string) (*d
|
||||
if !hmac.Equal([]byte(info.Password), []byte(pass)) || nameSetting.Value != info.Name {
|
||||
return nil, constant.ErrAuth
|
||||
}
|
||||
entranceSetting, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
|
||||
entranceSetting, err := settingRepo.Get(commonRepo.WithByKey("SecurityEntrance"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(entranceSetting.Value) != 0 && entranceSetting.Value != entrance {
|
||||
return nil, buserr.New(constant.ErrEntrance)
|
||||
}
|
||||
mfa, err := settingRepo.Get(settingRepo.WithByKey("MFAStatus"))
|
||||
mfa, err := settingRepo.Get(commonRepo.WithByKey("MFAStatus"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -68,11 +68,11 @@ func (u *AuthService) Login(c *gin.Context, info dto.Login, entrance string) (*d
|
||||
}
|
||||
|
||||
func (u *AuthService) MFALogin(c *gin.Context, info dto.MFALogin, entrance string) (*dto.UserLoginInfo, error) {
|
||||
nameSetting, err := settingRepo.Get(settingRepo.WithByKey("UserName"))
|
||||
nameSetting, err := settingRepo.Get(commonRepo.WithByKey("UserName"))
|
||||
if err != nil {
|
||||
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
|
||||
}
|
||||
passwordSetting, err := settingRepo.Get(settingRepo.WithByKey("Password"))
|
||||
passwordSetting, err := settingRepo.Get(commonRepo.WithByKey("Password"))
|
||||
if err != nil {
|
||||
return nil, errors.WithMessage(constant.ErrRecordNotFound, err.Error())
|
||||
}
|
||||
@ -83,18 +83,18 @@ func (u *AuthService) MFALogin(c *gin.Context, info dto.MFALogin, entrance strin
|
||||
if !hmac.Equal([]byte(info.Password), []byte(pass)) || nameSetting.Value != info.Name {
|
||||
return nil, constant.ErrAuth
|
||||
}
|
||||
entranceSetting, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
|
||||
entranceSetting, err := settingRepo.Get(commonRepo.WithByKey("SecurityEntrance"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(entranceSetting.Value) != 0 && entranceSetting.Value != entrance {
|
||||
return nil, buserr.New(constant.ErrEntrance)
|
||||
}
|
||||
mfaSecret, err := settingRepo.Get(settingRepo.WithByKey("MFASecret"))
|
||||
mfaSecret, err := settingRepo.Get(commonRepo.WithByKey("MFASecret"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mfaInterval, err := settingRepo.Get(settingRepo.WithByKey("MFAInterval"))
|
||||
mfaInterval, err := settingRepo.Get(commonRepo.WithByKey("MFAInterval"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -107,11 +107,11 @@ func (u *AuthService) MFALogin(c *gin.Context, info dto.MFALogin, entrance strin
|
||||
}
|
||||
|
||||
func (u *AuthService) generateSession(c *gin.Context, name, authMethod string) (*dto.UserLoginInfo, error) {
|
||||
setting, err := settingRepo.Get(settingRepo.WithByKey("SessionTimeout"))
|
||||
setting, err := settingRepo.Get(commonRepo.WithByKey("SessionTimeout"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
httpsSetting, err := settingRepo.Get(settingRepo.WithByKey("SSL"))
|
||||
httpsSetting, err := settingRepo.Get(commonRepo.WithByKey("SSL"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -151,7 +151,7 @@ func (u *AuthService) generateSession(c *gin.Context, name, authMethod string) (
|
||||
}
|
||||
|
||||
func (u *AuthService) LogOut(c *gin.Context) error {
|
||||
httpsSetting, err := settingRepo.Get(settingRepo.WithByKey("SSL"))
|
||||
httpsSetting, err := settingRepo.Get(commonRepo.WithByKey("SSL"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -167,7 +167,7 @@ func (u *AuthService) LogOut(c *gin.Context) error {
|
||||
}
|
||||
|
||||
func (u *AuthService) VerifyCode(code string) (bool, error) {
|
||||
setting, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
|
||||
setting, err := settingRepo.Get(commonRepo.WithByKey("SecurityEntrance"))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@ -175,7 +175,7 @@ func (u *AuthService) VerifyCode(code string) (bool, error) {
|
||||
}
|
||||
|
||||
func (u *AuthService) CheckIsSafety(code string) (string, error) {
|
||||
status, err := settingRepo.Get(settingRepo.WithByKey("SecurityEntrance"))
|
||||
status, err := settingRepo.Get(commonRepo.WithByKey("SecurityEntrance"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@ -189,7 +189,7 @@ func (u *AuthService) CheckIsSafety(code string) (string, error) {
|
||||
}
|
||||
|
||||
func (u *AuthService) GetResponsePage() (string, error) {
|
||||
pageCode, err := settingRepo.Get(settingRepo.WithByKey("NoAuthSetting"))
|
||||
pageCode, err := settingRepo.Get(commonRepo.WithByKey("NoAuthSetting"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ func (u *BackupService) SearchWithPage(req dto.SearchPageWithType) (int64, inter
|
||||
func (u *BackupService) LoadOneDriveInfo() (dto.OneDriveInfo, error) {
|
||||
var data dto.OneDriveInfo
|
||||
data.RedirectUri = constant.OneDriveRedirectURI
|
||||
clientID, err := settingRepo.Get(settingRepo.WithByKey("OneDriveID"))
|
||||
clientID, err := settingRepo.Get(commonRepo.WithByKey("OneDriveID"))
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
@ -182,7 +182,7 @@ func (u *BackupService) LoadOneDriveInfo() (dto.OneDriveInfo, error) {
|
||||
return data, err
|
||||
}
|
||||
data.ClientID = string(idItem)
|
||||
clientSecret, err := settingRepo.Get(settingRepo.WithByKey("OneDriveSc"))
|
||||
clientSecret, err := settingRepo.Get(commonRepo.WithByKey("OneDriveSc"))
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
|
@ -3,11 +3,12 @@ package service
|
||||
import "github.com/1Panel-dev/1Panel/core/app/repo"
|
||||
|
||||
var (
|
||||
hostRepo = repo.NewIHostRepo()
|
||||
commandRepo = repo.NewICommandRepo()
|
||||
commonRepo = repo.NewICommonRepo()
|
||||
settingRepo = repo.NewISettingRepo()
|
||||
backupRepo = repo.NewIBackupRepo()
|
||||
logRepo = repo.NewILogRepo()
|
||||
groupRepo = repo.NewIGroupRepo()
|
||||
hostRepo = repo.NewIHostRepo()
|
||||
commandRepo = repo.NewICommandRepo()
|
||||
commonRepo = repo.NewICommonRepo()
|
||||
settingRepo = repo.NewISettingRepo()
|
||||
backupRepo = repo.NewIBackupRepo()
|
||||
logRepo = repo.NewILogRepo()
|
||||
groupRepo = repo.NewIGroupRepo()
|
||||
launcherRepo = repo.NewILauncherRepo()
|
||||
)
|
||||
|
@ -74,7 +74,7 @@ func (u *SettingService) GetSettingInfo() (*dto.SettingInfo, error) {
|
||||
func (u *SettingService) Update(key, value string) error {
|
||||
switch key {
|
||||
case "AppStoreLastModified":
|
||||
exist, _ := settingRepo.Get(settingRepo.WithByKey("AppStoreLastModified"))
|
||||
exist, _ := settingRepo.Get(commonRepo.WithByKey("AppStoreLastModified"))
|
||||
if exist.ID == 0 {
|
||||
_ = settingRepo.Create("AppStoreLastModified", value)
|
||||
return nil
|
||||
@ -270,14 +270,14 @@ func (u *SettingService) UpdateSSL(c *gin.Context, req dto.SSLUpdate) error {
|
||||
}
|
||||
|
||||
func (u *SettingService) LoadFromCert() (*dto.SSLInfo, error) {
|
||||
ssl, err := settingRepo.Get(settingRepo.WithByKey("SSL"))
|
||||
ssl, err := settingRepo.Get(commonRepo.WithByKey("SSL"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ssl.Value == "disable" {
|
||||
return &dto.SSLInfo{}, nil
|
||||
}
|
||||
sslType, err := settingRepo.Get(settingRepo.WithByKey("SSLType"))
|
||||
sslType, err := settingRepo.Get(commonRepo.WithByKey("SSLType"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -311,7 +311,7 @@ func (u *SettingService) LoadFromCert() (*dto.SSLInfo, error) {
|
||||
}
|
||||
|
||||
func (u *SettingService) HandlePasswordExpired(c *gin.Context, old, new string) error {
|
||||
setting, err := settingRepo.Get(settingRepo.WithByKey("Password"))
|
||||
setting, err := settingRepo.Get(commonRepo.WithByKey("Password"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -328,7 +328,7 @@ func (u *SettingService) HandlePasswordExpired(c *gin.Context, old, new string)
|
||||
return err
|
||||
}
|
||||
|
||||
expiredSetting, err := settingRepo.Get(settingRepo.WithByKey("ExpirationDays"))
|
||||
expiredSetting, err := settingRepo.Get(commonRepo.WithByKey("ExpirationDays"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -33,11 +33,11 @@ func NewIUpgradeService() IUpgradeService {
|
||||
|
||||
func (u *UpgradeService) SearchUpgrade() (*dto.UpgradeInfo, error) {
|
||||
var upgrade dto.UpgradeInfo
|
||||
currentVersion, err := settingRepo.Get(settingRepo.WithByKey("SystemVersion"))
|
||||
currentVersion, err := settingRepo.Get(commonRepo.WithByKey("SystemVersion"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
DeveloperMode, err := settingRepo.Get(settingRepo.WithByKey("DeveloperMode"))
|
||||
DeveloperMode, err := settingRepo.Get(commonRepo.WithByKey("DeveloperMode"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -14,33 +14,34 @@ import (
|
||||
|
||||
func Init() {
|
||||
settingRepo := repo.NewISettingRepo()
|
||||
masterSetting, err := settingRepo.Get(settingRepo.WithByKey("MasterAddr"))
|
||||
commonRepo := repo.NewICommonRepo()
|
||||
masterSetting, err := settingRepo.Get(commonRepo.WithByKey("MasterAddr"))
|
||||
if err != nil {
|
||||
global.LOG.Errorf("load master addr from setting failed, err: %v", err)
|
||||
}
|
||||
global.CONF.System.MasterAddr = masterSetting.Value
|
||||
portSetting, err := settingRepo.Get(settingRepo.WithByKey("ServerPort"))
|
||||
portSetting, err := settingRepo.Get(commonRepo.WithByKey("ServerPort"))
|
||||
if err != nil {
|
||||
global.LOG.Errorf("load service port from setting failed, err: %v", err)
|
||||
}
|
||||
global.CONF.System.Port = portSetting.Value
|
||||
ipv6Setting, err := settingRepo.Get(settingRepo.WithByKey("Ipv6"))
|
||||
ipv6Setting, err := settingRepo.Get(commonRepo.WithByKey("Ipv6"))
|
||||
if err != nil {
|
||||
global.LOG.Errorf("load ipv6 status from setting failed, err: %v", err)
|
||||
}
|
||||
global.CONF.System.Ipv6 = ipv6Setting.Value
|
||||
bindAddressSetting, err := settingRepo.Get(settingRepo.WithByKey("BindAddress"))
|
||||
bindAddressSetting, err := settingRepo.Get(commonRepo.WithByKey("BindAddress"))
|
||||
if err != nil {
|
||||
global.LOG.Errorf("load bind address from setting failed, err: %v", err)
|
||||
}
|
||||
global.CONF.System.BindAddress = bindAddressSetting.Value
|
||||
sslSetting, err := settingRepo.Get(settingRepo.WithByKey("SSL"))
|
||||
sslSetting, err := settingRepo.Get(commonRepo.WithByKey("SSL"))
|
||||
if err != nil {
|
||||
global.LOG.Errorf("load service ssl from setting failed, err: %v", err)
|
||||
}
|
||||
global.CONF.System.SSL = sslSetting.Value
|
||||
|
||||
if _, err := settingRepo.Get(settingRepo.WithByKey("SystemStatus")); err != nil {
|
||||
if _, err := settingRepo.Get(commonRepo.WithByKey("SystemStatus")); err != nil {
|
||||
_ = settingRepo.Create("SystemStatus", "Free")
|
||||
}
|
||||
if err := settingRepo.Update("SystemStatus", "Free"); err != nil {
|
||||
|
@ -15,6 +15,7 @@ func Init() {
|
||||
migrations.InitMasterAddr,
|
||||
migrations.InitHost,
|
||||
migrations.InitTerminalSetting,
|
||||
migrations.InitAppLauncher,
|
||||
})
|
||||
if err := m.Migrate(); err != nil {
|
||||
global.LOG.Error(err)
|
||||
|
@ -233,3 +233,10 @@ var InitTerminalSetting = &gormigrate.Migration{
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var InitAppLauncher = &gormigrate.Migration{
|
||||
ID: "20241029-init-app-launcher",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
return tx.AutoMigrate(&model.AppLauncher{})
|
||||
},
|
||||
}
|
||||
|
@ -13,7 +13,8 @@ import (
|
||||
func BindDomain() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
settingRepo := repo.NewISettingRepo()
|
||||
status, err := settingRepo.Get(settingRepo.WithByKey("BindDomain"))
|
||||
commonRepo := repo.NewICommonRepo()
|
||||
status, err := settingRepo.Get(commonRepo.WithByKey("BindDomain"))
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
|
@ -8,7 +8,8 @@ import (
|
||||
|
||||
func LoadErrCode(errInfo string) int {
|
||||
settingRepo := repo.NewISettingRepo()
|
||||
codeVal, err := settingRepo.Get(settingRepo.WithByKey("NoAuthSetting"))
|
||||
commonRepo := repo.NewICommonRepo()
|
||||
codeVal, err := settingRepo.Get(commonRepo.WithByKey("NoAuthSetting"))
|
||||
if err != nil {
|
||||
return 500
|
||||
}
|
||||
|
@ -15,7 +15,8 @@ import (
|
||||
func WhiteAllow() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
settingRepo := repo.NewISettingRepo()
|
||||
status, err := settingRepo.Get(settingRepo.WithByKey("AllowIPs"))
|
||||
commonRepo := repo.NewICommonRepo()
|
||||
status, err := settingRepo.Get(commonRepo.WithByKey("AllowIPs"))
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
|
@ -10,7 +10,8 @@ import (
|
||||
func GlobalLoading() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
settingRepo := repo.NewISettingRepo()
|
||||
status, err := settingRepo.Get(settingRepo.WithByKey("SystemStatus"))
|
||||
commonRepo := repo.NewICommonRepo()
|
||||
status, err := settingRepo.Get(commonRepo.WithByKey("SystemStatus"))
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
|
@ -21,7 +21,8 @@ func PasswordExpired() gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
settingRepo := repo.NewISettingRepo()
|
||||
setting, err := settingRepo.Get(settingRepo.WithByKey("ExpirationDays"))
|
||||
commonRepo := repo.NewICommonRepo()
|
||||
setting, err := settingRepo.Get(commonRepo.WithByKey("ExpirationDays"))
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypePasswordExpired, err)
|
||||
return
|
||||
@ -32,7 +33,7 @@ func PasswordExpired() gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
extime, err := settingRepo.Get(settingRepo.WithByKey("ExpirationTime"))
|
||||
extime, err := settingRepo.Get(commonRepo.WithByKey("ExpirationTime"))
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypePasswordExpired, err)
|
||||
return
|
||||
|
@ -32,7 +32,8 @@ func SessionAuth() gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
settingRepo := repo.NewISettingRepo()
|
||||
setting, err := settingRepo.Get(settingRepo.WithByKey("SessionTimeout"))
|
||||
commonRepo := repo.NewICommonRepo()
|
||||
setting, err := settingRepo.Get(commonRepo.WithByKey("SessionTimeout"))
|
||||
if err != nil {
|
||||
global.LOG.Errorf("create operation record failed, err: %v", err)
|
||||
}
|
||||
|
17
core/router/app_launcher.go
Normal file
17
core/router/app_launcher.go
Normal file
@ -0,0 +1,17 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
v2 "github.com/1Panel-dev/1Panel/core/app/api/v2"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type AppLauncherRouter struct{}
|
||||
|
||||
func (s *AppLauncherRouter) InitRouter(Router *gin.RouterGroup) {
|
||||
launcherRouter := Router.Group("launcher")
|
||||
baseApi := v2.ApiGroupApp.BaseApi
|
||||
{
|
||||
launcherRouter.GET("/search", baseApi.SearchAppLauncher)
|
||||
launcherRouter.POST("/change/show", baseApi.UpdateAppLauncher)
|
||||
}
|
||||
}
|
@ -9,5 +9,6 @@ func commonGroups() []CommonRouter {
|
||||
&CommandRouter{},
|
||||
&HostRouter{},
|
||||
&GroupRouter{},
|
||||
&AppLauncherRouter{},
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,8 @@ type BaseClaims struct {
|
||||
|
||||
func NewJWT() *JWT {
|
||||
settingRepo := repo.NewISettingRepo()
|
||||
jwtSign, _ := settingRepo.Get(settingRepo.WithByKey("JWTSigningKey"))
|
||||
commonRepo := repo.NewICommonRepo()
|
||||
jwtSign, _ := settingRepo.Get(commonRepo.WithByKey("JWTSigningKey"))
|
||||
return &JWT{
|
||||
[]byte(jwtSign.Value),
|
||||
}
|
||||
|
@ -8,6 +8,34 @@ export namespace Dashboard {
|
||||
|
||||
diskSize: number;
|
||||
}
|
||||
export interface AppLauncher {
|
||||
key: string;
|
||||
icon: string;
|
||||
limit: number;
|
||||
shortDescEn: string;
|
||||
shortDescZh: string;
|
||||
currentRow: InstallDetail;
|
||||
|
||||
isInstall: boolean;
|
||||
isRecommend: boolean;
|
||||
detail: Array<InstallDetail>;
|
||||
}
|
||||
export interface AppLauncherOption {
|
||||
key: string;
|
||||
isShow: boolean;
|
||||
}
|
||||
export interface InstallDetail {
|
||||
installID: number;
|
||||
detailID: string;
|
||||
name: string;
|
||||
version: string;
|
||||
path: string;
|
||||
status: string;
|
||||
appType: string;
|
||||
webUI: string;
|
||||
httpPort: string;
|
||||
httpsPort: string;
|
||||
}
|
||||
export interface BaseInfo {
|
||||
websiteNumber: number;
|
||||
databaseNumber: number;
|
||||
|
@ -5,6 +5,19 @@ export const loadOsInfo = () => {
|
||||
return http.get<Dashboard.OsInfo>(`/dashboard/base/os`);
|
||||
};
|
||||
|
||||
export const loadAppLauncher = () => {
|
||||
return http.get<Array<Dashboard.AppLauncher>>(`/dashboard/app/launcher`);
|
||||
};
|
||||
export const loadAppLauncherOption = (filter: string) => {
|
||||
return http.post<Array<Dashboard.AppLauncherOption>>(`/dashboard/app/launcher/option`, { filter: filter });
|
||||
};
|
||||
export const changeLauncherStatus = (key: string, val: string) => {
|
||||
return http.post(`/core/launcher/change/show`, { key: key, value: val });
|
||||
};
|
||||
export const resetLauncherStatus = () => {
|
||||
return http.post(`/core/launcher/reset`);
|
||||
};
|
||||
|
||||
export const loadBaseInfo = (ioOption: string, netOption: string) => {
|
||||
return http.get<Dashboard.BaseInfo>(`/dashboard/base/${ioOption}/${netOption}`);
|
||||
};
|
||||
|
@ -336,6 +336,8 @@ const message = {
|
||||
name: 'Tamper Proof',
|
||||
},
|
||||
home: {
|
||||
recommend: 'recommend',
|
||||
dir: 'dir',
|
||||
restart_1panel: 'Restart Panel',
|
||||
restart_system: 'Restart Server',
|
||||
operationSuccess: 'Operation succeeded, rebooting, please refresh the browser manually later!',
|
||||
|
@ -330,6 +330,8 @@ const message = {
|
||||
tamper: '防篡改',
|
||||
},
|
||||
home: {
|
||||
recommend: '推薦',
|
||||
dir: '目錄',
|
||||
restart_1panel: '重啟面板',
|
||||
restart_system: '重啟服務器',
|
||||
operationSuccess: '操作成功,正在重啟,請稍後手動刷新瀏覽器!',
|
||||
|
@ -330,6 +330,8 @@ const message = {
|
||||
tamper: '防篡改',
|
||||
},
|
||||
home: {
|
||||
recommend: '推荐',
|
||||
dir: '目录',
|
||||
restart_1panel: '重启面板',
|
||||
restart_system: '重启服务器',
|
||||
operationSuccess: '操作成功,正在重启,请稍后手动刷新浏览器!',
|
||||
|
@ -1,67 +1,212 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-scrollbar height="525px" class="moz-height">
|
||||
<div class="h-app-card" v-for="(app, index) in apps" :key="index">
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="5">
|
||||
<div>
|
||||
<el-avatar shape="square" :size="55" :src="'data:image/png;base64,' + app.icon" />
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="15">
|
||||
<div class="h-app-content">
|
||||
<div>
|
||||
<span class="h-app-title">{{ app.name }}</span>
|
||||
</div>
|
||||
<div class="h-app-desc">
|
||||
<span>
|
||||
{{ language == 'zh' || language == 'tw' ? app.shortDescZh : app.shortDescEn }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
<el-button
|
||||
class="h-app-button"
|
||||
type="primary"
|
||||
plain
|
||||
round
|
||||
size="small"
|
||||
:disabled="app.limit == 1 && app.installed"
|
||||
@click="goInstall(app.key, app.type)"
|
||||
>
|
||||
{{ $t('app.install') }}
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="h-app-divider" />
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
<CardWithHeader :header="$t('home.app')" class="mt-5" :loading="loading">
|
||||
<template #header-r>
|
||||
<el-popover placement="left" :width="226" trigger="click">
|
||||
<el-input size="small" v-model="filter" clearable @input="loadOption()" />
|
||||
<el-table :show-header="false" :data="options" stripe max-height="500px">
|
||||
<el-table-column prop="key" width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="name">
|
||||
<template #default="{ row }">
|
||||
<el-switch
|
||||
@change="onChangeStatus(row)"
|
||||
class="float-right"
|
||||
size="small"
|
||||
v-model="row.isShow"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<template #reference>
|
||||
<el-button class="h-button-setting" link icon="Setting"></el-button>
|
||||
</template>
|
||||
</el-popover>
|
||||
</template>
|
||||
<template #body>
|
||||
<el-scrollbar height="525px" class="moz-height">
|
||||
<div class="h-app-card" v-for="(app, index) in apps" :key="index">
|
||||
<el-row :gutter="5">
|
||||
<el-col :span="5">
|
||||
<div>
|
||||
<el-badge
|
||||
badge-style="background-color: transparent; color: #646a73; font-size: 12px; border: none"
|
||||
:value="$t('home.recommend')"
|
||||
v-if="app.isRecommend"
|
||||
:offset="[-60, 0]"
|
||||
>
|
||||
<el-avatar
|
||||
shape="square"
|
||||
:size="55"
|
||||
:src="'data:image/png;base64,' + app.icon"
|
||||
/>
|
||||
</el-badge>
|
||||
<el-avatar
|
||||
v-else
|
||||
shape="square"
|
||||
:size="55"
|
||||
:src="'data:image/png;base64,' + app.icon"
|
||||
/>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="16">
|
||||
<div class="h-app-content" v-if="!app.currentRow">
|
||||
<div>
|
||||
<span class="h-app-title">{{ app.name }}</span>
|
||||
</div>
|
||||
<div class="h-app-desc">
|
||||
<span>
|
||||
{{
|
||||
language == 'zh' || language == 'tw' ? app.shortDescZh : app.shortDescEn
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="h-app-content" v-else>
|
||||
<div>
|
||||
<el-dropdown trigger="hover">
|
||||
<el-button plain size="small" link class="h-app-dropdown">
|
||||
{{ app.currentRow.name }}
|
||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu
|
||||
v-for="(detailItem, index2) in app.detail"
|
||||
:key="index2"
|
||||
>
|
||||
<el-dropdown-item @click="app.currentRow = detailItem">
|
||||
{{ detailItem.name + ' - ' + detailItem.version }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<div class="h-app-margin">
|
||||
<el-button plain size="small" link class="h-app-desc">
|
||||
{{ $t('app.version') + ': ' + app.currentRow.version }}
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="h-app-margin">
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
link
|
||||
@click="onOperate('stop', app.currentRow)"
|
||||
>
|
||||
{{ $t('commons.operate.up') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
:style="mobile ? 'margin-left: -1px' : ''"
|
||||
size="small"
|
||||
type="primary"
|
||||
link
|
||||
@click="onOperate('stop', app.currentRow)"
|
||||
>
|
||||
{{ $t('commons.operate.down') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
:style="mobile ? 'margin-left: -1px' : ''"
|
||||
size="small"
|
||||
type="primary"
|
||||
link
|
||||
@click="toFolder(app.currentRow.path)"
|
||||
>
|
||||
{{ $t('home.dir') }}
|
||||
</el-button>
|
||||
<el-popover
|
||||
placement="left"
|
||||
trigger="hover"
|
||||
v-if="app.currentRow.appType == 'website'"
|
||||
:width="260"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button
|
||||
link
|
||||
size="small"
|
||||
type="primary"
|
||||
:style="mobile ? 'margin-left: -1px' : ''"
|
||||
>
|
||||
{{ $t('app.toLink') }}
|
||||
</el-button>
|
||||
</template>
|
||||
<span v-if="defaultLink == '' && app.currentRow.webUI == ''">
|
||||
{{ $t('app.webUIConfig') }}
|
||||
</span>
|
||||
<div v-else>
|
||||
<div>
|
||||
<el-button
|
||||
v-if="defaultLink != ''"
|
||||
type="primary"
|
||||
link
|
||||
@click="toLink(defaultLink + ':' + app.currentRow.httpPort)"
|
||||
>
|
||||
{{ defaultLink + ':' + app.currentRow.httpPort }}
|
||||
</el-button>
|
||||
</div>
|
||||
<div>
|
||||
<el-button
|
||||
v-if="app.currentRow.webUI != ''"
|
||||
type="primary"
|
||||
link
|
||||
@click="toLink(app.currentRow.webUI)"
|
||||
>
|
||||
{{ app.currentRow.webUI }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-popover>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="1">
|
||||
<el-button
|
||||
class="h-app-button"
|
||||
type="primary"
|
||||
plain
|
||||
round
|
||||
size="small"
|
||||
:disabled="app.limit == 1 && app.detail && app.detail.length !== 0"
|
||||
@click="goInstall(app.key, app.appType)"
|
||||
>
|
||||
{{ $t('app.install') }}
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="h-app-divider" />
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</template>
|
||||
</CardWithHeader>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { App } from '@/api/interface/app';
|
||||
import { SearchApp } from '@/api/modules/app';
|
||||
import { GetAppStoreConfig, InstalledOp } from '@/api/modules/app';
|
||||
import { changeLauncherStatus, loadAppLauncher, loadAppLauncherOption } from '@/api/modules/dashboard';
|
||||
import i18n from '@/lang';
|
||||
import { GlobalStore } from '@/store';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { getLanguage } from '@/utils/util';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { toFolder } from '@/global/business';
|
||||
|
||||
const router = useRouter();
|
||||
const language = getLanguage();
|
||||
|
||||
let req = reactive({
|
||||
name: '',
|
||||
tags: [],
|
||||
page: 1,
|
||||
pageSize: 50,
|
||||
recommend: true,
|
||||
});
|
||||
const globalStore = GlobalStore();
|
||||
|
||||
let loading = ref(false);
|
||||
let apps = ref<App.AppDTO[]>([]);
|
||||
let apps = ref([]);
|
||||
const options = ref([]);
|
||||
const filter = ref();
|
||||
const mobile = computed(() => {
|
||||
return globalStore.isMobile();
|
||||
});
|
||||
const defaultLink = ref('');
|
||||
|
||||
const acceptParams = (): void => {
|
||||
search(req);
|
||||
search();
|
||||
loadOption();
|
||||
getAppStoreConfig();
|
||||
};
|
||||
|
||||
const goInstall = (key: string, type: string) => {
|
||||
@ -77,17 +222,82 @@ const goInstall = (key: string, type: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
const search = async (req: App.AppReq) => {
|
||||
const search = async () => {
|
||||
loading.value = true;
|
||||
await SearchApp(req)
|
||||
await loadAppLauncher()
|
||||
.then((res) => {
|
||||
apps.value = res.data.items;
|
||||
loading.value = false;
|
||||
apps.value = res.data;
|
||||
for (const item of apps.value) {
|
||||
if (item.detail && item.detail.length !== 0) {
|
||||
item.currentRow = item.detail[0];
|
||||
}
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const onChangeStatus = async (row: any) => {
|
||||
loading.value = true;
|
||||
await changeLauncherStatus(row.key, row.isShow ? 'Enable' : 'Disable')
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
search();
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const toLink = (link: string) => {
|
||||
window.open(link, '_blank');
|
||||
};
|
||||
|
||||
const getAppStoreConfig = async () => {
|
||||
try {
|
||||
const res = await GetAppStoreConfig();
|
||||
if (res.data.defaultDomain != '') {
|
||||
defaultLink.value = res.data.defaultDomain;
|
||||
}
|
||||
} catch (error) {}
|
||||
};
|
||||
|
||||
const onOperate = async (operation: string, row: any) => {
|
||||
ElMessageBox.confirm(
|
||||
i18n.global.t('app.operatorHelper', [i18n.global.t('app.' + operation)]),
|
||||
i18n.global.t('app.' + operation),
|
||||
{
|
||||
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
||||
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
||||
type: 'info',
|
||||
},
|
||||
).then(async () => {
|
||||
loading.value = true;
|
||||
let params = {
|
||||
installId: row.installId,
|
||||
operate: operation,
|
||||
detailId: row.detailId,
|
||||
};
|
||||
await InstalledOp(params)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
search();
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const loadOption = async () => {
|
||||
const res = await loadAppLauncherOption(filter.value || '');
|
||||
options.value = res.data || [];
|
||||
console.log(options.value);
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
@ -125,11 +335,39 @@ defineExpose({
|
||||
}
|
||||
|
||||
.h-app-divider {
|
||||
margin-top: 13px;
|
||||
margin-top: 10px;
|
||||
border: 0;
|
||||
border-top: var(--panel-border);
|
||||
}
|
||||
|
||||
.h-app-desc {
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-regular);
|
||||
}
|
||||
|
||||
.h-button-setting {
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.h-app-dropdown {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
color: #1f2329;
|
||||
}
|
||||
|
||||
.h-app-margin {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.h-app-option {
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: var(--el-text-color-regular);
|
||||
}
|
||||
|
||||
/* FOR MOZILLA */
|
||||
@-moz-document url-prefix() {
|
||||
.moz-height {
|
||||
|
@ -230,11 +230,7 @@
|
||||
</template>
|
||||
</CardWithHeader>
|
||||
|
||||
<CardWithHeader :header="$t('home.app')" style="margin-top: 20px">
|
||||
<template #body>
|
||||
<App ref="appRef" />
|
||||
</template>
|
||||
</CardWithHeader>
|
||||
<AppLauncher ref="appRef" style="margin-top: 20px" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
@ -245,7 +241,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, onBeforeUnmount, ref, reactive } from 'vue';
|
||||
import Status from '@/views/home/status/index.vue';
|
||||
import App from '@/views/home/app/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 CardWithHeader from '@/components/card-with-header/index.vue';
|
||||
|
Loading…
x
Reference in New Issue
Block a user