完成预览卡片数据加载实时更新

This commit is contained in:
柏码の讲师 2023-12-12 16:46:17 +08:00
parent 7ec7d5c336
commit 265e659f65
10 changed files with 124 additions and 24 deletions

View File

@ -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());
}
}

View File

@ -2,6 +2,7 @@ package com.example.entity.dto;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.example.entity.BaseData;
import lombok.AllArgsConstructor;
import lombok.Data;
@ -10,7 +11,7 @@ import java.util.Date;
@Data
@TableName("db_client")
@AllArgsConstructor
public class Client {
public class Client implements BaseData {
@TableId
Integer id;
String name;

View File

@ -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;
}

View File

@ -29,7 +29,7 @@ public class RequestLogFilter extends OncePerRequestFilter {
@Resource
SnowflakeIdGenerator generator;
private final Set<String> ignores = Set.of("/swagger-ui", "/v3/api-docs", "/monitor/runtime");
private final Set<String> ignores = Set.of("/swagger-ui", "/v3/api-docs", "/monitor/runtime", "/api/monitor/list");
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

View File

@ -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();
}

View File

@ -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;
@ -15,10 +16,7 @@ import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.security.SecureRandom;
import java.util.Date;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@Service
@ -89,6 +87,20 @@ public class ClientServiceImpl extends ServiceImpl<ClientMapper, Client> impleme
influx.writeRuntimeData(client.getId(), vo);
}
@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 = currentRuntime.get(client.getId());
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);

View File

@ -22,6 +22,6 @@ 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";
}

View File

@ -1,5 +1,9 @@
<script setup>
import {fitByUnit} from '@/tools'
const props = defineProps({
data: Object
})
</script>
<template>
@ -7,46 +11,55 @@
<div style="display: flex;justify-content: space-between">
<div>
<div class="name">
<span class="flag-icon flag-icon-cn"></span>
<span style="margin: 0 5px">白马后端云服务器</span>
<span :class="`flag-icon flag-icon-${data.location}`"></span>
<span style="margin: 0 5px">{{ 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.11</span>
<span style="margin-right: 10px">公网IP: {{data.ip}}</span>
<i class="fa-solid fa-copy" style="color: dodgerblue"></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.toFixed(1)} GB`}}</span>
</div>
<div class="progress">
<span>CPU: 2.5%</span>
<el-progress status="success" :percentage="2.5" :stroke-width="5" :show-text="false"/>
<span>{{`CPU: ${(data.cpuUsage * 100).toFixed(1)}%`}}</span>
<el-progress status="success"
:percentage="data.cpuUsage * 100" :stroke-width="5" :show-text="false"/>
</div>
<div class="progress">
<span>内存: <b>1.2</b> GB</span>
<el-progress status="success" :percentage="1.2/4 * 100" :stroke-width="5" :show-text="false"/>
<span>内存: <b>{{data.memoryUsage.toFixed(1)}}</b> GB</span>
<el-progress status="success"
:percentage="data.memoryUsage/data.memory * 100" :stroke-width="5" :show-text="false"/>
</div>
<div class="network-flow">
<div>网络流量</div>
<div>
<i class="fa-solid fa-arrow-up"></i>
<span> 52 KB/s</span>
<span>{{` ${fitByUnit(data.networkUpload, 'KB')}/s`}}</span>
<el-divider direction="vertical"/>
<i class="fa-solid fa-arrow-down"></i>
<span> 256 KB/s</span>
<span>{{` ${fitByUnit(data.networkDownload, 'KB')}/s`}}</span>
</div>
</div>
</div>
@ -99,6 +112,10 @@
font-size: 12px;
}
.cpu {
font-size: 13px;
}
.network-flow {
margin-top: 10px;
font-size: 12px;

View File

@ -0,0 +1,16 @@
function fitByUnit(value, unit) {
const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
let index = units.indexOf(unit)
while (((value < 1 && value !== 0) || value >= 1024) && (index >= 0 || index < units.length)) {
if(value >= 1024) {
value = value / 1024
index = index + 1
} else {
value = value * 1024
index = index - 1
}
}
return `${parseInt(value)} ${units[index]}`
}
export { fitByUnit }

View File

@ -1,6 +1,13 @@
<script setup>
import PreviewCard from "@/component/PreviewCard.vue";
import {ref} from "vue";
import {get} from "@/net";
const list = ref([])
const updateList = () => get('/api/monitor/list', data => list.value = data)
setInterval(updateList, 10000)
updateList()
</script>
<template>
@ -9,9 +16,7 @@ import PreviewCard from "@/component/PreviewCard.vue";
<div class="desc">在这里管理所有已经注册的主机实例实时监控主机运行状态快速进行管理和操作</div>
<el-divider style="margin: 10px 0"/>
<div class="card-list">
<preview-card/>
<preview-card/>
<preview-card/>
<preview-card v-for="item in list" :data="item"/>
</div>
</div>
</template>