99 lines
3.3 KiB
Vue
99 lines
3.3 KiB
Vue
<template>
|
||
<view class="card device-status-card">
|
||
<view class="card-header mb-md flex-row-sb">
|
||
<view class="title">设备信息</view>
|
||
<view class="tag-apple tag-success">{{ deviceInfo.carrier_name || '-' }}</view>
|
||
</view>
|
||
<view class="device-info flex-col-g16">
|
||
<view class="info-row flex-row-sb">
|
||
<view class="info-label">
|
||
<view class="subtitle">当前卡: {{ deviceInfo.currentIccid }}</view>
|
||
</view>
|
||
<view class="info-values flex-row-g20" @tap="$emit('authentication')">
|
||
<view class="tag-apple" :class="isRealName ? 'tag-success' : 'tag-warning'">
|
||
{{ isRealName ? "已实名" : "未实名" }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="info-row flex-row-sb">
|
||
<view class="info-label">
|
||
<view class="subtitle" v-if="isDevice">IMEI:{{ deviceInfo.imei || '-' }}</view>
|
||
<view class="subtitle" v-else>手机号:{{ deviceInfo.bound_phone || '-' }}</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="device-metrics flex-row-sb mt-md">
|
||
<view class="metric-item flex-col-center">
|
||
<view class="caption mb-xs">信号强度</view>
|
||
<view class="metric-value">{{ getSignalText(deviceInfo) }}</view>
|
||
</view>
|
||
<view class="metric-item flex-col-center">
|
||
<view class="caption mb-xs">设备电量</view>
|
||
<view class="metric-value">{{ deviceInfo.battery }} %</view>
|
||
</view>
|
||
<view class="metric-item flex-col-center">
|
||
<view class="caption mb-xs">连接数量</view>
|
||
<view class="metric-value">{{ deviceInfo.connCnt }}/{{ deviceInfo.max_clients }}</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
const props = defineProps({
|
||
deviceInfo: { type: Object, default: () => ({}) },
|
||
isRealName: { type: Boolean, default: false },
|
||
isDevice: { type: Boolean, default: true },
|
||
opratorList: { type: Array, default: () => [] }
|
||
});
|
||
|
||
defineEmits(['authentication']);
|
||
|
||
const normalizeSignalScore = (value, min, max) => {
|
||
if (value === null || value === undefined || value === '' || value === '-') return null;
|
||
|
||
const numericValue = Number(value);
|
||
if (!Number.isFinite(numericValue)) return null;
|
||
if (numericValue <= min) return 0;
|
||
if (numericValue >= max) return 100;
|
||
|
||
return ((numericValue - min) / (max - min)) * 100;
|
||
};
|
||
|
||
const getSignalText = (deviceInfo) => {
|
||
const signalScores = [
|
||
{ score: normalizeSignalScore(deviceInfo?.rsrp, -120, -80), weight: 0.5 },
|
||
{ score: normalizeSignalScore(deviceInfo?.rsrq, -20, -10), weight: 0.25 },
|
||
{ score: normalizeSignalScore(deviceInfo?.rssi, -100, -65), weight: 0.25 }
|
||
].filter(item => item.score !== null);
|
||
|
||
if (!signalScores.length) return '-';
|
||
|
||
const totalWeight = signalScores.reduce((sum, item) => sum + item.weight, 0);
|
||
const weightedScore =
|
||
signalScores.reduce((sum, item) => sum + item.score * item.weight, 0) / totalWeight;
|
||
|
||
if (weightedScore >= 67) return '强';
|
||
if (weightedScore >= 34) return '中';
|
||
return '弱';
|
||
};
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.device-status-card {
|
||
.info-row {
|
||
padding: var(--space-sm) 0;
|
||
border-bottom: 1rpx solid var(--gray-200);
|
||
&:last-child { border-bottom: none; }
|
||
.info-label { min-width: 200rpx; }
|
||
.info-values { flex: 1; justify-content: flex-end; }
|
||
}
|
||
.device-metrics {
|
||
background: var(--gray-100);
|
||
border-radius: var(--radius-small);
|
||
padding: 20rpx;
|
||
.metric-item { flex: 1; }
|
||
}
|
||
}
|
||
</style>
|