This commit is contained in:
@@ -114,11 +114,6 @@
|
||||
<ElDescriptionsItem label="切卡模式">{{
|
||||
getSwitchModeName(cardInfo?.switch_mode)
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="信号强度">
|
||||
<ElTag :type="getSignalStrengthType()" size="small">
|
||||
{{ calculateSignalStrength() }}
|
||||
</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="已绑定卡数">{{
|
||||
cardInfo?.bound_card_count || 0
|
||||
}}</ElDescriptionsItem>
|
||||
@@ -266,44 +261,16 @@
|
||||
</ElDescriptionsItem>
|
||||
|
||||
<!-- 信号信息 -->
|
||||
<ElDescriptionsItem label="信号强度(RSSI)">
|
||||
{{
|
||||
deviceRealtime.rssi !== undefined &&
|
||||
deviceRealtime.rssi !== null &&
|
||||
deviceRealtime.rssi !== ''
|
||||
? deviceRealtime.rssi
|
||||
: '-'
|
||||
}}
|
||||
<ElDescriptionsItem label="信号综合判断">
|
||||
<ElTag :type="getSignalQualityType(deviceRealtime.signal_quality)" size="small">
|
||||
{{ getSignalQualityText(deviceRealtime.signal_quality) }}
|
||||
</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="接收功率(RSRP)">
|
||||
{{
|
||||
deviceRealtime.rsrp !== undefined &&
|
||||
deviceRealtime.rsrp !== null &&
|
||||
deviceRealtime.rsrp !== ''
|
||||
? `${deviceRealtime.rsrp} dBm`
|
||||
: '-'
|
||||
}}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="接收质量(RSRQ)">
|
||||
{{
|
||||
deviceRealtime.rsrq !== undefined &&
|
||||
deviceRealtime.rsrq !== null &&
|
||||
deviceRealtime.rsrq !== ''
|
||||
? `${deviceRealtime.rsrq} dB`
|
||||
: '-'
|
||||
}}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="信噪比(SINR)">
|
||||
{{
|
||||
deviceRealtime.sinr !== undefined &&
|
||||
deviceRealtime.sinr !== null &&
|
||||
deviceRealtime.sinr !== ''
|
||||
? `${deviceRealtime.sinr} dB`
|
||||
: '-'
|
||||
}}
|
||||
<ElDescriptionsItem label="信号较弱原因" :span="3">
|
||||
{{ getSignalBadReasonText(deviceRealtime.signal_bad_reason) }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="已连接设备数">
|
||||
{{ deviceRealtime.client_number }} / {{ deviceRealtime.max_clients }}
|
||||
{{ deviceRealtime.client_number ?? '-' }} / {{ deviceRealtime.max_clients ?? '-' }}
|
||||
</ElDescriptionsItem>
|
||||
|
||||
<!-- WiFi 信息 -->
|
||||
@@ -437,7 +404,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, toRef } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
import {
|
||||
ElCard,
|
||||
ElDescriptions,
|
||||
@@ -479,6 +446,7 @@
|
||||
msisdn?: string
|
||||
carrier_name?: string
|
||||
real_name_status?: number
|
||||
realname_policy?: string
|
||||
network_status?: number
|
||||
current_month_usage_mb?: number
|
||||
last_gateway_reading_mb?: number
|
||||
@@ -510,16 +478,15 @@
|
||||
interface DeviceRealtimeInfo {
|
||||
online_status?: number
|
||||
status?: number
|
||||
battery_level?: number
|
||||
battery_level?: number | null
|
||||
run_time?: string
|
||||
connect_time?: string
|
||||
last_online_time?: string
|
||||
rssi?: string
|
||||
rsrp?: string
|
||||
rsrq?: string
|
||||
sinr?: string
|
||||
client_number?: number
|
||||
max_clients?: number
|
||||
current_iccid?: string
|
||||
signal_quality?: string
|
||||
signal_bad_reason?: string
|
||||
wifi_enabled?: boolean
|
||||
ssid?: string
|
||||
wifi_password?: string
|
||||
@@ -590,7 +557,6 @@
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
// 使用格式化工具
|
||||
const deviceRealtimeRef = toRef(props, 'deviceRealtime')
|
||||
const {
|
||||
formatDataSize,
|
||||
formatDuration,
|
||||
@@ -601,10 +567,11 @@
|
||||
getAssetStatusType,
|
||||
getOnlineStatusName,
|
||||
getOnlineStatusType,
|
||||
calculateSignalStrength,
|
||||
getSignalStrengthType,
|
||||
getSignalQualityText,
|
||||
getSignalQualityType,
|
||||
getSignalBadReasonText,
|
||||
getSwitchModeName
|
||||
} = useAssetFormatters(deviceRealtimeRef)
|
||||
} = useAssetFormatters()
|
||||
|
||||
// 排序后的设备卡列表(按卡槽位置排序,当前卡排在最前面)
|
||||
const sortedDeviceCards = computed(() => {
|
||||
@@ -628,8 +595,8 @@
|
||||
})
|
||||
|
||||
// 处理轮询开关变化
|
||||
const handlePollingChange = (value: boolean) => {
|
||||
emit('update:pollingEnabled', value)
|
||||
const handlePollingChange = (value: string | number | boolean) => {
|
||||
emit('update:pollingEnabled', Boolean(value))
|
||||
}
|
||||
|
||||
// 跳转到卡片信息
|
||||
|
||||
@@ -96,28 +96,46 @@
|
||||
</span>
|
||||
</div>
|
||||
<div class="progress-wrapper">
|
||||
<ElProgress
|
||||
:percentage="
|
||||
getUsageProgress(
|
||||
currentPackage.virtual_used_mb || 0,
|
||||
currentPackage.virtual_total_mb || 0
|
||||
)
|
||||
"
|
||||
:color="
|
||||
getProgressColorByPercentage(
|
||||
<div class="progress-track">
|
||||
<ElProgress
|
||||
:show-text="false"
|
||||
:percentage="
|
||||
getUsageProgress(
|
||||
currentPackage.virtual_used_mb || 0,
|
||||
currentPackage.virtual_total_mb || 0
|
||||
)
|
||||
"
|
||||
:color="
|
||||
getProgressColorByPercentage(
|
||||
getUsageProgress(
|
||||
currentPackage.virtual_used_mb || 0,
|
||||
currentPackage.virtual_total_mb || 0
|
||||
)
|
||||
)
|
||||
"
|
||||
:stroke-width="10"
|
||||
/>
|
||||
<div
|
||||
class="breakpoint-marker"
|
||||
:style="
|
||||
getBreakpointMarkerStyle(
|
||||
currentPackage.virtual_total_mb || 0,
|
||||
currentPackage.real_total_mb || 0
|
||||
)
|
||||
"
|
||||
:title="`停机阈值/真流量总量: ${formatDataSize(currentPackage.virtual_total_mb || 0)} / ${formatDataSize(currentPackage.real_total_mb || 0)}`"
|
||||
></div>
|
||||
</div>
|
||||
<span class="progress-percentage">
|
||||
{{
|
||||
formatProgressPercentage(
|
||||
getUsageProgress(
|
||||
currentPackage.virtual_used_mb || 0,
|
||||
currentPackage.virtual_total_mb || 0
|
||||
)
|
||||
)
|
||||
"
|
||||
:stroke-width="10"
|
||||
/>
|
||||
<div
|
||||
class="breakpoint-marker"
|
||||
:style="{ left: getBreakpointPosition(currentPackage) + '%' }"
|
||||
:title="`停机阈值/真流量总量: ${formatDataSize(currentPackage.virtual_total_mb || 0)} / ${formatDataSize(currentPackage.real_total_mb || 0)}`"
|
||||
></div>
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -231,8 +249,14 @@
|
||||
import { formatDateTime } from '@/utils/business/format'
|
||||
import type { PackageInfo } from '../types'
|
||||
|
||||
const { formatAmount, formatDataSize, getUsageProgress, getProgressColorByPercentage } =
|
||||
useAssetFormatters()
|
||||
const {
|
||||
formatAmount,
|
||||
formatDataSize,
|
||||
getUsageProgress,
|
||||
getProgressColorByPercentage,
|
||||
formatProgressPercentage,
|
||||
getBreakpointMarkerStyle
|
||||
} = useAssetFormatters()
|
||||
|
||||
const userStore = useUserStore()
|
||||
const { info: userInfo } = storeToRefs(userStore)
|
||||
@@ -269,11 +293,6 @@
|
||||
}
|
||||
return typeMap[type || ''] || '-'
|
||||
}
|
||||
|
||||
const getBreakpointPosition = (pkg: PackageInfo) => {
|
||||
if (!pkg.real_total_mb || pkg.real_total_mb === 0) return 0
|
||||
return (pkg.virtual_total_mb / pkg.real_total_mb) * 100
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@@ -369,18 +388,34 @@
|
||||
}
|
||||
|
||||
.progress-wrapper {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1px;
|
||||
|
||||
.breakpoint-marker {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-color: var(--el-color-danger);
|
||||
border-radius: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 1;
|
||||
cursor: pointer;
|
||||
.progress-track {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
.breakpoint-marker {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-color: var(--el-color-danger);
|
||||
border-radius: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-percentage {
|
||||
min-width: 44px;
|
||||
font-size: 14px;
|
||||
color: var(--el-text-color-secondary);
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,6 +169,8 @@
|
||||
{ label: '设备重置', value: 'device_reset' },
|
||||
{ label: '设备分配', value: 'device_allocate' },
|
||||
{ label: '设备回收', value: 'device_recall' },
|
||||
{ label: '设备绑卡', value: 'device_bind_card' },
|
||||
{ label: '设备解绑卡', value: 'device_unbind_card' },
|
||||
{ label: '卡分配', value: 'card_allocate' },
|
||||
{ label: '卡回收', value: 'card_recall' },
|
||||
{ label: '卡停机', value: 'card_stop' },
|
||||
@@ -195,6 +197,8 @@
|
||||
device_reset: 'warning',
|
||||
device_allocate: 'primary',
|
||||
device_recall: 'warning',
|
||||
device_bind_card: 'primary',
|
||||
device_unbind_card: 'warning',
|
||||
card_allocate: 'primary',
|
||||
card_recall: 'warning',
|
||||
card_stop: 'danger',
|
||||
@@ -223,17 +227,26 @@
|
||||
asset_type: '资产类型',
|
||||
batch_no: '批次号',
|
||||
card_category: '卡类型',
|
||||
device_imei: '设备IMEI',
|
||||
device_sn: '设备SN',
|
||||
device_virtual_no: '设备虚拟号',
|
||||
device_virtual_nos: '设备虚拟号',
|
||||
enable_polling: '轮询开关',
|
||||
file_key: '文件存储键',
|
||||
first_realname_at: '首次实名时间',
|
||||
iccid: 'ICCID',
|
||||
iccids: 'ICCID',
|
||||
network_status: '网络状态',
|
||||
real_name_status: '实名状态',
|
||||
realname_policy: '实名认证策略',
|
||||
shop_name: '店铺',
|
||||
source_service: '来源服务',
|
||||
source_shop_name: '来源店铺',
|
||||
status: '资产状态',
|
||||
stop_reason: '停机原因',
|
||||
switch_mode: '切卡模式'
|
||||
switch_mode: '切卡模式',
|
||||
target_shop_name: '目标店铺',
|
||||
to_shop_name: '目标店铺'
|
||||
}
|
||||
|
||||
const realnamePolicyMap: Record<string, string> = {
|
||||
@@ -371,6 +384,13 @@
|
||||
if (typeof value === 'boolean') return value ? '是' : '否'
|
||||
if (typeof value === 'number') return String(value)
|
||||
if (typeof value === 'string') return value || '空'
|
||||
if (Array.isArray(value)) {
|
||||
if (value.length === 0) return '空'
|
||||
if (value.every((item) => ['string', 'number', 'boolean'].includes(typeof item))) {
|
||||
return value.map((item) => formatValue(item)).join('、')
|
||||
}
|
||||
return JSON.stringify(value)
|
||||
}
|
||||
if (typeof value === 'object') return JSON.stringify(value)
|
||||
return String(value)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
<div class="card-header">
|
||||
<span>套餐列表</span>
|
||||
<div class="card-header-right">
|
||||
<ElButton type="primary" :disabled="props.boundDeviceId" @click="handleShowRecharge"
|
||||
<ElButton
|
||||
type="primary"
|
||||
:disabled="Boolean(props.boundDeviceId)"
|
||||
@click="handleShowRecharge"
|
||||
>套餐充值</ElButton
|
||||
>
|
||||
</div>
|
||||
@@ -97,28 +100,46 @@
|
||||
>
|
||||
</div>
|
||||
<div class="progress-wrapper">
|
||||
<ElProgress
|
||||
style="margin-top: 4px"
|
||||
:percentage="
|
||||
getUsageProgress(
|
||||
scope.row.virtual_used_mb || 0,
|
||||
scope.row.virtual_total_mb || 0
|
||||
)
|
||||
"
|
||||
:color="
|
||||
getProgressColorByPercentage(
|
||||
<div class="progress-track">
|
||||
<ElProgress
|
||||
style="margin-top: 4px"
|
||||
:show-text="false"
|
||||
:percentage="
|
||||
getUsageProgress(
|
||||
scope.row.virtual_used_mb || 0,
|
||||
scope.row.virtual_total_mb || 0
|
||||
)
|
||||
"
|
||||
:color="
|
||||
getProgressColorByPercentage(
|
||||
getUsageProgress(
|
||||
scope.row.virtual_used_mb || 0,
|
||||
scope.row.virtual_total_mb || 0
|
||||
)
|
||||
)
|
||||
"
|
||||
/>
|
||||
<div
|
||||
class="breakpoint-marker"
|
||||
:style="
|
||||
getBreakpointMarkerStyle(
|
||||
scope.row.virtual_total_mb || 0,
|
||||
scope.row.real_total_mb || 0
|
||||
)
|
||||
"
|
||||
:title="`停机阈值/真流量总量: ${formatDataSize(scope.row.virtual_total_mb || 0)} / ${formatDataSize(scope.row.real_total_mb || 0)}`"
|
||||
></div>
|
||||
</div>
|
||||
<span class="progress-percentage">
|
||||
{{
|
||||
formatProgressPercentage(
|
||||
getUsageProgress(
|
||||
scope.row.virtual_used_mb || 0,
|
||||
scope.row.virtual_total_mb || 0
|
||||
)
|
||||
)
|
||||
"
|
||||
/>
|
||||
<div
|
||||
class="breakpoint-marker"
|
||||
:style="{ left: getBreakpointPosition(scope.row) + '%' }"
|
||||
:title="`停机阈值/真流量总量: ${formatDataSize(scope.row.virtual_total_mb || 0)} / ${formatDataSize(scope.row.real_total_mb || 0)}`"
|
||||
></div>
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
@@ -346,14 +367,11 @@
|
||||
formatAmount,
|
||||
getPackageStatusTagType,
|
||||
getUsageProgress,
|
||||
getProgressColorByPercentage
|
||||
getProgressColorByPercentage,
|
||||
formatProgressPercentage,
|
||||
getBreakpointMarkerStyle
|
||||
} = useAssetFormatters()
|
||||
|
||||
const getBreakpointPosition = (pkg: PackageInfo) => {
|
||||
if (!pkg.real_total_mb || pkg.real_total_mb === 0) return 0
|
||||
return (pkg.virtual_total_mb / pkg.real_total_mb) * 100
|
||||
}
|
||||
|
||||
// 套餐名称点击
|
||||
const handlePackageNameClick = (packageRow: PackageInfo) => {
|
||||
if (!hasAuth('package_usage:daily_records')) {
|
||||
@@ -459,18 +477,34 @@
|
||||
}
|
||||
|
||||
.progress-wrapper {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1px;
|
||||
|
||||
.breakpoint-marker {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-color: var(--el-color-danger);
|
||||
border-radius: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 1;
|
||||
cursor: pointer;
|
||||
.progress-track {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
.breakpoint-marker {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-color: var(--el-color-danger);
|
||||
border-radius: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-percentage {
|
||||
min-width: 44px;
|
||||
font-size: 14px;
|
||||
color: var(--el-text-color-secondary);
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user