From 16de25c2caaef78d7fda881411db93d0638ea2dd Mon Sep 17 00:00:00 2001 From: zwb Date: Mon, 29 Jul 2024 12:03:47 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4Job=E7=9A=84=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E6=96=B9=E5=BC=8F=20=E4=BC=98=E5=8C=96=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=AD=98=E5=82=A8=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LoongPanel-Asp/ApplicationDbContext.cs | 43 ++-- LoongPanel-Asp/Configs/alert.ini | 8 +- LoongPanel-Asp/Configs/jobs.ini | 18 +- .../Controllers/AccountController.cs | 70 +++---- .../Controllers/ConfigController.cs | 67 +++--- LoongPanel-Asp/Controllers/JobController.cs | 42 ++-- .../Controllers/PublicFileController.cs | 16 +- LoongPanel-Asp/Controllers/RoteController.cs | 13 +- .../Controllers/ServerController.cs | 178 ++++++++-------- LoongPanel-Asp/Controllers/UserController.cs | 10 +- LoongPanel-Asp/Helpers/DataHelper.cs | 96 ++++----- LoongPanel-Asp/Helpers/JobConfigHelper.cs | 42 ++-- LoongPanel-Asp/Hubs/SessionHub.cs | 11 +- LoongPanel-Asp/Hubs/TerminalHub.cs | 11 +- LoongPanel-Asp/Init.cs | 94 ++++----- LoongPanel-Asp/Jobs/CpuJob.cs | 192 +++--------------- LoongPanel-Asp/Jobs/DiskJob.cs | 142 ++----------- LoongPanel-Asp/Jobs/JobBase.cs | 40 ++++ LoongPanel-Asp/Jobs/MemoryJob.cs | 104 ++-------- LoongPanel-Asp/Jobs/NetworkJob.cs | 87 ++------ LoongPanel-Asp/Jobs/ProcessJob.cs | 108 ++-------- LoongPanel-Asp/Jobs/SystemJob.cs | 18 ++ LoongPanel-Asp/Jobs/UserJob.cs | 77 ++----- LoongPanel-Asp/LoongPanel-Asp.csproj | 19 +- .../Middlewares/ApiPermissionMiddleware.cs | 8 +- .../Middlewares/PermissionMiddleware.cs | 3 +- LoongPanel-Asp/Models/AccountModel.cs | 1 - LoongPanel-Asp/Models/OrderType.cs | 12 +- LoongPanel-Asp/Program.cs | 9 +- LoongPanel-Asp/Servers/DataService.cs | 46 +++++ LoongPanel-Asp/Servers/EmailService.cs | 46 +++-- LoongPanel-Asp/Servers/SSHService.cs | 6 +- LoongPanel-Asp/Servers/SSHStreamService.cs | 155 +++++++------- .../markdowns/templates/值班记录.md | 52 ++--- .../markdowns/templates/巡检模板1.md | 24 +-- web/components/Cards/MiniCard.vue | 6 +- web/components/Grid/MainGrid.vue | 3 + web/components/Term.vue | 12 +- web/layouts/Login.vue | 1 - web/layouts/Main.vue | 1 - web/nuxt.config.ts | 3 +- 41 files changed, 759 insertions(+), 1135 deletions(-) create mode 100644 LoongPanel-Asp/Jobs/JobBase.cs create mode 100644 LoongPanel-Asp/Jobs/SystemJob.cs create mode 100644 LoongPanel-Asp/Servers/DataService.cs diff --git a/LoongPanel-Asp/ApplicationDbContext.cs b/LoongPanel-Asp/ApplicationDbContext.cs index b9963d5..221250a 100755 --- a/LoongPanel-Asp/ApplicationDbContext.cs +++ b/LoongPanel-Asp/ApplicationDbContext.cs @@ -1,7 +1,4 @@ using System.ComponentModel.DataAnnotations; -using System.Security.Cryptography; -using System.Text.Json; -using LoongPanel_Asp.Models; using LoongPanel_Asp.utils; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; @@ -71,7 +68,7 @@ public class ApplicationDbContext(DbContextOptions options v => v.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList() ).Metadata.SetValueComparer(new ListOfStringValueComparer()); }); - + // 配置 ServerMonitoringData 实体 modelBuilder.Entity(entity => @@ -115,11 +112,14 @@ public class ApplicationDbContext(DbContextOptions options Name = roleName, NormalizedName = roleName.ToUpperInvariant(), ApiPermissions = - ["1","2","3","4","5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20","21","22","23","24","25","26","27","28","29","30","31","32","33","34","35"], - RouterPermissions = ["1", "3", "4","5","6","7","8","9","10","11","12","13","14","15","16"] + [ + "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", + "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35" + ], + RouterPermissions = ["1", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16"] }); } - + var apiRouterPermissions = ControllerScanner.GetApiPermissions(); foreach (var permission in apiRouterPermissions) @@ -142,16 +142,15 @@ public class ApplicationDbContext(DbContextOptions options new RotePermission { Id = 7, Name = "Gpu", Router = "^/host/gpu/.+$" }, new RotePermission { Id = 8, Name = "用户详细", Router = "^/userinfo/.+$" }, new RotePermission { Id = 9, Name = "用户监测", Router = "^/serveruser/.+$" }, - new RotePermission { Id = 10, Name = "进程列表", Router = "/host/process" }, + new RotePermission { Id = 10, Name = "进程列表", Router = "/host/process" }, new RotePermission { Id = 11, Name = "网络连接列表", Router = "/host/networklist" }, new RotePermission { Id = 12, Name = "巡检记录", Router = "/inspectionrecords" }, new RotePermission { Id = 13, Name = "巡检记录", Router = "^/settings/.+$" }, - new RotePermission { Id = 14, Name = "登录页面修改密码", Router = "^/changepassword/.+$" }, + new RotePermission { Id = 14, Name = "登录页面修改密码", Router = "^/changepassword/.+$" } ]; foreach (var permission in rotePermissions) modelBuilder.Entity().HasData(permission); } - } public class ApplicationUser : IdentityUser @@ -161,22 +160,20 @@ public class ApplicationUser : IdentityUser [MaxLength(255)] public required string Avatar { get; set; } [MaxLength(255)] public string? Desc { get; set; } - + [MaxLength(255)] public required string Posts { get; set; } - + [MaxLength(255)] public string? Address { get; set; } - - [MaxLength(255)] public DateTime? LastLoginTime { get; set; } - + + [MaxLength(255)] public DateTime? LastLoginTime { get; set; } + [MaxLength(255)] public required DateTime CreateDate { get; init; } - + [MaxLength(255)] public required DateTime ModifiedDate { get; set; } - + [MaxLength(255)] public string? PhysicalAddress { get; set; } - - [DataType(DataType.DateTime)] - public DateTimeOffset? PasswordExpiredDate { get; set; } - + + [DataType(DataType.DateTime)] public DateTimeOffset? PasswordExpiredDate { get; set; } } public class ApplicationRole : IdentityRole @@ -209,13 +206,13 @@ public class ServerMonitoringData public DateTime? Time { get; set; } - public required string ServerId { get; set; } + public required string? ServerId { get; set; } public required string? Data { get; set; } public required string DataName { get; set; } - public required string? DataType { get; set; } + public required string DataType { get; set; } } public class ListOfStringValueComparer() : ValueComparer>((c1, c2) => c1!.SequenceEqual(c2!), diff --git a/LoongPanel-Asp/Configs/alert.ini b/LoongPanel-Asp/Configs/alert.ini index 87e6542..aa66bb4 100644 --- a/LoongPanel-Asp/Configs/alert.ini +++ b/LoongPanel-Asp/Configs/alert.ini @@ -1,5 +1,5 @@ [CpuTotalUsage_d3YT] -ValueName=Cpu总使用率 -Description=Cpu总使用率超过20%通知,超过30%警告 -Notify=20 -Warning=30 \ No newline at end of file +ValueName = Cpu总使用率 +Description = Cpu总使用率超过20%通知,超过30%警告 +Notify = 20 +Warning = 30 \ No newline at end of file diff --git a/LoongPanel-Asp/Configs/jobs.ini b/LoongPanel-Asp/Configs/jobs.ini index e7c5d3a..b7f70f6 100755 --- a/LoongPanel-Asp/Configs/jobs.ini +++ b/LoongPanel-Asp/Configs/jobs.ini @@ -1,4 +1,11 @@ -[CpuTotalJob] +[DataJob] +Group = Data +ValueName = 数据库提交 +Description = A simple job that uses the database +JobType = LoongPanel_Asp.Jobs.DataJob, LoongPanel-Asp +CronExpression = 0 0/1 * * * ? * + +[CpuTotalJob] Group = CPU ValueName = CPU使用率 Description = A simple job that uses the CPU @@ -22,6 +29,15 @@ JobType = LoongPanel_Asp.Jobs.CpuSpeedJob, LoongPanel-Asp Executor = d3YT,xseg CronExpression = 2/10 * * * * ? * + +[SystemTimeIntervalLoadJob] +Group = System +ValueName = 系统间隔负载 +Description = A simple job that uses the CPU +JobType = LoongPanel_Asp.Jobs.SystemTimeIntervalLoadJob, LoongPanel-Asp +Executor = d3YT,xseg +CronExpression = 1/5 * * * * ? * + [ProcessTotalJob] Group = Process ValueName = 进程总使用数 diff --git a/LoongPanel-Asp/Controllers/AccountController.cs b/LoongPanel-Asp/Controllers/AccountController.cs index 31bbe2c..be861b6 100755 --- a/LoongPanel-Asp/Controllers/AccountController.cs +++ b/LoongPanel-Asp/Controllers/AccountController.cs @@ -28,7 +28,7 @@ public class AccountController( //判断用户名,邮箱是否唯一 var user = await userManager.FindByNameAsync(model.UserName); if (user != null) return BadRequest("用户名已存在"); - + //创建用户 user = new ApplicationUser { @@ -39,14 +39,16 @@ public class AccountController( Email = model.Email, UserName = model.UserName, PhoneNumber = model.Phone, - NickName = model.FullName, + NickName = model.FullName }; var result = await userManager.CreateAsync(user, model.Password); - if (!result.Succeeded) return BadRequest("无法创建用户,"+string.Join(",",result.Errors.ToList().Select(e=>e.Description))); - + if (!result.Succeeded) + return BadRequest("无法创建用户," + string.Join(",", result.Errors.ToList().Select(e => e.Description))); + //添加用户到默认角色 result = await userManager.AddToRoleAsync(user, model.Role); - if (!result.Succeeded) return BadRequest("无法创建用户,"+string.Join(",",result.Errors.ToList().Select(e=>e.Description))); + if (!result.Succeeded) + return BadRequest("无法创建用户," + string.Join(",", result.Errors.ToList().Select(e => e.Description))); return Ok("用户创建成功"); } catch (Exception e) @@ -55,7 +57,7 @@ public class AccountController( throw; } } - + [HttpPost("Login")] public async Task Login([FromBody] LoginModel model) @@ -67,31 +69,25 @@ public class AccountController( else user = await userManager.FindByNameAsync(model.EmailOrUserName); if (user == null) return BadRequest("用户不存在"); - var result = await signInManager.CheckPasswordSignInAsync(user, model.Password,true); + var result = await signInManager.CheckPasswordSignInAsync(user, model.Password, true); if (!result.Succeeded) return BadRequest("错误账号或密码"); - if (await userManager.IsLockedOutAsync(user)) - { - return BadRequest("账号已锁定,请联系管理员"); - } - if (!user.EmailConfirmed&&user.UserName!="admin") - { + if (await userManager.IsLockedOutAsync(user)) return BadRequest("账号已锁定,请联系管理员"); + if (!user.EmailConfirmed && user.UserName != "admin") return Unauthorized(new { user.Email, user.Id }); - } //创建修改密码令牌 var tokenPassword = await userManager.GeneratePasswordResetTokenAsync(user); - if ((user.PasswordExpiredDate == null || user.PasswordExpiredDate < DateTimeOffset.Now)&&user.UserName!="admin") - { + if ((user.PasswordExpiredDate == null || user.PasswordExpiredDate < DateTimeOffset.Now) && + user.UserName != "admin") //返回402 - return StatusCode(402,new + return StatusCode(402, new { tokenPassword, - user.Id, + user.Id }); - } var roles = await userManager.GetRolesAsync(user); var roleId = roles.ToList()[0]; // 直接获取角色ID列表 var claimsIdentity = new ClaimsIdentity(new[] @@ -101,21 +97,22 @@ public class AccountController( new Claim(ClaimTypes.Role, roleId.ToLower()) // 将角色ID列表转换为逗号分隔的字符串 }); var token = tokenHelper.GenerateToken(claimsIdentity); - + return Ok(new { user.NickName, - Token=token + Token = token }); } [HttpGet("VerifyEmail")] - public async Task VerifyEmail( [FromQuery] string userId,[FromQuery] string email ,[FromQuery] string? code = null) + public async Task VerifyEmail([FromQuery] string userId, [FromQuery] string email, + [FromQuery] string? code = null) { //如果code 不为空 if (code != null) { - var r= emailService.VerifyEmailVerifyCode(userId,code); + var r = emailService.VerifyEmailVerifyCode(userId, code); if (!r) return BadRequest("验证码错误"); //验证成功 //更新用户信息 @@ -126,31 +123,28 @@ public class AccountController( await userManager.UpdateAsync(user); return Ok("邮箱验证成功"); } - await emailService.SendEmailVerifyCodeAsync( userId,email, "尊敬的用户"); + + await emailService.SendEmailVerifyCodeAsync(userId, email, "尊敬的用户"); return Ok("邮件已发送"); } + [HttpGet("ChangePassword")] - public async Task ChangePassword([FromQuery] string userId, [FromQuery] string token,[FromQuery] string newPassword) + public async Task ChangePassword([FromQuery] string userId, [FromQuery] string token, + [FromQuery] string newPassword) { // 获取当前经过身份验证的用户 var authenticatedUser = await userManager.FindByIdAsync(userId); - if (authenticatedUser == null) - { - return BadRequest("用户不存在"); - } + if (authenticatedUser == null) return BadRequest("用户不存在"); // 重置密码 var result = await userManager.ResetPasswordAsync(authenticatedUser, token, newPassword); - if (!result.Succeeded) - { - return BadRequest("修改密码失败"); - } + if (!result.Succeeded) return BadRequest("修改密码失败"); //修改用户的过期时间为1天后 authenticatedUser.PasswordExpiredDate = DateTimeOffset.Now.AddDays(1); await userManager.UpdateAsync(authenticatedUser); return Ok("修改密码成功"); } - + [HttpGet("ForgotPassword")] public async Task ForgotPassword([FromQuery] string email) { @@ -168,7 +162,7 @@ public class AccountController( var user = await userManager.FindByEmailAsync(email); if (user == null) return BadRequest("用户不存在"); //随机生成密码12位 特殊字符大小写数字 英文 - token= token.Replace(" ", "+"); + token = token.Replace(" ", "+"); var newPassword = GenerateRandomPassword(32); var result = await userManager.ResetPasswordAsync(user, token, newPassword); if (!result.Succeeded) return BadRequest(result.Errors.FirstOrDefault()?.Description); @@ -179,7 +173,7 @@ public class AccountController( $"

您的新密码是:{newPassword}

"); return Ok("密码重置成功,新密码已生成并发送给用户邮箱。"); } - + //登出 [HttpGet("Logout")] public async Task Logout() @@ -187,6 +181,7 @@ public class AccountController( await signInManager.SignOutAsync(); return Ok("Logout successful"); } + private string GenerateRandomPassword(int length) { const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%&*"; @@ -195,6 +190,7 @@ public class AccountController( { rng.GetBytes(byteBuffer); } + return new string(byteBuffer.Select(b => chars[b % chars.Length]).ToArray()); } -} +} \ No newline at end of file diff --git a/LoongPanel-Asp/Controllers/ConfigController.cs b/LoongPanel-Asp/Controllers/ConfigController.cs index d004647..9d05155 100644 --- a/LoongPanel-Asp/Controllers/ConfigController.cs +++ b/LoongPanel-Asp/Controllers/ConfigController.cs @@ -1,6 +1,5 @@ using System.Security.Claims; using IniParser; -using IniParser.Model; using LoongPanel_Asp.Helpers; using Microsoft.AspNetCore.Mvc; @@ -8,22 +7,23 @@ namespace LoongPanel_Asp.Controllers; [ApiController] [Route("Api/[controller]")] -public class ConfigController:ControllerBase +public class ConfigController : ControllerBase { [HttpGet("GetAlertConfig")] public IActionResult GetAlertConfig() { var userId = HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier)!.Value; //从Configs/Alerts/userId.ini - var parser=new FileIniDataParser(); - var fullPath=Path.Combine("Configs","Alerts",$"{userId}.ini"); + var parser = new FileIniDataParser(); + var fullPath = Path.Combine("Configs", "Alerts", $"{userId}.ini"); //判断文件是否存在 if (!System.IO.File.Exists(fullPath)) { //复制一份默认配置文件 - System.IO.File.Copy(Path.Combine("Configs","alert.ini"),fullPath); + System.IO.File.Copy(Path.Combine("Configs", "alert.ini"), fullPath); JobConfigHelper.ReloadAlerts(); } + var data = parser.ReadFile(fullPath); //获得所有section var sections = data.Sections; @@ -34,10 +34,10 @@ public class ConfigController:ControllerBase { AlertType = x.SectionName.Split("_")[0], ServerId = x.SectionName.Split("_")[1], - Notify= x.Keys["Notify"], - Warning=x.Keys["Warning"], - TypeName=x.Keys["ValueName"], - Description=x.Keys["Description"], + Notify = x.Keys["Notify"], + Warning = x.Keys["Warning"], + TypeName = x.Keys["ValueName"], + Description = x.Keys["Description"] }; return alertConfiguration; }); @@ -48,37 +48,32 @@ public class ConfigController:ControllerBase public IActionResult AddAlertConfig([FromBody] AlertModel model) { var userId = HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier)!.Value; - var fullPath=Path.Combine("Configs","Alerts",$"{userId}.ini"); - var parser=new FileIniDataParser(); + var fullPath = Path.Combine("Configs", "Alerts", $"{userId}.ini"); + var parser = new FileIniDataParser(); var data = parser.ReadFile(fullPath); //判断是否存在 - if (data.Sections.Contains($"{model.DataType}_{model.ServerId}")) - { - return BadRequest("配置已存在"); - } - var sectionName=$"{model.DataType}_{model.ServerId}"; - data[sectionName]["Notify"]=model.Notify; - data[sectionName]["Warning"]=model.Warning; - data[sectionName]["ValueName"]=model.DataName; - data[sectionName]["Description"]=model.Description; - parser.WriteFile(fullPath,data); + if (data.Sections.Contains($"{model.DataType}_{model.ServerId}")) return BadRequest("配置已存在"); + var sectionName = $"{model.DataType}_{model.ServerId}"; + data[sectionName]["Notify"] = model.Notify; + data[sectionName]["Warning"] = model.Warning; + data[sectionName]["ValueName"] = model.DataName; + data[sectionName]["Description"] = model.Description; + parser.WriteFile(fullPath, data); JobConfigHelper.ReloadAlerts(); return Ok("配置已添加"); } + [HttpDelete("DeleteAlertConfig")] - public IActionResult DeleteAlertConfig([FromQuery] string dataType,[FromQuery] string serverId) + public IActionResult DeleteAlertConfig([FromQuery] string dataType, [FromQuery] string serverId) { var userId = HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier)!.Value; - var fullPath=Path.Combine("Configs","Alerts",$"{userId}.ini"); - var parser=new FileIniDataParser(); + var fullPath = Path.Combine("Configs", "Alerts", $"{userId}.ini"); + var parser = new FileIniDataParser(); var data = parser.ReadFile(fullPath); //判断是否存在 - if (!data.Sections.Contains($"{dataType}_{serverId}")) - { - return BadRequest("配置不存在"); - } + if (!data.Sections.Contains($"{dataType}_{serverId}")) return BadRequest("配置不存在"); data.Sections.RemoveSection($"{dataType}_{serverId}"); - parser.WriteFile(fullPath,data); + parser.WriteFile(fullPath, data); JobConfigHelper.ReloadAlerts(); return Ok("配置已删除"); } @@ -86,11 +81,11 @@ public class ConfigController:ControllerBase public class AlertModel { - public required string ServerId {get;init;} - public required string DataType {get;init;} - public required string Description {get;init;} - public required string Notify {get;init;} - public required string Warning {get;init;} - - public required string DataName {get;init;} + public required string ServerId { get; init; } + public required string DataType { get; init; } + public required string Description { get; init; } + public required string Notify { get; init; } + public required string Warning { get; init; } + + public required string DataName { get; init; } } \ No newline at end of file diff --git a/LoongPanel-Asp/Controllers/JobController.cs b/LoongPanel-Asp/Controllers/JobController.cs index ba786cd..ed6fefc 100755 --- a/LoongPanel-Asp/Controllers/JobController.cs +++ b/LoongPanel-Asp/Controllers/JobController.cs @@ -8,23 +8,34 @@ namespace LoongPanel_Asp.Controllers; public class JobController(ApplicationDbContext dbContext) : ControllerBase { [HttpGet("GetJobList")] - public IActionResult GetJobList([FromQuery]string? serverId=null) + public IActionResult GetJobList([FromQuery] string? serverId = null) { var wildcardRules = new Dictionary> { - { "CPU总体参数", ["CpuTotalUsage","CpuTotalSpeed","CpuIOWaitUsage","CpuSystemUsage","CpuUserUsage"] }, + { "CPU总体参数", ["CpuTotalUsage", "CpuTotalSpeed", "CpuIOWaitUsage", "CpuSystemUsage", "CpuUserUsage"] }, { "CPU单核参数", ["CpuSingleSpeed-*"] }, { "CPU用户参数", ["CpuUsage-*"] }, - { "内存总体参数", ["MemoryCache","MemoryFree","MemoryTotal","MemoryTotalUsage","MemoryUsed"] }, + { "内存总体参数", ["MemoryCache", "MemoryFree", "MemoryTotal", "MemoryTotalUsage", "MemoryUsed"] }, { "内存用户参数", ["MemoryUsage-*"] }, - { "Swap参数", ["SwapFree","SwapTotal","SwapTotalUsage","SwapUsed"] }, - { "各个磁盘参数", ["DiskTps-*","DiskTps-*","DiskUtil-*","DiskWriteKB-*","DiskWriteKB-*","DiskAwait-*","DiskReadKB-*"] }, + { "Swap参数", ["SwapFree", "SwapTotal", "SwapTotalUsage", "SwapUsed"] }, + { + "各个磁盘参数", + [ + "DiskTps-*", "DiskTps-*", "DiskUtil-*", "DiskWriteKB-*", "DiskWriteKB-*", "DiskAwait-*", + "DiskReadKB-*" + ] + }, { "磁盘总体参数", ["DiskTotalUsage"] }, { "网络总体参数", ["InterfaceTotalUtilizationPercentage"] }, - { "各个网络接口参数", ["InterfaceUtilizationPercentage-*","InterfaceUtilizationPercentage-*","ReceivedPacketsPerSecond-*","TransmittedPacketsPerSecond-*"] }, - { "进程", ["PhrasePatternCount","ProcessTotalCount","ThreadsTotalCount"] }, - { "用户进程", ["UserProcesses-*"] }, - + { + "各个网络接口参数", + [ + "InterfaceUtilizationPercentage-*", "InterfaceUtilizationPercentage-*", + "ReceivedPacketsPerSecond-*", "TransmittedPacketsPerSecond-*" + ] + }, + { "进程", ["PhrasePatternCount", "ProcessTotalCount", "ThreadsTotalCount"] }, + { "用户进程", ["UserProcesses-*"] } }; var filteredData = dbContext.ServerMonitoringData .Where(x => string.IsNullOrEmpty(serverId) || x.ServerId == serverId) @@ -36,21 +47,22 @@ public class JobController(ApplicationDbContext dbContext) : ControllerBase { x.DataName, x.DataType, - GroupName = wildcardRules.FirstOrDefault(rule => x.DataType != null && IsMatch(x.DataType, rule.Value)).Key ?? "其他" + GroupName = wildcardRules.FirstOrDefault(rule => x.DataType != null && IsMatch(x.DataType, rule.Value)) + .Key ?? "其他" }) .GroupBy(x => x.GroupName) .Select(group => new { - GroupName=group.Key, + GroupName = group.Key, Items = group.ToList() }) .ToList(); - return Ok(groupedData); } + private bool IsMatch(string input, List patterns) { - return patterns.Select(pattern => "^" + Regex.Escape(pattern).Replace("\\*", ".*") + "$").Any(regexPattern => Regex.IsMatch(input, regexPattern)); + return patterns.Select(pattern => "^" + Regex.Escape(pattern).Replace("\\*", ".*") + "$") + .Any(regexPattern => Regex.IsMatch(input, regexPattern)); } -} - +} \ No newline at end of file diff --git a/LoongPanel-Asp/Controllers/PublicFileController.cs b/LoongPanel-Asp/Controllers/PublicFileController.cs index 0a862fe..b6d23c2 100644 --- a/LoongPanel-Asp/Controllers/PublicFileController.cs +++ b/LoongPanel-Asp/Controllers/PublicFileController.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Mvc; -using Microsoft.Net.Http.Headers; namespace LoongPanel_Asp.Controllers; @@ -10,22 +9,13 @@ public class PublicFileController(IWebHostEnvironment webHostEnvironment) : Cont [HttpPost("UploadImage")] public async Task UploadImage(IFormFile? file) { - if (file == null || file.Length == 0) - { - return BadRequest("文件不能为空"); - } + if (file == null || file.Length == 0) return BadRequest("文件不能为空"); var allowedExtensions = new[] { ".jpg", ".jpeg", ".png", ".gif" }; var extension = Path.GetExtension(file.FileName).ToLowerInvariant(); Console.WriteLine(extension); - if (!allowedExtensions.Contains(extension)) - { - return BadRequest("不支持的文件类型"); - } + if (!allowedExtensions.Contains(extension)) return BadRequest("不支持的文件类型"); var uploadsFolderPath = Path.Combine(webHostEnvironment.WebRootPath, "public/image"); - if (!Directory.Exists(uploadsFolderPath)) - { - Directory.CreateDirectory(uploadsFolderPath); - } + if (!Directory.Exists(uploadsFolderPath)) Directory.CreateDirectory(uploadsFolderPath); var uniqueFileName = $"{Guid.NewGuid()}{extension}"; var filePath = Path.Combine(uploadsFolderPath, uniqueFileName); diff --git a/LoongPanel-Asp/Controllers/RoteController.cs b/LoongPanel-Asp/Controllers/RoteController.cs index a2dd959..eb32471 100755 --- a/LoongPanel-Asp/Controllers/RoteController.cs +++ b/LoongPanel-Asp/Controllers/RoteController.cs @@ -1,6 +1,5 @@ using System.Security.Claims; using System.Text.RegularExpressions; -using LoongPanel_Asp.Helpers; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; @@ -20,16 +19,14 @@ public class RoteController( var role = await roleManager.FindByNameAsync(roleId); var rotes = role!.RouterPermissions.ToList(); //获取路由列表 - var apiPermissions = dbContext.RotePermissions.ToList().Where(x => rotes.Any(y => y == x.Id.ToString())).Select(x=>x.Router).ToList(); + var apiPermissions = dbContext.RotePermissions.ToList().Where(x => rotes.Any(y => y == x.Id.ToString())) + .Select(x => x.Router).ToList(); //如果rotes 中包括* - if (rotes.Contains("*")) - { - return Ok("权限验证通过"); - } + if (rotes.Contains("*")) return Ok("权限验证通过"); //将path全部小写 path = path.ToLower(); //使用正则匹配 - var firstOrDefault = apiPermissions.FirstOrDefault(x => Regex.IsMatch(path,x)); - return Ok(firstOrDefault != null ? Ok("权限验证通过") : Unauthorized("你不具有访问此资源的权力")); + var firstOrDefault = apiPermissions.FirstOrDefault(x => Regex.IsMatch(path, x)); + return Ok(firstOrDefault != null ? Ok("权限验证通过") : Unauthorized("你不具有访问此资源的权力")); } } \ No newline at end of file diff --git a/LoongPanel-Asp/Controllers/ServerController.cs b/LoongPanel-Asp/Controllers/ServerController.cs index 9cc6621..df0e8cd 100755 --- a/LoongPanel-Asp/Controllers/ServerController.cs +++ b/LoongPanel-Asp/Controllers/ServerController.cs @@ -1,17 +1,12 @@ using System.Collections.Concurrent; -using System.Collections.Specialized; using System.Dynamic; using System.Globalization; -using System.Net; -using System.Net.Sockets; -using System.Text; using System.Text.RegularExpressions; using LoongPanel_Asp.Helpers; -using LoongPanel_Asp.Models; using LoongPanel_Asp.Servers; -using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using Newtonsoft.Json; namespace LoongPanel_Asp.Controllers; @@ -23,7 +18,7 @@ public class ServerController(IServiceProvider serviceProvider, ApplicationDbCon [HttpGet("GetServerList")] public IActionResult GetServerList() { - var serverConfigs=JobConfigHelper.GetServers(); + var serverConfigs = JobConfigHelper.GetServers(); //读取每一个配置项转换为列表 var serverList = serverConfigs.Select(section => new ServerInfo { @@ -98,7 +93,7 @@ public class ServerController(IServiceProvider serviceProvider, ApplicationDbCon var timeList2 = timeList.Select(time => time?.ToLocalTime().ToString("MM-dd HH:mm:ss")).ToList(); // 返回结果 - + var returnValue = new { times = timeList2, @@ -175,9 +170,10 @@ public class ServerController(IServiceProvider serviceProvider, ApplicationDbCon { var sshClient = serviceProvider.GetService(); var serverConfigs = JobConfigHelper.GetServers().ToList(); - var server = serverConfigs.Find(x =>x.Id == serverId); + var server = serverConfigs.Find(x => x.Id == serverId); if (server == null) return BadRequest(); - var output = await sshClient?.ExecuteCommandAsync(false, serverId,"echo",$"'{server.Password}'","|","sudo","-S","lshw","-class","memory","-json")!; + var output = await sshClient?.ExecuteCommandAsync(false, serverId, "echo", $"'{server.Password}'", "|", "sudo", + "-S", "lshw", "-class", "memory", "-json")!; if (string.IsNullOrEmpty(output)) return BadRequest(); return Ok(output); } @@ -188,12 +184,14 @@ public class ServerController(IServiceProvider serviceProvider, ApplicationDbCon { var sshClient = serviceProvider.GetService(); var serverConfigs = JobConfigHelper.GetServers().ToList(); - var server = serverConfigs.Find(x =>x.Id == serverId); + var server = serverConfigs.Find(x => x.Id == serverId); if (server == null) return BadRequest(); - var output = await sshClient?.ExecuteCommandAsync(serverId,$"echo {server.Password}","|","sudo -S /usr/sbin/fdisk -l","|","grep 'Disk /'","|","awk '{print $2,$3}'")!; + var output = await sshClient?.ExecuteCommandAsync(serverId, $"echo {server.Password}", "|", + "sudo -S /usr/sbin/fdisk -l", "|", "grep 'Disk /'", "|", "awk '{print $2,$3}'")!; if (string.IsNullOrEmpty(output)) return BadRequest(output); var diskList = output.Split("\n", StringSplitOptions.RemoveEmptyEntries); - var outList = diskList.Select(disk => disk.Split(":", StringSplitOptions.RemoveEmptyEntries)).Select(info => new { name = info[0], size = info[1] }).ToList(); + var outList = diskList.Select(disk => disk.Split(":", StringSplitOptions.RemoveEmptyEntries)) + .Select(info => new { name = info[0], size = info[1] }).ToList(); return Ok(outList); } @@ -202,45 +200,49 @@ public class ServerController(IServiceProvider serviceProvider, ApplicationDbCon { var sshClient = serviceProvider.GetService(); var serverConfigs = JobConfigHelper.GetServers().ToList(); - var server = serverConfigs.Find(x =>x.Id == serverId); + var server = serverConfigs.Find(x => x.Id == serverId); if (server == null) return BadRequest(); - var output = await sshClient?.ExecuteCommandAsync(serverId,"ip link show" ,"|","grep '^[0-9]'","|","awk -F': ' '{print $2}'")!; + var output = await sshClient?.ExecuteCommandAsync(serverId, "ip link show", "|", "grep '^[0-9]'", "|", + "awk -F': ' '{print $2}'")!; if (string.IsNullOrEmpty(output)) return BadRequest(); var data = output.Split('\n', StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToList(); return Ok(data); } + [HttpGet("GetServerNetworkEquipmentInfo")] - public async Task GetServerNetworkEquipmentInfo([FromQuery] string serverId,[FromQuery] string networkId) + public async Task GetServerNetworkEquipmentInfo([FromQuery] string serverId, + [FromQuery] string networkId) { var sshClient = serviceProvider.GetService(); var serverConfigs = JobConfigHelper.GetServers().ToList(); - var server = serverConfigs.Find(x =>x.Id == serverId); + var server = serverConfigs.Find(x => x.Id == serverId); if (server == null) return BadRequest(); - var output = await sshClient?.ExecuteCommandAsync(serverId,"/usr/sbin/ifconfig",networkId)!; + var output = await sshClient?.ExecuteCommandAsync(serverId, "/usr/sbin/ifconfig", networkId)!; if (string.IsNullOrEmpty(output)) return BadRequest(); output = string.Join(" ", output.Split("\n", StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim())); var data = output.Split(" ", StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).Skip(1).ToList(); return Ok(data); } + [HttpGet("GetServerGpuList")] public async Task GetServerGpuList([FromQuery] string serverId) { var sshClient = serviceProvider.GetService(); var serverConfigs = JobConfigHelper.GetServers().ToList(); - var server = serverConfigs.Find(x =>x.Id == serverId); + var server = serverConfigs.Find(x => x.Id == serverId); if (server == null) return BadRequest(); - var output = await sshClient?.ExecuteCommandAsync(serverId,"lspci" ,"|","awk '/VGA/ {print $1}' ")!; + var output = await sshClient?.ExecuteCommandAsync(serverId, "lspci", "|", "awk '/VGA/ {print $1}' ")!; if (string.IsNullOrEmpty(output)) return BadRequest(); var data = output.Split('\n', StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToList(); return Ok(data); } - + [HttpGet("GetServerDiskInfo")] - public async Task GetServerDiskInfo([FromQuery] string serverId,[FromQuery] string diskId) + public async Task GetServerDiskInfo([FromQuery] string serverId, [FromQuery] string diskId) { var sshClient = serviceProvider.GetService(); var serverConfigs = JobConfigHelper.GetServers().ToList(); - var server = serverConfigs.Find(x =>x.Id == serverId); + var server = serverConfigs.Find(x => x.Id == serverId); if (server == null) return BadRequest(); var type = "ata"; if (diskId.StartsWith("nvme")) type = "nvme"; @@ -248,20 +250,20 @@ public class ServerController(IServiceProvider serviceProvider, ApplicationDbCon else if (diskId.StartsWith("sd")) type = "ata"; else if (diskId.StartsWith("hd")) type = "ata"; diskId = $"/dev/{diskId}"; - var output = await sshClient?.ExecuteCommandAsync(serverId,$"echo '{server.Password}'","|","sudo -S","/usr/sbin/smartctl -i",diskId,$"-d {type}","-T permissive","2>/dev/null","|","awk 'NR>4'")!; + var output = await sshClient?.ExecuteCommandAsync(serverId, $"echo '{server.Password}'", "|", "sudo -S", + "/usr/sbin/smartctl -i", diskId, $"-d {type}", "-T permissive", "2>/dev/null", "|", "awk 'NR>4'")!; if (string.IsNullOrEmpty(output)) return BadRequest(output); if (output.Contains("=== START OF INFORMATION SECTION ===")) - { //截断 - output = output.Substring(output.IndexOf("=== START OF INFORMATION SECTION ===", StringComparison.Ordinal) + "=== START OF INFORMATION SECTION ===".Length); - } + output = output.Substring(output.IndexOf("=== START OF INFORMATION SECTION ===", StringComparison.Ordinal) + + "=== START OF INFORMATION SECTION ===".Length); var diskInfo = output .Split('\n', StringSplitOptions.RemoveEmptyEntries) .Select(line => line.Trim().Split(':')) .ToList().Select(x => new { - name=x[0].Replace(" ","_"), - value=x[1] + name = x[0].Replace(" ", "_"), + value = x[1] }).ToList(); return Ok(diskInfo); } @@ -271,14 +273,18 @@ public class ServerController(IServiceProvider serviceProvider, ApplicationDbCon { var sshClient = serviceProvider.GetService(); var serverConfigs = JobConfigHelper.GetServers().ToList(); - var server = serverConfigs.Find(x =>x.Id == serverId); + var server = serverConfigs.Find(x => x.Id == serverId); if (server == null) return BadRequest(); - var output = await sshClient?.ExecuteCommandAsync(serverId,"awk -F: '$1 != \"nobody\" &&$1 != \"build\" {print $1 \":\"$3}' /etc/passwd | sort -t: -k2nr")!; + var output = await sshClient?.ExecuteCommandAsync(serverId, + "awk -F: '$1 != \"nobody\" &&$1 != \"build\" {print $1 \":\"$3}' /etc/passwd | sort -t: -k2nr")!; if (string.IsNullOrEmpty(output)) return BadRequest("无法获得用户树"); var data = output.Split('\n', StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToList(); - output = await sshClient?.ExecuteCommandAsync(serverId,"w -husf","|"," awk '$2 !~ /^tty/ {print$1, $2}'"," |"," sort ","|"," uniq")!; + output = await sshClient?.ExecuteCommandAsync(serverId, "w -husf", "|", " awk '$2 !~ /^tty/ {print$1, $2}'", + " |", " sort ", "|", " uniq")!; var onlineList = output.Split('\n', StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToList(); - output = await sshClient?.ExecuteCommandAsync(serverId,"lastlog | awk 'NR > 1 { if ($2 ~ /^**Never/) {print $1, \"-\",\"NULL\"} else {print $1,$2, substr($0,index($0,$3))}}' ")!; + output = await sshClient?.ExecuteCommandAsync(serverId, + "lastlog | awk 'NR > 1 { if ($2 ~ /^**Never/) {print $1, \"-\",\"NULL\"} else {print $1,$2, substr($0,index($0,$3))}}' ") + !; if (string.IsNullOrEmpty(output)) return BadRequest("无法获得用户登录记录"); var loginList = output.Split('\n', StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToList(); var serverUserList = new List(); @@ -309,9 +315,9 @@ public class ServerController(IServiceProvider serviceProvider, ApplicationDbCon var len = x.Split(' ', StringSplitOptions.RemoveEmptyEntries).ToList(); var name = len[0]; var d = serverUserList.Find(y => y.Name == name); - if(d==null) return; + if (d == null) return; var port = len[1]; - var time = string.Join(" ",len.Skip(2).ToList()); + var time = string.Join(" ", len.Skip(2).ToList()); if (time != "NULL") { DateTimeOffset.TryParseExact(time, @@ -321,51 +327,55 @@ public class ServerController(IServiceProvider serviceProvider, ApplicationDbCon out var dateTimeOffset); time = dateTimeOffset.ToString("G"); } + d.LastLoginTime = time; - d.Port = port; + d.Port = port; }); - serverUserList = serverUserList.OrderByDescending(x => x.IsOnline).ThenByDescending(x => x.LastLoginTime).ToList(); + serverUserList = serverUserList.OrderByDescending(x => x.IsOnline).ThenByDescending(x => x.LastLoginTime) + .ToList(); return Ok(serverUserList); } [HttpGet("GetServerProcessesList")] - public async Task GetServerProcessesList([FromQuery] string serverId,[FromQuery] string? userName) + public async Task GetServerProcessesList([FromQuery] string serverId, [FromQuery] string? userName) { var sshClient = serviceProvider.GetService(); var serverConfigs = JobConfigHelper.GetServers().ToList(); var server = serverConfigs.Find(x => x.Id == serverId); if (server == null) return BadRequest(); var output = await sshClient?.ExecuteCommandAsync(serverId, - "ps -eo pid,user,%cpu,%mem,comm --sort=-%cpu | awk 'NR>1'",userName!=null?$"| grep {userName}":"" )!; + "ps -eo pid,user,%cpu,%mem,comm --sort=-%cpu | awk 'NR>1'", userName != null ? $"| grep {userName}" : "")!; var data = output.Split("\n", StringSplitOptions.RemoveEmptyEntries); var processList = data.Select(x => { - x=x.Trim(); + x = x.Trim(); var line = x.Split(' ', StringSplitOptions.RemoveEmptyEntries).ToList(); return new { - Pid=line[0], + Pid = line[0], User = line[1], - Cpu=line[2], - Memory=line[3], - ProcessName=string.Join(" ",line.Skip(4)) + Cpu = line[2], + Memory = line[3], + ProcessName = string.Join(" ", line.Skip(4)) }; }).ToList(); return Ok(processList); } [HttpGet("GetServerProcessesKill")] - public async Task GetServerProcessesKill([FromQuery] string serverId, [FromQuery] string pid,[FromQuery] bool force=false) + public async Task GetServerProcessesKill([FromQuery] string serverId, [FromQuery] string pid, + [FromQuery] bool force = false) { var sshClient = serviceProvider.GetService(); var serverConfigs = JobConfigHelper.GetServers().ToList(); var server = serverConfigs.Find(x => x.Id == serverId); if (server == null) return BadRequest(); var output = await sshClient?.ExecuteCommandAsync(serverId, - $"echo {server.Password}","|","sudo -SS","kill",force?"-9":"-15",pid )!; + $"echo {server.Password}", "|", "sudo -SS", "kill", force ? "-9" : "-15", pid)!; return Ok($"关闭信号已发送,{output}"); } + [HttpGet("GetServerNetworkList")] public async Task GetServerNetworkList([FromQuery] string serverId, [FromQuery] string? userName) { @@ -374,7 +384,7 @@ public class ServerController(IServiceProvider serviceProvider, ApplicationDbCon var server = serverConfigs.Find(x => x.Id == serverId); if (server == null) return BadRequest(); var output = await sshClient?.ExecuteCommandAsync(serverId, - $"echo {server.Password}","|","sudo -S ss -tunapo")!; + $"echo {server.Password}", "|", "sudo -S ss -tunapo")!; if (string.IsNullOrEmpty(output)) return BadRequest("返回为空"); try { @@ -386,15 +396,15 @@ public class ServerController(IServiceProvider serviceProvider, ApplicationDbCon var networkList = data.Select(x => new { - netId=x[0], - recvQ=x[2], - sendQ=x[3], - addressForm=x[4], - addressTo=x[5], - process=x[6].Split("),(",StringSplitOptions.RemoveEmptyEntries).Select(s=>new + netId = x[0], + recvQ = x[2], + sendQ = x[3], + addressForm = x[4], + addressTo = x[5], + process = x[6].Split("),(", StringSplitOptions.RemoveEmptyEntries).Select(s => new { - name=s.Split(",")[0].Replace("users:((\"","").Replace("\"",""), - pid=s.Split(",")[1].Split("=",StringSplitOptions.RemoveEmptyEntries)[1] + name = s.Split(",")[0].Replace("users:((\"", "").Replace("\"", ""), + pid = s.Split(",")[1].Split("=", StringSplitOptions.RemoveEmptyEntries)[1] }) }); return Ok(networkList); @@ -407,35 +417,35 @@ public class ServerController(IServiceProvider serviceProvider, ApplicationDbCon [HttpPost("UpLoadWord")] public async Task UpLoadWord( - [FromQuery] string serverId, + [FromQuery] string serverId, [FromQuery] string userName, [FromQuery] string wordId, [FromBody] WordModel content) { // 拼接路径 markdowns/ServerId/id.json - var path = Path.Combine(AppContext.BaseDirectory,"markdowns",serverId, $"{wordId}.json"); - var createAt=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); + var path = Path.Combine(AppContext.BaseDirectory, "markdowns", serverId, $"{wordId}.json"); + var createAt = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); var lastModifyAt = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); var directoryPath = Path.GetDirectoryName(path); if (!Directory.Exists(directoryPath)) - { // 不存在则创建目录 - if (directoryPath != null) Directory.CreateDirectory(directoryPath); - } - + if (directoryPath != null) + Directory.CreateDirectory(directoryPath); + // 检查文件是否存在 if (System.IO.File.Exists(path)) { // 读取现有JSON文件 var json = await System.IO.File.ReadAllTextAsync(path); // 反序列化JSON为动态对象 - dynamic existingWord = Newtonsoft.Json.JsonConvert.DeserializeObject(json) ?? new ExpandoObject();; - + dynamic existingWord = JsonConvert.DeserializeObject(json) ?? new ExpandoObject(); + ; + // 使用内部的createAt更新createAt createAt = existingWord.createAt; } - + // 创建新的配置对象 var newWord = new WordFileModel @@ -446,9 +456,9 @@ public class ServerController(IServiceProvider serviceProvider, ApplicationDbCon WordName = content.Name, CreateAt = createAt, LastModifyAt = lastModifyAt - }; + }; // 将新的配置对象序列化为JSON - var newJson = Newtonsoft.Json.JsonConvert.SerializeObject(newWord); + var newJson = JsonConvert.SerializeObject(newWord); // 覆盖写入新的JSON配置 await System.IO.File.WriteAllTextAsync(path, newJson); @@ -461,18 +471,15 @@ public class ServerController(IServiceProvider serviceProvider, ApplicationDbCon public async Task GetWordList([FromQuery] string serverId) { var path = Path.Combine(AppContext.BaseDirectory, "markdowns", serverId); - if (!Directory.Exists(path)) - { - Directory.CreateDirectory(path); - } - + if (!Directory.Exists(path)) Directory.CreateDirectory(path); + var files = Directory.GetFiles(path); var wordList = new List(); foreach (var file in files) { var fileInfo = new FileInfo(file); var json = await System.IO.File.ReadAllTextAsync(file); - var word = Newtonsoft.Json.JsonConvert.DeserializeObject(json); + var word = JsonConvert.DeserializeObject(json); //去除content if (word == null) continue; word.Content = null; @@ -480,6 +487,7 @@ public class ServerController(IServiceProvider serviceProvider, ApplicationDbCon word.FileSize = fileSize.ToString(); wordList.Add(word); } + return Ok(wordList); } @@ -488,19 +496,19 @@ public class ServerController(IServiceProvider serviceProvider, ApplicationDbCon { var path = Path.Combine(AppContext.BaseDirectory, "markdowns", serverId, wordId + ".json"); var json = await System.IO.File.ReadAllTextAsync(path); - var word = Newtonsoft.Json.JsonConvert.DeserializeObject(json); + var word = JsonConvert.DeserializeObject(json); return Ok(word); - } + [HttpGet("GetWordTemplates")] public async Task GetWordTemplates() { var path = Path.Combine(AppContext.BaseDirectory, "markdowns", "templates"); var files = Directory.GetFiles(path); - var templates = files.Select( x => new + var templates = files.Select(x => new { - name = Path.GetFileName(x).Replace(".md",""), - content= System.IO.File.ReadAllTextAsync(x).Result + name = Path.GetFileName(x).Replace(".md", ""), + content = System.IO.File.ReadAllTextAsync(x).Result }).ToList(); return Ok(templates); } @@ -525,15 +533,15 @@ public class WordFileModel public required string? Content { get; set; } public string? FileSize { get; set; } public required string CreateAt { get; set; } - public required string WordName { get; set;} + public required string WordName { get; set; } public required string LastModifyAt { get; set; } } public class ServerUserInfo { - public required string Name { get; set; } - public required bool IsOnline { get; set; } - public required string? LastLoginTime { get; set; } - public required string? Address { get; set; } - public required string? Port { get; set; } -} + public required string Name { get; set; } + public required bool IsOnline { get; set; } + public required string? LastLoginTime { get; set; } + public required string? Address { get; set; } + public required string? Port { get; set; } +} \ No newline at end of file diff --git a/LoongPanel-Asp/Controllers/UserController.cs b/LoongPanel-Asp/Controllers/UserController.cs index 97bcfe0..e08d419 100755 --- a/LoongPanel-Asp/Controllers/UserController.cs +++ b/LoongPanel-Asp/Controllers/UserController.cs @@ -19,7 +19,7 @@ public class UserController(UserManager userManager) : Controll if (user == null) return BadRequest("用户不存在"); //获取role var roles = await userManager.GetRolesAsync(user); - + // 创建一个匿名对象,只包含您想要公开的信息 var userInfo = new { @@ -36,7 +36,7 @@ public class UserController(UserManager userManager) : Controll user.Avatar, user.Desc, user.Posts, - Role = roles[0], + Role = roles[0] }; // 返回用户信息 @@ -78,7 +78,7 @@ public class UserController(UserManager userManager) : Controll { user.Address, user.Avatar, - CreateDate=user.CreateDate.ToLocalTime().ToString("U"), + CreateDate = user.CreateDate.ToLocalTime().ToString("U"), user.Desc, user.Email, user.Id, @@ -86,10 +86,10 @@ public class UserController(UserManager userManager) : Controll user.PhoneNumber, LastLoginTime = user.LastLoginTime?.ToLocalTime().ToString("U"), user.Posts, - ModifiedDate=user.ModifiedDate.ToLocalTime().ToString("U"), + ModifiedDate = user.ModifiedDate.ToLocalTime().ToString("U"), user.UserName, user.PhysicalAddress, - IsLock=user.LockoutEnd > DateTimeOffset.UtcNow + IsLock = user.LockoutEnd > DateTimeOffset.UtcNow }).ToList(); return Ok(userInfoList); } diff --git a/LoongPanel-Asp/Helpers/DataHelper.cs b/LoongPanel-Asp/Helpers/DataHelper.cs index fd94039..024cc48 100755 --- a/LoongPanel-Asp/Helpers/DataHelper.cs +++ b/LoongPanel-Asp/Helpers/DataHelper.cs @@ -1,63 +1,45 @@ -using LoongPanel_Asp.Hubs; -using Microsoft.AspNetCore.SignalR; +namespace LoongPanel_Asp.Helpers; -namespace LoongPanel_Asp.Helpers; - -public class DataHelper(ApplicationDbContext dbContext,IHubContext context) +public static class DataHelper { - public async Task SaveData(ServerMonitoringData data) + public static void AddMonitoringData(List res, string data, string dataName, string dataType) { - // 保存数据到数据库 - var dataDb = dbContext.ServerMonitoringData; - //获取当前时间 - var time = DateTime.UtcNow; - data.Time = time; - dataDb.Add(data); - //提交 - await dbContext.SaveChangesAsync(); - } - - //批量添加 - public async Task SaveData(List data) - { - var dataDb = dbContext.ServerMonitoringData; - var time = DateTime.UtcNow; - foreach (var i in data) + res.Add(new ServerMonitoringData { - i.Time = time; - dataDb.Add(i); - } - - await dbContext.SaveChangesAsync(); - } - public async Task CheckData(string serverId,string valueType,string value,string valueName) - { - - var alertConfigs = JobConfigHelper.GetAlerts(); - if (!alertConfigs.TryGetValue(serverId, out var serverAlert)) return; - serverAlert.Notify.TryGetValue(valueType, out var notifyValuePairs); - serverAlert.Warning.TryGetValue(valueType, out var warningValuePairs); - var matchingValues = warningValuePairs?.Where(pair => double.Parse(value) >= double.Parse(pair.Key)) - .SelectMany(pair => pair.Value).Distinct().ToList(); - - if (matchingValues?.Count > 0) - { - foreach (var item in matchingValues) - { - await context.Clients.Group(item).SendAsync("ReceiveWaring", value, valueName); - var key=$"{serverId}_{valueType}+{item}"; - } - return; - } - - matchingValues = notifyValuePairs?.Where(pair => double.Parse(value) >= double.Parse(pair.Key)) - .SelectMany(pair => pair.Value).Distinct().ToList(); - if (matchingValues?.Count > 0) - { - foreach (var item in matchingValues) - { - await context.Clients.Group(item).SendAsync("ReceiveNotify", value, valueName); - } - } + ServerId = null, + Data = data, + DataName = dataName, + DataType = dataType + }); } + // public async Task CheckData(string serverId,string valueType,string value,string valueName) + // { + // + // var alertConfigs = JobConfigHelper.GetAlerts(); + // if (!alertConfigs.TryGetValue(serverId, out var serverAlert)) return; + // serverAlert.Notify.TryGetValue(valueType, out var notifyValuePairs); + // serverAlert.Warning.TryGetValue(valueType, out var warningValuePairs); + // var matchingValues = warningValuePairs?.Where(pair => double.Parse(value) >= double.Parse(pair.Key)) + // .SelectMany(pair => pair.Value).Distinct().ToList(); + // + // if (matchingValues?.Count > 0) + // { + // foreach (var item in matchingValues) + // { + // await context.Clients.Group(item).SendAsync("ReceiveWaring", value, valueName); + // var key=$"{serverId}_{valueType}+{item}"; + // } + // return; + // } + // + // matchingValues = notifyValuePairs?.Where(pair => double.Parse(value) >= double.Parse(pair.Key)) + // .SelectMany(pair => pair.Value).Distinct().ToList(); + // if (matchingValues?.Count > 0) + // { + // foreach (var item in matchingValues) + // { + // await context.Clients.Group(item).SendAsync("ReceiveNotify", value, valueName); + // } + // } + // } } \ No newline at end of file diff --git a/LoongPanel-Asp/Helpers/JobConfigHelper.cs b/LoongPanel-Asp/Helpers/JobConfigHelper.cs index 41da3d0..f62a39d 100755 --- a/LoongPanel-Asp/Helpers/JobConfigHelper.cs +++ b/LoongPanel-Asp/Helpers/JobConfigHelper.cs @@ -33,7 +33,7 @@ public static class JobConfigHelper Description = section.Keys["Description"], CronExpression = section.Keys["CronExpression"], ValueName = section.Keys["ValueName"], - Executor = section.Keys["Executor"].Split(',').Select(executor => + Executor = section.Keys["Executor"]?.Split(',').Select(executor => { // 查找serverConfigs 中id匹配 未找到则跳过 var server = serverConfigs.FirstOrDefault(server => server.Id == executor); @@ -71,7 +71,7 @@ public static class JobConfigHelper return _serverConfigs; } - public static Dictionary GetAlerts() + public static Dictionary GetAlerts() { if (_alertsConfigs != null) return _alertsConfigs; @@ -81,11 +81,11 @@ public static class JobConfigHelper var alertsFolderPath = Path.Combine(Environment.CurrentDirectory, "Configs", "Alerts"); // 检查目录是否存在,如果不存在则创建 if (!Directory.Exists(alertsFolderPath)) Directory.CreateDirectory(alertsFolderPath); - + // 获取目录下所有.ini文件的路径 var alertFiles = Directory.GetFiles(alertsFolderPath, "*.ini"); - var notifyUsersMap = new Dictionary>>>(); - var warningUsersMap = new Dictionary>>>(); + var notifyUsersMap = new Dictionary>>>(); + var warningUsersMap = new Dictionary>>>(); // 读取配置信息 foreach (var alertFile in alertFiles) { @@ -97,7 +97,7 @@ public static class JobConfigHelper { var serverId = alertSection.SectionName.Split("_")[1]; var type = alertSection.SectionName.Split("_")[0]; - var notifyValue= alertSection.Keys["Notify"]; + var notifyValue = alertSection.Keys["Notify"]; var warningValue = alertSection.Keys["Warning"]; var userId = Path.GetFileNameWithoutExtension(alertFile); if (!notifyUsersMap.TryGetValue(serverId, out var notifyTypes)) @@ -111,6 +111,7 @@ public static class JobConfigHelper warningTypes = []; warningUsersMap.Add(serverId, warningTypes); } + if (!notifyTypes.TryGetValue(type, out var notifyValues)) { notifyValues = []; @@ -128,25 +129,30 @@ public static class JobConfigHelper notifyUsersList = []; notifyValues.Add(notifyValue, notifyUsersList); } + if (!warningValues.TryGetValue(warningValue, out var warningUsersList)) { - warningUsersList = []; - warningValues.Add(warningValue, warningUsersList); + warningUsersList = []; + warningValues.Add(warningValue, warningUsersList); } + notifyUsersList.Add(userId); warningUsersList.Add(userId); } } + //遍历 notifyUsersMap foreach (var (serverId, notifyUsersList) in notifyUsersMap) { //获得key 和 value - if(!alertsConfigs.TryGetValue(serverId, out var alertsConfig)){ + if (!alertsConfigs.TryGetValue(serverId, out var alertsConfig)) + { //创建新的 alertsConfig = new AlertConfiguration(); alertsConfigs.Add(serverId, alertsConfig); } - alertsConfig.Notify= notifyUsersList; + + alertsConfig.Notify = notifyUsersList; } foreach (var (serverId, emailUsersList) in warningUsersMap) @@ -158,19 +164,20 @@ public static class JobConfigHelper alertsConfig = new AlertConfiguration(); alertsConfigs.Add(serverId, alertsConfig); } + alertsConfig.Warning = emailUsersList; } - _alertsConfigs =alertsConfigs; + _alertsConfigs = alertsConfigs; return alertsConfigs; } - + public static void ReloadAlerts() { _alertsConfigs = null; GetAlerts(); } - + public static void ReloadServers() { _serverConfigs = null; @@ -190,7 +197,7 @@ public class JobConfiguration public string? Description { get; init; } //执行者 - public required List Executor { get; init; } + public List? Executor { get; init; } //任务类型 public required string JobType { get; init; } @@ -202,9 +209,10 @@ public class JobConfiguration public string? ValueName { get; init; } } -public class AlertConfiguration(Dictionary>>? notify=null, - Dictionary>>? warning=null) +public class AlertConfiguration( + Dictionary>>? notify = null, + Dictionary>>? warning = null) { public Dictionary>> Notify { get; set; } = notify ?? []; public Dictionary>> Warning { get; set; } = warning ?? []; -} +} \ No newline at end of file diff --git a/LoongPanel-Asp/Hubs/SessionHub.cs b/LoongPanel-Asp/Hubs/SessionHub.cs index 56fd3d0..f1fc7b8 100755 --- a/LoongPanel-Asp/Hubs/SessionHub.cs +++ b/LoongPanel-Asp/Hubs/SessionHub.cs @@ -17,7 +17,7 @@ public class SessionHub(UserManager userManager, ILiteDatabase // 查询获取用户对象 var user = await userManager.FindByIdAsync(userId); user!.Address = ip?.ToString(); - + user!.LastLoginTime = DateTime.UtcNow; // 更新用户信息 await userManager.UpdateAsync(user); @@ -31,7 +31,7 @@ public class SessionHub(UserManager userManager, ILiteDatabase NickName = user.NickName!, Avatar = user.Avatar, Role = role.ToList(), - Posts = user.Posts, + Posts = user.Posts }; @@ -64,12 +64,11 @@ public class SessionHub(UserManager userManager, ILiteDatabase await base.OnDisconnectedAsync(exception); } - public async Task SendMessage(string userId, string receiver ,string message) + public async Task SendMessage(string userId, string receiver, string message) { Console.WriteLine("12312312312{0},{1}", userId, message); await Clients.Group(receiver).SendAsync("sendMessage", userId, message); } - } //定义类型UserInfo @@ -82,6 +81,6 @@ public class UserInfo public required string Avatar { get; init; } public required List Role { get; init; } - - public required string Posts { get; init;} + + public required string Posts { get; init; } } \ No newline at end of file diff --git a/LoongPanel-Asp/Hubs/TerminalHub.cs b/LoongPanel-Asp/Hubs/TerminalHub.cs index 881a657..632344e 100644 --- a/LoongPanel-Asp/Hubs/TerminalHub.cs +++ b/LoongPanel-Asp/Hubs/TerminalHub.cs @@ -4,34 +4,35 @@ using Microsoft.AspNetCore.SignalR; namespace LoongPanel_Asp.Hubs; -public class TerminalHub(SshStreamService sshStreamService):Hub +public class TerminalHub(SshStreamService sshStreamService) : Hub { - public override async Task OnConnectedAsync() { var userId = Context.User!.Claims.First(x => x.Type == ClaimTypes.NameIdentifier).Value; await Groups.AddToGroupAsync(Context.ConnectionId, userId); } + //create a terminal public void CreateTerminal(string serverId) { var userId = Context.User!.Claims.First(x => x.Type == ClaimTypes.NameIdentifier).Value; sshStreamService.Connect(userId, serverId); } + //send a message to the terminal public void SendMessage(string message) { var userId = Context.User!.Claims.First(x => x.Type == ClaimTypes.NameIdentifier).Value; Console.WriteLine(message); - sshStreamService.Write(userId,message); + sshStreamService.Write(userId, message); } public void ResizeTerminal(int row, int col) { var userId = Context.User!.Claims.First(x => x.Type == ClaimTypes.NameIdentifier).Value; - sshStreamService.ReSize(userId,col,row); + sshStreamService.ReSize(userId, col, row); } - + //断开 public override Task OnDisconnectedAsync(Exception? exception) { diff --git a/LoongPanel-Asp/Init.cs b/LoongPanel-Asp/Init.cs index 4127727..84e7544 100644 --- a/LoongPanel-Asp/Init.cs +++ b/LoongPanel-Asp/Init.cs @@ -1,62 +1,52 @@ using Microsoft.AspNetCore.Identity; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using System; -using System.Threading; -using System.Threading.Tasks; -using LoongPanel_Asp.Helpers; -namespace LoongPanel_Asp +namespace LoongPanel_Asp; + +public class Init : IHostedService { - public class Init : IHostedService + private readonly IServiceProvider _serviceProvider; + + public Init(IServiceProvider serviceProvider) { - private readonly IServiceProvider _serviceProvider; + _serviceProvider = serviceProvider; + } - public Init(IServiceProvider serviceProvider) + public async Task StartAsync(CancellationToken cancellationToken) + { + using var scope = _serviceProvider.CreateScope(); + var userManager = scope.ServiceProvider.GetRequiredService>(); + var roleManager = scope.ServiceProvider.GetRequiredService>(); + // 检查管理员用户是否存在 + var adminUser = await userManager.FindByNameAsync("admin"); + if (adminUser == null) { - _serviceProvider = serviceProvider; - } - - public async Task StartAsync(CancellationToken cancellationToken) - { - using var scope = _serviceProvider.CreateScope(); - var userManager = scope.ServiceProvider.GetRequiredService>(); - var roleManager = scope.ServiceProvider.GetRequiredService>(); - // 检查管理员用户是否存在 - var adminUser = await userManager.FindByNameAsync("admin"); - if (adminUser == null) + adminUser = new ApplicationUser { - adminUser = new ApplicationUser - { - Avatar = "https://api.multiavatar.com/admin.svg", - Posts = "管理员", - CreateDate = DateTime.UtcNow, - ModifiedDate = DateTime.UtcNow, - Email = "admin@admin.com", - UserName = "admin", - PhoneNumber = "999999999", - NickName = "默认管理员", - }; + Avatar = "https://api.multiavatar.com/admin.svg", + Posts = "管理员", + CreateDate = DateTime.UtcNow, + ModifiedDate = DateTime.UtcNow, + Email = "admin@admin.com", + UserName = "admin", + PhoneNumber = "999999999", + NickName = "默认管理员" + }; - var result = await userManager.CreateAsync(adminUser, "Qwertyuiop123!@#"); - //分配管理员角色 - if (result.Succeeded) - await userManager.AddToRoleAsync(adminUser, "admin"); - if (result.Succeeded) - Console.WriteLine("管理员创建成功,账号:{0},密码:{1}", "admin", "Qwertyuiop123!@#"); - else - foreach (var error in result.Errors) - { - Console.WriteLine(error.Description); - } - } - } - - public Task StopAsync(CancellationToken cancellationToken) - { - // 这里可以执行一些应用程序停止时的清理操作 - return Task.CompletedTask; + var result = await userManager.CreateAsync(adminUser, "Qwertyuiop123!@#"); + //分配管理员角色 + if (result.Succeeded) + await userManager.AddToRoleAsync(adminUser, "admin"); + if (result.Succeeded) + Console.WriteLine("管理员创建成功,账号:{0},密码:{1}", "admin", "Qwertyuiop123!@#"); + else + foreach (var error in result.Errors) + Console.WriteLine(error.Description); } } -} + + public Task StopAsync(CancellationToken cancellationToken) + { + // 这里可以执行一些应用程序停止时的清理操作 + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/LoongPanel-Asp/Jobs/CpuJob.cs b/LoongPanel-Asp/Jobs/CpuJob.cs index b8861f5..02edec3 100755 --- a/LoongPanel-Asp/Jobs/CpuJob.cs +++ b/LoongPanel-Asp/Jobs/CpuJob.cs @@ -1,183 +1,53 @@ using System.Globalization; using LoongPanel_Asp.Helpers; -using LoongPanel_Asp.Hubs; using LoongPanel_Asp.Models; using LoongPanel_Asp.Servers; -using Microsoft.AspNetCore.SignalR; using Quartz; -using Property = LoongPanel_Asp.Models.Property; namespace LoongPanel_Asp.Jobs; -public class CpuTotalJob( - IHubContext hubContext, - IServiceProvider serviceProvider, - ApplicationDbContext dbContext) : IJob +public class CpuTotalJob(DataService dataService, SshService sshService) : IiJob(dataService, sshService) { - private static int _count; - - public async Task Execute(IJobExecutionContext context) + protected override async Task ExecuteInternal(IJobExecutionContext context, ServerModel server, + SshService sshService, List res) { - var dataMap = context.JobDetail.JobDataMap; - var dataHelper = new DataHelper(dbContext,hubContext); - var serverList = (List)dataMap["executor"]; - var cpuDataListAll = new List(); - var sshClient = serviceProvider.GetService(); - foreach (var server in serverList) - { - var output = await sshClient?.ExecuteCommandAsync(server.Id, "sar", "-u", "3 1", "|", "grep", "Average")!; - if (string.IsNullOrEmpty(output)) continue; - - output = output.Replace("Average:", "").Replace("all", "").TrimStart(); - var cpuList = output.Split(' ', StringSplitOptions.RemoveEmptyEntries); - - var cpuProperties = new List - { - new() { Name = "CpuUserUsage", DisplayName = "CPU用户使用率", Order = 0 }, - new() { Name = "CpuSystemUsage", DisplayName = "CPU系统使用率", Order = 1 }, - new() { Name = "CpuIOWaitUsage", DisplayName = "CPUIO等待使用率", Order = 2 } - }; - - var cpuDataList = cpuProperties.Select(property => new ServerMonitoringData { ServerId = server.Id, Data = cpuList[(int)property.Order!], DataName = property.DisplayName, DataType = property.Name }).ToList(); - - // Calculate CpuTotalUsage separately - var idleUsage = double.Parse(cpuList[5]); - var totalUsage = new ServerMonitoringData - { - ServerId = server.Id, - Data = (100 - idleUsage).ToString(CultureInfo.InvariantCulture), - DataName = "CPU总使用率", - DataType = "CpuTotalUsage" - }; - cpuDataList.Add(totalUsage); - cpuDataList.ForEach(async data => - { - await hubContext.Clients.All.SendAsync("ReceiveData", data.ServerId, data.DataType, data.Data); - await dataHelper.CheckData(server.Id, data.DataType??"", data.Data??"", data.DataName); - }); - cpuDataListAll.AddRange(cpuDataList); - } - - _count++; - if (_count <= 10) return; - _count = 0; - // Add to database - await dataHelper.SaveData(cpuDataListAll); + var output = await sshService.ExecuteCommandAsync(server.Id, "sar", "-u", "3 1", "|", "grep", "Average"); + if (string.IsNullOrEmpty(output)) return; + var values = output.Split(' ', StringSplitOptions.RemoveEmptyEntries).Skip(2).ToList(); + DataHelper.AddMonitoringData(res, values[0], "CPU用户使用率", "CpuUserUsage"); + DataHelper.AddMonitoringData(res, values[2], "CPU系统使用率", "CpuSystemUsage"); + DataHelper.AddMonitoringData(res, values[3], "CPUIO等待率", "CpuIOWaitUsage"); + DataHelper.AddMonitoringData(res, (100 - double.Parse(values[5])).ToString(CultureInfo.InvariantCulture), + "CPU总使用率", "CpuTotalUsage"); } } -public class CpuSpeedJob( - IHubContext hubContext, - IServiceProvider serviceProvider, - ApplicationDbContext dbContext) : IJob +public class CpuSpeedJob(DataService dataService, SshService sshService) : IiJob(dataService, sshService) { - private static int _count; - - public async Task Execute(IJobExecutionContext context) + protected override async Task ExecuteInternal(IJobExecutionContext context, ServerModel server, + SshService sshService, List res) { - var dataMap = context.JobDetail.JobDataMap; - var dataHelper = new DataHelper(dbContext,hubContext); - var serverList = (List)dataMap["executor"]; - var cpuDataListAll = new List(); - var sshClient = serviceProvider.GetService(); - foreach (var server in serverList) - { - var output = - await sshClient?.ExecuteCommandAsync(server.Id, "cat", "/proc/cpuinfo", "|", "grep", "'cpu MHz'")!; - if (string.IsNullOrEmpty(output)) continue; - //切分每行 - var cpuSpeedList = output.Split('\n', StringSplitOptions.RemoveEmptyEntries); - //获取第一行 - var cpuTotalSpeed = cpuSpeedList[0].Split(':', StringSplitOptions.RemoveEmptyEntries)[1].Trim(); - var cpuDataList = new List(); - var totalSpeed = new ServerMonitoringData - { - ServerId = server.Id, - Data = cpuTotalSpeed, - DataName = "CPU总速度", - DataType = "CpuTotalSpeed" - }; - cpuDataList.Add(totalSpeed); - //遍历剩下的行 - foreach (var (cpuSpeed, index) in cpuSpeedList.Skip(1).Select((x, index) => (x, index))) - { - var speed = cpuSpeed.Split(':', StringSplitOptions.RemoveEmptyEntries)[1].Trim(); - var singleSpeed = new ServerMonitoringData - { - ServerId = server.Id, - Data = speed, - DataName = $"CPU单核速度-{index}", - DataType = $"CpuSingleSpeed-{index}" - }; - cpuDataList.Add(singleSpeed); - } - - cpuDataListAll.AddRange(cpuDataList); - - cpuDataList.ForEach(Action); - continue; - - async void Action(ServerMonitoringData data) - { - await hubContext.Clients.All.SendAsync("ReceiveData", data.ServerId, data.DataType, data.Data); - await dataHelper.CheckData(server.Id, data.DataType ?? "", data.Data ?? "", data.DataName); - } - } - - _count++; - if (_count <= 10) return; - _count = 0; - await dataHelper.SaveData(cpuDataListAll); + var output = await sshService.ExecuteCommandAsync(server.Id, "cat", "/proc/cpuinfo", "|", "grep", "'cpu MHz'"); + if (string.IsNullOrEmpty(output)) return; + var cpuSpeeds = output.Split('\n', StringSplitOptions.RemoveEmptyEntries) + .Select(line => line.Split(':', 2)[1].Trim()) + .Where(speed => !string.IsNullOrEmpty(speed)).ToList(); + DataHelper.AddMonitoringData(res, cpuSpeeds[0], "CPU总频率", "CpuTotalSpeed"); + cpuSpeeds.Skip(1).Select((speed, i) => (speed, i)).ToList().ForEach(x => + DataHelper.AddMonitoringData(res, x.speed, $"CPU{x.i + 1}频率", $"CpuSingleSpeed-{x.i + 1}")); } } -public class CpuSingleUsageJob( - IHubContext hubContext, - IServiceProvider serviceProvider, - ApplicationDbContext dbContext) : IJob +public class CpuSingleUsageJob(DataService dataService, SshService sshService) : IiJob(dataService, sshService) { - private static int _count; - - public async Task Execute(IJobExecutionContext context) + protected override async Task ExecuteInternal(IJobExecutionContext context, ServerModel server, + SshService sshService, List res) { - var dataMap = context.JobDetail.JobDataMap; - var dataHelper = new DataHelper(dbContext,hubContext); - var serverList = (List)dataMap["executor"]; - var cpuDataListAll = new List(); - foreach (var server in serverList) - { - var sshClient = serviceProvider.GetService(); - var output = - await sshClient?.ExecuteCommandAsync(server.Id, "sar -P ALL 3 1", "|", "grep Average", "|", - "awk 'NR>2 {print 100-$NF}'")!; - if (string.IsNullOrEmpty(output)) continue; - var cpuDataList = new List(); - foreach (var (cpuUsage, index) in output.Split("\n", StringSplitOptions.RemoveEmptyEntries) - .Select((x, index) => (x, index))) - { - var singleUsage = new ServerMonitoringData - { - ServerId = server.Id, - Data = cpuUsage, - DataName = $"CPU单核使用率-{index}", - DataType = $"CpuSingleUsage-{index}" - }; - cpuDataList.Add(singleUsage); - } - - cpuDataList.ForEach(Action); - continue; - - async void Action(ServerMonitoringData data) - { - await hubContext.Clients.All.SendAsync("ReceiveData", data.ServerId, data.DataType, data.Data); - await dataHelper.CheckData(server.Id, data.DataType ?? "", data.Data ?? "", data.DataName); - } - } - - _count++; - if (_count <= 10) return; - _count = 0; - await dataHelper.SaveData(cpuDataListAll); + var output = await sshService.ExecuteCommandAsync(server.Id, "sar -P ALL 3 1", "|", "grep Average", "|", + "awk 'NR>2 {print 100-$NF}'"); + if (string.IsNullOrEmpty(output)) return; + var values = output.Split('\n', StringSplitOptions.RemoveEmptyEntries); + values.Select((value, i) => (value, i)).ToList().ForEach(x => + DataHelper.AddMonitoringData(res, x.value, $"CPU{x.i}使用率", $"CpuSingleUsage-{x.i}")); } } \ No newline at end of file diff --git a/LoongPanel-Asp/Jobs/DiskJob.cs b/LoongPanel-Asp/Jobs/DiskJob.cs index 93c3dfd..473a59f 100755 --- a/LoongPanel-Asp/Jobs/DiskJob.cs +++ b/LoongPanel-Asp/Jobs/DiskJob.cs @@ -1,137 +1,39 @@ using LoongPanel_Asp.Helpers; -using LoongPanel_Asp.Hubs; using LoongPanel_Asp.Models; using LoongPanel_Asp.Servers; -using Microsoft.AspNetCore.SignalR; using Quartz; namespace LoongPanel_Asp.Jobs; -public class DiskTotalJob( - IHubContext hubContext, - IServiceProvider serviceProvider, - ApplicationDbContext dbContext) : IJob +public class DiskTotalJob(DataService dataService, SshService sshService) : IiJob(dataService, sshService) { - private static int _count; - - public async Task Execute(IJobExecutionContext context) + protected override async Task ExecuteInternal(IJobExecutionContext context, ServerModel server, + SshService sshService, List res) { - var dataMap = context.JobDetail.JobDataMap; - var dataHelper = new DataHelper(dbContext,hubContext); - var serverList = (List)dataMap["executor"]; - //获得cpu信息 - var diskDataListAll = new List(); - foreach (var server in serverList) - { - var sshClient = serviceProvider.GetService(); - var diskDataList = new List(); - var output = await sshClient?.ExecuteCommandAsync(server.Id, "df", "--total", "|", "grep", "total")!; - if (string.IsNullOrEmpty(output)) return; - var disk = output.Split(" ", StringSplitOptions.RemoveEmptyEntries); - var diskTotalUsage = new ServerMonitoringData - { - ServerId = server.Id, - Data = disk[4].Replace("%", ""), - DataName = "磁盘总使用率", - DataType = "DiskTotalUsage" - }; - await hubContext.Clients.All.SendAsync("ReceiveData", diskTotalUsage.ServerId, diskTotalUsage.DataType, - diskTotalUsage.Data); - await dataHelper.CheckData(server.Id, diskTotalUsage.DataType ?? "", diskTotalUsage.Data ?? "", "磁盘总使用率"); - diskDataList.Add(diskTotalUsage); - diskDataListAll.AddRange(diskDataList); - } - - _count++; - if (_count <= 10) return; - _count = 0; - await dataHelper.SaveData(diskDataListAll); + var output = await sshService.ExecuteCommandAsync(server.Id, "df", "--total", "|", "grep", "total"); + if (string.IsNullOrEmpty(output)) return; + var diskTotal = output.Split(" ", StringSplitOptions.RemoveEmptyEntries)[4].Replace("%", ""); + DataHelper.AddMonitoringData(res, diskTotal, "磁盘总使用率", "DiskTotalUsage"); } } -public class DiskUseJob( - IHubContext hubContext, - IServiceProvider serviceProvider, - ApplicationDbContext dbContext) : IJob +public class DiskUseJob(DataService dataService, SshService sshService) : IiJob(dataService, sshService) { - private static int _count; - - public async Task Execute(IJobExecutionContext context) + protected override async Task ExecuteInternal(IJobExecutionContext context, ServerModel server, + SshService sshService, List res) { - var dataMap = context.JobDetail.JobDataMap; - var dataHelper = new DataHelper(dbContext,hubContext); - var serverList = (List)dataMap["executor"]; - //获得cpu信息 - var diskDataListAll = new List(); - foreach (var server in serverList) + var output = await sshService.ExecuteCommandAsync(server.Id, + "sar -d 3 1 | grep Average: | awk 'NR>1' | awk '{$1=\"\";print$0}'"); + if (string.IsNullOrEmpty(output)) return; + + output.Split("\n").Select(x => x.Trim()).Where(line => !string.IsNullOrEmpty(line)).ToList().ForEach(line => { - var sshClient = serviceProvider.GetService(); - var diskDataList = new List(); - var output = - await sshClient?.ExecuteCommandAsync(server.Id, "sar -d 3 1", "|", "grep Average:", "|", "awk 'NR>1'","|","awk '{$1=\"\";print $0}'")!; - if (string.IsNullOrEmpty(output)) return; - var lines = output.Split("\n", StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToList(); - - foreach (var line in lines) - { - var disk = line.Split(" ", StringSplitOptions.RemoveEmptyEntries); - var dev = disk[0]; - // 每秒传输数 - var diskTps = new ServerMonitoringData - { - ServerId = server.Id, - Data = disk[1], - DataName = $"磁盘每秒传输数-{dev}" , - DataType = $"DiskTps-{dev}" - }; - diskDataList.Add(diskTps); - var diskReadKb = new ServerMonitoringData - { - ServerId = server.Id, - Data = disk[2], - DataName = $"磁盘每秒读取数据量-{dev}" , - DataType = $"DiskReadKB-{dev}" - }; - diskDataList.Add(diskReadKb); - var diskWriteKb = new ServerMonitoringData - { - ServerId = server.Id, - Data = disk[3], - DataName = $"磁盘每秒写入数据量-{dev}" , - DataType = $"DiskWriteKB-{dev}" - }; - diskDataList.Add(diskWriteKb); - var diskAwait = new ServerMonitoringData - { - ServerId = server.Id, - Data = disk[7], - DataName = $"磁盘平均等待时间-{dev}" , - DataType = $"DiskAwait-{dev}" - }; - diskDataList.Add(diskAwait); - var diskUtil = new ServerMonitoringData - { - ServerId = server.Id, - Data = disk[8], - DataName = $"磁盘利用率-{dev}" , - DataType = $"DiskUtil-{dev}" - }; - diskDataList.Add(diskUtil); - - diskDataList.ForEach(Action); - continue; - - async void Action(ServerMonitoringData data) - { - await hubContext.Clients.All.SendAsync("ReceiveData", data.ServerId, data.DataType, data.Data); - await dataHelper.CheckData(server.Id, data.DataType ?? "", data.Data ?? "", data.DataName); - } - } - diskDataListAll.AddRange(diskDataList); - } - _count++; - if (_count <= 10) return; - _count = 0; - await dataHelper.SaveData(diskDataListAll); + var diskValues = line.Split(' ', StringSplitOptions.RemoveEmptyEntries).ToList(); + var diskName = diskValues[0]; + DataHelper.AddMonitoringData(res, diskValues[1], $"磁盘每秒传输数-{diskName}", $"DiskTps-{diskName}"); + DataHelper.AddMonitoringData(res, diskValues[2], $"磁盘每秒读数-{diskName}", $"DiskReadKB-{diskName}"); + DataHelper.AddMonitoringData(res, diskValues[3], $"磁盘每秒写数-{diskName}", $"DiskWriteKB-{diskName}"); + DataHelper.AddMonitoringData(res, diskValues[8], $"磁盘利用率-{diskName}", $"DiskUtil-{diskName}"); + }); } } \ No newline at end of file diff --git a/LoongPanel-Asp/Jobs/JobBase.cs b/LoongPanel-Asp/Jobs/JobBase.cs new file mode 100644 index 0000000..5d3c539 --- /dev/null +++ b/LoongPanel-Asp/Jobs/JobBase.cs @@ -0,0 +1,40 @@ +using LoongPanel_Asp.Models; +using LoongPanel_Asp.Servers; +using Quartz; + +namespace LoongPanel_Asp.Jobs; + +public abstract class IiJob( + DataService dataService, + SshService sshService) + : IJob +{ + public async Task Execute(IJobExecutionContext context) + { + var dataMap = context.JobDetail.JobDataMap; + var serverList = (List)dataMap["executor"]; + var res = new List(); + foreach (var server in serverList) + { + var r = new List(); + await ExecuteInternal(context, server, sshService, r); + r.ForEach(x => x.ServerId = server.Id); + res.AddRange(r); + } + + await dataService.Save(res); + } + + protected abstract Task ExecuteInternal(IJobExecutionContext context, ServerModel server, SshService sshService, + List res); +} + +//DataService Submit +public class DataJob(DataService service) : IJob +{ + public Task Execute(IJobExecutionContext context) + { + _ = service.Submit(); + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/LoongPanel-Asp/Jobs/MemoryJob.cs b/LoongPanel-Asp/Jobs/MemoryJob.cs index e3e6972..79b45e0 100755 --- a/LoongPanel-Asp/Jobs/MemoryJob.cs +++ b/LoongPanel-Asp/Jobs/MemoryJob.cs @@ -1,99 +1,35 @@ using System.Globalization; using LoongPanel_Asp.Helpers; -using LoongPanel_Asp.Hubs; using LoongPanel_Asp.Models; using LoongPanel_Asp.Servers; -using Microsoft.AspNetCore.SignalR; using Quartz; namespace LoongPanel_Asp.Jobs; -public class MemoryTotalJob( - IHubContext hubContext, - IServiceProvider serviceProvider, - ApplicationDbContext dbContext) : IJob +public class MemoryTotalJob(DataService dataService, SshService sshService) : IiJob(dataService, sshService) { - private static int _count; - - public async Task Execute(IJobExecutionContext context) + protected override async Task ExecuteInternal(IJobExecutionContext context, ServerModel server, + SshService sshService, List res) { - var dataMap = context.JobDetail.JobDataMap; - var dataHelper = new DataHelper(dbContext,hubContext); - // 从JobDataMap中获取参数 - var serverList = (List)dataMap["executor"]; + var output = + await sshService.ExecuteCommandAsync(server.Id, "free -w | awk 'NR>1' | awk '{$1=\"\";print$0}' | xargs"); + var values = output.Split(" ", StringSplitOptions.RemoveEmptyEntries); + var memoryTotal = values[0]; + var memoryUsed = values[1]; + var memoryFree = values[2]; + var swapTotal = values[6]; + var swapUsed = values[7]; + DataHelper.AddMonitoringData(res, memoryUsed, "内存使用量", "MemoryUsed"); + DataHelper.AddMonitoringData(res, memoryFree, "内存空闲量", "MemoryFree"); + var memoryUsedPercent = Math.Round(double.Parse(memoryUsed) / double.Parse(memoryTotal) * 100, 2) + .ToString(CultureInfo.InvariantCulture); + DataHelper.AddMonitoringData(res, memoryUsedPercent, "内存总使用率", "MemoryTotalUsage"); - var serverDataListAll = new List(); - foreach (var server in serverList) + if (double.Parse(swapTotal) > 0) { - var sshClient = serviceProvider.GetService(); - var output = await sshClient?.ExecuteCommandAsync(server.Id, "free -w", "|", "awk 'NR>1'", "|", - "awk '{$1=\"\";print $0}'", "|", "xargs")!; - if (string.IsNullOrEmpty(output)) continue; - var serverDataList = new List(); - var dataList = output.Split(" ", StringSplitOptions.RemoveEmptyEntries); - var memoryProperties = new List - { - new() { Name = "MemoryTotal", DisplayName = "内存总量", Order = 0 }, - new() { Name = "MemoryUsed", DisplayName = "内存使用量", Order = 1 }, - new() { Name = "MemoryFree", DisplayName = "内存空闲量", Order = 2 }, - new() { Name = "MemoryCache", DisplayName = "内存缓存量", Order = 5 }, - new() { Name = "SwapTotal", DisplayName = "Swap总量", Order = 7 }, - new() { Name = "SwapUsed", DisplayName = "Swap使用量", Order = 8 }, - new() { Name = "SwapFree", DisplayName = "Swap空闲量", Order = 9 } - }; - memoryProperties.ForEach(data => - { - var d = new ServerMonitoringData - { - ServerId = server.Id, - Data = double.Parse(dataList[(int)data.Order!]).ToString(CultureInfo.CurrentCulture), - DataName = data.DisplayName, - DataType = data.Name - }; - serverDataList.Add(d); - }); - //计算内存使用率 - var memoryUsed = double.Parse(dataList[1]); - var memoryTotal = double.Parse(dataList[0]); - if (memoryTotal <= 0) memoryTotal = 1; - var memoryUsedRate = memoryUsed / memoryTotal * 100; - - var memoryData = new ServerMonitoringData - { - ServerId = server.Id, - Data = memoryUsedRate.ToString(CultureInfo.InvariantCulture), - DataName = "内存总使用率", - DataType = "MemoryTotalUsage" - }; - serverDataList.Add(memoryData); - //计算交换使用率 - var swapUsed = double.Parse(dataList[8]); - var swapTotal = double.Parse(dataList[7]); - if (swapTotal <= 0) swapTotal = 1; - var swapUsedRate = swapUsed / swapTotal * 100; - var swapData = new ServerMonitoringData - { - ServerId = server.Id, - Data = swapUsedRate.ToString(CultureInfo.InvariantCulture), - DataName = "Swap使用率", - DataType = "SwapTotalUsage" - }; - serverDataList.Add(swapData); - - serverDataList.ForEach(Action); - serverDataListAll.AddRange(serverDataList); - continue; - - async void Action(ServerMonitoringData data) - { - await hubContext.Clients.All.SendAsync("ReceiveData", data.ServerId, data.DataType, data.Data); - await dataHelper.CheckData(server.Id, data.DataType ?? "", data.Data ?? "", data.DataName); - } + var swapUsedPercent = Math.Round(double.Parse(swapUsed) / double.Parse(swapTotal) * 100, 2) + .ToString(CultureInfo.InvariantCulture); + DataHelper.AddMonitoringData(res, swapUsedPercent, "Swap总使用率", "SwapTotalUsage"); } - - _count++; - if (_count <= 10) return; - _count = 0; - await dataHelper.SaveData(serverDataListAll); } } \ No newline at end of file diff --git a/LoongPanel-Asp/Jobs/NetworkJob.cs b/LoongPanel-Asp/Jobs/NetworkJob.cs index 51d1314..4096371 100755 --- a/LoongPanel-Asp/Jobs/NetworkJob.cs +++ b/LoongPanel-Asp/Jobs/NetworkJob.cs @@ -1,84 +1,33 @@ using System.Globalization; using LoongPanel_Asp.Helpers; -using LoongPanel_Asp.Hubs; using LoongPanel_Asp.Models; using LoongPanel_Asp.Servers; -using Microsoft.AspNetCore.SignalR; using Quartz; namespace LoongPanel_Asp.Jobs; -public class NetworkTotalJob( - IHubContext hubContext, - IServiceProvider serviceProvider, - ApplicationDbContext dbContext) : IJob +public class NetworkTotalJob(DataService dataService, SshService sshService) : IiJob(dataService, sshService) { - private static int _count; - - public async Task Execute(IJobExecutionContext context) + protected override async Task ExecuteInternal(IJobExecutionContext context, ServerModel server, + SshService sshService, List res) { - var dataMap = context.JobDetail.JobDataMap; - var dataHelper = new DataHelper(dbContext,hubContext); - var serverList = (List)dataMap["executor"]; - var netWorkDataListAll = new List(); - foreach (var server in serverList) + var output = await sshService.ExecuteCommandAsync(server.Id, "sar", "-n", "DEV", "3 1", "|", "grep", "Average:", + "|", "awk 'NR>1'", "|", "awk '{$1=\"\";print $0}'"); + if (string.IsNullOrEmpty(output)) return; + var lines = output.Split("\n", StringSplitOptions.RemoveEmptyEntries); + var totalUsage = 0.0; + foreach (var line in lines) { - var sshClient = serviceProvider.GetService(); - var netWorkDataList = new List(); - var output = await sshClient?.ExecuteCommandAsync(server.Id, "sar", "-n", "DEV", "3 1", "|", "grep", - "Average:", "|", "awk 'NR>1'", "|", "awk '{$1=\"\";print $0}'")!; - if (string.IsNullOrEmpty(output)) continue; - var lines = output.Split("\n"); - var totalUsage = 0.0; - foreach (var line in lines) - { - if (string.IsNullOrEmpty(line)) continue; - var data = line.Split(" ", StringSplitOptions.RemoveEmptyEntries); - var iFace = data[0]; - var dataNum = data.Skip(1).Select(double.Parse).ToList(); - var netWorkProperties = new List - { - new() { Name = "ReceivedPacketsPerSecond", DisplayName = "每秒钟接收到的数据包数量", Order = 0 }, - new() { Name = "TransmittedPacketsPerSecond", DisplayName = "每秒钟发送的数据包数量", Order = 1 }, - new() { Name = "InterfaceUtilizationPercentage", DisplayName = "网络接口的使用率", Order = 7 } - }; - netWorkProperties.ForEach(property => - { - var d = new ServerMonitoringData - { - ServerId = server.Id, - Data = dataNum[(int)property.Order!].ToString(CultureInfo.InvariantCulture), - DataName = $"{property.DisplayName}-{iFace}", - DataType = $"{property.Name}-{iFace}" - }; - netWorkDataList.Add(d); - }); - totalUsage += dataNum[7]; - } - - var d = new ServerMonitoringData - { - ServerId = server.Id, - Data = totalUsage.ToString(CultureInfo.InvariantCulture), - DataName = "网络接口总体使用率", - DataType = "InterfaceTotalUtilizationPercentage" - }; - netWorkDataList.Add(d); - netWorkDataListAll.AddRange(netWorkDataList); - - netWorkDataList.ForEach( Action); - continue; - - async void Action(ServerMonitoringData data) - { - await hubContext.Clients.All.SendAsync("ReceiveData", data.ServerId, data.DataType, data.Data); - await dataHelper.CheckData(server.Id, data.DataType ?? "", data.Data ?? "", data.DataName); - } + if (string.IsNullOrEmpty(line)) continue; + var values = line.Split(" ", StringSplitOptions.RemoveEmptyEntries); + var iFace = values[0]; + DataHelper.AddMonitoringData(res, values[1], $"每秒钟接收到的数据包数量-{iFace}", $"NetWorkReceive-{iFace}"); + DataHelper.AddMonitoringData(res, values[2], $"每秒钟发送的数据包数量-{iFace}", $"NetWorkSend-{iFace}"); + DataHelper.AddMonitoringData(res, values[8], $"网络接口的使用率-{iFace}", $"NetWorkUsage-{iFace}"); + totalUsage += double.Parse(values[8]); } - _count++; - if (_count <= 10) return; - _count = 0; - await dataHelper.SaveData(netWorkDataListAll); + DataHelper.AddMonitoringData(res, totalUsage.ToString(CultureInfo.InvariantCulture), "网络接口的使用率-总", + "NetWorkUsage"); } } \ No newline at end of file diff --git a/LoongPanel-Asp/Jobs/ProcessJob.cs b/LoongPanel-Asp/Jobs/ProcessJob.cs index a0971b0..caeb2c3 100644 --- a/LoongPanel-Asp/Jobs/ProcessJob.cs +++ b/LoongPanel-Asp/Jobs/ProcessJob.cs @@ -1,106 +1,34 @@ using LoongPanel_Asp.Helpers; -using LoongPanel_Asp.Hubs; using LoongPanel_Asp.Models; using LoongPanel_Asp.Servers; -using Microsoft.AspNetCore.SignalR; using Quartz; namespace LoongPanel_Asp.Jobs; -public class ProcessTotalJob( - IHubContext hubContext, - IServiceProvider serviceProvider, - ApplicationDbContext dbContext) : IJob +public class ProcessTotalJob(DataService dataService, SshService sshService) : IiJob(dataService, sshService) { - private static int _count; - - public async Task Execute(IJobExecutionContext context) + protected override async Task ExecuteInternal(IJobExecutionContext context, ServerModel server, + SshService sshService, List res) { - var dataMap = context.JobDetail.JobDataMap; - var dataHelper = new DataHelper(dbContext,hubContext); - var serverList = (List)dataMap["executor"]; - var processDataListAll = new List(); - var sshClient = serviceProvider.GetService(); - foreach (var server in serverList) - { - var output = await sshClient?.ExecuteCommandAsync(server.Id, "ps", "-e", "|", "wc", "-l")!; - if (string.IsNullOrEmpty(output)) continue; - var processDataList = new List(); - var count = int.Parse(output); - var processTotalCount = new ServerMonitoringData - { - ServerId = server.Id, - Data = count.ToString(), - DataName = "进程总数", - DataType = "ProcessTotalCount" - }; - processDataList.Add(processTotalCount); - output = await sshClient?.ExecuteCommandAsync(server.Id, "ps", "-eLf", "|", "wc", "-l")!; - if (string.IsNullOrEmpty(output)) continue; - count = int.Parse(output); - var threadsTotalCount = new ServerMonitoringData - { - ServerId = server.Id, - Data = count.ToString(), - DataName = "线程总数", - DataType = "ThreadsTotalCount" - }; - processDataList.Add(threadsTotalCount); - - processDataList.ForEach(Action); - processDataListAll.AddRange(processDataList); - continue; - - async void Action(ServerMonitoringData data) - { - await hubContext.Clients.All.SendAsync("ReceiveData", data.ServerId, data.DataType, data.Data); - await dataHelper.CheckData(server.Id, data.DataType ?? "", data.Data ?? "", data.DataName); - } - } - - _count++; - if (_count <= 10) return; - _count = 0; - await dataHelper.SaveData(processDataListAll); + var output = await sshService.ExecuteCommandAsync(server.Id, "ps", "-e", "|", "wc", "-l"); + if (string.IsNullOrEmpty(output)) return; + var value = int.Parse(output).ToString(); + DataHelper.AddMonitoringData(res, value, "进程总数", "ProcessTotalCount"); + output = await sshService.ExecuteCommandAsync(server.Id, "ps", "-eLf", "|", "wc", "-l"); + if (string.IsNullOrEmpty(output)) return; + value = int.Parse(output).ToString(); + DataHelper.AddMonitoringData(res, value, "线程总数", "ThreadTotalCount"); } } -public class PhrasePatternJob( - IHubContext hubContext, - IServiceProvider serviceProvider, - ApplicationDbContext dbContext) : IJob +public class PhrasePatternJob(DataService dataService, SshService sshService) : IiJob(dataService, sshService) { - private static int _count; - - public async Task Execute(IJobExecutionContext context) + protected override async Task ExecuteInternal(IJobExecutionContext context, ServerModel server, + SshService sshService, List res) { - var dataMap = context.JobDetail.JobDataMap; - var dataHelper = new DataHelper(dbContext,hubContext); - var serverList = (List)dataMap["executor"]; - var processDataListAll = new List(); - var sshClient = serviceProvider.GetService(); - foreach (var server in serverList) - { - var output = await sshClient?.ExecuteCommandAsync(server.Id, "lsof", "|", "wc", "-l")!; - if (string.IsNullOrEmpty(output)) continue; - var count = int.Parse(output); - var phrasePatternCount = new ServerMonitoringData - { - ServerId = server.Id, - Data = count.ToString(), - DataName = "句柄", - DataType = "PhrasePatternCount" - }; - processDataListAll.Add(phrasePatternCount); - await hubContext.Clients.All.SendAsync("ReceiveData", server.Id, phrasePatternCount.DataType, - phrasePatternCount.Data); - await dataHelper.CheckData(server.Id, phrasePatternCount.DataType ?? "", phrasePatternCount.Data ?? "", - "句柄数"); - } - - _count++; - if (_count <= 10) return; - _count = 0; - await dataHelper.SaveData(processDataListAll); + var output = await sshService.ExecuteCommandAsync(server.Id, "lsof", "|", "wc", "-l"); + if (string.IsNullOrEmpty(output)) return; + var value = int.Parse(output).ToString(); + DataHelper.AddMonitoringData(res, value, "句柄", "PhrasePatternCount"); } } \ No newline at end of file diff --git a/LoongPanel-Asp/Jobs/SystemJob.cs b/LoongPanel-Asp/Jobs/SystemJob.cs new file mode 100644 index 0000000..eef8fb9 --- /dev/null +++ b/LoongPanel-Asp/Jobs/SystemJob.cs @@ -0,0 +1,18 @@ +namespace LoongPanel_Asp.Jobs; + +// public class SystemTimeIntervalLoadJob(DataService dataService, SshService sshService) : IiJob(dataService, sshService) +// { +// protected override async Task?> ExecuteInternal(IJobExecutionContext context, ServerModel server, SshService sshService) +// { +// var output = await sshService?.ExecuteCommandAsync(server.Id, "sar", "-u", "3 1", "|", "grep", "Average")!; +// if (string.IsNullOrEmpty(output)) return null; +// var totalUsage = new ServerMonitoringData +// { +// ServerId = server.Id, +// Data = "20", +// DataName = "CPU总使用率", +// DataType = "CpuTotalUsage" +// }; +// return new List { totalUsage }; +// } +// } \ No newline at end of file diff --git a/LoongPanel-Asp/Jobs/UserJob.cs b/LoongPanel-Asp/Jobs/UserJob.cs index 4ff5341..07e0471 100644 --- a/LoongPanel-Asp/Jobs/UserJob.cs +++ b/LoongPanel-Asp/Jobs/UserJob.cs @@ -1,76 +1,27 @@ using LoongPanel_Asp.Helpers; -using LoongPanel_Asp.Hubs; using LoongPanel_Asp.Models; using LoongPanel_Asp.Servers; -using Microsoft.AspNetCore.SignalR; using Quartz; namespace LoongPanel_Asp.Jobs; -public class UserTotalJob(IHubContext hubContext, - IServiceProvider serviceProvider, - ApplicationDbContext dbContext): IJob +public class UserTotalJob(DataService dataService, SshService sshService) : IiJob(dataService, sshService) { - private static int _count; - public async Task Execute(IJobExecutionContext context) + protected override async Task ExecuteInternal(IJobExecutionContext context, ServerModel server, + SshService sshService, List res) { - // 执行用户统计任务 - var dataMap = context.JobDetail.JobDataMap; - var dataHelper = new DataHelper(dbContext,hubContext); - var serverList = (List)dataMap["executor"]; - var userDataListAll = new List(); - var sshClient = serviceProvider.GetService(); - foreach (var server in serverList) + var output = await sshService.ExecuteCommandAsync(server.Id, + "ps -o ruser=userForLongName -eo user,pcpu,pmem,comm --sort=-pcpu | awk 'NR>1 && $1 !~ /^systemd/ {user[$1]+=$2; mem[$1]+=$3; count[$1]++; total[$1]=$2+$3} END {for (u in user) print u, user[u], mem[u]/count[u], count[u]}' | sort -k1,1r -k2,2nr"); + if (string.IsNullOrEmpty(output)) return; + var users = output.Split("\n", StringSplitOptions.RemoveEmptyEntries); + + foreach (var user in users) { - var output = await sshClient?.ExecuteCommandAsync(server.Id, "ps -o ruser=userForLongName -eo user,pcpu,pmem,comm --sort=-pcpu | awk 'NR>1 && $1 !~ /^systemd/ {user[$1]+=$2; mem[$1]+=$3; count[$1]++; total[$1]=$2+$3} END {for (u in user) print u, user[u], mem[u]/count[u], count[u]}' | sort -k1,1r -k2,2nr")!; - if (string.IsNullOrEmpty(output)) continue; - var lines = output.Split("\n",StringSplitOptions.RemoveEmptyEntries); - - foreach (var line in lines) - { - var d = line.Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToList(); - var name = d[0]; - var cpu = d[1]; - var mem = d[2]; - var command=d[3]; - var data = new ServerMonitoringData - { - ServerId = server.Id, - Data = cpu, - DataName = $"CPU使用率-{name}", - DataType = $"CpuUsage-{name}" - }; - userDataListAll.Add(data); - data = new ServerMonitoringData - { - ServerId = server.Id, - Data = mem, - DataName = $"内存使用率-{name}", - DataType = $"MemoryUsage-{name}" - }; - userDataListAll.Add(data); - data = new ServerMonitoringData - { - ServerId = server.Id, - Data = command, - DataName = $"用户进程数-{name}", - DataType = $"UserProcesses-{name}" - }; - userDataListAll.Add(data); - } - } - - userDataListAll.ForEach(Action); - _count++; - if (_count <= 10) return; - _count = 0; - await dataHelper.SaveData(userDataListAll); - return; - - async void Action(ServerMonitoringData data) - { - await hubContext.Clients.All.SendAsync("ReceiveData", data.ServerId, data.DataType, data.Data); - await dataHelper.CheckData(data.ServerId, data.DataType ?? "", data.Data ?? "", data.DataName); + var values = user.Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToList(); + var name = values[0]; + DataHelper.AddMonitoringData(res, values[1], $"CPU使用率-{name}", $"CpuUsage-{name}"); + DataHelper.AddMonitoringData(res, values[2], $"内存使用率-{name}", $"MemUsage-{name}"); + DataHelper.AddMonitoringData(res, values[3], $"用户进程数-{name}", $"UserProcessCount-{name}"); } } } \ No newline at end of file diff --git a/LoongPanel-Asp/LoongPanel-Asp.csproj b/LoongPanel-Asp/LoongPanel-Asp.csproj index 3e100c5..f633125 100755 --- a/LoongPanel-Asp/LoongPanel-Asp.csproj +++ b/LoongPanel-Asp/LoongPanel-Asp.csproj @@ -18,7 +18,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -35,23 +35,20 @@ PreserveNewest - PreserveNewest + PreserveNewest - PreserveNewest - - - PreserveNewest + PreserveNewest - + - - PreserveNewest - + + PreserveNewest + diff --git a/LoongPanel-Asp/Middlewares/ApiPermissionMiddleware.cs b/LoongPanel-Asp/Middlewares/ApiPermissionMiddleware.cs index 838906b..95e9f27 100755 --- a/LoongPanel-Asp/Middlewares/ApiPermissionMiddleware.cs +++ b/LoongPanel-Asp/Middlewares/ApiPermissionMiddleware.cs @@ -16,13 +16,13 @@ public class ApiPermissionMiddleware( // 获取配置中定义的公开API列表 var publicApis = configuration["PublicApi"]?.Split(";", StringSplitOptions.RemoveEmptyEntries) ?? []; - + if (publicApis.Any(api => context.Request.Path.Value == api)) { await next(context); return; } - + if (context.Request.Path.Value!.StartsWith("/public")) { await next(context); @@ -84,14 +84,10 @@ public class ApiPermissionMiddleware( // 判断请求是否拥有权限 if (!apiPermissions.Any(x => context.Request.Path.Value != null && context.Request.Path.Value.StartsWith(x))) - { await ForbiddenResponse(context); - } else - { // 请求拥有权限,调用下一个中间件 await next(context); - } } catch (Exception ex) { diff --git a/LoongPanel-Asp/Middlewares/PermissionMiddleware.cs b/LoongPanel-Asp/Middlewares/PermissionMiddleware.cs index 4973464..6cdf2b0 100755 --- a/LoongPanel-Asp/Middlewares/PermissionMiddleware.cs +++ b/LoongPanel-Asp/Middlewares/PermissionMiddleware.cs @@ -18,6 +18,7 @@ public class PermissionMiddleware( await next(context); return; } + Console.WriteLine(context.Request.Path.Value!); //如果访问 /public/* if (context.Request.Path.Value!.StartsWith("/public")) @@ -25,7 +26,7 @@ public class PermissionMiddleware( await next(context); return; } - + // 获取请求头中的Authorization信息 var authorizationHeader = context.Request.Headers["Authorization"]; diff --git a/LoongPanel-Asp/Models/AccountModel.cs b/LoongPanel-Asp/Models/AccountModel.cs index e4ee375..ace898b 100755 --- a/LoongPanel-Asp/Models/AccountModel.cs +++ b/LoongPanel-Asp/Models/AccountModel.cs @@ -5,7 +5,6 @@ public class EmailModel public required string Email { get; set; } } - public class RegisterModel : EmailModel { public required string UserName { get; set; } diff --git a/LoongPanel-Asp/Models/OrderType.cs b/LoongPanel-Asp/Models/OrderType.cs index 0a759df..44bf9ee 100755 --- a/LoongPanel-Asp/Models/OrderType.cs +++ b/LoongPanel-Asp/Models/OrderType.cs @@ -7,10 +7,9 @@ public class Property public int? Order { get; set; } } - public class ServerModel { - public required string Id { get;init; } + public required string Id { get; init; } public required string Address { get; set; } public required int Port { get; set; } public required string ServerName { get; set; } @@ -19,11 +18,10 @@ public class ServerModel public required bool Http { get; set; } } - public class EmailSettings { - public required string Host {get;init;} - public required string Port {get;init;} - public required string Username {get;init;} - public required string Password {get;init;} + public required string Host { get; init; } + public required string Port { get; init; } + public required string Username { get; init; } + public required string Password { get; init; } } \ No newline at end of file diff --git a/LoongPanel-Asp/Program.cs b/LoongPanel-Asp/Program.cs index bdec315..81ddecc 100755 --- a/LoongPanel-Asp/Program.cs +++ b/LoongPanel-Asp/Program.cs @@ -3,10 +3,8 @@ using LoongPanel_Asp; using LoongPanel_Asp.Helpers; using LoongPanel_Asp.Hubs; using LoongPanel_Asp.Middlewares; -using LoongPanel_Asp.Models; using LoongPanel_Asp.Servers; using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Identity.UI.Services; using Microsoft.EntityFrameworkCore; using Quartz; using Quartz.AspNetCore; @@ -77,7 +75,8 @@ builder.Services.AddCors(options => { //允许全部 policy.WithOrigins("http://localhost:3001", "http://192.168.1.22:3001", "http://192.168.1.22:3001", - "https://192.168.0.22:3000","https://loongpanel.xn--7p0a.site").AllowAnyHeader().AllowAnyMethod().AllowCredentials(); + "https://192.168.0.22:3000", "https://loongpanel.xn--7p0a.site").AllowAnyHeader().AllowAnyMethod() + .AllowCredentials(); }); }); @@ -104,13 +103,11 @@ builder.Services.AddQuartzServer(options => builder.Services.AddScoped(); builder.Services.AddSingleton(); +builder.Services.AddSingleton(); builder.Services.AddHostedService(); - - - var app = builder.Build(); // Configure the HTTP request pipeline. diff --git a/LoongPanel-Asp/Servers/DataService.cs b/LoongPanel-Asp/Servers/DataService.cs new file mode 100644 index 0000000..b1510f0 --- /dev/null +++ b/LoongPanel-Asp/Servers/DataService.cs @@ -0,0 +1,46 @@ +using LoongPanel_Asp.Hubs; +using Microsoft.AspNetCore.SignalR; + +namespace LoongPanel_Asp.Servers; + +public class DataService(IServiceProvider serviceProvider, IHubContext context) : IDisposable +{ + //创建一个存储 + private static readonly Dictionary ServerMonitoringData = new(); + + public void Dispose() + { + Submit().Wait(); + } + + public async Task Save(ServerMonitoringData data) + { + data.Time = DateTime.UtcNow; + ServerMonitoringData[$"{data.DataType}-{data.ServerId}"] = data; + await context.Clients.All.SendAsync("ReceiveData", data.ServerId, data.DataType, data.Data); + } + + public async Task Save(List datas) + { + foreach (var data in datas) + { + data.Time = DateTime.UtcNow; + ServerMonitoringData[$"{data.DataType}-{data.ServerId}"] = data; + await context.Clients.All.SendAsync("ReceiveData", data.ServerId, data.DataType, data.Data); + } + } + + //提交 + public async Task Submit() + { + var dbContext = serviceProvider.GetRequiredService(); + var dataDb = dbContext.ServerMonitoringData; + await dataDb.AddRangeAsync(ServerMonitoringData.Values); + await dbContext.SaveChangesAsync(); + ServerMonitoringData.Clear(); + } + + private async Task CheckData() + { + } +} \ No newline at end of file diff --git a/LoongPanel-Asp/Servers/EmailService.cs b/LoongPanel-Asp/Servers/EmailService.cs index a9fa79c..fdb1854 100644 --- a/LoongPanel-Asp/Servers/EmailService.cs +++ b/LoongPanel-Asp/Servers/EmailService.cs @@ -1,54 +1,61 @@ using System.Collections.Concurrent; -using System.Net; -using LoongPanel_Asp.Models; using MimeKit; using SmtpClient = MailKit.Net.Smtp.SmtpClient; namespace LoongPanel_Asp.Servers; -public class EmailService:IDisposable +public class EmailService : IDisposable { - - private readonly SmtpClient _smtpClient; private readonly IConfigurationSection _emailSettings; + + private readonly SmtpClient _smtpClient; + //创建一个验证码缓存字典 private readonly ConcurrentDictionary _verifyCodeCache = new(); + public EmailService(IConfigurationSection emailSettings) { _emailSettings = emailSettings; // 初始化SmtpClient _smtpClient = new SmtpClient(); - _smtpClient.Connect(_emailSettings["Host"], int.Parse(_emailSettings["Port"] ?? throw new InvalidOperationException()), true); + _smtpClient.Connect(_emailSettings["Host"], + int.Parse(_emailSettings["Port"] ?? throw new InvalidOperationException()), true); _smtpClient.Authenticate(_emailSettings["Username"], _emailSettings["Password"]); } - - + + public void Dispose() + { + _smtpClient.Dispose(); + } + + //发送邮件 - public async Task SendEmailAsync(string toAddress,string toName, string subject, string body) + public async Task SendEmailAsync(string toAddress, string toName, string subject, string body) { using var mailMessage = new MimeMessage(); - mailMessage.From.Add(new MailboxAddress("龙盾云御",_emailSettings["Username"])); + mailMessage.From.Add(new MailboxAddress("龙盾云御", _emailSettings["Username"])); mailMessage.To.Add(new MailboxAddress(toName, toAddress)); mailMessage.Subject = subject; var bodyBuilder = new BodyBuilder { - HtmlBody = body, + HtmlBody = body }; mailMessage.Body = bodyBuilder.ToMessageBody(); await _smtpClient.SendAsync(mailMessage); } - - + + //发送邮箱验证码 - public async Task SendEmailVerifyCodeAsync( string userId,string toAddress, string toName) + public async Task SendEmailVerifyCodeAsync(string userId, string toAddress, string toName) { const string subject = "龙盾云御邮箱验证码"; - var code=GenerateVerifyCode(); + var code = GenerateVerifyCode(); var body = $"

您的验证码是:{code}

"; await SendEmailAsync(toAddress, toName, subject, body); //存入缓存 _verifyCodeCache.AddOrUpdate(userId, code, (key, oldValue) => code); } + //验证邮箱验证码 public bool VerifyEmailVerifyCode(string userId, string code) { @@ -57,8 +64,8 @@ public class EmailService:IDisposable _verifyCodeCache.TryRemove(userId, out _); return true; } - - + + //生成6位随机验证码 private static string GenerateVerifyCode() { @@ -66,9 +73,4 @@ public class EmailService:IDisposable var verifyCode = random.Next(100000, 999999).ToString(); return verifyCode; } - - public void Dispose() - { - throw new NotImplementedException(); - } } \ No newline at end of file diff --git a/LoongPanel-Asp/Servers/SSHService.cs b/LoongPanel-Asp/Servers/SSHService.cs index dc5cf3b..c3468c0 100755 --- a/LoongPanel-Asp/Servers/SSHService.cs +++ b/LoongPanel-Asp/Servers/SSHService.cs @@ -1,5 +1,4 @@ using LoongPanel_Asp.Helpers; -using LoongPanel_Asp.Models; using Renci.SshNet; using ConnectionInfo = Renci.SshNet.ConnectionInfo; @@ -30,12 +29,13 @@ public class SshService : IDisposable private void LoadServerConfigurations() { // 从数据库中加载服务器配置信息 - var serverConfigurations=JobConfigHelper.GetServers(); + var serverConfigurations = JobConfigHelper.GetServers(); foreach (var serverConfiguration in serverConfigurations) { var connectionInfo = new ConnectionInfo(serverConfiguration.Address, serverConfiguration.Port, - serverConfiguration.Username, new PasswordAuthenticationMethod(serverConfiguration.Username, serverConfiguration.Password)); + serverConfiguration.Username, + new PasswordAuthenticationMethod(serverConfiguration.Username, serverConfiguration.Password)); _serverConnectionInfos[serverConfiguration.Id] = connectionInfo; var sshClient = new SshClient(connectionInfo); // 设置超时时间 diff --git a/LoongPanel-Asp/Servers/SSHStreamService.cs b/LoongPanel-Asp/Servers/SSHStreamService.cs index 60ed048..3539df0 100644 --- a/LoongPanel-Asp/Servers/SSHStreamService.cs +++ b/LoongPanel-Asp/Servers/SSHStreamService.cs @@ -1,95 +1,25 @@ -using Renci.SshNet; -using System; -using System.Collections.Concurrent; -using System.IO; +using System.Collections.Concurrent; using LoongPanel_Asp.Helpers; using LoongPanel_Asp.Hubs; using Microsoft.AspNetCore.SignalR; +using Renci.SshNet; using ConnectionInfo = Renci.SshNet.ConnectionInfo; namespace LoongPanel_Asp.Servers; public class SshStreamService : IDisposable { - private readonly ConcurrentDictionary _sshStreams = new(); private readonly IHubContext _hubContext; - private CancellationTokenSource _cancellationTokenSource; - private Task _readingTask; - + private readonly ConcurrentDictionary _sshStreams = new(); + private readonly CancellationTokenSource _cancellationTokenSource; + private readonly Task _readingTask; + public SshStreamService(IHubContext hubContext) { _hubContext = hubContext; _cancellationTokenSource = new CancellationTokenSource(); _readingTask = Task.Run(() => StartReadingAsync(_cancellationTokenSource.Token)); } - public void Connect(string userId, string serverId) - { - // 假设 JobConfigHelper.GetServers() 返回一个包含服务器配置的列表 - var serverConfig = JobConfigHelper.GetServers().Find(x => x.Id == serverId); - if (serverConfig == null) throw new InvalidOperationException("Server not found."); - //从_sshStreams查找是否存在 替换 - - var host = serverConfig.Address; - var port = serverConfig.Port; - var username = serverConfig.Username; - var password = serverConfig.Password; - - var connectionInfo = new ConnectionInfo(host, port, username, new PasswordAuthenticationMethod(username, password)); - var sshClient = new SshClient(connectionInfo); - sshClient.Connect(); - var shellStream = sshClient.CreateShellStream("xterm", 100, 40, 800, 600, 1024); - if (_sshStreams.TryGetValue(userId, out var existing)) - { - // 关闭旧的连接 - existing.Client.Disconnect(); - existing.Client.Dispose(); - existing.Stream.Close(); - existing.Stream.Dispose(); - } - - _sshStreams[userId]= (sshClient, shellStream); - } - - public void ReSize(string userId,int col, int row) - { - //从sshStreams中获取对象 - if (_sshStreams.TryGetValue(userId, out var tuple)) - { - var (ssh, stream) = tuple; - if (ssh.IsConnected) - { - var ansiResizeCommand = $"stty cols {col}; stty rows {row}"; - stream.WriteLine(ansiResizeCommand); - } - else - { - throw new InvalidOperationException("SSH client is not connected or shell stream is not available."); - } - } - else - { - throw new InvalidOperationException("SSH connection not found for the given user ID."); - } - } - - public void Write(string userId, string data) - { - if (!_sshStreams.TryGetValue(userId, out var sshStreamInfo)) return; - var (_, shellStream) = sshStreamInfo; - shellStream?.Write(data); - } - - public void Disconnect(string userId) - { - if (_sshStreams.TryRemove(userId, out var sshStreamInfo)) - { - var (sshClient, shellStream) = sshStreamInfo; - shellStream?.Close(); - shellStream?.Dispose(); - sshClient.Disconnect(); - sshClient.Dispose(); - } - } public void Dispose() { @@ -111,9 +41,80 @@ public class SshStreamService : IDisposable sshClient.Disconnect(); sshClient.Dispose(); } + _sshStreams.Clear(); } - + + public void Connect(string userId, string serverId) + { + // 假设 JobConfigHelper.GetServers() 返回一个包含服务器配置的列表 + var serverConfig = JobConfigHelper.GetServers().Find(x => x.Id == serverId); + if (serverConfig == null) throw new InvalidOperationException("Server not found."); + //从_sshStreams查找是否存在 替换 + + var host = serverConfig.Address; + var port = serverConfig.Port; + var username = serverConfig.Username; + var password = serverConfig.Password; + + var connectionInfo = + new ConnectionInfo(host, port, username, new PasswordAuthenticationMethod(username, password)); + var sshClient = new SshClient(connectionInfo); + sshClient.Connect(); + var shellStream = sshClient.CreateShellStream("xterm", 100, 40, 800, 600, 1024); + if (_sshStreams.TryGetValue(userId, out var existing)) + { + // 关闭旧的连接 + existing.Client.Disconnect(); + existing.Client.Dispose(); + existing.Stream.Close(); + existing.Stream.Dispose(); + } + + _sshStreams[userId] = (sshClient, shellStream); + } + + public void ReSize(string userId, int col, int row) + { + //从sshStreams中获取对象 + if (_sshStreams.TryGetValue(userId, out var tuple)) + { + var (ssh, stream) = tuple; + if (ssh.IsConnected) + { + var ansiResizeCommand = $"stty cols {col}; stty rows {row}"; + stream.WriteLine(ansiResizeCommand); + } + else + { + throw new InvalidOperationException("SSH client is not connected or shell stream is not available."); + } + } + else + { + throw new InvalidOperationException("SSH connection not found for the given user ID."); + } + } + + public void Write(string userId, string data) + { + if (!_sshStreams.TryGetValue(userId, out var sshStreamInfo)) return; + var (_, shellStream) = sshStreamInfo; + shellStream?.Write(data); + } + + public void Disconnect(string userId) + { + if (_sshStreams.TryRemove(userId, out var sshStreamInfo)) + { + var (sshClient, shellStream) = sshStreamInfo; + shellStream?.Close(); + shellStream?.Dispose(); + sshClient.Disconnect(); + sshClient.Dispose(); + } + } + private async Task StartReadingAsync(CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested) diff --git a/LoongPanel-Asp/markdowns/templates/值班记录.md b/LoongPanel-Asp/markdowns/templates/值班记录.md index 7957a64..0443987 100644 --- a/LoongPanel-Asp/markdowns/templates/值班记录.md +++ b/LoongPanel-Asp/markdowns/templates/值班记录.md @@ -1,26 +1,26 @@ -| ֵ¼ | col | col | col | col | col | -| -------- | ------- | ------- | ------- | ------- | ------- | -| content | content | content | content | content | content | -| content | content | content | content | content | content | -| content | content | content | content | content | content | -| content | content | content | content | content | content | -| content | content | content | content | content | content | -| content | content | content | content | content | content | -| content | content | content | content | content | content | -| content | content | content | content | content | content | -| content | content | content | content | content | content | -| content | content | content | content | content | content | -| content | content | content | content | content | content | -| content | content | content | content | content | content | -| content | content | content | content | content | content | -| content | content | content | content | content | content | -| content | content | content | content | content | content | -| content | content | content | content | content | content | -| content | content | content | content | content | content | -| content | content | content | content | content | content | -| content | content | content | content | content | content | -| content | content | content | content | content | content | -| content | content | content | content | content | content | -| content | content | content | content | content | content | -| content | content | content | content | content | content | -| content | content | content | content | content | content | \ No newline at end of file +| ֵ���¼ | col | col | col | col | col | +|---------|---------|---------|---------|---------|---------| +| content | content | content | content | content | content | +| content | content | content | content | content | content | +| content | content | content | content | content | content | +| content | content | content | content | content | content | +| content | content | content | content | content | content | +| content | content | content | content | content | content | +| content | content | content | content | content | content | +| content | content | content | content | content | content | +| content | content | content | content | content | content | +| content | content | content | content | content | content | +| content | content | content | content | content | content | +| content | content | content | content | content | content | +| content | content | content | content | content | content | +| content | content | content | content | content | content | +| content | content | content | content | content | content | +| content | content | content | content | content | content | +| content | content | content | content | content | content | +| content | content | content | content | content | content | +| content | content | content | content | content | content | +| content | content | content | content | content | content | +| content | content | content | content | content | content | +| content | content | content | content | content | content | +| content | content | content | content | content | content | +| content | content | content | content | content | content | \ No newline at end of file diff --git a/LoongPanel-Asp/markdowns/templates/巡检模板1.md b/LoongPanel-Asp/markdowns/templates/巡检模板1.md index 990661d..ff231ed 100644 --- a/LoongPanel-Asp/markdowns/templates/巡检模板1.md +++ b/LoongPanel-Asp/markdowns/templates/巡检模板1.md @@ -8,21 +8,21 @@ ## 第二部分:巡检项目 -| 序号 | 巡检项目名称 | 巡检要点 | 巡检内容 | -| ---- | ------------ | -------------------------------------------------- | -------------------------------------------------------------- | -| 1 | 设备运行状况 | 检查设备运行是否平稳,有无异常振动或噪音。 | 详细记录设备运行参数,比较历史数据,分析是否存在异常。 | -| 2 | 安全防护措施 | 检查安全防护设施是否完好,如安全栅栏、警示标志等。 | 确认所有安全设施无损坏,位置正确,且工作人员了解如何正确使用。 | -| 3 | 环境卫生状况 | 检查工作区域是否清洁,有无垃圾或障碍物。 | 清理工作区域,确保无杂物,保持环境整洁。 | -|...|.....|....|...| +| 序号 | 巡检项目名称 | 巡检要点 | 巡检内容 | +|-----|--------|---------------------------|---------------------------------| +| 1 | 设备运行状况 | 检查设备运行是否平稳,有无异常振动或噪音。 | 详细记录设备运行参数,比较历史数据,分析是否存在异常。 | +| 2 | 安全防护措施 | 检查安全防护设施是否完好,如安全栅栏、警示标志等。 | 确认所有安全设施无损坏,位置正确,且工作人员了解如何正确使用。 | +| 3 | 环境卫生状况 | 检查工作区域是否清洁,有无垃圾或障碍物。 | 清理工作区域,确保无杂物,保持环境整洁。 | +| ... | ..... | .... | ... | ## 第三部分:检查记录 -| 序号 | 检查项目 | 检查结果 | 异常说明 | 处理措施 | 反馈意见 | -| ---- | -------- | -------- | ---------------- | ------------------------------ | ---------------------- | -| 1 | 外壳 | 正常 | 无 | 无 | 无 | -| 2 | 电源 | 异常 | 设备有轻微振动。 | 已联系维修人员,计划明日检修。 | 建议增加设备维护频率。 | -| 3 | 主机 | 正常 | 无 | 无 | 无 | -|...|.....|....|...|...|...| +| 序号 | 检查项目 | 检查结果 | 异常说明 | 处理措施 | 反馈意见 | +|-----|-------|------|----------|-----------------|-------------| +| 1 | 外壳 | 正常 | 无 | 无 | 无 | +| 2 | 电源 | 异常 | 设备有轻微振动。 | 已联系维修人员,计划明日检修。 | 建议增加设备维护频率。 | +| 3 | 主机 | 正常 | 无 | 无 | 无 | +| ... | ..... | .... | ... | ... | ... | ## 第四部分:巡检总结 diff --git a/web/components/Cards/MiniCard.vue b/web/components/Cards/MiniCard.vue index 54f8471..bee3d93 100755 --- a/web/components/Cards/MiniCard.vue +++ b/web/components/Cards/MiniCard.vue @@ -70,9 +70,9 @@ dataStore.$subscribe((_, state) => { - - {{ i }} - + + 这里什么都没有 + diff --git a/web/components/Grid/MainGrid.vue b/web/components/Grid/MainGrid.vue index 40e9287..eaa2c1e 100644 --- a/web/components/Grid/MainGrid.vue +++ b/web/components/Grid/MainGrid.vue @@ -108,6 +108,9 @@ watchDebounced( diff --git a/web/components/Term.vue b/web/components/Term.vue index 9d2ee59..076ee53 100644 --- a/web/components/Term.vue +++ b/web/components/Term.vue @@ -64,9 +64,9 @@ onMounted(async () => { .then(() => { console.log("Terminal created") }) - setTimeout(()=>{ - connection.invoke("SendMessage","neofetch\n") - },200) + // setTimeout(()=>{ + // connection.invoke("SendMessage","neofetch\n") + // },200) }) const resize=()=>{ @@ -125,9 +125,9 @@ const resize=()=>{ height: 500px; max-width: 80vw; max-height: 80vh; - border-radius: $radius; - background: rgba(0,0,0,.5); - backdrop-filter: blur(20px) + border-radius: $radius*2; + backdrop-filter: blur(20px); + border: 2px solid #fff; } #terminal { diff --git a/web/layouts/Login.vue b/web/layouts/Login.vue index 6be2719..22391d0 100755 --- a/web/layouts/Login.vue +++ b/web/layouts/Login.vue @@ -25,7 +25,6 @@ onMounted(() => { width: 100%; padding: 32px; gap: 32px; - background: unset; display: grid; grid-template-columns: 1fr minmax(800px,1fr); grid-template-rows: 1fr; diff --git a/web/layouts/Main.vue b/web/layouts/Main.vue index c284df5..d75f069 100755 --- a/web/layouts/Main.vue +++ b/web/layouts/Main.vue @@ -199,7 +199,6 @@ onKeyStroke('Shift', (e) => { -
diff --git a/web/nuxt.config.ts b/web/nuxt.config.ts index 9f6c9c6..d4c974c 100755 --- a/web/nuxt.config.ts +++ b/web/nuxt.config.ts @@ -68,7 +68,8 @@ export default defineNuxtConfig({ css: ['assets/min.scss', 'vue-toastification/dist/index.css'], devServer: { - port: 3001, host: '0.0.0.0', + port: 3001, + // host: '0.0.0.0', // https: { // key: "./localhost+3-key.pem", // cert: "./localhost+3.pem",