mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-09-22 08:00:53 +00:00
feat: async load data of top CPU and memory processes data (#11081)
* feat: async load data of top CPU and memory processes data * refactor: Update CPU and memory top toggle functionality and state management --------- Co-authored-by: 王贺 <wanghe@fit2cloud.com>
This commit is contained in:
@@ -179,6 +179,28 @@ func (b *BaseApi) LoadDashboardCurrentInfo(c *gin.Context) {
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags Dashboard
|
||||
// @Summary Load top cpu processes
|
||||
// @Success 200 {Array} dto.Process
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /dashboard/current/top/cpu [get]
|
||||
func (b *BaseApi) LoadDashboardTopCPU(c *gin.Context) {
|
||||
data := dashboardService.LoadTopCPU()
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags Dashboard
|
||||
// @Summary Load top memory processes
|
||||
// @Success 200 {Array} dto.Process
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /dashboard/current/top/mem [get]
|
||||
func (b *BaseApi) LoadDashboardTopMem(c *gin.Context) {
|
||||
data := dashboardService.LoadTopMem()
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags Dashboard
|
||||
// @Summary System restart
|
||||
// @Accept json
|
||||
|
||||
@@ -39,6 +39,8 @@ type IDashboardService interface {
|
||||
LoadBaseInfo(ioOption string, netOption string) (*dto.DashboardBase, error)
|
||||
LoadCurrentInfoForNode() *dto.NodeCurrent
|
||||
LoadCurrentInfo(ioOption string, netOption string) *dto.DashboardCurrent
|
||||
LoadTopCPU() []dto.Process
|
||||
LoadTopMem() []dto.Process
|
||||
|
||||
LoadQuickOptions() []dto.QuickJump
|
||||
ChangeQuick(req dto.ChangeQuicks) error
|
||||
@@ -217,9 +219,6 @@ func (u *DashboardService) LoadCurrentInfo(ioOption string, netOption string) *d
|
||||
currentInfo.GPUData = loadGPUInfo()
|
||||
currentInfo.XPUData = loadXpuInfo()
|
||||
|
||||
currentInfo.TopCPUItems = loadTopCPU()
|
||||
currentInfo.TopMemItems = loadTopMem()
|
||||
|
||||
if ioOption == "all" {
|
||||
diskInfo, _ := disk.IOCounters()
|
||||
for _, state := range diskInfo {
|
||||
@@ -261,6 +260,14 @@ func (u *DashboardService) LoadCurrentInfo(ioOption string, netOption string) *d
|
||||
return ¤tInfo
|
||||
}
|
||||
|
||||
func (u *DashboardService) LoadTopCPU() []dto.Process {
|
||||
return loadTopCPU()
|
||||
}
|
||||
|
||||
func (u *DashboardService) LoadTopMem() []dto.Process {
|
||||
return loadTopMem()
|
||||
}
|
||||
|
||||
func (u *DashboardService) LoadAppLauncher(ctx *gin.Context) ([]dto.AppLauncher, error) {
|
||||
var data []dto.AppLauncher
|
||||
appInstalls, err := appInstallRepo.ListBy(context.Background())
|
||||
|
||||
@@ -20,6 +20,8 @@ func (s *DashboardRouter) InitRouter(Router *gin.RouterGroup) {
|
||||
cmdRouter.GET("/base/:ioOption/:netOption", baseApi.LoadDashboardBaseInfo)
|
||||
cmdRouter.GET("/current/node", baseApi.LoadCurrentInfoForNode)
|
||||
cmdRouter.GET("/current/:ioOption/:netOption", baseApi.LoadDashboardCurrentInfo)
|
||||
cmdRouter.GET("/current/top/cpu", baseApi.LoadDashboardTopCPU)
|
||||
cmdRouter.GET("/current/top/mem", baseApi.LoadDashboardTopMem)
|
||||
cmdRouter.POST("/system/restart/:operation", baseApi.SystemRestart)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,8 +103,8 @@ export namespace Dashboard {
|
||||
gpuData: Array<GPUInfo>;
|
||||
xpuData: Array<XPUInfo>;
|
||||
|
||||
topCPUItems: Array<Process>;
|
||||
topMemItems: Array<Process>;
|
||||
topCPUItems?: Array<Process>;
|
||||
topMemItems?: Array<Process>;
|
||||
|
||||
netBytesSent: number;
|
||||
netBytesRecv: number;
|
||||
|
||||
@@ -29,6 +29,14 @@ export const loadCurrentInfo = (ioOption: string, netOption: string) => {
|
||||
return http.get<Dashboard.CurrentInfo>(`/dashboard/current/${ioOption}/${netOption}`);
|
||||
};
|
||||
|
||||
export const loadTopCPU = () => {
|
||||
return http.get<Array<Dashboard.Process>>(`/dashboard/current/top/cpu`);
|
||||
};
|
||||
|
||||
export const loadTopMem = () => {
|
||||
return http.get<Array<Dashboard.Process>>(`/dashboard/current/top/mem`);
|
||||
};
|
||||
|
||||
export const systemRestart = (operation: string) => {
|
||||
return http.post(`/dashboard/system/restart/${operation}`);
|
||||
};
|
||||
|
||||
@@ -450,6 +450,14 @@ const currentChartInfo = reactive({
|
||||
|
||||
const chartsOption = ref({ ioChart1: null, networkChart: null });
|
||||
|
||||
const updateCurrentInfo = (data: Dashboard.CurrentInfo) => {
|
||||
currentInfo.value = {
|
||||
...data,
|
||||
topCPUItems: currentInfo.value.topCPUItems || [],
|
||||
topMemItems: currentInfo.value.topMemItems || [],
|
||||
};
|
||||
};
|
||||
|
||||
const changeOption = async () => {
|
||||
isInit.value = true;
|
||||
loadData();
|
||||
@@ -484,7 +492,7 @@ const onLoadBaseInfo = async (isInit: boolean, range: string) => {
|
||||
}
|
||||
const res = await loadBaseInfo(searchInfo.ioOption, searchInfo.netOption);
|
||||
baseInfo.value = res.data;
|
||||
currentInfo.value = baseInfo.value.currentInfo;
|
||||
updateCurrentInfo(baseInfo.value.currentInfo);
|
||||
onLoadCurrentInfo();
|
||||
isStatusInit.value = false;
|
||||
statusRef.value?.acceptParams(currentInfo.value, baseInfo.value);
|
||||
@@ -584,7 +592,7 @@ const onLoadCurrentInfo = async () => {
|
||||
timeNetDatas.value.splice(0, 1);
|
||||
}
|
||||
loadData();
|
||||
currentInfo.value = res.data;
|
||||
updateCurrentInfo(res.data);
|
||||
statusRef.value?.acceptParams(currentInfo.value, baseInfo.value);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
<template>
|
||||
<div class="custom-row">
|
||||
<el-col :xs="6" :sm="6" :md="3" :lg="3" :xl="3" align="center">
|
||||
<el-popover :hide-after="20" :teleported="false" :width="320" v-if="chartsOption['load']">
|
||||
<el-popover
|
||||
:hide-after="20"
|
||||
:teleported="false"
|
||||
:width="320"
|
||||
v-if="chartsOption['load']"
|
||||
@hide="onCpuPopoverHide"
|
||||
>
|
||||
<el-descriptions :column="1" size="small">
|
||||
<el-descriptions-item :label="$t('home.loadAverage', [1])">
|
||||
{{ formatNumber(currentInfo.load1) }}
|
||||
@@ -14,12 +20,12 @@
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<el-button link size="small" type="primary" class="float-left mb-2" @click="showTop = !showTop">
|
||||
<el-button link size="small" type="primary" class="float-left mb-2" @click="toggleCpuTop">
|
||||
{{ $t('home.cpuTop') }}
|
||||
<el-icon v-if="!showTop"><ArrowRight /></el-icon>
|
||||
<el-icon v-if="showTop"><ArrowDown /></el-icon>
|
||||
<el-icon v-if="!showCpuTop"><ArrowRight /></el-icon>
|
||||
<el-icon v-if="showCpuTop"><ArrowDown /></el-icon>
|
||||
</el-button>
|
||||
<ComplexTable v-if="showTop" :data="currentInfo.topCPUItems">
|
||||
<ComplexTable v-if="showCpuTop" :data="currentInfo.topCPUItems">
|
||||
<el-table-column :min-width="120" show-overflow-tooltip :label="$t('menu.process')" prop="name" />
|
||||
<el-table-column :min-width="60" :label="$t('monitor.percent')" prop="percent">
|
||||
<template #default="{ row }">{{ row.percent.toFixed(2) }}%</template>
|
||||
@@ -45,7 +51,13 @@
|
||||
<span class="input-help">{{ loadStatus(currentInfo.loadUsagePercent) }}</span>
|
||||
</el-col>
|
||||
<el-col :xs="6" :sm="6" :md="3" :lg="3" :xl="3">
|
||||
<el-popover :hide-after="20" :teleported="false" :width="430" v-if="chartsOption['cpu']">
|
||||
<el-popover
|
||||
:hide-after="20"
|
||||
:teleported="false"
|
||||
:width="430"
|
||||
v-if="chartsOption['cpu']"
|
||||
@hide="onCpuPopoverHide"
|
||||
>
|
||||
<el-descriptions :title="baseInfo.cpuModelName" :column="2" size="small">
|
||||
<el-descriptions-item :label="$t('home.core')">
|
||||
{{ baseInfo.cpuCores }}
|
||||
@@ -71,12 +83,12 @@
|
||||
</div>
|
||||
<br />
|
||||
|
||||
<el-button link size="small" type="primary" class="mt-1 mb-2" @click="showTop = !showTop">
|
||||
<el-button link size="small" type="primary" class="mt-2 mb-2" @click="toggleCpuTop">
|
||||
{{ $t('home.cpuTop') }}
|
||||
<el-icon v-if="!showTop"><ArrowRight /></el-icon>
|
||||
<el-icon v-if="showTop"><ArrowDown /></el-icon>
|
||||
<el-icon v-if="!showCpuTop"><ArrowRight /></el-icon>
|
||||
<el-icon v-if="showCpuTop"><ArrowDown /></el-icon>
|
||||
</el-button>
|
||||
<ComplexTable v-if="showTop" :data="currentInfo.topCPUItems">
|
||||
<ComplexTable v-if="showCpuTop" :data="currentInfo.topCPUItems">
|
||||
<el-table-column :min-width="120" show-overflow-tooltip :label="$t('menu.process')" prop="name" />
|
||||
<el-table-column :min-width="60" :label="$t('monitor.percent')" prop="percent">
|
||||
<template #default="{ row }">{{ row.percent.toFixed(2) }}%</template>
|
||||
@@ -107,7 +119,13 @@
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :xs="6" :sm="6" :md="3" :lg="3" :xl="3" align="center">
|
||||
<el-popover :hide-after="20" :teleported="false" :width="480" v-if="chartsOption['memory']">
|
||||
<el-popover
|
||||
:hide-after="20"
|
||||
:teleported="false"
|
||||
:width="480"
|
||||
v-if="chartsOption['memory']"
|
||||
@hide="onMemPopoverHide"
|
||||
>
|
||||
<el-descriptions direction="vertical" :title="$t('home.mem')" class="ml-1" :column="4" size="small">
|
||||
<el-descriptions-item :label-width="60" :label="$t('home.total')">
|
||||
{{ computeSize(currentInfo.memoryTotal) }}
|
||||
@@ -154,12 +172,12 @@
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<el-button link size="small" type="primary" class="float-left mb-2" @click="showTop = !showTop">
|
||||
<el-button link size="small" type="primary" class="float-left mb-2" @click="toggleMemTop">
|
||||
{{ $t('home.memTop') }}
|
||||
<el-icon v-if="!showTop"><ArrowRight /></el-icon>
|
||||
<el-icon v-if="showTop"><ArrowDown /></el-icon>
|
||||
<el-icon v-if="!showMemTop"><ArrowRight /></el-icon>
|
||||
<el-icon v-if="showMemTop"><ArrowDown /></el-icon>
|
||||
</el-button>
|
||||
<ComplexTable v-if="showTop" :data="currentInfo.topMemItems">
|
||||
<ComplexTable v-if="showMemTop" :data="currentInfo.topMemItems">
|
||||
<el-table-column :min-width="120" show-overflow-tooltip :label="$t('menu.process')" prop="name" />
|
||||
<el-table-column :min-width="100" :label="$t('monitor.memory')" prop="memory">
|
||||
<template #default="{ row }">
|
||||
@@ -334,13 +352,19 @@
|
||||
import { Dashboard } from '@/api/interface/dashboard';
|
||||
import { computeSize } from '@/utils/util';
|
||||
import i18n from '@/lang';
|
||||
import { nextTick, ref } from 'vue';
|
||||
import { nextTick, onBeforeUnmount, ref } from 'vue';
|
||||
import { routerToFileWithPath, routerToName } from '@/utils/router';
|
||||
import { stopProcess } from '@/api/modules/process';
|
||||
import { loadTopCPU, loadTopMem } from '@/api/modules/dashboard';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
const showMore = ref(false);
|
||||
const totalCount = ref();
|
||||
|
||||
let cpuPopoverTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
let memPopoverTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
let cpuLoading = false;
|
||||
let memLoading = false;
|
||||
|
||||
const baseInfo = ref<Dashboard.BaseInfo>({
|
||||
hostname: '',
|
||||
os: '',
|
||||
@@ -405,7 +429,8 @@ const currentInfo = ref<Dashboard.CurrentInfo>({
|
||||
});
|
||||
|
||||
const cpuShowAll = ref();
|
||||
const showTop = ref();
|
||||
const showCpuTop = ref(false);
|
||||
const showMemTop = ref(false);
|
||||
const killProcessID = ref();
|
||||
const confirmConfRef = ref();
|
||||
|
||||
@@ -515,6 +540,91 @@ function formatNumber(val: number) {
|
||||
return Number(val.toFixed(2));
|
||||
}
|
||||
|
||||
const toggleCpuTop = async () => {
|
||||
showCpuTop.value = !showCpuTop.value;
|
||||
if (showCpuTop.value) {
|
||||
await loadTopCPUData();
|
||||
if (cpuPopoverTimer) {
|
||||
clearInterval(Number(cpuPopoverTimer));
|
||||
}
|
||||
cpuPopoverTimer = setInterval(loadTopCPUData, 5000);
|
||||
} else {
|
||||
if (cpuPopoverTimer) {
|
||||
clearInterval(Number(cpuPopoverTimer));
|
||||
cpuPopoverTimer = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onCpuPopoverHide = () => {
|
||||
showCpuTop.value = false;
|
||||
if (cpuPopoverTimer) {
|
||||
clearInterval(Number(cpuPopoverTimer));
|
||||
cpuPopoverTimer = null;
|
||||
}
|
||||
};
|
||||
|
||||
const toggleMemTop = async () => {
|
||||
showMemTop.value = !showMemTop.value;
|
||||
if (showMemTop.value) {
|
||||
await loadTopMemData();
|
||||
if (memPopoverTimer) {
|
||||
clearInterval(Number(memPopoverTimer));
|
||||
}
|
||||
memPopoverTimer = setInterval(loadTopMemData, 5000);
|
||||
} else {
|
||||
if (memPopoverTimer) {
|
||||
clearInterval(Number(memPopoverTimer));
|
||||
memPopoverTimer = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onMemPopoverHide = () => {
|
||||
showMemTop.value = false;
|
||||
if (memPopoverTimer) {
|
||||
clearInterval(Number(memPopoverTimer));
|
||||
memPopoverTimer = null;
|
||||
}
|
||||
};
|
||||
|
||||
const loadTopCPUData = async () => {
|
||||
if (cpuLoading) return;
|
||||
cpuLoading = true;
|
||||
try {
|
||||
const res = await loadTopCPU();
|
||||
currentInfo.value.topCPUItems = res.data || [];
|
||||
} catch (_error) {
|
||||
// ignore load errors
|
||||
} finally {
|
||||
cpuLoading = false;
|
||||
}
|
||||
};
|
||||
|
||||
const loadTopMemData = async () => {
|
||||
if (memLoading) return;
|
||||
memLoading = true;
|
||||
try {
|
||||
const res = await loadTopMem();
|
||||
currentInfo.value.topMemItems = res.data || [];
|
||||
} catch (_error) {
|
||||
// ignore load errors
|
||||
} finally {
|
||||
memLoading = false;
|
||||
}
|
||||
};
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (cpuPopoverTimer) {
|
||||
clearInterval(Number(cpuPopoverTimer));
|
||||
cpuPopoverTimer = null;
|
||||
}
|
||||
if (memPopoverTimer) {
|
||||
clearInterval(Number(memPopoverTimer));
|
||||
memPopoverTimer = null;
|
||||
}
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user