fix:仪表盘数据对接修改
This commit is contained in:
@@ -95,7 +95,7 @@ export function doGetCheckCode() {
|
|||||||
/** Get dashboard gauge data */
|
/** Get dashboard gauge data */
|
||||||
export function fetchDashboardData() {
|
export function fetchDashboardData() {
|
||||||
return request<Api.Dashboard.GaugeData>({
|
return request<Api.Dashboard.GaugeData>({
|
||||||
url: '/u/cdr/getOne',
|
url: '/u/account/dashboard',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
22
src/typings/api.d.ts
vendored
22
src/typings/api.d.ts
vendored
@@ -443,18 +443,18 @@ declare namespace Api {
|
|||||||
namespace Dashboard {
|
namespace Dashboard {
|
||||||
/** Dashboard gauge data */
|
/** Dashboard gauge data */
|
||||||
interface GaugeData {
|
interface GaugeData {
|
||||||
/** Remaining credit amount */
|
/** Balance amount */
|
||||||
remainingCredit: number;
|
balance: number;
|
||||||
/** Used credit amount */
|
/** Total traffic amount (bytes) */
|
||||||
usedCredit: number;
|
traffic: number;
|
||||||
/** Remaining flow amount (MB) */
|
/** Used traffic amount (bytes) */
|
||||||
remainingFlow: number;
|
trafficUsed: number;
|
||||||
/** Used flow amount (MB) */
|
/** Current traffic rate (B/s) */
|
||||||
usedFlow: number;
|
activity: number;
|
||||||
/** Current traffic rate (MB/s) */
|
/** Peak traffic rate (B/s) */
|
||||||
trafficRate: number;
|
|
||||||
/** Peak traffic rate (MB/s) */
|
|
||||||
peakTrafficRate: number;
|
peakTrafficRate: number;
|
||||||
|
/** Number of connected devices */
|
||||||
|
clientNum: number;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ defineOptions({
|
|||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
|
|
||||||
interface GaugeData {
|
// 本地界面显示用的数据类型
|
||||||
|
interface GaugeDisplayData {
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
value: number;
|
value: number;
|
||||||
@@ -24,25 +25,61 @@ interface GaugeData {
|
|||||||
description?: string;
|
description?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加速率单位转换函数
|
||||||
|
const formatSpeed = (speedBps: number): { value: number; unit: string } => {
|
||||||
|
// 处理 0 值、undefined 或 null 的情况
|
||||||
|
if (!speedBps || speedBps === 0) {
|
||||||
|
return { value: 0, unit: 'B/s' };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (speedBps < 1024) {
|
||||||
|
return { value: Number(speedBps.toFixed(2)), unit: 'B/s' };
|
||||||
|
} else if (speedBps < 1024 * 1024) {
|
||||||
|
return { value: Number((speedBps / 1024).toFixed(2)), unit: 'KB/s' };
|
||||||
|
} else if (speedBps < 1024 * 1024 * 1024) {
|
||||||
|
return { value: Number((speedBps / (1024 * 1024)).toFixed(2)), unit: 'MB/s' };
|
||||||
|
} else {
|
||||||
|
return { value: Number((speedBps / (1024 * 1024 * 1024)).toFixed(2)), unit: 'GB/s' };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加流量单位转换函数
|
||||||
|
const formatTraffic = (bytes: number): { value: number; unit: string } => {
|
||||||
|
// 处理 0 值、undefined 或 null 的情况
|
||||||
|
if (!bytes || bytes === 0) {
|
||||||
|
return { value: 0, unit: 'B' };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes < 1024) {
|
||||||
|
return { value: Number(bytes.toFixed(2)), unit: 'B' };
|
||||||
|
} else if (bytes < 1024 * 1024) {
|
||||||
|
return { value: Number((bytes / 1024).toFixed(2)), unit: 'KB' };
|
||||||
|
} else if (bytes < 1024 * 1024 * 1024) {
|
||||||
|
return { value: Number((bytes / (1024 * 1024)).toFixed(2)), unit: 'MB' };
|
||||||
|
} else {
|
||||||
|
return { value: Number((bytes / (1024 * 1024 * 1024)).toFixed(2)), unit: 'GB' };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 使用 ref 来存储基础数据
|
// 使用 ref 来存储基础数据
|
||||||
const baseData = ref([
|
const baseData = ref<GaugeDisplayData[]>([
|
||||||
{
|
{
|
||||||
id: 0,
|
id: 0,
|
||||||
title: t('page.headerbanner.Remainingcredit'),
|
title: t('page.headerbanner.Remainingcredit'),
|
||||||
value: 23,
|
value: 0,
|
||||||
max: 100,
|
max: 100,
|
||||||
unit: '元',
|
unit: '元',
|
||||||
description: t('page.headerbanner.monthphonebill'),
|
description: t('page.headerbanner.monthphonebill'),
|
||||||
subTitle: t('page.headerbanner.Used')+'77元'
|
subTitle: t('page.headerbanner.deviceCount') + ': 0台'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
title: t('page.headerbanner.Flowremaining'),
|
title: t('page.headerbanner.Flowremaining'),
|
||||||
value: 890,
|
value: 0,
|
||||||
max: 1024,
|
max: 1024,
|
||||||
unit: 'MB',
|
unit: 'B',
|
||||||
description: t('page.headerbanner.monthflowr'),
|
description: t('page.headerbanner.monthflowr'),
|
||||||
subTitle: t('page.headerbanner.Used')+'134MB'
|
subTitle: t('page.headerbanner.Used') + ': 0B'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
@@ -59,7 +96,7 @@ const baseData = ref([
|
|||||||
const gaugeData = computed(() => baseData.value);
|
const gaugeData = computed(() => baseData.value);
|
||||||
|
|
||||||
// 仪盘配置生成函数
|
// 仪盘配置生成函数
|
||||||
const getGaugeOptions = (data: GaugeData): ECOption => ({
|
const getGaugeOptions = (data: GaugeDisplayData): ECOption => ({
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: 'transparent',
|
||||||
series: [{
|
series: [{
|
||||||
name: data.title,
|
name: data.title,
|
||||||
@@ -134,7 +171,7 @@ const { domRef: gauge3Ref, updateOptions: updateGauge3 } = useEcharts(() => getG
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 更新单个图表的数据
|
// 更新单个图表的数据
|
||||||
const updateGaugeData = (opts: ECOption, data: GaugeData) => {
|
const updateGaugeData = (opts: ECOption, data: GaugeDisplayData) => {
|
||||||
if (!opts.series || !Array.isArray(opts.series)) {
|
if (!opts.series || !Array.isArray(opts.series)) {
|
||||||
opts.series = [{
|
opts.series = [{
|
||||||
name: data.title,
|
name: data.title,
|
||||||
@@ -191,62 +228,74 @@ const updateGaugeData = (opts: ECOption, data: GaugeData) => {
|
|||||||
return opts;
|
return opts;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 更新图表数据
|
// 添加峰值速率的 ref
|
||||||
async function mockData() {
|
const peakTrafficRate = ref(0);
|
||||||
updateGauge1(opts => updateGaugeData(opts, gaugeData.value[0]));
|
|
||||||
updateGauge2(opts => updateGaugeData(opts, gaugeData.value[1]));
|
|
||||||
updateGauge3(opts => updateGaugeData(opts, gaugeData.value[2]));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新语言
|
|
||||||
function updateLocale() {
|
|
||||||
updateGauge1((opts) => updateGaugeData(opts, gaugeData.value[0]));
|
|
||||||
updateGauge2((opts) => updateGaugeData(opts, gaugeData.value[1]));
|
|
||||||
updateGauge3((opts) => updateGaugeData(opts, gaugeData.value[2]));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加速度格式化函数
|
|
||||||
function formatSpeed(bytesPerSecond: number): { value: number; unit: string } {
|
|
||||||
// 处理 0 值、undefined 或 null 的情况
|
|
||||||
if (!bytesPerSecond || bytesPerSecond === 0) {
|
|
||||||
return { value: 0, unit: 'B/s' };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bytesPerSecond < 1024) {
|
|
||||||
return { value: Number(bytesPerSecond.toFixed(2)), unit: 'B/s' };
|
|
||||||
} else if (bytesPerSecond < 1024 * 1024) {
|
|
||||||
return { value: Number((bytesPerSecond / 1024).toFixed(2)), unit: 'KB/s' };
|
|
||||||
} else if (bytesPerSecond < 1024 * 1024 * 1024) {
|
|
||||||
return { value: Number((bytesPerSecond / (1024 * 1024)).toFixed(2)), unit: 'MB/s' };
|
|
||||||
} else {
|
|
||||||
return { value: Number((bytesPerSecond / (1024 * 1024 * 1024)).toFixed(2)), unit: 'GB/s' };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修改 mockDataUpdate 函数
|
// 修改 mockDataUpdate 函数
|
||||||
async function mockDataUpdate() {
|
async function mockDataUpdate() {
|
||||||
// 获取实际数据
|
try {
|
||||||
const data = await authStore.getDashboardData();
|
const response = await authStore.getDashboardData();
|
||||||
if (data) {
|
if (response) {
|
||||||
// 更新话费数据
|
// 更新余额和设备数据
|
||||||
baseData.value[0] = {
|
baseData.value[0] = {
|
||||||
...baseData.value[0],
|
...baseData.value[0],
|
||||||
value: data.remainingCredit,
|
value: response.balance,
|
||||||
subTitle: t('page.headerbanner.Used') + `: ${data.usedCredit}元`
|
max: Math.max(response.balance, 100),
|
||||||
|
subTitle: t('page.headerbanner.deviceCount') + `: ${response.clientNum}台`
|
||||||
};
|
};
|
||||||
|
|
||||||
// 更新流量数据
|
// 先计算剩余流量(字节单位)
|
||||||
|
const totalTraffic = response.traffic; // 总流量(字节)
|
||||||
|
const usedTraffic = response.trafficUsed; // 已用流量(字节)
|
||||||
|
|
||||||
|
// 计算剩余流量,确保不会出现负数
|
||||||
|
const remainingTraffic = Math.max(0, totalTraffic - usedTraffic); // 剩余流量(字节)
|
||||||
|
|
||||||
|
// 计算进度比例,确保在 0-1 之间
|
||||||
|
const progressRatio = Math.min(1, Math.max(0, remainingTraffic / totalTraffic));
|
||||||
|
|
||||||
|
// 格式化流量显示
|
||||||
|
const formattedTotal = formatTraffic(totalTraffic);
|
||||||
|
const formattedUsed = formatTraffic(usedTraffic);
|
||||||
|
const formattedRemaining = formatTraffic(remainingTraffic);
|
||||||
|
|
||||||
|
// 更新流量数据显示
|
||||||
baseData.value[1] = {
|
baseData.value[1] = {
|
||||||
...baseData.value[1],
|
...baseData.value[1],
|
||||||
value: data.remainingFlow,
|
value: formattedRemaining.value, // 仪表盘显示剩余流量
|
||||||
subTitle: t('page.headerbanner.Used') + `: ${data.usedFlow}MB`
|
unit: formattedRemaining.unit, // 使用转换后的单位
|
||||||
|
max: formattedTotal.value, // 最大值为总流量
|
||||||
|
description: `${t('page.headerbanner.monthflowr')} (${formattedTotal.value}${formattedTotal.unit})`, // 显示总流量
|
||||||
|
subTitle: t('page.headerbanner.Used') + `: ${formattedUsed.value}${formattedUsed.unit}` // 显示已用流量
|
||||||
};
|
};
|
||||||
|
|
||||||
// 格式化当前速度和峰值速度
|
// 更新仪表盘的进度比例
|
||||||
const currentSpeed = formatSpeed(data.trafficRate || 0);
|
updateGauge2(opts => {
|
||||||
const peakSpeed = formatSpeed(data.peakTrafficRate || 0);
|
if (opts.series && Array.isArray(opts.series)) {
|
||||||
|
const series = opts.series[0] as any;
|
||||||
|
if (series.axisLine) {
|
||||||
|
series.axisLine.lineStyle.color = [
|
||||||
|
[progressRatio, '#4284f5'],
|
||||||
|
[1, '#0c47a7']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return updateGaugeData(opts, baseData.value[1]);
|
||||||
|
});
|
||||||
|
|
||||||
// 设置一个最小的最大值,避免当速度为0时仪表盘显示异常
|
// 获取当前速率
|
||||||
|
const currentActivity = Number(response.activity ?? 0);
|
||||||
|
|
||||||
|
// 更新峰值速率
|
||||||
|
if (currentActivity > peakTrafficRate.value) {
|
||||||
|
peakTrafficRate.value = currentActivity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式化当前速度和峰值速度
|
||||||
|
const currentSpeed = formatSpeed(currentActivity);
|
||||||
|
const peakSpeed = formatSpeed(peakTrafficRate.value);
|
||||||
|
|
||||||
|
// 设置速率的最大值
|
||||||
const minMax = 1024; // 1KB/s 作为最小最大值
|
const minMax = 1024; // 1KB/s 作为最小最大值
|
||||||
const dynamicMax = Math.max(
|
const dynamicMax = Math.max(
|
||||||
currentSpeed.value * 1.5,
|
currentSpeed.value * 1.5,
|
||||||
@@ -263,11 +312,14 @@ async function mockDataUpdate() {
|
|||||||
subTitle: t('page.headerbanner.maxspeed') + `: ${peakSpeed.value}${peakSpeed.unit}`
|
subTitle: t('page.headerbanner.maxspeed') + `: ${peakSpeed.value}${peakSpeed.unit}`
|
||||||
};
|
};
|
||||||
|
|
||||||
// 更新表
|
// 更新图表
|
||||||
updateGauge1(opts => updateGaugeData(opts, baseData.value[0]));
|
updateGauge1(opts => updateGaugeData(opts, baseData.value[0]));
|
||||||
updateGauge2(opts => updateGaugeData(opts, baseData.value[1]));
|
updateGauge2(opts => updateGaugeData(opts, baseData.value[1]));
|
||||||
updateGauge3(opts => updateGaugeData(opts, baseData.value[2]));
|
updateGauge3(opts => updateGaugeData(opts, baseData.value[2]));
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to fetch dashboard data:', error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加 timer 声明
|
// 添加 timer 声明
|
||||||
@@ -275,8 +327,7 @@ let timer: ReturnType<typeof setInterval> | null = null;
|
|||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
async function init() {
|
async function init() {
|
||||||
await mockData();
|
// 立即执行一次数据更新
|
||||||
// 立即执行一次
|
|
||||||
await mockDataUpdate();
|
await mockDataUpdate();
|
||||||
// 设置定期执行的定时器
|
// 设置定期执行的定时器
|
||||||
timer = setInterval(mockDataUpdate, 30000);
|
timer = setInterval(mockDataUpdate, 30000);
|
||||||
@@ -288,18 +339,29 @@ onUnmounted(() => {
|
|||||||
clearInterval(timer);
|
clearInterval(timer);
|
||||||
timer = null;
|
timer = null;
|
||||||
}
|
}
|
||||||
|
peakTrafficRate.value = 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
// 监听语言变化
|
// 监听语言变化
|
||||||
watch(
|
watch(
|
||||||
() => appStore.locale,
|
() => appStore.locale,
|
||||||
() => {
|
() => {
|
||||||
updateLocale();
|
//updateLocale();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
init();
|
init();
|
||||||
|
|
||||||
|
// 导出更新数据的方法
|
||||||
|
const updateDashboard = async () => {
|
||||||
|
await mockDataUpdate();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 将方法暴露给父组件
|
||||||
|
defineExpose({
|
||||||
|
updateDashboard
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
Reference in New Issue
Block a user