diff --git a/src/views/asset-management/asset-information/components/BasicInfoCard.vue b/src/views/asset-management/asset-information/components/BasicInfoCard.vue index 8ae17a7..f873b1f 100644 --- a/src/views/asset-management/asset-information/components/BasicInfoCard.vue +++ b/src/views/asset-management/asset-information/components/BasicInfoCard.vue @@ -267,16 +267,40 @@ - {{ deviceRealtime.rssi || '-' }} + {{ + deviceRealtime.rssi !== undefined && + deviceRealtime.rssi !== null && + deviceRealtime.rssi !== '' + ? deviceRealtime.rssi + : '-' + }} - {{ deviceRealtime.rsrp ? `${deviceRealtime.rsrp} dBm` : '-' }} + {{ + deviceRealtime.rsrp !== undefined && + deviceRealtime.rsrp !== null && + deviceRealtime.rsrp !== '' + ? `${deviceRealtime.rsrp} dBm` + : '-' + }} - {{ deviceRealtime.rsrq ? `${deviceRealtime.rsrq} dB` : '-' }} + {{ + deviceRealtime.rsrq !== undefined && + deviceRealtime.rsrq !== null && + deviceRealtime.rsrq !== '' + ? `${deviceRealtime.rsrq} dB` + : '-' + }} - {{ deviceRealtime.sinr ? `${deviceRealtime.sinr} dB` : '-' }} + {{ + deviceRealtime.sinr !== undefined && + deviceRealtime.sinr !== null && + deviceRealtime.sinr !== '' + ? `${deviceRealtime.sinr} dB` + : '-' + }} {{ deviceRealtime.client_number }} / {{ deviceRealtime.max_clients }} diff --git a/src/views/asset-management/asset-information/composables/useAssetFormatters.ts b/src/views/asset-management/asset-information/composables/useAssetFormatters.ts index f3f94d9..9fbdfee 100644 --- a/src/views/asset-management/asset-information/composables/useAssetFormatters.ts +++ b/src/views/asset-management/asset-information/composables/useAssetFormatters.ts @@ -4,8 +4,10 @@ import type { Ref } from 'vue' +type TagType = 'primary' | 'success' | 'warning' | 'info' | 'danger' + export function useAssetFormatters(deviceRealtime?: Ref) { - // 格式化数据大小(MB转GB/MB) + // 格式化数据大小(MB 转 GB/MB) const formatDataSize = (mb: number) => { if (mb >= 1024) { return `${(mb / 1024).toFixed(2)}GB` @@ -20,11 +22,11 @@ export function useAssetFormatters(deviceRealtime?: Ref) { return `¥${yuan.toFixed(2)}` } - // 格式化时长(秒转为时分秒) + // 格式化时长(秒转时分秒) const formatDuration = (seconds?: string) => { if (!seconds) return '-' const sec = Number(seconds) - if (isNaN(sec)) return '-' + if (Number.isNaN(sec)) return '-' const hours = Math.floor(sec / 3600) const minutes = Math.floor((sec % 3600) / 60) @@ -32,14 +34,14 @@ export function useAssetFormatters(deviceRealtime?: Ref) { if (hours > 0) { return `${hours}小时${minutes}分${secs}秒` - } else if (minutes > 0) { - return `${minutes}分${secs}秒` - } else { - return `${secs}秒` } + if (minutes > 0) { + return `${minutes}分${secs}秒` + } + return `${secs}秒` } - // 格式化ICCID为4位一组,用横杠分隔 + // 格式化 ICCID,每 4 位一组,用横杠分隔 const formatIccidWithDashes = (iccid: string) => { if (!iccid) return '' return iccid.replace(/(\d{4})(?=\d)/g, '$1-') @@ -89,15 +91,13 @@ export function useAssetFormatters(deviceRealtime?: Ref) { } // 获取资产状态标签类型 - const getAssetStatusType = ( - status?: number - ): 'primary' | 'success' | 'warning' | 'info' | 'danger' => { + const getAssetStatusType = (status?: number): TagType => { if (status === undefined || status === null) return 'info' - const map: Record = { - 1: 'info', // 在库 - 2: 'success', // 已分销 - 3: 'success', // 已激活 - 4: 'danger' // 已停用 + const map: Record = { + 1: 'info', + 2: 'success', + 3: 'success', + 4: 'danger' } return map[status] || 'info' } @@ -113,81 +113,87 @@ export function useAssetFormatters(deviceRealtime?: Ref) { } // 获取在线状态标签类型 - const getOnlineStatusType = ( - status?: number - ): 'primary' | 'success' | 'warning' | 'info' | 'danger' => { - const map: Record = { - 0: 'info', // 未知 - 1: 'success', // 在线 - 2: 'danger' // 离线 + const getOnlineStatusType = (status?: number): TagType => { + const map: Record = { + 0: 'info', + 1: 'success', + 2: 'danger' } return map[status ?? 0] || 'info' } // 获取钱包状态标签类型 const getWalletStatusType = (status?: number) => { - const map: Record = { - 1: 'success', // 正常 - 2: 'warning', // 冻结 - 3: 'danger' // 关闭 + const map: Record = { + 1: 'success', + 2: 'warning', + 3: 'danger' } return map[status || 1] || 'info' } // 获取套餐状态标签类型 - const getPackageStatusTagType = ( - status?: number - ): 'primary' | 'success' | 'warning' | 'info' | 'danger' => { + const getPackageStatusTagType = (status?: number): TagType => { if (status === undefined || status === null) return 'info' - const map: Record = { - 0: 'info', // 待生效 - 1: 'success', // 生效中 - 2: 'warning', // 已用完 - 3: 'danger', // 已过期 - 4: 'info' // 已失效 + const map: Record = { + 0: 'info', + 1: 'success', + 2: 'warning', + 3: 'danger', + 4: 'info' } return map[status] || 'info' } - // 计算信号强度等级(基于RSSI、RSRP、RSRQ) + const parseSignalValue = (value: unknown) => { + if (value === null || value === undefined || value === '') return null + const parsed = Number(value) + return Number.isNaN(parsed) ? null : parsed + } + + const clamp = (value: number, min: number, max: number) => { + return Math.min(Math.max(value, min), max) + } + + const calculateSignalScore = () => { + if (!deviceRealtime?.value) return null + + const rsrp = parseSignalValue(deviceRealtime.value.rsrp) + const rsrq = parseSignalValue(deviceRealtime.value.rsrq) + const sinr = parseSignalValue(deviceRealtime.value.sinr) + + // RSRP、RSRQ 必须是负数;SINR 允许 0 或负值 + if (rsrp === null || rsrq === null || sinr === null) return null + if (rsrp >= 0 || rsrq >= 0) return null + + const rsrpScore = clamp((rsrp + 120) * 2, 0, 100) + const rsrqScore = clamp((rsrq + 20) * 5, 0, 100) + const sinrScore = clamp(sinr * 5, 0, 100) + + return rsrpScore * 0.5 + sinrScore * 0.3 + rsrqScore * 0.2 + } + + // 计算信号强度等级:基于 RSRP、RSRQ、SINR 的综合评分,RSSI 不参与 const calculateSignalStrength = () => { - if (!deviceRealtime?.value) return '-' + const score = calculateSignalScore() + if (score === null) return '-' - const rssi = deviceRealtime.value.rssi ? Number(deviceRealtime.value.rssi) : null - const rsrp = deviceRealtime.value.rsrp ? Number(deviceRealtime.value.rsrp) : null - - // 优先使用RSRP判断(更准确) - // RSRP范围通常在-140到-44 dBm之间,0或正值表示无效数据 - if (rsrp !== null && !isNaN(rsrp) && rsrp < 0) { - if (rsrp >= -80) return '优秀' - if (rsrp >= -90) return '良好' - if (rsrp >= -100) return '一般' - if (rsrp >= -110) return '较差' - return '极差' - } - - // 其次使用RSSI - // RSSI范围通常在-113到-51 dBm之间,0或正值表示无效数据 - if (rssi !== null && !isNaN(rssi) && rssi < 0) { - if (rssi >= -70) return '优秀' - if (rssi >= -85) return '良好' - if (rssi >= -100) return '一般' - if (rssi >= -110) return '较差' - return '极差' - } - - return '-' + if (score >= 85) return '极好' + if (score >= 70) return '良好' + if (score >= 50) return '一般' + if (score >= 30) return '较差' + return '很差' } // 获取信号强度标签类型 - const getSignalStrengthType = (): 'primary' | 'success' | 'warning' | 'info' | 'danger' => { + const getSignalStrengthType = (): TagType => { const strength = calculateSignalStrength() - const map: Record = { - 优秀: 'success', + const map: Record = { + 极好: 'success', 良好: 'success', 一般: 'warning', 较差: 'danger', - 极差: 'danger' + 很差: 'danger' } return map[strength] || 'info' } @@ -203,10 +209,10 @@ export function useAssetFormatters(deviceRealtime?: Ref) { // 获取交易类型标签颜色 const getTransactionTypeTag = (type: string | undefined) => { - const map: Record = { - recharge: 'success', // 充值 - deduct: 'danger', // 扣款 - refund: 'warning' // 退款 + const map: Record = { + recharge: 'success', + deduct: 'danger', + refund: 'warning' } return map[type || ''] || 'info' } @@ -214,10 +220,10 @@ export function useAssetFormatters(deviceRealtime?: Ref) { // 获取支付状态标签类型 const getPaymentStatusType = (status: number): 'success' | 'warning' | 'danger' | 'info' => { const statusMap: Record = { - 1: 'warning', // 待支付 - 2: 'success', // 已支付 - 3: 'danger', // 已取消 - 4: 'info' // 已关闭 + 1: 'warning', + 2: 'success', + 3: 'danger', + 4: 'info' } return statusMap[status] || 'info' }