mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-10-06 05:24:33 +08:00
feat: 完善节点管理功能 (#6139)
Some checks failed
sync2gitee / repo-sync (push) Failing after -7m53s
Some checks failed
sync2gitee / repo-sync (push) Failing after -7m53s
This commit is contained in:
parent
226bf9d8d2
commit
2c2228192f
16 changed files with 123 additions and 87 deletions
|
@ -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 获取首页实时数据
|
||||
|
|
|
@ -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{}):
|
||||
|
|
|
@ -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"`
|
||||
|
|
|
@ -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"])
|
||||
}
|
||||
|
|
|
@ -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 ¤tInfo
|
||||
}
|
||||
|
||||
func (u *DashboardService) LoadBaseInfo(ioOption string, netOption string) (*dto.DashboardBase, error) {
|
||||
var baseInfo dto.DashboardBase
|
||||
hostInfo, err := host.Info()
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -1,13 +1,5 @@
|
|||
package constant
|
||||
|
||||
const (
|
||||
AuthMethodSession = "session"
|
||||
SessionName = "psession"
|
||||
|
||||
AuthMethodJWT = "jwt"
|
||||
JWTHeaderName = "PanelAuthorization"
|
||||
JWTBufferTime = 3600
|
||||
JWTIssuer = "1Panel"
|
||||
|
||||
PasswordExpiredName = "expired"
|
||||
)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
ErrInvalidParams: "請求參數錯誤: {{ .detail }}"
|
||||
ErrTokenParse: "Token 產生錯誤: {{ .detail }}"
|
||||
ErrInitialPassword: "原密碼錯誤"
|
||||
ErrInternalServer: "伺服器內部錯誤: {{ .detail }}"
|
||||
ErrRecordExist: "記錄已存在"
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
ErrInvalidParams: "请求参数错误: {{ .detail }}"
|
||||
ErrTokenParse: "Token 生成错误: {{ .detail }}"
|
||||
ErrInitialPassword: "原密码错误"
|
||||
ErrInternalServer: "服务内部错误: {{ .detail }}"
|
||||
ErrRecordExist: "记录已存在"
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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"])
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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'] = {
|
||||
|
|
Loading…
Add table
Reference in a new issue