import { computed, toValue, type MaybeRefOrGetter } from 'vue' import type { VehicleCardModel } from '@/types/car' export interface VehicleCardStateOptions { vehicle: MaybeRefOrGetter } const stateLabels: Record = { idle: '空闲', running: '运行', charging: '充电', paused: '暂停', fault: '故障', offline: '离线' } function formatMissionIdSuffix(missionId?: string | number | null): string { if (missionId == null) return '' const id = String(missionId).trim() if (!id || id === '0') return '' return `-${id}` } function appendMissionId(base: string, missionId?: string | number | null): string { const suffix = formatMissionIdSuffix(missionId) return suffix ? `${base}${suffix}` : base } export function useVehicleCardState(opts: VehicleCardStateOptions) { const vehicle = computed(() => toValue(opts.vehicle)) const stateLabel = computed(() => stateLabels[vehicle.value.state] ?? vehicle.value.state) const batteryPct = computed(() => { const raw = vehicle.value.batterySoc ?? 0 const pct = raw > 1 ? raw : raw * 100 return Math.max(0, Math.min(100, Math.round(pct))) }) const batteryTone = computed(() => { const p = batteryPct.value if (p < 20) return 'tone-danger' if (p < 50) return 'tone-warning' return 'tone-success' }) const switchOn = computed(() => vehicle.value.maintenanceMode === 'online') const statusPill = computed(() => { const v = vehicle.value if (v.reachable === false) return { label: '不可达', tone: 'tone-danger' } if (v.isAlarmActive) return { label: '报警中', tone: 'tone-danger' } if (v.maintenanceMode === 'offline') return { label: '下线维护', tone: 'tone-warning' } if (v.maintenanceMode === 'repair') return { label: '现场检修', tone: 'tone-warning' } if (v.maintenanceMode === 'blown') return { label: '返厂检修', tone: 'tone-danger' } if (v.state === 'fault') return { label: '故障', tone: 'tone-danger' } if (v.state === 'running') return { label: '运行中', tone: 'tone-success' } if (v.state === 'charging') return { label: '充电中', tone: 'tone-info' } if (v.state === 'offline') return { label: '离线', tone: 'tone-idle' } return { label: stateLabel.value, tone: 'tone-idle' } }) const missionIdSuffix = computed(() => formatMissionIdSuffix(vehicle.value.missionId)) const statusDisplayLabel = computed(() => appendMissionId(statusPill.value.label, vehicle.value.missionId) ) const runtimeStatusLabel = computed(() => appendMissionId(vehicle.value.lstatus ?? stateLabel.value, vehicle.value.missionId) ) const accentTone = computed(() => statusPill.value.tone) const latencyLabel = computed(() => { const ms = vehicle.value.latencyMs if (vehicle.value.reachable === false && ms == null) return '不可达' if (ms == null) return '—' return `${ms} ms` }) const latencyClass = computed(() => { const ms = vehicle.value.latencyMs if (vehicle.value.reachable === false) return 'val-danger' // WatchDog TCP RTT:局域网正常多在几十毫秒;>150 警示,>400 危险 if (ms != null && ms > 400) return 'val-danger' if (ms != null && ms > 150) return 'val-warn' return '' }) const faultLabel = computed(() => { const v = vehicle.value.faultRatePercent if (v == null) return '—' return `${v.toFixed(2)}%` }) const faultClass = computed(() => { const v = vehicle.value.faultRatePercent ?? 0 if (v >= 5) return 'val-danger' if (v >= 1) return 'val-warn' return '' }) const cpuLabel = computed(() => { const v = vehicle.value.cpuPercent return v != null ? `${Math.round(v)}%` : '—' }) const memLabel = computed(() => { const v = vehicle.value.memPercent return v != null ? `${Math.round(v)}%` : '—' }) const cpuChipClass = computed(() => { const v = vehicle.value.cpuPercent if (v == null) return '' if (v >= 90) return 'val-danger' if (v >= 75) return 'val-warn' return 'val-ok' }) const memChipClass = computed(() => { const v = vehicle.value.memPercent if (v == null) return '' if (v >= 90) return 'val-danger' if (v >= 75) return 'val-warn' return 'val-ok' }) return { stateLabel, batteryPct, batteryTone, switchOn, statusPill, missionIdSuffix, statusDisplayLabel, runtimeStatusLabel, accentTone, latencyLabel, latencyClass, faultLabel, faultClass, cpuLabel, memLabel, cpuChipClass, memChipClass } }