179 lines
4.2 KiB
Vue
Executable File
179 lines
4.2 KiB
Vue
Executable File
<script lang="ts" setup>
|
|
import {useDataStore} from "~/strores/DataStore";
|
|
import {useMainLayoutStore} from "~/strores/UseMainLayoutStore";
|
|
import { MoveDown,CircleAlert,CircleX } from 'lucide-vue-next';
|
|
const props = defineProps({
|
|
title: {
|
|
type: String,
|
|
default: "CPU使用率",
|
|
},
|
|
info:{
|
|
type:Array,
|
|
default:()=>[],
|
|
},
|
|
unit: {
|
|
type: String,
|
|
default: "%"
|
|
},
|
|
watcher: {
|
|
type: [String, Array],
|
|
default: "cpuTotalUsage",
|
|
validator: (value) => {
|
|
return typeof value === 'string' || Array.isArray(value);
|
|
}
|
|
},
|
|
reverse: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
})
|
|
const values=ref<string[]>(Array( Array.isArray(props.watcher)?props.watcher.length:1).fill('0'))
|
|
const dataStore = useDataStore()
|
|
const mainStore = useMainLayoutStore()
|
|
const status=ref<string>("success")
|
|
//监听dataStore变更
|
|
const value=ref<number>(Number(values.value[0]))
|
|
dataStore.$subscribe((_, state) => {
|
|
//获得d3YT#cpuUserUsage的key的value
|
|
const watcher = Array.isArray(props.watcher) ? [...props.watcher] : [props.watcher];
|
|
// 使用map函数从state.data中取出每个watcherKey对应的值
|
|
values.value = watcher.map(watcherKey => state.data[watcherKey as string]);
|
|
//检测第一个值超过50则warning 超过80则error
|
|
value.value=Number(values.value[0])
|
|
status.value = value.value > 80 ? "error" : value.value > 50 ? "warning" : "success";
|
|
})
|
|
|
|
</script>
|
|
|
|
<template>
|
|
<n-popover trigger="hover" placement="bottom">
|
|
<template #trigger>
|
|
<div class="mini-card-box">
|
|
<n-progress type="circle" processing :status="status" :percentage="
|
|
values[0]
|
|
" style="width: 68px;">
|
|
<MoveDown class="arrow" :style="{transform:`rotate(${(100-value)/100*360*-1}deg)`}" v-if="status==='success'"/>
|
|
<div class="warning" v-if="status==='warning'">
|
|
<CircleAlert />
|
|
</div>
|
|
<div class="error" v-if="status==='error'">
|
|
<CircleX />
|
|
</div>
|
|
</n-progress>
|
|
<div class="text">
|
|
<h3>
|
|
{{ title }}
|
|
</h3>
|
|
<h2>
|
|
{{ Number(values[0]??0).toFixed(2)}}{{ unit }}
|
|
</h2>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<n-tag type="info" v-for="i in info">
|
|
{{ i }}
|
|
</n-tag>
|
|
</n-popover>
|
|
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
@import "../../base";
|
|
|
|
.mini-card-box {
|
|
display: flex;
|
|
align-items: center;
|
|
background: $light-bg-color;
|
|
padding: 20px 24px ;
|
|
|
|
|
|
border-radius: $radius;
|
|
box-shadow: 0 10px 30px 0 rgba(17, 38, 146, 0.05);
|
|
gap: 25px;
|
|
border: $border;
|
|
*{
|
|
@include SC_Font()
|
|
}
|
|
> svg {
|
|
width: 68px;
|
|
height: 68px;
|
|
}
|
|
|
|
.dark-mode & {
|
|
background: $dark-bg-color;
|
|
}
|
|
}
|
|
|
|
.arrow{
|
|
width: 30px;
|
|
height: 30px;
|
|
stroke: $light-unfocused-color;
|
|
//旋转中心为几何中心
|
|
transform-origin: center;
|
|
//过度
|
|
transition: transform 0.3s ease-in-out;
|
|
}
|
|
|
|
.text {
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
h2, h3 {
|
|
color: $light-unfocused-color;
|
|
line-height: 175%; /* 28px */
|
|
font-size: 16px;
|
|
font-weight: 400;
|
|
}
|
|
|
|
h2 {
|
|
font-size: 19px;
|
|
font-weight: 600;
|
|
color: $light-text-color;
|
|
.dark-mode & {
|
|
color: $dark-text-color;
|
|
}
|
|
}
|
|
}
|
|
.warning,.error{
|
|
display: flex;
|
|
place-items: center;
|
|
place-content: center;
|
|
width: 70px;
|
|
height: 70px;
|
|
border-radius: 50%;
|
|
animation: background-fade-error 0.5s infinite ease-in-out;
|
|
svg{
|
|
width: 40px;
|
|
height: 40px;
|
|
stroke: #fff;
|
|
}
|
|
}
|
|
.warning{
|
|
animation: background-fade 1s infinite ease-in-out;
|
|
}
|
|
|
|
@keyframes background-fade {
|
|
0% {
|
|
background-color: rgba(255, 255, 0, 0.3); /* 黄色,完全透明 */
|
|
}
|
|
50% {
|
|
background-color: rgba(255, 255, 0, 1); /* 黄色,完全不透明 */
|
|
}
|
|
100% {
|
|
background-color: rgba(255, 255, 0, 0.3); /* 黄色,完全透明 */
|
|
}
|
|
}
|
|
|
|
@keyframes background-fade-error {
|
|
0% {
|
|
background-color: rgba(255, 0, 0, 0.3); /* 红色,完全透明 */
|
|
}
|
|
50% {
|
|
background-color: rgba(255, 0, 0, 1); /* 红色,完全不透明 */
|
|
box-shadow: 0 0 10px rgba(255, 0, 0, 0.5); /* 红色阴影 */
|
|
}
|
|
100% {
|
|
background-color: rgba(255, 0, 0, 0.3); /* 红色,完全透明 */
|
|
}
|
|
}
|
|
</style> |