From b4c01b85444bf0a1a14f9d7c746afe1efd798702 Mon Sep 17 00:00:00 2001 From: zhongzm Date: Wed, 22 Jan 2025 18:38:24 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E4=BB=AA=E8=A1=A8=E7=9B=98=E7=95=8C?= =?UTF-8?q?=E9=9D=A2=E4=BF=AE=E6=94=B9=E4=BB=A5=E5=8F=8A=E4=B8=AD=E8=8B=B1?= =?UTF-8?q?=E6=96=87=E9=80=82=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/locales/langs/en-us.ts | 14 +- src/locales/langs/zh-cn.ts | 8 + src/typings/api.d.ts | 11 +- src/views/home/modules/header-banner.vue | 526 ++++++++++++++--------- 4 files changed, 350 insertions(+), 209 deletions(-) diff --git a/src/locales/langs/en-us.ts b/src/locales/langs/en-us.ts index 13cccad..fa667c5 100644 --- a/src/locales/langs/en-us.ts +++ b/src/locales/langs/en-us.ts @@ -540,15 +540,23 @@ const local: any = { pay:'pay now' }, headerbanner:{ - Remainingcredit:'Remain credit', + packageinfo:'Package', + packagename:'Package name', + price:'Price', + uplimit:'Up speed', + downlimit:'Down speed', + client:'Client', + accountinfor:'Account information', + Remainingcredit:'Remain balance', monthphonebill:'Month bill', - Flowremaining:'Remain flowr', - monthflowr:'Month flowr', + Flowremaining:'Remain traffic', + monthflowr:'Traffic', Trafficrate:'Traffic rate', Currentspeed:'Current speed', Used:'Used', maxspeed:'Max', deviceCount: "Device", + nolimit:'Unlimited', }, userInfo:{ kyc:'KYC certification', diff --git a/src/locales/langs/zh-cn.ts b/src/locales/langs/zh-cn.ts index e96ecdf..3286677 100644 --- a/src/locales/langs/zh-cn.ts +++ b/src/locales/langs/zh-cn.ts @@ -542,6 +542,13 @@ const local:any = { pay:'立即支付', }, headerbanner:{ + packageinfo:'套餐信息', + packagename:'套餐名称', + price:'套餐费用', + uplimit:'上行速率', + downlimit:'下行速率', + client:'设备数', + accountinfor:'账户信息', Remainingcredit:'剩余话费', monthphonebill:'本月话费', Flowremaining:'剩余流量', @@ -551,6 +558,7 @@ const local:any = { Used:'已用', maxspeed:'峰值', deviceCount: "设备数", + nolimit:'无限制', }, userInfo:{ kyc:'KYC认证', diff --git a/src/typings/api.d.ts b/src/typings/api.d.ts index c286d41..f602f70 100644 --- a/src/typings/api.d.ts +++ b/src/typings/api.d.ts @@ -453,8 +453,15 @@ declare namespace Api { traffic: number; trafficUsed: number; trafficEnable: boolean; - activity: number; - error?: any; // 添加可选的 error 属性 + rateLimitEnable: boolean; + upLimitEnable: boolean; + downLimitEnable: boolean; + upLimit: number; + downLimit: number; + packageName:string; + clientNumEnable:boolean; + price:string; + error?: any; } } diff --git a/src/views/home/modules/header-banner.vue b/src/views/home/modules/header-banner.vue index 2156112..6984dd5 100644 --- a/src/views/home/modules/header-banner.vue +++ b/src/views/home/modules/header-banner.vue @@ -25,6 +25,10 @@ interface GaugeDisplayData { displayValue?: string; subTitle?: string; description?: string; + speedLimits?: { + upLimit: string; + downLimit: string; + }; } // 添加速率单位转换函数 @@ -74,7 +78,7 @@ const formatBalance = (balance: number | string): string => { return numBalance.toFixed(2); }; -// 使用 ref 来存储基础数据 +// 修改基础数据,移除速率仪表盘 const baseData = ref([ { id: 0, @@ -92,16 +96,11 @@ const baseData = ref([ max: 1024, unit: 'B', description: t('page.headerbanner.monthflowr'), - subTitle: t('page.headerbanner.Used') + ': 0B' - }, - { - id: 2, - title: t('page.headerbanner.Trafficrate'), - value: 0, - max: 10, - unit: 'B/s', - description: t('page.headerbanner.Currentspeed'), - subTitle: t('page.headerbanner.maxspeed') + '0B/s' + subTitle: t('page.headerbanner.Used') + ': 0B', + speedLimits: { + upLimit: '无限制', + downLimit: '无限制' + } } ]); @@ -179,9 +178,6 @@ const { domRef: gauge1Ref, updateOptions: updateGauge1 } = useEcharts(() => getG const { domRef: gauge2Ref, updateOptions: updateGauge2 } = useEcharts(() => getGaugeOptions(gaugeData.value[1]), { onRender: () => {} }); -const { domRef: gauge3Ref, updateOptions: updateGauge3 } = useEcharts(() => getGaugeOptions(gaugeData.value[2]), { - onRender: () => {} -}); // 更新单个图表的数据 const updateGaugeData = (opts: ECOption, data: GaugeDisplayData, progressRatio?: number) => { @@ -254,126 +250,106 @@ const updateGaugeData = (opts: ECOption, data: GaugeDisplayData, progressRatio?: return newOpts; }; -// 添加峰值速率的 ref -const peakTrafficRate = ref(0); - -// 添加检查是否可以上网的函数 -function checkAndTriggerAuth(dashboardData: any) { - // 检查是否有余额 - const hasBalance = dashboardData.balance > 0; - // 检查是否不限制流量 - const noTrafficLimit = !dashboardData.trafficEnable; - // 检查是否有剩余流量 - const hasRemainingTraffic = dashboardData.trafficEnable && - (dashboardData.traffic - dashboardData.trafficUsed) > 0; - - // 如果满足任一条件,静默触发上网 - if (hasBalance || noTrafficLimit || hasRemainingTraffic) { - clientAuth().catch(err => { - console.warn('Auto auth failed:', err); - }); +// 修改速率格式化函数 +const formatSpeedLimit = (speed: number): string => { + if (speed >= 1000000) { + return `${(speed / 1000000).toFixed(1)}Gbps`; + } else if (speed >= 1000) { + return `${(speed / 1000).toFixed(1)}Mbps`; } -} + return `${speed}Kbps`; +}; -// 修改 mockDataUpdate 函数,在获取数据后添加检查 +// 添加速率限制的响应式引用 +const speedLimits = ref({ + upLimit: t('page.headerbanner.nolimit'), + downLimit: t('page.headerbanner.nolimit') +}); + +// 添加套餐信息的响应式引用 +const packageInfo = ref({ + packageName: '', + price: '0.00' +}); + +// 修改数据更新函数,添加套餐信息的更新 async function mockDataUpdate() { try { const response = await authStore.getDashboardData(); - // 检查响应是否有效且不是错误响应 if (response && typeof response === 'object' && !response.error) { - // 检查必要的字段是否存在 - if (response.balance !== undefined) { - // 更新余额和设备数据 - const numBalance = Number(response.balance); - baseData.value[0] = { - ...baseData.value[0], - value: numBalance, - max: Math.max(numBalance, 100), - displayValue: formatBalance(response.balance), - unit: '元', - subTitle: t('page.headerbanner.deviceCount') + `: ${response.clientNum || 0}台` - }; + // 更新套餐信息 + packageInfo.value = { + packageName: response.packageName || '暂无套餐', + price: formatBalance(response.price || 0) + }; - // 处理流量数据,使用默认值处理可能的空值 - const totalTraffic = response.traffic || 0; - const usedTraffic = response.trafficUsed || 0; - const remainingTraffic = Math.max(0, totalTraffic - usedTraffic); - const progressRatio = totalTraffic ? Math.min(1, Math.max(0, remainingTraffic / totalTraffic)) : 0; + // 更新余额和设备数据 + const numBalance = Number(response.balance); + baseData.value[0] = { + ...baseData.value[0], + value: numBalance, + max: Math.max(numBalance, 100), + displayValue: formatBalance(response.balance), + unit: '元', + subTitle: t('page.headerbanner.deviceCount') + `: ${response.clientNumEnable ? (response.clientNum || 0) + '台' : t('page.headerbanner.nolimit')}` + }; - // 格式化流量显示 - const formattedTotal = formatTraffic(totalTraffic); - const formattedUsed = formatTraffic(usedTraffic); - const formattedRemaining = formatTraffic(remainingTraffic); + // 更新流量数据 + const totalTraffic = response.trafficEnable ? (response.traffic || 0) : 0; + const usedTraffic = response.trafficEnable ? (response.trafficUsed || 0) : 0; + const remainingTraffic = Math.max(0, totalTraffic - usedTraffic); + const progressRatio = totalTraffic ? Math.min(1, Math.max(0, remainingTraffic / totalTraffic)) : 0; - // 更新流量数据显示 - baseData.value[1] = { - ...baseData.value[1], - value: remainingTraffic, - max: totalTraffic, - displayValue: `${formattedRemaining.value}${formattedRemaining.unit}`, - unit: '', - description: `${t('page.headerbanner.monthflowr')} (${formattedTotal.value}${formattedTotal.unit})`, - subTitle: t('page.headerbanner.Used') + `: ${formattedUsed.value}${formattedUsed.unit}` - }; + // 格式化流量显示 + const formattedTotal = response.trafficEnable ? formatTraffic(totalTraffic) : { value: 0, unit: '' }; + const formattedUsed = response.trafficEnable ? formatTraffic(usedTraffic) : { value: 0, unit: '' }; + const formattedRemaining = response.trafficEnable ? formatTraffic(remainingTraffic) : { value: 0, unit: '' }; - // 获取当前速率 - const currentActivity = Number(response.activity ?? 0); - - // 更新峰值速率 - if (currentActivity > peakTrafficRate.value) { - peakTrafficRate.value = currentActivity; + // 更新流量数据显示 + baseData.value[1] = { + ...baseData.value[1], + value: remainingTraffic, + max: totalTraffic, + displayValue: response.trafficEnable ? `${formattedRemaining.value}${formattedRemaining.unit}` : t('page.headerbanner.nolimit'), + unit: '', + description: response.trafficEnable + ? `${t('page.headerbanner.monthflowr')} (${formattedTotal.value}${formattedTotal.unit})` + : `${t('page.headerbanner.monthflowr')} (${t('page.headerbanner.nolimit')})`, + subTitle: response.trafficEnable + ? t('page.headerbanner.Used') + `: ${formattedUsed.value}${formattedUsed.unit}` + : t('page.headerbanner.Used') + `: 0B`, + speedLimits: { + upLimit: speedLimits.value.upLimit, + downLimit: speedLimits.value.downLimit } + }; - // 格式化当前速度和峰值速度 - 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}` + // 更新速率限制显示 + if (response.rateLimitEnable) { + speedLimits.value = { + upLimit: response.upLimitEnable ? formatSpeedLimit(response.upLimit) : t('page.headerbanner.nolimit'), + downLimit: response.downLimitEnable ? formatSpeedLimit(response.downLimit) : t('page.headerbanner.nolimit') }; - - // 静默执行自动上网检查 - try { - await checkAndTriggerAuth(response); - } catch (error) { - console.warn('Auto auth check failed:', error); - } - - // 更新图表 - updateGauge1(opts => updateGaugeData(opts, baseData.value[0])); - updateGauge2(opts => { - const newOpts = updateGaugeData(opts, baseData.value[1], progressRatio); - return { - ...newOpts, - animation: true, - animationDuration: 1000, - animationEasing: 'cubicInOut' - }; - }); - updateGauge3(opts => updateGaugeData(opts, baseData.value[2])); } else { - // 静默处理无效数据 - console.warn('Invalid dashboard data structure:', response); + speedLimits.value = { + upLimit: t('page.headerbanner.nolimit'), + downLimit: t('page.headerbanner.nolimit') + }; } - } else { - // 静默处理无效响应 - console.warn('Invalid response:', response); + + // 更新图表 + updateGauge1(opts => updateGaugeData(opts, baseData.value[0])); + updateGauge2(opts => { + const newOpts = updateGaugeData(opts, baseData.value[1], progressRatio); + return { + ...newOpts, + animation: true, + animationDuration: 1000, + animationEasing: 'cubicInOut' + }; + }); } } catch (error) { - // 静默处理所有错误 console.warn('Dashboard update failed:', error); } } @@ -395,7 +371,6 @@ onUnmounted(() => { clearInterval(timer); timer = null; } - peakTrafficRate.value = 0; }); // 监听语言变化 @@ -418,27 +393,87 @@ const updateDashboard = async () => { defineExpose({ updateDashboard }); + +// 修改流量获取函数 +const getTrafficTotal = (description?: string, trafficEnable?: boolean): string => { + if (!trafficEnable) return t('page.headerbanner.nolimit'); + if (!description) return '0B'; + const matches = description.match(/\((.*?)\)/); + return matches ? matches[1] : '0B'; +}; + +// 修改设备数量获取函数 +const getDeviceCount = (subTitle?: string, clientNumEnable?: boolean): string => { + if (!clientNumEnable) return t('page.headerbanner.nolimit'); + if (!subTitle) return '0'; + const parts = subTitle.split(': '); + return parts.length > 1 ? parts[1] : '0'; +}; @@ -446,141 +481,224 @@ defineExpose({ .card-wrapper { margin-bottom: 16px; background: linear-gradient(180deg, #4284f5 0%, #0c47a7 100%); - padding: 20px 16px; + padding: 16px 12px; + color: #fff; +} + +.dashboard-layout { + display: flex; + gap: 12px; +} + +/* 左侧部分样式 */ +.left-section { + flex: 0 0 auto; + width: 200px; + display: flex; + align-items: center; + justify-content: flex-start; } .gauge-container { - height: 220px; - min-height: 140px; + text-align: center; position: relative; display: flex; flex-direction: column; + align-items: center; + justify-content: center; + width: 100%; + margin-left: -20px; } .gauge-chart { - flex: 1; - min-height: 120px; - position: relative; -} - -:deep(.echarts-container) { - position: absolute !important; - top: 0; - left: 0; - right: 0; - bottom: 0; + width: 200px; + height: 200px; } .gauge-info { - padding: 4px 0; - text-align: center; - color: #fff; - margin-top: -20px; -} - -.gauge-value { - font-size: 24px; - font-weight: bold; - line-height: 1.2; + margin-top: -16px; } .gauge-title { font-size: 14px; - margin: 4px 0; -} - -.sub-title { color: rgba(255, 255, 255, 0.85); +} + +.gauge-value { + font-size: 18px; + font-weight: bold; + margin-top: 2px; +} + +/* 右侧部分样式 */ +.right-section { + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + gap: 6px; +} + +.info-section { + margin-bottom: 8px; +} + +.section-title { font-size: 14px; + font-weight: 500; + color: #fff; + margin-bottom: 4px; + padding-left: 6px; + border-left: 3px solid #fff; } -.gauge-desc { +.info-group { + background: rgba(255, 255, 255, 0.05); + border-radius: 8px; + padding: 6px 8px; +} + +.info-item { + display: flex; + justify-content: space-between; + align-items: center; + padding: 4px 0; +} + +.info-item:not(:last-child) { + border-bottom: 1px solid rgba(255, 255, 255, 0.1); +} + +.info-label { + color: rgba(255, 255, 255, 0.85); font-size: 12px; - color: rgba(255, 255, 255, 0.7); - margin: 2px 0; } -/* 在小屏幕下调整样式 */ +.info-value { + font-size: 13px; + font-weight: 500; +} + +/* 移动端适配 */ @media screen and (max-width: 768px) { .card-wrapper { + padding: 16px 12px; + } + + .dashboard-layout { + gap: 12px; + } + + .right-section { + gap: 6px; + } + + .info-section { margin-bottom: 8px; - padding: 8px 4px; } - :deep(.arco-row) { - margin: 0 !important; + .section-title { + font-size: 14px; + margin-bottom: 4px; + padding-left: 6px; } - :deep(.arco-col) { - padding: 0 !important; + .info-group { + padding: 6px 8px; + } + + .info-item { + padding: 4px 0; + } + + .left-section { + width: 140px; + min-height: 180px; } .gauge-container { - height: 160px; - min-height: 90px; + width: 140px; + margin-left: -15px; } .gauge-chart { - min-height: 70px; + width: 140px; + height: 140px; } .gauge-info { - padding: 2px 0; + margin-top: -16px; } .gauge-value { font-size: 18px; + margin-top: 2px; } - .gauge-title { + .info-label { font-size: 12px; - margin: 2px 0; + white-space: nowrap; } - .sub-title { - font-size: 12px; - } - - .gauge-desc { - font-size: 10px; - } - - /* 调整仪表盘在小屏幕下的置 */ - :deep(.echarts-container) { - top: 0; - transform: scale(0.9); - transform-origin: center 45%; - } - - .gauge-info { - margin-top: -15px; + .info-value { + font-size: 13px; + word-break: break-all; } } -/* 在超小屏幕下进一步优化 */ +/* 超小屏幕优化 */ @media screen and (max-width: 375px) { .card-wrapper { - padding: 4px 2px; + padding: 10px 8px; + } + + .dashboard-layout { + gap: 6px; + } + + .left-section { + width: 120px; + min-height: 160px; } .gauge-container { - height: 140px; - min-height: 80px; + width: 120px; + margin-left: -10px; } .gauge-chart { - min-height: 60px; - } - - :deep(.echarts-container) { - top: 0; - transform: scale(0.85); - transform-origin: center 40%; + width: 120px; + height: 120px; } .gauge-info { - margin-top: -10px; - padding: 1px 0; + margin-top: -12px; + } + + .gauge-value { + font-size: 16px; + } + + .section-title { + font-size: 13px; + margin-bottom: 3px; + padding-left: 4px; + } + + .info-group { + padding: 4px 6px; + } + + .info-item { + padding: 3px 0; + } + + .info-label { + font-size: 11px; + } + + .info-value { + font-size: 12px; } }