修改bug
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 8m39s

This commit is contained in:
sexygoat
2026-03-11 17:09:35 +08:00
parent bd45f7a224
commit d43de4cd06
37 changed files with 2552 additions and 1696 deletions

View File

@@ -1,312 +0,0 @@
<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>

View File

@@ -51,7 +51,7 @@
hasAuth('iot_card:batch_download')
"
type="info"
@contextmenu.prevent="showMoreMenu"
@click="showMoreMenuOnClick"
>
更多操作
</ElButton>
@@ -68,10 +68,13 @@
:pageSize="pagination.pageSize"
:total="pagination.total"
:marginTop="10"
:row-class-name="getRowClassName"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
@selection-change="handleSelectionChange"
@row-contextmenu="handleRowContextMenu"
@cell-mouse-enter="handleCellMouseEnter"
@cell-mouse-leave="handleCellMouseLeave"
>
<template #default>
<ElTableColumn type="selection" width="55" />
@@ -79,6 +82,9 @@
</template>
</ArtTable>
<!-- 鼠标悬浮提示 -->
<TableContextMenuHint :visible="showContextMenuHint" :position="hintPosition" />
<!-- 批量分配对话框 -->
<ElDialog
v-model="allocateDialogVisible"
@@ -597,8 +603,10 @@
import type { SearchFormItem } from '@/types'
import { useCheckedColumns } from '@/composables/useCheckedColumns'
import { useAuth } from '@/composables/useAuth'
import { useTableContextMenu } from '@/composables/useTableContextMenu'
import { formatDateTime } from '@/utils/business/format'
import ArtMenuRight from '@/components/core/others/ArtMenuRight.vue'
import TableContextMenuHint from '@/components/core/others/TableContextMenuHint.vue'
import type { MenuItemType } from '@/components/core/others/ArtMenuRight.vue'
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
import type {
@@ -616,6 +624,16 @@
const { hasAuth } = useAuth()
const router = useRouter()
// 使用表格右键菜单功能
const {
showContextMenuHint,
hintPosition,
getRowClassName,
handleCellMouseEnter,
handleCellMouseLeave
} = useTableContextMenu()
const loading = ref(false)
const allocateDialogVisible = ref(false)
const allocateLoading = ref(false)
@@ -910,11 +928,11 @@
}
}
// 跳转到IoT卡详情页面
// 跳转到资产信息页面(原IoT卡详情)
const goToCardDetail = (iccid: string) => {
if (hasAuth('iot_card:view_detail')) {
router.push({
path: RoutesAlias.StandaloneCardList + '/detail',
path: '/asset-management/single-card',
query: {
iccid: iccid
}
@@ -1575,13 +1593,19 @@
return items
})
// 显示更多操作菜单
// 显示更多操作菜单 (右键)
const showMoreMenu = (e: MouseEvent) => {
e.preventDefault()
e.stopPropagation()
moreMenuRef.value?.show(e)
}
// 显示更多操作菜单 (左键点击)
const showMoreMenuOnClick = (e: MouseEvent) => {
e.stopPropagation()
moreMenuRef.value?.show(e)
}
// 处理更多操作菜单选择
const handleMoreMenuSelect = (item: MenuItemType) => {
switch (item.key) {
@@ -1829,4 +1853,8 @@
.standalone-card-list-page {
// Card list page styles
}
:deep(.el-table__row.table-row-with-context-menu) {
cursor: pointer;
}
</style>