first
This commit is contained in:
245
src/pages/agent-system/packages/index.vue
Normal file
245
src/pages/agent-system/packages/index.vue
Normal file
@@ -0,0 +1,245 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { getEnterpriseCards } from '@/api/enterprise'
|
||||
import { getUserInfo } from '@/api/auth'
|
||||
|
||||
interface CardInfo {
|
||||
id: number
|
||||
iccid: string
|
||||
msisdn: string
|
||||
virtual_no?: string
|
||||
carrier_id: number
|
||||
carrier_name?: string
|
||||
package_name?: string
|
||||
status: number
|
||||
status_name: string
|
||||
network_status: number
|
||||
network_status_name: string
|
||||
}
|
||||
|
||||
// 企业ID
|
||||
const enterpriseId = ref<number>(0)
|
||||
// IoT卡列表
|
||||
const cardList = ref<CardInfo[]>([])
|
||||
// 加载状态
|
||||
const loading = ref(true)
|
||||
|
||||
// 套餐统计
|
||||
const packageStats = computed(() => {
|
||||
const total = cardList.value.length
|
||||
const hasPackage = cardList.value.filter(c => c.package_name).length
|
||||
const noPackage = total - hasPackage
|
||||
|
||||
return { total, hasPackage, noPackage }
|
||||
})
|
||||
|
||||
// 按套餐分组
|
||||
const packageGroups = computed(() => {
|
||||
const groups = new Map<string, CardInfo[]>()
|
||||
|
||||
cardList.value.forEach(card => {
|
||||
const pkg = card.package_name || '无套餐'
|
||||
if (!groups.has(pkg)) {
|
||||
groups.set(pkg, [])
|
||||
}
|
||||
groups.get(pkg)!.push(card)
|
||||
})
|
||||
|
||||
return Array.from(groups.entries()).map(([name, cards]) => ({
|
||||
name,
|
||||
count: cards.length,
|
||||
cards,
|
||||
}))
|
||||
})
|
||||
|
||||
// 加载数据
|
||||
async function loadData() {
|
||||
loading.value = true
|
||||
|
||||
try {
|
||||
// 获取企业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')
|
||||
}
|
||||
enterpriseId.value = apiUserInfo.enterprise_id
|
||||
}
|
||||
}
|
||||
|
||||
// 获取企业卡列表
|
||||
const response = await getEnterpriseCards(enterpriseId.value)
|
||||
cardList.value = response?.items || []
|
||||
} catch (error: any) {
|
||||
console.error('加载数据失败:', error)
|
||||
if (error instanceof Error && error.message && !error.statusCode) {
|
||||
uni.$u.toast(error.message)
|
||||
}
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 查看IoT卡详情
|
||||
function viewCardDetail(card: CardInfo) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/agent-system/asset-search/index?iccid=${card.iccid}`,
|
||||
})
|
||||
}
|
||||
|
||||
// 获取卡片状态颜色
|
||||
function getStatusColor(status: number) {
|
||||
const map: Record<number, { bg: string, text: string }> = {
|
||||
1: { bg: '#f5f5f5', text: '#999' }, // 在库
|
||||
2: { bg: '#e8f5e9', text: '#2e7d32' }, // 已分销
|
||||
3: { bg: '#ffebee', text: '#c62828' }, // 已停用
|
||||
}
|
||||
return map[status] || { bg: '#f5f5f5', text: '#999' }
|
||||
}
|
||||
|
||||
// 获取网络状态颜色
|
||||
function getNetworkStatusColor(status: number) {
|
||||
return status === 1
|
||||
? { bg: '#e8f5e9', text: '#2e7d32' }
|
||||
: { bg: '#ffebee', text: '#c62828' }
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="bg-[#fafafa] min-h-screen pb-safe">
|
||||
<!-- 顶部统计 -->
|
||||
<view class="px-4 pt-4 pb-3">
|
||||
<view class="bg-white rounded-16px shadow-[0_2px_12px_rgba(0,0,0,0.06)] p-4">
|
||||
<text class="text-16px font-700 text-[#212121] block mb-3">套餐统计</text>
|
||||
<view class="grid grid-cols-3 gap-3">
|
||||
<view class="text-center">
|
||||
<text class="text-24px font-700 text-[#212121] block">{{ packageStats.total }}</text>
|
||||
<text class="text-11px text-[#999] mt-1">总IoT卡</text>
|
||||
</view>
|
||||
<view class="text-center">
|
||||
<text class="text-24px font-700 text-[#ff6700] block">{{ packageStats.hasPackage }}</text>
|
||||
<text class="text-11px text-[#999] mt-1">已订购</text>
|
||||
</view>
|
||||
<view class="text-center">
|
||||
<text class="text-24px font-700 text-[#999] block">{{ packageStats.noPackage }}</text>
|
||||
<text class="text-11px text-[#999] mt-1">未订购</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<view v-if="loading" class="pt-20 flex flex-col items-center">
|
||||
<i class="i-mdi-loading animate-spin text-40px text-[#999]" />
|
||||
</view>
|
||||
|
||||
<!-- 套餐分组列表 -->
|
||||
<view v-else class="px-4 pb-4">
|
||||
<view class="space-y-3">
|
||||
<view
|
||||
v-for="group in packageGroups"
|
||||
:key="group.name"
|
||||
class="bg-white rounded-16px shadow-[0_2px_12px_rgba(0,0,0,0.06)] overflow-hidden"
|
||||
>
|
||||
<!-- 套餐头部 -->
|
||||
<view class="px-4 py-3 bg-[#f8fafc] border-b-1px border-[#f1f5f9]">
|
||||
<view class="flex items-center justify-between">
|
||||
<view class="flex items-center gap-2">
|
||||
<i class="i-mdi-package-variant text-20px text-[#ff6700]" />
|
||||
<text class="text-15px font-600 text-[#212121]">{{ group.name }}</text>
|
||||
</view>
|
||||
<text class="text-12px text-[#999]">{{ group.count }} 张</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- IoT卡列表 -->
|
||||
<view class="px-4 py-2">
|
||||
<view
|
||||
v-for="(card, index) in group.cards"
|
||||
:key="card.id"
|
||||
class="py-3 active:bg-[#f8fafc] transition-all"
|
||||
:class="{ 'border-t-1px border-[#f1f5f9]': index > 0 }"
|
||||
@click="viewCardDetail(card)"
|
||||
>
|
||||
<view class="flex items-start justify-between">
|
||||
<view class="flex-1 min-w-0">
|
||||
<!-- ICCID -->
|
||||
<text class="text-13px text-[#212121] block mb-1 font-500">
|
||||
{{ card.iccid }}
|
||||
</text>
|
||||
|
||||
<!-- 电话号码 -->
|
||||
<view class="flex items-center gap-2 mb-1">
|
||||
<i class="i-mdi-phone text-14px text-[#999]" />
|
||||
<text class="text-12px text-[#666]">
|
||||
{{ card.msisdn }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<!-- 状态标签 -->
|
||||
<view class="flex items-center gap-2">
|
||||
<!-- 卡片状态 -->
|
||||
<view
|
||||
:style="{
|
||||
backgroundColor: getStatusColor(card.status).bg,
|
||||
color: getStatusColor(card.status).text,
|
||||
}"
|
||||
class="px-2 py-0.5 rounded text-10px font-600"
|
||||
>
|
||||
{{ card.status_name }}
|
||||
</view>
|
||||
|
||||
<!-- 网络状态 -->
|
||||
<view
|
||||
:style="{
|
||||
backgroundColor: getNetworkStatusColor(card.network_status).bg,
|
||||
color: getNetworkStatusColor(card.network_status).text,
|
||||
}"
|
||||
class="px-2 py-0.5 rounded text-10px font-600"
|
||||
>
|
||||
{{ card.network_status_name }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 右侧箭头 -->
|
||||
<view class="flex items-center ml-3">
|
||||
<i class="i-mdi-chevron-right text-20px text-[#cbd5e1]" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view v-if="packageGroups.length === 0" class="bg-white rounded-16px py-16 flex flex-col items-center">
|
||||
<i class="i-mdi-package-variant-closed text-64px text-[#ddd] mb-3" />
|
||||
<text class="text-15px text-[#999]">暂无套餐数据</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.space-y-3 > view:not(:last-child) {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
@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