You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

158 lines
3.2 KiB
Vue

<template>
<div class="card">
<div class="panel-title">
<span class="title-dot"></span>
<span>设备概况</span>
</div>
<div class="panel-body overview-body">
<div v-for="item in overviewItems" :key="item.key" class="gauge-item">
<div class="gauge" :style="getGaugeStyle(item.percent, item.color)">
<div class="gauge-inner">
<div class="gauge-value">{{ item.value }}</div>
<div class="gauge-label">{{ item.label }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { colors } from '../utils'
const overviewItems = [
{ key: 'device', label: '', value: '987,965', percent: 78, color: colors.cyan },
{ key: 'running', label: '', value: '30', percent: 66, color: colors.blue },
{ key: 'idle', label: '', value: '2', percent: 42, color: colors.warn },
{ key: 'alarm', label: '', value: '10', percent: 58, color: colors.danger }
]
const getGaugeStyle = (percent: number, color: string) => {
const p = Math.max(0, Math.min(100, percent))
return {
background: `conic-gradient(${color} ${p * 3.6}deg, rgba(148,163,184,0.18) 0deg)`
}
}
</script>
<style scoped>
.card {
height: 100%;
background: linear-gradient(135deg, rgba(15,23,42,0.96), rgba(15,23,42,0.88));
border-radius: 8px;
border: 1px solid rgba(30,64,175,0.85);
box-shadow:
0 18px 45px rgba(15,23,42,0.95),
0 0 0 1px rgba(15,23,42,1),
inset 0 0 0 1px rgba(56,189,248,0.05);
position: relative;
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 0;
}
.card::before,
.card::after {
content: "";
position: absolute;
width: 12px;
height: 12px;
border-radius: 2px;
border: 1px solid rgba(56,189,248,0.75);
opacity: 0.6;
pointer-events: none;
}
.card::before {
top: -1px;
left: -1px;
border-right: none;
border-bottom: none;
}
.card::after {
right: -1px;
bottom: -1px;
border-left: none;
border-top: none;
}
.panel-title {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 12px;
border-bottom: 1px solid rgba(41, 54, 95, 0.9);
font-size: 16px;
font-weight: 900;
color: #e5f0ff;
}
.title-dot {
width: 10px;
height: 10px;
border-radius: 50%;
border: 1px solid rgba(56,189,248,0.95);
box-shadow: 0 0 12px rgba(56,189,248,0.45);
}
.panel-body {
flex: 1;
min-height: 0;
padding: 10px 12px;
}
.overview-body {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
}
.gauge-item {
display: flex;
align-items: center;
justify-content: center;
}
.gauge {
width: 110px;
height: 110px;
border-radius: 50%;
padding: 8px;
box-sizing: border-box;
}
.gauge-inner {
width: 100%;
height: 100%;
border-radius: 50%;
background: rgba(2,6,23,0.92);
border: 1px solid rgba(148,163,184,0.25);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 2px;
text-align: center;
}
.gauge-value {
font-size: 18px;
font-weight: 900;
color: #e5f0ff;
}
.gauge-label {
font-size: 11px;
color: rgba(148,163,184,0.95);
}
@media (max-width: 1366px) {
.gauge {
width: 96px;
height: 96px;
}
}
</style>