fix: 流量
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 1m5s

This commit is contained in:
sexygoat
2026-05-06 18:14:08 +08:00
parent 663c71cbc1
commit d8a16bdf8d
3 changed files with 477 additions and 52 deletions

View File

@@ -268,12 +268,20 @@ export interface AssetPackage {
package_id: number
package_name: string
package_type: 'formal' | 'addon'
order_id?: number
order_no?: string
status: number
status_name: string
usage_type: string
priority: number
package_usage_id: number
master_usage_id: number | null
paid_amount?: number
enable_virtual_data?: boolean
reduction_pct?: number
real_total_mb?: number
real_used_mb?: number
virtual_total_mb?: number
data_limit_mb: number
data_usage_mb: number
virtual_limit_mb: number

View File

@@ -2,6 +2,7 @@
import { ref, computed, onMounted } from 'vue'
import { getAssetDetail, getAssetPackages, getCurrentPackage, getAssetHistory, stopAsset, startAsset } from '@/api/assets'
import type { AssetType, CardInfo, DeviceInfo, AssetPackage, HistoryRecord } from '@/api/assets'
import { formatDataSize, formatTime } from '@/utils/format'
// 资产类型
const assetType = ref<AssetType>('card')
@@ -55,6 +56,50 @@ const statusColor = computed(() => {
: { bg: '#ffebee', text: '#c62828' }
})
function getPackageStatusColor(status?: number) {
const map: Record<number, { bg: string, text: string }> = {
0: { bg: '#fff3e0', text: '#e65100' },
1: { bg: '#e8f5e9', text: '#2e7d32' },
2: { bg: '#f5f5f5', text: '#999' },
3: { bg: '#ffebee', text: '#c62828' },
4: { bg: '#f5f5f5', text: '#999' },
}
return status !== undefined ? map[status] || { bg: '#f5f5f5', text: '#999' } : { bg: '#f5f5f5', text: '#999' }
}
function getPackageUsedMb(pkg: AssetPackage) {
return Number(pkg.enable_virtual_data ? pkg.virtual_used_mb : pkg.real_used_mb) || 0
}
function getPackageTotalMb(pkg: AssetPackage) {
return Number(pkg.real_total_mb) || 0
}
function getPackageRemainMb(pkg: AssetPackage) {
return Math.max(0, getPackageTotalMb(pkg) - (Number(pkg.real_used_mb) || 0))
}
function getPackageUsagePercent(pkg: AssetPackage) {
const total = getPackageTotalMb(pkg)
if (total <= 0)
return 0
return Math.min(100, (getPackageUsedMb(pkg) / total) * 100)
}
function getPackageTypeText(type?: AssetPackage['package_type']) {
const map: Record<string, string> = {
formal: '正式套餐',
addon: '加油包',
}
return type ? map[type] || type : '-'
}
function formatPackagePrice(amount?: number) {
if (amount === undefined || amount === null)
return '-'
return `¥${(amount / 100).toFixed(2)}`
}
// 页面加载
onMounted(() => {
// 从路由参数获取 assetType 和 assetIdentifier
@@ -72,7 +117,7 @@ async function loadAssetDetail() {
try {
// 调用资产详情接口
const detailData = await getAssetDetail(assetType.value, assetId.value)
const detailData = await getAssetDetail(assetType.value, assetIdentifier.value)
// 根据类型提取详情
if (assetType.value === 'card' && detailData.card) {
@@ -118,29 +163,16 @@ async function loadAssetDetail() {
// 加载套餐列表
async function loadPackages() {
try {
// 1. 调用当前生效套餐接口
try {
const current = await getCurrentPackage(assetIdentifier.value)
currentPackage.value = current
} catch (error) {
console.warn('获取当前套餐失败:', error)
currentPackage.value = null
}
// 2. 调用套餐列表接口
currentPackage.value = await getCurrentPackage(assetIdentifier.value)
const packagesData = await getAssetPackages(assetIdentifier.value, {
page: 1,
page_size: 50
})
packageList.value = packagesData.items || []
// 如果没有获取到当前套餐,从列表中查找生效中的套餐
if (!currentPackage.value && packageList.value.length > 0) {
currentPackage.value = packageList.value.find(pkg => pkg.status === 1) || null
}
}
catch (error: any) {
console.error('加载套餐列表失败:', error)
packageList.value = []
}
}
@@ -282,7 +314,7 @@ function viewWallet() {
<view class="bg-white rounded-16px shadow-[0_2px_12px_rgba(0,0,0,0.06)] overflow-hidden mb-3">
<!-- 顶部信息 -->
<view class="px-4 pt-4 pb-3 border-b-1px border-[#f5f5f5]">
<view class="flex items-center justify-between mb-3">
<view v-if="false" class="flex items-center justify-between mb-3">
<view class="flex items-center gap-2">
<i
:class="[
@@ -437,7 +469,83 @@ function viewWallet() {
<view v-if="activeTab === 'package'" class="space-y-3">
<!-- 当前套餐 -->
<view v-if="currentPackage" class="bg-white rounded-16px shadow-[0_2px_12px_rgba(0,0,0,0.06)] p-4">
<view class="flex items-center justify-between mb-3">
<view class="flex items-start justify-between gap-3 mb-3">
<view class="min-w-0 flex-1">
<text class="text-14px font-600 text-[#212121] block break-all">
{{ currentPackage.package_name || '-' }}
</text>
<text class="text-11px text-[#999] block mt-1 break-all">
订单号{{ currentPackage.order_no || '-' }}
</text>
</view>
<view
:style="{
backgroundColor: getPackageStatusColor(currentPackage.status).bg,
color: getPackageStatusColor(currentPackage.status).text,
}"
class="px-2 py-0.5 rounded text-10px font-600"
>
{{ currentPackage.status_name || '-' }}
</view>
</view>
<view class="grid grid-cols-3 gap-2 mb-3">
<view class="bg-[#f5f5f5] rounded-8px p-2 text-center">
<text class="text-10px text-[#999] block mb-1">总量</text>
<text class="text-12px font-600 text-[#212121]">{{ formatDataSize(getPackageTotalMb(currentPackage)) }}</text>
</view>
<view class="bg-[#f5f5f5] rounded-8px p-2 text-center">
<text class="text-10px text-[#999] block mb-1">已使用</text>
<text class="text-12px font-600 text-[var(--brand-primary)]">{{ formatDataSize(getPackageUsedMb(currentPackage)) }}</text>
</view>
<view class="bg-[#f5f5f5] rounded-8px p-2 text-center">
<text class="text-10px text-[#999] block mb-1">剩余</text>
<text class="text-12px font-600 text-[#2e7d32]">{{ formatDataSize(getPackageRemainMb(currentPackage)) }}</text>
</view>
</view>
<view class="bg-[#f5f5f5] rounded-8px p-2 mb-3">
<view class="flex items-center justify-between mb-1">
<text class="text-11px text-[#666]">已使用</text>
<text class="text-11px font-600 text-[#212121]">
{{ formatDataSize(getPackageUsedMb(currentPackage)) }} /
{{ formatDataSize(getPackageTotalMb(currentPackage)) }}
</text>
</view>
<view class="h-4px bg-[#e0e0e0] rounded-full overflow-hidden">
<view
:style="{ width: `${getPackageUsagePercent(currentPackage)}%` }"
:class="[
'h-full rounded-full transition-all',
getPackageUsagePercent(currentPackage) > 90 ? 'bg-[#ff6b6b]' : 'bg-[#3ed268]',
]"
/>
</view>
</view>
<view class="space-y-2 mb-1">
<view class="flex items-center justify-between text-12px">
<text class="text-[#666]">套餐价格</text>
<text class="text-[#212121]">{{ formatPackagePrice(currentPackage.paid_amount) }}</text>
</view>
<view class="flex items-center justify-between text-12px">
<text class="text-[#666]">套餐类型</text>
<text class="text-[#212121]">{{ getPackageTypeText(currentPackage.package_type) }}</text>
</view>
<view class="flex items-center justify-between text-12px">
<text class="text-[#666]">开始时间</text>
<text class="text-[#212121]">{{ formatTime(currentPackage.activated_at) }}</text>
</view>
<view class="flex items-center justify-between text-12px">
<text class="text-[#666]">到期时间</text>
<text class="text-[#212121]">{{ formatTime(currentPackage.expires_at) }}</text>
</view>
<view class="flex items-center justify-between text-12px">
<text class="text-[#666]">下单时间</text>
<text class="text-[#212121]">{{ formatTime(currentPackage.created_at) }}</text>
</view>
</view>
<view v-if="false" class="flex items-center justify-between mb-3">
<text class="text-14px font-600 text-[#212121]">
当前套餐
</text>
@@ -446,14 +554,14 @@ function viewWallet() {
</view>
</view>
<text class="text-16px font-700 text-[#212121] block mb-2">
<text v-if="false" class="text-16px font-700 text-[#212121] block mb-2">
{{ currentPackage.package_name || '-' }}
</text>
<text class="text-14px text-[var(--brand-primary)] font-600 block mb-3">
<text v-if="false" class="text-14px text-[var(--brand-primary)] font-600 block mb-3">
已用: {{ currentPackage.virtual_used_mb || 0 }}MB / 总量: {{ currentPackage.virtual_limit_mb || 0 }}MB
</text>
<view class="flex items-center justify-between text-12px text-[#999]">
<view v-if="false" class="flex items-center justify-between text-12px text-[#999]">
<text v-if="currentPackage.activated_at && currentPackage.expires_at">
{{ currentPackage.activated_at }} ~ {{ currentPackage.expires_at }}
</text>
@@ -488,7 +596,7 @@ function viewWallet() {
</view>
<view class="flex items-center justify-between mb-1">
<text class="text-12px text-[#666]">
已用: {{ pkg.virtual_used_mb || 0 }}MB / {{ pkg.virtual_limit_mb || 0 }}MB
已用: {{ formatDataSize(getPackageUsedMb(pkg)) }} / {{ formatDataSize(getPackageTotalMb(pkg)) }}
</text>
<text class="text-11px text-[#999]">
优先级: {{ pkg.priority || '-' }}
@@ -501,10 +609,10 @@ function viewWallet() {
</view>
<!-- 暂无套餐 -->
<view v-else class="bg-white rounded-16px shadow-[0_2px_12px_rgba(0,0,0,0.06)] p-4 py-12 center flex-col">
<view v-if="!currentPackage" class="bg-white rounded-16px shadow-[0_2px_12px_rgba(0,0,0,0.06)] p-4 py-12 center flex-col">
<i class="i-mdi-package-variant-closed text-60px text-[#ddd] mb-2" />
<text class="text-13px text-[#999]">
暂无套餐数据
暂无生效套餐
</text>
</view>
</view>

View File

@@ -14,10 +14,10 @@
const realtimeStatus = ref<AssetRealtimeStatus | null>(null)
// 当前套餐
const currentPackage = ref<AssetPackage | null>(null)
// 套餐列表
const packageList = ref<AssetPackage[]>([])
// 是否展开套餐列表
const showPackageList = ref(true)
// 套餐列表
// 是否展开套餐列表
// 是否为卡片
const isCard = computed(() => assetType.value === 'card')
@@ -50,6 +50,8 @@
assetType.value = null
assetInfo.value = null
realtimeStatus.value = null
currentPackage.value = null
packageList.value = []
}
}
@@ -187,9 +189,35 @@
}
// 计算套餐使用百分比
function getPackageUsedMb(pkg : AssetPackage) {
return Number(pkg.enable_virtual_data ? pkg.virtual_used_mb : pkg.real_used_mb) || 0
}
function getPackageTotalMb(pkg : AssetPackage) {
return Number(pkg.real_total_mb) || 0
}
function getPackageRemainMb(pkg : AssetPackage) {
return Math.max(0, getPackageTotalMb(pkg) - (Number(pkg.real_used_mb) || 0))
}
function getPackageTypeText(type ?: AssetPackage['package_type']) {
const map : Record<string, string> = {
formal: '正式套餐',
addon: '加油包',
}
return type ? map[type] || type : '-'
}
function formatPackagePrice(amount ?: number) {
if (amount === undefined || amount === null) return '-'
return `¥${(amount / 100).toFixed(2)}`
}
function getPackageUsagePercent(pkg : AssetPackage) {
if (!pkg.virtual_limit_mb || pkg.virtual_limit_mb === 0) return 0
return Math.min(100, (pkg.virtual_used_mb / pkg.virtual_limit_mb) * 100)
const total = getPackageTotalMb(pkg)
if (total <= 0) return 0
return Math.min(100, (getPackageUsedMb(pkg) / total) * 100)
}
// 获取信号质量等级 (基于 RSRP)
@@ -287,7 +315,7 @@
<view class="bg-white rounded-16px shadow-[0_2px_12px_rgba(0,0,0,0.06)] overflow-hidden">
<!-- 顶部状态栏 -->
<view class="px-4 pt-4 pb-3 border-b-1px border-[#f5f5f5]">
<view class="flex items-center justify-between mb-2">
<view v-if="false" class="flex items-center justify-between mb-2">
<view class="flex items-center gap-2">
<text class="text-16px font-700 text-[#212121]">
IoT卡
@@ -477,8 +505,8 @@
<!-- 套餐信息 -->
<view class="bg-white rounded-16px shadow-[0_2px_12px_rgba(0,0,0,0.06)] overflow-hidden mt-2 p-2 px-4 pb-3">
<view class="flex items-center justify-between mb-2">
<text class="text-13px font-600 text-[#212121]">套餐信息</text>
<view v-if="currentPackage" class="flex items-center gap-1 px-2 py-1 rounded-8px bg-[#f5f5f5]"
<text class="text-13px font-600 text-[#212121]">当前生效套餐</text>
<view v-if="false && currentPackage" class="flex items-center gap-1 px-2 py-1 rounded-8px bg-[#f5f5f5]"
@click="togglePackageList">
<text class="text-11px text-[#666]">全部套餐</text>
<i :class="[
@@ -490,8 +518,218 @@
<!-- 当前套餐 -->
<view v-if="currentPackage" class="bg-[#f5f5f5] rounded-12px p-3">
<view class="flex items-start justify-between gap-3 mb-3">
<view class="min-w-0 flex-1">
<text class="text-14px font-600 text-[#212121] block break-all">
{{ currentPackage.package_name || '-' }}
</text>
<text class="text-11px text-[#999] block mt-1 break-all">
订单号{{ currentPackage.order_no || '-' }}
</text>
</view>
<view :style="{
backgroundColor: getPackageStatusColor(currentPackage.status).bg,
color: getPackageStatusColor(currentPackage.status).text,
}" class="px-2 py-0.5 rounded text-10px font-600">
{{ currentPackage.status_name || '-' }}
</view>
</view>
<view class="grid grid-cols-3 gap-2 mb-3">
<view class="bg-white rounded-8px p-2 text-center">
<text class="text-10px text-[#999] block mb-1">总量</text>
<text class="text-12px font-600 text-[#212121]">{{ formatDataSize(getPackageTotalMb(currentPackage)) }}</text>
</view>
<view class="bg-white rounded-8px p-2 text-center">
<text class="text-10px text-[#999] block mb-1">已使用</text>
<text class="text-12px font-600 text-[var(--brand-primary)]">{{ formatDataSize(getPackageUsedMb(currentPackage)) }}</text>
</view>
<view class="bg-white rounded-8px p-2 text-center">
<text class="text-10px text-[#999] block mb-1">剩余</text>
<text class="text-12px font-600 text-[#2e7d32]">{{ formatDataSize(getPackageRemainMb(currentPackage)) }}</text>
</view>
</view>
<view class="bg-white rounded-8px p-2 mb-3">
<view class="flex items-center justify-between mb-1">
<text class="text-11px text-[#666]">已使用</text>
<text class="text-11px font-600 text-[#212121]">
{{ formatDataSize(getPackageUsedMb(currentPackage)) }} /
{{ formatDataSize(getPackageTotalMb(currentPackage)) }}
</text>
</view>
<view class="h-4px bg-[#e0e0e0] rounded-full overflow-hidden">
<view :style="{ width: `${getPackageUsagePercent(currentPackage)}%` }" :class="[
'h-full rounded-full transition-all',
getPackageUsagePercent(currentPackage) > 90 ? 'bg-[#ff6b6b]' : 'bg-[#3ed268]',
]" />
</view>
</view>
<view class="space-y-1 mb-1">
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">套餐价格</text>
<text class="text-[#212121]">{{ formatPackagePrice(currentPackage.paid_amount) }}</text>
</view>
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">套餐类型</text>
<text class="text-[#212121]">{{ getPackageTypeText(currentPackage.package_type) }}</text>
</view>
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">开始时间</text>
<text class="text-[#212121]">{{ formatTime(currentPackage.activated_at) }}</text>
</view>
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">到期时间</text>
<text class="text-[#212121]">{{ formatTime(currentPackage.expires_at) }}</text>
</view>
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">下单时间</text>
<text class="text-[#212121]">{{ formatTime(currentPackage.created_at) }}</text>
</view>
</view>
<view v-if="false" class="flex items-start justify-between gap-3 mb-3">
<view class="min-w-0 flex-1">
<text class="text-14px font-600 text-[#212121] block break-all">
{{ currentPackage.package_name || '-' }}
</text>
<text class="text-11px text-[#999] block mt-1 break-all">
订单号{{ currentPackage.order_no || '-' }}
</text>
</view>
<view :style="{
backgroundColor: getPackageStatusColor(currentPackage.status).bg,
color: getPackageStatusColor(currentPackage.status).text,
}" class="px-2 py-0.5 rounded text-10px font-600">
{{ currentPackage.status_name || '-' }}
</view>
</view>
<view v-if="false" class="grid grid-cols-3 gap-2 mb-3">
<view class="bg-white rounded-8px p-2 text-center">
<text class="text-10px text-[#999] block mb-1">总量</text>
<text class="text-12px font-600 text-[#212121]">{{ formatDataSize(getPackageTotalMb(currentPackage)) }}</text>
</view>
<view class="bg-white rounded-8px p-2 text-center">
<text class="text-10px text-[#999] block mb-1">已使用</text>
<text class="text-12px font-600 text-[var(--brand-primary)]">{{ formatDataSize(getPackageUsedMb(currentPackage)) }}</text>
</view>
<view class="bg-white rounded-8px p-2 text-center">
<text class="text-10px text-[#999] block mb-1">剩余</text>
<text class="text-12px font-600 text-[#2e7d32]">{{ formatDataSize(getPackageRemainMb(currentPackage)) }}</text>
</view>
</view>
<view v-if="false" class="bg-white rounded-8px p-2 mb-3">
<view class="flex items-center justify-between mb-1">
<text class="text-11px text-[#666]">已使用</text>
<text class="text-11px font-600 text-[#212121]">
{{ formatDataSize(getPackageUsedMb(currentPackage)) }} /
{{ formatDataSize(getPackageTotalMb(currentPackage)) }}
</text>
</view>
<view class="h-4px bg-[#e0e0e0] rounded-full overflow-hidden">
<view :style="{ width: `${getPackageUsagePercent(currentPackage)}%` }" :class="[
'h-full rounded-full transition-all',
getPackageUsagePercent(currentPackage) > 90 ? 'bg-[#ff6b6b]' : 'bg-[#3ed268]',
]" />
</view>
</view>
<view v-if="false" class="space-y-1 mb-1">
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">套餐价格</text>
<text class="text-[#212121]">{{ formatPackagePrice(currentPackage.paid_amount) }}</text>
</view>
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">套餐类型</text>
<text class="text-[#212121]">{{ getPackageTypeText(currentPackage.package_type) }}</text>
</view>
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">开始时间</text>
<text class="text-[#212121]">{{ formatTime(currentPackage.activated_at) }}</text>
</view>
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">到期时间</text>
<text class="text-[#212121]">{{ formatTime(currentPackage.expires_at) }}</text>
</view>
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">下单时间</text>
<text class="text-[#212121]">{{ formatTime(currentPackage.created_at) }}</text>
</view>
</view>
<view v-if="false" class="flex items-start justify-between gap-3 mb-3">
<view class="min-w-0 flex-1">
<text class="text-14px font-600 text-[#212121] block break-all">
{{ currentPackage.package_name || '-' }}
</text>
<text class="text-11px text-[#999] block mt-1 break-all">
订单号{{ currentPackage.order_no || '-' }}
</text>
</view>
<view :style="{
backgroundColor: getPackageStatusColor(currentPackage.status).bg,
color: getPackageStatusColor(currentPackage.status).text,
}" class="px-2 py-0.5 rounded text-10px font-600">
{{ currentPackage.status_name || '-' }}
</view>
</view>
<view v-if="false" class="grid grid-cols-3 gap-2 mb-3">
<view class="bg-white rounded-8px p-2 text-center">
<text class="text-10px text-[#999] block mb-1">总量</text>
<text class="text-12px font-600 text-[#212121]">{{ formatDataSize(getPackageTotalMb(currentPackage)) }}</text>
</view>
<view class="bg-white rounded-8px p-2 text-center">
<text class="text-10px text-[#999] block mb-1">已使用</text>
<text class="text-12px font-600 text-[var(--brand-primary)]">{{ formatDataSize(getPackageUsedMb(currentPackage)) }}</text>
</view>
<view class="bg-white rounded-8px p-2 text-center">
<text class="text-10px text-[#999] block mb-1">剩余</text>
<text class="text-12px font-600 text-[#2e7d32]">{{ formatDataSize(getPackageRemainMb(currentPackage)) }}</text>
</view>
</view>
<view v-if="false" class="bg-white rounded-8px p-2 mb-3">
<view class="flex items-center justify-between mb-1">
<text class="text-11px text-[#666]">已使用</text>
<text class="text-11px font-600 text-[#212121]">
{{ formatDataSize(getPackageUsedMb(currentPackage)) }} /
{{ formatDataSize(getPackageTotalMb(currentPackage)) }}
</text>
</view>
<view class="h-4px bg-[#e0e0e0] rounded-full overflow-hidden">
<view :style="{ width: `${getPackageUsagePercent(currentPackage)}%` }" :class="[
'h-full rounded-full transition-all',
getPackageUsagePercent(currentPackage) > 90 ? 'bg-[#ff6b6b]' : 'bg-[#3ed268]',
]" />
</view>
</view>
<view v-if="false" class="space-y-1 mb-1">
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">套餐价格</text>
<text class="text-[#212121]">{{ formatPackagePrice(currentPackage.paid_amount) }}</text>
</view>
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">套餐类型</text>
<text class="text-[#212121]">{{ getPackageTypeText(currentPackage.package_type) }}</text>
</view>
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">开始时间</text>
<text class="text-[#212121]">{{ formatTime(currentPackage.activated_at) }}</text>
</view>
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">到期时间</text>
<text class="text-[#212121]">{{ formatTime(currentPackage.expires_at) }}</text>
</view>
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">下单时间</text>
<text class="text-[#212121]">{{ formatTime(currentPackage.created_at) }}</text>
</view>
</view>
<!-- 套餐名称和状态 -->
<view class="flex items-center justify-between mb-2">
<view v-if="false" class="flex items-center justify-between mb-2">
<view class="flex items-center gap-2">
<i :class="[
'text-16px',
@@ -510,7 +748,7 @@
</view>
<!-- 流量使用进度 -->
<view class="bg-white rounded-8px p-2 mb-2">
<view v-if="false" class="bg-white rounded-8px p-2 mb-2">
<view class="flex items-center justify-between mb-1">
<text class="text-11px text-[#666]">虚拟流量</text>
<text class="text-11px font-600 text-[#212121]">
@@ -528,7 +766,7 @@
</view>
<!-- 套餐详情 -->
<view class="space-y-1">
<view v-if="false" class="space-y-1">
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">真实流量</text>
<text class="text-[#212121]">
@@ -554,9 +792,9 @@
<text class="text-12px text-[#999]">暂无生效套餐</text>
</view>
<!-- 套餐列表展开时显示 -->
<view v-if="showPackageList && packageList.length > 0" class="mt-3">
<text class="text-13px font-600 text-[#212121] block mb-2">全部套餐 ({{ packageList.length }})</text>
<!-- 套餐列表 -->
<view v-if="packageList.length > 0" class="mt-3">
<text class="text-13px font-600 text-[#212121] block mb-2">套餐列表 ({{ packageList.length }})</text>
<view class="space-y-2">
<view v-for="pkg in packageList" :key="pkg.package_usage_id" class="bg-[#f5f5f5] rounded-12px p-3">
<!-- 套餐头部 -->
@@ -580,9 +818,9 @@
<!-- 流量信息 -->
<view class="space-y-0.5">
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">虚拟流量</text>
<text class="text-[#666]">已使用</text>
<text class="text-[#212121]">
{{ formatDataSize(pkg.virtual_used_mb) }} / {{ formatDataSize(pkg.virtual_limit_mb) }}
{{ formatDataSize(getPackageUsedMb(pkg)) }} / {{ formatDataSize(getPackageTotalMb(pkg)) }}
</text>
</view>
<view v-if="pkg.activated_at" class="flex items-center justify-between text-10px">
@@ -611,7 +849,7 @@
<view class="bg-white rounded-16px shadow-[0_2px_12px_rgba(0,0,0,0.06)] overflow-hidden">
<!-- 顶部状态栏 -->
<view class="px-4 pt-4 pb-3 border-b-1px border-[#f5f5f5]">
<view class="flex items-center justify-between mb-2">
<view v-if="false" class="flex items-center justify-between mb-2">
<view class="flex items-center gap-2">
<view>
<text class="text-16px font-700 text-[#212121] block mb-0.5">
@@ -932,9 +1170,9 @@
<view v-if="realtimeStatus.device_realtime.ssid" class="bg-[#f5f5f5] rounded-12px p-3 mb-2">
<text class="text-12px text-[#666] block mb-2">WiFi信息</text>
<view class="space-y-1">
<!-- SSID -->
<!-- WiFi名称 -->
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">SSID</text>
<text class="text-[#666]">WiFi名称</text>
<text class="text-[#212121]">{{ realtimeStatus.device_realtime.ssid }}</text>
</view>
@@ -998,8 +1236,8 @@
<!-- 套餐信息 -->
<view class="bg-white rounded-16px shadow-[0_2px_12px_rgba(0,0,0,0.06)] overflow-hidden mt-2 p-2 px-4 pb-3">
<view class="flex items-center justify-between mb-2">
<text class="text-13px font-600 text-[#212121]">套餐信息</text>
<view v-if="currentPackage" class="flex items-center gap-1 px-2 py-1 rounded-8px bg-[#f5f5f5]"
<text class="text-13px font-600 text-[#212121]">当前生效套餐</text>
<view v-if="false && currentPackage" class="flex items-center gap-1 px-2 py-1 rounded-8px bg-[#f5f5f5]"
@click="togglePackageList">
<text class="text-11px text-[#666]">全部套餐</text>
<i :class="[
@@ -1011,8 +1249,79 @@
<!-- 当前套餐 -->
<view v-if="currentPackage" class="bg-[#f5f5f5] rounded-12px p-3">
<view class="flex items-start justify-between gap-3 mb-3">
<view class="min-w-0 flex-1">
<text class="text-14px font-600 text-[#212121] block break-all">
{{ currentPackage.package_name || '-' }}
</text>
<text class="text-11px text-[#999] block mt-1 break-all">
订单号{{ currentPackage.order_no || '-' }}
</text>
</view>
<view :style="{
backgroundColor: getPackageStatusColor(currentPackage.status).bg,
color: getPackageStatusColor(currentPackage.status).text,
}" class="px-2 py-0.5 rounded text-10px font-600">
{{ currentPackage.status_name || '-' }}
</view>
</view>
<view class="grid grid-cols-3 gap-2 mb-3">
<view class="bg-white rounded-8px p-2 text-center">
<text class="text-10px text-[#999] block mb-1">总量</text>
<text class="text-12px font-600 text-[#212121]">{{ formatDataSize(getPackageTotalMb(currentPackage)) }}</text>
</view>
<view class="bg-white rounded-8px p-2 text-center">
<text class="text-10px text-[#999] block mb-1">已使用</text>
<text class="text-12px font-600 text-[var(--brand-primary)]">{{ formatDataSize(getPackageUsedMb(currentPackage)) }}</text>
</view>
<view class="bg-white rounded-8px p-2 text-center">
<text class="text-10px text-[#999] block mb-1">剩余</text>
<text class="text-12px font-600 text-[#2e7d32]">{{ formatDataSize(getPackageRemainMb(currentPackage)) }}</text>
</view>
</view>
<view class="bg-white rounded-8px p-2 mb-3">
<view class="flex items-center justify-between mb-1">
<text class="text-11px text-[#666]">已使用</text>
<text class="text-11px font-600 text-[#212121]">
{{ formatDataSize(getPackageUsedMb(currentPackage)) }} /
{{ formatDataSize(getPackageTotalMb(currentPackage)) }}
</text>
</view>
<view class="h-4px bg-[#e0e0e0] rounded-full overflow-hidden">
<view :style="{ width: `${getPackageUsagePercent(currentPackage)}%` }" :class="[
'h-full rounded-full transition-all',
getPackageUsagePercent(currentPackage) > 90 ? 'bg-[#ff6b6b]' : 'bg-[#3ed268]',
]" />
</view>
</view>
<view class="space-y-1 mb-1">
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">套餐价格</text>
<text class="text-[#212121]">{{ formatPackagePrice(currentPackage.paid_amount) }}</text>
</view>
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">套餐类型</text>
<text class="text-[#212121]">{{ getPackageTypeText(currentPackage.package_type) }}</text>
</view>
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">开始时间</text>
<text class="text-[#212121]">{{ formatTime(currentPackage.activated_at) }}</text>
</view>
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">到期时间</text>
<text class="text-[#212121]">{{ formatTime(currentPackage.expires_at) }}</text>
</view>
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">下单时间</text>
<text class="text-[#212121]">{{ formatTime(currentPackage.created_at) }}</text>
</view>
</view>
<!-- 套餐名称和状态 -->
<view class="flex items-center justify-between mb-2">
<view v-if="false" class="flex items-center justify-between mb-2">
<view class="flex items-center gap-2">
<i :class="[
'text-16px',
@@ -1031,7 +1340,7 @@
</view>
<!-- 流量使用进度 -->
<view class="bg-white rounded-8px p-2 mb-2">
<view v-if="false" class="bg-white rounded-8px p-2 mb-2">
<view class="flex items-center justify-between mb-1">
<text class="text-11px text-[#666]">虚拟流量</text>
<text class="text-11px font-600 text-[#212121]">
@@ -1049,7 +1358,7 @@
</view>
<!-- 套餐详情 -->
<view class="space-y-1">
<view v-if="false" class="space-y-1">
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">真实流量</text>
<text class="text-[#212121]">
@@ -1075,9 +1384,9 @@
<text class="text-12px text-[#999]">暂无生效套餐</text>
</view>
<!-- 套餐列表展开时显示 -->
<view v-if="showPackageList && packageList.length > 0" class="mt-3">
<text class="text-13px font-600 text-[#212121] block mb-2">全部套餐 ({{ packageList.length }})</text>
<!-- 套餐列表 -->
<view v-if="packageList.length > 0" class="mt-3">
<text class="text-13px font-600 text-[#212121] block mb-2">套餐列表 ({{ packageList.length }})</text>
<view class="space-y-2">
<view v-for="pkg in packageList" :key="pkg.package_usage_id" class="bg-[#f5f5f5] rounded-12px p-3">
<!-- 套餐头部 -->
@@ -1101,9 +1410,9 @@
<!-- 流量信息 -->
<view class="space-y-0.5">
<view class="flex items-center justify-between text-11px">
<text class="text-[#666]">虚拟流量</text>
<text class="text-[#666]">已使用</text>
<text class="text-[#212121]">
{{ formatDataSize(pkg.virtual_used_mb) }} / {{ formatDataSize(pkg.virtual_limit_mb) }}
{{ formatDataSize(getPackageUsedMb(pkg)) }} / {{ formatDataSize(getPackageTotalMb(pkg)) }}
</text>
</view>
<view v-if="pkg.activated_at" class="flex items-center justify-between text-10px">