Files
gt-agent-company/src/pages/agent-system/index.vue
sexygoat 91d7d4c21f
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 1m27s
fix: 优化界面以及更新接口
2026-04-15 11:54:43 +08:00

1513 lines
55 KiB
Vue

<script setup lang="ts">
import { computed, ref } from 'vue'
const currentTab = ref('my-packages') // my-packages | commission | packages | assets | tags
const currentView = ref('list') // list | detail
// 套餐状态枚举
const packageStatus = {
0: { name: '待生效', color: '#ff9800', bgColor: '#fff3e0' },
1: { name: '生效中', color: '#4caf50', bgColor: '#e8f5e9' },
2: { name: '已用完', color: '#9e9e9e', bgColor: '#f5f5f5' },
3: { name: '已过期', color: '#f44336', bgColor: '#ffebee' },
4: { name: '已失效', color: '#757575', bgColor: '#eeeeee' },
}
// 套餐类型
const packageTypeMap = {
formal: '正式套餐',
addon: '加油包',
}
// 套餐列表数据 (示例)
const packageList = ref([
{
package_usage_id: 1,
package_id: 101,
package_name: '月付套餐 50GB',
package_type: 'formal',
status: 1,
status_name: '生效中',
data_limit_mb: 51200, // 50GB
data_usage_mb: 12800, // 12.5GB
virtual_limit_mb: 102400, // 虚流量100GB
virtual_used_mb: 25600, // 已用虚流量25GB
virtual_remain_mb: 76800, // 剩余虚流量75GB
virtual_ratio: 0.5, // 真实/虚拟比例
priority: 1,
usage_type: 'single_card',
master_usage_id: null,
activated_at: '2024-03-01T10:00:00Z',
expires_at: '2024-04-01T10:00:00Z',
created_at: '2024-02-25T15:30:00Z',
},
{
package_usage_id: 2,
package_id: 102,
package_name: '加油包 20GB',
package_type: 'addon',
status: 1,
status_name: '生效中',
data_limit_mb: 20480, // 20GB
data_usage_mb: 5120, // 5GB
virtual_limit_mb: 40960,
virtual_used_mb: 10240,
virtual_remain_mb: 30720,
virtual_ratio: 0.5,
priority: 2,
usage_type: 'single_card',
master_usage_id: 1,
activated_at: '2024-03-15T14:00:00Z',
expires_at: '2024-04-15T14:00:00Z',
created_at: '2024-03-15T13:00:00Z',
},
{
package_usage_id: 3,
package_id: 103,
package_name: '年付套餐 500GB',
package_type: 'formal',
status: 0,
status_name: '待生效',
data_limit_mb: 512000, // 500GB
data_usage_mb: 0,
virtual_limit_mb: 1024000,
virtual_used_mb: 0,
virtual_remain_mb: 1024000,
virtual_ratio: 0.5,
priority: 3,
usage_type: 'device',
master_usage_id: null,
activated_at: null,
expires_at: null,
created_at: '2024-03-18T09:00:00Z',
},
{
package_usage_id: 4,
package_id: 104,
package_name: '月付套餐 30GB',
package_type: 'formal',
status: 2,
status_name: '已用完',
data_limit_mb: 30720, // 30GB
data_usage_mb: 30720, // 已用完
virtual_limit_mb: 61440,
virtual_used_mb: 61440,
virtual_remain_mb: 0,
virtual_ratio: 0.5,
priority: 4,
usage_type: 'single_card',
master_usage_id: null,
activated_at: '2024-02-01T10:00:00Z',
expires_at: '2024-03-01T10:00:00Z',
created_at: '2024-01-28T11:00:00Z',
},
])
// 选中的套餐详情
const selectedPackage = ref<any>(null)
// 选中的标签 (用于分配)
const selectedTag = ref<any>(null)
// 标签分配模式
const isAssignMode = ref(false)
// 切换Tab
function switchTab(tab: string) {
currentTab.value = tab
currentView.value = 'list'
selectedPackage.value = null
}
// 查看详情
function navigateTo(view: string) {
currentView.value = view
if (view === 'list') {
selectedPackage.value = null
selectedTag.value = null
isAssignMode.value = false
}
}
// 进入标签分配模式
function enterAssignMode(tag: any) {
selectedTag.value = tag
isAssignMode.value = true
currentView.value = 'assign'
}
// 切换资产标签
function toggleAssetTag(asset: any, tagName: string) {
const index = asset.tags.indexOf(tagName)
if (index > -1) {
// 已有该标签,移除
asset.tags.splice(index, 1)
}
else {
// 没有该标签,添加
asset.tags.push(tagName)
}
}
// 查看套餐详情
function viewPackageDetail(pkg: any) {
selectedPackage.value = pkg
currentView.value = 'detail'
}
// 格式化流量 (MB to GB)
function formatDataSize(mb: number): string {
if (mb < 1024)
return `${mb}MB`
return `${(mb / 1024).toFixed(1)}GB`
}
// 计算使用百分比
function calcUsagePercent(used: number, total: number): number {
if (total === 0)
return 0
return Math.min(Math.round((used / total) * 100), 100)
}
// 格式化时间
function formatDate(dateStr: string | null): string {
if (!dateStr)
return '--'
const date = new Date(dateStr)
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`
}
// 格式化日期时间
function formatDateTime(dateStr: string | null): string {
if (!dateStr)
return '--'
const date = new Date(dateStr)
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`
}
// 计算剩余天数
function calcRemainingDays(expiresAt: string | null): number | null {
if (!expiresAt)
return null
const now = new Date()
const expireDate = new Date(expiresAt)
const diff = expireDate.getTime() - now.getTime()
return Math.ceil(diff / (1000 * 60 * 60 * 24))
}
// 统计数据
const stats = computed(() => {
const total = packageList.value.length
const active = packageList.value.filter(p => p.status === 1).length
const pending = packageList.value.filter(p => p.status === 0).length
const expired = packageList.value.filter(p => p.status === 3 || p.status === 4).length
return [
{ label: '套餐总数', value: total.toString(), unit: '个', icon: 'i-mdi-package-variant', color: '#2196f3' },
{ label: '生效中', value: active.toString(), unit: '个', icon: 'i-mdi-check-circle', color: '#4caf50' },
{ label: '待生效', value: pending.toString(), unit: '个', icon: 'i-mdi-clock', color: '#ff9800' },
{ label: '已过期', value: expired.toString(), unit: '个', icon: 'i-mdi-alert-circle', color: '#f44336' },
]
})
// 标签列表数据 (示例)
const tagList = ref([
{ id: 1, name: '热门推荐', color: '#ff6700', asset_count: 12, description: '热门高转化资产' },
{ id: 2, name: '新品上架', color: '#4caf50', asset_count: 8, description: '最近30天上架' },
{ id: 3, name: 'VIP专享', color: '#2196f3', asset_count: 6, description: 'VIP用户专属' },
{ id: 4, name: '限时优惠', color: '#ff9800', asset_count: 15, description: '限时促销活动' },
{ id: 5, name: '高佣金', color: '#9c27b0', asset_count: 10, description: '佣金比例较高' },
{ id: 6, name: '长期有效', color: '#00bcd4', asset_count: 20, description: '长期有效套餐' },
])
// 资产列表数据 (示例)
const assetList = ref([
{
id: 1,
name: '资产名称 A1',
code: 'AST-2024-001',
tags: ['热门'],
status: 'active',
package_count: 2,
total_data_mb: 71680, // 70GB
},
{
id: 2,
name: '资产名称 B2',
code: 'AST-2024-002',
tags: ['新品'],
status: 'active',
package_count: 1,
total_data_mb: 51200, // 50GB
},
{
id: 3,
name: '资产名称 C3',
code: 'AST-2024-003',
tags: [],
status: 'inactive',
package_count: 0,
total_data_mb: 0,
},
])
// 佣金概览数据 (示例)
const commissionOverview = ref({
shop_id: 1,
shop_name: '示例店铺',
total_commission: 125800, // 1258.00元 (分)
available_commission: 85000, // 850.00元
withdrawn_commission: 30000, // 300.00元
withdrawing_commission: 10000, // 100.00元
frozen_commission: 800, // 8.00元
unwithdraw_commission: 95800, // 958.00元
})
// 佣金统计数据 (示例)
const commissionStats = ref({
total_amount: 125800, // 1258.00元
total_count: 156,
cost_diff_amount: 95000, // 950.00元
cost_diff_count: 120,
cost_diff_percent: 755, // 75.5%
one_time_amount: 30800, // 308.00元
one_time_count: 36,
one_time_percent: 245, // 24.5%
})
// 每日佣金统计 (示例)
const dailyCommission = ref([
{ date: '2024-03-18', total_amount: 12800, total_count: 8 },
{ date: '2024-03-17', total_amount: 15600, total_count: 12 },
{ date: '2024-03-16', total_amount: 9800, total_count: 6 },
{ date: '2024-03-15', total_amount: 18900, total_count: 15 },
{ date: '2024-03-14', total_amount: 11200, total_count: 9 },
])
// 佣金明细列表 (示例)
const commissionDetails = ref([
{
id: 1,
order_id: 1001,
shop_id: 1,
amount: 12800, // 128.00元
commission_source: 'cost_diff',
status: 1,
status_name: '已入账',
created_at: '2024-03-18T14:32:00Z',
},
{
id: 2,
order_id: 1002,
shop_id: 1,
amount: 5600, // 56.00元
commission_source: 'one_time',
status: 1,
status_name: '已入账',
created_at: '2024-03-18T10:15:00Z',
},
{
id: 3,
order_id: 1003,
shop_id: 1,
amount: 8900, // 89.00元
commission_source: 'cost_diff',
status: 1,
status_name: '已入账',
created_at: '2024-03-17T16:48:00Z',
},
{
id: 4,
order_id: 1004,
shop_id: 1,
amount: 3200, // 32.00元
commission_source: 'one_time',
status: 2,
status_name: '已失效',
created_at: '2024-03-17T09:20:00Z',
},
])
// 佣金来源映射
const commissionSourceMap: Record<string, string> = {
cost_diff: '成本价差',
one_time: '一次性佣金',
tier_bonus: '梯度奖励',
}
// 格式化金额 (分 to 元)
function formatAmount(cents: number): string {
return (cents / 100).toFixed(2)
}
// 我的套餐使用情况数据 (示例)
const myPackageUsage = ref({
main_package: {
package_usage_id: 1,
package_id: 101,
package_name: '月付套餐 50GB',
status: 1,
status_text: '生效中',
total_mb: 51200, // 50GB
used_mb: 12800, // 12.5GB
priority: 1,
activated_at: '2024-03-01T10:00:00Z',
expires_at: '2024-04-01T10:00:00Z',
},
addon_packages: [
{
package_usage_id: 2,
package_id: 102,
package_name: '加油包 20GB',
status: 1,
status_text: '生效中',
total_mb: 20480, // 20GB
used_mb: 5120, // 5GB
priority: 2,
activated_at: '2024-03-15T14:00:00Z',
expires_at: '2024-04-15T14:00:00Z',
},
{
package_usage_id: 5,
package_id: 105,
package_name: '加油包 10GB',
status: 0,
status_text: '待生效',
total_mb: 10240, // 10GB
used_mb: 0,
priority: 3,
activated_at: null,
expires_at: null,
},
],
total: {
total_mb: 81920, // 80GB (50+20+10)
used_mb: 17920, // 17.5GB (12.5+5)
},
})
// 资产统计
const assetStats = computed(() => {
const total = assetList.value.length
const active = assetList.value.filter(a => a.status === 'active').length
const totalPackages = assetList.value.reduce((sum, a) => sum + a.package_count, 0)
const totalData = assetList.value.reduce((sum, a) => sum + a.total_data_mb, 0)
return [
{ label: '资产总数', value: total.toString(), unit: '个', icon: 'i-mdi-package-variant', color: '#2196f3' },
{ label: '激活中', value: active.toString(), unit: '个', icon: 'i-mdi-check-circle', color: '#4caf50' },
{ label: '套餐总数', value: totalPackages.toString(), unit: '个', icon: 'i-mdi-gift', color: '#ff9800' },
{ label: '总流量', value: formatDataSize(totalData), unit: '', icon: 'i-mdi-database', color: '#ff6700' },
]
})
// 筛选状态
const filterStatus = ref<number | null>(null)
// 筛选后的套餐列表
const filteredPackages = computed(() => {
if (filterStatus.value === null) {
return packageList.value
}
return packageList.value.filter(p => p.status === filterStatus.value)
})
</script>
<template>
<view class="mobile-agent-system bg-[#fafafa] min-h-screen pb-safe">
<!-- 主内容区 -->
<view class="px-4 pt-4">
<!-- Tab 切换 -->
<view class="grid grid-cols-5 gap-1 bg-[#f5f5f5] rounded-full p-1 mb-4">
<button
:class="{
'bg-white shadow-sm text-[#212121]': currentTab === 'my-packages',
'text-[#9e9e9e]': currentTab !== 'my-packages'
}"
class="py-2 rounded-full text-11px font-500 transition-all duration-200"
@click="switchTab('my-packages')"
>
我的套餐
</button>
<button
:class="{
'bg-white shadow-sm text-[#212121]': currentTab === 'commission',
'text-[#9e9e9e]': currentTab !== 'commission'
}"
class="py-2 rounded-full text-11px font-500 transition-all duration-200"
@click="switchTab('commission')"
>
我的佣金
</button>
<button
:class="{
'bg-white shadow-sm text-[#212121]': currentTab === 'packages',
'text-[#9e9e9e]': currentTab !== 'packages'
}"
class="py-2 rounded-full text-11px font-500 transition-all duration-200"
@click="switchTab('packages')"
>
套餐列表
</button>
<button
:class="{
'bg-white shadow-sm text-[#212121]': currentTab === 'assets',
'text-[#9e9e9e]': currentTab !== 'assets'
}"
class="py-2 rounded-full text-11px font-500 transition-all duration-200"
@click="switchTab('assets')"
>
资产列表
</button>
<button
:class="{
'bg-white shadow-sm text-[#212121]': currentTab === 'tags',
'text-[#9e9e9e]': currentTab !== 'tags'
}"
class="py-2 rounded-full text-11px font-500 transition-all duration-200"
@click="switchTab('tags')"
>
标签管理
</button>
</view>
<!-- 我的佣金 -->
<view v-if="currentTab === 'commission'">
<!-- 佣金概览卡片 (绿色渐变) -->
<view class="
bg-gradient-to-br from-[#4caf50] to-[#66bb6a]
rounded-16px p-6 mb-4
shadow-[0_8px_24px_rgba(76,175,80,0.2)]
">
<text class="text-13px text-white/70 block mb-2">可提现佣金</text>
<text class="text-48px font-700 text-white block mb-4">
¥{{ formatAmount(commissionOverview.available_commission) }}
</text>
<view class="flex items-center gap-6 mb-4">
<view>
<text class="text-11px text-white/60 block">累计佣金</text>
<text class="text-16px font-600 text-white">¥{{ formatAmount(commissionOverview.total_commission) }}</text>
</view>
<view class="w-1px h-24px bg-white/20" />
<view>
<text class="text-11px text-white/60 block">已提现</text>
<text class="text-16px font-600 text-white">¥{{ formatAmount(commissionOverview.withdrawn_commission) }}</text>
</view>
</view>
<button class="
w-full
bg-white text-[#4caf50]
py-3 rounded-8px
text-15px font-600
active:scale-98
transition-transform duration-200
">
立即提现
</button>
</view>
<!-- 佣金状态卡片组 -->
<view class="grid grid-cols-3 gap-2 mb-4">
<view class="bg-white rounded-8px p-3 text-center shadow-[0_2px_8px_rgba(0,0,0,0.04)]">
<text class="text-11px text-[#9e9e9e] block mb-1">提现中</text>
<text class="text-16px font-600 text-[#ff9800]">¥{{ formatAmount(commissionOverview.withdrawing_commission) }}</text>
</view>
<view class="bg-white rounded-8px p-3 text-center shadow-[0_2px_8px_rgba(0,0,0,0.04)]">
<text class="text-11px text-[#9e9e9e] block mb-1">冻结中</text>
<text class="text-16px font-600 text-[#f44336]">¥{{ formatAmount(commissionOverview.frozen_commission) }}</text>
</view>
<view class="bg-white rounded-8px p-3 text-center shadow-[0_2px_8px_rgba(0,0,0,0.04)]">
<text class="text-11px text-[#9e9e9e] block mb-1">未提现</text>
<text class="text-16px font-600 text-[#2196f3]">¥{{ formatAmount(commissionOverview.unwithdraw_commission) }}</text>
</view>
</view>
<!-- 佣金统计 -->
<view class="bg-white rounded-12px p-4 mb-4 shadow-[0_2px_8px_rgba(0,0,0,0.04)]">
<text class="text-16px font-600 text-[#212121] block mb-3">佣金统计</text>
<view class="space-y-3">
<!-- 总计 -->
<view class="flex items-center justify-between pb-3 border-b border-[#eeeeee]">
<view>
<text class="text-13px text-[#757575] block">总收入</text>
<text class="text-11px text-[#bdbdbd]">{{ commissionStats.total_count }} </text>
</view>
<text class="text-20px font-700 text-[#212121]">
¥{{ formatAmount(commissionStats.total_amount) }}
</text>
</view>
<!-- 成本价差 -->
<view class="flex items-center justify-between">
<view class="flex-1">
<view class="flex items-center gap-2 mb-1">
<text class="text-13px text-[#757575]">成本价差</text>
<span class="px-2 py-0.5 bg-[#e3f2fd] text-[#2196f3] text-10px rounded-full">
{{ (commissionStats.cost_diff_percent / 10).toFixed(1) }}%
</span>
</view>
<text class="text-11px text-[#bdbdbd]">{{ commissionStats.cost_diff_count }} </text>
</view>
<text class="text-18px font-600 text-[#212121]">
¥{{ formatAmount(commissionStats.cost_diff_amount) }}
</text>
</view>
<!-- 一次性佣金 -->
<view class="flex items-center justify-between">
<view class="flex-1">
<view class="flex items-center gap-2 mb-1">
<text class="text-13px text-[#757575]">一次性佣金</text>
<span class="px-2 py-0.5 bg-[#fff3e0] text-[#ff9800] text-10px rounded-full">
{{ (commissionStats.one_time_percent / 10).toFixed(1) }}%
</span>
</view>
<text class="text-11px text-[#bdbdbd]">{{ commissionStats.one_time_count }} </text>
</view>
<text class="text-18px font-600 text-[#212121]">
¥{{ formatAmount(commissionStats.one_time_amount) }}
</text>
</view>
</view>
</view>
<!-- 每日佣金统计 -->
<view class="bg-white rounded-12px p-4 mb-4 shadow-[0_2px_8px_rgba(0,0,0,0.04)]">
<view class="flex items-center justify-between mb-3">
<text class="text-16px font-600 text-[#212121]">每日收入</text>
<text class="text-12px text-[#9e9e9e]">近7日</text>
</view>
<view class="space-y-2">
<view
v-for="item in dailyCommission"
:key="item.date"
class="
flex items-center justify-between
p-3 rounded-8px
bg-[#fafafa]
"
>
<view>
<text class="text-13px text-[#212121] block mb-1">{{ item.date }}</text>
<text class="text-11px text-[#9e9e9e]">{{ item.total_count }} </text>
</view>
<text class="text-16px font-600 text-[#4caf50]">
+¥{{ formatAmount(item.total_amount) }}
</text>
</view>
</view>
</view>
<!-- 佣金明细 -->
<view class="bg-white rounded-12px p-4 shadow-[0_2px_8px_rgba(0,0,0,0.04)]">
<view class="flex items-center justify-between mb-3">
<text class="text-16px font-600 text-[#212121]">佣金明细</text>
<button class="text-13px text-[var(--brand-primary)]">查看全部 </button>
</view>
<view class="space-y-3">
<view
v-for="detail in commissionDetails.slice(0, 5)"
:key="detail.id"
class="
flex items-center justify-between
pb-3
border-b border-[#eeeeee]
last:border-0
"
>
<view class="flex-1">
<view class="flex items-center gap-2 mb-1">
<text class="text-14px font-500 text-[#212121]">
订单 #{{ detail.order_id }}
</text>
<span
:style="{
color: detail.status === 1 ? '#4caf50' : '#f44336',
backgroundColor: detail.status === 1 ? '#e8f5e9' : '#ffebee'
}"
class="px-2 py-0.5 text-10px rounded-full"
>
{{ detail.status_name }}
</span>
</view>
<view class="flex items-center gap-3 text-11px text-[#9e9e9e]">
<text>{{ commissionSourceMap[detail.commission_source] }}</text>
<text>{{ formatDateTime(detail.created_at) }}</text>
</view>
</view>
<text
:class="{
'text-[#4caf50]': detail.status === 1,
'text-[#9e9e9e]': detail.status === 2
}"
class="text-18px font-600"
>
+¥{{ formatAmount(detail.amount) }}
</text>
</view>
</view>
</view>
</view>
<!-- 我的套餐使用情况 -->
<view v-if="currentTab === 'my-packages'">
<!-- 总计卡片 (橙色渐变) -->
<view class="
bg-gradient-to-br from-[var(--brand-primary)] to-[var(--brand-primary-light)]
rounded-16px p-6 mb-4
shadow-brand-colored
">
<text class="text-13px text-white/70 block mb-2">套餐总计</text>
<view class="flex items-end gap-2 mb-4">
<text class="text-40px font-700 text-white">
{{ formatDataSize(myPackageUsage.total.used_mb) }}
</text>
<text class="text-16px text-white/80 mb-1">
/ {{ formatDataSize(myPackageUsage.total.total_mb) }}
</text>
</view>
<!-- 进度条 -->
<view class="w-full h-8px bg-white/20 rounded-full overflow-hidden mb-4">
<view
:style="{
width: calcUsagePercent(myPackageUsage.total.used_mb, myPackageUsage.total.total_mb) + '%'
}"
class="h-full bg-white rounded-full transition-all duration-300"
/>
</view>
<!-- 统计 -->
<view class="flex items-center justify-between text-white/80 text-12px">
<text>使用率: {{ calcUsagePercent(myPackageUsage.total.used_mb, myPackageUsage.total.total_mb) }}%</text>
<text>剩余: {{ formatDataSize(myPackageUsage.total.total_mb - myPackageUsage.total.used_mb) }}</text>
</view>
</view>
<!-- 主套餐 -->
<view v-if="myPackageUsage.main_package" class="mb-4">
<text class="text-15px font-600 text-[#212121] block mb-3">主套餐</text>
<view class="
bg-white rounded-12px p-4
shadow-[0_2px_8px_rgba(0,0,0,0.04)]
border-2 border-[var(--brand-primary)]/20
">
<view class="flex items-start justify-between mb-3">
<text class="text-16px font-600 text-[#212121]">
{{ myPackageUsage.main_package.package_name }}
</text>
<span
:style="{
color: packageStatus[myPackageUsage.main_package.status].color,
backgroundColor: packageStatus[myPackageUsage.main_package.status].bgColor
}"
class="px-3 py-1 text-12px font-500 rounded-full"
>
{{ myPackageUsage.main_package.status_text }}
</span>
</view>
<!-- 流量进度 -->
<view class="mb-3">
<view class="flex items-center justify-between mb-1">
<text class="text-12px text-[#757575]">流量使用</text>
<text class="text-13px font-600 text-[#212121]">
{{ formatDataSize(myPackageUsage.main_package.used_mb) }} /
{{ formatDataSize(myPackageUsage.main_package.total_mb) }}
</text>
</view>
<view class="w-full h-8px bg-[#f5f5f5] rounded-full overflow-hidden">
<view
:style="{
width: calcUsagePercent(myPackageUsage.main_package.used_mb, myPackageUsage.main_package.total_mb) + '%',
backgroundColor: myPackageUsage.main_package.status === 2 ? '#f44336' : '#4caf50'
}"
class="h-full transition-all duration-300 rounded-full"
/>
</view>
</view>
<!-- 时间信息 -->
<view class="flex items-center justify-between text-11px text-[#bdbdbd]">
<view class="flex items-center gap-1">
<i class="i-mdi-clock-outline w-12px h-12px" />
<text>激活: {{ formatDate(myPackageUsage.main_package.activated_at) }}</text>
</view>
<view class="flex items-center gap-1">
<i class="i-mdi-calendar-clock w-12px h-12px" />
<text>到期: {{ formatDate(myPackageUsage.main_package.expires_at) }}</text>
<template v-if="myPackageUsage.main_package.status === 1 && calcRemainingDays(myPackageUsage.main_package.expires_at)">
<text
:class="{
'text-[#f44336]': calcRemainingDays(myPackageUsage.main_package.expires_at)! <= 7,
'text-[#ff9800]': calcRemainingDays(myPackageUsage.main_package.expires_at)! > 7 && calcRemainingDays(myPackageUsage.main_package.expires_at)! <= 30
}"
>
({{ calcRemainingDays(myPackageUsage.main_package.expires_at) }})
</text>
</template>
</view>
</view>
</view>
</view>
<!-- 加油包列表 -->
<view v-if="myPackageUsage.addon_packages && myPackageUsage.addon_packages.length > 0">
<view class="flex items-center justify-between mb-3">
<text class="text-15px font-600 text-[#212121]">加油包</text>
<text class="text-12px text-[#9e9e9e]">
{{ myPackageUsage.addon_packages.length }}
</text>
</view>
<view class="space-y-2">
<view
v-for="addon in myPackageUsage.addon_packages"
:key="addon.package_usage_id"
class="
bg-white rounded-12px p-4
shadow-[0_2px_8px_rgba(0,0,0,0.04)]
border border-[#eeeeee]
"
>
<view class="flex items-start justify-between mb-2">
<view class="flex-1">
<text class="text-15px font-600 text-[#212121] block mb-1">
{{ addon.package_name }}
</text>
<text class="text-11px text-[#9e9e9e]">
优先级: {{ addon.priority }}
</text>
</view>
<span
:style="{
color: packageStatus[addon.status].color,
backgroundColor: packageStatus[addon.status].bgColor
}"
class="px-2 py-1 text-11px font-500 rounded-full"
>
{{ addon.status_text }}
</span>
</view>
<!-- 流量进度 -->
<view class="mb-2">
<view class="flex items-center justify-between mb-1">
<text class="text-11px text-[#757575]">流量</text>
<text class="text-12px font-600 text-[#212121]">
{{ formatDataSize(addon.used_mb) }} / {{ formatDataSize(addon.total_mb) }}
</text>
</view>
<view class="w-full h-6px bg-[#f5f5f5] rounded-full overflow-hidden">
<view
:style="{
width: calcUsagePercent(addon.used_mb, addon.total_mb) + '%',
backgroundColor: addon.status === 2 ? '#f44336' : addon.status === 1 ? '#4caf50' : '#9e9e9e'
}"
class="h-full transition-all duration-300 rounded-full"
/>
</view>
</view>
<!-- 时间 -->
<view v-if="addon.status !== 0" class="flex items-center justify-between text-11px text-[#bdbdbd]">
<text>激活: {{ formatDate(addon.activated_at) }}</text>
<text>到期: {{ formatDate(addon.expires_at) }}</text>
</view>
<text v-else class="text-11px text-[#ff9800]">等待激活</text>
</view>
</view>
</view>
<!-- 无加油包 -->
<view v-else class="bg-white rounded-12px p-6 text-center">
<i class="i-mdi-gift-outline w-48px h-48px text-[#e0e0e0] mb-2" />
<text class="text-13px text-[#9e9e9e] block mb-3">暂无加油包</text>
<button class="
bg-[var(--brand-primary)] text-white
px-5 py-2 rounded-8px
text-13px font-500
">
购买加油包
</button>
</view>
</view>
<!-- 套餐列表 -->
<view v-if="currentTab === 'packages' && currentView === 'list'">
<!-- 统计卡片 -->
<view class="grid grid-cols-2 gap-3 mb-4">
<view
v-for="stat in stats"
:key="stat.label"
class="bg-white rounded-12px p-4 shadow-[0_2px_8px_rgba(0,0,0,0.04)]"
>
<view class="flex items-center justify-between mb-3">
<text class="text-13px text-[#9e9e9e]">{{ stat.label }}</text>
<view
:style="{ backgroundColor: stat.color + '20' }"
class="w-32px h-32px rounded-full center"
>
<i :class="stat.icon" :style="{ color: stat.color }" class="w-18px h-18px" />
</view>
</view>
<text class="text-24px font-700 text-[#212121] block">
{{ stat.value }}
</text>
<text class="text-11px text-[#bdbdbd]">{{ stat.unit }}</text>
</view>
</view>
<!-- 筛选标签 -->
<view class="flex gap-2 mb-3 overflow-x-auto pb-2">
<button
:class="{
'bg-[var(--brand-primary-light)] text-[var(--brand-primary)]': filterStatus === null,
'text-[#9e9e9e]': filterStatus !== null
}"
class="px-4 py-1.5 rounded-full text-13px font-500 whitespace-nowrap"
@click="filterStatus = null"
>
全部 ({{ packageList.length }})
</button>
<button
:class="{
'bg-[#e8f5e9] text-[#4caf50]': filterStatus === 1,
'text-[#9e9e9e]': filterStatus !== 1
}"
class="px-4 py-1.5 rounded-full text-13px font-500 whitespace-nowrap"
@click="filterStatus = 1"
>
生效中
</button>
<button
:class="{
'bg-[#fff3e0] text-[#ff9800]': filterStatus === 0,
'text-[#9e9e9e]': filterStatus !== 0
}"
class="px-4 py-1.5 rounded-full text-13px font-500 whitespace-nowrap"
@click="filterStatus = 0"
>
待生效
</button>
<button
:class="{
'bg-[#ffebee] text-[#f44336]': filterStatus === 3,
'text-[#9e9e9e]': filterStatus !== 3
}"
class="px-4 py-1.5 rounded-full text-13px font-500 whitespace-nowrap"
@click="filterStatus = 3"
>
已过期
</button>
</view>
<!-- 套餐卡片列表 -->
<view class="space-y-3">
<view
v-for="pkg in filteredPackages"
:key="pkg.package_usage_id"
class="
bg-white rounded-12px p-4
shadow-[0_2px_8px_rgba(0,0,0,0.04)]
border border-[#eeeeee]
cursor-pointer
"
@click="viewPackageDetail(pkg)"
>
<!-- 套餐名称 + 状态 -->
<view class="flex items-start justify-between mb-3">
<view class="flex-1">
<text class="text-16px font-600 text-[#212121] block mb-1">
{{ pkg.package_name }}
</text>
<view class="flex items-center gap-2">
<span
:style="{ color: pkg.package_type === 'addon' ? '#ff9800' : '#2196f3' }"
class="text-11px"
>
{{ packageTypeMap[pkg.package_type] }}
</span>
<span class="text-11px text-[#bdbdbd]">
优先级: {{ pkg.priority }}
</span>
</view>
</view>
<span
:style="{
color: packageStatus[pkg.status].color,
backgroundColor: packageStatus[pkg.status].bgColor
}"
class="px-3 py-1 text-12px font-500 rounded-full"
>
{{ pkg.status_name }}
</span>
</view>
<!-- 流量使用情况 -->
<view class="mb-3">
<!-- 虚流量 -->
<view class="mb-2">
<view class="flex items-center justify-between mb-1">
<text class="text-12px text-[#757575]">虚流量使用</text>
<text class="text-13px font-600 text-[#212121]">
{{ formatDataSize(pkg.virtual_used_mb) }} / {{ formatDataSize(pkg.virtual_limit_mb) }}
</text>
</view>
<view class="w-full h-8px bg-[#f5f5f5] rounded-full overflow-hidden">
<view
:style="{
width: calcUsagePercent(pkg.virtual_used_mb, pkg.virtual_limit_mb) + '%',
backgroundColor: pkg.status === 2 ? '#f44336' : pkg.status === 1 ? '#4caf50' : '#9e9e9e'
}"
class="h-full transition-all duration-300 rounded-full"
/>
</view>
</view>
<!-- 真流量 -->
<view class="flex items-center justify-between">
<text class="text-11px text-[#9e9e9e]">真流量</text>
<text class="text-11px text-[#757575]">
{{ formatDataSize(pkg.data_usage_mb) }} / {{ formatDataSize(pkg.data_limit_mb) }}
</text>
</view>
</view>
<!-- 时间信息 -->
<view class="flex items-center justify-between text-11px text-[#bdbdbd]">
<view class="flex items-center gap-1">
<i class="i-mdi-clock-outline w-12px h-12px" />
<text>激活: {{ formatDate(pkg.activated_at) }}</text>
</view>
<view class="flex items-center gap-1">
<i class="i-mdi-calendar-clock w-12px h-12px" />
<text>到期: {{ formatDate(pkg.expires_at) }}</text>
<template v-if="pkg.status === 1 && calcRemainingDays(pkg.expires_at)">
<text
:class="{
'text-[#f44336]': calcRemainingDays(pkg.expires_at)! <= 7,
'text-[#ff9800]': calcRemainingDays(pkg.expires_at)! > 7 && calcRemainingDays(pkg.expires_at)! <= 30
}"
>
({{ calcRemainingDays(pkg.expires_at) }})
</text>
</template>
</view>
</view>
</view>
</view>
<!-- 空状态 -->
<view v-if="filteredPackages.length === 0" class="center flex-col py-16">
<i class="i-mdi-package-variant-closed w-64px h-64px text-[#e0e0e0] mb-3" />
<text class="text-14px text-[#9e9e9e]">暂无套餐数据</text>
</view>
</view>
<!-- 资产列表 -->
<view v-if="currentTab === 'assets' && currentView === 'list'">
<!-- 统计卡片 -->
<view class="grid grid-cols-2 gap-3 mb-4">
<view
v-for="stat in assetStats"
:key="stat.label"
class="bg-white rounded-12px p-4 shadow-[0_2px_8px_rgba(0,0,0,0.04)]"
>
<view class="flex items-center justify-between mb-3">
<text class="text-13px text-[#9e9e9e]">{{ stat.label }}</text>
<view
:style="{ backgroundColor: stat.color + '20' }"
class="w-32px h-32px rounded-full center"
>
<i :class="stat.icon" :style="{ color: stat.color }" class="w-18px h-18px" />
</view>
</view>
<text class="text-24px font-700 text-[#212121] block">
{{ stat.value }}
</text>
<text v-if="stat.unit" class="text-11px text-[#bdbdbd]">{{ stat.unit }}</text>
</view>
</view>
<!-- 资产卡片列表 -->
<view class="space-y-3">
<view
v-for="asset in assetList"
:key="asset.id"
class="
bg-white rounded-12px p-4
shadow-[0_2px_8px_rgba(0,0,0,0.04)]
border border-[#eeeeee]
cursor-pointer
"
>
<view class="flex items-start gap-3">
<!-- 缩略图 -->
<view class="w-56px h-56px bg-[#f5f5f5] rounded-8px center flex-shrink-0">
<i class="i-mdi-package-variant w-28px h-28px text-[#bdbdbd]" />
</view>
<!-- 信息 -->
<view class="flex-1">
<text class="text-15px font-600 text-[#212121] block mb-1">
{{ asset.name }}
</text>
<text class="text-12px text-[#9e9e9e] block mb-2">
编号: {{ asset.code }}
</text>
<view class="flex items-center justify-between">
<!-- 标签 -->
<view class="flex gap-1">
<span
v-for="tag in asset.tags"
:key="tag"
class="px-2 py-0.5 bg-[var(--brand-primary-light)] text-[var(--brand-primary)] text-11px rounded-full"
>
{{ tag }}
</span>
<span
v-if="asset.status === 'active'"
class="px-2 py-0.5 bg-[#e8f5e9] text-[#4caf50] text-11px rounded-full"
>
激活
</span>
<span
v-else
class="px-2 py-0.5 bg-[#f5f5f5] text-[#9e9e9e] text-11px rounded-full"
>
未激活
</span>
</view>
<!-- 箭头 -->
<i class="i-mdi-chevron-right w-20px h-20px text-[#bdbdbd]" />
</view>
<!-- 套餐信息 -->
<view class="flex items-center gap-4 mt-2 text-11px text-[#757575]">
<view class="flex items-center gap-1">
<i class="i-mdi-gift w-12px h-12px" />
<text>{{ asset.package_count }} 个套餐</text>
</view>
<view class="flex items-center gap-1">
<i class="i-mdi-database w-12px h-12px" />
<text>{{ formatDataSize(asset.total_data_mb) }}</text>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 空状态 -->
<view v-if="assetList.length === 0" class="center flex-col py-16">
<i class="i-mdi-package-variant-closed w-64px h-64px text-[#e0e0e0] mb-3" />
<text class="text-14px text-[#9e9e9e]">暂无资产数据</text>
</view>
</view>
<!-- 标签管理 -->
<view v-if="currentTab === 'tags' && currentView === 'list'">
<!-- 标签统计 -->
<view class="bg-white rounded-12px p-4 mb-4 shadow-[0_2px_8px_rgba(0,0,0,0.04)]">
<view class="flex items-center justify-between">
<view class="flex-1 text-center border-r border-[#eeeeee]">
<text class="text-24px font-700 text-[#212121] block">{{ tagList.length }}</text>
<text class="text-11px text-[#9e9e9e]">标签总数</text>
</view>
<view class="flex-1 text-center">
<text class="text-24px font-700 text-[var(--brand-primary)] block">
{{ tagList.reduce((sum, t) => sum + t.asset_count, 0) }}
</text>
<text class="text-11px text-[#9e9e9e]">已分配资产</text>
</view>
</view>
</view>
<!-- 标签网格 -->
<view class="grid grid-cols-2 gap-3">
<view
v-for="tag in tagList"
:key="tag.id"
class="
bg-white rounded-12px p-4
shadow-[0_2px_8px_rgba(0,0,0,0.04)]
border-2 border-[#eeeeee]
cursor-pointer
"
>
<view class="flex items-center justify-between mb-3">
<view
:style="{ backgroundColor: tag.color }"
class="w-40px h-40px rounded-full center"
>
<i class="i-mdi-tag w-20px h-20px text-white" />
</view>
<button
class="w-32px h-32px center hover:bg-[#f5f5f5] rounded-full"
@click.stop
>
<i class="i-mdi-dots-vertical w-18px h-18px text-[#9e9e9e]" />
</button>
</view>
<text class="text-15px font-600 text-[#212121] block mb-1">
{{ tag.name }}
</text>
<text class="text-12px text-[#9e9e9e] block mb-3">
{{ tag.description }}
</text>
<view class="flex items-center justify-between">
<text class="text-11px text-[#bdbdbd]">
已分配 {{ tag.asset_count }} 个资产
</text>
<button
class="text-12px text-[var(--brand-primary)] font-500"
@click="enterAssignMode(tag)"
>
分配
</button>
</view>
</view>
</view>
<!-- 创建标签按钮 -->
<button class="
w-full
mt-4
bg-[var(--brand-primary)] text-white
py-3 rounded-12px
text-14px font-500
flex items-center justify-center gap-2
shadow-brand-xs
">
<i class="i-mdi-plus w-18px h-18px" />
创建新标签
</button>
</view>
<!-- 标签分配页面 -->
<view v-if="currentTab === 'tags' && currentView === 'assign' && selectedTag">
<!-- 返回按钮 -->
<button
class="flex items-center gap-2 mb-4 text-[#757575]"
@click="navigateTo('list')"
>
<i class="i-mdi-chevron-left w-20px h-20px" />
<text class="text-14px">返回</text>
</button>
<!-- 标签信息卡片 -->
<view class="bg-white rounded-12px p-4 mb-4 shadow-[0_2px_8px_rgba(0,0,0,0.04)]">
<view class="flex items-center gap-3">
<view
:style="{ backgroundColor: selectedTag.color }"
class="w-48px h-48px rounded-full center"
>
<i class="i-mdi-tag w-24px h-24px text-white" />
</view>
<view class="flex-1">
<text class="text-18px font-700 text-[#212121] block mb-1">
{{ selectedTag.name }}
</text>
<text class="text-12px text-[#9e9e9e]">
{{ selectedTag.description }}
</text>
</view>
</view>
</view>
<!-- 资产列表 (可勾选) -->
<text class="text-15px font-600 text-[#212121] block mb-3">
选择要分配的资产 ({{ assetList.filter(a => a.tags.includes(selectedTag.name)).length }}/{{ assetList.length }})
</text>
<view class="space-y-2 mb-4">
<view
v-for="asset in assetList"
:key="asset.id"
class="
bg-white rounded-12px p-4
shadow-[0_2px_8px_rgba(0,0,0,0.04)]
border border-[#eeeeee]
flex items-center gap-3
cursor-pointer
"
@click="toggleAssetTag(asset, selectedTag.name)"
>
<!-- 勾选框 -->
<view
:class="{
'bg-[var(--brand-primary)] border-[var(--brand-primary)]': asset.tags.includes(selectedTag.name),
'bg-white border-[#e0e0e0]': !asset.tags.includes(selectedTag.name)
}"
class="
w-20px h-20px
rounded-4px
border-2
center
transition-all duration-200
"
>
<i
v-if="asset.tags.includes(selectedTag.name)"
class="i-mdi-check w-14px h-14px text-white"
/>
</view>
<!-- 资产信息 -->
<view class="flex-1">
<text class="text-14px font-500 text-[#212121] block mb-1">
{{ asset.name }}
</text>
<text class="text-11px text-[#9e9e9e]">
编号: {{ asset.code }}
</text>
</view>
<!-- 状态 -->
<span
v-if="asset.status === 'active'"
class="px-2 py-0.5 bg-[#e8f5e9] text-[#4caf50] text-11px rounded-full"
>
激活
</span>
</view>
</view>
<!-- 保存按钮 -->
<view class="fixed bottom-0 left-0 right-0 bg-white p-4 pb-safe border-t border-[#eeeeee]">
<button class="
w-full
bg-[var(--brand-primary)] text-white
py-3 rounded-8px
text-15px font-600
shadow-brand-xs
">
保存分配
</button>
</view>
</view>
<!-- 套餐详情 -->
<view v-if="currentTab === 'packages' && currentView === 'detail' && selectedPackage">
<!-- 返回按钮 -->
<button
class="flex items-center gap-2 mb-4 text-[#757575]"
@click="navigateTo('list')"
>
<i class="i-mdi-chevron-left w-20px h-20px" />
<text class="text-14px">返回</text>
</button>
<!-- 套餐基本信息卡片 -->
<view class="bg-white rounded-12px p-4 mb-3 shadow-[0_2px_8px_rgba(0,0,0,0.04)]">
<view class="flex items-start justify-between mb-3">
<text class="text-18px font-700 text-[#212121]">
{{ selectedPackage.package_name }}
</text>
<span
:style="{
color: packageStatus[selectedPackage.status].color,
backgroundColor: packageStatus[selectedPackage.status].bgColor
}"
class="px-3 py-1.5 text-13px font-600 rounded-full"
>
{{ selectedPackage.status_name }}
</span>
</view>
<view class="grid grid-cols-2 gap-3">
<view class="flex items-center gap-2">
<i class="i-mdi-tag-outline w-16px h-16px text-[#9e9e9e]" />
<text class="text-13px text-[#757575]">
套餐类型: <text class="text-[#212121] font-500">{{ packageTypeMap[selectedPackage.package_type] }}</text>
</text>
</view>
<view class="flex items-center gap-2">
<i class="i-mdi-sort-numeric-ascending w-16px h-16px text-[#9e9e9e]" />
<text class="text-13px text-[#757575]">
优先级: <text class="text-[#212121] font-500">{{ selectedPackage.priority }}</text>
</text>
</view>
<view v-if="selectedPackage.master_usage_id" class="flex items-center gap-2 col-span-2">
<i class="i-mdi-link-variant w-16px h-16px text-[#9e9e9e]" />
<text class="text-13px text-[#757575]">
主套餐ID: <text class="text-[#212121] font-500">{{ selectedPackage.master_usage_id }}</text>
</text>
</view>
</view>
</view>
<!-- 流量使用详情 -->
<view class="bg-white rounded-12px p-4 mb-3 shadow-[0_2px_8px_rgba(0,0,0,0.04)]">
<text class="text-16px font-600 text-[#212121] block mb-3">流量使用</text>
<!-- 虚流量统计 -->
<view class="mb-4">
<view class="flex items-center justify-between mb-2">
<text class="text-14px text-[#757575]">虚流量使用</text>
<text class="text-18px font-700 text-[#212121]">
{{ calcUsagePercent(selectedPackage.virtual_used_mb, selectedPackage.virtual_limit_mb) }}%
</text>
</view>
<view class="w-full h-12px bg-[#f5f5f5] rounded-full overflow-hidden mb-2">
<view
:style="{
width: calcUsagePercent(selectedPackage.virtual_used_mb, selectedPackage.virtual_limit_mb) + '%',
backgroundColor: selectedPackage.status === 2 ? '#f44336' : '#4caf50'
}"
class="h-full transition-all duration-300 rounded-full"
/>
</view>
<view class="grid grid-cols-3 gap-2 text-12px">
<view class="text-center p-2 bg-[#f5f5f5] rounded-8px">
<text class="text-[#9e9e9e] block mb-1">已用</text>
<text class="text-[#212121] font-600">{{ formatDataSize(selectedPackage.virtual_used_mb) }}</text>
</view>
<view class="text-center p-2 bg-[#f5f5f5] rounded-8px">
<text class="text-[#9e9e9e] block mb-1">剩余</text>
<text class="text-[#4caf50] font-600">{{ formatDataSize(selectedPackage.virtual_remain_mb) }}</text>
</view>
<view class="text-center p-2 bg-[#f5f5f5] rounded-8px">
<text class="text-[#9e9e9e] block mb-1">总量</text>
<text class="text-[#212121] font-600">{{ formatDataSize(selectedPackage.virtual_limit_mb) }}</text>
</view>
</view>
</view>
<!-- 真流量统计 -->
<view class="pb-3 border-b border-[#eeeeee] mb-3">
<view class="flex items-center justify-between mb-2">
<text class="text-14px text-[#757575]">真流量使用</text>
<text class="text-16px font-600 text-[#212121]">
{{ formatDataSize(selectedPackage.data_usage_mb) }} / {{ formatDataSize(selectedPackage.data_limit_mb) }}
</text>
</view>
<view class="w-full h-8px bg-[#f5f5f5] rounded-full overflow-hidden">
<view
:style="{
width: calcUsagePercent(selectedPackage.data_usage_mb, selectedPackage.data_limit_mb) + '%',
backgroundColor: selectedPackage.status === 2 ? '#f44336' : '#2196f3'
}"
class="h-full transition-all duration-300 rounded-full"
/>
</view>
</view>
<!-- 虚流量比例 -->
<view class="flex items-center justify-between p-3 bg-[#fff7f0] rounded-8px">
<view class="flex items-center gap-2">
<i class="i-mdi-calculator w-18px h-18px text-[var(--brand-primary)]" />
<text class="text-13px text-[#757575]">虚流量比例</text>
</view>
<text class="text-16px font-700 text-[var(--brand-primary)]">
1 : {{ (1 / selectedPackage.virtual_ratio).toFixed(1) }}
</text>
</view>
</view>
<!-- 时间信息 -->
<view class="bg-white rounded-12px p-4 mb-3 shadow-[0_2px_8px_rgba(0,0,0,0.04)]">
<text class="text-16px font-600 text-[#212121] block mb-3">时间信息</text>
<view class="space-y-3">
<view class="flex items-center justify-between">
<view class="flex items-center gap-2">
<i class="i-mdi-calendar-plus w-18px h-18px text-[#9e9e9e]" />
<text class="text-14px text-[#757575]">创建时间</text>
</view>
<text class="text-14px text-[#212121] font-500">
{{ formatDateTime(selectedPackage.created_at) }}
</text>
</view>
<view v-if="selectedPackage.activated_at" class="flex items-center justify-between">
<view class="flex items-center gap-2">
<i class="i-mdi-play-circle w-18px h-18px text-[#4caf50]" />
<text class="text-14px text-[#757575]">激活时间</text>
</view>
<text class="text-14px text-[#212121] font-500">
{{ formatDateTime(selectedPackage.activated_at) }}
</text>
</view>
<view v-if="selectedPackage.expires_at" class="flex items-center justify-between">
<view class="flex items-center gap-2">
<i class="i-mdi-calendar-clock w-18px h-18px text-[#f44336]" />
<text class="text-14px text-[#757575]">到期时间</text>
</view>
<view class="text-right">
<text class="text-14px text-[#212121] font-500 block">
{{ formatDateTime(selectedPackage.expires_at) }}
</text>
<text
v-if="calcRemainingDays(selectedPackage.expires_at)"
:class="{
'text-[#f44336]': calcRemainingDays(selectedPackage.expires_at)! <= 7,
'text-[#ff9800]': calcRemainingDays(selectedPackage.expires_at)! > 7 && calcRemainingDays(selectedPackage.expires_at)! <= 30,
'text-[#4caf50]': calcRemainingDays(selectedPackage.expires_at)! > 30
}"
class="text-12px"
>
剩余 {{ calcRemainingDays(selectedPackage.expires_at) }}
</text>
</view>
</view>
</view>
</view>
<!-- 操作按钮 -->
<view class="grid grid-cols-2 gap-3">
<button class="
bg-white text-[#757575]
border border-[#e0e0e0]
py-3 rounded-8px
text-14px font-500
">
续费套餐
</button>
<button class="
bg-[var(--brand-primary)] text-white
py-3 rounded-8px
text-14px font-500
shadow-brand-xs
">
购买加油包
</button>
</view>
</view>
</view>
</view>
</template>
<style lang="scss" scoped>
.mobile-agent-system {
-webkit-overflow-scrolling: touch;
}
::-webkit-scrollbar {
display: none;
}
</style>