From 8edc1e19c76ad6c6baf9e5fb787a01ef38139640 Mon Sep 17 00:00:00 2001 From: zhongzm Date: Wed, 25 Dec 2024 18:51:09 +0800 Subject: [PATCH] =?UTF-8?q?fix:=E4=BB=AA=E8=A1=A8=E7=9B=98=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=AF=B9=E6=8E=A5=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/service/api/auth.ts | 2 +- src/typings/api.d.ts | 22 +-- src/views/home/modules/header-banner.vue | 222 +++++++++++++++-------- 3 files changed, 154 insertions(+), 92 deletions(-) diff --git a/src/service/api/auth.ts b/src/service/api/auth.ts index 7ecddf2..221ab1d 100644 --- a/src/service/api/auth.ts +++ b/src/service/api/auth.ts @@ -95,7 +95,7 @@ export function doGetCheckCode() { /** Get dashboard gauge data */ export function fetchDashboardData() { return request({ - url: '/u/cdr/getOne', + url: '/u/account/dashboard', method: 'get' }); } diff --git a/src/typings/api.d.ts b/src/typings/api.d.ts index 67467c0..a956d3e 100644 --- a/src/typings/api.d.ts +++ b/src/typings/api.d.ts @@ -443,18 +443,18 @@ declare namespace Api { namespace Dashboard { /** Dashboard gauge data */ interface GaugeData { - /** Remaining credit amount */ - remainingCredit: number; - /** Used credit amount */ - usedCredit: number; - /** Remaining flow amount (MB) */ - remainingFlow: number; - /** Used flow amount (MB) */ - usedFlow: number; - /** Current traffic rate (MB/s) */ - trafficRate: number; - /** Peak traffic rate (MB/s) */ + /** Balance amount */ + balance: number; + /** Total traffic amount (bytes) */ + traffic: number; + /** Used traffic amount (bytes) */ + trafficUsed: number; + /** Current traffic rate (B/s) */ + activity: number; + /** Peak traffic rate (B/s) */ peakTrafficRate: number; + /** Number of connected devices */ + clientNum: number; } } diff --git a/src/views/home/modules/header-banner.vue b/src/views/home/modules/header-banner.vue index 6787b7e..6327c18 100644 --- a/src/views/home/modules/header-banner.vue +++ b/src/views/home/modules/header-banner.vue @@ -14,7 +14,8 @@ defineOptions({ const appStore = useAppStore(); -interface GaugeData { +// 本地界面显示用的数据类型 +interface GaugeDisplayData { id: number; title: string; value: number; @@ -24,25 +25,61 @@ interface GaugeData { 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 来存储基础数据 -const baseData = ref([ +const baseData = ref([ { id: 0, title: t('page.headerbanner.Remainingcredit'), - value: 23, + value: 0, max: 100, unit: '元', description: t('page.headerbanner.monthphonebill'), - subTitle: t('page.headerbanner.Used')+'77元' + subTitle: t('page.headerbanner.deviceCount') + ': 0台' }, { id: 1, title: t('page.headerbanner.Flowremaining'), - value: 890, + value: 0, max: 1024, - unit: 'MB', + unit: 'B', description: t('page.headerbanner.monthflowr'), - subTitle: t('page.headerbanner.Used')+'134MB' + subTitle: t('page.headerbanner.Used') + ': 0B' }, { id: 2, @@ -59,7 +96,7 @@ const baseData = ref([ const gaugeData = computed(() => baseData.value); // 仪盘配置生成函数 -const getGaugeOptions = (data: GaugeData): ECOption => ({ +const getGaugeOptions = (data: GaugeDisplayData): ECOption => ({ backgroundColor: 'transparent', series: [{ 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)) { opts.series = [{ name: data.title, @@ -191,82 +228,97 @@ const updateGaugeData = (opts: ECOption, data: GaugeData) => { return opts; }; -// 更新图表数据 -async function mockData() { - 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' }; - } -} +// 添加峰值速率的 ref +const peakTrafficRate = ref(0); // 修改 mockDataUpdate 函数 async function mockDataUpdate() { - // 获取实际数据 - const data = await authStore.getDashboardData(); - if (data) { - // 更新话费数据 - baseData.value[0] = { - ...baseData.value[0], - value: data.remainingCredit, - subTitle: t('page.headerbanner.Used') + `: ${data.usedCredit}元` - }; + try { + const response = await authStore.getDashboardData(); + if (response) { + // 更新余额和设备数据 + baseData.value[0] = { + ...baseData.value[0], + value: response.balance, + max: Math.max(response.balance, 100), + subTitle: t('page.headerbanner.deviceCount') + `: ${response.clientNum}台` + }; - // 更新流量数据 - baseData.value[1] = { - ...baseData.value[1], - value: data.remainingFlow, - subTitle: t('page.headerbanner.Used') + `: ${data.usedFlow}MB` - }; + // 先计算剩余流量(字节单位) + const totalTraffic = response.traffic; // 总流量(字节) + const usedTraffic = response.trafficUsed; // 已用流量(字节) - // 格式化当前速度和峰值速度 - const currentSpeed = formatSpeed(data.trafficRate || 0); - const peakSpeed = formatSpeed(data.peakTrafficRate || 0); + // 计算剩余流量,确保不会出现负数 + const remainingTraffic = Math.max(0, totalTraffic - usedTraffic); // 剩余流量(字节) - // 设置一个最小的最大值,避免当速度为0时仪表盘显示异常 - const minMax = 1024; // 1KB/s 作为最小最大值 - const dynamicMax = Math.max( - currentSpeed.value * 1.5, - peakSpeed.value, - minMax - ); + // 计算进度比例,确保在 0-1 之间 + const progressRatio = Math.min(1, Math.max(0, remainingTraffic / totalTraffic)); - // 更新速率数据 - baseData.value[2] = { - ...baseData.value[2], - value: currentSpeed.value, - unit: currentSpeed.unit, - max: dynamicMax, - subTitle: t('page.headerbanner.maxspeed') + `: ${peakSpeed.value}${peakSpeed.unit}` - }; + // 格式化流量显示 + const formattedTotal = formatTraffic(totalTraffic); + const formattedUsed = formatTraffic(usedTraffic); + const formattedRemaining = formatTraffic(remainingTraffic); - // 更新表 - updateGauge1(opts => updateGaugeData(opts, baseData.value[0])); - updateGauge2(opts => updateGaugeData(opts, baseData.value[1])); - updateGauge3(opts => updateGaugeData(opts, baseData.value[2])); + // 更新流量数据显示 + baseData.value[1] = { + ...baseData.value[1], + value: formattedRemaining.value, // 仪表盘显示剩余流量 + unit: formattedRemaining.unit, // 使用转换后的单位 + max: formattedTotal.value, // 最大值为总流量 + description: `${t('page.headerbanner.monthflowr')} (${formattedTotal.value}${formattedTotal.unit})`, // 显示总流量 + subTitle: t('page.headerbanner.Used') + `: ${formattedUsed.value}${formattedUsed.unit}` // 显示已用流量 + }; + + // 更新仪表盘的进度比例 + updateGauge2(opts => { + 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]); + }); + + // 获取当前速率 + 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 dynamicMax = Math.max( + currentSpeed.value * 1.5, + peakSpeed.value, + minMax + ); + + // 更新速率数据 + baseData.value[2] = { + ...baseData.value[2], + value: currentSpeed.value, + unit: currentSpeed.unit, + max: dynamicMax, + subTitle: t('page.headerbanner.maxspeed') + `: ${peakSpeed.value}${peakSpeed.unit}` + }; + + // 更新图表 + updateGauge1(opts => updateGaugeData(opts, baseData.value[0])); + updateGauge2(opts => updateGaugeData(opts, baseData.value[1])); + updateGauge3(opts => updateGaugeData(opts, baseData.value[2])); + } + } catch (error) { + console.error('Failed to fetch dashboard data:', error); } } @@ -275,8 +327,7 @@ let timer: ReturnType | null = null; // 初始化 async function init() { - await mockData(); - // 立即执行一次 + // 立即执行一次数据更新 await mockDataUpdate(); // 设置定期执行的定时器 timer = setInterval(mockDataUpdate, 30000); @@ -288,18 +339,29 @@ onUnmounted(() => { clearInterval(timer); timer = null; } + peakTrafficRate.value = 0; }); // 监听语言变化 watch( () => appStore.locale, () => { - updateLocale(); + //updateLocale(); } ); // 初始化 init(); + +// 导出更新数据的方法 +const updateDashboard = async () => { + await mockDataUpdate(); +}; + +// 将方法暴露给父组件 +defineExpose({ + updateDashboard +});