Merge branch 'feature/monitor2' into dev
This commit is contained in:
commit
c91eaf3e94
@ -0,0 +1,5 @@
|
|||||||
|
package systemApiStructs
|
||||||
|
|
||||||
|
type MonitorGetDiskStateByPathReq struct {
|
||||||
|
Path string `json:"path"`
|
||||||
|
}
|
@ -1,14 +1,21 @@
|
|||||||
package system
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sun-panel/api/api_v1/common/apiData/systemApiStructs"
|
||||||
"sun-panel/api/api_v1/common/apiReturn"
|
"sun-panel/api/api_v1/common/apiReturn"
|
||||||
"sun-panel/global"
|
"sun-panel/global"
|
||||||
|
"sun-panel/lib/monitor"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/gin-gonic/gin/binding"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MonitorApi struct{}
|
type MonitorApi struct{}
|
||||||
|
|
||||||
|
const cacheSecond = 3
|
||||||
|
|
||||||
|
// 弃用
|
||||||
func (a *MonitorApi) GetAll(c *gin.Context) {
|
func (a *MonitorApi) GetAll(c *gin.Context) {
|
||||||
if value, ok := global.SystemMonitor.Get("value"); ok {
|
if value, ok := global.SystemMonitor.Get("value"); ok {
|
||||||
apiReturn.SuccessData(c, value)
|
apiReturn.SuccessData(c, value)
|
||||||
@ -16,3 +23,74 @@ func (a *MonitorApi) GetAll(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
apiReturn.Error(c, "failed")
|
apiReturn.Error(c, "failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *MonitorApi) GetCpuState(c *gin.Context) {
|
||||||
|
if v, ok := global.SystemMonitor.Get(global.SystemMonitor_CPU_INFO); ok {
|
||||||
|
global.Logger.Debugln("读取缓存的的CPU信息")
|
||||||
|
apiReturn.SuccessData(c, v)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cpuInfo, err := monitor.GetCPUInfo()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
apiReturn.Error(c, "failed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 缓存
|
||||||
|
global.SystemMonitor.Set(global.SystemMonitor_CPU_INFO, cpuInfo, cacheSecond*time.Second)
|
||||||
|
apiReturn.SuccessData(c, cpuInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *MonitorApi) GetMemonyState(c *gin.Context) {
|
||||||
|
if v, ok := global.SystemMonitor.Get(global.SystemMonitor_MEMORY_INFO); ok {
|
||||||
|
global.Logger.Debugln("读取缓存的的RAM信息")
|
||||||
|
apiReturn.SuccessData(c, v)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
memoryInfo, err := monitor.GetMemoryInfo()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
apiReturn.Error(c, "failed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 缓存
|
||||||
|
global.SystemMonitor.Set(global.SystemMonitor_MEMORY_INFO, memoryInfo, cacheSecond*time.Second)
|
||||||
|
apiReturn.SuccessData(c, memoryInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *MonitorApi) GetDiskStateByPath(c *gin.Context) {
|
||||||
|
|
||||||
|
req := systemApiStructs.MonitorGetDiskStateByPathReq{}
|
||||||
|
if err := c.ShouldBindBodyWith(&req, binding.JSON); err != nil {
|
||||||
|
apiReturn.ErrorParamFomat(c, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cacheDiskName := global.SystemMonitor_DISK_INFO + req.Path
|
||||||
|
|
||||||
|
if v, ok := global.SystemMonitor.Get(cacheDiskName); ok {
|
||||||
|
global.Logger.Debugln("读取缓存的的DISK信息")
|
||||||
|
apiReturn.SuccessData(c, v)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
diskState, err := monitor.GetDiskInfoByPath(req.Path)
|
||||||
|
if err != nil {
|
||||||
|
apiReturn.Error(c, "failed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 缓存
|
||||||
|
global.SystemMonitor.Set(cacheDiskName, diskState, cacheSecond*time.Second)
|
||||||
|
apiReturn.SuccessData(c, diskState)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *MonitorApi) GetDiskMountpoints(c *gin.Context) {
|
||||||
|
if list, err := monitor.GetDiskMountpoints(); err != nil {
|
||||||
|
apiReturn.Error(c, err.Error())
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
apiReturn.SuccessData(c, list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -35,6 +35,6 @@ var (
|
|||||||
Db *gorm.DB
|
Db *gorm.DB
|
||||||
RedisDb *redis.Client
|
RedisDb *redis.Client
|
||||||
SystemSetting *systemSetting.SystemSettingCache
|
SystemSetting *systemSetting.SystemSettingCache
|
||||||
SystemMonitor cache.Cacher[ModelSystemMonitor]
|
SystemMonitor cache.Cacher[interface{}]
|
||||||
RateLimit *RateLimiter
|
RateLimit *RateLimiter
|
||||||
)
|
)
|
||||||
|
@ -1,6 +1,14 @@
|
|||||||
package global
|
package global
|
||||||
|
|
||||||
import "sun-panel/lib/monitor"
|
import (
|
||||||
|
"sun-panel/lib/monitor"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SystemMonitor_CPU_INFO = "CPU_INFO"
|
||||||
|
SystemMonitor_MEMORY_INFO = "MEMORY_INFO"
|
||||||
|
SystemMonitor_DISK_INFO = "DISK_INFO"
|
||||||
|
)
|
||||||
|
|
||||||
type ModelSystemMonitor struct {
|
type ModelSystemMonitor struct {
|
||||||
CPUInfo monitor.CPUInfo `json:"cpuInfo"`
|
CPUInfo monitor.CPUInfo `json:"cpuInfo"`
|
||||||
|
@ -12,7 +12,6 @@ import (
|
|||||||
"sun-panel/initialize/other"
|
"sun-panel/initialize/other"
|
||||||
"sun-panel/initialize/redis"
|
"sun-panel/initialize/redis"
|
||||||
"sun-panel/initialize/runlog"
|
"sun-panel/initialize/runlog"
|
||||||
"sun-panel/initialize/systemMonitor"
|
|
||||||
"sun-panel/initialize/systemSettingCache"
|
"sun-panel/initialize/systemSettingCache"
|
||||||
"sun-panel/initialize/userToken"
|
"sun-panel/initialize/userToken"
|
||||||
"sun-panel/lib/cmn"
|
"sun-panel/lib/cmn"
|
||||||
@ -90,8 +89,7 @@ func InitApp() error {
|
|||||||
// 其他的初始化
|
// 其他的初始化
|
||||||
global.VerifyCodeCachePool = other.InitVerifyCodeCachePool()
|
global.VerifyCodeCachePool = other.InitVerifyCodeCachePool()
|
||||||
global.SystemSetting = systemSettingCache.InItSystemSettingCache()
|
global.SystemSetting = systemSettingCache.InItSystemSettingCache()
|
||||||
global.SystemMonitor = global.NewCache[global.ModelSystemMonitor](5*time.Hour, -1, "systemMonitorCache")
|
global.SystemMonitor = global.NewCache[interface{}](5*time.Hour, -1, "systemMonitorCache")
|
||||||
systemMonitor.Start(global.SystemMonitor, 3*time.Second)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -97,6 +97,24 @@ func GetDiskInfo() ([]DiskInfo, error) {
|
|||||||
return disks, nil
|
return disks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetDiskMountpoints() ([]disk.PartitionStat, error) {
|
||||||
|
return disk.Partitions(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDiskInfoByPath(path string) (*DiskInfo, error) {
|
||||||
|
diskInfo := DiskInfo{}
|
||||||
|
usage, err := disk.Usage(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
diskInfo.Free = usage.Free
|
||||||
|
diskInfo.Mountpoint = usage.Path
|
||||||
|
diskInfo.Total = usage.Total
|
||||||
|
diskInfo.Used = usage.Used
|
||||||
|
diskInfo.UsedPercent = usage.UsedPercent
|
||||||
|
return &diskInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
// 获取网络统计信息
|
// 获取网络统计信息
|
||||||
func GetNetIOCountersInfo() ([]NetIOCountersInfo, error) {
|
func GetNetIOCountersInfo() ([]NetIOCountersInfo, error) {
|
||||||
netInfo := []NetIOCountersInfo{}
|
netInfo := []NetIOCountersInfo{}
|
||||||
|
@ -9,11 +9,15 @@ import (
|
|||||||
|
|
||||||
func InitMonitorRouter(router *gin.RouterGroup) {
|
func InitMonitorRouter(router *gin.RouterGroup) {
|
||||||
api := api_v1.ApiGroupApp.ApiSystem.MonitorApi
|
api := api_v1.ApiGroupApp.ApiSystem.MonitorApi
|
||||||
// r := router.Group("", middleware.LoginInterceptor)
|
r := router.Group("", middleware.LoginInterceptor)
|
||||||
|
r.POST("/system/monitor/getDiskMountpoints", api.GetDiskMountpoints)
|
||||||
|
|
||||||
// 公开模式
|
// 公开模式
|
||||||
rPublic := router.Group("", middleware.PublicModeInterceptor)
|
rPublic := router.Group("", middleware.PublicModeInterceptor)
|
||||||
{
|
{
|
||||||
rPublic.POST("/system/monitor/getAll", api.GetAll)
|
rPublic.POST("/system/monitor/getAll", api.GetAll)
|
||||||
|
rPublic.POST("/system/monitor/getCpuState", api.GetCpuState)
|
||||||
|
rPublic.POST("/system/monitor/getDiskStateByPath", api.GetDiskStateByPath)
|
||||||
|
rPublic.POST("/system/monitor/getMemonyState", api.GetMemonyState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,3 +5,28 @@ export function getAll<T>() {
|
|||||||
url: '/system/monitor/getAll',
|
url: '/system/monitor/getAll',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getCpuState<T>() {
|
||||||
|
return post<T>({
|
||||||
|
url: '/system/monitor/getCpuState',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getDiskStateByPath<T>(path: string) {
|
||||||
|
return post<T>({
|
||||||
|
url: '/system/monitor/getDiskStateByPath',
|
||||||
|
data: { path },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMemonyState<T>() {
|
||||||
|
return post<T>({
|
||||||
|
url: '/system/monitor/getMemonyState',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getDiskMountpoints<T>() {
|
||||||
|
return post<T>({
|
||||||
|
url: '/system/monitor/getDiskMountpoints',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
53
src/components/common/ItemCard/index.vue
Normal file
53
src/components/common/ItemCard/index.vue
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { PanelPanelConfigStyleEnum } from '@/enums'
|
||||||
|
|
||||||
|
interface Prop {
|
||||||
|
cardTypeStyle: PanelPanelConfigStyleEnum
|
||||||
|
class?: string
|
||||||
|
backgroundColor?: string
|
||||||
|
iconTextIconHideTitle?: boolean // 隐藏小图标标题
|
||||||
|
iconTextColor?: string // 小图标文字颜色
|
||||||
|
iconText?: string // 小图标文字
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Prop>(), {})
|
||||||
|
|
||||||
|
const defaultBackground = '#2a2a2a6b'
|
||||||
|
const propClass = ref(props.class)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="w-full">
|
||||||
|
<!-- 详情图标 -->
|
||||||
|
<div
|
||||||
|
v-if="cardTypeStyle === PanelPanelConfigStyleEnum.info"
|
||||||
|
class="w-full rounded-2xl transition-all duration-200 flex"
|
||||||
|
:class="propClass"
|
||||||
|
:style="{ backgroundColor: backgroundColor ?? defaultBackground }"
|
||||||
|
>
|
||||||
|
<slot name="info" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 极简图标(APP) -->
|
||||||
|
<div
|
||||||
|
v-if="cardTypeStyle === PanelPanelConfigStyleEnum.icon"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="overflow-hidden rounded-2xl sunpanel w-[70px] h-[70px] mx-auto transition-all duration-200"
|
||||||
|
:class="propClass"
|
||||||
|
:style="{ backgroundColor: backgroundColor ?? defaultBackground }"
|
||||||
|
>
|
||||||
|
<slot name="small" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="!iconTextIconHideTitle"
|
||||||
|
class="text-center app-icon-text-shadow cursor-pointer mt-[2px]"
|
||||||
|
:style="{ color: iconTextColor }"
|
||||||
|
>
|
||||||
|
{{ iconText }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
@ -8,6 +8,7 @@ import RoundCardModal from './RoundCardModal/index.vue'
|
|||||||
import SvgIconOnline from './SvgIconOnline/index.vue'
|
import SvgIconOnline from './SvgIconOnline/index.vue'
|
||||||
import JsonImportExport from './JsonImportExport/index.vue'
|
import JsonImportExport from './JsonImportExport/index.vue'
|
||||||
import AppLoader from './AppLoader/index.vue'
|
import AppLoader from './AppLoader/index.vue'
|
||||||
|
import ItemCard from './ItemCard/index.vue'
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Verification,
|
Verification,
|
||||||
@ -20,4 +21,5 @@ export {
|
|||||||
SvgIconOnline,
|
SvgIconOnline,
|
||||||
JsonImportExport,
|
JsonImportExport,
|
||||||
AppLoader,
|
AppLoader,
|
||||||
|
ItemCard,
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { onMounted, onUnmounted, ref } from 'vue'
|
||||||
|
import GenericProgress from '../components/GenericProgress/index.vue'
|
||||||
|
import { getCpuState } from '@/api/system/systemMonitor'
|
||||||
|
import type { PanelPanelConfigStyleEnum } from '@/enums'
|
||||||
|
|
||||||
|
interface Prop {
|
||||||
|
cardTypeStyle: PanelPanelConfigStyleEnum
|
||||||
|
refreshInterval: number
|
||||||
|
textColor: string
|
||||||
|
progressColor: string
|
||||||
|
progressRailColor: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Prop>()
|
||||||
|
let timer: NodeJS.Timer
|
||||||
|
const cpuState = ref<SystemMonitor.CPUInfo | null>(null)
|
||||||
|
|
||||||
|
function correctionNumber(v: number, keepNum = 2): number {
|
||||||
|
return v === 0 ? 0 : Number(v.toFixed(keepNum))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getData() {
|
||||||
|
try {
|
||||||
|
const { data, code } = await getCpuState<SystemMonitor.CPUInfo>()
|
||||||
|
if (code === 0)
|
||||||
|
cpuState.value = data
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getData()
|
||||||
|
timer = setInterval(() => {
|
||||||
|
getData()
|
||||||
|
}, (!props.refreshInterval || props.refreshInterval <= 2000) ? 2000 : props.refreshInterval)
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
clearInterval(timer)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="w-full">
|
||||||
|
<GenericProgress
|
||||||
|
:progress-color="progressColor"
|
||||||
|
:progress-rail-color="progressRailColor"
|
||||||
|
:progress-height="5"
|
||||||
|
:percentage="correctionNumber(cpuState?.usages[0] || 0)"
|
||||||
|
:card-type-style="cardTypeStyle"
|
||||||
|
:info-card-right-text="`${correctionNumber(cpuState?.usages[0] || 0)}%`"
|
||||||
|
info-card-left-text="CPU"
|
||||||
|
:text-color="textColor"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
@ -0,0 +1,69 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { onMounted, onUnmounted, ref } from 'vue'
|
||||||
|
import GenericProgress from '../components/GenericProgress/index.vue'
|
||||||
|
import type { PanelPanelConfigStyleEnum } from '@/enums'
|
||||||
|
import { bytesToSize } from '@/utils/cmn'
|
||||||
|
import { getDiskStateByPath } from '@/api/system/systemMonitor'
|
||||||
|
|
||||||
|
interface Prop {
|
||||||
|
cardTypeStyle: PanelPanelConfigStyleEnum
|
||||||
|
refreshInterval: number
|
||||||
|
textColor: string
|
||||||
|
progressColor: string
|
||||||
|
progressRailColor: string
|
||||||
|
path: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Prop>()
|
||||||
|
let timer: NodeJS.Timer
|
||||||
|
const diskState = ref<SystemMonitor.DiskInfo | null>(null)
|
||||||
|
|
||||||
|
function correctionNumber(v: number, keepNum = 2): number {
|
||||||
|
return v === 0 ? 0 : Number(v.toFixed(keepNum))
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatdiskSize(v: number): string {
|
||||||
|
return bytesToSize(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatdiskToByte(v: number): number {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getData() {
|
||||||
|
try {
|
||||||
|
const { data, code } = await getDiskStateByPath<SystemMonitor.DiskInfo>(props.path)
|
||||||
|
if (code === 0)
|
||||||
|
diskState.value = data
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getData()
|
||||||
|
timer = setInterval(() => {
|
||||||
|
getData()
|
||||||
|
}, (!props.refreshInterval || props.refreshInterval <= 2000) ? 2000 : props.refreshInterval)
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
clearInterval(timer)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="w-full">
|
||||||
|
<GenericProgress
|
||||||
|
:progress-color="progressColor"
|
||||||
|
:progress-rail-color="progressRailColor"
|
||||||
|
:progress-height="5"
|
||||||
|
:percentage="correctionNumber(diskState?.usedPercent || 0)"
|
||||||
|
:card-type-style="cardTypeStyle"
|
||||||
|
:info-card-right-text="`${formatdiskSize(formatdiskToByte(diskState?.total || 0))}/${formatdiskSize(formatdiskToByte(diskState?.free || 0))}`"
|
||||||
|
:info-card-left-text="diskState?.mountpoint"
|
||||||
|
:text-color="textColor"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
@ -0,0 +1,64 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { onMounted, onUnmounted, ref } from 'vue'
|
||||||
|
import GenericProgress from '../components/GenericProgress/index.vue'
|
||||||
|
import { getMemonyState } from '@/api/system/systemMonitor'
|
||||||
|
import type { PanelPanelConfigStyleEnum } from '@/enums'
|
||||||
|
import { bytesToSize } from '@/utils/cmn'
|
||||||
|
|
||||||
|
interface Prop {
|
||||||
|
cardTypeStyle: PanelPanelConfigStyleEnum
|
||||||
|
refreshInterval: number
|
||||||
|
textColor: string
|
||||||
|
progressColor: string
|
||||||
|
progressRailColor: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Prop>()
|
||||||
|
let timer: NodeJS.Timer
|
||||||
|
const memoryState = ref<SystemMonitor.MemoryInfo | null>(null)
|
||||||
|
|
||||||
|
function correctionNumber(v: number, keepNum = 2): number {
|
||||||
|
return v === 0 ? 0 : Number(v.toFixed(keepNum))
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatMemorySize(v: number): string {
|
||||||
|
return bytesToSize(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getData() {
|
||||||
|
try {
|
||||||
|
const { data, code } = await getMemonyState<SystemMonitor.MemoryInfo>()
|
||||||
|
if (code === 0)
|
||||||
|
memoryState.value = data
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getData()
|
||||||
|
timer = setInterval(() => {
|
||||||
|
getData()
|
||||||
|
}, (!props.refreshInterval || props.refreshInterval <= 2000) ? 2000 : props.refreshInterval)
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
clearInterval(timer)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="w-full">
|
||||||
|
<GenericProgress
|
||||||
|
:progress-color="progressColor"
|
||||||
|
:progress-rail-color="progressRailColor"
|
||||||
|
:progress-height="5"
|
||||||
|
:percentage="correctionNumber(memoryState?.usedPercent || 0)"
|
||||||
|
:card-type-style="cardTypeStyle"
|
||||||
|
:info-card-right-text="`${formatMemorySize(memoryState?.total || 0)}/${formatMemorySize(memoryState?.free || 0)}`"
|
||||||
|
info-card-left-text="RAM"
|
||||||
|
:text-color="textColor"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
@ -0,0 +1,118 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { MonitorType } from '../typings'
|
||||||
|
import type { CardStyle } from '../typings'
|
||||||
|
import GenericMonitorCard from '../components/GenericMonitorCard/index.vue'
|
||||||
|
import CardCPU from './CPU.vue'
|
||||||
|
import Memory from './Memory.vue'
|
||||||
|
import Disk from './Disk.vue'
|
||||||
|
import { SvgIcon } from '@/components/common'
|
||||||
|
import { PanelPanelConfigStyleEnum } from '@/enums'
|
||||||
|
|
||||||
|
interface Prop {
|
||||||
|
extendParam?: any
|
||||||
|
iconTextColor?: string
|
||||||
|
iconTextIconHideTitle: boolean
|
||||||
|
cardTypeStyle: PanelPanelConfigStyleEnum
|
||||||
|
monitorType: string
|
||||||
|
cardStyle: CardStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Prop>(), {})
|
||||||
|
|
||||||
|
const iconText = computed(() => {
|
||||||
|
switch (props.monitorType) {
|
||||||
|
case MonitorType.cpu:
|
||||||
|
return 'CPU'
|
||||||
|
case MonitorType.disk:
|
||||||
|
return props.extendParam.path
|
||||||
|
case MonitorType.memory:
|
||||||
|
return 'RAM'
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
})
|
||||||
|
const refreshInterval = 5000
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="w-full">
|
||||||
|
<GenericMonitorCard
|
||||||
|
:icon-text-icon-hide-title="false"
|
||||||
|
:card-type-style="cardTypeStyle"
|
||||||
|
:icon-text="iconText"
|
||||||
|
:icon-text-color="iconTextColor"
|
||||||
|
:background-color="extendParam.backgroundColor"
|
||||||
|
class="hover:shadow-[0_0_20px_10px_rgba(0,0,0,0.2)]"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<!-- 图标 -->
|
||||||
|
<div class="w-[60px] h-[70px]">
|
||||||
|
<div class="w-[60px] h-full flex items-center justify-center text-white">
|
||||||
|
<SvgIcon v-if="monitorType === MonitorType.cpu" icon="solar-cpu-bold" :style="{ color: extendParam.color }" style="width:35px;height:35px" />
|
||||||
|
<SvgIcon v-if="monitorType === MonitorType.memory" icon="material-symbols-memory-alt-rounded" :style="{ color: extendParam.color }" style="width:35px;height:35px" />
|
||||||
|
<SvgIcon v-if="monitorType === MonitorType.disk" icon="clarity-hard-disk-solid" :style="{ color: extendParam.color }" style="width:35px;height:35px" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #info>
|
||||||
|
<!-- 如果为纯白色,将自动根据背景的明暗计算字体的黑白色 -->
|
||||||
|
<div
|
||||||
|
class=" w-full text-white flex items-center"
|
||||||
|
>
|
||||||
|
<CardCPU
|
||||||
|
v-if="monitorType === MonitorType.cpu"
|
||||||
|
:card-type-style="PanelPanelConfigStyleEnum.info"
|
||||||
|
:progress-color="extendParam?.progressColor"
|
||||||
|
:progress-rail-color="extendParam?.progressRailColor"
|
||||||
|
:text-color="extendParam?.color"
|
||||||
|
:refresh-interval="refreshInterval"
|
||||||
|
/>
|
||||||
|
<Memory
|
||||||
|
v-else-if="monitorType === MonitorType.memory"
|
||||||
|
:card-type-style="PanelPanelConfigStyleEnum.info"
|
||||||
|
:progress-color="extendParam?.progressColor"
|
||||||
|
:progress-rail-color="extendParam?.progressRailColor"
|
||||||
|
:text-color="extendParam?.color"
|
||||||
|
:refresh-interval="refreshInterval"
|
||||||
|
/>
|
||||||
|
<Disk
|
||||||
|
v-else-if="monitorType === MonitorType.disk"
|
||||||
|
:card-type-style="PanelPanelConfigStyleEnum.info"
|
||||||
|
:progress-color="extendParam?.progressColor"
|
||||||
|
:progress-rail-color="extendParam?.progressRailColor"
|
||||||
|
:text-color="extendParam?.color"
|
||||||
|
:path="extendParam?.path"
|
||||||
|
:refresh-interval="refreshInterval"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #small>
|
||||||
|
<CardCPU
|
||||||
|
v-if="monitorType === MonitorType.cpu"
|
||||||
|
:card-type-style="PanelPanelConfigStyleEnum.icon"
|
||||||
|
:progress-color="extendParam?.progressColor"
|
||||||
|
:progress-rail-color="extendParam?.progressRailColor"
|
||||||
|
:text-color="extendParam?.color"
|
||||||
|
:refresh-interval="refreshInterval"
|
||||||
|
/>
|
||||||
|
<Memory
|
||||||
|
v-else-if="monitorType === MonitorType.memory"
|
||||||
|
:card-type-style="PanelPanelConfigStyleEnum.icon"
|
||||||
|
:progress-color="extendParam?.progressColor"
|
||||||
|
:progress-rail-color="extendParam?.progressRailColor"
|
||||||
|
:text-color="extendParam?.color"
|
||||||
|
:refresh-interval="refreshInterval"
|
||||||
|
/>
|
||||||
|
<Disk
|
||||||
|
v-else-if="monitorType === MonitorType.disk"
|
||||||
|
:card-type-style="PanelPanelConfigStyleEnum.icon"
|
||||||
|
:progress-color="extendParam?.progressColor"
|
||||||
|
:progress-rail-color="extendParam?.progressRailColor"
|
||||||
|
:text-color="extendParam?.color"
|
||||||
|
:path="extendParam?.path"
|
||||||
|
:refresh-interval="refreshInterval"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</GenericMonitorCard>
|
||||||
|
</div>
|
||||||
|
</template>
|
@ -0,0 +1,133 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, onMounted, ref } from 'vue'
|
||||||
|
import { NColorPicker, NForm, NFormItem, NSelect } from 'naive-ui'
|
||||||
|
import type { DiskExtendParam } from '../../typings'
|
||||||
|
import GenericMonitorCard from '../../components/GenericMonitorCard/index.vue'
|
||||||
|
import GenericProgress from '../../components/GenericProgress/index.vue'
|
||||||
|
import { PanelPanelConfigStyleEnum } from '@/enums'
|
||||||
|
import { getDiskMountpoints } from '@/api/system/systemMonitor'
|
||||||
|
import { defautSwatchesBackground } from '@/utils/defaultData'
|
||||||
|
|
||||||
|
interface Emit {
|
||||||
|
(e: 'update:diskExtendParam', visible: DiskExtendParam): void
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
diskExtendParam: DiskExtendParam
|
||||||
|
}>()
|
||||||
|
const emit = defineEmits<Emit>()
|
||||||
|
|
||||||
|
const mountPointList = ref<{
|
||||||
|
label: string
|
||||||
|
value: string
|
||||||
|
}[]>([])
|
||||||
|
|
||||||
|
const extendParam = computed({
|
||||||
|
get: () => props.diskExtendParam,
|
||||||
|
set: (visible) => {
|
||||||
|
emit('update:diskExtendParam', visible)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
async function getMountPointList() {
|
||||||
|
try {
|
||||||
|
const { data } = await getDiskMountpoints<SystemMonitor.Mountpoint[]>()
|
||||||
|
mountPointList.value = []
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
const element = data[i]
|
||||||
|
if (i === 0 && !extendParam.value.path)
|
||||||
|
extendParam.value.path = element.mountpoint
|
||||||
|
|
||||||
|
mountPointList.value.push({
|
||||||
|
label: element.mountpoint,
|
||||||
|
value: element.mountpoint,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getMountPointList()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<!-- <div>{{ diskExtendParam }}</div> -->
|
||||||
|
<div class="flex mb-5 justify-center transparent-grid p-2 rounded-xl border">
|
||||||
|
<div class="w-[200px]">
|
||||||
|
<GenericMonitorCard
|
||||||
|
icon-text-icon-hide-title
|
||||||
|
:card-type-style="PanelPanelConfigStyleEnum.info"
|
||||||
|
icon="solar-cpu-bold"
|
||||||
|
:background-color="extendParam.backgroundColor"
|
||||||
|
:text-color="extendParam.color"
|
||||||
|
>
|
||||||
|
<template #info>
|
||||||
|
<GenericProgress
|
||||||
|
:progress-color="extendParam.progressColor"
|
||||||
|
:progress-rail-color="extendParam.progressRailColor"
|
||||||
|
:percentage="50"
|
||||||
|
:progress-height="5"
|
||||||
|
info-card-left-text="DEMO"
|
||||||
|
info-card-right-text="TEXT"
|
||||||
|
:text-color="extendParam.color"
|
||||||
|
:card-type-style="PanelPanelConfigStyleEnum.info"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</GenericMonitorCard>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-[80px] ml-2">
|
||||||
|
<GenericMonitorCard
|
||||||
|
icon-text-icon-hide-title
|
||||||
|
:card-type-style="PanelPanelConfigStyleEnum.icon"
|
||||||
|
icon="solar-cpu-bold"
|
||||||
|
:background-color="extendParam.backgroundColor"
|
||||||
|
:icon-text-color="extendParam.color"
|
||||||
|
>
|
||||||
|
<template #small>
|
||||||
|
<GenericProgress
|
||||||
|
:progress-color="extendParam.progressColor"
|
||||||
|
:progress-rail-color="extendParam.progressRailColor"
|
||||||
|
:percentage="50"
|
||||||
|
:text-color="extendParam.color"
|
||||||
|
:card-type-style="PanelPanelConfigStyleEnum.icon"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</GenericMonitorCard>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<NForm ref="formRef" v-model="extendParam">
|
||||||
|
<NFormItem label="磁盘挂载点">
|
||||||
|
<NSelect v-model:value="extendParam.path" size="small" :options="mountPointList" />
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem label="主色">
|
||||||
|
<NColorPicker v-model:value="extendParam.progressColor" :swatches="defautSwatchesBackground" :modes="['hex']" size="small" />
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem label="副色">
|
||||||
|
<NColorPicker v-model:value="extendParam.progressRailColor" :swatches="defautSwatchesBackground" :modes="['hex']" size="small" />
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem label="文字图标颜色">
|
||||||
|
<NColorPicker v-model:value="extendParam.color" :swatches="defautSwatchesBackground" :modes="['hex']" size="small" />
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem label="卡片背景色">
|
||||||
|
<NColorPicker v-model:value="extendParam.backgroundColor" :swatches="defautSwatchesBackground" :modes="['hex']" size="small" />
|
||||||
|
</NFormItem>
|
||||||
|
</NForm>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.transparent-grid {
|
||||||
|
background-image: linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%),
|
||||||
|
linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%);
|
||||||
|
background-size: 16px 16px;
|
||||||
|
background-position: 0 0, 8px 8px;
|
||||||
|
background-color: #e2e8f0;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,101 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { NColorPicker, NForm, NFormItem } from 'naive-ui'
|
||||||
|
import type { GenericProgressStyleExtendParam } from '../../typings'
|
||||||
|
import GenericMonitorCard from '../../components/GenericMonitorCard/index.vue'
|
||||||
|
import GenericProgress from '../../components/GenericProgress/index.vue'
|
||||||
|
import { PanelPanelConfigStyleEnum } from '@/enums'
|
||||||
|
import { defautSwatchesBackground } from '@/utils/defaultData'
|
||||||
|
|
||||||
|
interface Emit {
|
||||||
|
(e: 'update:genericProgressStyleExtendParam', visible: GenericProgressStyleExtendParam): void
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
genericProgressStyleExtendParam: GenericProgressStyleExtendParam
|
||||||
|
}>()
|
||||||
|
const emit = defineEmits<Emit>()
|
||||||
|
|
||||||
|
const data = computed({
|
||||||
|
get: () => props.genericProgressStyleExtendParam,
|
||||||
|
set: (visible) => {
|
||||||
|
emit('update:genericProgressStyleExtendParam', visible)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<!-- <div>{{ genericProgressStyleExtendParam }}</div>
|
||||||
|
<div>{{ data }}</div> -->
|
||||||
|
<div class="flex mb-5 justify-center transparent-grid p-2 rounded-xl border">
|
||||||
|
<div class="w-[200px]">
|
||||||
|
<GenericMonitorCard
|
||||||
|
icon-text-icon-hide-title
|
||||||
|
:card-type-style="PanelPanelConfigStyleEnum.info"
|
||||||
|
icon="solar-cpu-bold"
|
||||||
|
:background-color="data.backgroundColor"
|
||||||
|
:text-color="data.color"
|
||||||
|
>
|
||||||
|
<template #info>
|
||||||
|
<GenericProgress
|
||||||
|
:progress-color="data.progressColor"
|
||||||
|
:progress-rail-color="data.progressRailColor"
|
||||||
|
:percentage="50"
|
||||||
|
:progress-height="5"
|
||||||
|
info-card-left-text="DEMO"
|
||||||
|
info-card-right-text="TEXT"
|
||||||
|
:text-color="data.color"
|
||||||
|
:card-type-style="PanelPanelConfigStyleEnum.info"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</GenericMonitorCard>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-[80px] ml-2">
|
||||||
|
<GenericMonitorCard
|
||||||
|
icon-text-icon-hide-title
|
||||||
|
:card-type-style="PanelPanelConfigStyleEnum.icon"
|
||||||
|
icon="solar-cpu-bold"
|
||||||
|
:background-color="data.backgroundColor"
|
||||||
|
:icon-text-color="data.color"
|
||||||
|
>
|
||||||
|
<template #small>
|
||||||
|
<GenericProgress
|
||||||
|
:progress-color="data.progressColor"
|
||||||
|
:progress-rail-color="data.progressRailColor"
|
||||||
|
:percentage="50"
|
||||||
|
:text-color="data.color"
|
||||||
|
:card-type-style="PanelPanelConfigStyleEnum.icon"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</GenericMonitorCard>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<NForm ref="formRef" v-model="data">
|
||||||
|
<NFormItem label="主色">
|
||||||
|
<NColorPicker v-model:value="data.progressColor" :swatches="defautSwatchesBackground" :modes="['hex']" size="small" />
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem label="副色">
|
||||||
|
<NColorPicker v-model:value="data.progressRailColor" :swatches="defautSwatchesBackground" :modes="['hex']" size="small" />
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem label="文字图标颜色">
|
||||||
|
<NColorPicker v-model:value="data.color" :swatches="defautSwatchesBackground" :modes="['hex']" size="small" />
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem label="卡片背景色">
|
||||||
|
<NColorPicker v-model:value="data.backgroundColor" :swatches="defautSwatchesBackground" :modes="['hex']" size="small" />
|
||||||
|
</NFormItem>
|
||||||
|
</NForm>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.transparent-grid {
|
||||||
|
background-image: linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%),
|
||||||
|
linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%);
|
||||||
|
background-size: 16px 16px;
|
||||||
|
background-position: 0 0, 8px 8px;
|
||||||
|
background-color: #e2e8f0;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,35 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { NColorPicker, NForm, NFormItem } from 'naive-ui'
|
||||||
|
import type { ProgressStyle } from '../../typings'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
progressStyle: ProgressStyle
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'update:progressStyle', visible: ProgressStyle): void // 定义修改父组件(prop内)的值的事件
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const data = computed({
|
||||||
|
get: () => props.progressStyle,
|
||||||
|
set() {
|
||||||
|
emit('update:progressStyle', data.value)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<NForm ref="formRef" :model="data">
|
||||||
|
<NFormItem path="url" label="主色">
|
||||||
|
<!-- <NSelect :style="{ width: '100px' }" :options="urlProtocolOptions" /> -->
|
||||||
|
<NColorPicker v-model:value="data.color" size="small" />
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem path="url" label="背景色">
|
||||||
|
<!-- <NSelect :style="{ width: '100px' }" :options="urlProtocolOptions" /> -->
|
||||||
|
<NColorPicker v-model:value="data.railColor" size="small" />
|
||||||
|
</NFormItem>
|
||||||
|
</NForm>
|
||||||
|
</div>
|
||||||
|
</template>
|
146
src/components/deskModule/SystemMonitor/Edit/index.vue
Normal file
146
src/components/deskModule/SystemMonitor/Edit/index.vue
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, defineEmits, defineProps, ref, watch } from 'vue'
|
||||||
|
import { NButton, NModal, NTabPane, NTabs, useMessage } from 'naive-ui'
|
||||||
|
import { MonitorType } from '../typings'
|
||||||
|
import type { DiskExtendParam, GenericProgressStyleExtendParam, MonitorData } from '../typings'
|
||||||
|
import { add, saveByIndex } from '../common'
|
||||||
|
|
||||||
|
import GenericProgressStyleEditor from './GenericProgressStyleEditor/index.vue'
|
||||||
|
import DiskEditor from './DiskEditor/index.vue'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
visible: boolean
|
||||||
|
monitorData: MonitorData | null
|
||||||
|
index: number | null
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
const emit = defineEmits<Emit>()
|
||||||
|
|
||||||
|
// 默认通用的进度扩展参数
|
||||||
|
const defaultGenericProgressStyleExtendParam: GenericProgressStyleExtendParam = {
|
||||||
|
progressColor: '#fff',
|
||||||
|
progressRailColor: '#CFCFCFA8',
|
||||||
|
color: '#fff',
|
||||||
|
backgroundColor: '#2a2a2a6b',
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultDiskExtendParam: DiskExtendParam = {
|
||||||
|
progressColor: '#fff',
|
||||||
|
progressRailColor: '#CFCFCFA8',
|
||||||
|
color: '#fff',
|
||||||
|
backgroundColor: '#2a2a2a6b',
|
||||||
|
path: '',
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultMonitorData: MonitorData = {
|
||||||
|
extendParam: defaultGenericProgressStyleExtendParam,
|
||||||
|
monitorType: MonitorType.cpu,
|
||||||
|
}
|
||||||
|
|
||||||
|
const active = ref<string>(MonitorType.cpu)
|
||||||
|
const currentMonitorData = ref<MonitorData>(props.monitorData || { ...defaultMonitorData })
|
||||||
|
const currentGenericProgressStyleExtendParam = ref<GenericProgressStyleExtendParam>({ ...defaultGenericProgressStyleExtendParam })
|
||||||
|
const currentDiskExtendParam = ref<DiskExtendParam>({ ...defaultDiskExtendParam })
|
||||||
|
|
||||||
|
const ms = useMessage()
|
||||||
|
const submitLoading = ref(false)
|
||||||
|
|
||||||
|
interface Emit {
|
||||||
|
(e: 'update:visible', visible: boolean): void
|
||||||
|
(e: 'done', item: boolean): void
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新值父组件传来的值
|
||||||
|
const show = computed({
|
||||||
|
get: () => props.visible,
|
||||||
|
set: (visible: boolean) => {
|
||||||
|
emit('update:visible', visible)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(() => props.visible, (value) => {
|
||||||
|
active.value = props.monitorData?.monitorType || MonitorType.cpu
|
||||||
|
if (props.monitorData?.monitorType === MonitorType.cpu || props.monitorData?.monitorType === MonitorType.memory)
|
||||||
|
currentGenericProgressStyleExtendParam.value = { ...props.monitorData?.extendParam }
|
||||||
|
else if (props.monitorData?.monitorType === MonitorType.disk)
|
||||||
|
currentDiskExtendParam.value = { ...props.monitorData?.extendParam }
|
||||||
|
|
||||||
|
if (!value)
|
||||||
|
handleResetExtendParam()
|
||||||
|
})
|
||||||
|
|
||||||
|
function handleResetExtendParam() {
|
||||||
|
currentGenericProgressStyleExtendParam.value = { ...defaultGenericProgressStyleExtendParam }
|
||||||
|
currentDiskExtendParam.value = { ...defaultDiskExtendParam }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存提交
|
||||||
|
async function handleSubmit() {
|
||||||
|
currentMonitorData.value.monitorType = active.value as MonitorType
|
||||||
|
if (currentMonitorData.value.monitorType === MonitorType.cpu || currentMonitorData.value.monitorType === MonitorType.memory)
|
||||||
|
currentMonitorData.value.extendParam = currentGenericProgressStyleExtendParam
|
||||||
|
|
||||||
|
else if (currentMonitorData.value.monitorType === MonitorType.disk)
|
||||||
|
currentMonitorData.value.extendParam = currentDiskExtendParam
|
||||||
|
|
||||||
|
console.log('保存', currentMonitorData.value.extendParam)
|
||||||
|
|
||||||
|
if (props.index !== null) {
|
||||||
|
const res = await saveByIndex(props.index, currentMonitorData.value)
|
||||||
|
if (res) {
|
||||||
|
show.value = false
|
||||||
|
emit('done', true)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ms.error('保存失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const res = await add(currentMonitorData.value)
|
||||||
|
if (res) {
|
||||||
|
show.value = false
|
||||||
|
emit('done', true)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ms.error('保存失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<NModal v-model:show="show" preset="card" size="small" style="width: 600px;border-radius: 1rem;" :title="monitorData ? '修改项目' : '添加项目'">
|
||||||
|
<!-- 选择监视器 -->
|
||||||
|
<!-- <div>
|
||||||
|
{{ JSON.stringify(currentGenericProgressStyleExtendParam) }}
|
||||||
|
{{ JSON.stringify(currentDiskExtendParam) }}
|
||||||
|
</div> -->
|
||||||
|
<NTabs v-model:value="active" type="segment">
|
||||||
|
<NTabPane :name="MonitorType.cpu" tab="CPU状态">
|
||||||
|
<GenericProgressStyleEditor v-model:genericProgressStyleExtendParam="currentGenericProgressStyleExtendParam" />
|
||||||
|
<NButton @click="handleResetExtendParam">
|
||||||
|
重置
|
||||||
|
</NButton>
|
||||||
|
</NTabPane>
|
||||||
|
<NTabPane :name="MonitorType.memory" tab="内存状态">
|
||||||
|
<GenericProgressStyleEditor v-model:genericProgressStyleExtendParam="currentGenericProgressStyleExtendParam" />
|
||||||
|
<NButton @click="handleResetExtendParam">
|
||||||
|
重置
|
||||||
|
</NButton>
|
||||||
|
</NTabPane>
|
||||||
|
<NTabPane :name="MonitorType.disk" tab="磁盘状态">
|
||||||
|
<DiskEditor v-model:disk-extend-param="currentDiskExtendParam" />
|
||||||
|
<NButton @click="handleResetExtendParam">
|
||||||
|
重置
|
||||||
|
</NButton>
|
||||||
|
</NTabPane>
|
||||||
|
</NTabs>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<NButton type="success" :loading="submitLoading" style="float: right;" @click="handleSubmit">
|
||||||
|
确定
|
||||||
|
</NButton>
|
||||||
|
</template>
|
||||||
|
</NModal>
|
||||||
|
</template>
|
88
src/components/deskModule/SystemMonitor/common.ts
Normal file
88
src/components/deskModule/SystemMonitor/common.ts
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import type { MonitorData } from './typings'
|
||||||
|
import { useModuleConfig } from '@/store/modules'
|
||||||
|
|
||||||
|
const modelName = 'systemMonitor'
|
||||||
|
const moduleConfig = useModuleConfig()
|
||||||
|
|
||||||
|
export async function saveAll(value: MonitorData[]) {
|
||||||
|
return await moduleConfig.saveToCloud(modelName, { list: value })
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getAll(): Promise< MonitorData[]> {
|
||||||
|
const res = await moduleConfig.getValueByNameFromCloud<{ list: MonitorData[] }>(modelName)
|
||||||
|
if (res.code === 0 && res.data && res.data.list)
|
||||||
|
return res.data.list
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function add(value: MonitorData): Promise<boolean> {
|
||||||
|
let success = true
|
||||||
|
let newData: MonitorData[] = []
|
||||||
|
try {
|
||||||
|
const data = await getAll()
|
||||||
|
if (data)
|
||||||
|
newData = data
|
||||||
|
|
||||||
|
newData.push(value)
|
||||||
|
const res = await saveAll(newData)
|
||||||
|
if (res.code !== 0)
|
||||||
|
console.log('save failed', res)
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
success = false
|
||||||
|
}
|
||||||
|
return success
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function saveByIndex(index: number | undefined, value: MonitorData): Promise<boolean> {
|
||||||
|
if (!index)
|
||||||
|
index = 0
|
||||||
|
|
||||||
|
let success = true
|
||||||
|
let newData: MonitorData[] = []
|
||||||
|
try {
|
||||||
|
const data = await getAll()
|
||||||
|
if (data)
|
||||||
|
newData = data
|
||||||
|
|
||||||
|
newData[index] = value
|
||||||
|
const res = await saveAll(newData)
|
||||||
|
if (res.code !== 0)
|
||||||
|
console.log('save failed', res)
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
success = false
|
||||||
|
}
|
||||||
|
return success
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getByIndex(index: number): Promise<MonitorData | null> {
|
||||||
|
try {
|
||||||
|
const data = await getAll()
|
||||||
|
if (data[index])
|
||||||
|
return data[index]
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteByIndex(index: number): Promise<boolean> {
|
||||||
|
let success = true
|
||||||
|
try {
|
||||||
|
const data = await getAll()
|
||||||
|
if (data[index])
|
||||||
|
data.splice(index, 1)
|
||||||
|
await saveAll(data)
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
success = false
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return success
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// -------------------
|
||||||
|
// 系统监控图标临时使用(与 AppIcon/index.vue 一致)
|
||||||
|
// 如果确定这种方案将 AppIcon/index.vue 封装成通用组件
|
||||||
|
// -------------------
|
||||||
|
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { ItemCard, SvgIcon } from '@/components/common'
|
||||||
|
import type { PanelPanelConfigStyleEnum } from '@/enums'
|
||||||
|
|
||||||
|
interface Prop {
|
||||||
|
// size?: number // 默认70
|
||||||
|
extendParam?: any
|
||||||
|
iconTextColor?: string
|
||||||
|
iconTextIconHideTitle?: boolean
|
||||||
|
iconText?: string
|
||||||
|
textColor?: string
|
||||||
|
cardTypeStyle: PanelPanelConfigStyleEnum
|
||||||
|
// monitorType: string
|
||||||
|
icon?: string
|
||||||
|
class?: string
|
||||||
|
backgroundColor?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Prop>(), {})
|
||||||
|
const propClass = ref(props.class)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="w-full">
|
||||||
|
<ItemCard
|
||||||
|
:card-type-style="cardTypeStyle"
|
||||||
|
:icon-text="iconText"
|
||||||
|
:icon-text-color="iconTextColor"
|
||||||
|
:class="propClass"
|
||||||
|
:background-color="backgroundColor"
|
||||||
|
:icon-text-icon-hide-title="iconTextIconHideTitle"
|
||||||
|
>
|
||||||
|
<template #info>
|
||||||
|
<!-- 图标 -->
|
||||||
|
<div class="w-[60px] h-[70px]">
|
||||||
|
<div class="w-[60px] h-full flex items-center justify-center text-white">
|
||||||
|
<slot name="icon">
|
||||||
|
<SvgIcon :icon="icon ?? ''" style="width: 35px;height: 35px;" :style="{ color: textColor }" />
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class=" w-full text-white flex items-center"
|
||||||
|
:style=" { maxWidth: 'calc(100% - 80px)' }"
|
||||||
|
>
|
||||||
|
<slot name="info" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #small>
|
||||||
|
<slot name="small" />
|
||||||
|
</template>
|
||||||
|
</ItemCard>
|
||||||
|
</div>
|
||||||
|
</template>
|
@ -0,0 +1,57 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { NProgress } from 'naive-ui'
|
||||||
|
import { PanelPanelConfigStyleEnum } from '@/enums'
|
||||||
|
|
||||||
|
interface Prop {
|
||||||
|
textColor: string
|
||||||
|
progressColor: string
|
||||||
|
progressRailColor: string
|
||||||
|
progressHeight?: number
|
||||||
|
percentage: number
|
||||||
|
cardTypeStyle: PanelPanelConfigStyleEnum
|
||||||
|
infoCardLeftText?: string
|
||||||
|
infoCardRightText?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
defineProps<Prop>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="w-full">
|
||||||
|
<div v-if="cardTypeStyle === PanelPanelConfigStyleEnum.info">
|
||||||
|
<div class="mb-1 text-xs" :style="{ color: textColor }">
|
||||||
|
<span>
|
||||||
|
{{ infoCardLeftText }}
|
||||||
|
</span>
|
||||||
|
<span class="float-right">
|
||||||
|
{{ infoCardRightText }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<NProgress
|
||||||
|
type="line"
|
||||||
|
:color="progressColor"
|
||||||
|
:rail-color="progressRailColor"
|
||||||
|
:height="progressHeight"
|
||||||
|
:percentage="percentage"
|
||||||
|
:show-indicator="false"
|
||||||
|
:stroke-width="15"
|
||||||
|
style="max-width: 135px;"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<div class="flex justify-center h-full w-full mt-3">
|
||||||
|
<NProgress
|
||||||
|
:color="progressColor"
|
||||||
|
:rail-color="progressRailColor"
|
||||||
|
type="dashboard"
|
||||||
|
:percentage="percentage" :stroke-width="15"
|
||||||
|
style="width: 50px;"
|
||||||
|
>
|
||||||
|
<div class="text-white" style="font-size: 8px;" :style="{ color: textColor }">
|
||||||
|
{{ percentage }}%
|
||||||
|
</div>
|
||||||
|
</NProgress>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
171
src/components/deskModule/SystemMonitor/index copy.vue
Normal file
171
src/components/deskModule/SystemMonitor/index copy.vue
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { onMounted, onUnmounted, ref } from 'vue'
|
||||||
|
import { NProgress } from 'naive-ui'
|
||||||
|
import { getAll } from '@/api/system/systemMonitor'
|
||||||
|
import { SvgIcon } from '@/components/common'
|
||||||
|
import { bytesToSize } from '@/utils/cmn'
|
||||||
|
|
||||||
|
interface ProgressStyle {
|
||||||
|
color: string
|
||||||
|
railColor: string
|
||||||
|
height: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const systemMonitorData = ref<SystemMonitor.GetAllRes | null>(null)
|
||||||
|
const progressStyle = ref<ProgressStyle>({
|
||||||
|
color: 'white',
|
||||||
|
railColor: 'rgba(0, 0, 0, 0.5)',
|
||||||
|
height: 5,
|
||||||
|
})
|
||||||
|
const svgStyle = {
|
||||||
|
width: '25px',
|
||||||
|
height: '25px',
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getData() {
|
||||||
|
try {
|
||||||
|
const { data, code } = await getAll<SystemMonitor.GetAllRes>()
|
||||||
|
if (code === 0)
|
||||||
|
systemMonitorData.value = data
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function correctionNumber(v: number, keepNum = 2): number {
|
||||||
|
return v === 0 ? 0 : Number(v.toFixed(keepNum))
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatMemorySize(v: number): string {
|
||||||
|
return bytesToSize(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatdiskSize(v: number): string {
|
||||||
|
return bytesToSize(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatdiskToByte(v: number): number {
|
||||||
|
return v * 1024 * 1024
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
getData()
|
||||||
|
// timer = setInterval(() => {
|
||||||
|
// getData()
|
||||||
|
// }, 5000)
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
// clearInterval(timer)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="w-full system-monitor flex items-center px-2 text-white overflow-auto">
|
||||||
|
<!-- <div class="flex flex-col items-center justify-center ">
|
||||||
|
<div>
|
||||||
|
<NProgress type="dashboard" :percentage="correctionNumber(systemMonitorData?.cpuInfo.usages[0] || 0)" :stroke-width="15" style="width: 50px;">
|
||||||
|
<div class="text-white text-xs">
|
||||||
|
{{ correctionNumber(systemMonitorData?.cpuInfo.usages[0] || 0, 1) }}%
|
||||||
|
</div>
|
||||||
|
</NProgress>
|
||||||
|
</div>
|
||||||
|
<span>
|
||||||
|
CPU
|
||||||
|
</span>
|
||||||
|
</div> -->
|
||||||
|
<div class="text-xs mr-10 flex justify-center items-center">
|
||||||
|
<div class="mr-2">
|
||||||
|
<SvgIcon icon="solar-cpu-bold" :style="svgStyle" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="mb-1">
|
||||||
|
<span>
|
||||||
|
CPU
|
||||||
|
</span>
|
||||||
|
<span class="float-right">
|
||||||
|
{{ correctionNumber(systemMonitorData?.cpuInfo.usages[0] || 0) }}%
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<NProgress
|
||||||
|
type="line"
|
||||||
|
:color="progressStyle.color"
|
||||||
|
:rail-color="progressStyle.railColor"
|
||||||
|
:height="progressStyle.height"
|
||||||
|
:percentage="correctionNumber(systemMonitorData?.cpuInfo.usages[0] || 0)"
|
||||||
|
:show-indicator="false"
|
||||||
|
:stroke-width="15"
|
||||||
|
style="width: 150px;"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-xs mr-10 flex justify-center items-center">
|
||||||
|
<div class="mr-2">
|
||||||
|
<SvgIcon icon="material-symbols-memory-alt-rounded" :style="svgStyle" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="mb-1">
|
||||||
|
<span>
|
||||||
|
RAM
|
||||||
|
</span>
|
||||||
|
<span class="float-right">
|
||||||
|
{{ formatMemorySize(systemMonitorData?.memoryInfo.total || 0) }}/{{ formatMemorySize(systemMonitorData?.memoryInfo.free || 0) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<NProgress
|
||||||
|
type="line"
|
||||||
|
:color="progressStyle.color"
|
||||||
|
:rail-color="progressStyle.railColor"
|
||||||
|
:height="progressStyle.height"
|
||||||
|
:percentage="systemMonitorData?.memoryInfo.usedPercent"
|
||||||
|
:show-indicator="false"
|
||||||
|
:stroke-width="15" style="width: 150px;"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- <div class="text-xs mr-2">
|
||||||
|
<div class="mb-1">
|
||||||
|
<span>
|
||||||
|
网络:{{ systemMonitorData?.netIOCountersInfo[0].name }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span class="float-right">
|
||||||
|
上行:{{ netIOToKB(systemMonitorData?.netIOCountersInfo[0].bytesSent || 0) }}
|
||||||
|
下行:{{ netIOToKB(systemMonitorData?.netIOCountersInfo[0].bytesRecv || 0) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
|
||||||
|
<!-- 磁盘信息 -->
|
||||||
|
<div v-for=" item, index in systemMonitorData?.diskInfo" :key="index">
|
||||||
|
<div class="text-xs mr-10 flex justify-center items-center">
|
||||||
|
<div class="mr-2">
|
||||||
|
<SvgIcon icon="clarity-hard-disk-solid" :style="svgStyle" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="mb-1">
|
||||||
|
<span>
|
||||||
|
{{ item.mountpoint }}
|
||||||
|
</span>
|
||||||
|
<span class="float-right">
|
||||||
|
{{ formatdiskSize(formatdiskToByte(item.total || 0)) }}/{{ formatdiskSize(formatdiskToByte(item.free || 0)) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<NProgress
|
||||||
|
:color="progressStyle.color"
|
||||||
|
:rail-color="progressStyle.railColor"
|
||||||
|
:height="progressStyle.height"
|
||||||
|
type="line"
|
||||||
|
:percentage="item.usedPercent"
|
||||||
|
:show-indicator="false"
|
||||||
|
:stroke-width="15"
|
||||||
|
style="width: 150px;"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
@ -1,176 +1,300 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, onUnmounted, ref } from 'vue'
|
import { nextTick, onMounted, ref } from 'vue'
|
||||||
import { NProgress } from 'naive-ui'
|
import { VueDraggable } from 'vue-draggable-plus'
|
||||||
import { getAll } from '@/api/system/systemMonitor'
|
import { NButton, NDropdown, useDialog, useMessage } from 'naive-ui'
|
||||||
|
import AppIconSystemMonitor from './AppIconSystemMonitor/index.vue'
|
||||||
|
import { type CardStyle, type MonitorData, MonitorType } from './typings'
|
||||||
|
import Edit from './Edit/index.vue'
|
||||||
|
import { deleteByIndex, getAll, saveAll } from './common'
|
||||||
|
import { usePanelState } from '@/store'
|
||||||
|
import { PanelPanelConfigStyleEnum } from '@/enums'
|
||||||
import { SvgIcon } from '@/components/common'
|
import { SvgIcon } from '@/components/common'
|
||||||
import { bytesToSize } from '@/utils/cmn'
|
import { t } from '@/locales'
|
||||||
|
|
||||||
interface ProgressStyle {
|
interface MonitorGroup extends Panel.ItemIconGroup {
|
||||||
color: string
|
sortStatus?: boolean
|
||||||
railColor: string
|
hoverStatus: boolean
|
||||||
height: number
|
items?: Panel.ItemInfo[]
|
||||||
}
|
}
|
||||||
|
|
||||||
let timer: NodeJS.Timer
|
const props = defineProps<{
|
||||||
const systemMonitorData = ref<SystemMonitor.GetAllRes | null>(null)
|
allowEdit?: boolean
|
||||||
const progressStyle = ref<ProgressStyle>({
|
showTitle?: boolean
|
||||||
color: 'white',
|
}>()
|
||||||
railColor: 'rgba(0, 0, 0, 0.5)',
|
const panelState = usePanelState()
|
||||||
height: 5,
|
|
||||||
|
const dialog = useDialog()
|
||||||
|
const ms = useMessage()
|
||||||
|
|
||||||
|
const dropdownMenuX = ref(0)
|
||||||
|
const dropdownMenuY = ref(0)
|
||||||
|
const dropdownShow = ref(false)
|
||||||
|
const currentRightSelectIndex = ref<number | null>(null)
|
||||||
|
|
||||||
|
const monitorGroup = ref<MonitorGroup>({
|
||||||
|
hoverStatus: false,
|
||||||
|
sortStatus: false,
|
||||||
})
|
})
|
||||||
const svgStyle = {
|
|
||||||
width: '25px',
|
const editShowStatus = ref<boolean>(false)
|
||||||
height: '25px',
|
const editData = ref<MonitorData | null>(null)
|
||||||
|
const editIndex = ref<number | null>(null)
|
||||||
|
|
||||||
|
function handleAddItem() {
|
||||||
|
editShowStatus.value = true
|
||||||
|
editData.value = null
|
||||||
|
editIndex.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSetSortStatus(sortStatus: boolean) {
|
||||||
|
monitorGroup.value.sortStatus = sortStatus
|
||||||
|
|
||||||
|
// 并未保存排序重新更新数据
|
||||||
|
if (!sortStatus)
|
||||||
|
getData()
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSetHoverStatus(hoverStatus: boolean) {
|
||||||
|
monitorGroup.value.hoverStatus = hoverStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
const cardStyle: CardStyle = {
|
||||||
|
background: '#2a2a2a6b',
|
||||||
|
}
|
||||||
|
|
||||||
|
const monitorDatas = ref<MonitorData[]>([])
|
||||||
|
|
||||||
|
function handleClick(index: number, item: MonitorData) {
|
||||||
|
if (!props.allowEdit)
|
||||||
|
return
|
||||||
|
editShowStatus.value = true
|
||||||
|
editData.value = item
|
||||||
|
editIndex.value = index
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getData() {
|
async function getData() {
|
||||||
try {
|
monitorDatas.value = await getAll()
|
||||||
const { data, code } = await getAll<SystemMonitor.GetAllRes>()
|
|
||||||
if (code === 0)
|
|
||||||
systemMonitorData.value = data
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
|
|
||||||
|
if (monitorDatas.value.length === 0) {
|
||||||
|
// 防止空 - 默认数据
|
||||||
|
monitorDatas.value.push(
|
||||||
|
{
|
||||||
|
extendParam: {
|
||||||
|
backgroundColor: '#2a2a2a6b',
|
||||||
|
color: '#fff',
|
||||||
|
progressColor: '#fff',
|
||||||
|
progressRailColor: '#CFCFCFA8',
|
||||||
|
},
|
||||||
|
monitorType: MonitorType.cpu,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
// 生成并保存
|
||||||
|
saveAll(monitorDatas.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function correctionNumber(v: number, keepNum = 2): number {
|
|
||||||
return v === 0 ? 0 : Number(v.toFixed(keepNum))
|
|
||||||
}
|
|
||||||
|
|
||||||
// function formatMemoryToGB(v: number): number {
|
|
||||||
// return correctionNumber(v / 1024 / 1024 / 1024)
|
|
||||||
// }
|
|
||||||
|
|
||||||
function formatMemorySize(v: number): string {
|
|
||||||
return bytesToSize(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatdiskSize(v: number): string {
|
|
||||||
return bytesToSize(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatdiskToByte(v: number): number {
|
|
||||||
return v * 1024 * 1024
|
|
||||||
}
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getData()
|
getData()
|
||||||
timer = setInterval(() => {
|
|
||||||
getData()
|
|
||||||
}, 5000)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
function handleSaveDone() {
|
||||||
clearInterval(timer)
|
getData()
|
||||||
})
|
}
|
||||||
|
|
||||||
|
async function handleSaveSort() {
|
||||||
|
const { code } = await saveAll(monitorDatas.value)
|
||||||
|
if (code === 0)
|
||||||
|
monitorGroup.value.sortStatus = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleContextMenu(e: MouseEvent, index: number | null, item: MonitorData) {
|
||||||
|
if (index !== null) {
|
||||||
|
e.preventDefault()
|
||||||
|
currentRightSelectIndex.value = index
|
||||||
|
}
|
||||||
|
|
||||||
|
nextTick().then(() => {
|
||||||
|
dropdownShow.value = true
|
||||||
|
dropdownMenuX.value = e.clientX
|
||||||
|
dropdownMenuY.value = e.clientY
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDropdownMenuOptions() {
|
||||||
|
const dropdownMenuOptions = [
|
||||||
|
{
|
||||||
|
label: t('common.delete'),
|
||||||
|
key: 'delete',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
return dropdownMenuOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
function onClickoutside() {
|
||||||
|
// message.info('clickoutside')
|
||||||
|
dropdownShow.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteOneByIndex(index: number) {
|
||||||
|
const res = await deleteByIndex(index)
|
||||||
|
if (res)
|
||||||
|
getData()
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleRightMenuSelect(key: string | number) {
|
||||||
|
dropdownShow.value = false
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case 'delete':
|
||||||
|
dialog.warning({
|
||||||
|
title: '警告',
|
||||||
|
content: '你确定要删除吗?',
|
||||||
|
positiveText: '确定',
|
||||||
|
negativeText: '取消',
|
||||||
|
onPositiveClick: () => {
|
||||||
|
if (monitorDatas.value.length <= 1) {
|
||||||
|
ms.warning(t('common.leastOne'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (currentRightSelectIndex.value !== null)
|
||||||
|
deleteOneByIndex(currentRightSelectIndex.value)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="w-full p-5 px-5 bg-[#2a2a2a6b] system-monitor flex items-center px-2 text-white overflow-auto">
|
<div class="w-full">
|
||||||
<!-- <div class="flex flex-col items-center justify-center ">
|
<div
|
||||||
<div>
|
class="mt-[50px]"
|
||||||
<NProgress type="dashboard" :percentage="correctionNumber(systemMonitorData?.cpuInfo.usages[0] || 0)" :stroke-width="15" style="width: 50px;">
|
:class="monitorGroup.sortStatus ? 'shadow-2xl border shadow-[0_0_30px_10px_rgba(0,0,0,0.3)] p-[10px] rounded-2xl' : ''"
|
||||||
<div class="text-white text-xs">
|
@mouseenter="handleSetHoverStatus(true)"
|
||||||
{{ correctionNumber(systemMonitorData?.cpuInfo.usages[0] || 0, 1) }}%
|
@mouseleave="handleSetHoverStatus(false)"
|
||||||
|
>
|
||||||
|
<!-- 分组标题 -->
|
||||||
|
<div class="text-white text-xl font-extrabold mb-[20px] ml-[10px] flex items-center">
|
||||||
|
<span v-if="showTitle" class="text-shadow">
|
||||||
|
系统状态
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
v-if="allowEdit"
|
||||||
|
class="ml-2 delay-100 transition-opacity flex"
|
||||||
|
:class="monitorGroup.hoverStatus ? 'opacity-100' : 'opacity-0'"
|
||||||
|
>
|
||||||
|
<span class="mr-2 cursor-pointer" title="添加快捷图标" @click="handleAddItem()">
|
||||||
|
<SvgIcon class="text-white font-xl" icon="typcn:plus" />
|
||||||
|
</span>
|
||||||
|
<span class="mr-2 cursor-pointer " title="排序组快捷图标" @click="handleSetSortStatus(!monitorGroup.sortStatus)">
|
||||||
|
<SvgIcon class="text-white font-xl" icon="ri:drag-drop-line" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 详情图标 -->
|
||||||
|
<div v-if="panelState.panelConfig.iconStyle === PanelPanelConfigStyleEnum.info">
|
||||||
|
<VueDraggable
|
||||||
|
v-model="monitorDatas" item-key="sort" :animation="300"
|
||||||
|
class="icon-info-box"
|
||||||
|
filter=".not-drag"
|
||||||
|
:disabled="!monitorGroup.sortStatus"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="item, index in monitorDatas" :key="index"
|
||||||
|
:title="item.description"
|
||||||
|
@click="handleClick(index, item)"
|
||||||
|
@contextmenu="(e) => handleContextMenu(e, index, item)"
|
||||||
|
>
|
||||||
|
<AppIconSystemMonitor
|
||||||
|
:extend-param="item.extendParam"
|
||||||
|
:icon-text-icon-hide-title="false"
|
||||||
|
:card-type-style="panelState.panelConfig.iconStyle"
|
||||||
|
:monitor-type="item.monitorType"
|
||||||
|
:card-style="cardStyle"
|
||||||
|
:icon-text-color="panelState.panelConfig.iconTextColor"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</NProgress>
|
</VueDraggable>
|
||||||
</div>
|
</div>
|
||||||
<span>
|
|
||||||
CPU
|
|
||||||
</span>
|
|
||||||
</div> -->
|
|
||||||
<div class="text-xs mr-10 flex justify-center items-center">
|
|
||||||
<div class="mr-2">
|
|
||||||
<SvgIcon icon="solar-cpu-bold" :style="svgStyle" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="mb-1">
|
|
||||||
<span>
|
|
||||||
CPU
|
|
||||||
</span>
|
|
||||||
<span class="float-right">
|
|
||||||
{{ correctionNumber(systemMonitorData?.cpuInfo.usages[0] || 0) }}%
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<NProgress
|
|
||||||
type="line"
|
|
||||||
:color="progressStyle.color"
|
|
||||||
:rail-color="progressStyle.railColor"
|
|
||||||
:height="progressStyle.height"
|
|
||||||
:percentage="correctionNumber(systemMonitorData?.cpuInfo.usages[0] || 0)"
|
|
||||||
:show-indicator="false"
|
|
||||||
:stroke-width="15"
|
|
||||||
style="width: 150px;"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-xs mr-10 flex justify-center items-center">
|
<!-- APP图标宫型盒子 -->
|
||||||
<div class="mr-2">
|
<div v-if="panelState.panelConfig.iconStyle === PanelPanelConfigStyleEnum.icon">
|
||||||
<SvgIcon icon="material-symbols-memory-alt-rounded" :style="svgStyle" />
|
<div v-if="monitorDatas">
|
||||||
</div>
|
<VueDraggable
|
||||||
<div>
|
v-model="monitorDatas" item-key="sort" :animation="300"
|
||||||
<div class="mb-1">
|
class="icon-small-box"
|
||||||
<span>
|
filter=".not-drag"
|
||||||
RAM
|
:disabled="!monitorGroup.sortStatus"
|
||||||
</span>
|
>
|
||||||
<span class="float-right">
|
<div
|
||||||
{{ formatMemorySize(systemMonitorData?.memoryInfo.total || 0) }}/{{ formatMemorySize(systemMonitorData?.memoryInfo.free || 0) }}
|
v-for="item, index in monitorDatas" :key="index"
|
||||||
</span>
|
:title="item.description"
|
||||||
|
@click="handleClick(index, item)"
|
||||||
|
@contextmenu="(e) => handleContextMenu(e, index, item)"
|
||||||
|
>
|
||||||
|
<AppIconSystemMonitor
|
||||||
|
:extend-param="item.extendParam"
|
||||||
|
:icon-text-icon-hide-title="false"
|
||||||
|
:card-type-style="panelState.panelConfig.iconStyle"
|
||||||
|
:monitor-type="item.monitorType"
|
||||||
|
:card-style="cardStyle"
|
||||||
|
:icon-text-color="panelState.panelConfig.iconTextColor"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</vuedraggable>
|
||||||
</div>
|
</div>
|
||||||
<NProgress
|
|
||||||
type="line"
|
|
||||||
:color="progressStyle.color"
|
|
||||||
:rail-color="progressStyle.railColor"
|
|
||||||
:height="progressStyle.height"
|
|
||||||
:percentage="systemMonitorData?.memoryInfo.usedPercent"
|
|
||||||
:show-indicator="false"
|
|
||||||
:stroke-width="15" style="width: 150px;"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- <div class="text-xs mr-2">
|
<!-- 编辑栏 -->
|
||||||
<div class="mb-1">
|
<div v-if="monitorGroup.sortStatus && allowEdit" class="flex mt-[10px]">
|
||||||
<span>
|
|
||||||
网络:{{ systemMonitorData?.netIOCountersInfo[0].name }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="float-right">
|
|
||||||
上行:{{ netIOToKB(systemMonitorData?.netIOCountersInfo[0].bytesSent || 0) }}
|
|
||||||
下行:{{ netIOToKB(systemMonitorData?.netIOCountersInfo[0].bytesRecv || 0) }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
|
|
||||||
<!-- 磁盘信息 -->
|
|
||||||
<div v-for=" item, index in systemMonitorData?.diskInfo" :key="index">
|
|
||||||
<div class="text-xs mr-10 flex justify-center items-center">
|
|
||||||
<div class="mr-2">
|
|
||||||
<SvgIcon icon="clarity-hard-disk-solid" :style="svgStyle" />
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<div class="mb-1">
|
<NButton color="#2a2a2a6b" @click="handleSaveSort()">
|
||||||
<span>
|
<template #icon>
|
||||||
{{ item.mountpoint }}
|
<SvgIcon class="text-white font-xl" icon="material-symbols:save" />
|
||||||
</span>
|
</template>
|
||||||
<span class="float-right">
|
<div>
|
||||||
{{ formatdiskSize(formatdiskToByte(item.total || 0)) }}/{{ formatdiskSize(formatdiskToByte(item.free || 0)) }}
|
保存排序
|
||||||
</span>
|
</div>
|
||||||
</div>
|
</NButton>
|
||||||
<NProgress
|
|
||||||
:color="progressStyle.color"
|
|
||||||
:rail-color="progressStyle.railColor"
|
|
||||||
:height="progressStyle.height"
|
|
||||||
type="line"
|
|
||||||
:percentage="item.usedPercent"
|
|
||||||
:show-indicator="false"
|
|
||||||
:stroke-width="15"
|
|
||||||
style="width: 150px;"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Edit v-model:visible="editShowStatus" :monitor-data="editData" :index="editIndex" @done="handleSaveDone" />
|
||||||
|
|
||||||
|
<NDropdown
|
||||||
|
placement="bottom-start" trigger="manual" :x="dropdownMenuX" :y="dropdownMenuY"
|
||||||
|
:options="getDropdownMenuOptions()" :show="dropdownShow" :on-clickoutside="onClickoutside" @select="handleRightMenuSelect"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.icon-info-box {
|
||||||
|
width: 100%;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||||
|
gap: 18px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-small-box {
|
||||||
|
width: 100%;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(75px, 1fr));
|
||||||
|
gap: 18px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 500px) {
|
||||||
|
.icon-info-box{
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
33
src/components/deskModule/SystemMonitor/typings.ts
Normal file
33
src/components/deskModule/SystemMonitor/typings.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
export enum MonitorType {
|
||||||
|
'cpu' = 'cpu', // 图标风格
|
||||||
|
'memory' = 'memory', // 详情风格
|
||||||
|
'disk' = 'disk',
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CardStyle {
|
||||||
|
background: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MonitorData {
|
||||||
|
monitorType: MonitorType
|
||||||
|
extendParam?: { [key: string]: [value:any] } | any
|
||||||
|
description?: string
|
||||||
|
// cardStyle: CardStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProgressStyle {
|
||||||
|
color: string
|
||||||
|
railColor: string
|
||||||
|
height: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GenericProgressStyleExtendParam {
|
||||||
|
progressColor: string
|
||||||
|
progressRailColor: string
|
||||||
|
color: string
|
||||||
|
backgroundColor: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DiskExtendParam extends GenericProgressStyleExtendParam {
|
||||||
|
path: string
|
||||||
|
}
|
@ -40,6 +40,7 @@ export default {
|
|||||||
regularUser: '普通',
|
regularUser: '普通',
|
||||||
admin: '管理',
|
admin: '管理',
|
||||||
},
|
},
|
||||||
|
leastOne: '请至少保留一项',
|
||||||
},
|
},
|
||||||
setting: {
|
setting: {
|
||||||
setting: '设置',
|
setting: '设置',
|
||||||
|
@ -33,10 +33,10 @@ export const useModuleConfig = defineStore('module-config-store', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 保存到网络
|
// 保存到网络
|
||||||
saveToCloud(name: string, value: any) {
|
async saveToCloud(name: string, value: any) {
|
||||||
const moduleName = `module-${name}`
|
const moduleName = `module-${name}`
|
||||||
// 保存至网络
|
// 保存至网络
|
||||||
save(moduleName, value)
|
return save(moduleName, value)
|
||||||
},
|
},
|
||||||
|
|
||||||
// 从网络同步
|
// 从网络同步
|
||||||
|
6
src/typings/systemMonitor.d.ts
vendored
6
src/typings/systemMonitor.d.ts
vendored
@ -34,4 +34,10 @@ declare namespace SystemMonitor {
|
|||||||
netIOCountersInfo: NetIOCountersInfo[]
|
netIOCountersInfo: NetIOCountersInfo[]
|
||||||
memoryInfo: MemoryInfo
|
memoryInfo: MemoryInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Mountpoint{
|
||||||
|
device:string
|
||||||
|
mountpoint:string
|
||||||
|
fstype:string
|
||||||
|
}
|
||||||
}
|
}
|
10
src/utils/defaultData/index.ts
Normal file
10
src/utils/defaultData/index.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export const defautSwatchesBackground = [
|
||||||
|
'#00000000',
|
||||||
|
'#000000',
|
||||||
|
'#ffffff',
|
||||||
|
'#18A058',
|
||||||
|
'#2080F0',
|
||||||
|
'#F0A020',
|
||||||
|
'rgba(208, 48, 80, 1)',
|
||||||
|
'#C418D1FF',
|
||||||
|
]
|
0
src/views/exception/test/zujian.vue
Normal file
0
src/views/exception/test/zujian.vue
Normal file
@ -41,6 +41,7 @@ const itemIconInfo = computed({
|
|||||||
return v
|
return v
|
||||||
},
|
},
|
||||||
set() {
|
set() {
|
||||||
|
console.log('aaaa')
|
||||||
handleChange()
|
handleChange()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -52,6 +53,7 @@ function handleIconTypeRadioChange(type: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleChange() {
|
function handleChange() {
|
||||||
|
console.log('21222')
|
||||||
emit('update:itemIcon', itemIconInfo.value || null)
|
emit('update:itemIcon', itemIconInfo.value || null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,9 +333,6 @@ function handleAddItem(itemIconGroupId?: number) {
|
|||||||
/>
|
/>
|
||||||
<div class="mask" :style="{ backgroundColor: `rgba(0,0,0,${panelState.panelConfig.backgroundMaskNumber})` }" />
|
<div class="mask" :style="{ backgroundColor: `rgba(0,0,0,${panelState.panelConfig.backgroundMaskNumber})` }" />
|
||||||
<div ref="scrollContainerRef" class="absolute w-full h-full overflow-auto">
|
<div ref="scrollContainerRef" class="absolute w-full h-full overflow-auto">
|
||||||
<div v-if="panelState.panelConfig.searchBoxShow" class="flex mx-auto ">
|
|
||||||
<SystemMonitor @itemSearch="itemFrontEndSearch" />
|
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
class="p-2.5 mx-auto"
|
class="p-2.5 mx-auto"
|
||||||
:style="{
|
:style="{
|
||||||
@ -365,10 +362,11 @@ function handleAddItem(itemIconGroupId?: number) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 应用盒子 -->
|
<!-- 应用盒子 -->
|
||||||
<div class="mt-[50px]" :style="{ marginLeft: `${panelState.panelConfig.marginX}px`, marginRight: `${panelState.panelConfig.marginX}px` }">
|
<div :style="{ marginLeft: `${panelState.panelConfig.marginX}px`, marginRight: `${panelState.panelConfig.marginX}px` }">
|
||||||
<!-- <div v-if="panelState.panelConfig.searchBoxShow" class="flex mt-[20px] mx-auto ">
|
<!-- 系统状态 -->
|
||||||
<SystemMonitor @itemSearch="itemFrontEndSearch" />
|
<div v-if="panelState.panelConfig.searchBoxShow" class="flex mx-auto ">
|
||||||
</div> -->
|
<SystemMonitor allow-edit />
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 组纵向排列 -->
|
<!-- 组纵向排列 -->
|
||||||
<div
|
<div
|
||||||
@ -437,7 +435,7 @@ function handleAddItem(itemIconGroupId?: number) {
|
|||||||
<div v-if="panelState.panelConfig.iconStyle === PanelPanelConfigStyleEnum.icon">
|
<div v-if="panelState.panelConfig.iconStyle === PanelPanelConfigStyleEnum.icon">
|
||||||
<div v-if="itemGroup.items">
|
<div v-if="itemGroup.items">
|
||||||
<VueDraggable
|
<VueDraggable
|
||||||
v-model="itemGroup.items" item-key="id" :animation="300"
|
v-model="itemGroup.items" item-key="sort" :animation="300"
|
||||||
class="icon-small-box"
|
class="icon-small-box"
|
||||||
|
|
||||||
filter=".not-drag"
|
filter=".not-drag"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user