新增前端vue

This commit is contained in:
2026-02-09 16:27:42 +08:00
parent ef40bfcd44
commit 69ac89de6b
3 changed files with 76 additions and 144 deletions

View File

@@ -1,5 +1,6 @@
<template>
<Card title="基础信息">
<!-- 移除Card默认的内边距让内容更贴近边缘 -->
<Card title="基础信息" style="padding: 0;">
<div class="card-grid base-info-content">
<div class="metric-card">
<div class="metric-label">主机名称:</div>
@@ -80,15 +81,14 @@ watch(
</script>
<style scoped>
/* 基础信息卡片容器:核心滚动逻辑 + 紧凑间距 */
/* 基础信息卡片容器:核心滚动逻辑 + 2px边缘间距 */
.card-grid.base-info-content {
width: 100%;
height: 240px;
height: 30vh;
display: grid;
/* 关键:缩小卡片之间的间距从12px改为8px */
/* 关键:卡片间距保持8px容器内边距改为2px */
gap: 8px;
/* 关键缩小容器内边距从8px改为4px */
padding: 4px;
padding: 2px; /* 核心修改贴近Card边缘仅2px */
box-sizing: border-box;
/* 让卡片垂直排列,占满高度 */
grid-template-rows: repeat(auto-fit, minmax(40px, 1fr));
@@ -100,8 +100,8 @@ watch(
.metric-card {
display: flex;
align-items: center;
/* 关键:缩小卡片内部内边距(从12px 16px改为6px 10px */
padding: 6px 10px;
/* 关键:缩小卡片内部内边距(从6px 10px改为4px 8px */
padding: 4px 8px;
background-color: #f8f9fa;
border-radius: 8px;
border: 1px solid #e9ecef;
@@ -155,6 +155,17 @@ watch(
text-overflow: ellipsis;
}
/* 覆盖Ant Design Vue Card组件的默认内边距 */
:deep(.ant-card-body) {
padding: 0 !important; /* 移除Card主体的默认内边距 */
margin: 0;
}
:deep(.ant-card-head) {
padding: 0 12px !important; /* 调整Card标题栏内边距保持标题美观 */
border-bottom: 1px solid #f0f0f0; /* 保留标题栏下划线 */
}
/* 滚动条美化(可选) */
.card-grid.base-info-content::-webkit-scrollbar {
width: 6px; /* 滚动条宽度 */

View File

@@ -1,110 +1,78 @@
<template>
<!-- 1. 优化Card的内边距和间距移除不必要的margin减少整体占用空间 -->
<Card title="监控信息" style="width: 100%; height: 280px; margin: 0; padding: 8px;">
<!-- 2. 调整图表容器高度配合整体紧凑布局 -->
<div ref="chartDom" style="width: 100%; height: 210px;"></div>
<Card title="监控信息" style="width: 100%; height: 30vh; margin: 0; padding: 0;">
<div ref="chartDom" style="width: 100%; height: calc(100% - 32px - 4px); padding: 2px;"></div>
</Card>
</template>
<script lang="ts" setup name="Monitor">
import { ref, onMounted, watch, onUnmounted } from 'vue';
import { Card } from 'ant-design-vue';
import { useRouter } from 'vue-router';
import { BizResourceMonitor, bizResourceMonitorListAll } from '@jeesite/biz/api/biz/resourceMonitor';
import * as echarts from 'echarts';
// 定义接收的参数类型
const props = defineProps<{
formParams: Record<string, any>; // 接收参数
formParams: Record<string, any>;
}>();
// 监控数据列表
const monitorList = ref<BizResourceMonitor[]>([]);
// 改用普通ref管理echarts实例移除shallowRef
const chartInstance = ref<echarts.ECharts | null>(null);
// 图表DOM引用
const chartDom = ref<HTMLDivElement | null>(null);
// 存储resize回调函数方便卸载时移除
const resizeHandler = () => {
chartInstance.value?.resize();
};
// 获取监控数据
const fetchList = async (params: Record<string, any>) => {
try {
const result = await bizResourceMonitorListAll(params);
monitorList.value = result || [];
// 数据更新后重新渲染图表
renderChart();
} catch (error) {
console.error('获取数据列表失败:', error);
monitorList.value = [];
// 数据获取失败也清空图表
renderChart();
}
};
// 初始化ECharts实例
const initChart = () => {
if (!chartDom.value) return;
// 避免重复创建实例
if (chartInstance.value) {
chartInstance.value.dispose();
chartInstance.value = null;
}
// 创建ECharts实例
chartInstance.value = echarts.init(chartDom.value);
// 监听窗口大小变化,自适应调整图表
window.addEventListener('resize', resizeHandler);
};
// 渲染图表
const renderChart = () => {
if (!chartInstance.value) {
return;
}
if (!chartInstance.value) return;
if (monitorList.value.length === 0) {
// 清空图表
// 空数据时不直接隐藏tooltip仅清空数据避免影响tooltip初始化
chartInstance.value.setOption({
tooltip: {
show: false // 空数据时直接隐藏tooltip
},
series: [{ data: [] }, { data: [] }],
xAxis: { data: [] }
});
return;
}
// 处理数据提取X轴和Y轴数据
const xAxisData = monitorList.value.map(item => item.hourTime || '');
const cpuData = monitorList.value.map(item => {
// 处理空值/异常值确保数据合法性0-100
const value = item.cpuUsage ?? 0;
return Math.max(0, Math.min(100, value));
});
const memoryData = monitorList.value.map(item => {
// 处理空值/异常值确保数据合法性0-100
const value = item.memoryUsage ?? 0;
return Math.max(0, Math.min(100, value));
});
// 计算Y轴自适应的最大值和最小值
// 合并所有数据,找到极值
const allData = [...cpuData, ...memoryData];
const minValue = Math.min(...allData);
const maxValue = Math.max(...allData);
// 给Y轴极值增加一点余量让图表显示更美观比如±5%
// 确保最小值不小于0最大值不大于100
const yMin = Math.max(0, minValue - 5);
const yMax = Math.min(100, maxValue + 5);
// 自动计算刻度间隔按5/10/20等整数分割保证刻度美观
const getInterval = (min: number, max: number) => {
const range = max - min;
if (range <= 10) return 2;
@@ -114,137 +82,82 @@ const renderChart = () => {
};
const yInterval = getInterval(yMin, yMax);
// 配置ECharts选项
const option = {
// 图表标题
title: {
left: 'center'
},
// 图例组件 - 优化位置和间距,更紧凑
title: { left: 'center' },
legend: {
data: ['CPU使用率', '内存使用率'],
top: 5, // 减少顶部距离
left: '10px', // 调整左侧位置
itemGap: 15, // 减小图例项之间的间距
textStyle: {
fontSize: 11 // 缩小图例文字
}
top: 5,
left: 'center',
itemGap: 15,
textStyle: { fontSize: 11 }
},
// 网格配置 - 核心优化:大幅减少左右边距,让图表更紧凑
grid: {
left: '1%', // 从2%减到1%,大幅减少左侧空白
right: '1%', // 从2%减到1%,大幅减少右侧空白
bottom: '8%', // 微调底部间距
top: '18%', // 减少顶部间距
containLabel: true // 包含坐标轴标签
left: '2%', // 从1%改为5%,扩大触发区域
right: '2%', // 从1%改为5%,扩大触发区域
bottom: '8%',
top: '18%',
containLabel: true
},
// 提示框优化
tooltip: {
trigger: 'axis',
padding: [8, 12], // 减小tooltip内边距
textStyle: {
fontSize: 11 // 缩小提示框文字
}
},
// X轴配置 - 优化标签显示,更紧凑
xAxis: {
type: 'category',
data: xAxisData,
axisLabel: {
rotate: 20, // 减少旋转角度,节省空间
fontSize: 10, // 缩小字体
margin: 5 // 减小标签与轴线的距离
},
axisTick: {
alignWithLabel: true // 刻度线与标签对齐
}
axisLabel: { rotate: 20, fontSize: 10, margin: 5 },
axisTick: { alignWithLabel: true }
},
// Y轴配置核心修改自适应极值和刻度
yAxis: {
type: 'value',
name: '使用率(%)',
nameTextStyle: {
fontSize: 10 // 缩小Y轴名称字体
},
min: yMin, // 自适应最小值
max: yMax, // 自适应最大值
interval: yInterval, // 自适应刻度间隔
axisLabel: {
formatter: '{value}%',
fontSize: 10, // 缩小Y轴标签字体
margin: 5 // 减小标签与轴线的距离
}
nameTextStyle: { fontSize: 10 },
min: yMin,
max: yMax,
interval: yInterval,
axisLabel: { formatter: '{value}%', fontSize: 10, margin: 5 }
},
// 系列数据(两条曲线)
series: [
{
name: 'CPU使用率',
type: 'line', // 折线图
type: 'line',
data: cpuData,
smooth: true, // 平滑曲线
lineStyle: {
width: 2
},
itemStyle: {
color: '#f56c6c' // CPU曲线颜色
},
smooth: true,
lineStyle: { width: 2 },
itemStyle: { color: '#f56c6c' },
areaStyle: {
// 面积填充,增加视觉效果
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(245, 108, 108, 0.3)' },
{ offset: 1, color: 'rgba(245, 108, 108, 0.05)' }
])
},
// 数值精度
precision: 2,
// 增加tooltip触发的阈值
triggerLine: {
show: true,
length: 5
}
},
{
name: '内存使用率',
type: 'line', // 折线图
type: 'line',
data: memoryData,
smooth: true, // 平滑曲线
lineStyle: {
width: 2
},
itemStyle: {
color: '#409eff' // 内存曲线颜色
},
smooth: true,
lineStyle: { width: 2 },
itemStyle: { color: '#409eff' },
areaStyle: {
// 面积填充
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(64, 158, 255, 0.3)' },
{ offset: 1, color: 'rgba(64, 158, 255, 0.05)' }
])
},
// 数值精度
precision: 2,
// 增加tooltip触发的阈值
triggerLine: {
show: true,
length: 5
}
}
]
};
// 设置图表配置项使用replaceMerge确保配置完全更新
chartInstance.value.setOption(option, {
replaceMerge: ['tooltip', 'series', 'xAxis', 'yAxis'],
lazyUpdate: false
});
};
// 生命周期:挂载时初始化图表并获取数据
onMounted(() => {
initChart();
fetchList(props.formParams);
});
// 监听参数变化,重新获取数据
watch(
() => props.formParams,
async (newParams) => {
@@ -253,11 +166,8 @@ watch(
{ deep: true, immediate: false }
);
// 组件卸载时清理资源(新增/完善onUnmounted
onUnmounted(() => {
// 1. 移除窗口resize事件监听
window.removeEventListener('resize', resizeHandler);
// 2. 销毁ECharts实例释放内存
if (chartInstance.value) {
chartInstance.value.dispose();
chartInstance.value = null;
@@ -266,16 +176,17 @@ onUnmounted(() => {
</script>
<style scoped>
/* 可选进一步优化Card组件的样式 */
:deep(.ant-card) {
border-radius: 4px;
box-shadow: 0 1px 2px rgba(0,0,0,0.05);
box-sizing: border-box;
}
:deep(.ant-card-head) {
padding: 0 12px;
padding: 0 12px !important;
min-height: 32px;
line-height: 32px;
border-bottom: 1px solid #f0f0f0;
}
:deep(.ant-card-head-title) {
@@ -284,6 +195,8 @@ onUnmounted(() => {
}
:deep(.ant-card-body) {
padding: 8px;
padding: 0 !important;
margin: 0;
height: calc(100% - 32px);
}
</style>

View File

@@ -1,5 +1,6 @@
<template>
<Card title="磁盘信息">
<!-- 移除Card默认内边距让内容贴近边缘 -->
<Card title="磁盘信息" style="padding: 0;">
<div class="disk-table-container disk-info-content">
<div class="custom-table-wrapper">
<!-- 固定表头 -->
@@ -124,13 +125,12 @@ watch(
</script>
<style scoped>
/* 核心修复:给外层容器设置明确高度约束 */
/* 核心修复:给外层容器设置明确高度约束 + 2px内边距贴近Card边缘 */
.disk-table-container {
width: 100%;
/* 关键:设置固定高度,也可根据需求改为 max-height */
height: 240px;
/* 或者用百分比height: 80vh;(相对于视口高度) */
height: 30vh;
box-sizing: border-box;
padding: 2px; /* 核心内容与Card边缘仅2px间距 */
}
.custom-table-wrapper {
@@ -140,7 +140,7 @@ watch(
flex-direction: column;
}
/* 固定表头样式 */
/* 固定表头样式 - 调整内边距更紧凑 */
.table-header {
display: flex;
align-items: center;
@@ -148,24 +148,21 @@ watch(
background-color: #f8f9fa;
border-bottom: 1px solid #e9ecef;
font-weight: 600;
padding: 0 16px;
padding: 0 8px; /* 从16px改为8px更紧凑 */
box-sizing: border-box;
/* 固定表头sticky 结合父容器定位 */
position: relative;
z-index: 10;
}
/* 核心修复:内容区域强制高度 + 滚动 */
.table-body-wrapper {
/* 表头高度48px剩余高度全部给内容区 */
height: calc(100% - 48px);
/* 强制显示滚动条也可保留auto仅溢出时显示 */
overflow-y: scroll;
overflow-x: hidden;
box-sizing: border-box;
}
/* 表格行/列基础样式 */
/* 表格行/列基础样式 - 调整内边距更紧凑 */
.table-th, .table-td {
display: flex;
align-items: center;
@@ -178,7 +175,7 @@ watch(
align-items: center;
height: 48px;
border-bottom: 1px solid #e9ecef;
padding: 0 16px;
padding: 0 8px; /* 从16px改为8px更紧凑 */
box-sizing: border-box;
transition: background-color 0.2s;
}
@@ -275,4 +272,15 @@ watch(
.table-body-wrapper::-webkit-scrollbar-thumb:hover {
background: #a8a8a8;
}
/* 覆盖Ant Design Vue Card组件的默认内边距 */
:deep(.ant-card-body) {
padding: 0 !important; /* 移除Card主体的默认内边距 */
margin: 0;
}
:deep(.ant-card-head) {
padding: 0 12px !important; /* 调整Card标题栏内边距保持标题美观 */
border-bottom: 1px solid #f0f0f0; /* 保留标题栏下划线 */
}
</style>