178 lines
4.1 KiB
Vue
178 lines
4.1 KiB
Vue
<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 emit = defineEmits(['packageLoaded']);
|
||
|
||
const userStore = useUserStore();
|
||
|
||
// 流量数据
|
||
const usedMB = ref(0);
|
||
const realUsedMB = 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 && realUsedMB.value) {
|
||
const percent = (realUsedMB.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.getInfo(identifier);
|
||
|
||
if (data.current_package_usage_id) {
|
||
const realUsed = data.real_used_mb || 0;
|
||
const realTotal = data.real_total_mb || 0;
|
||
usedMB.value = data.enable_virtual_data ? (data.virtual_used_mb || 0) : realUsed;
|
||
realUsedMB.value = realUsed;
|
||
totalMB.value = realTotal;
|
||
remainMB.value = Math.max(realTotal - realUsed, 0);
|
||
emit('packageLoaded', data);
|
||
} else {
|
||
usedMB.value = 0;
|
||
realUsedMB.value = 0;
|
||
totalMB.value = 0;
|
||
remainMB.value = 0;
|
||
emit('packageLoaded', null);
|
||
}
|
||
} catch (e) {
|
||
console.error('加载套餐流量数据失败', e);
|
||
}
|
||
};
|
||
|
||
// 监听 identifier 变化
|
||
watch(() => props.identifier || userStore.state.identifier, (newVal) => {
|
||
if (newVal) {
|
||
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>
|