本文主要介紹SignalR在實際項目中的應用,以及.NET Framework和.NET Core中如何去使用SignalR。SignalR是一個開放源代碼庫,可用於簡化嚮應用添加實時Web功能,實時Web功能使伺服器端代碼能夠將內容推送到客戶端。 ...
官網文檔:https://learn.microsoft.com/zh-cn/aspnet/core/tutorials/signalr?view=aspnetcore-6.0&tabs=visual-studio
SignalR開源代碼:https://github.com/signalr
很多小伙伴問:在前後端分離項目中,後端是.NET Core前端是Vue如何使用SignalR?在前後端不分離項目中,.NET Framework MVC項目中又如何使用SignalR技術呢?那就來看看下麵這篇文章吧!本文主要介紹SignalR在實際項目中的應用,以及.NET Framework和.NET Core中如何去使用SignalR。
一、SignalR介紹
1.1-SignalR介紹
ASP.NET Core SignalR是一個開放源代碼庫,可用於簡化嚮應用添加實時Web功能,實時Web功能使伺服器端代碼能夠將內容推送到客戶端。
1.2-SignalR的應用
- 需要從伺服器進行高頻更新的應用:包括游戲、社交網路、投票、拍賣、地圖和GPS引用。
- 儀錶盤和監視應用:包括公司儀錶板、即時銷售更新或旅行報警
- 協作應用:包括白板應用和團隊會議軟體。
- 通知應用:社交網路、電子郵件、聊天、游戲、旅行報警和其他應用都需要使用的通知。
二、.NET Framework使用SignalR
參考文獻:
Owin介紹:https://www.cnblogs.com/Pinapple/p/6721361.html
Owin相關案例:https://blog.csdn.net/bifan546/article/details/77098896/
2.1-服務端(.NET Framework MVC)
(1)選擇要使用Signalr的項目,點擊【管理NuGet程式包】。
(2)搜索【SignalR】包,找到這個後然後點擊下載。
會自動安裝四個,註意他們之間有依賴關係:
(3).NET Framework平臺需要添加Owin相關的包。
OWIN 是一種定義 Web 伺服器和應用程式組件之間的交互的規範 。這一規範的目的是發展一個廣闊且充滿活力的、基於 Microsoft .NET Framework 的 Web 伺服器和應用程式組件生態系統。
Microsoft.Owin.Hosting
Microsoft.Owin.Cors
Microsoft.Owin.Host.HttpListener
(4)在Web項目(要使用的Signal)中創建一個【Startup.cs】文件。
using JiCai.Admin.Hubs;
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(JiCai.Admin.Startup))]
namespace JiCai.Admin
{
public class Startup
{
/// <summary>
/// 應用程式配置
/// </summary>
/// <param name="app"></param>
public void Configuration(IAppBuilder app)
{
//啟用SignalR
app.MapSignalR();
//綁定多個Hub
app.MapSignalR<DemoHub>("/demoHub");
}
}
}
例如:
(5)可以創建一個【Hubs】文件夾,專門放置Hub相關文件。[西瓜程式猿]這邊是創建一個Hub文件,名為【DemoHub.cs】。
using Fenqibao.DTO;
using JiCai.Admin.Hubs.ConectionOperate;
using JiCai.Admin.Hubs.Models;
using log4net;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Json;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace JiCai.Admin.Hubs
{
/// <summary>
/// 報表管理-總表Hub
/// </summary>
public class SummaryTableHub : PersistentConnection
{
public readonly BaseService _base = new BaseService();
private readonly ILog logger = LogManager.GetLogger(typeof(SummaryTableHub));
private ConnectionManagement summaryTableCon = new ConnectionManagement();
public CookieUserData LoginUserData
{
get
{
IOperator oper = ContainerManager.Resolve<IOperator>();
LoginUser loginUser = oper as LoginUser;
if (loginUser != null && loginUser.UserData != null)
{
return loginUser.UserData;
}
return null;
}
}
/// <summary>
/// 連接成功後調用
/// </summary>
/// <param name="request"></param>
/// <param name="connectionId"></param>
/// <returns></returns>
protected override Task OnConnected(IRequest request, string connectionId)
{
//獲得SignalR的連接id
var connid = connectionId;
//獲得用戶id
var userid = LoginUserData.Id.ToString();
Console.Write($"【{connid}】:已建立連接!");
//判斷一下用戶是不是已經鏈接了
var checkUserConn = summaryTableCon.IsConn(connid, userid);
if (!checkUserConn)
{
//添加一個新的連接
summaryTableCon.AddConnInfo(new SignalRConn()
{
UserId = userid,
ConnectionId = connid
});
}
//更新連接
else
{
summaryTableCon.UpdateConnInfo(userid, connid);
}
return Connection.Send(connectionId, $"【用戶:{connectionId}】真正連接成功!");
//return base.OnConnected(request, connectionId);
}
/// <summary>
/// 接收到請求的時候調用
/// </summary>
/// <param name="request"></param>
/// <param name="connectionId"></param>
/// <param name="data"></param>
/// <returns></returns>
protected override async Task OnReceived(IRequest request, string connectionId, string data)
{
//獲得用戶id
var userid = LoginUserData.Id.ToString();
await Task.Factory.StartNew(async () =>
{
while (true)
{
var list = GetSummaryTableList(userid);
string json_jieshou_mes = "";
if (list != null && list.Count > 0)
{
json_jieshou_mes = JsonConvert.SerializeObject(list);
}
await Connection.Send(connectionId, json_jieshou_mes);
//每5秒同步一次
await Task.Delay(5000);
}
}, TaskCreationOptions.LongRunning);
//return base.OnReceived(request, connectionId, data);
}
/// <summary>
/// 連接中斷的時候調用
/// </summary>
/// <param name="request"></param>
/// <param name="connectionId"></param>
/// <param name="stopCalled"></param>
/// <returns></returns>
protected override Task OnDisconnected(IRequest request, string connectionId, bool stopCalled)
{
Console.Write($"【{connectionId}】:已斷開連接!");
//獲得SignalR的連接id
var connid = connectionId;
//關閉連接
summaryTableCon.DelConnInfo(connid);
return base.OnDisconnected(request, connectionId, stopCalled);
}
/// <summary>
/// 連接超時重新連接的時候調用
/// </summary>
/// <param name="request"></param>
/// <param name="connectionId"></param>
/// <returns></returns>
protected override Task OnReconnected(IRequest request, string connectionId)
{
return base.OnReconnected(request, connectionId);
}
/// <summary>
/// 查詢數據
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
private List<SummaryTableDataModel> GetSummaryTableList(string userId)
{
var result = _base.Query<SummaryTableDataModel>($@"
select * from demo-data
;
").ToList();
return result;
}
}
}
(6)在Hubs/ConectionOperate文件夾中,[西瓜程式猿]這邊創建【ConnectionManagement】文件,用來管理所有連接。
using System.Collections.Generic;
using System.Linq;
namespace JiCai.Admin.Hubs.ConectionOperate
{
/// <summary>
/// 連接管理
/// </summary>
public class ConnectionManagement
{
/// <summary>
/// 用戶連接集合
/// </summary>
public static List<SignalRConn> SignalRConns { get; set; } = new List<SignalRConn>();
/// <summary>
/// 添加連接
/// </summary>
/// <param name="conn"></param>
public void AddConnInfo(SignalRConn conn)
{
SignalRConns.Add(conn);
}
/// <summary>
/// 刪除連接
/// </summary>
/// <param name="connid"></param>
public void DelConnInfo(string connid)
{
var signalRConns = SignalRConns.FirstOrDefault(u => u.ConnectionId == connid);
if (signalRConns != null)
{
SignalRConns.Remove(signalRConns);
}
}
/// <summary>
/// 更新鏈接(老的鏈接不起作用了)
/// 場景:客戶端重連了,userid沒變,但是connid變了
/// </summary>
/// <param name="userId">用戶id</param>
/// <param name="newConnsId">新的鏈接id</param>
public void UpdateConnInfo(string userId, string newConnsId)
{
var signalRConns = SignalRConns.FirstOrDefault(u => u.UserId.ToLower() == userId.ToLower());
if (signalRConns != null)
{
signalRConns.ConnectionId = newConnsId;
}
}
/// <summary>
/// 判斷用戶是否已經鏈接
/// </summary>
/// <param name="connid">連接id</param>
/// <param name="userid">用戶id</param>
/// <returns></returns>
public bool IsConn(string connid,string userid)
{
var userConn = SignalRConns.FirstOrDefault(u => u.ConnectionId.ToLower() == connid.ToLower() && u.UserId.ToLower() == userid.ToLower());
return userConn == null ? false : true;
}
}
}
(7)在Hubs/ConectionOperate文件夾中,創建【SignalRConn.cs】文件用來作為SignalR和系統用戶的連接實體。
namespace JiCai.Admin.Hubs.ConectionOperate
{
/// <summary>
/// 連接
/// </summary>
public class SignalRConn
{
/// <summary>
/// 系統用戶id
/// </summary>
public string UserId { get; set; }
/// <summary>
/// SignleR鏈接Id(每次鏈接SignalR都會分配一個id)
/// </summary>
public string ConnectionId { get; set; }
}
}
2.2-客戶端(JS)
(1)下載相關jq/signalr相關包,分別是【jquery.signalR-2.4.3.js】和【jquery-1.6.4.min.js】。可以訪問下載(如果失效了,請聯繫我[西瓜程式猿])。
下載地址(編碼:yRLCRp81):https://yongteng.lanzoub.com/iXDlu1631ugd
密碼:44x5
文件截圖:
(2)創建一個js文件【data_list_table_hub.js】,用來連接signalR。
// 連接服務
var connection = $.connection("/summary_table_hub");
// 建立鏈接
connection.start(function () {
//連接成功
console.log("西瓜程式猿-【" + new Date().toLocaleString() +"】連接成功!");
//發送消息
connection.send("給我數據吧");
});
// 連接斷開
connection.disconnected(function () {
console.log("西瓜程式猿-【" + new Date().toLocaleString() +"】連接斷開!");
});
// 接收伺服器發來的消息
connection.received(function (data) {
console.log("西瓜程式猿-【" + new Date().toLocaleString() +"】接收伺服器發來的消息:");
console.log(data);
//顯示數據
if (data != "" && checkJson(data)) {
var obj = JSON.parse(data);
var html_box = "";
for (var i = 0; i < obj.length; i++) {
html_box += `<tr>
<td>`+obj[i].project_name+`</td>
<td>`+ obj[i].zuori_sum+`</td>
<td>`+ obj[i].jinri_sum+`</td>
<td>`+ obj[i].qunian_sum+`</td>
<td>`+ obj[i].jinnian_sum+`</td>
<td>`+ obj[i].sum+`</td>
<td>`+ obj[i].yikaipiao_sum+`</td>
<td>`+ obj[i].weikaipiao_sum +`</td>
<td>`+ obj[i].yishoupiao_sum +`</td>
<td>`+ obj[i].weishoupiao_sum +`</td>
<td>`+ obj[i].kehu_yinghuikuan_sum+`</td>
<td>`+ obj[i].kehu_yihuikuan_sum+`</td>
<td>`+ obj[i].kehu_weihuikuan_sum +`</td>
<td>`+ obj[i].fuwu_yingfukuan_sum+`</td>
<td>`+ obj[i].fuwu_yifukuan_sum+`</td>
<td>`+ obj[i].fuwu_weifukuan_sum+`</td>
</tr>`
}
$("#last_async_date").text(new Date().toLocaleString());
$("#table_body").html(html_box);
}
});
//判斷是不是json字元串
function checkJson(str) {
if (typeof str == 'string') {
try {
var obj = JSON.parse(str);
// 等於這個條件說明就是JSON字元串 會返回true
if (typeof obj == 'object' && obj) {
return true;
} else {
//不是就返回false
return false;
}
} catch (e) {
return false;
}
}
return false;
}
(3)創建要展示的文件,我這邊是用MVC模式,所有前臺文件是cshtml。
@{
ViewBag.Title = "西瓜程式猿-明細表";
}
@section styles{
<style>
.table_tr_center {
text-align: center !important;
}
.table_tr_bg_0 {
background: rgb(253,226,226);
}
.table_tr_bg_1 {
background: rgb(218,226,246);
}
.table_tr_bg_2 {
background: rgb(228,237,219);
}
.table_tr_bg_3 {
background: rgb(249,229,215);
}
</style>
}
@section scripts{
<script src="~/Scripts/jquery-1.6.4.min.js"></script>
<script src="~/Scripts/jquery.signalR-2.4.3.js"></script>
<script src="~/Scripts/controller/hubs/[email protected]"></script>
}
<div class="row">
<div class="col-xs-12">
</div>
<div class="col-xs-12">
<div>
報表最新同步時間:<span id="last_async_date" style="color: #FF5722 !important;"></span>
</div>
<div class="layui-form">
<table class="layui-table">
<colgroup>
<col>
<col>
<col>
<col>
<col>
<col>
<col>
<col>
<col>
<col>
<col>
<col>
<col>
</colgroup>
<thead>
<tr>
<th colspan="2" class="table_tr_center table_tr_bg_0">項目信息</th>
<th colspan="5" class="table_tr_center table_tr_bg_1">銷售情況</th>
<th colspan="6" class="table_tr_center table_tr_bg_3">款項情況</th>
</tr>
<tr>
<th class="table_tr_center">項目名稱</th>
<th class="table_tr_center">服務商名稱</th>
<th class="table_tr_center">昨天訂單總額</th>
<th class="table_tr_center">今天訂單總額</th>
<th class="table_tr_center">去年訂單總額</th>
<th class="table_tr_center">今年訂單總額</th>
<th class="table_tr_center">訂單總額</th>
<th class="table_tr_center">客戶應回款總額</th>
<th class="table_tr_center">客戶已回款總額</th>
<th class="table_tr_center">客戶未回款總額</th>
<th class="table_tr_center">服務商應付款總額</th>
<th class="table_tr_center">服務商已付款總額</th>
<th class="table_tr_center">服務商未付款總額</th>
</tr>
</thead>
<tbody id="table_body">
</tbody>
</table>
</div>
</div>
</div>
(4)效果展示:
三、.NET Core WebAPI使用SignalR
場景:項目中需要服務端主動向客戶端發送通知消息,後端是使用.NETCore實現的,前端是使用Vue3全家桶項目,前後端分離模式。本次主要講使用SignalR如何來實現的。
3.1-服務端(.NET Core WebAPI)
1、右擊項目,點擊【管理NuGet程式包】安裝SignalR。
2、搜索【SignalR】,點擊【安裝】。
3、如果是.NET6以前的版本,在【Startup.cs】中配置:
如果是.NET6以後得版本,在【Program.cs】配置:
var builder = WebApplication.CreateBuilder(args);
//添加SignalR服務
builder.Services.AddSignalR();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}"
);
//添加SignalR端點
endpoints.MapHub<ServerMonitorHub>("/serverMonitorHub");
});
4、創建SignalR中心
中心是一個類,用於處理客戶端<——>伺服器通信的高級管道。在SignalR_Demo項目文件夾中,創建Hubs文件夾。在Hubs文件夾中,使用已下代碼創建ChatHub類。
public class ChatHub:Hub
{
/// <summary>
/// 發送消息
/// </summary>
/// <param name="user">用戶名</param>
/// <param name="message">發送信息</param>
/// <returns></returns>
public async Task SendMessage(string user,string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
3.2-客戶端(Vue3+Vite+TS)
(1)安裝SugbalR
npm install @latelier/vue-signalr
版本截圖:
(2)然後新建一個文件,用來封裝業務邏輯相關代碼。[西瓜程式猿]是在【src/utils】目錄下,創建了一個名為【signalr.ts】的文件,也可以是js文件,根據自己項目的需要去新建。
代碼:
import * as signalR from '@microsoft/signalr';
//如果需要身份驗證
//.withUrl('/messageHub', {accessTokenFactory: () => sessionStorage.getItem('token')})
let connection;
// 建立連接
async function start(url) {
try {
connection = new signalR.HubConnectionBuilder()
.withUrl(url)//跨域需要使用絕對地址
.configureLogging(signalR.LogLevel.Information)
.withAutomaticReconnect() // 設置自動重連機制
.build();
} catch(err) {
console.log(err);
setTimeout(start, 10000);//錯誤重連
}
}
// 開始signalr連接
const connect = async (url) => {
await start(url);
console.log(`【西瓜程式猿-${new Date().toLocaleString()}:SignalR已連接成功!`);
};
// 調用服務端方法
async function send(methodName, param){
try {
await connection.invoke(methodName, param);
} catch (err) {
console.error(err);
}
}
//斷開連接
const disconnect = async ()=>{
await connection.stop();
console.log(`【西瓜程式猿-${new Date().toLocaleString()}:SignalR已斷開連接!`);
};
export {
connection,
connect,
send,
disconnect
};
(3)然後再頁面進行使用。[西瓜程式猿]這裡以Echarts圖表展示為例子,首先先安裝Echarts包。
npm install echarts --save
版本截圖:
(4)然後再頁面寫入如下代碼,具體頁面樣式根據需要進行修改調整哦。
<!--
* @Author: Kimi Liu
* @Date: 2023-05-24 21:11:24
* @LastEditors: Kimi Liu
* @LastEditTime: 2023-07-07 16:18:55
* @FilePath: \KimiToolBox\src\views\monitor\server\index.vue
* @Description: 服務監控
* Copyright (c) 2023 by kimiliu.cn, All Rights Reserved.
-->
<template>
<!-- 麵包屑導航 -->
<breadcrumb class="breadcrumb_container" />
<div class="app_main_padding">
<el-row>
<el-col :span="24" class="card-box">
<el-card>
<template #header>
<span><i class="el-icon-monitor"></i> 伺服器信息</span>
</template>
<div class="el-table el-table--enable-row-hover el-table--medium">
<table cellspacing="0" style="width: 100%;">
<tbody>
<tr>
<td class="el-table__cell is-leaf"><div class="cell">主機名稱</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="serverInfo">{{serverInfo.HostName}}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">系統名稱</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="serverInfo">{{serverInfo.OSDescription}}</div></td>
</tr>
<tr>
<td class="el-table__cell is-leaf"><div class="cell">IP地址</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="serverInfo">{{serverInfo.IpAddress}}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">操作系統</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="serverInfo">{{serverInfo.OperatingSystem}} {{serverInfo.OsArchitecture}}</div></td>
</tr>
</tbody>
</table>
</div>
</el-card>
</el-col>
<el-col :span="24" class="card-box">
<el-card>
<template #header>
<span><i class="el-icon-monitor"></i> 應用信息</span>
</template>
<div class="el-table el-table--enable-row-hover el-table--medium">
<table cellspacing="0" style="width: 100%;">
<tbody>
<tr>
<td class="el-table__cell is-leaf"><div class="cell">.NET Core版本</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="serverInfo">{{serverInfo.FrameworkDescription}}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">記憶體占用</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="serverInfo">{{serverInfo.MemoryFootprint}}</div></td>
</tr>
<tr>
<td class="el-table__cell is-leaf"><div class="cell">環境變數</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="serverInfo">{{serverInfo.EnvironmentName}}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">項目路徑</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="serverInfo">{{serverInfo.ContentRootPath}}</div></td>
</tr>
</tbody>
</table>
</div>
</el-card>
</el-col>
<el-col :span="24" class="card-box">
<el-card>
<template #header>
<span><i class="el-icon-monitor"></i> 磁碟狀態</span>
</template>
<div class="el-table el-table--enable-row-hover el-table--medium">
<table cellspacing="0" style="width: 100%;" class="el-table__header">
<thead>
<tr>
<th class="el-table_2_column_12 is-leaf headWeight el-table__cell"><div class="cell">磁碟名稱</div></th>
<th class="el-table_2_column_11 is-leaf headWeight el-table__cell"><div>盤符路徑</div></th>
<th class="el-table_2_column_12 is-leaf headWeight el-table__cell"><div class="cell">文件系統</div></th>
<th class="el-table_2_column_12 is-leaf headWeight el-table__cell"><div class="cell">盤符類型</div></th>
<th class="el-table_2_column_12 is-leaf headWeight el-table__cell"><div class="cell">總大小</div></th>
<th class="el-table_2_column_12 is-leaf headWeight el-table__cell"><div class="cell">已用大小</div></th>
<th class="el-table_2_column_12 is-leaf headWeight el-table__cell"><div class="cell">可用大小</div></th>
<th class="el-table_2_column_12 is-leaf headWeight el-table__cell"><div class="cell">已使用率</div></th>
</tr>
</thead>
<tbody v-if="diskInfos" class="table_tbody">
<tr v-for="(sysFile, index) in diskInfos" :key="index">
<td class="el-table_2_column_11 el-table__cell"><div class="cell">{{ sysFile.DiskName }}</div></td>
<td class="el-table_2_column_11 el-table__cell"><div class="cell">{{ sysFile.RootPath }}</div></td>
<td class="el-table_2_column_11 el-table__cell"><div class="cell">{{ sysFile.DriveType }}</div></td>
<td class="el-table_2_column_11 el-table__cell"><div class="cell">{{ sysFile.FileSystem }}</div></td>
<td class="el-table_2_column_11 el-table__cell"><div class="cell">{{ sysFile.TotalSize }}</div></td>
<td class="el-table_2_column_11 el-table__cell"><div class="cell">{{ sysFile.UseSize }}</div></td>
<td class="el-table_2_column_11 el-table__cell"><div class="cell">{{ sysFile.ResidueSize }}</div></td>
<td class="el-table_2_column_11 el-table__cell"><div class="cell"><el-progress :percentage="sysFile.UseRate" :text-inside="true" :stroke-width="14" :color="customColor"/></div></td>
</tr>
</tbody>
</table>
</div>
</el-card>
</el-col>
<el-col :span="24" class="card-box">
<el-card class="box-card">
<template #header>
<span><i class="el-icon-monitor"></i> 狀態</span>
</template>
<div>
<el-row>
<el-col :xs="6" :sm="6" :md="6" :lg="6" :xl="6" style="margin-bottom: 10px" class="box_item">
<div class="title">CPU使用率</div>
<div class="content">
<el-progress type="dashboard" :percentage="cpuInfo.CPULoadVal" :color="customColor" />
</div>
<div class="footer">{{ cpuInfo.ProcessorCount }} 核心</div>
</el-col>
<el-col :xs="6" :sm="6" :md="6" :lg="6" :xl="6" style="margin-bottom: 10px" class="box_item">
<div class="title">記憶體使用率</div>
<div class="content">
<el-progress type="dashboard" :percentage="memoryInfo.UsedPercentage" :color="customColor" />
</div>
<div class="footer">{{ memoryInfo.UsedPhysicalMemory }} / {{ memoryInfo.TotalPhysicalMemory }}</div>
</el-col>
<el-col :xs="6" :sm="6" :md="6" :lg="6" :xl="6" style="margin-bottom: 10px" class="box_item">
<div class="title">網路監控上傳</div>
<div class="content">
<el-progress type="dashboard" :percentage="networkInfo.SentSize" :color="customColor" >
<template #default>
{{networkInfo.SentSize}} {{ networkInfo.SentSizeType }}
</template>
</el-progress>
</div>
<div class="footer"> {{networkInfo.SentSize}} {{ networkInfo.SentSizeType }}/S</div>
</el-col>
<el-col :xs="6" :sm="6" :md="6" :lg="6" :xl="6" style="margin-bottom: 10px" class="box_item">
<div class="title">網路監控下載</div>
<div class="content">
<el-progress type="dashboard" :percentage="networkInfo.ReceivedSize" :color="customColor" >
<template #default>
{{networkInfo.ReceivedSize}} {{ networkInfo.ReceivedSizeType }}
</template>
</el-progress>
</div>
<div class="footer"> {{networkInfo.ReceivedSize}} {{ networkInfo.ReceivedSizeType }}/S</div>
</el-col>
</el-row>
</div>
</el-card>
</el-col>
<el-col :span="24" class="card-box">
<el-row :gutter="25">
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12" style="margin-bottom: 10px">
<el-card class="box-card">
<template #header>
<span><i class="el-icon-monitor"></i> CPU使用率監控</span>
</template>
<div>
<div id="chart1" class="chart"></div>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12" style="margin-bottom: 10px">
<el-card class="box-card">
<template #header>
<span><i class="el-icon-monitor"></i> 記憶體使用率監控</span>
</template>
<div>
<div id="chart2" class="chart"></div>
</div>
</el-card>
</el-col>
</el-row>
</el-col>
</el-row>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, onBeforeUnmount, reactive } from 'vue';
import { EChartsOption, init } from 'echarts';
import { connection, connect, disconnect } from '@/utils/signalr';
import { getApiUrl } from '@/apis/common/utils';
// CPU監控圖標
const cpuOption = reactive<EChartsOption>(
{
tooltip: {
trigger: 'axis'
},
xAxis: {
type: 'category',
boundaryGap: false,
data: []
},
yAxis: {
type: 'value',
min: 0,
max: 100,
interval: 20,
axisLabel: {
formatter: '{value}%'
}
},
series: [
{
data: [],
type: 'line'
}
]
}
);
const memoryOption = reactive<EChartsOption>(
{
tooltip: {
trigger: 'axis'
},
xAxis: {
type: 'category',
boundaryGap: false,
data: []
},
yAxis: {
type: 'value',
min: 0,
max: 100,
interval: 20,
axisLabel: {
formatter: '{value}%'
}
},
series: [
{
data: [],
type: 'line'
}
]
}
);
// 獲得伺服器信息
const serverInfo = ref();
const cpuInfo = ref();
const memoryInfo = ref();
const diskInfos = ref([]);
const networkInfo = ref();
const getServerInfos = (res) => {
serverInfo.value = res.Server;
cpuInfo.value = res.CPU;
memoryInfo.value = res.Memory;
diskInfos.value = res.Disk;
networkInfo.value = res.Network;
if(cpuOption.xAxis.data.length >= 8) {
cpuOption.xAxis.data.shift();
cpuOption.series[0].data.shift();
memoryOption.xAxis.data.shift();
memoryOption.series[0].data.shift();
}
cpuOption.xAxis.data.push(res.Time);
cpuOption.series[0].data.push(res.CPU.CPULoadVal);
memoryOption.xAxis.data.push(res.Time);
memoryOption.series[0].data.push(res.Memory.UsedPercentage);
// 獲取dom,斷言HTMLElement類型,否則會報錯
const chartEle: HTMLElement = document.getElementById('chart1') as HTMLElement;
const chart = init(chartEle);
chart.setOption(cpuOption);
// 獲取dom,斷言HTMLElement類型,否則會報錯
const chartEle2: HTMLElement = document.getElementById('chart2') as HTMLElement;
const chart2 = init(chartEle2);
chart2.setOption(memoryOption);
// 重置圖表大小
window.addEventListener('resize', () => {
chart.resize();
chart2.resize();
});
};
onMounted(async () => {
// 建立連接
connect('http://192.168.11:8080/serverMonitorHub');
// 註冊方法(接收伺服器推送過來的數據)
connection.on('ReceiveMessage', (res) => {
console.log(`【${new Date().toLocaleString()}】:從伺服器同步成功!`);
if(res) {
const result = JSON.parse(res);
getServerInfos(result);
}
});
// 開始連接
await connection.start();
});
// 卸載
onBeforeUnmount(() => {
// 斷開連接
disconnect();
});
// 進度條顏色
const customColor = ref('#ff7831');
</script>
<style lang="scss" scoped>
.card-box {
padding-right: 15px;
margin-bottom: 15px;
}
:deep(.el-card.is-always-shadow) {
box-shadow: 0 5px 8px 0 rgba(0,0,0,0.03);
border: none;
}
.chart {
width: 100%;
height: 300px;
}
.box_item {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
}
.table_tbody {
tr td{
padding: 15px 0;
text-align: center;
}
}
</style>
(5)效果展示:
原文鏈接:https://www.cnblogs.com/kimiliucn/p/17648543.html
版權聲明:本文為原創文章,版權歸 [西瓜程式猿] 所有,轉載請註明出處,有任何疑問請私信咨詢。
原文鏈接:https://www.cnblogs.com/kimiliucn/p/17648543.html