fetch(modify):修复BUG
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 3m27s
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 3m27s
This commit is contained in:
@@ -399,9 +399,6 @@
|
||||
getCarrierTypeText(currentCardDetail.carrier_type)
|
||||
}}</ElDescriptionsItem>
|
||||
|
||||
<ElDescriptionsItem label="卡类型">{{
|
||||
currentCardDetail.card_type || '--'
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="卡业务类型">{{
|
||||
getCardCategoryText(currentCardDetail.card_category)
|
||||
}}</ElDescriptionsItem>
|
||||
@@ -437,9 +434,9 @@
|
||||
>{{ currentCardDetail.data_usage_mb }} MB</ElDescriptionsItem
|
||||
>
|
||||
|
||||
<ElDescriptionsItem label="首次佣金">
|
||||
<ElDescriptionsItem label="一次性佣金">
|
||||
<ElTag :type="currentCardDetail.first_commission_paid ? 'success' : 'info'">
|
||||
{{ currentCardDetail.first_commission_paid ? '已支付' : '未支付' }}
|
||||
{{ currentCardDetail.first_commission_paid ? '已产生' : '未产生' }}
|
||||
</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="累计充值">{{
|
||||
@@ -463,6 +460,111 @@
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 流量使用查询对话框 -->
|
||||
<ElDialog v-model="flowUsageDialogVisible" title="流量使用查询" width="500px">
|
||||
<div v-if="flowUsageLoading" style="text-align: center; padding: 40px">
|
||||
<ElIcon class="is-loading" :size="40"><Loading /></ElIcon>
|
||||
<div style="margin-top: 16px">查询中...</div>
|
||||
</div>
|
||||
|
||||
<ElDescriptions v-else-if="flowUsageData" :column="1" border>
|
||||
<ElDescriptionsItem label="已用流量">{{
|
||||
flowUsageData.usedFlow || 0
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="流量单位">{{
|
||||
flowUsageData.unit || 'MB'
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem v-if="flowUsageData.extend" label="扩展信息">{{
|
||||
flowUsageData.extend
|
||||
}}</ElDescriptionsItem>
|
||||
</ElDescriptions>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton type="primary" @click="flowUsageDialogVisible = false">关闭</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 实名状态查询对话框 -->
|
||||
<ElDialog v-model="realnameStatusDialogVisible" title="实名认证状态" width="500px">
|
||||
<div v-if="realnameStatusLoading" style="text-align: center; padding: 40px">
|
||||
<ElIcon class="is-loading" :size="40"><Loading /></ElIcon>
|
||||
<div style="margin-top: 16px">查询中...</div>
|
||||
</div>
|
||||
|
||||
<ElDescriptions v-else-if="realnameStatusData" :column="1" border>
|
||||
<ElDescriptionsItem label="实名状态">{{
|
||||
realnameStatusData.status || '未知'
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem v-if="realnameStatusData.extend" label="扩展信息">{{
|
||||
realnameStatusData.extend
|
||||
}}</ElDescriptionsItem>
|
||||
</ElDescriptions>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton type="primary" @click="realnameStatusDialogVisible = false">关闭</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 卡实时状态查询对话框 -->
|
||||
<ElDialog v-model="cardStatusDialogVisible" title="卡实时状态" width="500px">
|
||||
<div v-if="cardStatusLoading" style="text-align: center; padding: 40px">
|
||||
<ElIcon class="is-loading" :size="40"><Loading /></ElIcon>
|
||||
<div style="margin-top: 16px">查询中...</div>
|
||||
</div>
|
||||
|
||||
<ElDescriptions v-else-if="cardStatusData" :column="1" border>
|
||||
<ElDescriptionsItem label="ICCID">{{
|
||||
cardStatusData.iccid || '--'
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="卡状态">{{
|
||||
cardStatusData.cardStatus || '未知'
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem v-if="cardStatusData.extend" label="扩展信息">{{
|
||||
cardStatusData.extend
|
||||
}}</ElDescriptionsItem>
|
||||
</ElDescriptions>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton type="primary" @click="cardStatusDialogVisible = false">关闭</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 实名认证链接对话框 -->
|
||||
<ElDialog v-model="realnameLinkDialogVisible" title="实名认证链接" width="500px">
|
||||
<div v-if="realnameLinkLoading" style="text-align: center; padding: 40px">
|
||||
<ElIcon class="is-loading" :size="40"><Loading /></ElIcon>
|
||||
<div style="margin-top: 16px">获取中...</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="realnameLinkData && realnameLinkData.link" style="text-align: center">
|
||||
<div style="margin-bottom: 16px">
|
||||
<img v-if="qrcodeDataURL" :src="qrcodeDataURL" alt="实名认证二维码" />
|
||||
</div>
|
||||
<ElDescriptions :column="1" border>
|
||||
<ElDescriptionsItem label="实名链接">
|
||||
<a :href="realnameLinkData.link" target="_blank" style="color: var(--el-color-primary)">
|
||||
{{ realnameLinkData.link }}
|
||||
</a>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem v-if="realnameLinkData.extend" label="扩展信息">{{
|
||||
realnameLinkData.extend
|
||||
}}</ElDescriptionsItem>
|
||||
</ElDescriptions>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton type="primary" @click="realnameLinkDialogVisible = false">关闭</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 更多操作右键菜单 -->
|
||||
<ArtMenuRight
|
||||
ref="moreMenuRef"
|
||||
@@ -470,6 +572,14 @@
|
||||
:menu-width="180"
|
||||
@select="handleMoreMenuSelect"
|
||||
/>
|
||||
|
||||
<!-- 表格行操作右键菜单 -->
|
||||
<ArtMenuRight
|
||||
ref="cardOperationMenuRef"
|
||||
:menu-items="cardOperationMenuItems"
|
||||
:menu-width="160"
|
||||
@select="handleCardOperationMenuSelect"
|
||||
/>
|
||||
</ElCard>
|
||||
</div>
|
||||
</ArtTableFullScreen>
|
||||
@@ -479,14 +589,16 @@
|
||||
import { h } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { CardService, ShopService, PackageSeriesService } from '@/api/modules'
|
||||
import { ElMessage, ElTag, ElIcon } from 'element-plus'
|
||||
import { ElMessage, ElTag, ElIcon, ElMessageBox } from 'element-plus'
|
||||
import { Loading } from '@element-plus/icons-vue'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import QRCode from 'qrcode'
|
||||
import type { SearchFormItem } from '@/types'
|
||||
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||
import { formatDateTime } from '@/utils/business/format'
|
||||
import ArtMenuRight from '@/components/core/others/ArtMenuRight.vue'
|
||||
import type { MenuItemType } from '@/components/core/others/ArtMenuRight.vue'
|
||||
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
||||
import type {
|
||||
StandaloneIotCard,
|
||||
StandaloneCardStatus,
|
||||
@@ -543,8 +655,28 @@
|
||||
const cardDetailLoading = ref(false)
|
||||
const currentCardDetail = ref<any>(null)
|
||||
|
||||
// IoT卡操作相关对话框
|
||||
const flowUsageDialogVisible = ref(false)
|
||||
const flowUsageLoading = ref(false)
|
||||
const flowUsageData = ref<any>(null)
|
||||
|
||||
const realnameStatusDialogVisible = ref(false)
|
||||
const realnameStatusLoading = ref(false)
|
||||
const realnameStatusData = ref<any>(null)
|
||||
|
||||
const cardStatusDialogVisible = ref(false)
|
||||
const cardStatusLoading = ref(false)
|
||||
const cardStatusData = ref<any>(null)
|
||||
|
||||
const realnameLinkDialogVisible = ref(false)
|
||||
const realnameLinkLoading = ref(false)
|
||||
const realnameLinkData = ref<any>(null)
|
||||
const qrcodeDataURL = ref<string>('')
|
||||
|
||||
// 更多操作右键菜单
|
||||
const moreMenuRef = ref<InstanceType<typeof ArtMenuRight>>()
|
||||
const cardOperationMenuRef = ref<InstanceType<typeof ArtMenuRight>>()
|
||||
const currentOperatingIccid = ref<string>('')
|
||||
|
||||
// 店铺相关
|
||||
const targetShopLoading = ref(false)
|
||||
@@ -728,9 +860,9 @@
|
||||
const columnOptions = [
|
||||
{ label: 'ICCID', prop: 'iccid' },
|
||||
{ label: '卡接入号', prop: 'msisdn' },
|
||||
{ label: '卡类型', prop: 'card_type' },
|
||||
{ label: '卡业务类型', prop: 'card_category' },
|
||||
{ label: '运营商', prop: 'carrier_name' },
|
||||
{ label: '店铺名称', prop: 'shop_name' },
|
||||
{ label: '成本价', prop: 'cost_price' },
|
||||
{ label: '分销价', prop: 'distribute_price' },
|
||||
{ label: '状态', prop: 'status' },
|
||||
@@ -738,7 +870,7 @@
|
||||
{ label: '网络状态', prop: 'network_status' },
|
||||
{ label: '实名状态', prop: 'real_name_status' },
|
||||
{ label: '累计流量(MB)', prop: 'data_usage_mb' },
|
||||
{ label: '首次佣金', prop: 'first_commission_paid' },
|
||||
{ label: '一次性佣金', prop: 'first_commission_paid' },
|
||||
{ label: '累计充值', prop: 'accumulated_recharge' },
|
||||
{ label: '创建时间', prop: 'created_at' }
|
||||
]
|
||||
@@ -865,21 +997,23 @@
|
||||
label: '卡接入号',
|
||||
width: 130
|
||||
},
|
||||
{
|
||||
prop: 'card_type',
|
||||
label: '卡类型',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
prop: 'card_category',
|
||||
label: '卡业务类型',
|
||||
width: 100
|
||||
width: 100,
|
||||
formatter: (row: StandaloneIotCard) => getCardCategoryText(row.card_category)
|
||||
},
|
||||
{
|
||||
prop: 'carrier_name',
|
||||
label: '运营商',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
prop: 'shop_name',
|
||||
label: '店铺名称',
|
||||
minWidth: 150,
|
||||
formatter: (row: StandaloneIotCard) => row.shop_name || '-'
|
||||
},
|
||||
{
|
||||
prop: 'cost_price',
|
||||
label: '成本价',
|
||||
@@ -937,11 +1071,11 @@
|
||||
},
|
||||
{
|
||||
prop: 'first_commission_paid',
|
||||
label: '首次佣金',
|
||||
label: '一次性佣金',
|
||||
width: 100,
|
||||
formatter: (row: StandaloneIotCard) => {
|
||||
const type = row.first_commission_paid ? 'success' : 'info'
|
||||
const text = row.first_commission_paid ? '已支付' : '未支付'
|
||||
const text = row.first_commission_paid ? '已产生' : '未产生'
|
||||
return h(ElTag, { type, size: 'small' }, () => text)
|
||||
}
|
||||
},
|
||||
@@ -956,6 +1090,24 @@
|
||||
label: '创建时间',
|
||||
width: 180,
|
||||
formatter: (row: StandaloneIotCard) => formatDateTime(row.created_at)
|
||||
},
|
||||
{
|
||||
prop: 'operation',
|
||||
label: '操作',
|
||||
width: 200,
|
||||
fixed: 'right',
|
||||
formatter: (row: StandaloneIotCard) => {
|
||||
return h('div', { style: 'display: flex; gap: 0; align-items: center;' }, [
|
||||
h(ArtButtonTable, {
|
||||
text: '查询流量',
|
||||
onClick: () => showFlowUsageDialog(row.iccid)
|
||||
}),
|
||||
h(ArtButtonTable, {
|
||||
text: '更多操作',
|
||||
onContextmenu: (e: MouseEvent) => showCardOperationMenu(e, row.iccid)
|
||||
})
|
||||
])
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
@@ -1364,28 +1516,47 @@
|
||||
const moreMenuItems = computed((): MenuItemType[] => [
|
||||
{
|
||||
key: 'distribution',
|
||||
label: '网卡分销',
|
||||
icon: ''
|
||||
label: '网卡分销'
|
||||
},
|
||||
{
|
||||
key: 'recharge',
|
||||
label: '批量充值',
|
||||
icon: ''
|
||||
label: '批量充值'
|
||||
},
|
||||
{
|
||||
key: 'recycle',
|
||||
label: '网卡回收',
|
||||
icon: ''
|
||||
label: '网卡回收'
|
||||
},
|
||||
{
|
||||
key: 'download',
|
||||
label: '批量下载',
|
||||
icon: ''
|
||||
label: '批量下载'
|
||||
},
|
||||
{
|
||||
key: 'changePackage',
|
||||
label: '变更套餐',
|
||||
icon: ''
|
||||
label: '变更套餐'
|
||||
}
|
||||
])
|
||||
|
||||
// 卡操作菜单项配置
|
||||
const cardOperationMenuItems = computed((): MenuItemType[] => [
|
||||
{
|
||||
key: 'realname-status',
|
||||
label: '查询实名状态'
|
||||
},
|
||||
{
|
||||
key: 'card-status',
|
||||
label: '查询卡状态'
|
||||
},
|
||||
{
|
||||
key: 'realname-link',
|
||||
label: '获取实名链接'
|
||||
},
|
||||
{
|
||||
key: 'start-card',
|
||||
label: '启用卡片'
|
||||
},
|
||||
{
|
||||
key: 'stop-card',
|
||||
label: '停用卡片'
|
||||
}
|
||||
])
|
||||
|
||||
@@ -1417,6 +1588,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 显示卡操作菜单
|
||||
const showCardOperationMenu = (e: MouseEvent, iccid: string) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
currentOperatingIccid.value = iccid
|
||||
cardOperationMenuRef.value?.show(e)
|
||||
}
|
||||
|
||||
// 处理卡操作菜单选择
|
||||
const handleCardOperationMenuSelect = (item: MenuItemType) => {
|
||||
const iccid = currentOperatingIccid.value
|
||||
if (!iccid) return
|
||||
|
||||
handleCardOperation(item.key, iccid)
|
||||
}
|
||||
|
||||
// 网卡分销 - 正在开发中
|
||||
const cardDistribution = () => {
|
||||
ElMessage.info('功能正在开发中')
|
||||
@@ -1441,6 +1628,177 @@
|
||||
const changePackage = () => {
|
||||
ElMessage.info('功能正在开发中')
|
||||
}
|
||||
|
||||
// IoT卡操作处理函数
|
||||
const handleCardOperation = (command: string, iccid: string) => {
|
||||
switch (command) {
|
||||
case 'realname-status':
|
||||
showRealnameStatusDialog(iccid)
|
||||
break
|
||||
case 'card-status':
|
||||
showCardStatusDialog(iccid)
|
||||
break
|
||||
case 'realname-link':
|
||||
showRealnameLinkDialog(iccid)
|
||||
break
|
||||
case 'start-card':
|
||||
handleStartCard(iccid)
|
||||
break
|
||||
case 'stop-card':
|
||||
handleStopCard(iccid)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 查询流量使用
|
||||
const showFlowUsageDialog = async (iccid: string) => {
|
||||
flowUsageDialogVisible.value = true
|
||||
flowUsageLoading.value = true
|
||||
flowUsageData.value = null
|
||||
|
||||
try {
|
||||
const res = await CardService.getGatewayFlow(iccid)
|
||||
if (res.code === 0) {
|
||||
flowUsageData.value = res.data
|
||||
} else {
|
||||
ElMessage.error(res.message || '查询失败')
|
||||
flowUsageDialogVisible.value = false
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('查询流量使用失败:', error)
|
||||
ElMessage.error(error?.message || '查询失败')
|
||||
flowUsageDialogVisible.value = false
|
||||
} finally {
|
||||
flowUsageLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 查询实名认证状态
|
||||
const showRealnameStatusDialog = async (iccid: string) => {
|
||||
realnameStatusDialogVisible.value = true
|
||||
realnameStatusLoading.value = true
|
||||
realnameStatusData.value = null
|
||||
|
||||
try {
|
||||
const res = await CardService.getGatewayRealname(iccid)
|
||||
if (res.code === 0) {
|
||||
realnameStatusData.value = res.data
|
||||
} else {
|
||||
ElMessage.error(res.message || '查询失败')
|
||||
realnameStatusDialogVisible.value = false
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('查询实名状态失败:', error)
|
||||
ElMessage.error(error?.message || '查询失败')
|
||||
realnameStatusDialogVisible.value = false
|
||||
} finally {
|
||||
realnameStatusLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 查询卡实时状态
|
||||
const showCardStatusDialog = async (iccid: string) => {
|
||||
cardStatusDialogVisible.value = true
|
||||
cardStatusLoading.value = true
|
||||
cardStatusData.value = null
|
||||
|
||||
try {
|
||||
const res = await CardService.getGatewayStatus(iccid)
|
||||
if (res.code === 0) {
|
||||
cardStatusData.value = res.data
|
||||
} else {
|
||||
ElMessage.error(res.message || '查询失败')
|
||||
cardStatusDialogVisible.value = false
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('查询卡状态失败:', error)
|
||||
ElMessage.error(error?.message || '查询失败')
|
||||
cardStatusDialogVisible.value = false
|
||||
} finally {
|
||||
cardStatusLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 获取实名认证链接
|
||||
const showRealnameLinkDialog = async (iccid: string) => {
|
||||
realnameLinkDialogVisible.value = true
|
||||
realnameLinkLoading.value = true
|
||||
realnameLinkData.value = null
|
||||
qrcodeDataURL.value = ''
|
||||
|
||||
try {
|
||||
const res = await CardService.getRealnameLink(iccid)
|
||||
if (res.code === 0 && res.data?.link) {
|
||||
realnameLinkData.value = res.data
|
||||
// 生成二维码
|
||||
qrcodeDataURL.value = await QRCode.toDataURL(res.data.link, {
|
||||
width: 200,
|
||||
margin: 1
|
||||
})
|
||||
} else {
|
||||
ElMessage.error(res.message || '获取失败')
|
||||
realnameLinkDialogVisible.value = false
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('获取实名链接失败:', error)
|
||||
ElMessage.error(error?.message || '获取失败')
|
||||
realnameLinkDialogVisible.value = false
|
||||
} finally {
|
||||
realnameLinkLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 启用卡片(复机)
|
||||
const handleStartCard = (iccid: string) => {
|
||||
ElMessageBox.confirm('确定要启用该卡片吗?', '确认启用', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(async () => {
|
||||
try {
|
||||
const res = await CardService.startCard(iccid)
|
||||
if (res.code === 0) {
|
||||
ElMessage.success('启用成功')
|
||||
getTableData()
|
||||
} else {
|
||||
ElMessage.error(res.message || '启用失败')
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('启用卡片失败:', error)
|
||||
ElMessage.error(error?.message || '启用失败')
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
// 用户取消
|
||||
})
|
||||
}
|
||||
|
||||
// 停用卡片(停机)
|
||||
const handleStopCard = (iccid: string) => {
|
||||
ElMessageBox.confirm('确定要停用该卡片吗?', '确认停用', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(async () => {
|
||||
try {
|
||||
const res = await CardService.stopCard(iccid)
|
||||
if (res.code === 0) {
|
||||
ElMessage.success('停用成功')
|
||||
getTableData()
|
||||
} else {
|
||||
ElMessage.error(res.message || '停用失败')
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('停用卡片失败:', error)
|
||||
ElMessage.error(error?.message || '停用失败')
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
// 用户取消
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
Reference in New Issue
Block a user