feat: 🚀 服务监控CPU占用和磁盘占用
This commit is contained in:
parent
d92f7ae073
commit
e873d138dd
|
@ -70,6 +70,7 @@
|
||||||
"cropperjs": "^1.6.2",
|
"cropperjs": "^1.6.2",
|
||||||
"dayjs": "^1.11.11",
|
"dayjs": "^1.11.11",
|
||||||
"echarts": "^5.5.0",
|
"echarts": "^5.5.0",
|
||||||
|
"echarts-gl": "^2.0.9",
|
||||||
"el-table-infinite-scroll": "^3.0.3",
|
"el-table-infinite-scroll": "^3.0.3",
|
||||||
"element-plus": "2.7.1",
|
"element-plus": "2.7.1",
|
||||||
"intro.js": "^7.2.0",
|
"intro.js": "^7.2.0",
|
||||||
|
|
|
@ -71,6 +71,9 @@ importers:
|
||||||
echarts:
|
echarts:
|
||||||
specifier: ^5.5.0
|
specifier: ^5.5.0
|
||||||
version: 5.5.1
|
version: 5.5.1
|
||||||
|
echarts-gl:
|
||||||
|
specifier: ^2.0.9
|
||||||
|
version: 2.0.9(echarts@5.5.1)
|
||||||
el-table-infinite-scroll:
|
el-table-infinite-scroll:
|
||||||
specifier: ^3.0.3
|
specifier: ^3.0.3
|
||||||
version: 3.0.6(typescript@5.5.4)
|
version: 3.0.6(typescript@5.5.4)
|
||||||
|
@ -2049,6 +2052,9 @@ packages:
|
||||||
cjs-module-lexer@1.4.0:
|
cjs-module-lexer@1.4.0:
|
||||||
resolution: {integrity: sha512-N1NGmowPlGBLsOZLPvm48StN04V4YvQRL0i6b7ctrVY3epjP/ct7hFLOItz6pDIvRjwpfPxi52a2UWV2ziir8g==}
|
resolution: {integrity: sha512-N1NGmowPlGBLsOZLPvm48StN04V4YvQRL0i6b7ctrVY3epjP/ct7hFLOItz6pDIvRjwpfPxi52a2UWV2ziir8g==}
|
||||||
|
|
||||||
|
claygl@1.3.0:
|
||||||
|
resolution: {integrity: sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ==}
|
||||||
|
|
||||||
cli-boxes@3.0.0:
|
cli-boxes@3.0.0:
|
||||||
resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==}
|
resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
@ -2602,6 +2608,11 @@ packages:
|
||||||
eastasianwidth@0.2.0:
|
eastasianwidth@0.2.0:
|
||||||
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
||||||
|
|
||||||
|
echarts-gl@2.0.9:
|
||||||
|
resolution: {integrity: sha512-oKeMdkkkpJGWOzjgZUsF41DOh6cMsyrGGXimbjK2l6Xeq/dBQu4ShG2w2Dzrs/1bD27b2pLTGSaUzouY191gzA==}
|
||||||
|
peerDependencies:
|
||||||
|
echarts: ^5.1.2
|
||||||
|
|
||||||
echarts@5.5.1:
|
echarts@5.5.1:
|
||||||
resolution: {integrity: sha512-Fce8upazaAXUVUVsjgV6mBnGuqgO+JNDlcgF79Dksy4+wgGpQB2lmYoO4TSweFg/mZITdpGHomw/cNBJZj1icA==}
|
resolution: {integrity: sha512-Fce8upazaAXUVUVsjgV6mBnGuqgO+JNDlcgF79Dksy4+wgGpQB2lmYoO4TSweFg/mZITdpGHomw/cNBJZj1icA==}
|
||||||
|
|
||||||
|
@ -7912,6 +7923,8 @@ snapshots:
|
||||||
|
|
||||||
cjs-module-lexer@1.4.0: {}
|
cjs-module-lexer@1.4.0: {}
|
||||||
|
|
||||||
|
claygl@1.3.0: {}
|
||||||
|
|
||||||
cli-boxes@3.0.0: {}
|
cli-boxes@3.0.0: {}
|
||||||
|
|
||||||
cli-cursor@3.1.0:
|
cli-cursor@3.1.0:
|
||||||
|
@ -8511,6 +8524,12 @@ snapshots:
|
||||||
|
|
||||||
eastasianwidth@0.2.0: {}
|
eastasianwidth@0.2.0: {}
|
||||||
|
|
||||||
|
echarts-gl@2.0.9(echarts@5.5.1):
|
||||||
|
dependencies:
|
||||||
|
claygl: 1.3.0
|
||||||
|
echarts: 5.5.1
|
||||||
|
zrender: 5.6.0
|
||||||
|
|
||||||
echarts@5.5.1:
|
echarts@5.5.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.3.0
|
tslib: 2.3.0
|
||||||
|
|
|
@ -14,3 +14,23 @@ export const fetchSystemInfo = () => {
|
||||||
export const fetchSystemCaches = () => {
|
export const fetchSystemCaches = () => {
|
||||||
return http.request<any>('get', 'actuator/caches');
|
return http.request<any>('get', 'actuator/caches');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** actuator断端点-CPU占用 */
|
||||||
|
export const fetchSystemCPU = () => {
|
||||||
|
return http.request<any>('get', 'actuator/metrics/system.cpu.usage');
|
||||||
|
};
|
||||||
|
|
||||||
|
/** actuator断端点-CPU占用 */
|
||||||
|
export const fetchSystemProcessCPU = () => {
|
||||||
|
return http.request<any>('get', 'actuator/metrics/process.cpu.usage');
|
||||||
|
};
|
||||||
|
|
||||||
|
/** actuator断端点-磁盘可用 */
|
||||||
|
export const fetchSystemDiskFree = () => {
|
||||||
|
return http.request<any>('get', 'actuator/metrics/disk.free');
|
||||||
|
};
|
||||||
|
|
||||||
|
/** actuator断端点-磁盘总量 */
|
||||||
|
export const fetchSystemDiskTotal = () => {
|
||||||
|
return http.request<any>('get', 'actuator/metrics/disk.total');
|
||||||
|
};
|
||||||
|
|
|
@ -8,6 +8,7 @@ import router from './router';
|
||||||
import { useElementPlus } from '@/plugins/elementPlus';
|
import { useElementPlus } from '@/plugins/elementPlus';
|
||||||
import { injectResponsiveStorage } from '@/utils/responsive';
|
import { injectResponsiveStorage } from '@/utils/responsive';
|
||||||
import { createApp, type Directive } from 'vue';
|
import { createApp, type Directive } from 'vue';
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
|
||||||
import Table from '@pureadmin/table';
|
import Table from '@pureadmin/table';
|
||||||
// import PureDescriptions from "@pureadmin/descriptions";
|
// import PureDescriptions from "@pureadmin/descriptions";
|
||||||
|
@ -45,7 +46,7 @@ app.component('IconifyIconOnline', IconifyIconOnline);
|
||||||
app.component('FontIcon', FontIcon);
|
app.component('FontIcon', FontIcon);
|
||||||
app.component('Auth', Auth);
|
app.component('Auth', Auth);
|
||||||
app.component('Perms', Perms);
|
app.component('Perms', Perms);
|
||||||
|
app.config.globalProperties.$echarts = echarts;
|
||||||
app.use(VueTippy);
|
app.use(VueTippy);
|
||||||
|
|
||||||
getPlatformConfig(app).then(async config => {
|
getPlatformConfig(app).then(async config => {
|
||||||
|
|
|
@ -1,36 +1,26 @@
|
||||||
import type { App } from "vue";
|
import type { App } from 'vue';
|
||||||
import * as echarts from "echarts/core";
|
import * as echarts from 'echarts/core';
|
||||||
import { PieChart, BarChart, LineChart } from "echarts/charts";
|
import { BarChart, LineChart, PieChart } from 'echarts/charts';
|
||||||
import { CanvasRenderer, SVGRenderer } from "echarts/renderers";
|
import { CanvasRenderer, SVGRenderer } from 'echarts/renderers';
|
||||||
import {
|
import { DataZoomComponent, GraphicComponent, GridComponent, LegendComponent, PolarComponent, TitleComponent, ToolboxComponent, TooltipComponent, VisualMapComponent } from 'echarts/components';
|
||||||
GridComponent,
|
|
||||||
TitleComponent,
|
|
||||||
PolarComponent,
|
|
||||||
LegendComponent,
|
|
||||||
GraphicComponent,
|
|
||||||
ToolboxComponent,
|
|
||||||
TooltipComponent,
|
|
||||||
DataZoomComponent,
|
|
||||||
VisualMapComponent
|
|
||||||
} from "echarts/components";
|
|
||||||
|
|
||||||
const { use } = echarts;
|
const { use } = echarts;
|
||||||
|
|
||||||
use([
|
use([
|
||||||
PieChart,
|
PieChart,
|
||||||
BarChart,
|
BarChart,
|
||||||
LineChart,
|
LineChart,
|
||||||
CanvasRenderer,
|
CanvasRenderer,
|
||||||
SVGRenderer,
|
SVGRenderer,
|
||||||
GridComponent,
|
GridComponent,
|
||||||
TitleComponent,
|
TitleComponent,
|
||||||
PolarComponent,
|
PolarComponent,
|
||||||
LegendComponent,
|
LegendComponent,
|
||||||
GraphicComponent,
|
GraphicComponent,
|
||||||
ToolboxComponent,
|
ToolboxComponent,
|
||||||
TooltipComponent,
|
TooltipComponent,
|
||||||
DataZoomComponent,
|
DataZoomComponent,
|
||||||
VisualMapComponent
|
VisualMapComponent,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,7 +28,7 @@ use([
|
||||||
* @see 温馨提示:必须将 `$echarts` 添加到全局 `globalProperties` ,具体看 https://pure-admin-utils.netlify.app/hooks/useECharts/useECharts#%E4%BD%BF%E7%94%A8%E5%89%8D%E6%8F%90
|
* @see 温馨提示:必须将 `$echarts` 添加到全局 `globalProperties` ,具体看 https://pure-admin-utils.netlify.app/hooks/useECharts/useECharts#%E4%BD%BF%E7%94%A8%E5%89%8D%E6%8F%90
|
||||||
*/
|
*/
|
||||||
export function useEcharts(app: App) {
|
export function useEcharts(app: App) {
|
||||||
app.config.globalProperties.$echarts = echarts;
|
app.config.globalProperties.$echarts = echarts;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default echarts;
|
export default echarts;
|
||||||
|
|
|
@ -35,7 +35,6 @@ const onChange = (uploadFile: any) => {
|
||||||
reader.onload = e => {
|
reader.onload = e => {
|
||||||
imgBase64Src.value = e.target.result as string;
|
imgBase64Src.value = e.target.result as string;
|
||||||
isShow.value = true;
|
isShow.value = true;
|
||||||
console.log(imgBase64Src.value);
|
|
||||||
};
|
};
|
||||||
reader.readAsDataURL(uploadFile.raw);
|
reader.readAsDataURL(uploadFile.raw);
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,6 +4,9 @@ import SystemInfo from '@/views/monitor/server/system-info.vue';
|
||||||
import { svg } from '@/views/monitor/server/utils/columns';
|
import { svg } from '@/views/monitor/server/utils/columns';
|
||||||
import { info, loading, onSearch } from '@/views/monitor/server/utils/hooks';
|
import { info, loading, onSearch } from '@/views/monitor/server/utils/hooks';
|
||||||
import SystemServer from '@/views/monitor/server/system-server.vue';
|
import SystemServer from '@/views/monitor/server/system-server.vue';
|
||||||
|
import SystemCpu from '@/views/monitor/server/system-cpu.vue';
|
||||||
|
import SystemJvmCpu from '@/views/monitor/server/system-jvm-cpu.vue';
|
||||||
|
import SystemDisk from '@/views/monitor/server/system-disk.vue';
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
onSearch();
|
onSearch();
|
||||||
|
@ -15,6 +18,9 @@ onMounted(() => {
|
||||||
<el-row :gutter="16">
|
<el-row :gutter="16">
|
||||||
<system-info v-if="info" :info="info" />
|
<system-info v-if="info" :info="info" />
|
||||||
<system-server />
|
<system-server />
|
||||||
|
<system-cpu />
|
||||||
|
<system-jvm-cpu />
|
||||||
|
<system-disk />
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -0,0 +1,177 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, reactive, ref } from 'vue';
|
||||||
|
import { UtilsEChartsOption } from '@pureadmin/utils';
|
||||||
|
// import 'echarts-gl';
|
||||||
|
import { cardClass, cardLogoClass } from '@/views/monitor/server/utils/columns';
|
||||||
|
import { useRenderIcon } from '@/components/CommonIcon/src/hooks';
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
import { useIntervalFn } from '@vueuse/core';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import { fetchSystemCPU } from '@/api/v1/actuator';
|
||||||
|
|
||||||
|
const cupECharts = ref();
|
||||||
|
const myChart = ref<any>();
|
||||||
|
|
||||||
|
// 初始化ECharts
|
||||||
|
const seriesData = ref([]);
|
||||||
|
const xSeriesData = ref([]);
|
||||||
|
|
||||||
|
const option = reactive<UtilsEChartsOption>({
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: { type: 'cross' },
|
||||||
|
extraCssText: 'width: 170px',
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
top: '0%',
|
||||||
|
left: 'center',
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
// 让图表占满容器
|
||||||
|
top: '20px',
|
||||||
|
right: '20px',
|
||||||
|
bottom: '20px',
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
inverse: true,
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
data: seriesData.value,
|
||||||
|
type: 'line',
|
||||||
|
areaStyle: {},
|
||||||
|
animationDelay: function (idx) {
|
||||||
|
return idx * 10; // 设置动画延迟时间
|
||||||
|
},
|
||||||
|
animationDuration: 1000, // 设置动画持续时间
|
||||||
|
},
|
||||||
|
],
|
||||||
|
animationDuration: 666,
|
||||||
|
animationDurationUpdate: 200,
|
||||||
|
animationEasing: 'linear',
|
||||||
|
animationEasingUpdate: 'linear',
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 初始化数据 */
|
||||||
|
const onSearch = async () => {
|
||||||
|
// 获取数据
|
||||||
|
const result = await fetchSystemCPU();
|
||||||
|
const value = result.measurements[0].value ?? 0;
|
||||||
|
|
||||||
|
// 保留数组中的最新10条数据
|
||||||
|
if (seriesData.value.length > 5) {
|
||||||
|
seriesData.value = seriesData.value.slice(-5);
|
||||||
|
xSeriesData.value = xSeriesData.value.slice(-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
seriesData.value.push(value * 100);
|
||||||
|
xSeriesData.value.push(dayjs().format('mm:ss'));
|
||||||
|
|
||||||
|
myChart.value.setOption({
|
||||||
|
xAxis: { data: xSeriesData.value },
|
||||||
|
series: [{ type: 'line', data: seriesData.value }],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 初始化eacharts
|
||||||
|
myChart.value = echarts.init(cupECharts.value);
|
||||||
|
option && myChart.value.setOption(option);
|
||||||
|
|
||||||
|
onSearch();
|
||||||
|
|
||||||
|
// 定时刷新
|
||||||
|
useIntervalFn(() => onSearch(), 1000);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<el-col :lg="6" :md="8" :sm="12" :xl="4" :xs="24">
|
||||||
|
<div :class="cardClass">
|
||||||
|
<div class="list-card-item_detail bg-bg_color">
|
||||||
|
<el-row justify="space-between">
|
||||||
|
<div :class="cardLogoClass">
|
||||||
|
<component :is="useRenderIcon('solar:cpu-bold-duotone')" />
|
||||||
|
</div>
|
||||||
|
</el-row>
|
||||||
|
<p class="list-card-item_detail--name text-text_color_primary">服务CPU使用率</p>
|
||||||
|
<div ref="cupECharts" style="width: 100%; height: 230px" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.list-card-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 3px;
|
||||||
|
|
||||||
|
&_detail {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 140px;
|
||||||
|
padding: 24px 32px;
|
||||||
|
|
||||||
|
&--logo {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 46px;
|
||||||
|
height: 46px;
|
||||||
|
font-size: 26px;
|
||||||
|
color: #0052d9;
|
||||||
|
background: #e0ebff;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
&__disabled {
|
||||||
|
color: #a1c4ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--operation {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
&--tag {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--name {
|
||||||
|
margin: 24px 0 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--desc {
|
||||||
|
display: -webkit-box;
|
||||||
|
height: 40px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
overflow: hidden;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 20px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__disabled {
|
||||||
|
.list-card-item_detail--name {
|
||||||
|
color: var(--el-text-color-disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-card-item_detail--operation--tag {
|
||||||
|
color: #bababa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,118 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
// import 'echarts-gl';
|
||||||
|
import { cardClass, cardLogoClass } from '@/views/monitor/server/utils/columns';
|
||||||
|
import { useRenderIcon } from '@/components/CommonIcon/src/hooks';
|
||||||
|
import { fetchSystemDiskFree, fetchSystemDiskTotal } from '@/api/v1/actuator';
|
||||||
|
|
||||||
|
const free = ref();
|
||||||
|
const total = ref();
|
||||||
|
const percentage = ref<number>(0);
|
||||||
|
|
||||||
|
/** 初始化数据 */
|
||||||
|
const onSearch = async () => {
|
||||||
|
// 获取数据
|
||||||
|
const diskFree = await fetchSystemDiskFree();
|
||||||
|
const diskTotal = await fetchSystemDiskTotal();
|
||||||
|
free.value = diskFree.measurements[0].value / 1024 / 1024 / 1024;
|
||||||
|
total.value = diskTotal.measurements[0].value / 1024 / 1024 / 1024;
|
||||||
|
|
||||||
|
free.value = free.value.toFixed(2);
|
||||||
|
total.value = total.value.toFixed(2);
|
||||||
|
|
||||||
|
percentage.value = ((total.value - free.value) / total.value) * 100;
|
||||||
|
percentage.value = Number(percentage.value.toFixed(2));
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
onSearch();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<el-col :lg="6" :md="8" :sm="12" :xl="4" :xs="24">
|
||||||
|
<div :class="cardClass">
|
||||||
|
<div class="list-card-item_detail bg-bg_color">
|
||||||
|
<el-row justify="space-between">
|
||||||
|
<div :class="cardLogoClass">
|
||||||
|
<component :is="useRenderIcon('carbon:logo-vmware')" />
|
||||||
|
</div>
|
||||||
|
</el-row>
|
||||||
|
<p class="list-card-item_detail--name text-text_color_primary">磁盘使用</p>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<el-progress :percentage="percentage" type="dashboard" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.list-card-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 3px;
|
||||||
|
|
||||||
|
&_detail {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 140px;
|
||||||
|
padding: 24px 32px;
|
||||||
|
|
||||||
|
&--logo {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 46px;
|
||||||
|
height: 46px;
|
||||||
|
font-size: 26px;
|
||||||
|
color: #0052d9;
|
||||||
|
background: #e0ebff;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
&__disabled {
|
||||||
|
color: #a1c4ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--operation {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
&--tag {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--name {
|
||||||
|
margin: 24px 0 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--desc {
|
||||||
|
display: -webkit-box;
|
||||||
|
height: 40px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
overflow: hidden;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 20px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__disabled {
|
||||||
|
.list-card-item_detail--name {
|
||||||
|
color: var(--el-text-color-disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-card-item_detail--operation--tag {
|
||||||
|
color: #bababa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,176 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, reactive, ref } from 'vue';
|
||||||
|
import { UtilsEChartsOption } from '@pureadmin/utils';
|
||||||
|
// import 'echarts-gl';
|
||||||
|
import { cardClass, cardLogoClass } from '@/views/monitor/server/utils/columns';
|
||||||
|
import { useRenderIcon } from '@/components/CommonIcon/src/hooks';
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
import { useIntervalFn } from '@vueuse/core';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import { fetchSystemProcessCPU } from '@/api/v1/actuator';
|
||||||
|
|
||||||
|
const jvmCPUECharts = ref();
|
||||||
|
const myChart = ref<any>();
|
||||||
|
|
||||||
|
// 初始化ECharts
|
||||||
|
const seriesData = ref([]);
|
||||||
|
const xSeriesData = ref([]);
|
||||||
|
|
||||||
|
const option = reactive<UtilsEChartsOption>({
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: { type: 'cross' },
|
||||||
|
extraCssText: 'width: 170px',
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
top: '0%',
|
||||||
|
left: 'center',
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
top: '20px',
|
||||||
|
right: '20px',
|
||||||
|
bottom: '20px',
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
inverse: true,
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
data: seriesData.value,
|
||||||
|
type: 'line',
|
||||||
|
areaStyle: {},
|
||||||
|
animationDelay: function (idx) {
|
||||||
|
return idx * 10; // 设置动画延迟时间
|
||||||
|
},
|
||||||
|
animationDuration: 1000, // 设置动画持续时间
|
||||||
|
},
|
||||||
|
],
|
||||||
|
animationDuration: 666,
|
||||||
|
animationDurationUpdate: 200,
|
||||||
|
animationEasing: 'linear',
|
||||||
|
animationEasingUpdate: 'linear',
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 初始化数据 */
|
||||||
|
const onSearch = async () => {
|
||||||
|
// 获取数据
|
||||||
|
const result = await fetchSystemProcessCPU();
|
||||||
|
const value = result.measurements[0].value;
|
||||||
|
|
||||||
|
// 保留数组中的最新10条数据
|
||||||
|
if (seriesData.value.length > 5) {
|
||||||
|
seriesData.value = seriesData.value.slice(-5);
|
||||||
|
xSeriesData.value = xSeriesData.value.slice(-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
seriesData.value.push(value * 100);
|
||||||
|
xSeriesData.value.push(dayjs().format('mm:ss'));
|
||||||
|
|
||||||
|
myChart.value.setOption({
|
||||||
|
xAxis: { data: xSeriesData.value },
|
||||||
|
series: [{ type: 'line', data: seriesData.value }],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 初始化eacharts
|
||||||
|
myChart.value = echarts.init(jvmCPUECharts.value);
|
||||||
|
option && myChart.value.setOption(option);
|
||||||
|
|
||||||
|
onSearch();
|
||||||
|
|
||||||
|
// 定时刷新
|
||||||
|
useIntervalFn(() => onSearch(), 1000);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<el-col :lg="6" :md="8" :sm="12" :xl="4" :xs="24">
|
||||||
|
<div :class="cardClass">
|
||||||
|
<div class="list-card-item_detail bg-bg_color">
|
||||||
|
<el-row justify="space-between">
|
||||||
|
<div :class="cardLogoClass">
|
||||||
|
<component :is="useRenderIcon('carbon:logo-vmware')" />
|
||||||
|
</div>
|
||||||
|
</el-row>
|
||||||
|
<p class="list-card-item_detail--name text-text_color_primary">JVM最近cpu使用率</p>
|
||||||
|
<div ref="jvmCPUECharts" style="width: 100%; height: 230px" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.list-card-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 3px;
|
||||||
|
|
||||||
|
&_detail {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 140px;
|
||||||
|
padding: 24px 32px;
|
||||||
|
|
||||||
|
&--logo {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 46px;
|
||||||
|
height: 46px;
|
||||||
|
font-size: 26px;
|
||||||
|
color: #0052d9;
|
||||||
|
background: #e0ebff;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
&__disabled {
|
||||||
|
color: #a1c4ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--operation {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
&--tag {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--name {
|
||||||
|
margin: 24px 0 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--desc {
|
||||||
|
display: -webkit-box;
|
||||||
|
height: 40px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
overflow: hidden;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 20px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__disabled {
|
||||||
|
.list-card-item_detail--name {
|
||||||
|
color: var(--el-text-color-disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-card-item_detail--operation--tag {
|
||||||
|
color: #bababa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -272,6 +272,8 @@ export const onResetPassword = (row: any) => {
|
||||||
|
|
||||||
// 更新成功关闭弹窗
|
// 更新成功关闭弹窗
|
||||||
if (!result) return;
|
if (!result) return;
|
||||||
|
restPasswordForm.password = '';
|
||||||
|
restPasswordForm.userId = undefined;
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue