diff --git a/src/components/device/SwitchCardDialog.vue b/src/components/device/SwitchCardDialog.vue index 4b65b70..2f06543 100644 --- a/src/components/device/SwitchCardDialog.vue +++ b/src/components/device/SwitchCardDialog.vue @@ -42,9 +42,12 @@ :label="`${card.iccid} - 插槽${card.slot_position} - ${card.carrier_name}`" :value="card.iccid" > -
+
{{ card.iccid }} - 插槽{{ card.slot_position }} +
+ 插槽{{ card.slot_position }} + {{ card.carrier_name }} +
diff --git a/src/types/api/card.ts b/src/types/api/card.ts index 7ed4c09..681f185 100644 --- a/src/types/api/card.ts +++ b/src/types/api/card.ts @@ -374,8 +374,9 @@ export interface StandaloneIotCard { activated_at?: string | null // 激活时间 (可选) created_at: string // 创建时间 updated_at: string // 更新时间 - series_id?: number | null // 套餐系列ID - series_name?: string // 套餐系列名称 + series_id: number | null // 套餐系列ID + series_name: string // 套餐系列名称 + realname_policy: string // 实名制策略 } // ========== 单卡批量分配和回收相关 ========== diff --git a/src/views/asset-management/asset-information/components/BasicInfoCard.vue b/src/views/asset-management/asset-information/components/BasicInfoCard.vue index 929a872..705b195 100644 --- a/src/views/asset-management/asset-information/components/BasicInfoCard.vue +++ b/src/views/asset-management/asset-information/components/BasicInfoCard.vue @@ -10,7 +10,7 @@
-
+
自动轮询 - {{ - cardInfo?.software_version || '-' - }} {{ getSwitchModeName(cardInfo?.switch_mode) }} @@ -211,7 +208,7 @@ size="small" link @click="handleEnableBindingCard(scope.row)" - v-permission="'iot_card:start'" + v-permission="'iot_info:start'" > 启用此卡 @@ -221,7 +218,7 @@ size="small" link @click="handleDisableBindingCard(scope.row)" - v-permission="'iot_card:stop'" + v-permission="'iot_info:stop'" > 停用此卡 @@ -367,20 +364,53 @@ class="card-operations" style="margin-top: 16px; text-align: right" > - 启用此卡 - 停用此卡 - - 实名认证策略 + + 启用此卡 + + + 停用此卡 + + + + + 实名认证策略 +
- 设置切卡模式 - 重启设备 - 恢复出厂 - 切换SIM卡 - 设置WiFi - 实名认证策略 + 设置切卡模式 + + 重启设备 + + + 恢复出厂 + + + 切换SIM卡 + + + 设置WiFi + + + 实名认证策略 +
@@ -499,11 +529,21 @@ const { hasAuth } = useAuth() const realnamePolicyPermission = computed(() => { - return props.cardInfo?.asset_type === 'card' ? 'asset:card_realname_policy' : 'asset:device_realname_policy' + return props.cardInfo?.asset_type === 'card' + ? 'asset:card_realname_policy' + : 'asset:device_realname_policy' }) const canShowRealnamePolicy = computed(() => hasAuth(realnamePolicyPermission.value)) + const pollingPermission = computed(() => { + return props.cardInfo?.asset_type === 'card' + ? 'iot_info:auto_polling' + : 'device_info:auto_polling' + }) + + const canShowPolling = computed(() => hasAuth(pollingPermission.value)) + // Emits interface Emits { (e: 'update:pollingEnabled', value: boolean): void diff --git a/src/views/asset-management/asset-information/index.vue b/src/views/asset-management/asset-information/index.vue index 74944d2..247beaf 100644 --- a/src/views/asset-management/asset-information/index.vue +++ b/src/views/asset-management/asset-information/index.vue @@ -87,7 +87,8 @@ @@ -376,7 +381,7 @@ - + - -
- -
加载设备绑定的卡列表中...
-
- - - - -
+ @@ -566,7 +509,9 @@ label-width="120px" > - {{ currentOperatingDeviceIdentifier }} + {{ + currentOperatingDeviceIdentifier + }} @@ -621,6 +566,7 @@ import { ElMessage, ElMessageBox, ElTag, ElIcon, ElRadioGroup, ElRadio } from 'element-plus' import { Loading } from '@element-plus/icons-vue' import type { FormInstance, FormRules } from 'element-plus' + import SwitchCardDialog from '@/components/device/SwitchCardDialog.vue' import type { Device, DeviceStatus, @@ -708,6 +654,7 @@ const bindCardFormRef = ref() const iotCardList = ref([]) const iotCardSearchLoading = ref(false) + const iotCardHasSearched = ref(false) // 标记是否已执行过搜索 const bindCardForm = reactive({ iot_card_id: undefined as number | undefined, slot_position: 1 @@ -724,13 +671,6 @@ const switchCardDialogVisible = ref(false) const switchCardLoading = ref(false) - const switchCardFormRef = ref() - const switchCardForm = reactive({ - target_iccid: '' - }) - const switchCardRules = reactive({ - target_iccid: [{ required: true, message: '请选择目标ICCID', trigger: 'change' }] - }) const deviceBindingCards = ref([]) // 设备绑定的卡列表 const loadingDeviceCards = ref(false) // 加载设备绑定卡列表的状态 @@ -868,7 +808,7 @@ { label: '已绑定卡数', prop: 'bound_card_count' }, { label: '状态', prop: 'status' }, { label: '在线状态', prop: 'online_status' }, - { label: '固件版本', prop: 'software_version' }, + { label: '切卡模式', prop: 'switch_mode' }, { label: '最后在线时间', prop: 'last_online_time' }, { label: '最后同步时间', prop: 'last_gateway_sync_at' }, @@ -917,8 +857,8 @@ // 重置绑定卡表单 bindCardForm.iot_card_id = undefined bindCardForm.slot_position = 1 - // 加载设备卡列表和默认IoT卡列表 - await Promise.all([loadDeviceCards(device.virtual_no), loadDefaultIotCards()]) + // 只加载设备卡列表 + await loadDeviceCards(device.virtual_no) } // 加载设备绑定的卡列表 @@ -927,15 +867,9 @@ try { const res = await DeviceService.getDeviceCards(virtualNo) if (res.code === 0 && res.data) { - deviceCards.value = res.data.bindings || [] - console.log('设备绑定的卡列表:', deviceCards.value) - - // 🔧 临时调试:强制第一张卡显示为当前卡(方便测试UI效果) - // 测试完成后请删除此代码 - if (deviceCards.value.length > 0) { - deviceCards.value[0].is_current = true - console.log('🧪 测试模式:已将第一张卡标记为当前卡') - } + deviceCards.value = (res.data.bindings || []).sort( + (a, b) => a.slot_position - b.slot_position + ) } } catch (error) { console.error('获取设备绑定的卡列表失败:', error) @@ -950,7 +884,8 @@ try { const res = await CardService.getStandaloneIotCards({ page: 1, - page_size: 20 + page_size: 20, + is_standalone: true }) if (res.code === 0 && res.data?.items) { iotCardList.value = res.data.items @@ -969,11 +904,13 @@ return } iotCardSearchLoading.value = true + iotCardHasSearched.value = true try { const res = await CardService.getStandaloneIotCards({ page: 1, page_size: 20, - iccid: query + iccid: query, + is_standalone: true }) if (res.code === 0 && res.data?.items) { iotCardList.value = res.data.items @@ -1182,13 +1119,6 @@ return h(ElTag, { type: status.type }, () => status.text) } }, - { - prop: 'software_version', - label: '固件版本', - width: 120, - showOverflowTooltip: true, - formatter: (row: Device) => row.software_version || '-' - }, { prop: 'switch_mode', label: '切卡模式', @@ -1201,6 +1131,20 @@ return modeMap[row.switch_mode || ''] || '-' } }, + { + prop: 'realname_policy', + label: '实名认证策略', + width: 150, + formatter: (row: Device) => { + const policy = row.realname_policy || '' + const policyMap: Record = { + none: '无需实名', + before_order: '先实名后充值/购买', + after_order: '先充值/购买后实名' + } + return policyMap[policy] || (policy ? policy : '未知') + } + }, { prop: 'last_online_time', label: '最后在线时间', @@ -1229,13 +1173,17 @@ } ]) + let isFirstActivation = true onMounted(() => { getTableData() }) // 当页面被 keep-alive 激活时自动刷新数据 onActivated(() => { - getTableData() + if (!isFirstActivation) { + getTableData() + } + isFirstActivation = false }) // 获取设备列表 @@ -1758,7 +1706,6 @@ // 显示切换SIM卡对话框 const showSwitchCardDialog = async (imei: string) => { currentOperatingImei.value = imei - switchCardForm.target_iccid = '' deviceBindingCards.value = [] switchCardDialogVisible.value = true @@ -1775,14 +1722,6 @@ const res = await DeviceService.getDeviceCards(device.virtual_no) if (res.code === 0 && res.data) { deviceBindingCards.value = res.data.bindings || [] - - // 🔧 临时调试:强制第一张卡显示为当前卡(方便测试UI效果) - // 测试完成后请删除此代码 - if (deviceBindingCards.value.length > 0) { - deviceBindingCards.value[0].is_current = true - console.log('🧪 切换SIM卡测试模式:已将第一张卡标记为当前卡') - } - if (deviceBindingCards.value.length === 0) { ElMessage.warning('该设备暂无绑定的SIM卡') } @@ -1795,29 +1734,20 @@ } // 确认切换SIM卡 - const handleConfirmSwitchCard = async () => { - if (!switchCardFormRef.value) return - - await switchCardFormRef.value.validate(async (valid) => { - if (valid) { - switchCardLoading.value = true - try { - const res = await DeviceService.switchCard(currentOperatingImei.value, { - target_iccid: switchCardForm.target_iccid - }) - if (res.code === 0) { - ElMessage.success('切换SIM卡指令已发送') - switchCardDialogVisible.value = false - } else { - ElMessage.error(res.msg || '切换失败') - } - } catch (error: any) { - console.error('切换SIM卡失败:', error) - } finally { - switchCardLoading.value = false - } + const handleConfirmSwitchCard = async (data: { target_iccid: string }) => { + try { + const res = await DeviceService.switchCard(currentOperatingImei.value, { + target_iccid: data.target_iccid + }) + if (res.code === 0) { + ElMessage.success('切换SIM卡指令已发送') + switchCardDialogVisible.value = false + } else { + ElMessage.error(res.msg || '切换失败') } - }) + } catch (error: any) { + console.error('切换SIM卡失败:', error) + } } // 显示设置WiFi对话框 diff --git a/src/views/asset-management/iot-card-management/index.vue b/src/views/asset-management/iot-card-management/index.vue index d43990b..e1e1f6f 100644 --- a/src/views/asset-management/iot-card-management/index.vue +++ b/src/views/asset-management/iot-card-management/index.vue @@ -5,7 +5,7 @@ @@ -927,7 +927,7 @@ ] }, { - label: '独立卡', + label: '是否绑定设备', prop: 'is_standalone', type: 'select', config: { @@ -955,6 +955,7 @@ { label: '激活状态', prop: 'activation_status' }, { label: '网络状态', prop: 'network_status' }, { label: '实名状态', prop: 'real_name_status' }, + { label: '实名认证策略', prop: 'realname_policy' }, { label: '累计流量(MB)', prop: 'data_usage_mb' }, { label: '创建时间', prop: 'created_at' } ] @@ -1046,10 +1047,6 @@ return typeMap[status] || 'info' } - const formatCardPrice = (price: number) => { - return `¥${(price / 100).toFixed(2)}` - } - // 动态列配置 const { columnChecks, columns } = useCheckedColumns(() => [ { @@ -1151,6 +1148,21 @@ return h(ElTag, { type }, () => text) } }, + { + prop: 'realname_policy', + label: '实名认证策略', + width: 150, + formatter: (row: StandaloneIotCard) => { + const policy = row.realname_policy || '' + const policyMap: Record = { + none: '无需实名', + before_order: '先实名后充值/购买', + after_order: '先充值/购买后实名' + } + const text = policyMap[policy] || (policy ? policy : '未知') + return text + } + }, { prop: 'data_usage_mb', label: '累计流量(MB)', @@ -1711,99 +1723,6 @@ }) } - // 查询流量使用 - const showFlowUsageDialog = async (iccid: string) => { - flowUsageDialogVisible.value = true - flowUsageLoading.value = true - flowUsageData.value = null - - try { - // 通过 ICCID 解析获取资产信息,resolveAsset 接口已包含所有需要的数据 - const res = await AssetService.resolveAsset(iccid) - if (res.code === 0 && res.data) { - // 直接使用 resolveAsset 返回的流量信息 - flowUsageData.value = { - totalFlow: res.data.package_total_mb || 0, - usedFlow: res.data.package_used_mb || 0, - remainFlow: res.data.package_remain_mb || 0, - extend: res.data.extend - } - } else { - ElMessage.error(res.msg || '查询失败') - flowUsageDialogVisible.value = false - } - } catch (error: any) { - console.error('查询流量使用失败:', error) - flowUsageDialogVisible.value = false - } finally { - flowUsageLoading.value = false - } - } - - // 查询实名认证状态 - const showRealnameStatusDialog = async (iccid: string) => { - realnameStatusDialogVisible.value = true - realnameStatusLoading.value = true - realnameStatusData.value = null - - try { - // 通过 ICCID 解析获取资产信息,resolveAsset 接口已包含所有需要的数据 - const res = await AssetService.resolveAsset(iccid) - if (res.code === 0 && res.data) { - // 直接使用 resolveAsset 返回的实名状态,real_name_status: 0未实名 1已实名 - let statusText = '未知' - switch (res.data.real_name_status) { - case 0: - statusText = '未实名' - break - case 1: - statusText = '已实名' - break - } - realnameStatusData.value = { - status: statusText, - extend: res.data.extend - } - } else { - ElMessage.error(res.msg || '查询失败') - realnameStatusDialogVisible.value = false - } - } catch (error: any) { - console.error('查询实名状态失败:', error) - realnameStatusDialogVisible.value = false - } finally { - realnameStatusLoading.value = false - } - } - - // 查询卡实时状态 - const showCardStatusDialog = async (iccid: string) => { - cardStatusDialogVisible.value = true - cardStatusLoading.value = true - cardStatusData.value = null - - try { - // 通过 ICCID 解析获取资产信息,resolveAsset 接口已包含所有需要的数据 - const res = await AssetService.resolveAsset(iccid) - if (res.code === 0 && res.data) { - // 直接使用 resolveAsset 返回的网络状态 - cardStatusData.value = { - iccid: iccid, - cardStatus: res.data.network_status === 1 ? '正常' : '停机', - extend: res.data.extend - } - } else { - ElMessage.error(res.msg || '查询失败') - cardStatusDialogVisible.value = false - } - } catch (error: any) { - console.error('查询卡状态失败:', error) - cardStatusDialogVisible.value = false - } finally { - cardStatusLoading.value = false - } - } - // 启用此卡(复机) const handleStartCard = (iccid: string) => { ElMessageBox.confirm('确定要启用该卡片吗?', '确认启用', {