feat: 看板左右高度百分比适配

This commit is contained in:
TsMask
2024-01-27 14:57:21 +08:00
parent 4ea8ec2f96
commit 24b367c08e
7 changed files with 395 additions and 373 deletions

View File

@@ -1,71 +1,31 @@
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref, onMounted } from 'vue'; import { reactive, ref, onMounted } from 'vue';
import {
cdrEventData,
cdrEventTotal,
cdrEventId,
} from '../../hooks/useCDREvent';
import useI18n from '@/hooks/useI18n'; import useI18n from '@/hooks/useI18n';
const { t } = useI18n(); const { t } = useI18n();
const newNumber = ref(1);
const dataArr = ref([
{
recordType: 'CALL',
seqNumber: 1,
callReference: 'X1gcbQ8zT@10.10.91.252',
callerParty: '12307551241',
calledParty: '12307550064',
serviceResult: 'ok',
seizureTime: 1705542348,
answerTime: 1705542356,
releaseTime: 1705542378,
callDuration: 22,
},
]);
onMounted(() => {
setInterval(function () {
const random = Math.ceil(Math.random() * 1000);
const time = Math.ceil(Date.now() / 1000);
newNumber.value = time;
dataArr.value.unshift({
recordType: 'CALL',
seqNumber: time,
callReference: `X${random}Q8zT@10${random}.252`,
callerParty: `1230755${random}`,
calledParty: `${random}075064`,
serviceResult: random > 500 ? 'ok' : 'fail',
seizureTime: time,
answerTime: time,
releaseTime: time - random,
callDuration: 22,
});
if (dataArr.value.length > 50) {
dataArr.value.splice(50);
}
}, 2000);
});
</script> </script>
<template> <template>
<div class="cdr" style="display: block"> <div class="cdr" style="display: block">
<div class="cdr-head"> <div class="cdr-head">
<span class="col">号码</span> <span class="col">call</span>
<span class="col">行为</span> <span class="col">行为</span>
<span class="col-w">描述</span> <span class="col-w">信息</span>
</div> </div>
<div class="cdr-marquee-view"> <div class="cdr-marquee-view">
<div <div
class="row" class="row"
:class="{ 'row-new': item.seqNumber === newNumber }" :class="{ 'row-new': item.id === cdrEventId }"
v-for="item in dataArr" v-for="item in cdrEventData"
:key="item.seqNumber" :key="item.id"
> >
<span class="col">{{ item.callReference }}</span> <span class="col" :title="item.call">{{ item.call }}</span>
<span class="col">{{ item.recordType }}</span> <span class="col" :title="item.type">{{ item.type }}</span>
<span class="col-w" <span class="col-w" :title="item.msg">{{ item.msg }}</span>
>[{{ item.serviceResult }}]
{{ item.callerParty }}
->
{{ item.calledParty }}
# {{ item.callDuration }}
</span>
</div> </div>
</div> </div>
</div> </div>
@@ -73,21 +33,26 @@ onMounted(() => {
<style lang="less" scoped> <style lang="less" scoped>
.cdr { .cdr {
height: 88%;
&-head { &-head {
background: rgba(255, 255, 255, 0.1); background: rgba(255, 255, 255, 0.1);
font-size: 0.583rem; font-size: 0.583rem;
padding: 0.5rem 1.5rem; padding: 0.5rem 1.5rem;
color: #68d8fe; color: #68d8fe;
display: flex; display: flex;
justify-content: space-between; justify-content: flex-start;
line-height: 1.05; line-height: 1.05;
& .col { & .col {
width: 3.2rem; min-width: 3.2rem;
width: 30%;
margin-right: 1rem;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
&-w { &-w {
width: 8.4rem; min-width: 8.4rem;
width: 60%;
} }
} }
} }
@@ -95,7 +60,7 @@ onMounted(() => {
&-marquee-view { &-marquee-view {
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto; overflow-y: auto;
height: 70%; height: 92%;
/* 修改滚动条的样式 */ /* 修改滚动条的样式 */
&::-webkit-scrollbar { &::-webkit-scrollbar {
@@ -115,16 +80,18 @@ onMounted(() => {
} }
& .row { & .row {
line-height: 1.05; line-height: 1.5;
padding: 0.5rem 1.5rem; padding: 0 1.5rem;
color: #61a8ff; color: #61a8ff;
font-size: 0.75rem; font-size: 0.75rem;
position: relative; position: relative;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
cursor: context-menu;
&-new { &-new {
color: #fff; color: #fff;
animation: backInRight 0.3s alternate; animation: backInRight 0.3s alternate;
font-size: 0.95rem;
} }
@keyframes backInRight { @keyframes backInRight {
0% { 0% {
@@ -146,12 +113,18 @@ onMounted(() => {
} }
} }
& .col { & .col {
width: 3.2rem; min-width: 3.2rem;
width: 30%;
margin-right: 1rem;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
&-w { &-w {
width: 8.4rem; min-width: 8.4rem;
width: 60%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
} }
} }
} }

View File

@@ -1,18 +1,24 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref, onBeforeUnmount, nextTick } from 'vue'; import { onMounted, ref, onBeforeUnmount, nextTick, watch } from 'vue';
import * as echarts from 'echarts/core'; import * as echarts from 'echarts/core';
import { TooltipComponent } from 'echarts/components'; import { GridComponent, GridComponentOption } from 'echarts/components';
import { GaugeChart } from 'echarts/charts'; import {
BarChart,
BarSeriesOption,
PictorialBarChart,
PictorialBarSeriesOption,
} from 'echarts/charts';
import { CanvasRenderer } from 'echarts/renderers'; import { CanvasRenderer } from 'echarts/renderers';
import { graphNodeClickID, graphNodeState } from '../../hooks/useTopology'; import { graphNodeClickID, graphNodeState } from '../../hooks/useTopology';
import useI18n from '@/hooks/useI18n'; import useI18n from '@/hooks/useI18n';
import { GaugeSeriesOption } from 'echarts/types/dist/echarts'; import { markRaw } from 'vue';
import { watch } from 'vue';
const { t } = useI18n(); const { t } = useI18n();
echarts.use([TooltipComponent, GaugeChart, CanvasRenderer]); echarts.use([GridComponent, BarChart, PictorialBarChart, CanvasRenderer]);
type EChartsOption = echarts.ComposeOption<GaugeSeriesOption>; type EChartsOption = echarts.ComposeOption<
GridComponentOption | BarSeriesOption | PictorialBarSeriesOption
>;
/**图DOM节点实例对象 */ /**图DOM节点实例对象 */
const neResourcesDom = ref<HTMLElement | undefined>(undefined); const neResourcesDom = ref<HTMLElement | undefined>(undefined);
@@ -20,199 +26,188 @@ const neResourcesDom = ref<HTMLElement | undefined>(undefined);
/**图实例对象 */ /**图实例对象 */
const neResourcesChart = ref<any>(null); const neResourcesChart = ref<any>(null);
const optionData: EChartsOption = { // 类别
tooltip: { const category = ref<any>([
formatter: '{a} <br> {b} : {c}%', {
name: '系统内存',
value: 1,
}, },
{
name: '系统CPU',
value: 1,
},
{
name: '网元CPU',
value: 1,
},
]);
// 数据总数
const total = 100;
/**图数据 */
const optionData: EChartsOption = {
xAxis: {
max: total,
splitLine: {
show: false,
},
axisLine: {
show: false,
},
axisLabel: {
show: false,
},
axisTick: {
show: false,
},
},
grid: {
top: '1%', // 设置条形图的边距
bottom: '12%',
left: '25%',
right: '25%',
},
yAxis: [
{
type: 'category',
inverse: false,
data: category.value,
axisLine: {
show: false,
},
axisTick: {
show: false,
},
axisLabel: {
show: false,
},
},
],
series: [ series: [
{ {
name: '系统内存', // 内
type: 'gauge', type: 'bar',
center: ['15%', '45%'], barWidth: 10,
radius: '65%', legendHoverLink: false,
startAngle: 90, silent: true,
endAngle: -270,
min: 1,
max: 100,
itemStyle: { itemStyle: {
color: '#1890ff', color: function (params) {
}, // 红色
progress: { if (+params.value >= 70) {
show: true, return new echarts.graphic.LinearGradient(0, 0, 1, 0, [
width: 20, { offset: 0, color: '#fff1f0' },
overlap: true, { offset: 0.5, color: '#ffa39e' },
roundCap: true, { offset: 1, color: '#f5222d' },
clip: false, ]);
}, }
pointer: { // 蓝色
show: false, if (+params.value >= 30) {
}, return new echarts.graphic.LinearGradient(0, 0, 1, 0, [
axisLine: { { offset: 0, color: '#f0f5ff' },
lineStyle: { { offset: 0.5, color: '#adc6ff' },
width: 20, { offset: 1, color: '#2f54eb' },
]);
}
// 绿色
return new echarts.graphic.LinearGradient(0, 0, 1, 0, [
{ offset: 0, color: '#f6ffed' },
{ offset: 0.5, color: '#b7eb8f' },
{ offset: 1, color: '#52c41a' },
]);
}, },
}, },
axisTick: { label: {
show: false,
},
splitLine: {
show: false,
},
axisLabel: {
show: false,
},
anchor: {
show: false,
},
title: {
show: true, show: true,
offsetCenter: [0, '-10%'], position: 'left',
formatter: '{b}: ',
fontSize: 15, fontSize: 15,
color: '#fafafa', color: '#fff',
}, },
detail: { data: category.value,
valueAnimation: true, z: 1,
width: '60%', animationEasing: 'elasticOut',
lineHeight: 40,
borderRadius: 8,
offsetCenter: [0, '30%'],
fontSize: 15,
fontWeight: 'bolder',
formatter: '{value}%',
color: 'inherit',
},
data: [
{
name: '系统内存',
value: 1,
},
],
}, },
{ {
name: '系统CPU', // 分隔
type: 'gauge', type: 'pictorialBar',
center: ['50%', '45%'],
radius: '65%',
startAngle: 90,
endAngle: -270,
min: 1,
max: 100,
itemStyle: { itemStyle: {
color: '#1890ff', color: '#0a3ca0',
}, },
progress: { symbolRepeat: 'fixed',
show: true, symbolMargin: 6,
width: 20, symbol: 'rect',
overlap: true, symbolClip: true,
roundCap: true, symbolSize: [1, 12],
clip: false, symbolPosition: 'start',
}, symbolOffset: [0, -1],
pointer: { symbolBoundingData: total,
show: false, data: category.value,
}, z: 2,
axisLine: { animationEasing: 'elasticOut',
lineStyle: {
width: 20,
},
},
axisTick: {
show: false,
},
splitLine: {
show: false,
},
axisLabel: {
show: false,
},
anchor: {
show: false,
},
title: {
show: true,
offsetCenter: [0, '-10%'],
fontSize: 15,
color: '#fafafa',
},
detail: {
valueAnimation: true,
width: '60%',
lineHeight: 40,
borderRadius: 8,
offsetCenter: [0, '30%'],
fontSize: 15,
fontWeight: 'bolder',
formatter: '{value}%',
color: 'inherit',
},
data: [
{
name: '系统内存',
value: 20,
},
],
}, },
{ {
name: '网元内存', // 外边框
type: 'gauge', type: 'pictorialBar',
center: ['85%', '45%'], symbol: 'rect',
radius: '65%', symbolBoundingData: total,
startAngle: 90,
endAngle: -270,
min: 1,
max: 100,
itemStyle: { itemStyle: {
color: '#1890ff', color: 'transparent',
}, },
progress: { label: {
show: true, formatter: params => {
width: 20, var text = `{a| ${params.value}%} `;
overlap: true, if (+params.value >= 70) {
roundCap: true, text = `{c| ${params.value}%} `;
clip: false, } else if (+params.value >= 30) {
}, text = `{b| ${params.value}%} `;
pointer: { }
show: false, return text;
},
axisLine: {
lineStyle: {
width: 20,
}, },
}, rich: {
axisTick: { a: {
show: false, color: '#52c41a', // 绿
}, fontSize: 16,
splitLine: { },
show: false, b: {
}, color: '#2f54eb', // 蓝
axisLabel: { fontSize: 16,
show: false, },
}, c: {
anchor: { color: '#f5222d', // 红
show: false, fontSize: 16,
}, },
title: { f: {
show: true, color: '#ffffff', // 默认
offsetCenter: [0, '-10%'], fontSize: 16,
fontSize: 15, },
color: '#fafafa',
},
detail: {
valueAnimation: true,
width: '60%',
lineHeight: 40,
borderRadius: 8,
offsetCenter: [0, '30%'],
fontSize: 15,
fontWeight: 'bolder',
formatter: '{value}%',
color: 'inherit',
},
data: [
{
name: '系统内存',
value: 20,
}, },
], position: 'right',
distance: 0, // 向右偏移位置
show: true,
},
data: category.value,
z: 0,
animationEasing: 'elasticOut',
},
{
name: '外框',
type: 'bar',
barGap: '-120%', // 设置外框粗细
data: [total, total, total],
barWidth: 14,
itemStyle: {
color: 'transparent', // 填充色
borderColor: '#0a3ca0', // 边框色
borderWidth: 1, // 边框宽度
borderRadius: 1, //圆角半径
},
label: {
// 标签显示位置
show: false,
position: 'top', // insideTop 或者横向的 insideLeft
},
z: 0,
}, },
], ],
}; };
@@ -223,12 +218,14 @@ function handleRanderChart(
option: EChartsOption option: EChartsOption
) { ) {
if (!container) return; if (!container) return;
neResourcesChart.value = echarts.init(container, 'light'); neResourcesChart.value = markRaw(echarts.init(container, 'light'));
option && neResourcesChart.value.setOption(option); option && neResourcesChart.value.setOption(option);
// 创建 ResizeObserver 实例 // 创建 ResizeObserver 实例
var observer = new ResizeObserver(function (entries) { var observer = new ResizeObserver(entries => {
neResourcesChart.value.resize(); if (neResourcesChart.value) {
neResourcesChart.value.resize();
}
}); });
// 监听元素大小变化 // 监听元素大小变化
observer.observe(container); observer.observe(container);
@@ -240,75 +237,45 @@ function fnChangeData(data: any[], itemID: string) {
info = data.find((item: any) => item.id === 'OMC'); info = data.find((item: any) => item.id === 'OMC');
graphNodeClickID.value = 'OMC'; graphNodeClickID.value = 'OMC';
} }
let sysMemUsage = 0; // console.log(info.id);
// console.log(info.neState.cpu.nfCpuUsage);
// console.log(info.neState.cpu.sysCpuUsage);
// console.log(info.neState.mem.sysMemUsage);
let sysCpuUsage = 0; let sysCpuUsage = 0;
let nfCpuUsage = 0; let nfCpuUsage = 0;
if (info.neState.cpu) { if (info.neState.cpu) {
nfCpuUsage = info.neState.cpu.nfCpuUsage; nfCpuUsage = info.neState.cpu.nfCpuUsage;
if (nfCpuUsage > 1000) { if (nfCpuUsage > 100) {
nfCpuUsage = +(info.neState.cpu.nfCpuUsage / 100).toFixed(2); nfCpuUsage = +(info.neState.cpu.nfCpuUsage / 100).toFixed(2);
} }
sysCpuUsage = info.neState.cpu.sysCpuUsage; sysCpuUsage = info.neState.cpu.sysCpuUsage;
if (nfCpuUsage > 1000) { if (sysCpuUsage > 100) {
sysCpuUsage = +(info.neState.cpu.sysCpuUsage / 100).toFixed(2); sysCpuUsage = +(info.neState.cpu.sysCpuUsage / 100).toFixed(2);
} }
} }
let sysMemUsage = 0;
if (info.neState.mem) { if (info.neState.mem) {
let men = info.neState.mem.sysMemUsage; let men = info.neState.mem.sysMemUsage;
if (men > 1000) { if (men > 100) {
men = +(men / 100).toFixed(2); men = +(men / 100).toFixed(2);
} }
sysMemUsage = men; sysMemUsage = men;
} }
function colorStyle(v: number): string { category.value[0].value = sysMemUsage;
let color = '#1890ff'; category.value[1].value = sysCpuUsage;
if (v < 30) { category.value[2].value = nfCpuUsage;
color = '#73d13d';
}
if (v > 60) {
color = '#ff4d4f';
}
return color;
}
neResourcesChart.value.setOption({ neResourcesChart.value.setOption({
series: [ series: [
{ {
data: [ data: category.value,
{
name: '系统内存',
value: sysMemUsage,
itemStyle: {
color: colorStyle(sysMemUsage),
shadowColor: colorStyle(sysMemUsage),
},
},
],
}, },
{ {
data: [ data: category.value,
{
name: '系统CPU',
value: sysCpuUsage,
itemStyle: {
color: colorStyle(sysCpuUsage),
shadowColor: colorStyle(sysCpuUsage),
},
},
],
}, },
{ {
data: [ data: category.value,
{
name: '网元CPU',
value: nfCpuUsage,
itemStyle: {
color: colorStyle(nfCpuUsage),
shadowColor: colorStyle(nfCpuUsage),
},
},
],
}, },
], ],
}); });
@@ -330,43 +297,30 @@ watch(graphNodeClickID, v => {
onMounted(() => { onMounted(() => {
// setInterval(function () { // setInterval(function () {
// var ndata = [
// {
// name: '系统内存',
// value: Math.round(Math.random() * 100),
// },
// {
// name: '系统CPU',
// value: Math.round(Math.random() * 100),
// },
// {
// name: '网元CPU',
// value: Math.round(Math.random() * 100),
// },
// ];
// neResourcesChart.value.setOption({ // neResourcesChart.value.setOption({
// series: [ // series: [
// { // {
// data: [ // data: ndata,
// {
// name: '系统内存',
// value: sysMemUsage,
// itemStyle: {
// color: colorStyle(sysMemUsage),
// shadowColor: colorStyle(sysMemUsage),
// },
// },
// ],
// }, // },
// { // {
// data: [ // data: ndata,
// {
// name: '系统CPU',
// value: sysCpuUsage,
// itemStyle: {
// color: colorStyle(sysCpuUsage),
// shadowColor: colorStyle(sysCpuUsage),
// },
// },
// ],
// }, // },
// { // {
// data: [ // data: ndata,
// {
// name: '网元CPU',
// value: nfCpuUsage,
// itemStyle: {
// color: colorStyle(nfCpuUsage),
// shadowColor: colorStyle(nfCpuUsage),
// },
// },
// ],
// }, // },
// ], // ],
// }); // });

View File

@@ -8,13 +8,13 @@ onMounted(() => {});
</script> </script>
<template> <template>
<div class="cdr" style="display: block"> <div class="ue" style="display: block">
<div class="cdr-head"> <div class="ue-head">
<span class="col">IMSI</span> <span class="col">IMSI</span>
<span class="col">行为</span> <span class="col">行为</span>
<span class="col-w">信息</span> <span class="col-w">信息</span>
</div> </div>
<div class="cdr-marquee-view"> <div class="ue-marquee-view">
<div <div
class="row" class="row"
:class="{ 'row-new': item.id === ueEventId }" :class="{ 'row-new': item.id === ueEventId }"
@@ -30,22 +30,27 @@ onMounted(() => {});
</template> </template>
<style lang="less" scoped> <style lang="less" scoped>
.cdr { .ue {
height: 88%;
&-head { &-head {
background: rgba(255, 255, 255, 0.1); background: rgba(255, 255, 255, 0.1);
font-size: 0.583rem; font-size: 0.583rem;
padding: 0.5rem 1.5rem; padding: 0.5rem 1.5rem;
color: #68d8fe; color: #68d8fe;
display: flex; display: flex;
justify-content: space-between; justify-content: flex-start;
line-height: 1.05; line-height: 1.05;
& .col { & .col {
width: 3.2rem; min-width: 3.2rem;
width: 30%;
margin-right: 1rem;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
&-w { &-w {
width: 8.4rem; min-width: 8.4rem;
width: 60%;
} }
} }
} }
@@ -53,7 +58,7 @@ onMounted(() => {});
&-marquee-view { &-marquee-view {
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto; overflow-y: auto;
height: 70%; height: 92%;
/* 修改滚动条的样式 */ /* 修改滚动条的样式 */
&::-webkit-scrollbar { &::-webkit-scrollbar {
@@ -73,16 +78,18 @@ onMounted(() => {});
} }
& .row { & .row {
line-height: 1.05; line-height: 1.5;
padding: 0.5rem 1.5rem; padding: 0 1.5rem;
color: #61a8ff; color: #61a8ff;
font-size: 0.75rem; font-size: 0.75rem;
position: relative; position: relative;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
cursor: context-menu;
&-new { &-new {
color: #fff; color: #fff;
animation: backInRight 0.3s alternate; animation: backInRight 0.3s alternate;
font-size: 0.95rem;
} }
@keyframes backInRight { @keyframes backInRight {
0% { 0% {
@@ -104,12 +111,18 @@ onMounted(() => {});
} }
} }
& .col { & .col {
width: 3.2rem; min-width: 3.2rem;
width: 30%;
margin-right: 1rem;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
&-w { &-w {
width: 8.4rem; min-width: 8.4rem;
width: 60%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
} }
} }
} }

View File

@@ -9,6 +9,8 @@
padding: 5rem 0.833rem 0; padding: 5rem 0.833rem 0;
line-height: 1.15; line-height: 1.15;
background-color: #101129; background-color: #101129;
height: 100vh;
margin-bottom: -20px;
} }
.column { .column {
@@ -113,8 +115,8 @@
/* 本月告警统计 */ /* 本月告警统计 */
.alarmType { .alarmType {
height: 16rem; min-height: 13rem;
display: flex; height: 25%;
} }
.alarmType .chart { .alarmType .chart {
width: 100%; width: 100%;
@@ -122,13 +124,12 @@
margin-top: 1rem; margin-top: 1rem;
} }
/* cdr会话监控 */
/* 告警趋势 */ .cdrEvent {
.alarmDay { min-height: 22rem;
height: 22rem; height: 60%;
display: flex;
} }
.alarmDay .inner .chart { .cdrEvent .inner .chart {
width: 100%; width: 100%;
height: 100%; height: 100%;
margin-top: 1rem; margin-top: 1rem;
@@ -136,7 +137,8 @@
/* 总流量 */ /* 总流量 */
.totalFlow { .totalFlow {
height: 6.167rem; min-height: 6.167rem;
height: 12%;
} }
.totalFlow .inner .filter { .totalFlow .inner .filter {
display: flex; display: flex;
@@ -179,8 +181,8 @@
/* 资源情况 */ /* 资源情况 */
.resources { .resources {
height: 16rem; min-height: 13rem;
display: flex; height: 25%;
} }
.resources .inner .chart { .resources .inner .chart {
width: 100%; width: 100%;
@@ -188,12 +190,12 @@
margin-top: 1rem; margin-top: 1rem;
} }
/* 会话监控 */ /* ue会话监控 */
.cdr { .ueEvent {
height: 22rem; min-height: 22rem;
display: flex; height: 60%;
} }
.cdr .inner .chart { .ueEvent .inner .chart {
width: 100%; width: 100%;
height: 100%; height: 100%;
margin-top: 1rem; margin-top: 1rem;

View File

@@ -0,0 +1,10 @@
import { ref } from 'vue';
/**事件数据 */
export const cdrEventData = ref<Record<string, any>[]>([]);
/**事件总量 */
export const cdrEventTotal = ref<number>(0);
/**事件推送id */
export const cdrEventId = ref<string>('');

View File

@@ -5,6 +5,7 @@ import {
import { OptionsType, WS } from '@/plugins/ws-websocket'; import { OptionsType, WS } from '@/plugins/ws-websocket';
import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue'; import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue';
import { ueEventData, ueEventId, ueEventTotal } from './useUEEvent'; import { ueEventData, ueEventId, ueEventTotal } from './useUEEvent';
import { cdrEventData, cdrEventTotal, cdrEventId } from './useCDREvent';
/**websocket连接 */ /**websocket连接 */
export default function useWS() { export default function useWS() {
@@ -15,6 +16,36 @@ export default function useWS() {
ws.send(data); ws.send(data);
} }
function wsInitData() {
// cdrEvent CDR会话事件
ws.send({
requestId: '1005',
type: 'cdr',
data: {
neType: 'IMS',
neId: '001',
sortField: 'timestamp',
sortOrder: 'desc',
pageNum: 1,
pageSize: 50,
},
});
// ueEvent UE会话事件
ws.send({
requestId: '1010',
type: 'ue',
data: {
neType: 'AMF',
neId: '001',
sortField: 'timestamp',
sortOrder: 'desc',
pageNum: 1,
pageSize: 50,
},
});
}
/**接收数据后回调 */ /**接收数据后回调 */
function wsMessage(res: Record<string, any>) { function wsMessage(res: Record<string, any>) {
console.log(res); console.log(res);
@@ -42,6 +73,23 @@ export default function useWS() {
} }
} }
break; break;
//cdrEvent CDR会话事件
case '1005':
if (Array.isArray(data.rows)) {
cdrEventTotal.value = data.total;
const evDataArr: Record<string, any>[] = [];
for (const item of data.rows) {
const v = cdrEventParse(item);
if (v) {
evDataArr.push(v);
}
}
cdrEventData.value = evDataArr;
if (evDataArr.length > 0) {
cdrEventId.value = evDataArr[0].id;
}
}
break;
} }
if (!data?.groupId) { if (!data?.groupId) {
@@ -59,30 +107,25 @@ export default function useWS() {
} }
} }
break; break;
// cdrEvent CDR会话事件
case '1005':
if (data.data) {
const v = cdrEventParse(data.data);
if (v) {
cdrEventData.value.unshift(v);
cdrEventId.value = v.id;
}
}
break;
} }
} }
function wsInitData() {
ws.send({
requestId: '1010',
type: 'ue',
data: {
neType: 'AMF',
neId: '001',
sortField: 'timestamp',
sortOrder: 'desc',
pageNum: 1,
pageSize: 50,
},
});
}
/**ueEvent UE会话事件 数据解析 */ /**ueEvent UE会话事件 数据解析 */
function ueEventParse(item: Record<string, any>) { function ueEventParse(item: Record<string, any>) {
let evData: Record<string, any> = item.eventJSON; let evData: Record<string, any> = item.eventJSON;
if (typeof evData === 'string') { if (typeof evData === 'string') {
try { try {
evData = JSON.parse(item.eventJSON); evData = JSON.parse(evData);
} catch (error) { } catch (error) {
console.error(error); console.error(error);
return false; return false;
@@ -120,6 +163,29 @@ export default function useWS() {
} }
} }
/**cdrEvent CDR会话事件 数据解析 */
function cdrEventParse(item: Record<string, any>) {
let evData: Record<string, any> = item.cdrJSON || item.CDR;
if (typeof evData === 'string') {
try {
evData = JSON.parse(evData);
} catch (error) {
console.error(error);
return false;
}
}
if (evData.recordType === 'CALL') {
return {
id: item.id || item.timestamp,
type: evData.recordType,
time: evData.callDuration,
call: evData.callReference,
msg: `${evData.calledParty} -> ${evData.callerParty}`,
};
}
}
/**接收数据后回调 */ /**接收数据后回调 */
function wsError(ev: any) { function wsError(ev: any) {
// 接收数据后回调 // 接收数据后回调
@@ -133,8 +199,9 @@ export default function useWS() {
/**订阅通道组 /**订阅通道组
* *
* UE会话事件-AMF (GroupID:1010) * UE会话事件-AMF (GroupID:1010)
* CDR会话事件-IMS (GroupID:1005)
*/ */
subGroupID: '1010', subGroupID: '1010,1005',
}, },
onmessage: wsMessage, onmessage: wsMessage,
onerror: wsError, onerror: wsError,

View File

@@ -4,6 +4,7 @@ import useI18n from '@/hooks/useI18n';
import Topology from './components/Topology/index.vue'; import Topology from './components/Topology/index.vue';
import NeResources from './components/NeResources/index.vue'; import NeResources from './components/NeResources/index.vue';
import UEEvent from './components/UEEvent/index.vue'; import UEEvent from './components/UEEvent/index.vue';
import CDREvent from './components/CDREvent/index.vue';
import AlarnDayLine from './components/AlarnDayLine/index.vue'; import AlarnDayLine from './components/AlarnDayLine/index.vue';
import AlarnTypeBar from './components/AlarnTypeBar/index.vue'; import AlarnTypeBar from './components/AlarnTypeBar/index.vue';
import UPFFlow from './components/UPFFlow/index.vue'; import UPFFlow from './components/UPFFlow/index.vue';
@@ -136,7 +137,7 @@ onMounted(() => {
</div> </div>
</div> </div>
<!--本月告警统计--> <!--告警统计-->
<div class="alarmType panel"> <div class="alarmType panel">
<div class="inner"> <div class="inner">
<h3>告警统计</h3> <h3>告警统计</h3>
@@ -146,12 +147,14 @@ onMounted(() => {
</div> </div>
</div> </div>
<!-- 告警趋势 --> <!-- CDR会话 -->
<div class="alarmDay panel"> <div class="cdrEvent panel">
<div class="inner"> <div class="inner">
<h3>告警趋势</h3> <h3>
<WhatsAppOutlined style="color: #68d8fe" />&nbsp;&nbsp; CDR会话
</h3>
<div class="chart"> <div class="chart">
<AlarnDayLine /> <CDREvent />
</div> </div>
</div> </div>
</div> </div>
@@ -219,11 +222,11 @@ onMounted(() => {
</div> </div>
</div> </div>
</div> </div>
<!-- 会话监控 --> <!-- UE会话 -->
<div class="cdr panel"> <div class="ueEvent panel">
<div class="inner"> <div class="inner">
<h3> <h3>
<WhatsAppOutlined style="color: #d93f36" />&nbsp;&nbsp; 会话监控 <WhatsAppOutlined style="color: #68d8fe" />&nbsp;&nbsp; UE会话
</h3> </h3>
<div class="chart"> <div class="chart">
<UEEvent /> <UEEvent />