Files
profitManage1.2/src/views/resource/serverRegister/tabsChart.vue
T

382 lines
17 KiB
Vue
Raw Normal View History

<template>
<div class="w100 h100">
<div class="w100" style="height: 40px;">
<el-date-picker
v-model="timeList"
:style="{width: '360px!important', marginRight: '10px'}"
type="datetimerange"
:disabled="!timeShow"
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>
<!-- 不同条时间件切换 -->
<el-radio-group v-model="timeModel" size="medium" class="ml20" :disabled="timeShow" @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',
2026-01-04 18:31:52 +08:00
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: '系统描述'
2026-01-04 18:31:52 +08:00
},
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.$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.$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>