This commit is contained in:
312
src/views/asset-management/iot-card-management/detail.vue
Normal file
312
src/views/asset-management/iot-card-management/detail.vue
Normal file
@@ -0,0 +1,312 @@
|
||||
<template>
|
||||
<div class="iot-card-detail-page">
|
||||
<ElCard shadow="never">
|
||||
<!-- 页面头部 -->
|
||||
<div class="detail-header">
|
||||
<ElButton @click="handleBack">
|
||||
<template #icon>
|
||||
<ElIcon><ArrowLeft /></ElIcon>
|
||||
</template>
|
||||
返回
|
||||
</ElButton>
|
||||
<h2 class="detail-title">IoT卡详情</h2>
|
||||
<div class="header-actions">
|
||||
<ElButton type="primary" @click="handleRefresh" :loading="loading">
|
||||
<Icon name="refresh" /> 刷新
|
||||
</ElButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<div v-if="loading && !cardDetail" class="loading-container">
|
||||
<ElIcon class="is-loading" :size="60"><Loading /></ElIcon>
|
||||
<div class="loading-text">加载中...</div>
|
||||
</div>
|
||||
|
||||
<!-- 详情内容 -->
|
||||
<DetailPage v-if="cardDetail" :sections="detailSections" :data="cardDetail" />
|
||||
|
||||
<!-- 未找到卡片 -->
|
||||
<div v-if="!cardDetail && !loading" class="empty-container">
|
||||
<ElEmpty description="未找到该卡片信息" />
|
||||
</div>
|
||||
</ElCard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { h } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { CardService } from '@/api/modules'
|
||||
import { ElMessage, ElIcon, ElTag } from 'element-plus'
|
||||
import { ArrowLeft, Loading } from '@element-plus/icons-vue'
|
||||
import { formatDateTime } from '@/utils/business/format'
|
||||
import DetailPage from '@/components/common/DetailPage.vue'
|
||||
import type { DetailSection } from '@/components/common/DetailPage.vue'
|
||||
|
||||
defineOptions({ name: 'IotCardDetail' })
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
const loading = ref(false)
|
||||
const cardDetail = ref<any>(null)
|
||||
const iccid = ref<string>('')
|
||||
|
||||
onMounted(() => {
|
||||
iccid.value = (route.query.iccid as string) || ''
|
||||
if (iccid.value) {
|
||||
loadCardDetail()
|
||||
} else {
|
||||
ElMessage.error('缺少ICCID参数')
|
||||
}
|
||||
})
|
||||
|
||||
// 加载卡片详情
|
||||
const loadCardDetail = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await CardService.getIotCardDetailByIccid(iccid.value)
|
||||
if (res.code === 0) {
|
||||
cardDetail.value = res.data
|
||||
} else {
|
||||
ElMessage.error(res.msg || '获取卡片详情失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取卡片详情失败:', error)
|
||||
ElMessage.error('获取卡片详情失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 返回上一页
|
||||
const handleBack = () => {
|
||||
router.back()
|
||||
}
|
||||
|
||||
// 刷新
|
||||
const handleRefresh = () => {
|
||||
loadCardDetail()
|
||||
}
|
||||
|
||||
// 运营商类型文本
|
||||
const getCarrierTypeText = (type: string) => {
|
||||
const typeMap: Record<string, string> = {
|
||||
CMCC: '中国移动',
|
||||
CUCC: '中国联通',
|
||||
CTCC: '中国电信',
|
||||
CBN: '中国广电'
|
||||
}
|
||||
return typeMap[type] || type || '--'
|
||||
}
|
||||
|
||||
// 卡业务类型文本
|
||||
const getCardCategoryText = (category: string) => {
|
||||
const categoryMap: Record<string, string> = {
|
||||
normal: '普通卡',
|
||||
industry: '行业卡'
|
||||
}
|
||||
return categoryMap[category] || category || '--'
|
||||
}
|
||||
|
||||
// 状态文本
|
||||
const getStatusText = (status: number) => {
|
||||
const statusMap: Record<number, string> = {
|
||||
1: '在库',
|
||||
2: '已分销',
|
||||
3: '已激活',
|
||||
4: '已停用'
|
||||
}
|
||||
return statusMap[status] || '未知'
|
||||
}
|
||||
|
||||
// 状态标签类型
|
||||
const getStatusTagType = (status: number) => {
|
||||
const typeMap: Record<number, any> = {
|
||||
1: 'info',
|
||||
2: 'warning',
|
||||
3: 'success',
|
||||
4: 'danger'
|
||||
}
|
||||
return typeMap[status] || 'info'
|
||||
}
|
||||
|
||||
// 格式化价格
|
||||
const formatCardPrice = (price: number) => {
|
||||
return `¥${((price || 0) / 100).toFixed(2)}`
|
||||
}
|
||||
|
||||
// DetailPage 配置
|
||||
const detailSections: DetailSection[] = [
|
||||
{
|
||||
title: '基本信息',
|
||||
fields: [
|
||||
{ label: '卡ID', prop: 'id' },
|
||||
{
|
||||
label: 'ICCID',
|
||||
render: (data) => {
|
||||
return h(
|
||||
'span',
|
||||
{
|
||||
style: {
|
||||
padding: '3px 8px',
|
||||
fontFamily: "'SF Mono', Monaco, Inconsolata, 'Roboto Mono', monospace",
|
||||
fontSize: '13px',
|
||||
fontWeight: '500',
|
||||
color: 'var(--el-text-color-regular)',
|
||||
background: 'var(--el-fill-color-light)',
|
||||
border: '1px solid var(--el-border-color-lighter)',
|
||||
borderRadius: '4px'
|
||||
}
|
||||
},
|
||||
data.iccid
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '卡接入号',
|
||||
render: (data) => {
|
||||
return h(
|
||||
'span',
|
||||
{
|
||||
style: {
|
||||
padding: '3px 8px',
|
||||
fontFamily: "'SF Mono', Monaco, Inconsolata, 'Roboto Mono', monospace",
|
||||
fontSize: '13px',
|
||||
fontWeight: '500',
|
||||
color: 'var(--el-text-color-regular)',
|
||||
background: 'var(--el-fill-color-light)',
|
||||
border: '1px solid var(--el-border-color-lighter)',
|
||||
borderRadius: '4px'
|
||||
}
|
||||
},
|
||||
data.msisdn || '--'
|
||||
)
|
||||
}
|
||||
},
|
||||
{ label: '运营商', prop: 'carrier_name', formatter: (value) => value || '--' },
|
||||
{
|
||||
label: '运营商类型',
|
||||
prop: 'carrier_type',
|
||||
formatter: (value) => getCarrierTypeText(value)
|
||||
},
|
||||
{
|
||||
label: '卡业务类型',
|
||||
prop: 'card_category',
|
||||
formatter: (value) => getCardCategoryText(value)
|
||||
},
|
||||
{
|
||||
label: '状态',
|
||||
render: (data) => {
|
||||
return h(ElTag, { type: getStatusTagType(data.status) }, () => getStatusText(data.status))
|
||||
}
|
||||
},
|
||||
{ label: '套餐系列', prop: 'series_name', formatter: (value) => value || '--' },
|
||||
{
|
||||
label: '激活状态',
|
||||
render: (data) => {
|
||||
return h(
|
||||
ElTag,
|
||||
{ type: data.activation_status === 1 ? 'success' : 'info' },
|
||||
() => (data.activation_status === 1 ? '已激活' : '未激活')
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '实名状态',
|
||||
render: (data) => {
|
||||
return h(
|
||||
ElTag,
|
||||
{ type: data.real_name_status === 1 ? 'success' : 'warning' },
|
||||
() => (data.real_name_status === 1 ? '已实名' : '未实名')
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '网络状态',
|
||||
render: (data) => {
|
||||
return h(
|
||||
ElTag,
|
||||
{ type: data.network_status === 1 ? 'success' : 'danger' },
|
||||
() => (data.network_status === 1 ? '开机' : '停机')
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '累计流量使用',
|
||||
prop: 'data_usage_mb',
|
||||
formatter: (value) => `${value} MB`
|
||||
},
|
||||
{
|
||||
label: '一次性佣金',
|
||||
render: (data) => {
|
||||
return h(
|
||||
ElTag,
|
||||
{ type: data.first_commission_paid ? 'success' : 'info' },
|
||||
() => (data.first_commission_paid ? '已产生' : '未产生')
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '累计充值',
|
||||
prop: 'accumulated_recharge',
|
||||
formatter: (value) => formatCardPrice(value)
|
||||
},
|
||||
{ label: '所属店铺', prop: 'shop_name', formatter: (value) => value || '--' },
|
||||
{ label: '创建时间', prop: 'created_at', formatter: (value) => formatDateTime(value) },
|
||||
{ label: '更新时间', prop: 'updated_at', formatter: (value) => formatDateTime(value) }
|
||||
]
|
||||
}
|
||||
]
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.iot-card-detail-page {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.detail-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding-bottom: 16px;
|
||||
|
||||
.detail-title {
|
||||
margin: 0;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 60px 20px;
|
||||
gap: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
|
||||
.el-icon {
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.empty-container {
|
||||
padding: 60px 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
@@ -610,6 +610,7 @@
|
||||
BatchSetCardSeriesBindingResponse
|
||||
} from '@/types/api/card'
|
||||
import type { PackageSeriesResponse } from '@/types/api'
|
||||
import { RoutesAlias } from '@/router/routesAlias'
|
||||
|
||||
defineOptions({ name: 'StandaloneCardList' })
|
||||
|
||||
@@ -909,26 +910,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 打开卡详情弹窗
|
||||
const goToCardDetail = async (iccid: string) => {
|
||||
cardDetailDialogVisible.value = true
|
||||
cardDetailLoading.value = true
|
||||
currentCardDetail.value = null
|
||||
|
||||
try {
|
||||
const res = await CardService.getIotCardDetailByIccid(iccid)
|
||||
if (res.code === 0 && res.data) {
|
||||
currentCardDetail.value = res.data
|
||||
} else {
|
||||
ElMessage.error(res.message || '查询失败')
|
||||
cardDetailDialogVisible.value = false
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('查询卡片详情失败:', error)
|
||||
ElMessage.error(error?.message || '查询失败,请检查ICCID是否正确')
|
||||
cardDetailDialogVisible.value = false
|
||||
} finally {
|
||||
cardDetailLoading.value = false
|
||||
// 跳转到IoT卡详情页面
|
||||
const goToCardDetail = (iccid: string) => {
|
||||
if (hasAuth('iot_card:view_detail')) {
|
||||
router.push({
|
||||
path: RoutesAlias.StandaloneCardList + '/detail',
|
||||
query: {
|
||||
iccid: iccid
|
||||
}
|
||||
})
|
||||
} else {
|
||||
ElMessage.warning('您没有查看详情的权限')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -985,8 +977,11 @@
|
||||
return h(
|
||||
'span',
|
||||
{
|
||||
style: { color: 'var(--el-color-primary)', cursor: 'pointer' },
|
||||
onClick: () => goToCardDetail(row.iccid)
|
||||
style: 'color: var(--el-color-primary); cursor: pointer; text-decoration: underline;',
|
||||
onClick: (e: MouseEvent) => {
|
||||
e.stopPropagation()
|
||||
goToCardDetail(row.iccid)
|
||||
}
|
||||
},
|
||||
row.iccid
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user