Files
profitManage1.2/src/components/echartsList/line.vue
T
康冉冉 de5badded4 MTRAgent、服务器管理、交换机管理
1、MTRAgent丢包趋势图添加最新丢包率值显示
2、服务器管理的图形监控调整出入站流量和丢包的展示顺序
3、交换机管理列表添加唯一标识字段
2025-11-28 18:45:15 +08:00

383 lines
15 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>
<DateTimeSelect ref="changeDateTime" v-if="!(lineData && lineData.hiddenTime)" :sideIcon="sideIcon" :dateDataTrans="dateDataTrans" :dateShowType="dateShowType" @dataChange="dataChangeValue"></DateTimeSelect>
<!-- <div :id="`lineChart` + num" style="width:100%;height: 100%;" />-->
<!-- 新增包裹图表和自定义下拉框的容器设置为相对定位 -->
<div class="chart-wrapper">
<!-- 自定义的下拉选择框 -->
<template v-if="this.lineData && this.lineData.unitSelList && this.lineData.unitSelList.length > 0">
<select :class="'yaxis-selector yaxis-selector' + num" v-model="selectedYAxisName">
<option v-for="item of this.lineData.unitSelList" :value="item.value">{{item.label}}</option>
</select>
</template>
<!-- 图表容器id 用于初始化 ECharts -->
<div :id="`lineChart` + num" class="chart-container"></div>
</div>
</div>
</template>
<script>
import * as echarts from 'echarts'
import DateTimeSelect from './dateTimeSelect.vue'
export default {
name: 'echartsLine',
components: {DateTimeSelect},
props: {
lineData: {
type: Object,
default: () => {}
},
title: {
type: String,
default: null
},
dateShowType: {
type: String,
default: null
},
dateDataTrans: {
type: Object,
default: () => ({})
},
chartData: {
type: Function,
default: () => {
}
},
sideIcon: {
type: Object,
default: () => {}
}
},
watch: {
lineData: {
handler(val) {
this.$nextTick(() => {
this.selectedYAxisName = this.lineData && this.lineData.unitModel || '';
this.getList(this.title, this.lineData);
});
},
deep: true,
immediate: true
},
// 新增:监听下拉框选择的变化
selectedYAxisName(newVal) {
if (newVal != (this.lineData && this.lineData.unitModel)) {
let times = this.lineData && this.lineData.hiddenTime ? [] : this.$refs.changeDateTime.dateRange;
this.chartData({timeArr: times}, newVal);
}
}
},
data() {
return {
lineDataList: '',
num: '',
selectedYAxisName: '' // 新增:用于绑定下拉框选中的值
}
},
created() {
this.num = Math.floor(Math.random() * 9000);
},
mounted() {
if (this.lineData && this.lineData.hiddenTime) {
this.$nextTick(() => {
this.getList(this.title, this.lineData);
});
}
},
methods: {
getList(title, dataXY) {
let that = this;
const lineDataListIntance = echarts.init(document.getElementById('lineChart' + that.num));
let titleList = [{text: title, x: '50%', y: '3%', textAlign: 'center',textStyle: {fontSize: 16}}];
if (dataXY && dataXY.titleSubtext) {
titleList.push(dataXY.titleSubtext);
} else if (dataXY && dataXY.titleVal) {
titleList[0] = Object.assign({},titleList[0], dataXY.titleVal);
}
let legendData = dataXY && dataXY.legend ? dataXY.legend : {};
if (dataXY && dataXY.legend && dataXY.legend.formatter) {
let formatData = {
formatter: function(params) {
const customSuffix = dataXY && dataXY.content && dataXY.content[params] || ' ';
return `${params} ${customSuffix}`;
},
};
legendData = Object.assign({}, legendData, formatData);
}
let series = [];
if (dataXY && dataXY.dataList && dataXY.dataList.length > 0) {
dataXY.dataList.forEach(item => {
let str = {
name: item && item.name || '',
type: 'line',
// showSymbol: false,
symbol: item && item.symbol || 'circle',
data: item && item.data || []
};
if (!(item && item.areaStyleNone)) {
str['areaStyle'] = {
opacity: 0.6
};
}
series.push(str);
});
} else {
series = [{
data: dataXY && dataXY.data || [],
type: 'line',
smooth: true,
// areaStyle: { // 阴影
// color: 'rgba(140, 158, 217, 1)'
// }
}];
}
let option = {
title: titleList,
legend: legendData,
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
},
formatter: !dataXY.tooltipFormatter ? null : function(params) {
// 获取当前悬停的日期
const date = params[0].name;
// 构建提示框HTML内容
let html = `<div>${date}</div>`;
// 遍历所有系列
params.forEach(param => {
let valueparams = param.value;
if (dataXY.tooltipFormatter && dataXY.tooltipFormatter.valueToop) {
let value = dataXY.tooltipFormatter.valueToop;
valueparams = param.value && param.value === value.num ? value.msg : param.value || param.value === 0 ? param.value : '-';
}
// 为每个系列创建一行
html += `
<div style="display: flex; justify-content: space-between; align-items: center; margin: 4px 0;">
<div style="display: flex; align-items: center;">
<span style="display: inline-block; width: 10px; height: 10px; border-radius: 50%; background-color: ${param.color}; margin-right: 8px;"></span>
<span style="color: #57606f;">${param.seriesName} </span>
</div>
<span style="font-weight: bold; color: #2f3542;margin-left:20px;"> ${valueparams}</span>
</div>`;
});
return html;
}
},
grid: {
top: dataXY && dataXY.gridTop || '80px',
left: dataXY && dataXY.gridLeft || '2%',
right: '4%',
bottom: dataXY && dataXY.gridBotm || '3%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
axisLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
formatter: function(value) {
if (value) {
// 每4个字符换一行(根据实际文本长度调整)
const maxLength = 11;
let result = '';
let count = 0;
for (let i = 0; i < value.length; i++) {
count++;
result += value[i];
if (count % maxLength === 0 && i !== value.length - 1) {
result += '\n'; // 换行
}
}
return result;
}
},
// lineHeight: 10, // 行高(确保换行后不重叠)
},
data: dataXY && dataXY.lineXData || []
},
yAxis: {
type: 'value',
name: dataXY?.yAxisName || ' ',
nameTextStyle: dataXY && dataXY.unitSelList && dataXY.unitSelList.length > 0 ? {color: 'transparent'} : {}, // 将名称文本颜色设为透明,使其不可见
min: 0, // 自定义最小刻度(根据业务需求调整,如 0)
max: dataXY && dataXY.data && dataXY.data.length > 0 ? null : dataXY && dataXY.dataList && dataXY.dataList[0] && dataXY.dataList[0].data.length > 0 ? null : 100,
splitLine: {
show: true,
},
},
// 配置高亮状态下的样式
emphasis: dataXY && dataXY.highlight ? {
itemStyle: {
borderWidth: 2, // 边框加粗
shadowBlur: 5, // 添加阴影光晕
},
label: {
show: false, // 高亮时显示标签
}
} : {},
series: series
};
lineDataListIntance.setOption(option);
if (dataXY && dataXY.highlight) {
// 然后高亮当前点击的数据点
lineDataListIntance.dispatchAction({
type: 'highlight', // 高亮类型
seriesIndex: 0, // 系列索引,从点击事件参数中获取
dataIndex: 0 // 数据索引,从点击事件参数中获取
});
}
if (dataXY && dataXY.unitSelList && dataXY.unitSelList.length > 0) {
// 初始化图表后,调用方法定位下拉框
this.positionYAxisSelector(lineDataListIntance);
}
window.addEventListener("resize", () => {
lineDataListIntance.resize();
if (dataXY && dataXY.unitSelList && dataXY.unitSelList.length > 0) {
this.positionYAxisSelector(lineDataListIntance);
}
});
lineDataListIntance.off('click');
lineDataListIntance.on("click", function(params) {
that.$emit("chartClickModel", {params: params});
if (dataXY && dataXY.highlight) {
// 首先取消之前可能存在的高亮状态
lineDataListIntance.dispatchAction({
type: 'downplay' // 取消所有数据点的高亮
});
// 然后高亮当前点击的数据点
setTimeout(() => {
lineDataListIntance.dispatchAction({
type: 'highlight', // 高亮类型
seriesIndex: params.seriesIndex, // 系列索引,从点击事件参数中获取
dataIndex: params.dataIndex // 数据索引,从点击事件参数中获取
});
},1000);
}
});
// 2. 关键:拦截默认的鼠标移出事件,不做任何操作(即不取消高亮)
lineDataListIntance.on('mouseover', (params) => {
// 这个函数体为空,或者只包含一些不涉及downplay的逻辑
// 这样就阻止了鼠标移出时高亮自动消失
});
// 2. 关键:拦截默认的鼠标移出事件,不做任何操作(即不取消高亮)
lineDataListIntance.on('mouseout', (params) => {
// 这个函数体为空,或者只包含一些不涉及downplay的逻辑
// 这样就阻止了鼠标移出时高亮自动消失
});
},
positionYAxisSelector(chartInstance) {
const selector = document.querySelector('.yaxis-selector' + this.num);
if (!selector || !chartInstance) return;
const chartDom = chartInstance.getDom();
const chartRect = chartDom.getBoundingClientRect();
// 获取图表配置项中的网格设置
const option = chartInstance.getOption();
const grid = option.grid && option.grid[0] ? option.grid[0] : {};
// 使用网格的 left 和 top 作为基准点
const gridLeft = this.parseGridValue(grid.left || '2%', chartRect.width);
const gridTop = this.parseGridValue(grid.top || '80px', chartRect.height);
// const labelAreaLeft = gridLeft - 100; // 向左偏移
// const labelAreaTop = gridTop + (chartRect.height / 2) - 10; // 垂直居中
// selector.style.left = `${chartRect.left + window.pageXOffset + labelAreaLeft}px`;
// selector.style.top = `${chartRect.top + window.pageYOffset + labelAreaTop}px`;
const labelAreaLeft = gridLeft - 5; // 向左偏移
const labelAreaTop = gridTop - 35; // 垂直居中
selector.style.left = `${labelAreaLeft}px`;
selector.style.top = `${labelAreaTop}px`;
},
// 辅助方法:解析网格值(百分比、像素等)
parseGridValue(value, containerSize) {
if (typeof value === 'number') return value;
if (typeof value === 'string') {
if (value.includes('%')) {
return (parseFloat(value) / 100) * containerSize;
} else if (value.includes('px')) {
return parseFloat(value);
}
}
return 0;
},
// updateChartOnYAxisChange(selectedValue) {
// // 根据选择的值,动态更新图表配置
// // 例如,可以更新 Y 轴的单位名称、最大值、最小值,甚至切换整个 series 的数据[2](@ref)
// const chartDom = document.getElementById('lineChart' + this.num);
// const chartInstance = echarts.getInstanceByDom(chartDom);
//
// if (chartInstance) {
// // 示例:更新 Y 轴的名称显示(虽然它是隐藏的,但可能用于 tooltip 等)
// const option = chartInstance.getOption();
// option.yAxis[0].name = this.getYAxisNameByValue(selectedValue); // 假设的方法,根据值返回要显示的名称文本
//
// // 示例:可以在这里根据 selectedValue 重新设置 series 的 data[5](@ref)
// // option.series[0].data = ... 从某个数据源获取新数据
//
// chartInstance.setOption(option);
// }
// },
// getYAxisNameByValue(value) {
// // 一个简单映射,将下拉框的值转换为实际要显示的轴名称
// const map = {
// 'value1': '温度 (°C)',
// 'value2': '湿度 (%)',
// 'value3': '压力 (Pa)'
// };
// return map[value] || '';
// },
dataChangeValue(val, timeArr, iconVal) {
// 调用父级页面传过来的事件,在父级中处理该方法的逻辑--
if (timeArr) {
this.chartData(timeArr);
}
if (iconVal) {
this.chartData({iconVal: iconVal})
}
// let lineDataList = days && days.length > 0 ? days: this.lineData.lineXData;
// this.getList(this.title, {data: this.lineData.data, lineXData: lineDataList});
}
}
}
</script>
<style scoped>
/* 新增样式 */
.chart-wrapper {
position: relative; /* 为绝对定位的下拉框提供参考 */
width: 100%;
height: 100%;
}
.chart-container {
width: 100%;
height: 100%;
}
.yaxis-selector {
position: absolute; /* 绝对定位,相对于 .chart-wrapper */
z-index: 10; /* 确保下拉框显示在图表上方 */
/* 初始位置,后续由 js 方法精细调整 */
top: 0;
left: 0;
background: white;
border: 1px solid #ccc;
border-radius: 3px;
padding: 2px 5px;
font-size: 12px;
}
</style>