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
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>
|