From 54bbfe2fe4cb42f4612fce33a72199fb09ac071a Mon Sep 17 00:00:00 2001
From: lq1405 <2769838458@qq.com>
Date: Fri, 27 Dec 2024 21:50:13 +0800
Subject: [PATCH] =?UTF-8?q?V1.0.2=20=20=E6=96=B0=E5=A2=9E=E8=BD=AF?=
=?UTF-8?q?=E4=BB=B6=E7=AE=A1=E7=90=86=E6=9D=83=E9=99=90=EF=BC=8C=E6=96=B0?=
=?UTF-8?q?=E5=A2=9E=EF=BC=8C=E5=88=A0=E9=99=A4=EF=BC=8C=E7=AE=A1=E7=90=86?=
=?UTF-8?q?=E7=AD=89=EF=BC=8C=E8=BF=98=E6=9C=89=E8=BD=AF=E4=BB=B6=E6=8E=A7?=
=?UTF-8?q?=E5=88=B6=E6=9D=83=E9=99=90=E7=AD=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
LMS.Common/Attributes/NotEmptyAttribute.cs | 22 +
LMS.Common/Enum/ResponseCodeEnum.cs | 9 +
LMS.Common/Enum/SoftwareControlEnum.cs | 31 ++
LMS.DAO/ApplicationDbContext.cs | 8 +
LMS.DAO/UserDAO/UserBasicDAO.cs | 24 +-
LMS.Repository/DB/Software.cs | 41 ++
LMS.Repository/DB/SoftwareControl.cs | 45 ++
LMS.Repository/DB/UserSoftware.cs | 22 +
.../DTO/Software/SoftwareBasicDto.cs | 13 +
.../DTO/Software/SoftwareCollectionDto.cs | 44 ++
.../Software/SoftwareControlCollectionDto.cs | 47 ++
LMS.Repository/DTO/UserDto/UserBaseDto.cs | 7 +
LMS.Repository/Software/AddSoftwareModel.cs | 22 +
.../ModifySoftwareControlValidityModel.cs | 11 +
LMS.Repository/User/LoginResponse.cs | 21 +
.../Configuration/ServiceConfiguration.cs | 3 +
LMS.service/Controllers/SoftWareController.cs | 228 ++++++++-
LMS.service/Controllers/UserController.cs | 24 +-
.../Middleware/DynamicPermissionMiddleware.cs | 1 +
LMS.service/LMS.service.csproj | 2 +-
.../SoftwareService/SoftwareControlService.cs | 442 ++++++++++++++++++
.../SoftwareService/SoftwareService.cs | 320 +++++++++++++
.../Service/UserService/LoginService.cs | 164 ++++++-
SQL/v1.0.2/Software.sql | 37 ++
SQL/v1.0.2/SoftwareControl.sql | 38 ++
SQL/v1.0.2/UserSoftware.sql | 32 ++
26 files changed, 1625 insertions(+), 33 deletions(-)
create mode 100644 LMS.Common/Attributes/NotEmptyAttribute.cs
create mode 100644 LMS.Common/Enum/SoftwareControlEnum.cs
create mode 100644 LMS.Repository/DB/Software.cs
create mode 100644 LMS.Repository/DB/SoftwareControl.cs
create mode 100644 LMS.Repository/DB/UserSoftware.cs
create mode 100644 LMS.Repository/DTO/Software/SoftwareBasicDto.cs
create mode 100644 LMS.Repository/DTO/Software/SoftwareCollectionDto.cs
create mode 100644 LMS.Repository/DTO/Software/SoftwareControlCollectionDto.cs
create mode 100644 LMS.Repository/Software/AddSoftwareModel.cs
create mode 100644 LMS.Repository/Software/ModifySoftwareControlValidityModel.cs
create mode 100644 LMS.Repository/User/LoginResponse.cs
create mode 100644 LMS.service/Service/SoftwareService/SoftwareControlService.cs
create mode 100644 LMS.service/Service/SoftwareService/SoftwareService.cs
create mode 100644 SQL/v1.0.2/Software.sql
create mode 100644 SQL/v1.0.2/SoftwareControl.sql
create mode 100644 SQL/v1.0.2/UserSoftware.sql
diff --git a/LMS.Common/Attributes/NotEmptyAttribute.cs b/LMS.Common/Attributes/NotEmptyAttribute.cs
new file mode 100644
index 0000000..a43fb93
--- /dev/null
+++ b/LMS.Common/Attributes/NotEmptyAttribute.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LMS.Common.Attributes
+{
+ [AttributeUsage(AttributeTargets.Property)]
+ public class NotEmptyAttribute : ValidationAttribute
+ {
+ protected override ValidationResult IsValid(object value, ValidationContext validationContext)
+ {
+ if (value is string str && string.IsNullOrWhiteSpace(str))
+ {
+ return new ValidationResult(ErrorMessage ?? "字段不能为空");
+ }
+ return ValidationResult.Success;
+ }
+ }
+}
diff --git a/LMS.Common/Enum/ResponseCodeEnum.cs b/LMS.Common/Enum/ResponseCodeEnum.cs
index 3f04303..a41e529 100644
--- a/LMS.Common/Enum/ResponseCodeEnum.cs
+++ b/LMS.Common/Enum/ResponseCodeEnum.cs
@@ -77,6 +77,11 @@ namespace LMS.Common.Enums
[Description("无效的邀请码")]
InvalidAffiliateCode = 1014,
+ // 无效token
+ [Result("无效token")]
+ [Description("无效token")]
+ InvalidToken = 1015,
+
#endregion
#region Machine 操作失败
@@ -141,6 +146,10 @@ namespace LMS.Common.Enums
[Result(ResponseString.InvalidOptions)]
[Description(ResponseString.InvalidOptions)]
InvalidOptions = 5002,
+
+ [Result(ResponseString.IdDateNotFound)]
+ [Description(ResponseString.IdDateNotFound)]
+ IdDateNotFound = 5003,
#endregion
#region 提示词操作失败
diff --git a/LMS.Common/Enum/SoftwareControlEnum.cs b/LMS.Common/Enum/SoftwareControlEnum.cs
new file mode 100644
index 0000000..7a04ac0
--- /dev/null
+++ b/LMS.Common/Enum/SoftwareControlEnum.cs
@@ -0,0 +1,31 @@
+namespace LMS.Common.Enum
+{
+ public class SoftwareControlEnum
+ {
+ public enum SoftwareControlValidityEnum
+ {
+ ///
+ /// 0
+ ///
+ Zero = 0,
+ ///
+ /// 一个月
+ ///
+ Thirty = 30,
+ ///
+ /// 三个月
+ ///
+ Ninety = 90,
+
+ ///
+ /// 六个月
+ ///
+ OneHundredAndEighty = 180,
+ ///
+ /// 一年
+ ///
+ ThreeHundredAndSixtyFive = 365,
+
+ }
+ }
+}
diff --git a/LMS.DAO/ApplicationDbContext.cs b/LMS.DAO/ApplicationDbContext.cs
index 5d8fff3..6c45f11 100644
--- a/LMS.DAO/ApplicationDbContext.cs
+++ b/LMS.DAO/ApplicationDbContext.cs
@@ -34,6 +34,12 @@ namespace LMS.DAO
public DbSet Options { get; set; }
+ public DbSet Software { get; set; }
+
+ public DbSet UserSoftware { get; set; }
+
+ public DbSet SoftwareControl { get; set; }
+
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
@@ -47,6 +53,8 @@ namespace LMS.DAO
? new List() // 如果存储的是空字符串或空数组,则返回空列表
: JsonSerializer.Deserialize>(v, (JsonSerializerOptions?)null) ?? new List()
);
+ modelBuilder.Entity()
+ .HasKey(us => new { us.UserId, us.SoftwareId });
}
}
}
diff --git a/LMS.DAO/UserDAO/UserBasicDAO.cs b/LMS.DAO/UserDAO/UserBasicDAO.cs
index efdcc69..2c18e3a 100644
--- a/LMS.DAO/UserDAO/UserBasicDAO.cs
+++ b/LMS.DAO/UserDAO/UserBasicDAO.cs
@@ -1,11 +1,5 @@
using LMS.Repository.Models.DB;
using Microsoft.AspNetCore.Identity;
-using OneOf.Types;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace LMS.DAO.UserDAO
{
@@ -43,6 +37,24 @@ namespace LMS.DAO.UserDAO
bool isAdminOrSuperAdmin = await _userManager.IsInRoleAsync(user, "Admin") || await _userManager.IsInRoleAsync(user, "Super Admin");
return isAdminOrSuperAdmin;
}
+
+ ///
+ /// 检查用户是不是超级管理员
+ ///
+ ///
+ ///
+ ///
+ public async Task CheckUserIsSuperAdmin(long? userId)
+ {
+ if (userId == null)
+ {
+ return false;
+ }
+ User? user = await _userManager.FindByIdAsync(userId.ToString() ?? "0") ?? throw new Exception("用户不存在");
+
+ bool isSuperAdmin = await _userManager.IsInRoleAsync(user, "Super Admin");
+ return isSuperAdmin;
+ }
}
}
diff --git a/LMS.Repository/DB/Software.cs b/LMS.Repository/DB/Software.cs
new file mode 100644
index 0000000..733f083
--- /dev/null
+++ b/LMS.Repository/DB/Software.cs
@@ -0,0 +1,41 @@
+namespace LMS.Repository.DB;
+
+public class Software
+{
+ ///
+ /// ID
+ ///
+ public string Id { get; set; }
+ ///
+ /// 软件名称
+ ///
+ public string SoftwareName { get; set; }
+ ///
+ /// 软件代码
+ ///
+ public string SoftwareCode { get; set; }
+ ///
+ /// 创建用户ID
+ ///
+ public long CreatedUserId { get; set; }
+ ///
+ /// 更新用户ID
+ ///
+ public long UpdatedUserId { get; set; }
+ ///
+ /// 创建时间
+ ///
+ public DateTime CreatedTime { get; set; }
+ ///
+ /// 更新时间
+ ///
+ public DateTime UpdatedTime { get; set; }
+ ///
+ /// 备注
+ ///
+ public string Remark { get; set; }
+ ///
+ /// 是否启用
+ ///
+ public bool IsUse { get; set; }
+}
diff --git a/LMS.Repository/DB/SoftwareControl.cs b/LMS.Repository/DB/SoftwareControl.cs
new file mode 100644
index 0000000..0f584e1
--- /dev/null
+++ b/LMS.Repository/DB/SoftwareControl.cs
@@ -0,0 +1,45 @@
+namespace LMS.Repository.DB;
+
+public class SoftwareControl
+{
+ ///
+ /// ID
+ ///
+ public string Id { get; set; }
+ ///
+ /// 用户ID
+ ///
+ public long UserId { get; set; }
+ ///
+ /// 软件ID
+ ///
+ public string SoftwareId { get; set; }
+ ///
+ /// 创建用户ID
+ ///
+ public long CreatedUserId { get; set; }
+ ///
+ /// 创建时间
+ ///
+ public DateTime CreatedTime { get; set; }
+ ///
+ /// 更新用户ID
+ ///
+ public long UpdatedUserId { get; set; }
+ ///
+ /// 更新时间
+ ///
+ public DateTime UpdatedTime { get; set; }
+ ///
+ /// 备注
+ ///
+ public string Remark { get; set; }
+ ///
+ /// 到期时间
+ ///
+ public DateTime? ExpirationTime { get; set; }
+ ///
+ /// 是否永久
+ ///
+ public bool IsForever { get; set; }
+}
diff --git a/LMS.Repository/DB/UserSoftware.cs b/LMS.Repository/DB/UserSoftware.cs
new file mode 100644
index 0000000..f6d75ed
--- /dev/null
+++ b/LMS.Repository/DB/UserSoftware.cs
@@ -0,0 +1,22 @@
+namespace LMS.Repository.DB;
+
+public class UserSoftware
+{
+ ///
+ /// 用户ID
+ ///
+ public long UserId { get; set; }
+ ///
+ /// 软件ID
+ ///
+ public string SoftwareId { get; set; }
+ ///
+ ///
+ ///
+ public string MachineId { get; set; }
+
+ ///
+ /// 软件控制ID
+ ///
+ public string SoftwareControlId { get; set; }
+}
diff --git a/LMS.Repository/DTO/Software/SoftwareBasicDto.cs b/LMS.Repository/DTO/Software/SoftwareBasicDto.cs
new file mode 100644
index 0000000..41c1eb1
--- /dev/null
+++ b/LMS.Repository/DTO/Software/SoftwareBasicDto.cs
@@ -0,0 +1,13 @@
+namespace LMS.Repository.DTO.Software
+{
+ public class SoftwareBasicDto
+ {
+ public string Id { get; set; } = string.Empty;
+
+ public string SoftwareName { get; set; } = string.Empty;
+
+ public string SoftwareCode { get; set; } = string.Empty;
+
+ public bool IsUse { get; set; }
+ }
+}
diff --git a/LMS.Repository/DTO/Software/SoftwareCollectionDto.cs b/LMS.Repository/DTO/Software/SoftwareCollectionDto.cs
new file mode 100644
index 0000000..71d81ac
--- /dev/null
+++ b/LMS.Repository/DTO/Software/SoftwareCollectionDto.cs
@@ -0,0 +1,44 @@
+using LMS.Repository.DTO.UserDto;
+
+namespace LMS.Repository.DTO.Software
+{
+ public class SoftwareCollectionDto
+ {
+ ///
+ /// ID
+ ///
+ public string Id { get; set; }
+ ///
+ /// 软件名称
+ ///
+ public string SoftwareName { get; set; }
+ ///
+ /// 软件代码
+ ///
+ public string SoftwareCode { get; set; }
+ ///
+ /// 创建用户ID
+ ///
+ public UserBaseDto CreatedUser { get; set; }
+ ///
+ /// 更新用户ID
+ ///
+ public UserBaseDto UpdatedUser { get; set; }
+ ///
+ /// 创建时间
+ ///
+ public DateTime CreatedTime { get; set; }
+ ///
+ /// 更新时间
+ ///
+ public DateTime UpdatedTime { get; set; }
+ ///
+ /// 备注
+ ///
+ public string Remark { get; set; }
+ ///
+ /// 是否启用
+ ///
+ public bool IsUse { get; set; }
+ }
+}
diff --git a/LMS.Repository/DTO/Software/SoftwareControlCollectionDto.cs b/LMS.Repository/DTO/Software/SoftwareControlCollectionDto.cs
new file mode 100644
index 0000000..d650fb0
--- /dev/null
+++ b/LMS.Repository/DTO/Software/SoftwareControlCollectionDto.cs
@@ -0,0 +1,47 @@
+using LMS.Repository.DTO.UserDto;
+namespace LMS.Repository.DTO.Software
+{
+ public class SoftwareControlCollectionDto
+ {
+ ///
+ /// ID
+ ///
+ public string Id { get; set; }
+ ///
+ /// 用户ID
+ ///
+ public UserBaseDto User { get; set; }
+ ///
+ /// 软件ID
+ ///
+ public DB.Software Software { get; set; }
+ ///
+ /// 创建用户ID
+ ///
+ public UserBaseDto CreatedUser { get; set; }
+ ///
+ /// 创建时间
+ ///
+ public DateTime CreatedTime { get; set; }
+ ///
+ /// 更新用户ID
+ ///
+ public UserBaseDto UpdatedUser { get; set; }
+ ///
+ /// 更新时间
+ ///
+ public DateTime UpdatedTime { get; set; }
+ ///
+ /// 备注
+ ///
+ public string Remark { get; set; }
+ ///
+ /// 到期时间
+ ///
+ public DateTime? ExpirationTime { get; set; }
+ ///
+ /// 是否永久
+ ///
+ public bool IsForever { get; set; }
+ }
+}
diff --git a/LMS.Repository/DTO/UserDto/UserBaseDto.cs b/LMS.Repository/DTO/UserDto/UserBaseDto.cs
index 9bfd3e4..f041919 100644
--- a/LMS.Repository/DTO/UserDto/UserBaseDto.cs
+++ b/LMS.Repository/DTO/UserDto/UserBaseDto.cs
@@ -15,4 +15,11 @@ public class UserBaseDto
public string PhoneNumber { get; set; } = string.Empty;
public string Avatar { get; set; } = string.Empty;
+
+ // 添加隐藏联系信息的方法
+ public void HideContactInfo()
+ {
+ Email = "**********";
+ PhoneNumber = "***********";
+ }
}
diff --git a/LMS.Repository/Software/AddSoftwareModel.cs b/LMS.Repository/Software/AddSoftwareModel.cs
new file mode 100644
index 0000000..fb626c1
--- /dev/null
+++ b/LMS.Repository/Software/AddSoftwareModel.cs
@@ -0,0 +1,22 @@
+using LMS.Common.Attributes;
+using System.ComponentModel.DataAnnotations;
+
+namespace LMS.Repository.Software
+{
+ public class AddSoftwareModel
+ {
+ ///
+ /// 软件名称
+ ///
+ [Required]
+ [NotEmpty(ErrorMessage = "123")]
+ public string SoftwareName { get; set; }
+
+ ///
+ /// 软件代码
+ ///
+ [Required]
+ [NotEmpty(ErrorMessage = "123")]
+ public string SoftwareCode { get; set; }
+ }
+}
diff --git a/LMS.Repository/Software/ModifySoftwareControlValidityModel.cs b/LMS.Repository/Software/ModifySoftwareControlValidityModel.cs
new file mode 100644
index 0000000..596d9cd
--- /dev/null
+++ b/LMS.Repository/Software/ModifySoftwareControlValidityModel.cs
@@ -0,0 +1,11 @@
+using LMS.Common.Enum;
+
+namespace LMS.Repository.Software
+{
+ public class ModifySoftwareControlValidityModel
+ {
+ public SoftwareControlEnum.SoftwareControlValidityEnum? ExpirationTime { get; set; }
+
+ public bool? IsForever { get; set; }
+ }
+}
diff --git a/LMS.Repository/User/LoginResponse.cs b/LMS.Repository/User/LoginResponse.cs
new file mode 100644
index 0000000..fcfeafe
--- /dev/null
+++ b/LMS.Repository/User/LoginResponse.cs
@@ -0,0 +1,21 @@
+namespace LMS.Repository.User;
+public class LoginResponseBase
+{
+
+ public string Token { get; set; }
+ public string UserName { get; set; }
+ public long Id { get; set; }
+ public string NickName { get; set; }
+}
+
+public class LoginResponse : LoginResponseBase
+{
+ public string RefreshToken { get; set; }
+}
+
+public class SimpleLoginResponse : LoginResponseBase
+{
+ public bool IsForver { get; set; }
+
+ public DateTime? ExpirationTime { get; set; }
+}
diff --git a/LMS.service/Configuration/ServiceConfiguration.cs b/LMS.service/Configuration/ServiceConfiguration.cs
index 0b5e103..f965608 100644
--- a/LMS.service/Configuration/ServiceConfiguration.cs
+++ b/LMS.service/Configuration/ServiceConfiguration.cs
@@ -7,6 +7,7 @@ using LMS.service.Service;
using LMS.service.Service.PermissionService;
using LMS.service.Service.PromptService;
using LMS.service.Service.RoleService;
+using LMS.service.Service.SoftwareService;
using LMS.service.Service.UserService;
namespace Lai_server.Configuration
@@ -31,6 +32,8 @@ namespace Lai_server.Configuration
services.AddScoped();
services.AddScoped();
services.AddScoped();
+ services.AddScoped();
+ services.AddScoped();
diff --git a/LMS.service/Controllers/SoftWareController.cs b/LMS.service/Controllers/SoftWareController.cs
index 33830ca..df6c314 100644
--- a/LMS.service/Controllers/SoftWareController.cs
+++ b/LMS.service/Controllers/SoftWareController.cs
@@ -1,14 +1,230 @@
-using Microsoft.AspNetCore.Mvc;
+using LMS.Repository.DB;
+using LMS.Repository.DTO;
+using LMS.Repository.DTO.Software;
+using LMS.Repository.Models.User;
+using LMS.Repository.Software;
+using LMS.Repository.User;
+using LMS.service.Service.SoftwareService;
+using LMS.service.Service.UserService;
+using LMS.Tools.Extensions;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.RazorPages;
+using Microsoft.IdentityModel.Tokens;
+using System.ComponentModel.DataAnnotations;
+using System.IdentityModel.Tokens.Jwt;
+using static LMS.Common.Enums.ResponseCodeEnum;
namespace LMS.service.Controllers
{
[Route("lms/[controller]/[action]")]
public class SoftWareController : ControllerBase
{
- //public Index()
- //{
- // var version = Assembly.GetExecutingAssembly().GetName().Version;
- // Console.WriteLine($"Version: {version}");
- //}
+ private readonly SoftwareControlService _softwareControlService;
+ private readonly SoftwareService _softwareService;
+
+ public SoftWareController(SoftwareControlService softwareControlService, SoftwareService softwareService)
+ {
+ _softwareControlService = softwareControlService;
+ _softwareService = softwareService;
+ }
+
+ #region 软件控制-同步用户的软件控制权限
+ ///
+ /// 同步用户的软件控制权限,用于用户登录后同步用户的软件控制权限
+ ///
+ ///
+ ///
+ [HttpPost("{userId}")]
+ [Authorize]
+ public async Task>> ApplySoftwareControl(long userId)
+ {
+ long reuqestUserId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
+ return await _softwareControlService.ApplySoftwareControl(userId, reuqestUserId);
+ }
+
+ #endregion
+
+ #region 软件控制-设置软件的到期时间和是否永久
+
+ [HttpPost("{id}")]
+ [Authorize]
+ public async Task>> ModifySoftwareControlValidity(string id, [FromBody] ModifySoftwareControlValidityModel model)
+ {
+ if (!ModelState.IsValid)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.ParameterError);
+ }
+ if (model.IsForever == null && model.ExpirationTime == null)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.ParameterError);
+ }
+ long requestUserId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
+ return await _softwareControlService.ModifySoftwareControlValidity(id, model, requestUserId);
+ }
+
+ #endregion
+
+ #region 软件控制-获取软件信息的集合
+
+ [HttpGet]
+ [Authorize]
+ public async Task>>> GetSoftwareControlCollection([Required] int page, [Required] int pageSize, long? userId, string? softwareId, bool? IsForever, string? remark)
+ {
+ long requestUserId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
+ return await _softwareControlService.GetSoftwareControlCollection(page, pageSize, userId, softwareId, IsForever, remark, requestUserId);
+ }
+
+ #endregion
+
+ #region 软件控制-删除软件控制数据
+
+ [HttpDelete("{id}")]
+ [Authorize]
+ public async Task>> DeleteSoftwareControl(string id)
+ {
+ long requestUserId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
+ return await _softwareControlService.DeleteSoftwareControl(id, requestUserId);
+ }
+ #endregion
+
+ #region 软件控制-各个软件检测软件控制权限
+
+ [HttpPost("{userID}/{machineId}/{softwareId}")]
+ [Authorize]
+ public async Task>> CheckSoftwareControl(long userID, string machineId, string softwareId)
+ {
+ if (!ModelState.IsValid)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.ParameterError);
+ }
+ long requestUserId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
+ // 解析jwt,获取machineID
+ // 从请求头中获取 JWT
+ var token = HttpContext.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
+
+ // 解析 JWT 并获取 MachineId
+ var handler = new JwtSecurityTokenHandler();
+ var jwtToken = handler.ReadJwtToken(token);
+
+ // 假设 MachineId 存储在 JWT 的声明中
+ var machineIdClaim = jwtToken.Claims.FirstOrDefault(claim => claim.Type == "DeviceInfo");
+ string parsedMachineId = machineIdClaim?.Value ?? "";
+ if (parsedMachineId != machineId || userID != requestUserId)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.InvalidToken, "登录失效,请重新登录");
+ }
+
+ return await _softwareControlService.CheckSoftwareControl(userID, machineId, softwareId);
+ }
+
+ #endregion
+
+ #region 软件控制-传入用户可以未申请权限数量
+
+ [HttpGet("{userId}")]
+ [Authorize]
+ public async Task>> GetUserSoftwareControlCount(long userId)
+ {
+ long requestUserId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
+ return await _softwareControlService.GetUserSoftwareControlCount(userId, requestUserId);
+ }
+
+ #endregion
+
+
+
+ #region 软件-添加软件数据
+ ///
+ /// 添加软件数据
+ ///
+ ///
+ ///
+ [HttpPost]
+ [Authorize]
+ public async Task>> AddSoftware([FromBody] AddSoftwareModel software)
+ {
+ if (!ModelState.IsValid)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.ParameterError);
+ }
+ long reuqestUserId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
+ return await _softwareService.AddSoftware(software, reuqestUserId);
+ }
+ #endregion
+
+ #region 软件-修改软件信息
+
+ ///
+ /// 修改软件信息
+ ///
+ ///
+ ///
+ ///
+ [HttpPost("{id}")]
+ [Authorize]
+ public async Task>> MpdifySoftware(string id, [FromBody] AddSoftwareModel software)
+ {
+ if (!ModelState.IsValid)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.ParameterError);
+ }
+ long reuqestUserId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
+ return await _softwareService.ModifySoftware(id, software, reuqestUserId);
+ }
+
+ #endregion
+
+ #region 软件-获取软件列表信息
+ ///
+ /// 获取软件的列表信息,可以使用查询条件 softwareName, softwareCode
+ ///
+ /// 页数
+ /// 一页多少
+ /// 软件名字
+ /// 软件编码
+ ///
+ [HttpGet]
+ [Authorize]
+ public async Task>>> GetSoftwareCollection([Required] int page, [Required] int pageSize, string? softwareName, string? softwareCode, bool? isUse = true)
+ {
+ long reuqestUserId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
+ return await _softwareService.GetSoftwareCollection(page, pageSize, softwareName, softwareCode, reuqestUserId, isUse);
+ }
+ #endregion
+
+ #region 软件-获取软件的信息信息,通过ID
+
+ [HttpGet("{id}")]
+ [Authorize]
+ public async Task>> GetSoftwareInfoById(string id)
+ {
+ long reuqestUserId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
+ return await _softwareService.GetSoftwareInfoById(id, reuqestUserId);
+ }
+ #endregion
+
+ #region 软件-删除软件数据
+ [HttpDelete("{id}")]
+ [Authorize]
+ public async Task>> DeleteSoftware(string id)
+ {
+ long reuqestUserId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
+ return await _softwareService.DeleteSoftware(id, reuqestUserId);
+ }
+
+ #endregion
+
+ #region 软件-获取所有软件的基础信息
+
+ [HttpGet]
+ [Authorize]
+ public async Task>>> GetSoftwareBaseCollection()
+ {
+ long reuqestUserId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
+ return await _softwareService.GetSoftwareBaseCollection(reuqestUserId);
+ }
+
+ #endregion
}
}
diff --git a/LMS.service/Controllers/UserController.cs b/LMS.service/Controllers/UserController.cs
index 9965a42..ad6dc1a 100644
--- a/LMS.service/Controllers/UserController.cs
+++ b/LMS.service/Controllers/UserController.cs
@@ -46,7 +46,7 @@ namespace LMS.service.Controllers
#endregion
- #region 登录
+ #region 登录 会生成刷新token,用户后台的刷新
///
/// 用户登录接口
///
@@ -81,10 +81,30 @@ namespace LMS.service.Controllers
SameSite = SameSiteMode.None,
Expires = DateTime.UtcNow.AddDays(7),
};
- Response.Cookies.Append("refreshToken", ((LoginService.LoginResponse)apiResponse.Data).RefreshToken, cookieOptions);
+ Response.Cookies.Append("refreshToken", ((LoginResponse)apiResponse.Data).RefreshToken, cookieOptions);
return apiResponse;
}
+ #endregion
+
+ #region 简单登录,不生成刷新token,绑定机器码,有效期一天
+
+ [HttpPost("{softwareId}")]
+ public async Task>> SimpleLogin(string softwareId, [FromBody] LoginModel model)
+ {
+ if (!ModelState.IsValid)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.ParameterError);
+ }
+ string? ip = HttpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault();
+ if (string.IsNullOrEmpty(ip))
+ {
+ ip = HttpContext.Connection.RemoteIpAddress?.ToString();
+ }
+ return await _loginService.SimpleLogin(model, softwareId, ip, _keyStore);
+ }
+
+
#endregion
#region 注册
diff --git a/LMS.service/Extensions/Middleware/DynamicPermissionMiddleware.cs b/LMS.service/Extensions/Middleware/DynamicPermissionMiddleware.cs
index b224d03..2f798d9 100644
--- a/LMS.service/Extensions/Middleware/DynamicPermissionMiddleware.cs
+++ b/LMS.service/Extensions/Middleware/DynamicPermissionMiddleware.cs
@@ -59,6 +59,7 @@ namespace LMS.service.Extensions.Middleware
context.Items["UserId"] = userId;
return Convert.ToInt64(userIdClaim?.Value);
}
+
return 0;
}
}
diff --git a/LMS.service/LMS.service.csproj b/LMS.service/LMS.service.csproj
index 83a9e0e..8dc7350 100644
--- a/LMS.service/LMS.service.csproj
+++ b/LMS.service/LMS.service.csproj
@@ -7,7 +7,7 @@
ed64fb6f-9c93-43d0-b418-61f507f28420
Linux
.
- 1.0.0
+ 1.0.2
diff --git a/LMS.service/Service/SoftwareService/SoftwareControlService.cs b/LMS.service/Service/SoftwareService/SoftwareControlService.cs
new file mode 100644
index 0000000..6a3c90f
--- /dev/null
+++ b/LMS.service/Service/SoftwareService/SoftwareControlService.cs
@@ -0,0 +1,442 @@
+using AutoMapper;
+using LMS.Common.Enum;
+using LMS.DAO;
+using LMS.DAO.UserDAO;
+using LMS.Repository.DB;
+using LMS.Repository.DTO;
+using LMS.Repository.DTO.Software;
+using LMS.Repository.DTO.UserDto;
+using LMS.Repository.Models.DB;
+using LMS.Repository.Software;
+using LMS.Tools;
+using LMS.Tools.Extensions;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+using static LMS.Common.Enums.ResponseCodeEnum;
+
+namespace LMS.service.Service.SoftwareService
+{
+ public class SoftwareControlService(UserBasicDao userBasicDao, ApplicationDbContext dbContext, IMapper mapper)
+ {
+ private readonly UserBasicDao _userBasicDao = userBasicDao;
+ private readonly ApplicationDbContext _dbContext = dbContext;
+ private readonly IMapper _mapper = mapper;
+
+ #region 软件控制-同步用户的软件控制权限
+ ///
+ /// 用户自动同步软件控制,和software中的一致,只要没有的数据都同步上,不管isUse,这个会在后面过滤掉
+ ///
+ ///
+ ///
+ ///
+ ///
+ internal async Task>> ApplySoftwareControl(long id, long requestUserId)
+ {
+ using var transaction = _dbContext.Database.BeginTransaction();
+ try
+ {
+ // 用户ID和请求ID不一致,且请求ID不是管理员或超级管理员,返回无权限操作
+ if (id != requestUserId && !await _userBasicDao.CheckUserIsAdminOrSuperAdmin(requestUserId))
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
+ }
+
+ // 检查用户是否存在
+ if (!await _userBasicDao.CheckUserExistsByID(id))
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.FindUserByIdFail);
+ }
+
+ List softwareControl = await _dbContext.SoftwareControl.Where(x => x.UserId == id).ToListAsync();
+ List software = await _dbContext.Software.ToListAsync();
+
+ bool isAdd = false;
+
+ // 判断是不是所有的软件都有权限,如果没有就添加
+ foreach (var item in software)
+ {
+ if (softwareControl.FirstOrDefault(x => x.SoftwareId == item.Id) == null)
+ {
+ SoftwareControl softwareControlModel = new SoftwareControl
+ {
+ Id = Guid.NewGuid().ToString(),
+ UserId = id,
+ SoftwareId = item.Id,
+ CreatedUserId = requestUserId,
+ CreatedTime = BeijingTimeExtension.GetBeijingTime(),
+ UpdatedUserId = requestUserId,
+ UpdatedTime = BeijingTimeExtension.GetBeijingTime(),
+ Remark = string.Empty,
+ IsForever = false,
+ ExpirationTime = null,
+ };
+ await _dbContext.SoftwareControl.AddAsync(softwareControlModel);
+ isAdd = true;
+ }
+
+ }
+ // 判断现在的,将再soft中没有的软件控制删除
+ foreach (var item1 in softwareControl)
+ {
+ if (software.FirstOrDefault(x => x.Id == item1.SoftwareId) == null)
+ {
+ _dbContext.SoftwareControl.Remove(item1);
+ isAdd = true;
+ }
+ }
+
+ await _dbContext.SaveChangesAsync();
+ await transaction.CommitAsync();
+ if (isAdd)
+ {
+ return APIResponseModel.CreateSuccessResponseModel("同步所有的软件权限成功");
+ }
+ else
+ {
+ return APIResponseModel.CreateSuccessResponseModel("当前已获取所有的软件控制权限,不需要做处理");
+ }
+ }
+ catch (Exception ex)
+ {
+ await transaction.RollbackAsync();
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.SystemError, ex.Message);
+ }
+ }
+
+ #endregion
+
+ #region 软件控制-设置软件的到期时间和是否永久
+ ///
+ /// 设置软件的到期时间和是否永久
+ ///
+ /// 软件控制项的ID
+ /// 传入的数据
+ /// 请求的用户ID
+ ///
+ public async Task>> ModifySoftwareControlValidity(string id, ModifySoftwareControlValidityModel model, long requestUserId)
+ {
+ try
+ {
+ if (!await _userBasicDao.CheckUserIsAdminOrSuperAdmin(requestUserId))
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
+ }
+ if (model.ExpirationTime != null)
+ {
+ // 判断model传入的枚举值是不是再对应的enum中是有效的
+ if (!Enum.IsDefined(typeof(SoftwareControlEnum.SoftwareControlValidityEnum), model.ExpirationTime))
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.ParameterError, "传入的到期时间不在有效范围内");
+ }
+ }
+
+ // 判断指定ID的软件控制项是否存在
+ SoftwareControl? softwareControl = await _dbContext.SoftwareControl.FirstOrDefaultAsync(x => x.Id == id);
+ if (softwareControl == null)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.IdDateNotFound);
+ }
+
+ // 判断当前数据是不是永久,如果是永久,就不能修改
+ if (softwareControl.IsForever && model.IsForever == true)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.ParameterError, "当前已是永久,不可再修改");
+ }
+
+ // 判断传入的modal的IsForever是不是true,是的话直接设置未永久,不是的话,设置到期时间
+ if (model.IsForever == true)
+ {
+ softwareControl.IsForever = true;
+ softwareControl.ExpirationTime = null;
+ }
+ else
+ {
+ // 这边判断现在的到期时间是不是大于现在的时间,是的话,再到期时间的基础上加上传入的时间,不是的话,直接再现在时间加上传入的时间,如果现在是永久,直接设置到期时间为现在时间加上传入的时间
+ if (model.ExpirationTime == null)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.ParameterError, "当前到期时间为空,不可修改");
+ }
+
+ if (softwareControl.IsForever == true)
+ {
+ softwareControl.ExpirationTime = BeijingTimeExtension.GetBeijingTime().AddDays((double)model.ExpirationTime.Value);
+ softwareControl.IsForever = false;
+ }
+ else
+ {
+
+ if (softwareControl.ExpirationTime > BeijingTimeExtension.GetBeijingTime())
+ {
+ if (model.ExpirationTime == SoftwareControlEnum.SoftwareControlValidityEnum.Zero)
+ {
+ softwareControl.ExpirationTime = BeijingTimeExtension.GetBeijingTime();
+ }
+ else
+ {
+ softwareControl.ExpirationTime = softwareControl.ExpirationTime.Value.AddDays((double)model.ExpirationTime.Value);
+ }
+ }
+ else
+ {
+ softwareControl.ExpirationTime = BeijingTimeExtension.GetBeijingTime().AddDays((double)model.ExpirationTime.Value);
+ }
+
+
+ }
+ }
+ // 设置更新时间和更新人
+ softwareControl.UpdatedTime = BeijingTimeExtension.GetBeijingTime();
+ softwareControl.UpdatedUserId = requestUserId;
+ // 更新数据库
+ _dbContext.SoftwareControl.Update(softwareControl);
+ await _dbContext.SaveChangesAsync();
+ return APIResponseModel.CreateSuccessResponseModel("修改成功");
+ }
+ catch (Exception ex)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.SystemError, ex.Message);
+ }
+ }
+ #endregion
+
+ #region 软件控制-获取软件信息的集合
+ ///
+ /// 获取软件信息的集合
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task>>> GetSoftwareControlCollection(int page, int pageSize, long? userId, string? softwareId, bool? isForever, string? remark, long requestUserId)
+ {
+ try
+ {
+ // 判断权限,如果不是管理员或超级管理员,就判断是不是自己的数据,不是的话,返回无权限操作
+ IQueryable query = _dbContext.SoftwareControl.AsQueryable();
+ bool isAdminOrSuperAdmin = await _userBasicDao.CheckUserIsAdminOrSuperAdmin(requestUserId);
+
+ if (!isAdminOrSuperAdmin && userId != requestUserId)
+ {
+ return APIResponseModel>.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
+ }
+
+ if (userId != null)
+ {
+ query = query.Where(x => x.UserId == userId);
+ }
+ if (softwareId != null)
+ {
+ query = query.Where(x => x.SoftwareId == softwareId);
+ }
+ if (isForever != null)
+ {
+ query = query.Where(x => x.IsForever == isForever);
+ }
+ if (!string.IsNullOrWhiteSpace(remark))
+ {
+ query = query.Where(x => x.Remark.Contains(remark));
+ }
+
+
+ if (!isAdminOrSuperAdmin)
+ {
+ // 通过 softwareId 过滤掉isUse为false的数
+ List softwareIds = await _dbContext.Software.Where(x => x.IsUse == true).Select(x => x.Id).ToListAsync();
+ query = query.Where(x => softwareIds.Contains(x.SoftwareId));
+ }
+
+ // 通过ID降序
+ query = query.OrderByDescending(x => x.CreatedTime);
+
+ // 查询总数
+ int total = await query.CountAsync();
+
+ // 分页
+ query = query.Skip((page - 1) * pageSize).Take(pageSize);
+
+ List softwareControls = await query.ToListAsync();
+ List softwareControlCollectionDtos = new List();
+
+ foreach (var item in softwareControls)
+ {
+ SoftwareControlCollectionDto softwareControlCollectionDto = new SoftwareControlCollectionDto
+ {
+ Id = item.Id,
+ IsForever = item.IsForever,
+ ExpirationTime = item.ExpirationTime,
+ Remark = item.Remark,
+ CreatedTime = item.CreatedTime,
+ UpdatedTime = item.UpdatedTime,
+ };
+ Software? software = await _dbContext.Software.FirstOrDefaultAsync(x => x.Id == item.SoftwareId);
+ if (software != null)
+ {
+ softwareControlCollectionDto.Software = software;
+ }
+ User? user = await _dbContext.Users.FirstOrDefaultAsync(x => x.Id == item.UserId);
+ softwareControlCollectionDto.User = _mapper.Map(user);
+ softwareControlCollectionDto.User.HideContactInfo();
+
+ User? createdUser = await _dbContext.Users.FirstOrDefaultAsync(x => x.Id == item.CreatedUserId);
+ softwareControlCollectionDto.CreatedUser = _mapper.Map(createdUser);
+ softwareControlCollectionDto.CreatedUser.HideContactInfo();
+
+ User? updatedUser = await _dbContext.Users.FirstOrDefaultAsync(x => x.Id == item.UpdatedUserId);
+ softwareControlCollectionDto.UpdatedUser = _mapper.Map(updatedUser);
+ softwareControlCollectionDto.UpdatedUser.HideContactInfo();
+
+ softwareControlCollectionDtos.Add(softwareControlCollectionDto);
+ }
+ return APIResponseModel>.CreateSuccessResponseModel(new CollectionResponse
+ {
+ Total = total,
+ Collection = softwareControlCollectionDtos,
+ Current = page,
+ });
+ }
+ catch (Exception ex)
+ {
+ return APIResponseModel>.CreateErrorResponseModel(ResponseCode.SystemError, ex.Message);
+ }
+
+
+ }
+ #endregion
+
+ #region 软件控制-删除软件控制数据
+
+ ///
+ /// 删除软件控制数据
+ ///
+ ///
+ ///
+ ///
+ public async Task>> DeleteSoftwareControl(string id, long requestUserId)
+ {
+ try
+ {
+ if (!await _userBasicDao.CheckUserIsAdminOrSuperAdmin(requestUserId))
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
+ }
+
+ SoftwareControl? softwareControl = await _dbContext.SoftwareControl.FirstOrDefaultAsync(x => x.Id == id);
+ if (softwareControl == null)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.IdDateNotFound);
+ }
+
+ _dbContext.SoftwareControl.Remove(softwareControl);
+ await _dbContext.SaveChangesAsync();
+ return APIResponseModel.CreateSuccessResponseModel("删除成功");
+ }
+ catch (Exception ex)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.SystemError, ex.Message);
+ }
+ }
+
+ #endregion
+
+ #region 软件检查权限以及登录状态
+ ///
+ /// 检查软件控制权限 以及登录状态
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task>> CheckSoftwareControl(long userID, string machineId, string softwareId)
+ {
+ try
+ {
+ // 判断软件是不是存在
+ if (!await _dbContext.Software.AnyAsync(x => x.Id == softwareId))
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.IdDateNotFound);
+ }
+
+ // 判断是不是有关联信息,没有的话就是没有登录,或者是机器码不一致,再其他地方登录过了
+ UserSoftware? userSoftware = await _dbContext.UserSoftware.FirstOrDefaultAsync(x => x.UserId == userID && x.MachineId == machineId);
+ if (userSoftware == null)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.NotPermissionAction, "无用户登录信息或登录信息不正确,请确认是不是登录多次,请重新登录");
+ }
+
+ // 判断是不是有权限
+ SoftwareControl? softwareControl = await _dbContext.SoftwareControl.FirstOrDefaultAsync(x => x.UserId == userID && x.SoftwareId == softwareId);
+ if (softwareControl == null)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.NotPermissionAction, "无权限操作,请先申请权限");
+ }
+
+ // 判断是不是还能用
+ if (softwareControl.IsForever == true || softwareControl.ExpirationTime > BeijingTimeExtension.GetBeijingTime())
+ {
+ // 可用
+ return APIResponseModel.CreateSuccessResponseModel("1");
+ }
+ else
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.NotPermissionAction, "权限已过期,请重新申请");
+ }
+ }
+ catch (Exception ex)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.SystemError, ex.Message);
+ }
+ }
+
+ #endregion
+
+ #region 软件控制-用户可申请的软件控制数量
+ ///
+ /// 用户可申请的软件控制数量
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task>> GetUserSoftwareControlCount(long userId, long requestUserId)
+ {
+ try
+ {
+ bool isAdminOrSuperAdmin = await _userBasicDao.CheckUserIsAdminOrSuperAdmin(requestUserId);
+ if (!isAdminOrSuperAdmin && userId != requestUserId)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
+ }
+ User? user = await _dbContext.Users.FirstOrDefaultAsync(x => x.Id == userId);
+ if (user == null)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.FindUserByIdFail);
+ }
+
+ List software = await _dbContext.Software.Where(x => x.IsUse == true).ToListAsync();
+
+ List softwareControls = await _dbContext.SoftwareControl.Where(x => x.UserId == userId).ToListAsync();
+ // 判断software中的softwareId是否在softwareControl中,不在的话,不在的话计数
+ int count = 0;
+ foreach (var item in software)
+ {
+ if (softwareControls.FirstOrDefault(x => x.SoftwareId == item.Id) == null)
+ {
+ count++;
+ }
+ }
+ return APIResponseModel.CreateSuccessResponseModel(count);
+ }
+ catch (Exception ex)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.SystemError, ex.Message);
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/LMS.service/Service/SoftwareService/SoftwareService.cs b/LMS.service/Service/SoftwareService/SoftwareService.cs
new file mode 100644
index 0000000..72b6ace
--- /dev/null
+++ b/LMS.service/Service/SoftwareService/SoftwareService.cs
@@ -0,0 +1,320 @@
+using AutoMapper;
+using LMS.DAO;
+using LMS.DAO.UserDAO;
+using LMS.Repository.DB;
+using LMS.Repository.DTO;
+using LMS.Repository.DTO.Software;
+using LMS.Repository.DTO.UserDto;
+using LMS.Repository.Models.DB;
+using LMS.Repository.Software;
+using LMS.Tools.Extensions;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+using static LMS.Common.Enums.ResponseCodeEnum;
+
+namespace LMS.service.Service.SoftwareService
+{
+ public class SoftwareService(UserBasicDao userBasicDao, ApplicationDbContext dbContext, IMapper mapper)
+ {
+ private readonly UserBasicDao _userBasicDao = userBasicDao;
+ private readonly ApplicationDbContext _dbContext = dbContext;
+ private readonly IMapper _mapper = mapper;
+
+ #region 添加软件数据
+ ///
+ /// 添加软件数据
+ ///
+ ///
+ ///
+ ///
+ public async Task>> AddSoftware(AddSoftwareModel software, long reuqestUserId)
+ {
+ try
+ {
+ // 判断用户是不是超级管理员
+ if (!(await _userBasicDao.CheckUserIsSuperAdmin(reuqestUserId)))
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
+ }
+
+ // 判断软件名字软件代码是不是存在,存在的话,报错
+ bool isSoftwareExists = await _dbContext.Software.AnyAsync(x => x.SoftwareName == software.SoftwareName || x.SoftwareCode == software.SoftwareCode);
+ if (isSoftwareExists)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.ParameterError, "软件名称或软件编码已存在,请检查");
+ }
+
+ // 开始添加软件
+ Software software1 = new Software
+ {
+ Id = Guid.NewGuid().ToString(),
+ SoftwareName = software.SoftwareName,
+ SoftwareCode = software.SoftwareCode,
+ CreatedUserId = reuqestUserId,
+ UpdatedUserId = reuqestUserId,
+ CreatedTime = BeijingTimeExtension.GetBeijingTime(),
+ UpdatedTime = BeijingTimeExtension.GetBeijingTime(),
+ Remark = string.Empty,
+ IsUse = true
+ };
+ await _dbContext.Software.AddAsync(software1);
+ await _dbContext.SaveChangesAsync();
+ // Add software
+ return APIResponseModel.CreateSuccessResponseModel("Add software successfully");
+ }
+ catch (Exception ex)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.SystemError, ex.Message);
+ }
+ }
+ #endregion
+
+ #region 修改软件信息
+ ///
+ /// 修改软件信息
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task>> ModifySoftware(string id, AddSoftwareModel software, long reuqestUserId)
+ {
+ try
+ {
+ // 判断用户是不是超级管理员
+ if (!(await _userBasicDao.CheckUserIsSuperAdmin(reuqestUserId)))
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
+ }
+ // 判断传入的ID是不是存在
+ Software? software2 = await _dbContext.Software.FirstOrDefaultAsync(x => x.Id == id);
+ if (software2 == null)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.ParameterError, "Software does not exist");
+ }
+ // 判断软件名字软件代码是不是存在,不包含当前的,存在的话,报错
+ bool isSoftwareExists = await _dbContext.Software.AnyAsync(x => (x.SoftwareName == software.SoftwareName || x.SoftwareCode == software.SoftwareCode) && x.Id != id);
+ if (isSoftwareExists)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.ParameterError, "软件名称或软件编码已存在,请检查");
+ }
+ software2.SoftwareName = software.SoftwareName;
+ software2.SoftwareCode = software.SoftwareCode;
+ software2.UpdatedUserId = reuqestUserId;
+ software2.UpdatedTime = BeijingTimeExtension.GetBeijingTime();
+ _dbContext.Update(software2);
+ await _dbContext.SaveChangesAsync();
+ return APIResponseModel.CreateSuccessResponseModel("Modify software successfully");
+ }
+ catch (Exception ex)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.SystemError, ex.Message);
+ }
+ }
+ #endregion
+
+ #region 获取软件列表信息
+
+ ///
+ /// 获取软件信息的列表,可以使用查询条件 softwareName, softwareCode
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task>>> GetSoftwareCollection(int page, int pageSize, string? softwareName, string? softwareCode, long reuqestUserId, bool? isUse)
+ {
+ try
+ {
+ if (!await _userBasicDao.CheckUserIsSuperAdmin(reuqestUserId))
+ {
+ return APIResponseModel>.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
+ }
+
+ IQueryable query = _dbContext.Software.AsQueryable();
+ if (!string.IsNullOrWhiteSpace(softwareName))
+ {
+ query = query.Where(x => x.SoftwareName.Contains(softwareName));
+ }
+ if (!string.IsNullOrWhiteSpace(softwareCode))
+ {
+ query = query.Where(x => x.SoftwareCode.Contains(softwareCode));
+ }
+ if (isUse != null)
+ {
+ query = query.Where(x => x.IsUse == isUse);
+ }
+ // 按照创建时间排序
+ query = query.OrderByDescending(x => x.CreatedTime);
+ // 计算总数
+ int count = await query.CountAsync();
+ // 分页
+ List softwareList = await query.Skip((page - 1) * pageSize).Take(pageSize).ToListAsync();
+
+ List softwareCollectionDtos = [];
+ for (int i = 0; i < softwareList.Count; i++)
+ {
+
+ SoftwareCollectionDto softwareCollectionDto = new()
+ {
+ Id = softwareList[i].Id,
+ SoftwareName = softwareList[i].SoftwareName,
+ SoftwareCode = softwareList[i].SoftwareCode,
+ CreatedTime = softwareList[i].CreatedTime,
+ UpdatedTime = softwareList[i].UpdatedTime,
+ Remark = softwareList[i].Remark,
+ IsUse = softwareList[i].IsUse
+ };
+
+ User? createdUser = await _dbContext.Users.FirstOrDefaultAsync(x => x.Id == softwareList[i].CreatedUserId);
+ softwareCollectionDto.CreatedUser = _mapper.Map(createdUser);
+ softwareCollectionDto.CreatedUser.HideContactInfo();
+ User? updatedUser = await _dbContext.Users.FirstOrDefaultAsync(x => x.Id == softwareList[i].UpdatedUserId);
+ softwareCollectionDto.UpdatedUser = _mapper.Map(updatedUser);
+ softwareCollectionDto.UpdatedUser.HideContactInfo();
+ softwareCollectionDtos.Add(softwareCollectionDto);
+ }
+ return APIResponseModel>.CreateSuccessResponseModel(new CollectionResponse
+ {
+ Total = count,
+ Collection = softwareCollectionDtos,
+ Current = page
+ });
+ }
+ catch (Exception ex)
+ {
+ return APIResponseModel>.CreateErrorResponseModel(ResponseCode.SystemError, ex.Message);
+ }
+ }
+ #endregion
+
+ #region 获取软件信息,通用ID
+ ///
+ /// 获取软件信息,通过ID
+ ///
+ ///
+ ///
+ ///
+ public async Task>> GetSoftwareInfoById(string id, long reuqestUserId)
+ {
+ try
+ {
+ if (!await _userBasicDao.CheckUserIsSuperAdmin(reuqestUserId))
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
+ }
+
+ Software? software = await _dbContext.Software.FirstOrDefaultAsync(x => x.Id == id);
+ if (software == null)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.ParameterError, "Software does not exist");
+ }
+
+ SoftwareCollectionDto softwareCollection = new SoftwareCollectionDto
+ {
+ Id = software.Id,
+ SoftwareName = software.SoftwareName,
+ SoftwareCode = software.SoftwareCode,
+ CreatedTime = software.CreatedTime,
+ UpdatedTime = software.UpdatedTime,
+ Remark = software.Remark,
+ IsUse = software.IsUse
+ };
+
+ User? createdUser = await _dbContext.Users.FirstOrDefaultAsync(x => x.Id == software.CreatedUserId);
+ softwareCollection.CreatedUser = _mapper.Map(createdUser);
+ User? updatedUser = await _dbContext.Users.FirstOrDefaultAsync(x => x.Id == software.UpdatedUserId);
+ softwareCollection.UpdatedUser = _mapper.Map(updatedUser);
+ return APIResponseModel.CreateSuccessResponseModel(softwareCollection);
+ }
+ catch (Exception ex)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.SystemError, ex.Message);
+ }
+ }
+
+ #endregion
+
+ #region 删除软件数据
+
+ ///
+ /// 删除软件,通过软件ID
+ ///
+ ///
+ ///
+ ///
+ public async Task>> DeleteSoftware(string id, long reuqestUserId)
+ {
+ try
+ {
+ if (!await _userBasicDao.CheckUserIsSuperAdmin(reuqestUserId))
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
+ }
+
+ Software? software = await _dbContext.Software.FirstOrDefaultAsync(x => x.Id == id);
+ if (software == null)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.ParameterError, "Software does not exist");
+ }
+ software.IsUse = false;
+ _dbContext.Software.Update(software);
+ await _dbContext.SaveChangesAsync();
+ return APIResponseModel.CreateSuccessResponseModel("soft Delete software successfully");
+
+
+ //Software? software = await _dbContext.Software.FirstOrDefaultAsync(x => x.Id == id);
+ //if (software == null)
+ //{
+ // return APIResponseModel.CreateErrorResponseModel(ResponseCode.ParameterError, "Software does not exist");
+ //}
+ //// 开始删除软件
+ //_dbContext.Software.Remove(software);
+
+ ////TODO: 删除软件相关的数据(用户软件关联表,软件控制表)
+ //await _dbContext.SaveChangesAsync();
+ //return APIResponseModel.CreateSuccessResponseModel("Delete software successfully");
+ }
+ catch (Exception ex)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.SystemError, ex.Message);
+ }
+ }
+
+ #endregion
+
+ ///
+ /// 获取所有软件的基础信息
+ ///
+ ///
+ ///
+ ///
+ public async Task>>> GetSoftwareBaseCollection(long reuqestUserId)
+ {
+ try
+ {
+ List softwares = await _dbContext.Software.ToListAsync();
+ List softwareBasicDtos = [];
+ for (int i = 0; i < softwares.Count; i++)
+ {
+ SoftwareBasicDto softwareBasicDto = new SoftwareBasicDto
+ {
+ Id = softwares[i].Id,
+ SoftwareName = softwares[i].SoftwareName,
+ SoftwareCode = softwares[i].SoftwareCode,
+ IsUse = softwares[i].IsUse
+ };
+ softwareBasicDtos.Add(softwareBasicDto);
+ }
+ return APIResponseModel>.CreateSuccessResponseModel(softwareBasicDtos);
+ }
+ catch (Exception ex)
+ {
+ return APIResponseModel>.CreateErrorResponseModel(ResponseCode.SystemError, ex.Message);
+ }
+ }
+ }
+}
diff --git a/LMS.service/Service/UserService/LoginService.cs b/LMS.service/Service/UserService/LoginService.cs
index 87afe1b..4443374 100644
--- a/LMS.service/Service/UserService/LoginService.cs
+++ b/LMS.service/Service/UserService/LoginService.cs
@@ -1,9 +1,10 @@
using LMS.Common.RSAKey;
using LMS.DAO;
+using LMS.Repository.DB;
using LMS.Repository.Models.DB;
using LMS.Repository.Models.User;
-using LMS.service.Data;
+using LMS.Repository.User;
using LMS.Tools.Extensions;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
@@ -12,7 +13,6 @@ using Microsoft.IdentityModel.Tokens;
using System.Collections.Concurrent;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
-using System.Security.Cryptography.Xml;
using System.Text;
using static LMS.Common.Enums.ResponseCodeEnum;
@@ -31,28 +31,26 @@ namespace LMS.service.Service.UserService
_securityService = securityService;
}
- public class LoginResponse
- {
- public string Token { get; set; }
- public string UserName { get; set; }
- public long Id { get; set; }
- public string NickName { get; set; }
- public string RefreshToken { get; set; }
- }
-
+ #region 生成JWT
///
/// 生成JWT
///
///
///
///
- public string GenerateJWT(User user)
+ public string GenerateJWT(User user, int hours = 6, string deviceInfo = "")
{
- var claims = new List();
- claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()));
- claims.Add(new Claim(ClaimTypes.Name, user.UserName));
- // 获取角色(目前只有管理员)
- claims.Add(new Claim(ClaimTypes.Role, "AdminUser"));
+ var claims = new List
+ {
+ new(ClaimTypes.NameIdentifier, user.Id.ToString()),
+ new(ClaimTypes.Name, user.UserName),
+ // 获取角色(目前只有管理员)
+ new(ClaimTypes.Role, "AdminUser")
+ };
+ if (!string.IsNullOrEmpty(deviceInfo))
+ {
+ claims.Add(new Claim("DeviceInfo", deviceInfo));
+ }
//foreach (string role in roles)
//{
// claims.Add(new Claim(ClaimTypes.Role, role));
@@ -67,7 +65,7 @@ namespace LMS.service.Service.UserService
//设置Token的过期时间
- DateTime expires = DateTime.Now.AddHours(6);
+ DateTime expires = DateTime.Now.AddHours(hours);
byte[] secBytes = Encoding.UTF8.GetBytes(key);
var secKey = new SymmetricSecurityKey(secBytes);
@@ -81,6 +79,9 @@ namespace LMS.service.Service.UserService
return jwt;
}
+ #endregion
+
+ #region 用户登录,生成刷新token
///
/// 用户登录的服务层方法
///
@@ -172,6 +173,9 @@ namespace LMS.service.Service.UserService
}
}
+ #endregion
+
+ #region 刷新token的方法
///
/// 刷新token的方法
///
@@ -208,6 +212,8 @@ namespace LMS.service.Service.UserService
}
}
+ #endregion
+
#region 将用户设置为代理
///
/// 将用户设置为代理,要做一系列检查
@@ -273,6 +279,128 @@ namespace LMS.service.Service.UserService
return APIResponseModel.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
}
}
+
+ #endregion
+
+ //TODO 未测试
+ #region 用户登录的服务层方法,简化版,只是登录,不生成刷新token
+ ///
+ /// 用户登录的服务层方法,简化版,只是登录,不生成刷新token
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task>> SimpleLogin(LoginModel model, string softwareId, string ip, ConcurrentDictionary _keyStore)
+ {
+ using var transaction = await _context.Database.BeginTransactionAsync();
+ try
+ {
+ if (string.IsNullOrWhiteSpace(model.DeviceInfo))
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.ParameterError);
+ }
+ if (!_keyStore.TryRemove(model.TokenId, out var keyInfo)) // 没有找到对应的公钥
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.UserPasswordFail);
+ }
+
+ if (BeijingTimeExtension.GetBeijingTime() > keyInfo.Expiry) // 公钥超时
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.UserPasswordFail);
+ }
+
+ var rsaKeyId = keyInfo.Key;
+ var privateKey = _securityService.DecryptWithAES(rsaKeyId);
+ // 用户密码解密
+ string decryptedPassword = RsaKeyPairGenerator.Decrypt(privateKey, model.Password);
+
+ if (model.UserName == null)
+ {
+ throw new ArgumentNullException("UserName");
+ }
+
+ User? user = await _userManager.FindByNameAsync(model.UserName);
+
+ if (user == null)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.FindUserByNameFail);
+ }
+
+ if (await _userManager.IsLockedOutAsync(user))
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.UserIsLockedOut);
+ }
+
+ var result = await _userManager.CheckPasswordAsync(user, decryptedPassword);
+ if (!result)
+ {
+ // 失败计数器加1
+ await _userManager.AccessFailedAsync(user);
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.UserPasswordFail);
+ }
+
+ // 密码正确,确认权限
+ // 检查当前用户是不是有软件控制权限
+ Software? software = await _context.Software.FirstOrDefaultAsync(s => s.Id == softwareId);
+ if (software == null)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.IdDateNotFound, "没有找到指定的软件信息,请联系管理员");
+ }
+ SoftwareControl? softwareControl = await _context.SoftwareControl.FirstOrDefaultAsync(sc => sc.UserId == user.Id && sc.SoftwareId == softwareId);
+ if (softwareControl == null)
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.NotPermissionAction, "当前用户没有软件控制权限,请联系管理员");
+ }
+ // 不是永久,需要判断是不是到期
+ if (softwareControl.IsForever == false && softwareControl.ExpirationTime <= BeijingTimeExtension.GetBeijingTime())
+ {
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.NotPermissionAction, "当前用户的软件权限已到期,请联系管理员");
+ }
+
+ UserSoftware? userSoftware = await _context.UserSoftware.FirstOrDefaultAsync(us => us.UserId == user.Id && us.SoftwareId == softwareId);
+ if (userSoftware == null)
+ {
+ // 新建
+ userSoftware = new UserSoftware()
+ {
+ UserId = user.Id,
+ SoftwareId = softwareId,
+ MachineId = model.DeviceInfo,
+ SoftwareControlId = softwareControl.Id
+ };
+ await _context.UserSoftware.AddAsync(userSoftware);
+ }
+ else
+ {
+ // 修改
+ userSoftware.MachineId = model.DeviceInfo;
+ _context.Update(userSoftware);
+ await _context.SaveChangesAsync();
+ }
+
+ // 密码正确,返回token
+ string jwt = GenerateJWT(user, 24, model.DeviceInfo);
+
+ await _context.SaveChangesAsync();
+ await transaction.CommitAsync();
+
+
+ return APIResponseModel.CreateSuccessResponseModel(new SimpleLoginResponse()
+ {
+ Token = jwt,
+ UserName = user.UserName ?? "",
+ Id = user.Id,
+ NickName = user.NickName
+ });
+ }
+ catch (Exception e)
+ {
+ await transaction.RollbackAsync();
+ return APIResponseModel.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
+ }
+ }
+
#endregion
}
}
diff --git a/SQL/v1.0.2/Software.sql b/SQL/v1.0.2/Software.sql
new file mode 100644
index 0000000..ad17a36
--- /dev/null
+++ b/SQL/v1.0.2/Software.sql
@@ -0,0 +1,37 @@
+/*
+ Navicat Premium Dump SQL
+
+ Source Server : 亿速云(国内)
+ Source Server Type : MySQL
+ Source Server Version : 80018 (8.0.18)
+ Source Host : yisurds-66dc0b453c05d4.rds.ysydb1.com:14080
+ Source Schema : LMS_TEST
+
+ Target Server Type : MySQL
+ Target Server Version : 80018 (8.0.18)
+ File Encoding : 65001
+
+ Date: 27/12/2024 21:36:00
+*/
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for Software
+-- ----------------------------
+DROP TABLE IF EXISTS `Software`;
+CREATE TABLE `Software` (
+ `Id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'ID',
+ `SoftwareName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '软件名称',
+ `SoftwareCode` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '软件代码',
+ `CreatedUserId` bigint(20) NULL DEFAULT NULL COMMENT '创建用户ID',
+ `UpdatedUserId` bigint(20) NULL DEFAULT NULL COMMENT '更新用户ID',
+ `CreatedTime` datetime NULL DEFAULT NULL COMMENT '创建时间',
+ `UpdatedTime` datetime NULL DEFAULT NULL COMMENT '更新时间',
+ `Remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注',
+ `IsUse` tinyint(1) NULL DEFAULT NULL COMMENT '是否启用',
+ PRIMARY KEY (`Id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+SET FOREIGN_KEY_CHECKS = 1;
diff --git a/SQL/v1.0.2/SoftwareControl.sql b/SQL/v1.0.2/SoftwareControl.sql
new file mode 100644
index 0000000..62cb6d2
--- /dev/null
+++ b/SQL/v1.0.2/SoftwareControl.sql
@@ -0,0 +1,38 @@
+/*
+ Navicat Premium Dump SQL
+
+ Source Server : 亿速云(国内)
+ Source Server Type : MySQL
+ Source Server Version : 80018 (8.0.18)
+ Source Host : yisurds-66dc0b453c05d4.rds.ysydb1.com:14080
+ Source Schema : LMS_TEST
+
+ Target Server Type : MySQL
+ Target Server Version : 80018 (8.0.18)
+ File Encoding : 65001
+
+ Date: 27/12/2024 21:36:10
+*/
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for SoftwareControl
+-- ----------------------------
+DROP TABLE IF EXISTS `SoftwareControl`;
+CREATE TABLE `SoftwareControl` (
+ `Id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'ID',
+ `UserId` bigint(20) NOT NULL COMMENT '用户ID',
+ `SoftwareId` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '软件ID',
+ `CreatedUserId` bigint(20) NULL DEFAULT NULL COMMENT '创建用户ID',
+ `CreatedTime` datetime NULL DEFAULT NULL COMMENT '创建时间',
+ `UpdatedUserId` bigint(20) NULL DEFAULT NULL COMMENT '更新用户ID',
+ `UpdatedTime` datetime NULL DEFAULT NULL COMMENT '更新时间',
+ `Remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注',
+ `ExpirationTime` datetime NULL DEFAULT NULL COMMENT '到期时间',
+ `IsForever` tinyint(1) NULL DEFAULT NULL COMMENT '是否永久',
+ PRIMARY KEY (`Id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+SET FOREIGN_KEY_CHECKS = 1;
diff --git a/SQL/v1.0.2/UserSoftware.sql b/SQL/v1.0.2/UserSoftware.sql
new file mode 100644
index 0000000..01fc9d8
--- /dev/null
+++ b/SQL/v1.0.2/UserSoftware.sql
@@ -0,0 +1,32 @@
+/*
+ Navicat Premium Dump SQL
+
+ Source Server : 亿速云(国内)
+ Source Server Type : MySQL
+ Source Server Version : 80018 (8.0.18)
+ Source Host : yisurds-66dc0b453c05d4.rds.ysydb1.com:14080
+ Source Schema : LMS_TEST
+
+ Target Server Type : MySQL
+ Target Server Version : 80018 (8.0.18)
+ File Encoding : 65001
+
+ Date: 27/12/2024 21:36:16
+*/
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for UserSoftware
+-- ----------------------------
+DROP TABLE IF EXISTS `UserSoftware`;
+CREATE TABLE `UserSoftware` (
+ `UserId` bigint(20) NOT NULL COMMENT '用户ID',
+ `SoftwareId` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '软件ID',
+ `MachineId` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '机器码ID',
+ `SoftwareControlId` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '软件控制ID',
+ PRIMARY KEY (`UserId`, `SoftwareId`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
+
+SET FOREIGN_KEY_CHECKS = 1;