Merge branch 'multi-tenant' of http://192.168.2.166:3180/OMC/ems_frontend_vue3 into multi-tenant
This commit is contained in:
@@ -142,3 +142,20 @@ export async function getbusyhour(query: Record<string, any>) {
|
|||||||
params: query,
|
params: query,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
//MOS指标
|
||||||
|
export async function getMosHour(query: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: '/neData/ims/cdr/mos-hour',
|
||||||
|
method: 'get',
|
||||||
|
params: query,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//CCT指标
|
||||||
|
export async function getCctHour(query: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: '/neData/ims/cdr/cct-hour',
|
||||||
|
method: 'get',
|
||||||
|
params: query,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -124,6 +124,42 @@
|
|||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
|
<a-row :gutter="[16, 16]" style="margin-top: 16px;">
|
||||||
|
<a-col :xs="24" :sm="24" :lg="12">
|
||||||
|
<a-card bordered class="metric-card">
|
||||||
|
<div class="card-title">MOS<span class="main-icon phone">📞</span></div>
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="trend-chart">
|
||||||
|
<div class="mini-chart" ref="mosChartRef"></div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-info">
|
||||||
|
<div class="metric-value">
|
||||||
|
{{ calculateMosValue() }}
|
||||||
|
<span class="main-arrow" :class="calculateMosArrowDirection()">{{ calculateMosArrow() }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="metric-change">{{ calculateMosChange() }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
</a-col>
|
||||||
|
<a-col :xs="24" :sm="24" :lg="12">
|
||||||
|
<a-card bordered class="metric-card">
|
||||||
|
<div class="card-title">CCT<span class="main-icon phone">📞</span></div>
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="trend-chart">
|
||||||
|
<div class="mini-chart" ref="cctChartRef"></div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-info">
|
||||||
|
<div class="metric-value">
|
||||||
|
{{ calculateCctValue() }}
|
||||||
|
<span class="main-arrow" :class="calculateCctArrowDirection()">{{ calculateCctArrow() }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="metric-change">{{ calculateCctChange() }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
<div class="row-title" style="margin-top: 48px;">{{ t('views.perfManage.voiceOverView.registration') }}</div>
|
<div class="row-title" style="margin-top: 48px;">{{ t('views.perfManage.voiceOverView.registration') }}</div>
|
||||||
<a-row :gutter="[16, 16]">
|
<a-row :gutter="[16, 16]">
|
||||||
<a-col :xs="24" :sm="24" :lg="8">
|
<a-col :xs="24" :sm="24" :lg="8">
|
||||||
@@ -183,7 +219,7 @@ import { GridComponent } from 'echarts/components'
|
|||||||
import { CanvasRenderer } from 'echarts/renderers'
|
import { CanvasRenderer } from 'echarts/renderers'
|
||||||
import useNeInfoStore from '@/store/modules/neinfo'
|
import useNeInfoStore from '@/store/modules/neinfo'
|
||||||
import { WS } from '@/plugins/ws-websocket'
|
import { WS } from '@/plugins/ws-websocket'
|
||||||
import { listKPIData ,getbusyhour} from '@/api/perfManage/goldTarget'
|
import { listKPIData ,getbusyhour, getMosHour, getCctHour} from '@/api/perfManage/goldTarget'
|
||||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants'
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants'
|
||||||
import useI18n from '@/hooks/useI18n';
|
import useI18n from '@/hooks/useI18n';
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
@@ -194,6 +230,7 @@ const mosChartRef = ref<HTMLDivElement | null>(null)
|
|||||||
const failedCallsChartRef = ref<HTMLDivElement | null>(null)
|
const failedCallsChartRef = ref<HTMLDivElement | null>(null)
|
||||||
const callAttemptsChartRef = ref<HTMLDivElement | null>(null)
|
const callAttemptsChartRef = ref<HTMLDivElement | null>(null)
|
||||||
const callCompletionsChartRef = ref<HTMLDivElement | null>(null)
|
const callCompletionsChartRef = ref<HTMLDivElement | null>(null)
|
||||||
|
const cctChartRef = ref<HTMLDivElement | null>(null)
|
||||||
const regChartRef = ref<HTMLDivElement | null>(null)
|
const regChartRef = ref<HTMLDivElement | null>(null)
|
||||||
const failedRegChartRef = ref<HTMLDivElement | null>(null)
|
const failedRegChartRef = ref<HTMLDivElement | null>(null)
|
||||||
|
|
||||||
@@ -207,6 +244,10 @@ const imsWs = ref<any>(null)
|
|||||||
const imsRealtimeRawData = ref<any[]>([])
|
const imsRealtimeRawData = ref<any[]>([])
|
||||||
// Busy Hour数据(用于Call Attempts和Call Completions)
|
// Busy Hour数据(用于Call Attempts和Call Completions)
|
||||||
const busyHourData = ref<any>(null)
|
const busyHourData = ref<any>(null)
|
||||||
|
// MOS数据
|
||||||
|
const mosData = ref<any>(null)
|
||||||
|
// CCT数据
|
||||||
|
const cctData = ref<any>(null)
|
||||||
// WebSocket连接状态
|
// WebSocket连接状态
|
||||||
const wsStatus = ref('no connection')
|
const wsStatus = ref('no connection')
|
||||||
|
|
||||||
@@ -228,6 +269,8 @@ onMounted(async () => {
|
|||||||
// 先获取历史数据和Busy Hour数据,再订阅实时数据
|
// 先获取历史数据和Busy Hour数据,再订阅实时数据
|
||||||
await fetchHistoryData(selectedImsNeId.value)
|
await fetchHistoryData(selectedImsNeId.value)
|
||||||
await fetchBusyHourData(selectedImsNeId.value)
|
await fetchBusyHourData(selectedImsNeId.value)
|
||||||
|
await fetchMosData(selectedImsNeId.value)
|
||||||
|
await fetchCctData(selectedImsNeId.value)
|
||||||
subscribeImsRealtime(selectedImsNeId.value)
|
subscribeImsRealtime(selectedImsNeId.value)
|
||||||
} else {
|
} else {
|
||||||
// console.warn('没有找到IMS类型的网元') // 调试信息
|
// console.warn('没有找到IMS类型的网元') // 调试信息
|
||||||
@@ -331,6 +374,80 @@ async function fetchBusyHourData(neId: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取MOS数据
|
||||||
|
async function fetchMosData(neId: string) {
|
||||||
|
if (!neId) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 获取当天日期的时间戳
|
||||||
|
const today = new Date()
|
||||||
|
today.setHours(0, 0, 0, 0) // 设置为当天00:00:00
|
||||||
|
const timestamp = today.getTime()
|
||||||
|
|
||||||
|
// 构建请求参数
|
||||||
|
const params = {
|
||||||
|
neId: neId,
|
||||||
|
timestamp: timestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('获取MOS数据参数:', params)
|
||||||
|
|
||||||
|
const res = await getMosHour(params)
|
||||||
|
console.log('MOS数据响应:', res)
|
||||||
|
|
||||||
|
if (res.code === 1 && Array.isArray(res.data)) {
|
||||||
|
mosData.value = res.data
|
||||||
|
console.log('MOS数据加载完成:', mosData.value)
|
||||||
|
|
||||||
|
// 更新MOS图表
|
||||||
|
updateMosChart()
|
||||||
|
} else {
|
||||||
|
console.warn('获取MOS数据失败或数据为空')
|
||||||
|
mosData.value = null
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取MOS数据出错:', error)
|
||||||
|
mosData.value = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取CCT数据
|
||||||
|
async function fetchCctData(neId: string) {
|
||||||
|
if (!neId) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 获取当天日期的时间戳
|
||||||
|
const today = new Date()
|
||||||
|
today.setHours(0, 0, 0, 0) // 设置为当天00:00:00
|
||||||
|
const timestamp = today.getTime()
|
||||||
|
|
||||||
|
// 构建请求参数
|
||||||
|
const params = {
|
||||||
|
neId: neId,
|
||||||
|
timestamp: timestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('获取CCT数据参数:', params)
|
||||||
|
|
||||||
|
const res = await getCctHour(params)
|
||||||
|
console.log('CCT数据响应:', res)
|
||||||
|
|
||||||
|
if (res.code === 1 && Array.isArray(res.data)) {
|
||||||
|
cctData.value = res.data
|
||||||
|
console.log('CCT数据加载完成:', cctData.value)
|
||||||
|
|
||||||
|
// 更新CCT图表
|
||||||
|
updateCctChart()
|
||||||
|
} else {
|
||||||
|
console.warn('获取CCT数据失败或数据为空')
|
||||||
|
cctData.value = null
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取CCT数据出错:', error)
|
||||||
|
cctData.value = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 切换IMS网元时,重新订阅
|
// 切换IMS网元时,重新订阅
|
||||||
async function onImsNeChange() {
|
async function onImsNeChange() {
|
||||||
// console.log('切换IMS网元,新的网元ID:', selectedImsNeId.value) // 调试信息
|
// console.log('切换IMS网元,新的网元ID:', selectedImsNeId.value) // 调试信息
|
||||||
@@ -350,6 +467,8 @@ async function onImsNeChange() {
|
|||||||
// 先获取历史数据和Busy Hour数据,再订阅实时数据
|
// 先获取历史数据和Busy Hour数据,再订阅实时数据
|
||||||
await fetchHistoryData(selectedImsNeId.value)
|
await fetchHistoryData(selectedImsNeId.value)
|
||||||
await fetchBusyHourData(selectedImsNeId.value)
|
await fetchBusyHourData(selectedImsNeId.value)
|
||||||
|
await fetchMosData(selectedImsNeId.value)
|
||||||
|
await fetchCctData(selectedImsNeId.value)
|
||||||
subscribeImsRealtime(selectedImsNeId.value)
|
subscribeImsRealtime(selectedImsNeId.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1088,8 +1207,8 @@ function updateCallAttemptsChart() {
|
|||||||
chart = echarts.init(callAttemptsChartRef.value)
|
chart = echarts.init(callAttemptsChartRef.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果没有Busy Hour数据,显示默认的平直线
|
// 如果没有Busy Hour数据或数据为空数组,显示默认的平直线
|
||||||
if (!busyHourData.value) {
|
if (!busyHourData.value || busyHourData.value.length === 0) {
|
||||||
const defaultData = [0, 0, 0, 0, 0] // 5个默认数据点,值为0
|
const defaultData = [0, 0, 0, 0, 0] // 5个默认数据点,值为0
|
||||||
const xAxisData = [1, 2, 3, 4, 5]
|
const xAxisData = [1, 2, 3, 4, 5]
|
||||||
|
|
||||||
@@ -1235,8 +1354,8 @@ function updateCallCompletionsChart() {
|
|||||||
chart = echarts.init(callCompletionsChartRef.value)
|
chart = echarts.init(callCompletionsChartRef.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果没有Busy Hour数据,显示默认的平直线
|
// 如果没有Busy Hour数据或数据为空数组,显示默认的平直线
|
||||||
if (!busyHourData.value) {
|
if (!busyHourData.value || busyHourData.value.length === 0) {
|
||||||
const defaultData = [0, 0, 0, 0, 0] // 5个默认数据点,值为0
|
const defaultData = [0, 0, 0, 0, 0] // 5个默认数据点,值为0
|
||||||
const xAxisData = [1, 2, 3, 4, 5]
|
const xAxisData = [1, 2, 3, 4, 5]
|
||||||
|
|
||||||
@@ -1372,6 +1491,300 @@ function updateCallCompletionsChart() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 更新MOS图表
|
||||||
|
function updateMosChart() {
|
||||||
|
if (!mosChartRef.value) return
|
||||||
|
|
||||||
|
// 获取图表实例
|
||||||
|
let chart = echarts.getInstanceByDom(mosChartRef.value)
|
||||||
|
if (!chart) {
|
||||||
|
chart = echarts.init(mosChartRef.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有MOS数据或数据为空数组,显示默认的平直线
|
||||||
|
if (!mosData.value || mosData.value.length === 0) {
|
||||||
|
const defaultData = [0, 0, 0, 0, 0] // 5个默认数据点,值为0
|
||||||
|
const xAxisData = [1, 2, 3, 4, 5]
|
||||||
|
|
||||||
|
chart.setOption({
|
||||||
|
grid: { left: 0, right: 30, top: 10, bottom: 10 },
|
||||||
|
xAxis: { type: 'category', show: false, data: xAxisData },
|
||||||
|
yAxis: { type: 'value', show: false },
|
||||||
|
series: [{
|
||||||
|
data: defaultData,
|
||||||
|
type: 'line', symbol: 'none',
|
||||||
|
lineStyle: { width: 2, color: '#d9d9d9' },
|
||||||
|
areaStyle: { color: 'rgba(217,217,217,0.1)' }
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
|
||||||
|
// 清除所有旧标注
|
||||||
|
const chartContainer = mosChartRef.value
|
||||||
|
if (chartContainer) {
|
||||||
|
const existingLabels = chartContainer.querySelectorAll('.chart-label')
|
||||||
|
existingLabels.forEach(label => label.remove())
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从MOS数据中提取MOS值
|
||||||
|
const chartData = mosData.value.map((item: any) => Number(item.mosAverage) || 0)
|
||||||
|
|
||||||
|
// 生成时间轴数据
|
||||||
|
const xAxisData = Array.from({ length: chartData.length }, (_, i) => i + 1)
|
||||||
|
|
||||||
|
// 计算最大值、最小值、最新值
|
||||||
|
const maxValue = Math.max(...chartData)
|
||||||
|
const minValue = Math.min(...chartData)
|
||||||
|
const latestValue = chartData[chartData.length - 1]
|
||||||
|
|
||||||
|
chart.setOption({
|
||||||
|
grid: { left: 0, right: 30, top: 10, bottom: 10 },
|
||||||
|
xAxis: { type: 'category', show: false, data: xAxisData },
|
||||||
|
yAxis: { type: 'value', show: false },
|
||||||
|
series: [{
|
||||||
|
data: chartData,
|
||||||
|
type: 'line', symbol: 'none',
|
||||||
|
lineStyle: { width: 2, color: '#52c41a' }, // 绿色线条
|
||||||
|
areaStyle: { color: 'rgba(82,196,26,0.1)' } // 淡绿色填充
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
|
||||||
|
// 在图表容器中添加数值标注
|
||||||
|
const chartContainer = mosChartRef.value
|
||||||
|
if (chartContainer) {
|
||||||
|
// 清除之前的标注
|
||||||
|
const existingLabels = chartContainer.querySelectorAll('.chart-label')
|
||||||
|
existingLabels.forEach(label => label.remove())
|
||||||
|
|
||||||
|
// 添加右侧数值标注
|
||||||
|
const maxLabel = document.createElement('div')
|
||||||
|
maxLabel.className = 'chart-label'
|
||||||
|
maxLabel.style.cssText = `
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
top: 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #666;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 10;
|
||||||
|
`
|
||||||
|
maxLabel.textContent = maxValue.toFixed(2)
|
||||||
|
|
||||||
|
const latestLabel = document.createElement('div')
|
||||||
|
latestLabel.className = 'chart-label'
|
||||||
|
latestLabel.style.cssText = `
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #52c41a;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 10;
|
||||||
|
`
|
||||||
|
latestLabel.textContent = latestValue.toFixed(2)
|
||||||
|
|
||||||
|
const minLabel = document.createElement('div')
|
||||||
|
minLabel.className = 'chart-label'
|
||||||
|
minLabel.style.cssText = `
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
bottom: 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #666;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 10;
|
||||||
|
`
|
||||||
|
minLabel.textContent = minValue.toFixed(2)
|
||||||
|
|
||||||
|
// 添加底部时间标注
|
||||||
|
const oldestTimeLabel = document.createElement('div')
|
||||||
|
oldestTimeLabel.className = 'chart-label'
|
||||||
|
oldestTimeLabel.style.cssText = `
|
||||||
|
position: absolute;
|
||||||
|
left: 8px;
|
||||||
|
bottom: -20px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #999;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 10;
|
||||||
|
`
|
||||||
|
// 使用第一个数据点的时间戳计算相对时间
|
||||||
|
const oldestTime = Number(mosData.value[0]?.timeGroup) || Date.now()
|
||||||
|
oldestTimeLabel.textContent = calculateRelativeTime(oldestTime)
|
||||||
|
|
||||||
|
const nowTimeLabel = document.createElement('div')
|
||||||
|
nowTimeLabel.className = 'chart-label'
|
||||||
|
nowTimeLabel.style.cssText = `
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
bottom: -20px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #999;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 10;
|
||||||
|
`
|
||||||
|
nowTimeLabel.textContent = t('views.perfManage.voiceOverView.now')
|
||||||
|
|
||||||
|
chartContainer.appendChild(maxLabel)
|
||||||
|
chartContainer.appendChild(latestLabel)
|
||||||
|
chartContainer.appendChild(minLabel)
|
||||||
|
chartContainer.appendChild(oldestTimeLabel)
|
||||||
|
chartContainer.appendChild(nowTimeLabel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新CCT图表
|
||||||
|
function updateCctChart() {
|
||||||
|
if (!cctChartRef.value) return
|
||||||
|
|
||||||
|
// 获取图表实例
|
||||||
|
let chart = echarts.getInstanceByDom(cctChartRef.value)
|
||||||
|
if (!chart) {
|
||||||
|
chart = echarts.init(cctChartRef.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有CCT数据或数据为空数组,显示默认的平直线
|
||||||
|
if (!cctData.value || cctData.value.length === 0) {
|
||||||
|
const defaultData = [0, 0, 0, 0, 0] // 5个默认数据点,值为0
|
||||||
|
const xAxisData = [1, 2, 3, 4, 5]
|
||||||
|
|
||||||
|
chart.setOption({
|
||||||
|
grid: { left: 0, right: 30, top: 10, bottom: 10 },
|
||||||
|
xAxis: { type: 'category', show: false, data: xAxisData },
|
||||||
|
yAxis: { type: 'value', show: false },
|
||||||
|
series: [{
|
||||||
|
data: defaultData,
|
||||||
|
type: 'line', symbol: 'none',
|
||||||
|
lineStyle: { width: 2, color: '#d9d9d9' },
|
||||||
|
areaStyle: { color: 'rgba(217,217,217,0.1)' }
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
|
||||||
|
// 清除所有旧标注
|
||||||
|
const chartContainer = cctChartRef.value
|
||||||
|
if (chartContainer) {
|
||||||
|
const existingLabels = chartContainer.querySelectorAll('.chart-label')
|
||||||
|
existingLabels.forEach(label => label.remove())
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从CCT数据中提取CCT值
|
||||||
|
const chartData = cctData.value.map((item: any) => Number(item.callConnectionTime) || 0)
|
||||||
|
|
||||||
|
// 生成时间轴数据
|
||||||
|
const xAxisData = Array.from({ length: chartData.length }, (_, i) => i + 1)
|
||||||
|
|
||||||
|
// 计算最大值、最小值、最新值
|
||||||
|
const maxValue = Math.max(...chartData)
|
||||||
|
const minValue = Math.min(...chartData)
|
||||||
|
const latestValue = chartData[chartData.length - 1]
|
||||||
|
|
||||||
|
chart.setOption({
|
||||||
|
grid: { left: 0, right: 30, top: 10, bottom: 10 },
|
||||||
|
xAxis: { type: 'category', show: false, data: xAxisData },
|
||||||
|
yAxis: { type: 'value', show: false },
|
||||||
|
series: [{
|
||||||
|
data: chartData,
|
||||||
|
type: 'line', symbol: 'none',
|
||||||
|
lineStyle: { width: 2, color: '#fa8c16' }, // 橙色线条
|
||||||
|
areaStyle: { color: 'rgba(250,140,22,0.1)' } // 淡橙色填充
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
|
||||||
|
// 在图表容器中添加数值标注
|
||||||
|
const chartContainer = cctChartRef.value
|
||||||
|
if (chartContainer) {
|
||||||
|
// 清除之前的标注
|
||||||
|
const existingLabels = chartContainer.querySelectorAll('.chart-label')
|
||||||
|
existingLabels.forEach(label => label.remove())
|
||||||
|
|
||||||
|
// 添加右侧数值标注
|
||||||
|
const maxLabel = document.createElement('div')
|
||||||
|
maxLabel.className = 'chart-label'
|
||||||
|
maxLabel.style.cssText = `
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
top: 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #666;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 10;
|
||||||
|
`
|
||||||
|
maxLabel.textContent = maxValue.toFixed(2)
|
||||||
|
|
||||||
|
const latestLabel = document.createElement('div')
|
||||||
|
latestLabel.className = 'chart-label'
|
||||||
|
latestLabel.style.cssText = `
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #fa8c16;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 10;
|
||||||
|
`
|
||||||
|
latestLabel.textContent = latestValue.toFixed(2)
|
||||||
|
|
||||||
|
const minLabel = document.createElement('div')
|
||||||
|
minLabel.className = 'chart-label'
|
||||||
|
minLabel.style.cssText = `
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
bottom: 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #666;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 10;
|
||||||
|
`
|
||||||
|
minLabel.textContent = minValue.toFixed(2)
|
||||||
|
|
||||||
|
// 添加底部时间标注
|
||||||
|
const oldestTimeLabel = document.createElement('div')
|
||||||
|
oldestTimeLabel.className = 'chart-label'
|
||||||
|
oldestTimeLabel.style.cssText = `
|
||||||
|
position: absolute;
|
||||||
|
left: 8px;
|
||||||
|
bottom: -20px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #999;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 10;
|
||||||
|
`
|
||||||
|
// 使用第一个数据点的时间戳计算相对时间
|
||||||
|
const oldestTime = Number(cctData.value[0]?.timeGroup) || Date.now()
|
||||||
|
oldestTimeLabel.textContent = calculateRelativeTime(oldestTime)
|
||||||
|
|
||||||
|
const nowTimeLabel = document.createElement('div')
|
||||||
|
nowTimeLabel.className = 'chart-label'
|
||||||
|
nowTimeLabel.style.cssText = `
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
bottom: -20px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #999;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 10;
|
||||||
|
`
|
||||||
|
nowTimeLabel.textContent = t('views.perfManage.voiceOverView.now')
|
||||||
|
|
||||||
|
chartContainer.appendChild(maxLabel)
|
||||||
|
chartContainer.appendChild(latestLabel)
|
||||||
|
chartContainer.appendChild(minLabel)
|
||||||
|
chartContainer.appendChild(oldestTimeLabel)
|
||||||
|
chartContainer.appendChild(nowTimeLabel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 处理IMS实时数据(只存储当前选中网元)
|
// 处理IMS实时数据(只存储当前选中网元)
|
||||||
function handleIMSRealtimeData(res: any) {
|
function handleIMSRealtimeData(res: any) {
|
||||||
//console.log('收到实时数据:', res) // 调试信息
|
//console.log('收到实时数据:', res) // 调试信息
|
||||||
@@ -1549,6 +1962,18 @@ onMounted(() => {
|
|||||||
const chart = echarts.init(failedRegChartRef.value)
|
const chart = echarts.init(failedRegChartRef.value)
|
||||||
chart.setOption(defaultChartOption)
|
chart.setOption(defaultChartOption)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MOS
|
||||||
|
if (mosChartRef.value) {
|
||||||
|
const chart = echarts.init(mosChartRef.value)
|
||||||
|
chart.setOption(defaultChartOption)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CCT
|
||||||
|
if (cctChartRef.value) {
|
||||||
|
const chart = echarts.init(cctChartRef.value)
|
||||||
|
chart.setOption(defaultChartOption)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 计算MO值 (SCSCF.05/SCSCF.06)*100
|
// 计算MO值 (SCSCF.05/SCSCF.06)*100
|
||||||
@@ -2273,6 +2698,100 @@ function calculateCallCompletionsChange() {
|
|||||||
return `${changeText} ` + t('views.perfManage.voiceOverView.last') + ' 1h'
|
return `${changeText} ` + t('views.perfManage.voiceOverView.last') + ' 1h'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MOS相关计算函数
|
||||||
|
function calculateMosValue() {
|
||||||
|
if (!mosData.value || mosData.value.length === 0) return '-'
|
||||||
|
|
||||||
|
// 获取最新的MOS值(数组最后一个元素)
|
||||||
|
const latestData = mosData.value[mosData.value.length - 1]
|
||||||
|
const mosValue = Number(latestData.mosAverage) || 0
|
||||||
|
return mosValue.toFixed(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateMosArrowDirection() {
|
||||||
|
if (!mosData.value || mosData.value.length < 2) return 'up'
|
||||||
|
|
||||||
|
const latestValue = Number(mosData.value[mosData.value.length - 1].mosAverage) || 0
|
||||||
|
const previousValue = Number(mosData.value[mosData.value.length - 2].mosAverage) || 0
|
||||||
|
|
||||||
|
const change = latestValue - previousValue
|
||||||
|
if (change > 0) return 'up'
|
||||||
|
if (change < 0) return 'down'
|
||||||
|
return 'up'
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateMosArrow() {
|
||||||
|
if (!mosData.value || mosData.value.length < 2) return '→'
|
||||||
|
|
||||||
|
const latestValue = Number(mosData.value[mosData.value.length - 1].mosAverage) || 0
|
||||||
|
const previousValue = Number(mosData.value[mosData.value.length - 2].mosAverage) || 0
|
||||||
|
|
||||||
|
const change = latestValue - previousValue
|
||||||
|
if (change > 0) return '↗'
|
||||||
|
if (change < 0) return '↘'
|
||||||
|
return '→'
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateMosChange() {
|
||||||
|
if (!mosData.value || mosData.value.length < 2) return '±0.00 ' + t('views.perfManage.voiceOverView.last') + ' 1h'
|
||||||
|
|
||||||
|
const latestValue = Number(mosData.value[mosData.value.length - 1].mosAverage) || 0
|
||||||
|
const previousValue = Number(mosData.value[mosData.value.length - 2].mosAverage) || 0
|
||||||
|
|
||||||
|
const change = latestValue - previousValue
|
||||||
|
if (change === 0) return '±0.00 ' + t('views.perfManage.voiceOverView.last') + ' 1h'
|
||||||
|
|
||||||
|
const changeText = change > 0 ? `+${change.toFixed(2)}` : `${change.toFixed(2)}`
|
||||||
|
return `${changeText} ` + t('views.perfManage.voiceOverView.last') + ' 1h'
|
||||||
|
}
|
||||||
|
|
||||||
|
// CCT相关计算函数
|
||||||
|
function calculateCctValue() {
|
||||||
|
if (!cctData.value || cctData.value.length === 0) return '-'
|
||||||
|
|
||||||
|
// 获取最新的CCT值(数组最后一个元素)
|
||||||
|
const latestData = cctData.value[cctData.value.length - 1]
|
||||||
|
const cctValue = Number(latestData.callConnectionTime) || 0
|
||||||
|
return cctValue.toFixed(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateCctArrowDirection() {
|
||||||
|
if (!cctData.value || cctData.value.length < 2) return 'up'
|
||||||
|
|
||||||
|
const latestValue = Number(cctData.value[cctData.value.length - 1].callConnectionTime) || 0
|
||||||
|
const previousValue = Number(cctData.value[cctData.value.length - 2].callConnectionTime) || 0
|
||||||
|
|
||||||
|
const change = latestValue - previousValue
|
||||||
|
if (change > 0) return 'up'
|
||||||
|
if (change < 0) return 'down'
|
||||||
|
return 'up'
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateCctArrow() {
|
||||||
|
if (!cctData.value || cctData.value.length < 2) return '→'
|
||||||
|
|
||||||
|
const latestValue = Number(cctData.value[cctData.value.length - 1].callConnectionTime) || 0
|
||||||
|
const previousValue = Number(cctData.value[cctData.value.length - 2].callConnectionTime) || 0
|
||||||
|
|
||||||
|
const change = latestValue - previousValue
|
||||||
|
if (change > 0) return '↗'
|
||||||
|
if (change < 0) return '↘'
|
||||||
|
return '→'
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateCctChange() {
|
||||||
|
if (!cctData.value || cctData.value.length < 2) return '±0.00 ' + t('views.perfManage.voiceOverView.last') + ' 1h'
|
||||||
|
|
||||||
|
const latestValue = Number(cctData.value[cctData.value.length - 1].callConnectionTime) || 0
|
||||||
|
const previousValue = Number(cctData.value[cctData.value.length - 2].callConnectionTime) || 0
|
||||||
|
|
||||||
|
const change = latestValue - previousValue
|
||||||
|
if (change === 0) return '±0.00 ' + t('views.perfManage.voiceOverView.last') + ' 1h'
|
||||||
|
|
||||||
|
const changeText = change > 0 ? `+${change.toFixed(2)}` : `${change.toFixed(2)}`
|
||||||
|
return `${changeText} ` + t('views.perfManage.voiceOverView.last') + ' 1h'
|
||||||
|
}
|
||||||
|
|
||||||
// 测试数据更新
|
// 测试数据更新
|
||||||
// function testDataUpdate() {
|
// function testDataUpdate() {
|
||||||
// console.log('测试数据更新')
|
// console.log('测试数据更新')
|
||||||
|
|||||||
Reference in New Issue
Block a user