完成预览卡片列表加载以及数据定时刷新
This commit is contained in:
parent
70c94f9fc5
commit
42b6c9370d
@ -0,0 +1,24 @@
|
||||
package com.example.controller;
|
||||
|
||||
import com.example.entity.RestBean;
|
||||
import com.example.entity.vo.response.ClientPreviewVO;
|
||||
import com.example.service.ClientService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/monitor")
|
||||
public class MonitorController {
|
||||
|
||||
@Resource
|
||||
ClientService service;
|
||||
|
||||
@GetMapping("/list")
|
||||
public RestBean<List<ClientPreviewVO>> listAllClient() {
|
||||
return RestBean.success(service.listClients());
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.example.entity.vo.response;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ClientPreviewVO {
|
||||
int id;
|
||||
boolean online;
|
||||
String name;
|
||||
String location;
|
||||
String osName;
|
||||
String osVersion;
|
||||
String ip;
|
||||
String cpuName;
|
||||
int cpuCore;
|
||||
double memory;
|
||||
double cpuUsage;
|
||||
double memoryUsage;
|
||||
double networkUpload;
|
||||
double networkDownload;
|
||||
}
|
@ -4,6 +4,9 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.example.entity.dto.Client;
|
||||
import com.example.entity.vo.request.ClientDetailVO;
|
||||
import com.example.entity.vo.request.RuntimeDetailVO;
|
||||
import com.example.entity.vo.response.ClientPreviewVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ClientService extends IService<Client> {
|
||||
String registerToken();
|
||||
@ -12,4 +15,5 @@ public interface ClientService extends IService<Client> {
|
||||
boolean verifyAndRegister(String token);
|
||||
void updateClientDetail(ClientDetailVO vo, Client client);
|
||||
void updateRuntimeDetail(RuntimeDetailVO vo, Client client);
|
||||
List<ClientPreviewVO> listClients();
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import com.example.entity.dto.Client;
|
||||
import com.example.entity.dto.ClientDetail;
|
||||
import com.example.entity.vo.request.ClientDetailVO;
|
||||
import com.example.entity.vo.request.RuntimeDetailVO;
|
||||
import com.example.entity.vo.response.ClientPreviewVO;
|
||||
import com.example.mapper.ClientDetailMapper;
|
||||
import com.example.mapper.ClientMapper;
|
||||
import com.example.service.ClientService;
|
||||
@ -89,6 +90,20 @@ public class ClientServiceImpl extends ServiceImpl<ClientMapper, Client> impleme
|
||||
influx.writeRuntimeData(client.getId(), oldData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ClientPreviewVO> listClients() {
|
||||
return clientIdCache.values().stream().map(client -> {
|
||||
ClientPreviewVO vo = client.asViewObject(ClientPreviewVO.class);
|
||||
BeanUtils.copyProperties(detailMapper.selectById(vo.getId()), vo);
|
||||
RuntimeDetailVO runtime = lastRuntime.get(client);
|
||||
if(runtime != null && System.currentTimeMillis() - runtime.getTimestamp() < 60 * 1000) {
|
||||
BeanUtils.copyProperties(runtime, vo);
|
||||
vo.setOnline(true);
|
||||
}
|
||||
return vo;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
private void addClientCache(Client client) {
|
||||
clientIdCache.put(client.getId(), client);
|
||||
clientTokenCache.put(client.getToken(), client);
|
||||
|
@ -22,6 +22,5 @@ public final class Const {
|
||||
//消息队列
|
||||
public final static String MQ_MAIL = "mail";
|
||||
//用户角色
|
||||
public final static String ROLE_DEFAULT = "user";
|
||||
|
||||
public final static String ROLE_DEFAULT = "admin";
|
||||
}
|
||||
|
@ -1,5 +1,16 @@
|
||||
<script setup>
|
||||
import {fitToRightByteUnit} from "@/tools";
|
||||
import {useClipboard} from "@vueuse/core";
|
||||
import {ElMessage} from "element-plus";
|
||||
|
||||
const props = defineProps({
|
||||
data: Object
|
||||
})
|
||||
|
||||
const { copy } = useClipboard()
|
||||
const copyIp = () => {
|
||||
copy(props.data.ip).then(() => ElMessage.success('成功复制IP地址到剪贴板'))
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -7,60 +18,77 @@
|
||||
<div style="display: flex;justify-content: space-between">
|
||||
<div>
|
||||
<div class="title">
|
||||
<span class="flag-icon flag-icon-cn"></span>
|
||||
<span style="margin: 0 10px">柏码后端云服务器</span>
|
||||
<span :class="`flag-icon flag-icon-${data.location}`"></span>
|
||||
<span style="margin: 0 10px">{{ data.name }}</span>
|
||||
<i class="fa-solid fa-pen-to-square"></i>
|
||||
</div>
|
||||
<div class="os">
|
||||
操作系统: Ubuntu 20.04
|
||||
操作系统: {{`${data.osName} ${data.osVersion}`}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="status">
|
||||
<div class="status" v-if="data.online">
|
||||
<i style="color: #18cb18" class="fa-solid fa-circle-play"></i>
|
||||
<span style="margin-left: 5px">运行中</span>
|
||||
</div>
|
||||
<div class="status" v-else>
|
||||
<i style="color: #8a8a8a" class="fa-solid fa-circle-stop"></i>
|
||||
<span style="margin-left: 5px">离线</span>
|
||||
</div>
|
||||
</div>
|
||||
<el-divider style="margin: 10px 0"/>
|
||||
<div class="network">
|
||||
<span style="margin-right: 10px">公网IP: 192.168.0.10</span>
|
||||
<i style="color: dodgerblue" class="fa-solid fa-copy"></i>
|
||||
<span style="margin-right: 10px">公网IP: {{data.ip}}</span>
|
||||
<i class="fa-solid fa-copy copy-item" @click="copyIp"></i>
|
||||
</div>
|
||||
<div class="cpu">
|
||||
<span style="margin-right: 10px">处理器: {{data.cpuName}}</span>
|
||||
</div>
|
||||
<div class="hardware">
|
||||
<i class="fa-solid fa-microchip"></i>
|
||||
<span style="margin-right: 10px"> 2 CPU</span>
|
||||
<span style="margin-right: 10px">{{` ${data.cpuCore} CPU`}}</span>
|
||||
<i class="fa-solid fa-memory"></i>
|
||||
<span> 4 GB</span>
|
||||
<span>{{` ${data.memory} GB`}}</span>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<span>CPU: 2.5 %</span>
|
||||
<el-progress :percentage="2.5" :stroke-width="5" :show-text="false"/>
|
||||
<span>{{ `CPU: ${(data.cpuUsage * 100).toFixed(1)} %` }}</span>
|
||||
<el-progress :percentage="data.cpuUsage * 100" :stroke-width="5" :show-text="false"
|
||||
:status="data.cpuUsage * 100 > 80 ? 'exception' : 'success'"/>
|
||||
</div>
|
||||
<div class="progress" style="margin-top: 7px">
|
||||
<span>内存: <b>1.2</b> GB</span>
|
||||
<el-progress :percentage="1.2/4 * 100" :stroke-width="5" :show-text="false"/>
|
||||
<span>内存: <b>{{ data.memoryUsage.toFixed(1) }}</b> GB</span>
|
||||
<el-progress :percentage="data.memoryUsage/data.memory * 100" :stroke-width="5" :show-text="false"
|
||||
:status="data.memoryUsage/data.memory * 100 > 80 ? 'exception' : 'success'"/>
|
||||
</div>
|
||||
<div class="network-flow">
|
||||
<div>网络流量</div>
|
||||
<div>
|
||||
<i class="fa-solid fa-arrow-up"></i>
|
||||
<span> 52 KB/s</span>
|
||||
<span>{{` ${fitToRightByteUnit(data.networkUpload, 'KB')}/s`}}</span>
|
||||
<el-divider direction="vertical"/>
|
||||
<i class="fa-solid fa-arrow-down"></i>
|
||||
<span> 272 KB/s</span>
|
||||
<span>{{` ${fitToRightByteUnit(data.networkDownload, 'KB')}/s`}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
:deep(.el-progress-bar__outer) {
|
||||
:deep(.is-success .el-progress-bar__outer) {
|
||||
background-color: #18cb1822;
|
||||
}
|
||||
|
||||
:deep(.el-progress-bar__inner) {
|
||||
:deep(.is-exception .el-progress-bar__outer) {
|
||||
background-color: #ef4e4e22;
|
||||
}
|
||||
|
||||
:deep(.is-success .el-progress-bar__inner) {
|
||||
background-color: #18cb18;
|
||||
}
|
||||
|
||||
:deep(.is-exception .el-progress-bar__inner) {
|
||||
background-color: #ef4e4e;
|
||||
}
|
||||
|
||||
.dark .instance-card { color: #d9d9d9
|
||||
}
|
||||
.instance-card {
|
||||
@ -71,6 +99,17 @@
|
||||
box-sizing: border-box;
|
||||
color: #6b6b6b;
|
||||
|
||||
.copy-item {
|
||||
color: dodgerblue;
|
||||
transition: .3s;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
scale: 1.1;
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
.os {
|
||||
font-size: 13px;
|
||||
color: grey;
|
||||
@ -89,6 +128,10 @@
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.cpu {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.hardware {
|
||||
margin-top: 5px;
|
||||
font-size: 13px;
|
||||
|
16
itbaima-monitor-web/src/tools/index.js
Normal file
16
itbaima-monitor-web/src/tools/index.js
Normal file
@ -0,0 +1,16 @@
|
||||
function fitToRightByteUnit(value, unit) {
|
||||
const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
|
||||
let index = units.indexOf(unit)
|
||||
while ((value < 0 || value >= 1024) && (index >= 0 || index < units.length)) {
|
||||
if(value < 0) {
|
||||
value = value * 1024
|
||||
index = index - 1
|
||||
} else {
|
||||
value = value / 1024
|
||||
index = index + 1
|
||||
}
|
||||
}
|
||||
return `${parseInt(value)} ${units[index]}`
|
||||
}
|
||||
|
||||
export { fitToRightByteUnit }
|
@ -1,6 +1,13 @@
|
||||
<script setup>
|
||||
|
||||
import PreviewCard from "@/component/PreviewCard.vue";
|
||||
import {get} from "@/net";
|
||||
import {ref} from "vue";
|
||||
|
||||
const list = ref([])
|
||||
|
||||
const updateList = () => get('/api/monitor/list', data => list.value = data)
|
||||
setInterval(updateList, 10000)
|
||||
updateList()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -9,12 +16,7 @@ import PreviewCard from "@/component/PreviewCard.vue";
|
||||
<div class="description">在这里管理所有已经注册的主机实例,实时监控主机运行状态,快速进行管理和操作。</div>
|
||||
<el-divider style="margin: 10px 0"/>
|
||||
<div class="card-list">
|
||||
<preview-card/>
|
||||
<preview-card/>
|
||||
<preview-card/>
|
||||
<preview-card/>
|
||||
<preview-card/>
|
||||
<preview-card/>
|
||||
<preview-card :data="item" v-for="item in list"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
Loading…
x
Reference in New Issue
Block a user