feat: 黄金指标项图表实时5s展示

This commit is contained in:
TsMask
2024-02-06 18:41:54 +08:00
parent f07f57e7b4
commit 9ab1c03eda
3 changed files with 188 additions and 83 deletions

View File

@@ -719,6 +719,7 @@ export default {
exportSure:'Confirm whether to export all statistical data', exportSure:'Confirm whether to export all statistical data',
exportEmpty: "Export data is empty", exportEmpty: "Export data is empty",
showChartSelected: "Show All", showChartSelected: "Show All",
realTimeData: "Real Time 5s Data",
} }
}, },
traceManage: { traceManage: {

View File

@@ -719,6 +719,7 @@ export default {
exportSure:'确认是否导出全部统计数据', exportSure:'确认是否导出全部统计数据',
exportEmpty: "导出数据为空", exportEmpty: "导出数据为空",
showChartSelected: "显示全部", showChartSelected: "显示全部",
realTimeData: "实时5s数据",
} }
}, },
traceManage: { traceManage: {

View File

@@ -14,14 +14,25 @@ import { LineChart, LineSeriesOption } from 'echarts/charts';
import { UniversalTransition } from 'echarts/features'; import { UniversalTransition } from 'echarts/features';
import { CanvasRenderer } from 'echarts/renderers'; import { CanvasRenderer } from 'echarts/renderers';
import { reactive, ref, onMounted, toRaw, markRaw, nextTick } from 'vue'; import {
reactive,
ref,
onMounted,
toRaw,
markRaw,
nextTick,
onBeforeUnmount,
} from 'vue';
import { PageContainer } from 'antdv-pro-layout'; import { PageContainer } from 'antdv-pro-layout';
import { message, Modal } from 'ant-design-vue/lib'; import { message, Modal } from 'ant-design-vue/lib';
import { ColumnsType } from 'ant-design-vue/lib/table'; import { ColumnsType } from 'ant-design-vue/lib/table';
import { SizeType } from 'ant-design-vue/lib/config-provider'; import { SizeType } from 'ant-design-vue/lib/config-provider';
import { MenuInfo } from 'ant-design-vue/lib/menu/src/interface'; import { MenuInfo } from 'ant-design-vue/lib/menu/src/interface';
import TableColumnsDnd from '@/components/TableColumnsDnd/index.vue'; import TableColumnsDnd from '@/components/TableColumnsDnd/index.vue';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants'; import {
RESULT_CODE_ERROR,
RESULT_CODE_SUCCESS,
} from '@/constants/result-constants';
import useNeInfoStore from '@/store/modules/neinfo'; import useNeInfoStore from '@/store/modules/neinfo';
import useI18n from '@/hooks/useI18n'; import useI18n from '@/hooks/useI18n';
import { getKPITitle, listKPIData } from '@/api/perfManage/goldTarget'; import { getKPITitle, listKPIData } from '@/api/perfManage/goldTarget';
@@ -29,8 +40,10 @@ import { parseDateToStr } from '@/utils/date-utils';
import { writeSheet } from '@/utils/execl-utils'; import { writeSheet } from '@/utils/execl-utils';
import saveAs from 'file-saver'; import saveAs from 'file-saver';
import { generateColorRGBA } from '@/utils/generate-utils'; import { generateColorRGBA } from '@/utils/generate-utils';
import { OptionsType, WS } from '@/plugins/ws-websocket';
const neInfoStore = useNeInfoStore(); const neInfoStore = useNeInfoStore();
const { t, currentLocale } = useI18n(); const { t, currentLocale } = useI18n();
const ws = new WS();
echarts.use([ echarts.use([
TooltipComponent, TooltipComponent,
@@ -160,66 +173,17 @@ function fnTableChange(pagination: any, filters: any, sorter: any, extra: any) {
type StateType = { type StateType = {
/**网元类型 */ /**网元类型 */
neType: string[]; neType: string[];
/**图表实时统计 */
chartRealTime: boolean;
/**图表标签选择 */ /**图表标签选择 */
chartLegendSelectedFlag: boolean; chartLegendSelectedFlag: boolean;
/**图表标签选择 */
chartLegendSelected: Record<string, boolean>;
/**图表配置数据 */
chartOption: EChartsOption;
}; };
/**对象信息状态 */ /**对象信息状态 */
let state: StateType = reactive({ let state: StateType = reactive({
neType: [], neType: [],
chartRealTime: false,
chartLegendSelectedFlag: false, chartLegendSelectedFlag: false,
chartLegendSelected: {},
chartOption: {
tooltip: {
trigger: 'axis',
position: function (pt: any) {
return [pt[0], '10%'];
},
},
xAxis: {
type: 'category',
boundaryGap: false,
data: [],
},
yAxis: {
type: 'value',
boundaryGap: [0, '100%'],
},
legend: {
type: 'scroll',
orient: 'vertical',
top: 40,
right: 20,
itemWidth: 20,
itemGap: 25,
textStyle: {
color: '#646A73',
},
icon: 'circle',
selected: {},
},
grid: {
left: '10%',
right: '30%',
bottom: '20%',
},
dataZoom: [
{
type: 'inside',
start: 90,
end: 100,
},
{
start: 90,
end: 100,
},
],
series: [],
},
}); });
/** /**
@@ -373,7 +337,54 @@ function fnRanderChart() {
if (!container) return; if (!container) return;
kpiChart.value = markRaw(echarts.init(container, 'light')); kpiChart.value = markRaw(echarts.init(container, 'light'));
kpiChart.value.setOption(state.chartOption); const option: EChartsOption = {
tooltip: {
trigger: 'axis',
position: function (pt: any) {
return [pt[0], '10%'];
},
},
xAxis: {
type: 'category',
boundaryGap: false,
data: [], // 数据x轴
},
yAxis: {
type: 'value',
boundaryGap: [0, '100%'],
},
legend: {
type: 'scroll',
orient: 'vertical',
top: 40,
right: 20,
itemWidth: 20,
itemGap: 25,
textStyle: {
color: '#646A73',
},
icon: 'circle',
selected: {},
},
grid: {
left: '10%',
right: '30%',
bottom: '20%',
},
dataZoom: [
{
type: 'inside',
start: 90,
end: 100,
},
{
start: 90,
end: 100,
},
],
series: [], // 数据y轴
};
kpiChart.value.setOption(option);
// 创建 ResizeObserver 实例 // 创建 ResizeObserver 实例
var observer = new ResizeObserver(entries => { var observer = new ResizeObserver(entries => {
@@ -385,17 +396,24 @@ function fnRanderChart() {
observer.observe(container); observer.observe(container);
} }
/**图表标签选择 */
let chartLegendSelected: Record<string, boolean> = {};
/**图表配置数据x轴 */
let chartDataXAxisData: string[] = [];
/**图表配置数据y轴 */
let chartDataYSeriesData: Record<string, any>[] = [];
/**图表数据渲染 */ /**图表数据渲染 */
function fnRanderChartData() { function fnRanderChartData() {
if (kpiChart.value == null && tableState.data.length <= 0) { if (kpiChart.value == null && tableState.data.length <= 0) {
return; return;
} }
const xDatas: string[] = []; // 重置
const yDatas: Record<string, any>[] = []; chartLegendSelected = {};
chartDataXAxisData = [];
chartDataYSeriesData = [];
const tableColumnsKeyArr: string[] = [];
const chartLegendSelected: Record<string, boolean> = {};
for (const columns of tableColumns.value) { for (const columns of tableColumns.value) {
if ( if (
columns.key === 'neName' || columns.key === 'neName' ||
@@ -405,8 +423,9 @@ function fnRanderChartData() {
continue; continue;
} }
const color = generateColorRGBA(); const color = generateColorRGBA();
yDatas.push({ chartDataYSeriesData.push({
name: `${columns.title}`, name: `${columns.title}`,
key: `${columns.key}`,
type: 'line', type: 'line',
symbol: 'none', symbol: 'none',
sampling: 'lttb', sampling: 'lttb',
@@ -427,7 +446,6 @@ function fnRanderChartData() {
}, },
data: [], data: [],
}); });
tableColumnsKeyArr.push(`${columns.key}`);
chartLegendSelected[`${columns.title}`] = state.chartLegendSelectedFlag; chartLegendSelected[`${columns.title}`] = state.chartLegendSelectedFlag;
} }
@@ -436,40 +454,38 @@ function fnRanderChartData() {
if (queryParams.sortOrder === 'desc') { if (queryParams.sortOrder === 'desc') {
orgData = orgData.toReversed(); orgData = orgData.toReversed();
} }
for (const item of orgData) { for (const item of orgData) {
xDatas.push(item['timeGroup']); chartDataXAxisData.push(item['timeGroup']);
const keys = Object.keys(item); const keys = Object.keys(item);
for (let i = 0; i < tableColumnsKeyArr.length; i++) { for (const y of chartDataYSeriesData) {
for (const key of keys) { for (const key of keys) {
if (tableColumnsKeyArr[i] === key) { if (y.key === key) {
yDatas[i].data.push(+item[key]); y.data.push(+item[key]);
} }
} }
} }
} }
// console.log(queryParams.sortOrder, xDatas, yDatas); // console.log(queryParams.sortOrder, chartLegendSelected);
// console.log(chartDataXAxisData, chartDataYSeriesData)
// 图标签选择状态标记 // 绘制图数据
state.chartLegendSelected = chartLegendSelected;
kpiChart.value.setOption({ kpiChart.value.setOption({
legend: { legend: {
selected: chartLegendSelected, selected: chartLegendSelected,
}, },
xAxis: { xAxis: {
data: xDatas, data: chartDataXAxisData,
}, },
series: yDatas, series: chartDataYSeriesData,
}); });
} }
/**图表折线显示全部 */ /**图表折线显示全部 */
function fnLegendSelected(bool: any) { function fnLegendSelected(bool: any) {
const chartLegendSelected: Record<string, boolean> = {}; for (const key of Object.keys(chartLegendSelected)) {
for (const key of Object.keys(state.chartLegendSelected)) {
chartLegendSelected[key] = bool; chartLegendSelected[key] = bool;
} }
// 图标签选择状态标记
state.chartLegendSelected = chartLegendSelected;
kpiChart.value.setOption({ kpiChart.value.setOption({
legend: { legend: {
selected: chartLegendSelected, selected: chartLegendSelected,
@@ -477,6 +493,75 @@ function fnLegendSelected(bool: any) {
}); });
} }
/**图表实时统计 */
function fnRealTimeSwitch(bool: any) {
if (bool) {
// 建立链接
const options: OptionsType = {
url: '/ws',
params: {
/**订阅通道组
*
* 指标(GroupID:10)
*/
subGroupID: '10',
},
onmessage: wsMessage,
onerror: wsError,
};
ws.connect(options);
} else {
ws.close();
}
}
/**接收数据后回调 */
function wsError(ev: any) {
// 接收数据后回调
console.error(ev);
}
/**接收数据后回调 */
function wsMessage(res: Record<string, any>) {
const { code, requestId, data } = res;
if (code === RESULT_CODE_ERROR) {
console.warn(res.msg);
return;
}
// 订阅组信息
if (!data?.groupId) {
return;
}
// kpiEvent 黄金指标指标事件
if (data.groupId === '10') {
const kpiEvent = data.data;
for (const key of Object.keys(data.data)) {
const v = kpiEvent[key];
// x轴
if (key === 'timeGroup') {
// chartDataXAxisData.shift();
chartDataXAxisData.push(v);
continue;
}
// y轴
const yItem = chartDataYSeriesData.find(item => item.key === key);
if (yItem) {
// yItem.data.shift();
yItem.data.push(v);
}
}
// 绘制图数据
kpiChart.value.setOption({
xAxis: {
data: chartDataXAxisData,
},
series: chartDataYSeriesData,
});
}
}
onMounted(() => { onMounted(() => {
// 获取网元网元列表 // 获取网元网元列表
neInfoStore.fnNelist().then(res => { neInfoStore.fnNelist().then(res => {
@@ -512,8 +597,8 @@ onMounted(() => {
// 查询当前小时 // 查询当前小时
const nowDate: Date = new Date(); const nowDate: Date = new Date();
nowDate.setMinutes(0, 0, 0); nowDate.setMinutes(0, 0, 0);
queryRangePicker.value[0] = parseDateToStr(nowDate); // queryRangePicker.value[0] = parseDateToStr(nowDate);
// queryRangePicker.value[0] = '2024-01-30 00:00:00'; queryRangePicker.value[0] = '2024-01-30 00:00:00';
nowDate.setMinutes(59, 59, 59); nowDate.setMinutes(59, 59, 59);
queryRangePicker.value[1] = parseDateToStr(nowDate); queryRangePicker.value[1] = parseDateToStr(nowDate);
fnGetListTitle(); fnGetListTitle();
@@ -528,6 +613,10 @@ onMounted(() => {
} }
}); });
}); });
onBeforeUnmount(() => {
ws.close();
});
</script> </script>
<template> <template>
@@ -677,20 +766,34 @@ onMounted(() => {
</a-dropdown> </a-dropdown>
</a-tooltip> </a-tooltip>
</a-space> </a-space>
<a-space :size="8" align="center" v-show="!tableState.showTable"> <a-form layout="inline" v-show="!tableState.showTable">
<a-tooltip> <a-form-item
<template #title> :label="t('views.perfManage.goldTarget.showChartSelected')"
{{ t('views.perfManage.goldTarget.showChartSelected') }} name="chartLegendSelectedFlag"
</template> >
<a-switch <a-switch
:disabled="tableState.loading" :disabled="tableState.loading"
v-model:checked="state.chartLegendSelectedFlag" v-model:checked="state.chartLegendSelectedFlag"
:checked-children="t('common.switch.open')" :checked-children="t('common.switch.open')"
:un-checked-children="t('common.switch.shut')" :un-checked-children="t('common.switch.shut')"
@change="fnLegendSelected" @change="fnLegendSelected"
size="small"
/> />
</a-tooltip> </a-form-item>
</a-space> <a-form-item
:label="t('views.perfManage.goldTarget.realTimeData')"
name="chartRealTime"
>
<a-switch
:disabled="tableState.loading"
v-model:checked="state.chartRealTime"
:checked-children="t('common.switch.open')"
:un-checked-children="t('common.switch.shut')"
@change="fnRealTimeSwitch"
size="small"
/>
</a-form-item>
</a-form>
</template> </template>
<!-- 表格列表 --> <!-- 表格列表 -->