Files
profitManage1.2/src/views/resource/serverRegister/tabsChart.vue
T
康冉冉 8b53b3620e 图形监控上方去掉选择时间复选框、探测策略表单的频率字段改为下拉
1、tcpdump探测策略表单的频率字段改为下拉
2、虚拟网卡信息列表添加ping丢包率字段
3、服务器管理详情图形监控上方去掉选择时间复选框
4、HDD磁盘空间去掉HDD、图表单位改为大写
5、硬盘设备监控列表的读/写速率单位KB改为MB
2026-01-30 18:10:03 +08:00

384 lines
17 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="w100 h100">
<div class="w100" style="height: 40px;">
<!-- :disabled="!timeShow" -->
<el-date-picker
v-model="timeList"
:style="{width: '360px!important', marginRight: '10px'}"
type="datetimerange"
start-placeholder="开始时间"
end-placeholder="结束时间"
range-separator=""
format="yyyy-MM-dd HH:mm:ss"
value-format="yyyy-MM-dd HH:mm:ss"
:default-time="['00:00:00', '23:59:59']"
@change="(val) => dateChange(val)"/>
<!-- <el-checkbox v-model="timeShow" @change="checkChange">选择时间</el-checkbox>-->
<!-- 不同条时间件切换 :disabled="timeShow" -->
<el-radio-group v-model="timeModel" size="medium" class="ml20" @input="radioTimeChange">
<el-radio-button v-for="item of radioTimeList" :label="item.value">{{item.name}}</el-radio-button>
</el-radio-group>
<!-- 定时刷新 -->
<div class="disInlineBlock ml10">
<el-select v-model="timeRefresh" placeholder="请选择" style="width: 110px;" @change="fnTimeInter">
<el-option
v-for="item in timeModelOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
<!-- 单双列切换 -->
<el-radio-group v-model="layoutModel" size="medium" class="ml20" style="float: right;" @input="radioLayouteChange">
<el-radio-button v-for="item of radioLayoutList" :label="item.value">{{item.name}}</el-radio-button>
</el-radio-group>
</div>
<div class="mt10" v-if="activeName === '网卡流量监控'">
<span style="display: inline-block;font-size: 14px;font-weight: 600;">网卡名称</span>
<el-select v-model="interCardName" @change="handleSelect">
<el-option v-for="(item,key) of this.interCartList" :key="key" :value="key" :label="key">
{{key}}
</el-option>
</el-select>
</div>
<template v-if="echartDataList && Object.keys(echartDataList).length > 0">
<template v-for="(val, key, index) of echartDataList">
<div v-for="(item, chartIndex) of val.echartList" :ref="`scroll_${val.title}`" class="disInlineBlock mt10 mb10 plr-10" :style="`width: calc(100% / ${layoutModel}); height:300px;position: relative;`">
<!-- 图表标题 -->
<div style="width: 100%;position: absolute;top: 12px;left: 30px;z-index:999;cursor: default;">
<template v-if="val && val.serverIp">
<div class="w45 disInlineBlock" :title="`${val && val.toTitle || 'toTitle'}${val && val.titleTo || 'titleTo'}${item && item.title || ''}`">
<span v-if="val && val.toTitle" class="disInlineBlock" style="vertical-align: middle;">{{val.toTitle}}</span>
<span class="disInlineBlock" style="width:25%;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;vertical-align: middle;">{{val && val.titleTo || ''}}</span>
<span class="disInlineBlock" style="vertical-align: middle;">{{item && item.title}}</span>
</div>
<div class="disInlineBlock" style="vertical-align: bottom;">{{val.serverIp}}</div>
</template>
<div v-else class="w100" :title="`${val && val.toTitle || 'toTitle'}${val && val.titleTo || 'titleTo'}${item && item.title || ''}`">
<span v-if="val && val.toTitle" class="disInlineBlock" style="vertical-align: middle;">{{val.toTitle}}</span>
<span class="disInlineBlock" style="max-width: calc(100% - 240px);overflow: hidden;text-overflow: ellipsis;white-space: nowrap;vertical-align: middle;">{{val.titleTo}}</span>
<span class="disInlineBlock" style="vertical-align: middle;">{{item && item.title}}</span>
</div>
</div>
<!-- 图表 -->
<EchartsLine :ref="`${key}_${chartIndex}`" v-if="val && val.title" :key="`chart-${key || ''}-${index}-${chartIndex}`" :lineData="item && item.dataVal || {}"
:title="undefined" class="w100 h100" style="border: 1.5px solid #cfcfcf;"
:chartData="(valData, unit) => chartDataEvent(valData, item.fnEvent,val.title, unit)"></EchartsLine>
<div v-else class="w100 h100 flex-center disInlineBlock mt20 mb20 plr-10" :style="`width: calc(100% / ${layoutModel}); height:200px;background: #f5f7fa;`">
<div class="loading-placeholder">
<i class="el-icon-loading"></i>
<span>加载中...</span>
</div>
</div>
</div>
</template>
</template>
<!-- <div v-if="activeName === '网卡流量监控'">-->
<!-- <div v-for="(item, key) of systemContent" class="disInlineBlock w50" style="font-size: 14px;line-height: 25px;vertical-align: top;">-->
<!-- <span style="color: #C0C4CC;">{{item}}</span>{{modelVal[key]}}-->
<!-- </div>-->
<!-- </div>-->
</div>
</template>
<script>
import EchartsLine from "@/components/echartsList/line.vue";
export default {
name: "serRegisTabsChart",
components: {EchartsLine},
props: {
activeName: {
type: String,
default: ''
},
chartModelList: {
type: Object,
default: () => {}
},
modelVal: {
type: Object,
default: () => {}
},
interCartList: {
type: Object,
default: () => {}
}
},
watch: {
chartModelList: {
handler(val) {
if (val && Object.keys(val).length > 0) {
this.$nextTick(() => {
this.echartDataList = JSON.parse(JSON.stringify(val));
});
}
},
deep: true,
immediate: true
},
interCartList: {
handler(val) {
if (val && Object.keys(val).length > 0) {
this.$nextTick(() => {
this.interCardName = Object.keys(this.interCartList)[0];
this.radioTimeChange(this.timeModel);
});
} else if (this.activeName === '挂载文件系统监控' || this.activeName === '硬盘设备监控') {
setTimeout(() => {
this.radioTimeChange(this.timeModel);
},500);
}
},
deep: true,
immediate: true
},
},
data() {
return {
timeList: [],
timeShow: false,
radioTimeList: [{name: '近6小时', value: '6'}, {name: '近24小时', value: '24'}, {name: '昨天', value: '-1'}, {name: '近7天', value: '7'}],
timeModel: '6',
radioLayoutList: [{name: '单列显示', value: '1'}, {name: '双列显示', value: '2'}],
layoutModel: '2',
systemContent: {
systemSwOsCollect: '操作系统', systemSwArchCollect: '操作系统架构', kernelMaxprocCollect: '最大进程数', systemDiskSizeTotalCollect: '硬盘-总可用空间(GB)',
systemBoottimeCollect: '系统启动时间', systemUptimeCollect: '系统正确运行时间', systemLocaltimeCollect: '系统本地时间', avg1: 'CPU的1分钟负载(%)',
avg5: 'CPU的5分钟负载(%)', avg15: 'CPU的15分钟负载(%)', uti: 'CPU使用率(%)', normal: 'CPU正常运行时间(s)', idle: 'CPU空闲时间(s)', iowait: 'CPU等待响应时间(s)',
system: 'CPU系统时间(s)', noresp: 'CPU软件无响应时间(s)', user: 'CPU运行用户进程所花费的时间(s)',procNumRunCollect: '正在运行的进程数(个)', systemUsersNumCollect: '登录用户数(个)',
systemSwapSizeFreeCollect: '交换卷/文件的可用空间(字节)', systemSwapSizePercentCollect: '可用交换空间百分比(%)', memorySizeAvailableCollect: '可用内存(G)', memorySizePercentCollect: '可用内存百分比(%)', systemUnameCollect: '系统描述'
},
sysForm: {},
echartDataList: {},
echartData: {
title: 'GE1/0/1的丢包数',
dataVal: {
hiddenTime: true,
titleVal: {textAlign: 'left', left: '1%'},
yAxisName: ' ',
gridTop: '30%',
legend: {top: '15%', left: '10%'},
lineXData: ['2025-9-1', '2025-9-2', '2025-9-3', '2025-9-4', '2025-9-5', '2025-9-6', '2025-9-7'],
dataList: [{
name: '入站丢包',
data: [120, 132, 101, 134, 90, 230, 210],
},{
name: '出站丢包',
data: [220, 182, 191, 234, 290, 330, 310]
}]
}
},
currTimeList: {},
indexNum: 0,
interCardName: '',
timedRefresh: '',
timeRefresh: '300000',
timeModelOptions: [
{value: '30000', label: '30s刷新'},
{value: '60000', label: '1分钟刷新'},
{value: '300000', label: '5分钟刷新'},
{value: '0', label: '不刷新'},
],
}
},
created() {
},
beforeDestroy() {
clearInterval(this.timedRefresh);
this.timedRefresh = null;
},
methods: {
scrollContent() {
Object.keys(this.$refs).forEach(key => {
if (key.includes('scroll_')) {
if (this.$refs[key]) {
const ref = this.$refs[key];
if (Array.isArray(ref)) {
ref.forEach(item => {
const rect = item.getBoundingClientRect();
const windowHeight = (window.innerHeight || document.documentElement.clientHeight) + (800 / Number(this.layoutModel));
if (rect.top <= windowHeight) {
let originalKey = key.split('scroll_')[1];
this.$emit('lazyLoad', {key: originalKey,currTimeList: this.currTimeList});
}
})
} else if (ref) {
const rect = ref.getBoundingClientRect();
const windowHeight = (window.innerHeight || document.documentElement.clientHeight) + (800 / Number(this.layoutModel));
if (rect.top <= windowHeight) {
let originalKey = key.split('scroll_')[1];
this.$emit('lazyLoad', {key: originalKey,currTimeList: this.currTimeList});
}
}
}
}
})
},
// 定时刷新下拉
fnTimeInter(val) {
clearInterval(this.timedRefresh);
this.timedRefresh = null;
if (val !== '0') {
this.timedRefresh = setInterval(() => {
if (this.timeModel === '6') {
this.getTimeInterval();
} else if (this.timeModel === '24') {
this.get24Time();
} else if (this.timeModel === '-1') {
this.get24Time('-1');
} else if (this.timeModel === '7') {
this.get7dayTime();
}
this.timeList = [this.currTimeList.startTime, this.currTimeList.endTime];
this.$emit('timeChangeData', {currTimeList: this.currTimeList, interCardName: this.interCardName});
}, Number(val));
}
},
// 网卡下拉
handleSelect(val) {
this.$emit('timeChangeData', {currTimeList: this.currTimeList, interCardName: this.interCardName, onlyInterCard: true});
this.fnTimeInter(this.timeRefresh);
},
// 时间 多选框状态
checkChange(val) {
this.timeModel = null;
},
// 时间变化时
dateChange(val){
this.currTimeList = {startTime: val[0], endTime: val[1]};
this.$emit('timeChangeData', {currTimeList: this.currTimeList, interCardName: this.interCardName});
this.fnTimeInter(this.timeRefresh);
},
// 时间按钮切换
radioTimeChange(val) {
this.timeModel = val;
if (val === '6') {
this.getTimeInterval();
} else if (val === '24') {
this.get24Time();
} else if (val === '-1') {
this.get24Time('-1');
} else if (val === '7') {
this.get7dayTime();
}
this.timeList = [this.currTimeList.startTime, this.currTimeList.endTime];
this.$emit('timeChangeData', {currTimeList: this.currTimeList, interCardName: this.interCardName});
this.fnTimeInter(this.timeRefresh);
},
// 单双列按钮切换
radioLayouteChange(val) {
this.layoutModel = val;
this.$nextTick(() => {
// 遍历所有图表实例,分别调用 resize
Object.keys(this.$refs).forEach(key => {
if (!key.includes('scroll_')) {
const chartRefs = this.$refs[key];
if (Array.isArray(chartRefs)) {
chartRefs.forEach(chartRef => {
if (chartRef.resizeChart) {
chartRef.resizeChart();
}
});
}
}
});
});
},
// 近6小时
getTimeInterval() {
let now = new Date();
let sixHoursAgo = new Date(now);
sixHoursAgo.setHours(now.getHours() - 6); // 设置时间为当前时间往前推6小时
// 格式化当前时间和6小时前的时间
let nowFormatted = this.getFormattedDate(now);
let sixHoursAgoFormatted = this.getFormattedDate(sixHoursAgo);
this.currTimeList = {startTime: sixHoursAgoFormatted, endTime: nowFormatted};
},
getFormattedDate(date) {
let year = date.getFullYear();
let month = (date.getMonth() + 1).toString().padStart(2, '0'); // 月份是从0开始的
let day = date.getDate().toString().padStart(2, '0');
let hours = date.getHours().toString().padStart(2, '0');
let minutes = date.getMinutes().toString().padStart(2, '0');
let seconds = date.getSeconds().toString().padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
},
// 近24小时
get24Time(typeNum) {
const now = new Date();
// 获取当前时间
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
// 正确计算前一天(处理跨月情况)
const prevDate = new Date(now);
prevDate.setDate(now.getDate() - 1);
const prevYear = prevDate.getFullYear();
const prevMonth = String(prevDate.getMonth() + 1).padStart(2, '0');
const prevDay = String(prevDate.getDate()).padStart(2, '0');
// 构建时间字符串
const timeString = `${hours}:${minutes}:${seconds}`;
const startData = `${prevYear}-${prevMonth}-${prevDay} ${timeString}`;
const endData = `${year}-${month}-${day} ${timeString}`;
if (typeNum && typeNum === '-1') {
this.currTimeList = {startTime: `${prevYear}-${prevMonth}-${prevDay} 00:00:00`, endTime: `${prevYear}-${prevMonth}-${prevDay} 23:59:59`};
} else {
this.currTimeList = {startTime: startData, endTime: endData};
}
},
// 近7天的
get7dayTime() {
const now = new Date();
const dates = [];
for (let i = 0; i < 7; i++) {
const date = new Date();
date.setDate(now.getDate() - i); // 减去i天,i从0开始,因此第一天是今天,第二天是昨天,依此类推
dates.push(this.formatDate(date));
}
this.currTimeList = {startTime: dates[dates.length - 1], endTime: dates[0]};
},
formatDate(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份是从0开始的
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
},
chartDataEvent(valData, funcName, tabName, unit) {
this.$emit("chartFnEvent", this.currTimeList, funcName, tabName, unit, this.activeName, this.interCardName);
// // 检查函数是否存在,避免报错
// if (typeof this[funcName] === 'function') {
// // 调用实际函数,并传递参数(如选中的值、当前项)
// // this[funcName]({startTime: valData[0], endTime: valData[1]});
// } else {
// console.warn(`函数 ${funcName} 未定义`);
// }
}
}
}
</script>
<style scoped>
::v-deep .el-radio-button__orig-radio:checked + .el-radio-button__inner {
color: #1890ff!important;
background-color: unset!important;
}
.loading-placeholder {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
font-size: 1.1rem;
}
::v-deep .el-radio-button--medium .el-radio-button__inner {
padding: 10px 15px!important;
}
</style>