This commit is contained in:
@@ -7,99 +7,77 @@ import { getCarriers } from '@/api/carrier'
|
||||
import type { CarrierInfo } from '@/api/carrier'
|
||||
import SimplePicker from '@/components/SimplePicker.vue'
|
||||
|
||||
// 企业ID (用于调用企业接口)
|
||||
const enterpriseId = ref<number>(0)
|
||||
|
||||
// 卡片列表
|
||||
const cardList = ref<CardInfo[]>([])
|
||||
|
||||
// 加载状态
|
||||
const loading = ref(false)
|
||||
const loadingMore = ref(false)
|
||||
|
||||
// 搜索关键词
|
||||
const searchKeyword = ref('')
|
||||
|
||||
// 状态筛选 (undefined 表示全部)
|
||||
const statusFilter = ref<number | undefined>(undefined)
|
||||
|
||||
// 运营商筛选
|
||||
const carrierFilter = ref<number | undefined>(undefined)
|
||||
const showCarrierPicker = ref(false)
|
||||
|
||||
// 运营商列表
|
||||
const showSearchTypePicker = ref(false)
|
||||
const carrierList = ref<CarrierInfo[]>([])
|
||||
const page = ref(1)
|
||||
const pageSize = 20
|
||||
const hasMore = ref(true)
|
||||
|
||||
const searchType = ref<'iccid' | 'virtual'>('iccid')
|
||||
|
||||
// 网络状态选项 (network_status: 0=停机, 1=正常)
|
||||
const statusOptions = [
|
||||
{ label: '全部', value: undefined },
|
||||
{ label: '正常', value: 1 },
|
||||
{ label: '停机', value: 0 },
|
||||
]
|
||||
|
||||
// 运营商选项
|
||||
const searchTypeOptions = [
|
||||
{ label: 'ICCID', value: 'iccid' },
|
||||
{ label: '虚拟号', value: 'virtual' }
|
||||
]
|
||||
|
||||
const carrierOptions = computed(() => [
|
||||
{ label: '全部运营商', value: undefined },
|
||||
...carrierList.value.map(c => ({ label: c.carrier_name, value: c.id }))
|
||||
])
|
||||
|
||||
// 获取当前选中的运营商名称
|
||||
const selectedCarrierName = computed(() => {
|
||||
if (carrierFilter.value === undefined) return '运营商'
|
||||
const option = carrierOptions.value.find(o => o.value === carrierFilter.value)
|
||||
return option?.label || '运营商'
|
||||
})
|
||||
|
||||
// 分页参数
|
||||
const page = ref(1)
|
||||
const pageSize = 20
|
||||
const hasMore = ref(true)
|
||||
|
||||
// 直接显示卡片列表 (搜索由后端处理)
|
||||
const filteredCards = computed(() => {
|
||||
return cardList.value
|
||||
})
|
||||
|
||||
// 统计数据
|
||||
const stats = computed(() => {
|
||||
const total = cardList.value.length
|
||||
// network_status: 0=停机, 1=正常
|
||||
const active = cardList.value.filter(c => c.network_status === 1).length
|
||||
const inactive = cardList.value.filter(c => c.network_status === 0).length
|
||||
// status: 1=可用, 2=已分销, 3=已停用等
|
||||
const distributed = cardList.value.filter(c => c.status === 2).length
|
||||
|
||||
return { total, active, inactive, distributed }
|
||||
})
|
||||
|
||||
// 加载运营商列表
|
||||
async function loadCarriers() {
|
||||
try {
|
||||
const response = await getCarriers({ page: 1, size: 20 })
|
||||
const response = await getCarriers({ page: 1, size: 50 })
|
||||
carrierList.value = response?.items || []
|
||||
} catch (error) {
|
||||
console.error('加载运营商列表失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载
|
||||
onMounted(() => {
|
||||
loadCarriers()
|
||||
loadEnterpriseCards()
|
||||
})
|
||||
async function loadEnterpriseCards(isRefresh = false) {
|
||||
if (loading.value) return
|
||||
|
||||
if (isRefresh) {
|
||||
page.value = 1
|
||||
hasMore.value = true
|
||||
cardList.value = []
|
||||
}
|
||||
|
||||
// 加载企业卡列表
|
||||
async function loadEnterpriseCards() {
|
||||
loading.value = true
|
||||
|
||||
try {
|
||||
// 1. 获取企业ID (优先从本地存储获取)
|
||||
if (!enterpriseId.value) {
|
||||
const userInfo = uni.getStorageSync('user_info')
|
||||
if (userInfo?.enterprise_id) {
|
||||
enterpriseId.value = userInfo.enterprise_id
|
||||
} else {
|
||||
// 如果本地存储没有,则调用接口获取
|
||||
const apiUserInfo = await getUserInfo()
|
||||
if (!apiUserInfo.enterprise_id) {
|
||||
throw new Error('未找到企业ID')
|
||||
@@ -108,286 +86,276 @@ async function loadEnterpriseCards() {
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 获取企业卡片列表
|
||||
const params: any = {
|
||||
page: page.value,
|
||||
page_size: pageSize,
|
||||
}
|
||||
// 只有选择了具体状态才传 status 参数
|
||||
|
||||
if (statusFilter.value !== undefined) {
|
||||
params.status = statusFilter.value
|
||||
}
|
||||
// 运营商筛选
|
||||
if (carrierFilter.value !== undefined) {
|
||||
params.carrier_id = carrierFilter.value
|
||||
}
|
||||
// 添加搜索关键词支持 (根据接口文档)
|
||||
if (searchKeyword.value) {
|
||||
// 如果关键词看起来像ICCID (纯数字)
|
||||
if (/^\d+$/.test(searchKeyword.value)) {
|
||||
if (searchType.value === 'iccid') {
|
||||
params.iccid = searchKeyword.value
|
||||
} else {
|
||||
params.virtual_no = searchKeyword.value
|
||||
}
|
||||
}
|
||||
|
||||
const cardsData = await getEnterpriseCards(enterpriseId.value, params)
|
||||
const items = cardsData?.items || []
|
||||
|
||||
if (page.value === 1) {
|
||||
cardList.value = cardsData?.items || []
|
||||
}
|
||||
else {
|
||||
cardList.value.push(...(cardsData?.items || []))
|
||||
cardList.value = items
|
||||
} else {
|
||||
cardList.value.push(...items)
|
||||
}
|
||||
|
||||
// 判断是否还有更多数据
|
||||
const items = cardsData?.items || []
|
||||
hasMore.value = items.length >= pageSize
|
||||
}
|
||||
catch (error: any) {
|
||||
page.value++
|
||||
} catch (error: any) {
|
||||
console.error('加载企业卡列表失败:', error)
|
||||
// 如果是前端逻辑错误(非 API 错误),需要手动显示提示
|
||||
if (error instanceof Error && error.message && !error.statusCode) {
|
||||
uni.$u.toast(error.message)
|
||||
}
|
||||
// API 请求错误已由拦截器统一处理
|
||||
}
|
||||
finally {
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 查看卡片详情
|
||||
function viewCardDetail(card: any) {
|
||||
// 跳转到资产详情页
|
||||
uni.navigateTo({
|
||||
url: `/pages/agent-system/asset-search/index?iccid=${card.iccid}`,
|
||||
})
|
||||
}
|
||||
|
||||
// 获取网络状态文本 (使用后端返回的 network_status_name)
|
||||
function getNetworkStatusText(networkStatus: number, networkStatusName?: string) {
|
||||
// 优先使用后端返回的状态名称
|
||||
if (networkStatusName) {
|
||||
return networkStatusName
|
||||
}
|
||||
// 降级处理
|
||||
const map: Record<number, string> = {
|
||||
0: '停机',
|
||||
1: '正常',
|
||||
}
|
||||
return map[networkStatus] ?? '未知'
|
||||
if (networkStatusName) return networkStatusName
|
||||
return networkStatus === 1 ? '正常' : networkStatus === 0 ? '停机' : '未知'
|
||||
}
|
||||
|
||||
// 获取网络状态颜色
|
||||
function getNetworkStatusColor(networkStatus: number) {
|
||||
const map: Record<number, any> = {
|
||||
1: { bg: '#e8f5e9', text: '#2e7d32' }, // 正常
|
||||
0: { bg: '#ffebee', text: '#c62828' }, // 停机
|
||||
}
|
||||
return map[networkStatus] ?? { bg: '#f5f5f5', text: '#999' }
|
||||
return networkStatus === 1
|
||||
? { bg: '#e8f5e9', text: '#2e7d32' }
|
||||
: networkStatus === 0
|
||||
? { bg: '#ffebee', text: '#c62828' }
|
||||
: { bg: '#f5f5f5', text: '#999' }
|
||||
}
|
||||
|
||||
// 获取卡状态文本 (使用后端返回的 status_name)
|
||||
function getCardStatusText(status: number, statusName?: string) {
|
||||
// 优先使用后端返回的状态名称
|
||||
if (statusName) {
|
||||
return statusName
|
||||
}
|
||||
// 降级处理
|
||||
const map: Record<number, string> = {
|
||||
1: '可用',
|
||||
2: '已分销',
|
||||
3: '已停用',
|
||||
}
|
||||
if (statusName) return statusName
|
||||
const map: Record<number, string> = { 1: '可用', 2: '已分销', 3: '已停用' }
|
||||
return map[status] ?? '未知'
|
||||
}
|
||||
|
||||
// 清空搜索
|
||||
function clearSearch() {
|
||||
searchKeyword.value = ''
|
||||
page.value = 1
|
||||
hasMore.value = true
|
||||
cardList.value = []
|
||||
loadEnterpriseCards()
|
||||
}
|
||||
|
||||
// 执行搜索
|
||||
function handleSearch() {
|
||||
page.value = 1
|
||||
hasMore.value = true
|
||||
cardList.value = []
|
||||
loadEnterpriseCards()
|
||||
loadEnterpriseCards(true)
|
||||
}
|
||||
|
||||
// 刷新列表
|
||||
function refreshList() {
|
||||
page.value = 1
|
||||
hasMore.value = true
|
||||
cardList.value = []
|
||||
loadEnterpriseCards()
|
||||
}
|
||||
|
||||
// 状态筛选变化
|
||||
function handleStatusChange(status: number | undefined) {
|
||||
statusFilter.value = status
|
||||
page.value = 1
|
||||
hasMore.value = true
|
||||
cardList.value = []
|
||||
loadEnterpriseCards()
|
||||
}
|
||||
|
||||
// 运营商筛选变化 (SimplePicker确认时触发)
|
||||
function onCarrierConfirm(option: { label: string, value: any }) {
|
||||
carrierFilter.value = option.value
|
||||
page.value = 1
|
||||
hasMore.value = true
|
||||
cardList.value = []
|
||||
loadEnterpriseCards()
|
||||
loadEnterpriseCards(true)
|
||||
}
|
||||
|
||||
function onSearchTypeConfirm(option: { label: string, value: any }) {
|
||||
searchType.value = option.value
|
||||
}
|
||||
|
||||
function handleStatusChange(status: number | undefined) {
|
||||
statusFilter.value = status
|
||||
loadEnterpriseCards(true)
|
||||
}
|
||||
|
||||
function loadMore() {
|
||||
if (hasMore.value && !loading.value) {
|
||||
loadEnterpriseCards()
|
||||
}
|
||||
}
|
||||
|
||||
function onScroll(e: any) {
|
||||
const { scrollTop, scrollHeight, clientHeight } = e.target
|
||||
if (scrollHeight - scrollTop - clientHeight < 100) {
|
||||
loadMore()
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
loadCarriers()
|
||||
loadEnterpriseCards()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="bg-[var(--bg-page)] min-h-screen pb-safe">
|
||||
<view v-if="loading" class="pt-20 center">
|
||||
<text class="text-14px text-[var(--text-secondary)]">加载中...</text>
|
||||
<view class="bg-page min-h-screen flex flex-col">
|
||||
<!-- 搜索区域 -->
|
||||
<view class="bg-white px-4 pt-4 pb-3">
|
||||
<!-- 搜索框 -->
|
||||
<view class="relative flex items-center">
|
||||
<input
|
||||
v-model="searchKeyword"
|
||||
class="flex-1 h-10 bg-[#f1f5f9] rounded-full pl-4 pr-12 text-sm text-[#1e293b] placeholder-[#94a3b8]"
|
||||
:placeholder="searchType === 'iccid' ? '搜索ICCID' : '搜索虚拟号'"
|
||||
@confirm="handleSearch"
|
||||
/>
|
||||
<view class="absolute right-1 flex items-center">
|
||||
<view v-if="searchKeyword" class="w-8 h-8 flex items-center justify-center text-[#94a3b8]"
|
||||
@click="searchKeyword = ''">
|
||||
<i class="i-mdi-close-circle text-lg" />
|
||||
</view>
|
||||
<view class="w-8 h-8 flex items-center justify-center text-brand" @click="handleSearch">
|
||||
<i class="i-mdi-magnify text-xl" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 统计信息 -->
|
||||
<view class="flex items-center justify-around gap-3 mt-3">
|
||||
<view class="flex items-center gap-1">
|
||||
<text class="text-12px text-[#999]">卡总数</text>
|
||||
<text class="text-14px font-700 text-brand">{{ stats.total }}</text>
|
||||
</view>
|
||||
<view class="flex items-center gap-1">
|
||||
<view class="w-2 h-2 rounded-full bg-[#52c41a]" />
|
||||
<text class="text-12px text-[#666]">正常</text>
|
||||
<text class="text-12px font-600 text-[#212121]">{{ stats.active }}</text>
|
||||
</view>
|
||||
<view class="flex items-center gap-1">
|
||||
<view class="w-2 h-2 rounded-full bg-[#ff4d4f]" />
|
||||
<text class="text-12px text-[#666]">停机</text>
|
||||
<text class="text-12px font-600 text-[#212121]">{{ stats.inactive }}</text>
|
||||
</view>
|
||||
<view class="flex items-center gap-1">
|
||||
<view class="w-2 h-2 rounded-full bg-brand" />
|
||||
<text class="text-12px text-[#666]">已分销</text>
|
||||
<text class="text-12px font-600 text-[#212121]">{{ stats.distributed }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 筛选器 -->
|
||||
<view class="flex items-center gap-2 mt-3 flex-wrap">
|
||||
|
||||
<view class="flex items-center gap-1 px-3 py-1.5 bg-[#f8fafc] rounded-full flex-shrink-0"
|
||||
@click="showSearchTypePicker = true">
|
||||
<text class="text-12px" :class="searchType !== 'iccid' ? 'text-brand font-medium' : 'text-[#64748b]'">
|
||||
{{ searchType === 'iccid' ? 'ICCID' : '虚拟号' }}
|
||||
</text>
|
||||
<i class="i-mdi-chevron-down text-12px text-[#94a3b8]" />
|
||||
</view>
|
||||
|
||||
<view class="flex items-center gap-1.5 px-3 py-1.5 bg-[#f8fafc] rounded-full flex-shrink-0 max-w-36"
|
||||
@click="showCarrierPicker = true">
|
||||
<text class="text-12px truncate" :class="carrierFilter !== undefined ? 'text-brand font-medium' : 'text-[#64748b]'">
|
||||
{{ selectedCarrierName }}
|
||||
</text>
|
||||
<i class="i-mdi-chevron-down text-12px text-[#94a3b8] flex-shrink-0" />
|
||||
</view>
|
||||
|
||||
<view class="flex bg-[#f1f5f9] rounded-full flex-shrink-0">
|
||||
<view
|
||||
v-for="option in statusOptions"
|
||||
:key="option.value"
|
||||
class="px-3 py-1.5 text-12px font-medium transition-all rounded-full"
|
||||
:class="statusFilter === option.value ? 'bg-brand text-white' : 'text-[#64748b]'"
|
||||
@click="handleStatusChange(option.value)"
|
||||
>
|
||||
{{ option.label }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
v-if="carrierFilter !== undefined || statusFilter !== undefined"
|
||||
class="flex items-center gap-1 px-2 py-1.5 rounded-full bg-[#ff4d4f]/10 text-[#ff4d4f] flex-shrink-0"
|
||||
@click="carrierFilter = undefined; statusFilter = undefined; loadEnterpriseCards(true)"
|
||||
>
|
||||
<i class="i-mdi-close text-12px" />
|
||||
<text class="text-12px font-medium">清除</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else>
|
||||
<view class="bg-brand px-4 py-3 mx-4 mt-4 rounded-12px">
|
||||
<text class="text-11px text-white/60">企业授权IoT卡</text>
|
||||
<text class="text-24px font-700 text-white block mt-1">{{ stats.total }}</text>
|
||||
<!-- 列表内容 -->
|
||||
<view class="flex-1 overflow-y-auto min-h-0" @scroll="onScroll">
|
||||
<!-- 卡片列表 -->
|
||||
<view v-if="loading && cardList.length === 0" class="pt-20 flex justify-center">
|
||||
<text class="text-14px text-[#64748b]">加载中...</text>
|
||||
</view>
|
||||
|
||||
<view class="px-4 mt-4">
|
||||
<view class="flex items-center gap-2 mb-3">
|
||||
<input
|
||||
v-model="searchKeyword"
|
||||
class="flex-1 h-40px bg-[var(--bg-container)] rounded-full px-4 text-14px text-[var(--text-primary)]"
|
||||
placeholder="搜索 ICCID / 虚拟号 / 手机号"
|
||||
placeholder-class="text-[var(--text-quaternary)]"
|
||||
@confirm="handleSearch"
|
||||
>
|
||||
<view
|
||||
class="px-4 h-40px bg-brand text-white text-14px rounded-full flex items-center justify-center"
|
||||
@click="handleSearch"
|
||||
>
|
||||
搜索
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="flex items-center gap-2 mb-3">
|
||||
<view class="flex-1 bg-[var(--bg-container)] rounded-8px px-3 h-40px flex items-center" @click="showCarrierPicker = true">
|
||||
<text class="flex-1 text-14px text-[var(--text-primary)]">{{ selectedCarrierName }}</text>
|
||||
<text class="text-12px text-[var(--text-tertiary)]">▼</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="px-4">
|
||||
<view class="bg-[var(--bg-container)] rounded-12px p-4 mb-3">
|
||||
<view class="grid grid-cols-3 gap-3">
|
||||
<view class="text-center">
|
||||
<text class="text-11px text-[var(--text-tertiary)] block">正常</text>
|
||||
<text class="text-18px font-700 text-[#52c41a] mt-1">{{ stats.active }}</text>
|
||||
<view v-else-if="cardList.length > 0" class="px-4 pb-4">
|
||||
<view
|
||||
v-for="card in cardList"
|
||||
:key="card.id"
|
||||
class="bg-white rounded-12px p-4 mt-3"
|
||||
@click="viewCardDetail(card)"
|
||||
>
|
||||
<view class="flex items-center justify-between mb-2">
|
||||
<view class="flex items-center gap-2">
|
||||
<text class="text-15px font-600 text-[#212121]">{{ card.carrier_name || '-' }}</text>
|
||||
<text class="text-12px text-[#999]">{{ getCardStatusText(card.status, card.status_name) }}</text>
|
||||
</view>
|
||||
<view class="text-center">
|
||||
<text class="text-11px text-[var(--text-tertiary)] block">停机</text>
|
||||
<text class="text-18px font-700 text-[#ff4d4f] mt-1">{{ stats.inactive }}</text>
|
||||
</view>
|
||||
<view class="text-center">
|
||||
<text class="text-11px text-[var(--text-tertiary)] block">已分销</text>
|
||||
<text class="text-18px font-700 text-brand mt-1">{{ stats.distributed }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="flex items-center gap-2 mt-4">
|
||||
<view
|
||||
v-for="option in statusOptions"
|
||||
:key="option.value"
|
||||
:class="[
|
||||
'flex-1 text-center py-2 rounded-full text-13px transition-all',
|
||||
statusFilter === option.value
|
||||
? 'bg-brand text-white font-600'
|
||||
: 'bg-[var(--bg-muted)] text-[var(--text-secondary)]',
|
||||
]"
|
||||
@click="handleStatusChange(option.value)"
|
||||
:style="{
|
||||
backgroundColor: getNetworkStatusColor(card.network_status).bg,
|
||||
color: getNetworkStatusColor(card.network_status).text,
|
||||
}"
|
||||
class="px-3 py-1 rounded-full text-12px font-600"
|
||||
>
|
||||
{{ option.label }}
|
||||
{{ getNetworkStatusText(card.network_status, card.network_status_name) }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="filteredCards.length > 0" class="space-y-3 pb-4">
|
||||
<view
|
||||
v-for="card in filteredCards"
|
||||
:key="card.id"
|
||||
class="bg-[var(--bg-container)] rounded-12px p-4"
|
||||
@click="viewCardDetail(card)"
|
||||
>
|
||||
<view class="flex items-center justify-between">
|
||||
<view>
|
||||
<text class="text-15px font-600 text-[var(--text-primary)]">{{ card.carrier_name || '-' }}</text>
|
||||
<text class="text-12px text-[var(--text-tertiary)] ml-2">{{ getCardStatusText(card.status, card.status_name) }}</text>
|
||||
</view>
|
||||
<view class="text-13px text-[#666] mb-2">
|
||||
{{ card.package_name || '暂无套餐' }}
|
||||
</view>
|
||||
|
||||
<view class="flex items-center justify-between text-12px text-[#999]">
|
||||
<text class="truncate flex-1">{{ card.iccid || '-' }}</text>
|
||||
<text class="ml-2">{{ card.msisdn || '-' }}</text>
|
||||
</view>
|
||||
|
||||
<view v-if="card.virtual_no" class="text-12px text-[#999] mt-1">
|
||||
虚拟号: {{ card.virtual_no }}
|
||||
</view>
|
||||
|
||||
<view v-if="card.data_total && parseFloat(card.data_total) > 0" class="mt-3 bg-[#f5f5f5] rounded-8px p-3">
|
||||
<view class="flex items-center justify-between mb-2">
|
||||
<text class="text-12px text-[#666]">流量</text>
|
||||
<text class="text-12px font-600 text-[#212121]">
|
||||
{{ card.data_usage || '0' }} / {{ card.data_total || '0' }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="h-2 bg-[#e0e0e0] rounded-full overflow-hidden">
|
||||
<view
|
||||
:style="{
|
||||
backgroundColor: getNetworkStatusColor(card.network_status).bg,
|
||||
color: getNetworkStatusColor(card.network_status).text,
|
||||
}"
|
||||
class="px-3 py-1 rounded-full text-12px font-600"
|
||||
>
|
||||
{{ getNetworkStatusText(card.network_status, card.network_status_name) }}
|
||||
</view>
|
||||
:style="{ width: `${Math.min(100, (parseFloat(card.data_usage || '0') / parseFloat(card.data_total || '1')) * 100)}%` }"
|
||||
:class="[
|
||||
'h-full rounded-full transition-all',
|
||||
(parseFloat(card.data_usage || '0') / parseFloat(card.data_total || '1')) > 0.9 ? 'bg-[#ff4d4f]' : 'bg-[#52c41a]',
|
||||
]"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="mt-3 text-13px text-[var(--text-secondary)]">
|
||||
{{ card.package_name || '暂无套餐' }}
|
||||
</view>
|
||||
|
||||
<view class="mt-3 flex items-center justify-between text-12px text-[var(--text-tertiary)]">
|
||||
<text>{{ card.iccid || '-' }}</text>
|
||||
<text>{{ card.msisdn || '-' }}</text>
|
||||
</view>
|
||||
|
||||
<view v-if="card.virtual_no" class="mt-1 text-12px text-[var(--text-tertiary)]">
|
||||
虚拟号: {{ card.virtual_no }}
|
||||
</view>
|
||||
|
||||
<view class="mt-3 bg-[var(--bg-muted)] rounded-8px p-3">
|
||||
<view class="flex items-center justify-between mb-2">
|
||||
<text class="text-12px text-[var(--text-secondary)]">流量</text>
|
||||
<text class="text-12px font-600 text-[var(--text-primary)]">
|
||||
{{ card.data_usage || '0' }} / {{ card.data_total || '0' }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="h-6px bg-[var(--border-primary)] rounded-full overflow-hidden">
|
||||
<view
|
||||
:style="{
|
||||
width: `${(parseFloat(card.data_usage || '0') / parseFloat(card.data_total || '1')) * 100}%`,
|
||||
}"
|
||||
:class="[
|
||||
'h-full rounded-full transition-all duration-300',
|
||||
(parseFloat(card.data_usage || '0') / parseFloat(card.data_total || '1')) > 0.9
|
||||
? 'bg-[#ff4d4f]'
|
||||
: 'bg-[#52c41a]',
|
||||
]"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="mt-2 flex items-center justify-between text-11px text-[var(--text-tertiary)]">
|
||||
<text>激活: {{ card.activate_time || '-' }}</text>
|
||||
<text>到期: {{ card.expire_date || '-' }}</text>
|
||||
</view>
|
||||
<view class="mt-2 flex items-center justify-between text-11px text-[#999]">
|
||||
<text>激活: {{ card.activate_time || '-' }}</text>
|
||||
<text>到期: {{ card.expire_date || '-' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else class="pt-16 center">
|
||||
<text class="text-14px text-[var(--text-secondary)]">{{ searchKeyword ? '未找到匹配的卡' : '暂无卡数据' }}</text>
|
||||
<view v-if="loading" class="py-4 text-center">
|
||||
<text class="text-sm text-[#64748b]">加载中...</text>
|
||||
</view>
|
||||
<view v-else-if="!hasMore" class="py-4 text-center">
|
||||
<text class="text-sm text-[#94a3b8]">没有更多了</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="h-16" />
|
||||
<view v-else class="pt-16 flex flex-col items-center">
|
||||
<i class="i-mdi-package-variant-closed text-6xl text-[#cbd5e1] mb-3" />
|
||||
<text class="text-base text-[#64748b] mb-1">暂无数据</text>
|
||||
<text class="text-sm text-[#94a3b8]">{{ searchKeyword ? '未找到相关结果' : '暂无卡数据' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<SimplePicker
|
||||
@@ -396,38 +364,15 @@ function onCarrierConfirm(option: { label: string, value: any }) {
|
||||
title="选择运营商"
|
||||
@confirm="onCarrierConfirm"
|
||||
/>
|
||||
|
||||
<SimplePicker
|
||||
v-model:show="showSearchTypePicker"
|
||||
:options="searchTypeOptions"
|
||||
title="选择搜索类型"
|
||||
@confirm="onSearchTypeConfirm"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.space-y-3 > view:not(:last-child) {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.space-y-2 > view:not(:last-child) {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.break-all {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-spin {
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user