Files
device-voice-h5/components/TrafficCard.vue
sexygoat 1a407924de
All checks were successful
构建并部署前端到生产环境 / build-and-deploy (push) Successful in 47s
fix: 修改index数据来源
2026-04-14 10:31:25 +08:00

163 lines
4.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="card traffic-card">
<view class="card-header flex-row-sb mb-lg">
<view class="title">本月流量</view>
<view class="usage-percent">
<text class="title">{{ usedFlowPercent }}</text>
<text class="caption">%</text>
</view>
</view>
<view class="progress-section mb-lg">
<view class="progress-apple">
<view class="progress-fill" :style="{width: usedFlowPercent + '%'}"></view>
</view>
</view>
<view class="traffic-stats flex-row-sb">
<view class="stat-item flex-col-center">
<view class="caption mb-xs">已使用</view>
<view class="stat-value-container">
<text class="stat-value">{{ usedValue }}</text>
<text class="stat-unit">{{ usedUnit }}</text>
</view>
</view>
<view class="stat-item flex-col-center">
<view class="caption mb-xs">总流量</view>
<view class="stat-value-container">
<text class="stat-value">{{ totalValue }}</text>
<text class="stat-unit">{{ totalUnit }}</text>
</view>
</view>
<view class="stat-item flex-col-center">
<view class="caption mb-xs">剩余</view>
<view class="stat-value-container">
<text class="stat-value">{{ remainValue }}</text>
<text class="stat-unit">{{ remainUnit }}</text>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, computed, watch } from 'vue';
import { assetApi } from '@/api/index.js';
import { useUserStore } from '@/store/index.js';
const props = defineProps({
identifier: { type: String, default: '' }
});
const userStore = useUserStore();
// 流量数据
const usedMB = ref(0);
const totalMB = ref(0);
const remainMB = ref(0);
// 格式化流量数据MB 转 GB
const formatTraffic = (mb) => {
if (!mb || mb === 0) {
return { value: '0.00', unit: 'MB' };
}
if (mb >= 1024) {
return {
value: (mb / 1024).toFixed(2),
unit: 'GB'
};
}
return {
value: mb.toFixed(2),
unit: 'MB'
};
};
// 已使用流量
const usedValue = computed(() => formatTraffic(usedMB.value).value);
const usedUnit = computed(() => formatTraffic(usedMB.value).unit);
// 总流量
const totalValue = computed(() => formatTraffic(totalMB.value).value);
const totalUnit = computed(() => formatTraffic(totalMB.value).unit);
// 剩余流量
const remainValue = computed(() => formatTraffic(remainMB.value).value);
const remainUnit = computed(() => formatTraffic(remainMB.value).unit);
// 使用百分比
const usedFlowPercent = computed(() => {
if (totalMB.value && usedMB.value) {
const percent = (usedMB.value / totalMB.value * 100);
return Math.min(percent, 100).toFixed(2);
}
return '0.00';
});
// 加载套餐流量数据
const loadPackageData = async () => {
const identifier = props.identifier || userStore.state.identifier;
if (!identifier) return;
try {
const data = await assetApi.getPackageHistory(identifier, 1, 10, { status: 1 });
if (data.items && data.items.length > 0) {
// 只有一个生效中的套餐
const activePackage = data.items[0];
if (activePackage.enable_virtual_data) {
// 启用虚流量
usedMB.value = activePackage.virtual_used_mb || 0;
totalMB.value = activePackage.virtual_limit_mb || 0;
remainMB.value = activePackage.virtual_remain_mb || 0;
} else {
// 未启用虚流量,使用真流量
usedMB.value = activePackage.data_usage_mb || 0;
totalMB.value = activePackage.data_limit_mb || 0;
remainMB.value = totalMB.value - usedMB.value;
}
} else {
// 没有生效中的套餐
usedMB.value = 0;
totalMB.value = 0;
remainMB.value = 0;
}
} catch (e) {
console.error('加载套餐流量数据失败', e);
}
};
// 监听 identifier 变化
watch(() => props.identifier, (newVal) => {
if (newVal) {
loadPackageData();
}
}, { immediate: true });
// 如果没有传入 identifier则使用 store 中的
watch(() => userStore.state.identifier, (newVal) => {
if (newVal && !props.identifier) {
loadPackageData();
}
}, { immediate: true });
</script>
<style scoped lang="scss">
.traffic-card {
.usage-percent {
display: flex;
align-items: baseline;
gap: 4rpx;
.title { font-size: 35rpx; font-weight: 700; margin-right: 5rpx; }
}
.traffic-stats {
background: var(--gray-100);
border-radius: var(--radius-small);
padding: 20rpx;
margin-top: 16rpx;
.stat-item { flex: 1; }
}
}
</style>