feat: 完善节点管理功能 (#6139)
Some checks failed
sync2gitee / repo-sync (push) Failing after -7m53s

This commit is contained in:
ssongliu 2024-08-15 17:06:50 +08:00 committed by GitHub
parent 226bf9d8d2
commit 2c2228192f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 123 additions and 87 deletions

View file

@ -52,6 +52,17 @@ func (b *BaseApi) LoadDashboardBaseInfo(c *gin.Context) {
helper.SuccessWithData(c, data)
}
// @Tags Dashboard
// @Summary Load dashboard current info for node
// @Description 获取节点实时数据
// @Success 200 {object} dto.NodeCurrent
// @Security ApiKeyAuth
// @Router /dashboard/current/node [get]
func (b *BaseApi) LoadCurrentInfoForNode(c *gin.Context) {
data := dashboardService.LoadCurrentInfoForNode()
helper.SuccessWithData(c, data)
}
// @Tags Dashboard
// @Summary Load dashboard current info
// @Description 获取首页实时数据

View file

@ -32,12 +32,6 @@ func ErrorWithDetail(ctx *gin.Context, code int, msgKey string, err error) {
res.Message = i18n.GetMsgWithMap("ErrInvalidParams", nil)
case errors.Is(constant.ErrStructTransform, err):
res.Message = i18n.GetMsgWithMap("ErrStructTransform", map[string]interface{}{"detail": err})
case errors.Is(constant.ErrCaptchaCode, err):
res.Code = constant.CodeAuth
res.Message = "ErrCaptchaCode"
case errors.Is(constant.ErrAuth, err):
res.Code = constant.CodeAuth
res.Message = "ErrAuth"
case errors.Is(constant.ErrInitialPassword, err):
res.Message = i18n.GetMsgWithMap("ErrInitialPassword", map[string]interface{}{"detail": err})
case errors.As(err, &buserr.BusinessError{}):

View file

@ -34,6 +34,27 @@ type OsInfo struct {
DiskSize int64 `json:"diskSize"`
}
type NodeCurrent struct {
Load1 float64 `json:"load1"`
Load5 float64 `json:"load5"`
Load15 float64 `json:"load15"`
LoadUsagePercent float64 `json:"loadUsagePercent"`
CPUUsedPercent float64 `json:"cpuUsedPercent"`
CPUUsed float64 `json:"cpuUsed"`
CPUTotal int `json:"cpuTotal"`
MemoryTotal uint64 `json:"memoryTotal"`
MemoryAvailable uint64 `json:"memoryAvailable"`
MemoryUsed uint64 `json:"memoryUsed"`
MemoryUsedPercent float64 `json:"memoryUsedPercent"`
SwapMemoryTotal uint64 `json:"swapMemoryTotal"`
SwapMemoryAvailable uint64 `json:"swapMemoryAvailable"`
SwapMemoryUsed uint64 `json:"swapMemoryUsed"`
SwapMemoryUsedPercent float64 `json:"swapMemoryUsedPercent"`
}
type DashboardCurrent struct {
Uptime uint64 `json:"uptime"`
TimeSinceUptime string `json:"timeSinceUptime"`

View file

@ -384,6 +384,7 @@ func LoadLocalDirByStr(vars string) (string, error) {
}
return baseDir, nil
}
return baseDir, nil
}
return "", fmt.Errorf("error type dir: %T", varMap["dir"])
}

View file

@ -27,6 +27,7 @@ type DashboardService struct{}
type IDashboardService interface {
LoadOsInfo() (*dto.OsInfo, error)
LoadBaseInfo(ioOption string, netOption string) (*dto.DashboardBase, error)
LoadCurrentInfoForNode() *dto.NodeCurrent
LoadCurrentInfo(ioOption string, netOption string) *dto.DashboardCurrent
Restart(operation string) error
@ -40,7 +41,7 @@ func (u *DashboardService) Restart(operation string) error {
if operation != "1panel" && operation != "system" {
return fmt.Errorf("handle restart operation %s failed, err: nonsupport such operation", operation)
}
itemCmd := fmt.Sprintf("%s 1pctl restart", cmd.SudoHandleCmd())
itemCmd := fmt.Sprintf("%s systemctl restart 1panel.service", cmd.SudoHandleCmd())
if operation == "system" {
itemCmd = fmt.Sprintf("%s reboot", cmd.SudoHandleCmd())
}
@ -79,6 +80,37 @@ func (u *DashboardService) LoadOsInfo() (*dto.OsInfo, error) {
return &baseInfo, nil
}
func (u *DashboardService) LoadCurrentInfoForNode() *dto.NodeCurrent {
var currentInfo dto.NodeCurrent
currentInfo.CPUTotal, _ = cpu.Counts(true)
totalPercent, _ := cpu.Percent(0, false)
if len(totalPercent) == 1 {
currentInfo.CPUUsedPercent = totalPercent[0]
currentInfo.CPUUsed = currentInfo.CPUUsedPercent * 0.01 * float64(currentInfo.CPUTotal)
}
loadInfo, _ := load.Avg()
currentInfo.Load1 = loadInfo.Load1
currentInfo.Load5 = loadInfo.Load5
currentInfo.Load15 = loadInfo.Load15
currentInfo.LoadUsagePercent = loadInfo.Load1 / (float64(currentInfo.CPUTotal*2) * 0.75) * 100
memoryInfo, _ := mem.VirtualMemory()
currentInfo.MemoryTotal = memoryInfo.Total
currentInfo.MemoryAvailable = memoryInfo.Available
currentInfo.MemoryUsed = memoryInfo.Used
currentInfo.MemoryUsedPercent = memoryInfo.UsedPercent
swapInfo, _ := mem.SwapMemory()
currentInfo.SwapMemoryTotal = swapInfo.Total
currentInfo.SwapMemoryAvailable = swapInfo.Free
currentInfo.SwapMemoryUsed = swapInfo.Used
currentInfo.SwapMemoryUsedPercent = swapInfo.UsedPercent
return &currentInfo
}
func (u *DashboardService) LoadBaseInfo(ioOption string, netOption string) (*dto.DashboardBase, error) {
var baseInfo dto.DashboardBase
hostInfo, err := host.Info()

View file

@ -7,46 +7,32 @@ import (
const (
CodeSuccess = 200
CodeErrBadRequest = 400
CodeErrUnauthorized = 401
CodeErrNotFound = 404
CodeAuth = 406
CodeGlobalLoading = 407
CodeErrInternalServer = 500
CodeErrIP = 310
CodeErrDomain = 311
CodeErrEntrance = 312
CodePasswordExpired = 313
CodeErrXpack = 410
)
// internal
var (
ErrCaptchaCode = errors.New("ErrCaptchaCode")
ErrAuth = errors.New("ErrAuth")
ErrRecordExist = errors.New("ErrRecordExist")
ErrRecordNotFound = errors.New("ErrRecordNotFound")
ErrStructTransform = errors.New("ErrStructTransform")
ErrInitialPassword = errors.New("ErrInitialPassword")
ErrNotSupportType = errors.New("ErrNotSupportType")
ErrInvalidParams = errors.New("ErrInvalidParams")
ErrTokenParse = errors.New("ErrTokenParse")
)
// api
var (
ErrTypeInternalServer = "ErrInternalServer"
ErrTypeInvalidParams = "ErrInvalidParams"
ErrTypeNotLogin = "ErrNotLogin"
ErrTypePasswordExpired = "ErrPasswordExpired"
ErrNameIsExist = "ErrNameIsExist"
ErrDemoEnvironment = "ErrDemoEnvironment"
ErrCmdIllegal = "ErrCmdIllegal"
ErrXpackNotFound = "ErrXpackNotFound"
ErrXpackNotActive = "ErrXpackNotActive"
ErrXpackOutOfDate = "ErrXpackOutOfDate"
ErrTypeInternalServer = "ErrInternalServer"
ErrTypeInvalidParams = "ErrInvalidParams"
ErrNameIsExist = "ErrNameIsExist"
ErrDemoEnvironment = "ErrDemoEnvironment"
ErrCmdIllegal = "ErrCmdIllegal"
ErrXpackNotFound = "ErrXpackNotFound"
ErrXpackNotActive = "ErrXpackNotActive"
ErrXpackOutOfDate = "ErrXpackOutOfDate"
)
// app
@ -95,7 +81,7 @@ var (
ErrPathNotFound = "ErrPathNotFound"
ErrMovePathFailed = "ErrMovePathFailed"
ErrLinkPathNotFound = "ErrLinkPathNotFound"
ErrFileIsExist = "ErrFileIsExist"
ErrFileIsExist = "ErrFileIsExist"
ErrFileUpload = "ErrFileUpload"
ErrFileDownloadDir = "ErrFileDownloadDir"
ErrCmdNotFound = "ErrCmdNotFound"

View file

@ -1,13 +1,5 @@
package constant
const (
AuthMethodSession = "session"
SessionName = "psession"
AuthMethodJWT = "jwt"
JWTHeaderName = "PanelAuthorization"
JWTBufferTime = 3600
JWTIssuer = "1Panel"
PasswordExpiredName = "expired"
)

View file

@ -1,5 +1,4 @@
ErrInvalidParams: "Request parameter error: {{ .detail }}"
ErrTokenParse: "Token generation error: {{ .detail }}"
ErrInitialPassword: "Initial password error"
ErrInternalServer: "Service internal error: {{ .detail }}"
ErrRecordExist: "Record already exists"

View file

@ -1,5 +1,4 @@
ErrInvalidParams: "請求參數錯誤: {{ .detail }}"
ErrTokenParse: "Token 產生錯誤: {{ .detail }}"
ErrInitialPassword: "原密碼錯誤"
ErrInternalServer: "伺服器內部錯誤: {{ .detail }}"
ErrRecordExist: "記錄已存在"

View file

@ -1,5 +1,4 @@
ErrInvalidParams: "请求参数错误: {{ .detail }}"
ErrTokenParse: "Token 生成错误: {{ .detail }}"
ErrInitialPassword: "原密码错误"
ErrInternalServer: "服务内部错误: {{ .detail }}"
ErrRecordExist: "记录已存在"

View file

@ -13,6 +13,7 @@ func (s *DashboardRouter) InitRouter(Router *gin.RouterGroup) {
{
cmdRouter.GET("/base/os", baseApi.LoadDashboardOsInfo)
cmdRouter.GET("/base/:ioOption/:netOption", baseApi.LoadDashboardBaseInfo)
cmdRouter.GET("/current/node", baseApi.LoadCurrentInfoForNode)
cmdRouter.GET("/current/:ioOption/:netOption", baseApi.LoadDashboardCurrentInfo)
cmdRouter.POST("/system/restart/:operation", baseApi.SystemRestart)
}

View file

@ -407,6 +407,7 @@ func LoadLocalDirByStr(vars string) (string, error) {
return "", fmt.Errorf("mkdir %s failed, err: %v", baseDir, err)
}
}
return baseDir, nil
}
return "", fmt.Errorf("error type dir: %T", varMap["dir"])
}

View file

@ -27,7 +27,7 @@ class RequestHttp {
...config.headers,
};
config.headers.CurrentNode = globalStore.currentNode;
if (config.url === '/auth/login' || config.url === '/auth/mfalogin') {
if (config.url === '/core/auth/login' || config.url === '/core/auth/mfalogin') {
let entrance = Base64.encode(globalStore.entrance);
config.headers.EntranceCode = entrance;
}

View file

@ -1,8 +1,8 @@
<template>
<div>
<el-popover placement="bottom-start" :width="200" trigger="hover">
<el-popover placement="bottom-start" :width="200" trigger="click">
<template #reference>
<el-button class="timer-button" :icon="Refresh"></el-button>
<el-button class="timer-button" icon="Refresh"></el-button>
</template>
<el-select v-model="refreshRate" @change="changeRefresh">
<template #prefix>{{ $t('commons.table.refreshRate') }}</template>
@ -20,7 +20,6 @@
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue';
import { Refresh } from '@element-plus/icons-vue';
defineOptions({ name: 'TableSetting' });
const refreshRate = ref<number>(0);

View file

@ -39,6 +39,48 @@ export function getBrowserLang() {
}
return defaultBrowserLang;
}
export function loadUpTime(uptime: number) {
if (uptime <= 0) {
return '-';
}
let days = Math.floor(uptime / 86400);
let hours = Math.floor((uptime % 86400) / 3600);
let minutes = Math.floor((uptime % 3600) / 60);
let seconds = uptime % 60;
if (days !== 0) {
return (
days +
i18n.global.t('commons.units.day') +
' ' +
hours +
i18n.global.t('commons.units.hour') +
' ' +
minutes +
i18n.global.t('commons.units.minute') +
' ' +
seconds +
i18n.global.t('commons.units.second')
);
}
if (hours !== 0) {
return (
hours +
i18n.global.t('commons.units.hour') +
' ' +
minutes +
i18n.global.t('commons.units.minute') +
' ' +
seconds +
i18n.global.t('commons.units.second')
);
}
if (minutes !== 0) {
return minutes + i18n.global.t('commons.units.minute') + ' ' + seconds + i18n.global.t('commons.units.second');
}
return seconds + i18n.global.t('commons.units.second');
}
export function dateFormat(row: any, col: any, dataStr: any) {
const date = new Date(dataStr);
const y = date.getFullYear();

View file

@ -251,7 +251,7 @@ import LicenseImport from '@/components/license-import/index.vue';
import CardWithHeader from '@/components/card-with-header/index.vue';
import i18n from '@/lang';
import { Dashboard } from '@/api/interface/dashboard';
import { dateFormatForSecond, computeSize, computeSizeFromKBs } from '@/utils/util';
import { dateFormatForSecond, computeSize, computeSizeFromKBs, loadUpTime } from '@/utils/util';
import { useRouter } from 'vue-router';
import { loadBaseInfo, loadCurrentInfo } from '@/api/modules/dashboard';
import { getIOOptions, getNetworkOptions } from '@/api/modules/host';
@ -465,47 +465,6 @@ const onLoadCurrentInfo = async () => {
statusRef.value.acceptParams(currentInfo.value, baseInfo.value, isStatusInit.value);
};
function loadUpTime(uptime: number) {
if (uptime <= 0) {
return '-';
}
let days = Math.floor(uptime / 86400);
let hours = Math.floor((uptime % 86400) / 3600);
let minutes = Math.floor((uptime % 3600) / 60);
let seconds = uptime % 60;
if (days !== 0) {
return (
days +
i18n.global.t('commons.units.day') +
' ' +
hours +
i18n.global.t('commons.units.hour') +
' ' +
minutes +
i18n.global.t('commons.units.minute') +
' ' +
seconds +
i18n.global.t('commons.units.second')
);
}
if (hours !== 0) {
return (
hours +
i18n.global.t('commons.units.hour') +
' ' +
minutes +
i18n.global.t('commons.units.minute') +
' ' +
seconds +
i18n.global.t('commons.units.second')
);
}
if (minutes !== 0) {
return minutes + i18n.global.t('commons.units.minute') + ' ' + seconds + i18n.global.t('commons.units.second');
}
return seconds + i18n.global.t('commons.units.second');
}
const loadData = async () => {
if (chartOption.value === 'io') {
chartsOption.value['ioChart'] = {