main
vue 75 lines 1.96 KB
Raw
1 <template>
2 <n-card content-class="p-0!">
3 <div class="stat-card flex flex-col items-center justify-center p-4 text-center">
4 <div class="label text-xs" :style="{ color: 'var(--fg-secondary-color)' }">{{ label }}</div>
5 <div class="value mt-1 text-xl font-bold" :class="colorClass">
6 {{ displayValue }}
7 </div>
8 </div>
9 </n-card>
10 </template>
11
12 <script setup lang="ts">
13 import { NCard } from "naive-ui"
14 import { computed, toRefs } from "vue"
15
16 const props = withDefaults(
17 defineProps<{
18 label: string
19 value: number | null | undefined
20 format?: "number" | "bytes" | "uptime" | "percent"
21 decimals?: number
22 colorThresholds?: { low: number; mid: number }
23 }>(),
24 {
25 format: "number",
26 decimals: 0
27 }
28 )
29
30 const { label, value, format, decimals, colorThresholds } = toRefs(props)
31
32 // TODO-FE: refactor
33 function formatBytes(bytes: number): string {
34 const units = ["B", "KB", "MB", "GB", "TB"]
35 let i = 0
36 let v = bytes
37 while (v >= 1024 && i < units.length - 1) {
38 v /= 1024
39 i++
40 }
41 return `${v.toFixed(i === 0 ? 0 : 1)} ${units[i]}`
42 }
43
44 function formatUptime(seconds: number): string {
45 const d = Math.floor(seconds / 86400)
46 const h = Math.floor((seconds % 86400) / 3600)
47 const m = Math.floor((seconds % 3600) / 60)
48 if (d > 0) return `${d}d ${h}h ${m}m`
49 if (h > 0) return `${h}h ${m}m`
50 return `${m}m`
51 }
52
53 const displayValue = computed(() => {
54 if (value.value === null || value.value === undefined) return ""
55 const v = Number(value.value)
56 switch (format.value) {
57 case "bytes":
58 return formatBytes(v)
59 case "uptime":
60 return formatUptime(v)
61 case "percent":
62 return `${v.toFixed(decimals.value)}%`
63 default:
64 return v.toFixed(decimals.value)
65 }
66 })
67
68 const colorClass = computed(() => {
69 if (!colorThresholds?.value || value.value === null || value.value === undefined) return ""
70 const v = Number(value.value)
71 if (v < colorThresholds.value.low) return "text-red-400"
72 if (v < colorThresholds.value.mid) return "text-yellow-400"
73 return "text-green-400"
74 })
75 </script>