From fb836510559b05266f190e56cbc0591bcc0e38c3 Mon Sep 17 00:00:00 2001 From: youngq Date: Wed, 26 Jun 2024 17:47:25 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=A1=B9=E7=9B=AE=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WGShare.API.sln | 31 +++ WGShare.API/Controllers/AuthController.cs | 187 ++++++++++++++++++ .../Controllers/Backend/PremController.cs | 93 +++++++++ .../Controllers/Backend/RoleController.cs | 86 ++++++++ .../Controllers/Backend/TenantController.cs | 69 +++++++ .../Controllers/Backend/UserController.cs | 118 +++++++++++ .../Controllers/Basic/BasicController.cs | 51 +++++ .../Controllers/Frontend/HomeController.cs | 66 +++++++ .../Controllers/Frontend/RoomController.cs | 163 +++++++++++++++ WGShare.API/Helpers/JwtHelper.cs | 53 +++++ WGShare.API/Helpers/RedisHelper.cs | 47 +++++ WGShare.API/Program.cs | 81 ++++++++ WGShare.API/Properties/launchSettings.json | 31 +++ .../AuthenticationServiceExtensions.cs | 52 +++++ .../CorsAppBuilderExtensions.cs | 30 +++ .../ServiceConfigs/GlobalExceptionFilter.cs | 68 +++++++ .../ServiceConfigs/ModelActionFilter.cs | 60 ++++++ .../SqlsugarServiceExtensions.cs | 66 +++++++ WGShare.API/WGShare.API.csproj | 18 ++ WGShare.API/appsettings.Development.json | 15 ++ WGShare.API/appsettings.json | 23 +++ WGShare.Domain/DTOs/File/ShareFileInputDTO.cs | 29 +++ .../DTOs/File/ShareFileOutputDTO.cs | 46 +++++ .../DTOs/Login/AnonymousLoginDTO.cs | 19 ++ WGShare.Domain/DTOs/Login/UserLoginDTO.cs | 14 ++ .../DTOs/Perm/PermissionInputDTO.cs | 26 +++ WGShare.Domain/DTOs/Role/RoleInputDTO.cs | 22 +++ WGShare.Domain/DTOs/Role/RolePermInputDTO.cs | 15 ++ WGShare.Domain/DTOs/Room/RoomInputDTO.cs | 24 +++ WGShare.Domain/DTOs/Room/RoomOutputDTO.cs | 24 +++ WGShare.Domain/DTOs/Tenant/TenantInputDTO.cs | 23 +++ WGShare.Domain/DTOs/User/UserChangePwdDTO.cs | 14 ++ WGShare.Domain/DTOs/User/UserInputDTO.cs | 35 ++++ WGShare.Domain/DTOs/User/UserOutputDTO.cs | 25 +++ WGShare.Domain/DTOs/User/UserPremInputDTO.cs | 22 +++ WGShare.Domain/DTOs/User/UserSearchDTO.cs | 17 ++ WGShare.Domain/Entities/Admin.cs | 38 ++++ WGShare.Domain/Entities/Permission.cs | 40 ++++ WGShare.Domain/Entities/Role.cs | 40 ++++ WGShare.Domain/Entities/RolePrem.cs | 24 +++ WGShare.Domain/Entities/Room.cs | 53 +++++ WGShare.Domain/Entities/RoomManager.cs | 25 +++ WGShare.Domain/Entities/ShareFile.cs | 67 +++++++ WGShare.Domain/Entities/Tenant.cs | 42 ++++ WGShare.Domain/Entities/User.cs | 69 +++++++ WGShare.Domain/Entities/UserPrem.cs | 24 +++ WGShare.Domain/Enums/MenuType.cs | 17 ++ WGShare.Domain/FriendlyException/ErrorCode.cs | 20 ++ .../FriendlyException/ExceptionNotice.cs | 44 +++++ .../Exceptions/FriendlyInternalException.cs | 19 ++ WGShare.Domain/FriendlyException/Oops.cs | 75 +++++++ WGShare.Domain/GeneralModel/PagedBaseDto.cs | 24 +++ WGShare.Domain/GeneralModel/PagedResult.cs | 28 +++ WGShare.Domain/GeneralModel/UniformResult.cs | 46 +++++ WGShare.Domain/WGShare.Domain.csproj | 19 ++ 55 files changed, 2477 insertions(+) create mode 100644 WGShare.API.sln create mode 100644 WGShare.API/Controllers/AuthController.cs create mode 100644 WGShare.API/Controllers/Backend/PremController.cs create mode 100644 WGShare.API/Controllers/Backend/RoleController.cs create mode 100644 WGShare.API/Controllers/Backend/TenantController.cs create mode 100644 WGShare.API/Controllers/Backend/UserController.cs create mode 100644 WGShare.API/Controllers/Basic/BasicController.cs create mode 100644 WGShare.API/Controllers/Frontend/HomeController.cs create mode 100644 WGShare.API/Controllers/Frontend/RoomController.cs create mode 100644 WGShare.API/Helpers/JwtHelper.cs create mode 100644 WGShare.API/Helpers/RedisHelper.cs create mode 100644 WGShare.API/Program.cs create mode 100644 WGShare.API/Properties/launchSettings.json create mode 100644 WGShare.API/ServiceConfigs/AuthenticationServiceExtensions.cs create mode 100644 WGShare.API/ServiceConfigs/CorsAppBuilderExtensions.cs create mode 100644 WGShare.API/ServiceConfigs/GlobalExceptionFilter.cs create mode 100644 WGShare.API/ServiceConfigs/ModelActionFilter.cs create mode 100644 WGShare.API/ServiceConfigs/SqlsugarServiceExtensions.cs create mode 100644 WGShare.API/WGShare.API.csproj create mode 100644 WGShare.API/appsettings.Development.json create mode 100644 WGShare.API/appsettings.json create mode 100644 WGShare.Domain/DTOs/File/ShareFileInputDTO.cs create mode 100644 WGShare.Domain/DTOs/File/ShareFileOutputDTO.cs create mode 100644 WGShare.Domain/DTOs/Login/AnonymousLoginDTO.cs create mode 100644 WGShare.Domain/DTOs/Login/UserLoginDTO.cs create mode 100644 WGShare.Domain/DTOs/Perm/PermissionInputDTO.cs create mode 100644 WGShare.Domain/DTOs/Role/RoleInputDTO.cs create mode 100644 WGShare.Domain/DTOs/Role/RolePermInputDTO.cs create mode 100644 WGShare.Domain/DTOs/Room/RoomInputDTO.cs create mode 100644 WGShare.Domain/DTOs/Room/RoomOutputDTO.cs create mode 100644 WGShare.Domain/DTOs/Tenant/TenantInputDTO.cs create mode 100644 WGShare.Domain/DTOs/User/UserChangePwdDTO.cs create mode 100644 WGShare.Domain/DTOs/User/UserInputDTO.cs create mode 100644 WGShare.Domain/DTOs/User/UserOutputDTO.cs create mode 100644 WGShare.Domain/DTOs/User/UserPremInputDTO.cs create mode 100644 WGShare.Domain/DTOs/User/UserSearchDTO.cs create mode 100644 WGShare.Domain/Entities/Admin.cs create mode 100644 WGShare.Domain/Entities/Permission.cs create mode 100644 WGShare.Domain/Entities/Role.cs create mode 100644 WGShare.Domain/Entities/RolePrem.cs create mode 100644 WGShare.Domain/Entities/Room.cs create mode 100644 WGShare.Domain/Entities/RoomManager.cs create mode 100644 WGShare.Domain/Entities/ShareFile.cs create mode 100644 WGShare.Domain/Entities/Tenant.cs create mode 100644 WGShare.Domain/Entities/User.cs create mode 100644 WGShare.Domain/Entities/UserPrem.cs create mode 100644 WGShare.Domain/Enums/MenuType.cs create mode 100644 WGShare.Domain/FriendlyException/ErrorCode.cs create mode 100644 WGShare.Domain/FriendlyException/ExceptionNotice.cs create mode 100644 WGShare.Domain/FriendlyException/Exceptions/FriendlyInternalException.cs create mode 100644 WGShare.Domain/FriendlyException/Oops.cs create mode 100644 WGShare.Domain/GeneralModel/PagedBaseDto.cs create mode 100644 WGShare.Domain/GeneralModel/PagedResult.cs create mode 100644 WGShare.Domain/GeneralModel/UniformResult.cs create mode 100644 WGShare.Domain/WGShare.Domain.csproj diff --git a/WGShare.API.sln b/WGShare.API.sln new file mode 100644 index 0000000..6fad96e --- /dev/null +++ b/WGShare.API.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34723.18 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WGShare.API", "WGShare.API\WGShare.API.csproj", "{A5611B2B-6FFE-48BE-9AB5-EA846A47E37D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WGShare.Domain", "WGShare.Domain\WGShare.Domain.csproj", "{93A88636-4DAE-4832-A2F7-CAEB193017A3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A5611B2B-6FFE-48BE-9AB5-EA846A47E37D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A5611B2B-6FFE-48BE-9AB5-EA846A47E37D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A5611B2B-6FFE-48BE-9AB5-EA846A47E37D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A5611B2B-6FFE-48BE-9AB5-EA846A47E37D}.Release|Any CPU.Build.0 = Release|Any CPU + {93A88636-4DAE-4832-A2F7-CAEB193017A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {93A88636-4DAE-4832-A2F7-CAEB193017A3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {93A88636-4DAE-4832-A2F7-CAEB193017A3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {93A88636-4DAE-4832-A2F7-CAEB193017A3}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {CCBE5CF2-07F8-444A-9664-FA34CBB56143} + EndGlobalSection +EndGlobal diff --git a/WGShare.API/Controllers/AuthController.cs b/WGShare.API/Controllers/AuthController.cs new file mode 100644 index 0000000..cf10d26 --- /dev/null +++ b/WGShare.API/Controllers/AuthController.cs @@ -0,0 +1,187 @@ +using Masuit.Tools; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using System.Configuration; +using System.Security.Claims; +using WGShare.API.Controllers.Basic; +using WGShare.API.Helpers; +using WGShare.Domain.DTOs.Login; +using WGShare.Domain.Entities; +using WGShare.Domain.FriendlyException; + +namespace WGShare.API.Controllers +{ + [Route("auth")] + public class AuthController : BasicController + { + private readonly ISqlSugarClient _sqlSugar; + private readonly JwtHelper _jwtHelper; + + public AuthController(ISqlSugarClient sqlSugar, JwtHelper jwtHelper) + { + _sqlSugar = sqlSugar; + _jwtHelper = jwtHelper; + } + + /// + /// 检查用户名 + /// + /// + /// + [HttpGet("check-user"), AllowAnonymous] + public async Task CheckUser([FromQuery] string userName) + { + return await _sqlSugar.Queryable().AnyAsync(x => x.IsDelete == false && x.UserName == userName); + } + + /// + /// 正常账号登录 + /// + /// + [HttpPost("login"), AllowAnonymous] + public async Task Login([FromBody] UserLoginDTO loginDTO) + { + var user = await _sqlSugar.Queryable() + .FirstAsync(x => x.UserName == loginDTO.Account && x.IsDelete == false && x.Pwd == loginDTO.Pwd); + if (user == null) + { + throw Oops.Oh("用户名或密码不正确!"); + } + + var tenant = await _sqlSugar.Queryable().FirstAsync(x => x.Id == user.TenantId); + if (tenant == null || tenant.IsDelete == true) + { + throw Oops.Oh("该区域账号已停用,请联系管理员"); + } + + if (await _sqlSugar.Queryable().AnyAsync(x => x.IsDelete == true && x.Id == user.RoleId)) + { + throw Oops.Oh("该角色账号已停用,请联系管理员"); + } + + var perms = await _sqlSugar.Queryable() + .InnerJoin((m, rm) => m.Id == rm.PermId) + .Where((m, rm) => rm.RoleId == user.RoleId) + .Distinct() + .ToListAsync(); + + var btnAutn = new List(); + btnAutn.Add(new Claim("perm", perms.Sum(x => x.PermValue).ToString())); + btnAutn.Add(new Claim("role", user.RoleId)); + btnAutn.Add(new Claim("tenant", user.TenantId)); + + return Ok(new + { + perms = perms.Sum(x => x.PermValue), + token = _jwtHelper.CreateToken(user.Id, btnAutn), + roleId = user.RoleId, + userName = user.UserName, + tenantName = tenant.TenantName + }); + } + + /// + /// 匿名登录,直接进入会议室 + /// + /// + [HttpPost("anon-login")] + public async Task Login([FromBody] AnonymousLoginDTO loginDTO) + { + + var room = await _sqlSugar.Queryable().FirstAsync(x => x.Id == loginDTO.RoomId); + if (room == null) + { + throw Oops.Oh("会议号无效"); + } + var anonRoleId = "2"; + + // 匿名登录使用普通用户身份 + var perms = await _sqlSugar.Queryable() + .InnerJoin((m, rm) => m.Id == rm.PermId) + .Where((m, rm) => rm.RoleId == anonRoleId) + .Distinct() + .ToListAsync(); + + var tenant = await _sqlSugar.Queryable().FirstAsync(x => x.Id == room.TenantId); + if (tenant == null || tenant.IsDelete == true) + { + throw Oops.Oh("该区域账号已停用,请联系管理员"); + } + + + var btnAutn = new List(); + btnAutn.Add(new Claim("perm", perms.Sum(x => x.PermValue).ToString())); + btnAutn.Add(new Claim("role", anonRoleId)); + btnAutn.Add(new Claim("tenant", room.TenantId)); + btnAutn.Add(new Claim("mac", loginDTO.Mac)); + btnAutn.Add(new Claim("machine", loginDTO.MachineName)); + btnAutn.Add(new Claim("nickName", loginDTO.NickName)); + + return Ok(new + { + perms = perms.Sum(x => x.PermValue), + token = _jwtHelper.CreateToken("0", btnAutn), + roleId = anonRoleId, + userName = loginDTO.NickName, + tenantName = tenant.TenantName + }); + } + + /// + /// 登出(暂未处理任何业务逻辑) + /// + /// + [HttpPost("logout")] + public async Task Logout() + { + return true; + } + + + + #region 后台管理员登录接口 + /// + /// 管理员登录 + /// + /// + [HttpPost("admin/login"), AllowAnonymous] + public async Task LoginForAdmin([FromBody] UserLoginDTO loginDTO) + { + var adminClient = _sqlSugar.AsTenant().GetConnection("usercenter"); + + var user = await adminClient.Queryable() + .FirstAsync(x => x.Account == loginDTO.Account && x.Password == loginDTO.Pwd); + if (user == null) + { + throw Oops.Oh("用户名或密码不正确!"); + } + + return _jwtHelper.CreateToken(user.Id); + } + + /// + /// 管理员信息 + /// + /// + [HttpGet("admin/info")] + public async Task GetAdminInfo() + { + var adminClient = _sqlSugar.AsTenant().GetConnection("usercenter"); + + var user = await adminClient.Queryable() + .FirstAsync(x => x.Id == UId); + if (user == null) + { + throw Oops.Oh("管理员不存在!"); + } + + return Ok(new + { + name = user.Name, + id = user.Id, + }); + } + #endregion + } +} diff --git a/WGShare.API/Controllers/Backend/PremController.cs b/WGShare.API/Controllers/Backend/PremController.cs new file mode 100644 index 0000000..55cea1d --- /dev/null +++ b/WGShare.API/Controllers/Backend/PremController.cs @@ -0,0 +1,93 @@ +using Mapster; +using Masuit.Tools; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using WGShare.API.Controllers.Basic; +using WGShare.Domain.DTOs.Perm; +using WGShare.Domain.DTOs.Role; +using WGShare.Domain.Entities; +using WGShare.Domain.FriendlyException; +using Yitter.IdGenerator; + +namespace WGShare.API.Controllers.Backend +{ + [Route("be/perm")] + public class PremController : BasicController + { + private readonly ISqlSugarClient _sqlSugar; + + public PremController(ISqlSugarClient sqlSugar) + { + _sqlSugar = sqlSugar; + } + + + [HttpGet("{id}")] + public async Task GetSingle([FromRoute] string id) + { + return await _sqlSugar.Queryable().FirstAsync(x => x.Id == id); + } + + [HttpGet("all")] + public async Task> GetAll() + { + return await _sqlSugar.Queryable().ToListAsync(); + } + + [HttpPost] + public async Task Add([FromBody] PermissionInputDTO input) + { + var entity = input.Adapt(); + if (await _sqlSugar.Queryable().AnyAsync(x => x.PermValue == input.PermValue)) + { + throw Oops.Oh("权限值不能重复"); + } + entity.Id = YitIdHelper.NextId().ToString(); + + return await _sqlSugar.Insertable(entity).ExecuteCommandAsync() > 0; + } + + /// + /// 获取最新权限值 + /// + /// + [HttpGet("vale")] + public async Task GetPermValue() + { + var maxPerm = await _sqlSugar.Queryable().MaxAsync(x => x.PermValue); + if (maxPerm == 0) + { + return 1; + } + return maxPerm << 1; + } + + [HttpPut] + public async Task Modify([FromBody] PermissionInputDTO input) + { + var entity = input.Adapt(); + + if (await _sqlSugar.Queryable().AnyAsync(x => x.PermValue == input.PermValue && x.Id != input.Id)) + { + throw Oops.Oh("权限值不能重复"); + } + + return await _sqlSugar.Updateable(entity).ExecuteCommandAsync() > 0; + } + + [HttpDelete] + public async Task Delete([FromQuery] string id) + { + var roles = await _sqlSugar.Queryable() + .InnerJoin((r, rp) => r.Id == rp.RoleId) + .Where((r, rp) => rp.PermId == id) + .Select((r, rp) => r.RoleName).ToListAsync(); + if (!roles.IsNullOrEmpty()) + { + throw Oops.Oh($@"[{string.Join(',', roles)}]角色已使用,无法删除!"); + } + + return await _sqlSugar.Deleteable().Where(x => x.Id == id).ExecuteCommandHasChangeAsync(); + } + } +} diff --git a/WGShare.API/Controllers/Backend/RoleController.cs b/WGShare.API/Controllers/Backend/RoleController.cs new file mode 100644 index 0000000..24eea8a --- /dev/null +++ b/WGShare.API/Controllers/Backend/RoleController.cs @@ -0,0 +1,86 @@ +using Mapster; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using WGShare.API.Controllers.Basic; +using WGShare.Domain.DTOs.Role; +using WGShare.Domain.Entities; +using Yitter.IdGenerator; + +namespace WGShare.API.Controllers.Backend +{ + [Route("be/role")] + public class RoleController : BasicController + { + private readonly ISqlSugarClient _sqlSugar; + + public RoleController(ISqlSugarClient sqlSugar) + { + _sqlSugar = sqlSugar; + } + + + [HttpGet("{id}")] + public async Task GetSingle([FromRoute] string id) + { + return await _sqlSugar.Queryable().FirstAsync(x => x.Id == id); + } + + [HttpGet("list")] + public async Task> GetPageList() + { + return await _sqlSugar.Queryable().ToListAsync(); + } + + [HttpPost] + public async Task Add([FromBody] RoleInputDTO inputDTO) + { + var entity = inputDTO.Adapt(); + entity.Id = YitIdHelper.NextId().ToString(); + + return await _sqlSugar.Insertable(entity).ExecuteCommandAsync() > 0; + } + + [HttpPut] + public async Task Modify([FromBody] RoleInputDTO inputDTO) + { + var entity = inputDTO.Adapt(); + + return await _sqlSugar.Updateable(entity) + .UpdateColumns(x => new { x.RoleName }).ExecuteCommandAsync() > 0; + } + + [HttpDelete] + public async Task Delete([FromBody] params string[] ids) + { + return await _sqlSugar.Updateable() + .SetColumns(x => x.IsDelete == true) + .Where(x => ids.Contains(x.Id)).ExecuteCommandHasChangeAsync(); + } + + [HttpGet("dp-list")] + public async Task> GetDropDownList() + { + return await _sqlSugar.Queryable().Where(x => x.IsDelete == false).ToListAsync(); + } + + [HttpPost("auth-perm")] + public async Task PermAuth([FromQuery] string roleId, [FromBody] List inputDTO) + { + var entity = inputDTO.Adapt>(); + + await _sqlSugar.Deleteable() + .Where(x => x.RoleId == roleId).ExecuteCommandAsync(); + + return await _sqlSugar.Insertable(entity).ExecuteCommandAsync() > 0; + } + + [HttpGet("auth-perm")] + public async Task> GetPermAuth([FromQuery] string roleId) + { + return await _sqlSugar.Queryable() + .InnerJoin((p, rp) => p.Id == rp.PermId) + .Where((p, rp) => rp.RoleId == roleId) + .ToListAsync(); + } + } +} diff --git a/WGShare.API/Controllers/Backend/TenantController.cs b/WGShare.API/Controllers/Backend/TenantController.cs new file mode 100644 index 0000000..d70dcd4 --- /dev/null +++ b/WGShare.API/Controllers/Backend/TenantController.cs @@ -0,0 +1,69 @@ +using Mapster; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using WGShare.API.Controllers.Basic; +using WGShare.Domain.DTOs.Tenant; +using WGShare.Domain.DTOs.User; +using WGShare.Domain.Entities; +using WGShare.Domain.FriendlyException; +using WGShare.Domain.GeneralModel; +using Yitter.IdGenerator; + +namespace WGShare.API.Controllers.Backend +{ + [Route("be/tenant")] + public class TenantController : BasicController + { + private readonly ISqlSugarClient _sqlSugar; + + public TenantController(ISqlSugarClient sqlSugar) + { + _sqlSugar = sqlSugar; + } + + + [HttpGet("{id}")] + public async Task GetSingle([FromRoute] string id) + { + return await _sqlSugar.Queryable().FirstAsync(x => x.Id == id); + } + + [HttpGet("list")] + public async Task> GetList() + { + return await _sqlSugar.Queryable().ToListAsync(); + } + + [HttpPost] + public async Task Add([FromBody] TenantInputDTO inputDTO) + { + var entity = inputDTO.Adapt(); + entity.Id = YitIdHelper.NextId().ToString(); + return await _sqlSugar.Insertable(entity).ExecuteCommandAsync() > 0; + } + + [HttpPut] + public async Task Modify([FromBody] TenantInputDTO inputDTO) + { + var entity = inputDTO.Adapt(); + + + return await _sqlSugar.Updateable(entity) + .UpdateColumns(x => new { x.TenantName }).ExecuteCommandAsync() > 0; + } + + [HttpGet] + public async Task Delete([FromQuery] string id, [FromQuery] bool enable) + { + return await _sqlSugar.Updateable() + .SetColumns(x => x.IsDelete == enable) + .Where(x => x.Id == id).ExecuteCommandHasChangeAsync(); + } + + [HttpGet("dp-list")] + public async Task> GetDropDownList() + { + return await _sqlSugar.Queryable().Where(x => x.IsDelete == false).ToListAsync(); + } + } +} diff --git a/WGShare.API/Controllers/Backend/UserController.cs b/WGShare.API/Controllers/Backend/UserController.cs new file mode 100644 index 0000000..60a12ad --- /dev/null +++ b/WGShare.API/Controllers/Backend/UserController.cs @@ -0,0 +1,118 @@ +using Mapster; +using Microsoft.AspNetCore.Components.Forms; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using WGShare.API.Controllers.Basic; +using WGShare.Domain.DTOs.User; +using WGShare.Domain.Entities; +using WGShare.Domain.FriendlyException; +using WGShare.Domain.GeneralModel; +using Yitter.IdGenerator; + +namespace WGShare.API.Controllers.Backend +{ + [Route("be/user")] + public class UserController : BasicController + { + private readonly ISqlSugarClient _sqlSugar; + + public UserController(ISqlSugarClient sqlSugar) + { + _sqlSugar = sqlSugar; + } + + + [HttpGet("{id}")] + public async Task GetSingle([FromRoute] string id) + { + return await _sqlSugar.Queryable().FirstAsync(x => x.Id == id); + } + + [HttpGet("list")] + public async Task> GetPageList([FromQuery] UserSearchDTO searchDTO) + { + RefAsync total = 0; + + var list = await _sqlSugar.Queryable() + .InnerJoin((u, r) => u.RoleId == r.Id) + .InnerJoin((u, r, t) => u.TenantId == t.Id) + .WhereIF(!string.IsNullOrWhiteSpace(searchDTO.keyword), + u => u.UserName.Contains(searchDTO.keyword) || u.Account.Contains(searchDTO.keyword) || u.Id.Contains(searchDTO.keyword)) + .WhereIF(!string.IsNullOrWhiteSpace(searchDTO.TenantId), u => u.TenantId == searchDTO.TenantId) + .WhereIF(!string.IsNullOrWhiteSpace(searchDTO.RoleId), u => u.RoleId == searchDTO.RoleId) + //.Where(u => u.IsDelete == false) + .Select((u, r, t) => new User + { + Id = u.Id.SelectAll(), + RoleName = r.RoleName, + TenantName = t.TenantName + }) + .ToPageListAsync(searchDTO.PageIndex, searchDTO.PageSize, total); + + return PagedResult.Create(list, total.Value); + } + + [HttpPost] + public async Task Add([FromBody] UserInputDTO userInput) + { + var entity = userInput.Adapt(); + entity.Id = YitIdHelper.NextId().ToString(); + if (await _sqlSugar.Queryable().AnyAsync(x => x.Account == entity.Account)) + { + throw Oops.Oh("账号已存在!"); + } + + return await _sqlSugar.Insertable(entity).ExecuteCommandAsync() > 0; + } + + [HttpPut] + public async Task Modify([FromBody] UserInputDTO inputDTO) + { + var entity = inputDTO.Adapt(); + + if (await _sqlSugar.Queryable().AnyAsync(x => x.Account == entity.Account && x.Id != inputDTO.Id)) + { + throw Oops.Oh("账号已存在!"); + } + + return await _sqlSugar.Updateable(entity) + .IgnoreColumns(x => new { x.Pwd }).ExecuteCommandAsync() > 0; + } + + [HttpPut("pwd")] + public async Task ModifyPassword([FromBody] UserChangePwdDTO inputDTO) + { + var entity = inputDTO.Adapt(); + + return await _sqlSugar.Updateable(entity) + .UpdateColumns(x => new { x.Pwd }).ExecuteCommandAsync() > 0; + } + + [HttpDelete] + public async Task Delete([FromBody] params string[] ids) + { + return await _sqlSugar.Updateable() + .SetColumns(x => x.IsDelete == true) + .Where(x => ids.Contains(x.Id)).ExecuteCommandHasChangeAsync(); + } + + /// + /// 权限修改 + /// + /// + [HttpPut("auth-prem")] + [Obsolete] + public async Task EditPremissions([FromBody] List inputDTOs) + { + + var entity = inputDTOs.Adapt(); + + + await _sqlSugar.Deleteable() + .Where(x => inputDTOs.Select(x => x.UserId).Contains(x.UserId)).ExecuteCommandAsync(); + + + await _sqlSugar.Insertable(entity).ExecuteCommandAsync(); + } + } +} diff --git a/WGShare.API/Controllers/Basic/BasicController.cs b/WGShare.API/Controllers/Basic/BasicController.cs new file mode 100644 index 0000000..776fa73 --- /dev/null +++ b/WGShare.API/Controllers/Basic/BasicController.cs @@ -0,0 +1,51 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using SqlSugar.Extensions; +using WGShare.Domain.FriendlyException; + +namespace WGShare.API.Controllers.Basic +{ + [ApiController] + [Authorize] + public class BasicController : ControllerBase + { + public string UId + { + get + { + var uid = HttpContext.User.Claims.FirstOrDefault(x => x.Type == "uid").Value; + if (string.IsNullOrWhiteSpace(uid)) + { + throw Oops.Oh("用户信息有误,请重新登录"); + } + return uid; + } + } + + public string RoleId + { + get + { + var roleId = HttpContext.User.Claims.FirstOrDefault(x => x.Type == "role").Value; + if (string.IsNullOrWhiteSpace(roleId)) + { + throw Oops.Oh("用户信息有误,请重新登录"); + } + return roleId; + } + } + + public string TenantId + { + get + { + var tenant = HttpContext.User.Claims.FirstOrDefault(x => x.Type == "tenant").Value; + if (string.IsNullOrWhiteSpace(tenant)) + { + throw Oops.Oh("用户信息有误,请重新登录"); + } + return tenant; + } + } + } +} diff --git a/WGShare.API/Controllers/Frontend/HomeController.cs b/WGShare.API/Controllers/Frontend/HomeController.cs new file mode 100644 index 0000000..7078f5b --- /dev/null +++ b/WGShare.API/Controllers/Frontend/HomeController.cs @@ -0,0 +1,66 @@ +using Mapster; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using WGShare.API.Controllers.Basic; +using WGShare.Domain.DTOs.Room; +using WGShare.Domain.Entities; +using WGShare.Domain.FriendlyException; +using WGShare.Domain.GeneralModel; +using Yitter.IdGenerator; + +namespace WGShare.API.Controllers.Frontend +{ + /// + /// 首页接口 + /// + [Route("home")] + public class HomeController : BasicController + { + private readonly ISqlSugarClient _sqlSugar; + + public HomeController(ISqlSugarClient sqlSugar) + { + _sqlSugar = sqlSugar; + } + + + + /// + /// 获取会议室列表 + /// + /// + /// + [HttpGet("room")] + public async Task> GetRooms(PagedBaseDto dto) + { + RefAsync total = 0; + + var list = await _sqlSugar.Queryable() + .Where(x => x.TenantId == TenantId && x.IsDelete == false) + .ToPageListAsync(dto.PageIndex, dto.PageSize, total); + + return PagedResult.Create(list.Adapt>(), total.Value); + } + + /// + /// 创建会议室 + /// + /// + /// + [HttpPost("room")] + public async Task CreateRoom([FromBody] RoomInputDTO inputDTO) + { + var entity = inputDTO.Adapt(); + entity.Id = YitIdHelper.NextId().ToString(); + entity.TenantId = TenantId; + + if (await _sqlSugar.Queryable().AnyAsync(x => x.RoomNum == inputDTO.RoomNum)) + { + throw Oops.Oh("无效会议号,请重新输入"); + } + + return await _sqlSugar.Insertable(entity).ExecuteCommandAsync() > 0; + } + + } +} diff --git a/WGShare.API/Controllers/Frontend/RoomController.cs b/WGShare.API/Controllers/Frontend/RoomController.cs new file mode 100644 index 0000000..19d9116 --- /dev/null +++ b/WGShare.API/Controllers/Frontend/RoomController.cs @@ -0,0 +1,163 @@ +using Mapster; +using Masuit.Tools; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using System.CodeDom; +using WGShare.API.Controllers.Basic; +using WGShare.Domain.DTOs.File; +using WGShare.Domain.DTOs.Room; +using WGShare.Domain.DTOs.User; +using WGShare.Domain.Entities; +using WGShare.Domain.FriendlyException; +using WGShare.Domain.GeneralModel; +using Yitter.IdGenerator; +using ZstdSharp.Unsafe; + +namespace WGShare.API.Controllers.Frontend +{ + /// + /// 会议室接口 + /// + [Route("room")] + public class RoomController : BasicController + { + private readonly ISqlSugarClient _sqlSugar; + + public RoomController(ISqlSugarClient sqlSugar) + { + this._sqlSugar = sqlSugar; + } + + /// + /// 获取会议室管理员 + /// + /// + [HttpGet("manager")] + public async Task> GetRoomManager([FromQuery] string roomId) + { + return await _sqlSugar.Queryable() + .Where(x => x.RoomId == roomId) + .Select(x => x.UserId) + .ToListAsync(); + } + + /// + /// 设置房间管理员 + /// + /// + [HttpPost("manager")] + public async Task SetRoomManager([FromQuery] string roomId, [FromBody] List userIds) + { + var entities = userIds.ConvertAll(x => new RoomManager + { + RoomId = roomId, + UserId = x + }); + + return await _sqlSugar.Insertable(entities).ExecuteCommandAsync() > 0; + } + + /// + /// 查询用户信息 + /// + /// + [HttpGet("user")] + public async Task> GetUsers([FromQuery] string uidStr) + { + var uid = uidStr.Split(',', StringSplitOptions.RemoveEmptyEntries); + if (uid.IsNullOrEmpty()) + { + throw Oops.Oh("请输入需要查询的用户id,多id请用英文逗号,分割"); + } + + var users = await _sqlSugar.Queryable() + .Where(x => uid.Contains(x.Id)) + .ToListAsync(); + + return users.Adapt>(); + } + + /// + /// 检验房间是否存在 + /// + /// + [HttpGet("checkout"), AllowAnonymous] + public async Task ExistsRoom([FromQuery] string roomNum) + { + return await _sqlSugar.Queryable().AnyAsync(x => x.RoomNum == roomNum && x.IsDelete == false); + } + + /// + /// 获取单个会议室信息 + /// + /// + [HttpGet("{roomNum}")] + public async Task GetRoom([FromRoute] string roomNum) + { + var room = await _sqlSugar.Queryable().FirstAsync(x => x.RoomNum == roomNum && x.IsDelete == false); + if (room == null) + { + throw Oops.Oh("会议号无效"); + } + return room.Adapt(); + } + + /// + /// 分享上传文件 + /// + /// + /// + [HttpPost("file")] + public async Task AddFile([FromBody] ShareFileInputDTO inputDTO) + { + var entity = inputDTO.Adapt(); + entity.Id = YitIdHelper.NextId().ToString(); + entity.UserId = UId; + + return await _sqlSugar.Insertable(entity).ExecuteCommandAsync() > 0; + } + + /// + /// 删除文件 + /// + /// + [HttpDelete("file")] + public async Task DeleteFile([FromBody] List ids) + { + return await _sqlSugar.Updateable() + .SetColumns(x => x.IsDelete == true) + .Where(x => ids.Contains(x.Id)) + .ExecuteCommandHasChangeAsync(); + } + + /// + /// 获取分享文件列表 + /// + /// + [HttpGet("file")] + public async Task> GetFilesList([FromQuery] string roomId, [FromBody] PagedBaseDto pagedBaseDto) + { + RefAsync total = 0; + var list = await _sqlSugar.Queryable() + .LeftJoin((sf, u) => sf.UserId == u.Id) + .Where(x => x.IsDelete == false && x.RoomId == roomId) + .Select((sf, u) => new ShareFileOutputDTO + { + Id = sf.Id, + UserId = u.Id, + UserName = u.UserName, + FileName = sf.FileName, + FileUrl = sf.FileUrl, + RoomId = u.Id, + Size = sf.Size, + ModifyTime = sf.ModifyTime, + DownloadCount = sf.DownloadCount, + }).ToPageListAsync(pagedBaseDto.PageIndex, pagedBaseDto.PageSize, total); + + return PagedResult.Create(list, total.Value); + } + + + } +} diff --git a/WGShare.API/Helpers/JwtHelper.cs b/WGShare.API/Helpers/JwtHelper.cs new file mode 100644 index 0000000..6565f2a --- /dev/null +++ b/WGShare.API/Helpers/JwtHelper.cs @@ -0,0 +1,53 @@ +using Masuit.Tools; +using Microsoft.IdentityModel.Tokens; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Text; + +namespace WGShare.API.Helpers +{ + public class JwtHelper + { + private readonly IConfiguration _configuration; + + public JwtHelper(IConfiguration configuration) + { + _configuration = configuration; + } + + public string CreateToken(string uid, List claims = null) + { + if (claims.IsNullOrEmpty()) + claims = new(); + claims.AddRange(new List + { + new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), + new Claim("uid", uid), + }); + + // 2. 从 appsettings.json 中读取SecretKey + var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:SecretKey"])); + + // 3. 选择加密算法 + var algorithm = SecurityAlgorithms.HmacSha256; + + // 4. 生成Credentials + var signingCredentials = new SigningCredentials(secretKey, algorithm); + + // 5. 根据以上,生成token + var jwtSecurityToken = new JwtSecurityToken( + _configuration["Jwt:Issuer"], //Issuer + _configuration["Jwt:Audience"], //Audience + claims, //Claims, + DateTime.Now, //notBefore + DateTime.Now.AddSeconds(_configuration["Jwt:Expires"].ToDouble()), //expires + signingCredentials //Credentials + ); + + // 6. 将token变为string + var token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken); + + return token; + } + } +} diff --git a/WGShare.API/Helpers/RedisHelper.cs b/WGShare.API/Helpers/RedisHelper.cs new file mode 100644 index 0000000..dc2fa57 --- /dev/null +++ b/WGShare.API/Helpers/RedisHelper.cs @@ -0,0 +1,47 @@ +using FreeRedis; + +namespace WGShare.API.Helpers +{ + /// + /// redis静态访问类 + /// + public abstract class RedisHelper + { + private static RedisClient _instance; + + /// + /// redis实例 + /// + public static RedisClient Instance + { + get + { + if (_instance == null) + { + throw new Exception("使用前初始化redis静态访问类 RedisHelper.Initialization(new FreeRedis.RedisClient(\"127.0.0.1:6379,password=123,defaultDatabase=13,maxpoolsize=50,prefix=key前辍\"));"); + } + + return _instance; + } + } + + + /// + /// 初始化redis静态访问类 RedisHelper.Initialization(new FreeRedis.RedisClient(\"127.0.0.1:6379,password=123,defaultDatabase=13,maxpoolsize=50,prefix=key前辍\")) + /// + /// + internal static void Initialization(FreeRedis.RedisClient redisClient) + { + _instance = redisClient; + } + + internal static ThreadLocal rnd = new ThreadLocal(() => new Random()); + /// + /// 随机秒(防止所有key同一时间过期,雪崩) + /// + /// 最小秒数 + /// 最大秒数 + /// + public static int RandomExpired(int minTimeoutSeconds, int maxTimeoutSeconds) => rnd.Value.Next(minTimeoutSeconds, maxTimeoutSeconds); + } +} diff --git a/WGShare.API/Program.cs b/WGShare.API/Program.cs new file mode 100644 index 0000000..eca2d6a --- /dev/null +++ b/WGShare.API/Program.cs @@ -0,0 +1,81 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Serialization; +using SqlSugar; +using WGShare.API.Helpers; +using WGShare.API.ServiceConfigs; +using Yitter.IdGenerator; + +namespace WGShare.API +{ + public class Program + { + public static void Main(string[] args) + { + var builder = WebApplication.CreateBuilder(args); + var configuration = builder.Configuration; + + // Add services to the container. + + builder.Services.AddControllers(options => + { + // ȫ쳣ڴ д try catch + options.Filters.Add(); + // ȫģ͸ֵĬֵ ͳһظʽ + options.Filters.Add(); + }).AddNewtonsoftJson(options => + { + //޸ƵлʽĸСдշʽ + options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); + //Ĭϸʽ ʽ1 + options.SerializerSettings.Converters.Add(new IsoDateTimeConverter() { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" }); + //ѭ + options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; + //ֵ + //options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; + }); + // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle + builder.Services.AddEndpointsApiExplorer(); + builder.Services.AddSwaggerGen(); + builder.Services.AddSingleton(new JwtHelper(configuration)); + builder.Services.AddAuth(configuration["Jwt:Issuer"], + configuration["Jwt:Audience"], + configuration["Jwt:SecretKey"]); + builder.Services.AddSqlsugar(builder.Environment.EnvironmentName, new ConnectionConfig + { + DbType = DbType.MySql, + ConfigId = "metting", + ConnectionString = configuration.GetConnectionString("metting"), + IsAutoCloseConnection = true + }, + new ConnectionConfig + { + DbType = DbType.MySql, + ConfigId = "usercenter", + ConnectionString = configuration.GetConnectionString("usercenter"), + IsAutoCloseConnection = true + }); + YitIdHelper.SetIdGenerator(new IdGeneratorOptions(1)); + RedisHelper.Initialization(new FreeRedis.RedisClient(configuration["Redis:master"])); + + var app = builder.Build(); + + // Configure the HTTP request pipeline. + if (app.Environment.IsDevelopment()) + { + app.UseSwagger(); + app.UseSwaggerUI(); + app.UseCustomCors(); + } + + //мUseAuthentication֤Ҫ֤мǰã UseAuthorizationȨ + app.UseAuthentication(); + app.UseAuthorization(); + + + app.MapControllers(); + + app.Run(); + } + } +} diff --git a/WGShare.API/Properties/launchSettings.json b/WGShare.API/Properties/launchSettings.json new file mode 100644 index 0000000..bb54335 --- /dev/null +++ b/WGShare.API/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:42628", + "sslPort": 0 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5192", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/WGShare.API/ServiceConfigs/AuthenticationServiceExtensions.cs b/WGShare.API/ServiceConfigs/AuthenticationServiceExtensions.cs new file mode 100644 index 0000000..1066293 --- /dev/null +++ b/WGShare.API/ServiceConfigs/AuthenticationServiceExtensions.cs @@ -0,0 +1,52 @@ +using Mapster; +using MapsterMapper; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Serialization; +using Newtonsoft.Json; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.IdentityModel.Tokens; +using System.Text; +using System.Reflection.Metadata; + +namespace WGShare.API.ServiceConfigs +{ + public static class AuthenticationServiceExtensions + { + /// + /// 添加认证和授权 + /// + /// 服务集合 + /// + public static IServiceCollection AddAuth(this IServiceCollection services, string issuer, string audience, string secretKey) + { + services.AddAuthentication(options => + { + options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; + }).AddJwtBearer(options => + { + options.TokenValidationParameters = new TokenValidationParameters() + { + ValidateIssuer = true, //是否验证Issuer + ValidIssuer = issuer, //发行人Issuer + ValidateAudience = true, //是否验证Audience + ValidAudience = audience, //订阅人Audience + ValidateIssuerSigningKey = true, //是否验证SecurityKey + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey)), //SecurityKey + ValidateLifetime = true, //是否验证失效时间 + ClockSkew = TimeSpan.FromSeconds(30), //过期时间容错值,解决服务器端时间不同步问题(秒) + RequireExpirationTime = true, + }; + }); + + + return services; + //services.AddAuthorization(options => + //{ + // options.AddPolicy(Constant.Policy.FreePolicyName, + // policy => policy.RequireClaim(Constant.Auth.PermissionsKey, Constant.Auth.FreeClaimValue, Constant.Auth.VipClaimValue)); + // options.AddPolicy(Constant.Policy.VipPolicyName, + // policy => policy.RequireClaim(Constant.Auth.PermissionsKey, Constant.Auth.VipClaimValue)); + //}); + } + } +} diff --git a/WGShare.API/ServiceConfigs/CorsAppBuilderExtensions.cs b/WGShare.API/ServiceConfigs/CorsAppBuilderExtensions.cs new file mode 100644 index 0000000..b30e0a5 --- /dev/null +++ b/WGShare.API/ServiceConfigs/CorsAppBuilderExtensions.cs @@ -0,0 +1,30 @@ +using Microsoft.AspNetCore.Builder; + +namespace WGShare.API.ServiceConfigs +{ + /// + /// 跨域配置扩展服务 + /// + public static class CorsAppBuilderExtensions + { + /// + /// 允许所有跨域请求 (属于基础服务,若已调用 UseBasicServices 则无需调用) + /// + /// + /// + public static IApplicationBuilder UseCustomCors(this IApplicationBuilder app) + { + //// 获取配置文件中的允许跨域的地址 + //var hosts = AppSetting.AllowedHosts.Split("|", StringSplitOptions.RemoveEmptyEntries); + app.UseCors(options => + { + options.WithOrigins("*") // 允许跨域请求的地址 + .AllowAnyHeader() // 允许的请求标头 + .AllowAnyMethod(); // 允许跨域请求的类型 (GET,POST等) + + }); + + return app; + } + } +} diff --git a/WGShare.API/ServiceConfigs/GlobalExceptionFilter.cs b/WGShare.API/ServiceConfigs/GlobalExceptionFilter.cs new file mode 100644 index 0000000..8701751 --- /dev/null +++ b/WGShare.API/ServiceConfigs/GlobalExceptionFilter.cs @@ -0,0 +1,68 @@ +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Mvc; +using WGShare.Domain.GeneralModel; +using Masuit.Tools; +using WGShare.Domain.FriendlyException.Exceptions; +using WGShare.Domain.FriendlyException; + +namespace WGShare.API.ServiceConfigs +{ + /// + /// 全局异常捕获 + /// + public class GlobalExceptionFilter : IAsyncExceptionFilter + { + private readonly ILogger _logger; + + public GlobalExceptionFilter(ILogger logger) + { + _logger = logger; //在构造函数中注入日志处理实例 + } + + public async Task OnExceptionAsync(ExceptionContext context) + { + // 如果异常没有被处理则进行处理 + if (context.ExceptionHandled == false) + { + // 定义返回类型 + UniformResult result; + + // 如果为业务逻辑抛出的内部异常 + if (context.Exception is FriendlyInternalException ex) + { + // 企业微信异常通知 + //await ExceptionNotice.SendFriendlyExceptionAsync(ex); + + result = UniformResult + .Create(ex.FriendlyData, ex.ErrorCode, context.Exception.Message); + } + else + { + // 程序异常,不对外暴露程序异常细节 + result = UniformResult + .Create(null, 500, "程序出错啦🐞🐞🐞!"); + + //使用日志对象 _logger 的 LogError() 方法将异常信息写入日志文件 + _logger.LogError(context.Exception, context.Exception.Message); + + // 企业微信异常通知 + await ExceptionNotice.SendAsync(context.Exception, "全局异常捕获"); + } + + context.Result = new ContentResult + { + // 返回状态码设置为200,表示成功 + StatusCode = StatusCodes.Status200OK, + // 设置返回格式 + ContentType = "application/json;charset=utf-8", + Content = result.ToJsonString() + }; + + + } + + // 设置为true,表示异常已经被处理了 + context.ExceptionHandled = true; + } + } +} diff --git a/WGShare.API/ServiceConfigs/ModelActionFilter.cs b/WGShare.API/ServiceConfigs/ModelActionFilter.cs new file mode 100644 index 0000000..c965520 --- /dev/null +++ b/WGShare.API/ServiceConfigs/ModelActionFilter.cs @@ -0,0 +1,60 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using WGShare.Domain.GeneralModel; + +namespace WGShare.API.ServiceConfigs +{ + public class ModelActionFilter : ActionFilterAttribute + { + /// + /// 在Controller的Action执行后执行 + /// + /// + public override void OnActionExecuted(ActionExecutedContext context) + { + //特殊处理:对有ApiResultIgnoreAttribute标签的,不进行返回结果包装,原样输出 + //var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor; + //if (controllerActionDescriptor != null) + //{ + // var isDefined = controllerActionDescriptor.EndpointMetadata.Any(a => a.GetType().Equals(typeof(ApiResultIgnoreAttribute))); + // if (isDefined) + // { + // return; + // } + //} + // 返回结果为JsonResult的请求进行Result包装 + if (context.Result != null) + { + switch (context.Result) + { + case ObjectResult: + { + var result = context.Result as ObjectResult; + context.Result = new JsonResult(UniformResult.Create(result.Value)); + break; + } + case EmptyResult: + context.Result = new JsonResult(UniformResult.Create(null)); + break; + case ContentResult: + { + var result = context.Result as ContentResult; + context.Result = new JsonResult(UniformResult.Create(result.Content)); + break; + } + } + } + + base.OnActionExecuted(context); + } + + /// + /// 在Controller的Action执行前执行 + /// + /// + public override void OnActionExecuting(ActionExecutingContext context) + { + base.OnActionExecuting(context); + } + } +} diff --git a/WGShare.API/ServiceConfigs/SqlsugarServiceExtensions.cs b/WGShare.API/ServiceConfigs/SqlsugarServiceExtensions.cs new file mode 100644 index 0000000..ef6cae4 --- /dev/null +++ b/WGShare.API/ServiceConfigs/SqlsugarServiceExtensions.cs @@ -0,0 +1,66 @@ +using Mapster; +using MapsterMapper; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Serialization; +using Newtonsoft.Json; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.IdentityModel.Tokens; +using System.Text; +using System.Reflection.Metadata; +using SqlSugar; +using System.Text.RegularExpressions; + +namespace WGShare.API.ServiceConfigs +{ + public static class SqlsugarServiceExtensions + { + /// + /// 添加SqlSugar + /// + /// 服务集合 + /// + public static IServiceCollection AddSqlsugar(this IServiceCollection services, string env, params ConnectionConfig[] connectionConfigs) + { + SqlSugarScope sqlSugar = new SqlSugarScope(connectionConfigs.ToList(), + db => + { + if (env == Environments.Development) + { + // 正则表达式匹配Ip + var ipMatch = Regex.Match(db.CurrentConnectionConfig.ConnectionString, @"((25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))\.){3}(25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))"); + + var connections = db.CurrentConnectionConfig.ConnectionString.Split(';'); + string dbNamne = string.Empty; + foreach (var item in connections) + { + if (item.Contains("Database")) + { + dbNamne = item.Split('=')[1]; + } + } + + //SQL执行前 + db.Aop.OnLogExecuting = (sql, pars) => + { + // 打印 Sql 语句 + Console.WriteLine($@"{new string('=', 10)}BEGIN{new string('=', 5)} DB-IP:{ipMatch.Value} {new string('=', 5)} DB-Name:{dbNamne} {new string('=', 15)}"); + Console.WriteLine($"执行Sql:{Environment.NewLine}{sql}"); + Console.WriteLine($"参数:{db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value))}"); + }; + + //SQL执行完成 + db.Aop.OnLogExecuted = (sql, pars) => + { + //执行完了可以输出SQL执行时间 + Console.WriteLine("Sql用时:" + db.Ado.SqlExecutionTime.ToString()); + Console.WriteLine($@"{new string('=', 10)}END{new string('=', 7)} DB-IP:{ipMatch.Value} {new string('=', 5)} DB-Name:{dbNamne} {new string('=', 15)}"); + }; + } + }); + + services.AddSingleton(sqlSugar); + + return services; + } + } +} diff --git a/WGShare.API/WGShare.API.csproj b/WGShare.API/WGShare.API.csproj new file mode 100644 index 0000000..948283a --- /dev/null +++ b/WGShare.API/WGShare.API.csproj @@ -0,0 +1,18 @@ + + + + net8.0 + enable + enable + True + + + + + + + + + + + diff --git a/WGShare.API/appsettings.Development.json b/WGShare.API/appsettings.Development.json new file mode 100644 index 0000000..f5c2cc0 --- /dev/null +++ b/WGShare.API/appsettings.Development.json @@ -0,0 +1,15 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "ConnectionStrings": { + "metting": "Database=metting;Server=192.168.2.9;Port=3306;Uid=root;Pwd=qwe123!@#;AllowZeroDateTime=True;ConvertZeroDateTime=True;", + "usercenter": "Database=usercenter;Server=192.168.2.9;Port=3306;Uid=root;Pwd=qwe123!@#;AllowZeroDateTime=True;ConvertZeroDateTime=True;" + }, + "Redis": { + "master": "192.168.2.7:6379,password=qwe123!@#,defaultDatabase=12,name=wgshare,prefix=wgshare" + } +} diff --git a/WGShare.API/appsettings.json b/WGShare.API/appsettings.json new file mode 100644 index 0000000..f5b8963 --- /dev/null +++ b/WGShare.API/appsettings.json @@ -0,0 +1,23 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + "Jwt": { + "SecretKey": "apDbztyqjSNuvWnezhbdUxduhDidZbF897t2uTJs53RMdY9Cai7eexavBhka3HN6mcTe9oohjFg6bNffRRkcfMqnVKNBnmyPzkRgNopHGJAL7KMwkeZdZ7BaWnT57jCi", + "Issuer": "WGshareApi", + "Audience": "WGshareClient", + // 过期 秒 + "Expires": 14400 + }, + "ConnectionStrings": { + "metting": "Database=metting;Server=192.168.2.9;Port=3306;Uid=root;Pwd=qwe123!@#;AllowZeroDateTime=True;ConvertZeroDateTime=True;", + "usercenter": "Database=usercenter;Server=192.168.2.9;Port=3306;Uid=root;Pwd=qwe123!@#;AllowZeroDateTime=True;ConvertZeroDateTime=True;" + }, + "Redis": { + "master": "" + } +} diff --git a/WGShare.Domain/DTOs/File/ShareFileInputDTO.cs b/WGShare.Domain/DTOs/File/ShareFileInputDTO.cs new file mode 100644 index 0000000..7ca9986 --- /dev/null +++ b/WGShare.Domain/DTOs/File/ShareFileInputDTO.cs @@ -0,0 +1,29 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WGShare.Domain.DTOs.File +{ + public class ShareFileInputDTO + { + /// + /// 文件地址 + /// + public string FileUrl { get; set; } + /// + /// 文件大小 kb + /// + public double Size { get; set; } + /// + /// 文件名称 + /// + public string FileName { get; set; } + /// + /// 会议房间Id + /// + public string RoomId { get; set; } + } +} diff --git a/WGShare.Domain/DTOs/File/ShareFileOutputDTO.cs b/WGShare.Domain/DTOs/File/ShareFileOutputDTO.cs new file mode 100644 index 0000000..a145339 --- /dev/null +++ b/WGShare.Domain/DTOs/File/ShareFileOutputDTO.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WGShare.Domain.DTOs.File +{ + public class ShareFileOutputDTO + { + + public string Id { get; set; } + + /// + /// 文件地址 + /// + public string FileUrl { get; set; } + /// + /// 文件大小 kb + /// + public double Size { get; set; } + /// + /// 文件名称 + /// + public string FileName { get; set; } + /// + /// 会议房间Id + /// + public string RoomId { get; set; } + + public string UserId { get; set; } + + /// + /// 上传者名称 + /// + public string UserName { get; set; } + + /// + /// 更新时间 + /// + public DateTime ModifyTime { get; set; } + + public int DownloadCount { get; set; } + + } +} diff --git a/WGShare.Domain/DTOs/Login/AnonymousLoginDTO.cs b/WGShare.Domain/DTOs/Login/AnonymousLoginDTO.cs new file mode 100644 index 0000000..613349c --- /dev/null +++ b/WGShare.Domain/DTOs/Login/AnonymousLoginDTO.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WGShare.Domain.DTOs.Login +{ + public class AnonymousLoginDTO + { + public string NickName { get; set; } + + public string MachineName { get; set; } + + public string Mac { get; set; } + + public string RoomId { get; set; } + } +} diff --git a/WGShare.Domain/DTOs/Login/UserLoginDTO.cs b/WGShare.Domain/DTOs/Login/UserLoginDTO.cs new file mode 100644 index 0000000..5940bbe --- /dev/null +++ b/WGShare.Domain/DTOs/Login/UserLoginDTO.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WGShare.Domain.DTOs.Login +{ + public class UserLoginDTO + { + public string Account { get; set; } + public string Pwd { get; set; } + } +} diff --git a/WGShare.Domain/DTOs/Perm/PermissionInputDTO.cs b/WGShare.Domain/DTOs/Perm/PermissionInputDTO.cs new file mode 100644 index 0000000..c250719 --- /dev/null +++ b/WGShare.Domain/DTOs/Perm/PermissionInputDTO.cs @@ -0,0 +1,26 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yitter.IdGenerator; + +namespace WGShare.Domain.DTOs.Perm +{ + public class PermissionInputDTO + { + /// + /// 菜单/按钮Id + /// + public string? Id { get; set; } + /// + /// 权限名称 + /// + public string PermName { get; set; } + /// + /// 权限值 + /// + public int PermValue { get; set; } + } +} diff --git a/WGShare.Domain/DTOs/Role/RoleInputDTO.cs b/WGShare.Domain/DTOs/Role/RoleInputDTO.cs new file mode 100644 index 0000000..aa3028a --- /dev/null +++ b/WGShare.Domain/DTOs/Role/RoleInputDTO.cs @@ -0,0 +1,22 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yitter.IdGenerator; + +namespace WGShare.Domain.DTOs.Role +{ + public class RoleInputDTO + { + /// + /// + /// + public string? Id { get; set; } + /// + /// 角色名 + /// + public string RoleName { get; set; } + } +} diff --git a/WGShare.Domain/DTOs/Role/RolePermInputDTO.cs b/WGShare.Domain/DTOs/Role/RolePermInputDTO.cs new file mode 100644 index 0000000..ebd0dac --- /dev/null +++ b/WGShare.Domain/DTOs/Role/RolePermInputDTO.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WGShare.Domain.DTOs.Role +{ + public class RolePermInputDTO + { + public string RoleId { get; set; } + + public string PermId { get; set; } + } +} diff --git a/WGShare.Domain/DTOs/Room/RoomInputDTO.cs b/WGShare.Domain/DTOs/Room/RoomInputDTO.cs new file mode 100644 index 0000000..428323c --- /dev/null +++ b/WGShare.Domain/DTOs/Room/RoomInputDTO.cs @@ -0,0 +1,24 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yitter.IdGenerator; + +namespace WGShare.Domain.DTOs.Room +{ + public class RoomInputDTO + { + /// + /// 会议室名称 + /// + [SugarColumn(ColumnName = "room_name")] + public string RoomName { get; set; } + /// + /// 会议号 + /// + [SugarColumn(ColumnName = "room_num")] + public string RoomNum { get; set; } + } +} diff --git a/WGShare.Domain/DTOs/Room/RoomOutputDTO.cs b/WGShare.Domain/DTOs/Room/RoomOutputDTO.cs new file mode 100644 index 0000000..e85a478 --- /dev/null +++ b/WGShare.Domain/DTOs/Room/RoomOutputDTO.cs @@ -0,0 +1,24 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yitter.IdGenerator; + +namespace WGShare.Domain.DTOs.Room +{ + public class RoomOutputDTO + { + public string Id { get; set; } + /// + /// 会议室名称 + /// + public string RoomName { get; set; } + + /// + /// 会议号 + /// + public string RoomNum { get; set; } + } +} diff --git a/WGShare.Domain/DTOs/Tenant/TenantInputDTO.cs b/WGShare.Domain/DTOs/Tenant/TenantInputDTO.cs new file mode 100644 index 0000000..daf3f36 --- /dev/null +++ b/WGShare.Domain/DTOs/Tenant/TenantInputDTO.cs @@ -0,0 +1,23 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yitter.IdGenerator; + +namespace WGShare.Domain.DTOs.Tenant +{ + public class TenantInputDTO + { + /// + /// + /// + public string? Id { get; set; } + + /// + /// 租户名称 + /// + public string TenantName { get; set; } + } +} diff --git a/WGShare.Domain/DTOs/User/UserChangePwdDTO.cs b/WGShare.Domain/DTOs/User/UserChangePwdDTO.cs new file mode 100644 index 0000000..261e5e8 --- /dev/null +++ b/WGShare.Domain/DTOs/User/UserChangePwdDTO.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WGShare.Domain.DTOs.User +{ + public class UserChangePwdDTO + { + public string Id { get; set; } + public string Pwd { get; set; } + } +} diff --git a/WGShare.Domain/DTOs/User/UserInputDTO.cs b/WGShare.Domain/DTOs/User/UserInputDTO.cs new file mode 100644 index 0000000..6576755 --- /dev/null +++ b/WGShare.Domain/DTOs/User/UserInputDTO.cs @@ -0,0 +1,35 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WGShare.Domain.DTOs.User +{ + public class UserInputDTO + { + + public string? Id { get; set; } + /// + /// 用户名称 + /// + public string UserName { get; set; } + /// + /// 账号 + /// + public string Account { get; set; } + /// + /// 密码 + /// + public string Pwd { get; set; } + /// + /// + /// + public string RoleId { get; set; } + /// + /// 租户id + /// + public string TenantId { get; set; } + } +} diff --git a/WGShare.Domain/DTOs/User/UserOutputDTO.cs b/WGShare.Domain/DTOs/User/UserOutputDTO.cs new file mode 100644 index 0000000..b04cbb1 --- /dev/null +++ b/WGShare.Domain/DTOs/User/UserOutputDTO.cs @@ -0,0 +1,25 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WGShare.Domain.DTOs.User +{ + public class UserOutputDTO + { + public string Id { get; set; } + /// + /// 用户名称 + /// + public string UserName { get; set; } + /// + /// 账号 + /// + public string Account { get; set; } + public string RoleId { get; set; } + public string RoleName { get; set; } + + } +} diff --git a/WGShare.Domain/DTOs/User/UserPremInputDTO.cs b/WGShare.Domain/DTOs/User/UserPremInputDTO.cs new file mode 100644 index 0000000..f61f3b5 --- /dev/null +++ b/WGShare.Domain/DTOs/User/UserPremInputDTO.cs @@ -0,0 +1,22 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WGShare.Domain.DTOs.User +{ + public class UserPremInputDTO + { + + /// + /// 用户Id + /// + public string UserId { get; set; } + /// + /// 权限Id + /// + public string PermId { get; set; } + } +} diff --git a/WGShare.Domain/DTOs/User/UserSearchDTO.cs b/WGShare.Domain/DTOs/User/UserSearchDTO.cs new file mode 100644 index 0000000..05d761d --- /dev/null +++ b/WGShare.Domain/DTOs/User/UserSearchDTO.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WGShare.Domain.GeneralModel; + +namespace WGShare.Domain.DTOs.User +{ + public class UserSearchDTO: PagedBaseDto + { + public string? keyword { get; set; } + + public string? TenantId { get; set; } + public string? RoleId { get; set; } + } +} diff --git a/WGShare.Domain/Entities/Admin.cs b/WGShare.Domain/Entities/Admin.cs new file mode 100644 index 0000000..07c822c --- /dev/null +++ b/WGShare.Domain/Entities/Admin.cs @@ -0,0 +1,38 @@ +using SqlSugar; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yitter.IdGenerator; + +namespace WGShare.Domain.Entities +{ + /// + /// 超级管理员 + /// + [SugarTable("admin")] + public class Admin + { + /// + /// + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true)] + public string Id { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "Name")] + public string Name { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "Account")] + public string Account { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "Password")] + public string Password { get; set; } + } +} diff --git a/WGShare.Domain/Entities/Permission.cs b/WGShare.Domain/Entities/Permission.cs new file mode 100644 index 0000000..5097259 --- /dev/null +++ b/WGShare.Domain/Entities/Permission.cs @@ -0,0 +1,40 @@ +using SqlSugar; +using WGShare.Domain.Enums; +using Yitter.IdGenerator; + +namespace WGShare.Domain.Entities +{ + /// + /// 权限表 + /// + [SugarTable("permission")] + public class Permission + { + /// + /// 菜单/按钮Id + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true)] + public string Id { get; set; } = YitIdHelper.NextId().ToString(); + /// + /// 创建时间 + /// 默认值: CURRENT_TIMESTAMP + /// + [SugarColumn(ColumnName = "create_time", IsOnlyIgnoreInsert = true, IsOnlyIgnoreUpdate = true)] + public DateTime CreateTime { get; set; } + /// + /// 修改时间 + /// + [SugarColumn(ColumnName = "modify_time", IsOnlyIgnoreInsert = true, IsOnlyIgnoreUpdate = true)] + public DateTime ModifyTime { get; set; } + /// + /// 权限名称 + /// + [SugarColumn(ColumnName = "perm_name")] + public string PermName { get; set; } + /// + /// 权限值 + /// + [SugarColumn(ColumnName = "perm_value")] + public int PermValue { get; set; } + } +} diff --git a/WGShare.Domain/Entities/Role.cs b/WGShare.Domain/Entities/Role.cs new file mode 100644 index 0000000..1cfea6c --- /dev/null +++ b/WGShare.Domain/Entities/Role.cs @@ -0,0 +1,40 @@ +using SqlSugar; +using Yitter.IdGenerator; + +namespace WGShare.Domain.Entities +{ + /// + /// 用户角色表 + /// + [SugarTable("role")] + public class Role + { + /// + /// + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true)] + public string Id { get; set; } = YitIdHelper.NextId().ToString(); + /// + /// 是否删除 + /// 默认值: b'0' + /// + [SugarColumn(ColumnName = "is_delete")] + public bool IsDelete { get; set; } + /// + /// 创建时间 + /// 默认值: CURRENT_TIMESTAMP + /// + [SugarColumn(ColumnName = "create_time", IsOnlyIgnoreInsert = true, IsOnlyIgnoreUpdate = true)] + public DateTime CreateTime { get; set; } + /// + /// 修改时间 + /// + [SugarColumn(ColumnName = "modify_time", IsOnlyIgnoreInsert = true, IsOnlyIgnoreUpdate = true)] + public DateTime ModifyTime { get; set; } + /// + /// 角色名 + /// + [SugarColumn(ColumnName = "role_name")] + public string RoleName { get; set; } + } +} diff --git a/WGShare.Domain/Entities/RolePrem.cs b/WGShare.Domain/Entities/RolePrem.cs new file mode 100644 index 0000000..221158d --- /dev/null +++ b/WGShare.Domain/Entities/RolePrem.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SqlSugar; +namespace WGShare.Domain.Entities +{ + /// + /// 角色权限关系表 + /// + [SugarTable("role_perm")] + public class RolePrem + { + /// + /// 角色Id + /// + [SugarColumn(ColumnName = "role_id", IsPrimaryKey = true)] + public string RoleId { get; set; } + /// + /// 权限Id + /// + [SugarColumn(ColumnName = "perm_id", IsPrimaryKey = true)] + public string PermId { get; set; } + } +} diff --git a/WGShare.Domain/Entities/Room.cs b/WGShare.Domain/Entities/Room.cs new file mode 100644 index 0000000..0afb85e --- /dev/null +++ b/WGShare.Domain/Entities/Room.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SqlSugar; +using Yitter.IdGenerator; +namespace WGShare.Domain.Entities +{ + /// + /// 会议室房间表 + /// + [SugarTable("room")] + public class Room + { + /// + /// + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true)] + public string Id { get; set; } = YitIdHelper.NextId().ToString(); + /// + /// 是否删除 + /// 默认值: b'0' + /// + [SugarColumn(ColumnName = "is_delete")] + public bool IsDelete { get; set; } + /// + /// 创建时间 + /// 默认值: CURRENT_TIMESTAMP + /// + [SugarColumn(ColumnName = "create_time", IsOnlyIgnoreInsert = true, IsOnlyIgnoreUpdate = true)] + public DateTime CreateTime { get; set; } + /// + /// 修改时间 + /// + [SugarColumn(ColumnName = "modify_time", IsOnlyIgnoreInsert = true, IsOnlyIgnoreUpdate = true)] + public DateTime ModifyTime { get; set; } + /// + /// 会议室名称 + /// + [SugarColumn(ColumnName = "room_name")] + public string RoomName { get; set; } + /// + /// 租户id + /// + [SugarColumn(ColumnName = "tenant_id")] + public string TenantId { get; set; } + + /// + /// 会议号 + /// + [SugarColumn(ColumnName = "room_num")] + public string RoomNum { get; set; } + } +} diff --git a/WGShare.Domain/Entities/RoomManager.cs b/WGShare.Domain/Entities/RoomManager.cs new file mode 100644 index 0000000..3b80197 --- /dev/null +++ b/WGShare.Domain/Entities/RoomManager.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SqlSugar; +using Yitter.IdGenerator; +namespace WGShare.Domain.Entities +{ + /// + /// 会议室管理员关系表 + /// + [SugarTable("room_manager")] + public class RoomManager + { + /// + /// 用户Id + /// + [SugarColumn(ColumnName = "user_id", IsPrimaryKey = true)] + public string UserId { get; set; } + /// + /// 房间Id + /// + [SugarColumn(ColumnName = "room_id", IsPrimaryKey = true)] + public string RoomId { get; set; } + } +} diff --git a/WGShare.Domain/Entities/ShareFile.cs b/WGShare.Domain/Entities/ShareFile.cs new file mode 100644 index 0000000..3f0bccb --- /dev/null +++ b/WGShare.Domain/Entities/ShareFile.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SqlSugar; +using Yitter.IdGenerator; +namespace WGShare.Domain.Entities +{ + /// + /// 会议室文件分享 + /// + [SugarTable("share_file")] + public class ShareFile + { + /// + /// + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true)] + public string Id { get; set; } = YitIdHelper.NextId().ToString(); + /// + /// 是否删除 + /// 默认值: b'0' + /// + [SugarColumn(ColumnName = "is_delete")] + public bool IsDelete { get; set; } + /// + /// 创建时间 + /// 默认值: CURRENT_TIMESTAMP + /// + [SugarColumn(ColumnName = "create_time", IsOnlyIgnoreInsert = true, IsOnlyIgnoreUpdate = true)] + public DateTime CreateTime { get; set; } + /// + /// 修改时间 + /// + [SugarColumn(ColumnName = "modify_time", IsOnlyIgnoreInsert = true, IsOnlyIgnoreUpdate = true)] + public DateTime ModifyTime { get; set; } + /// + /// 文件地址 + /// + [SugarColumn(ColumnName = "file_url")] + public string FileUrl { get; set; } + /// + /// 上传者id + /// + [SugarColumn(ColumnName = "user_id")] + public string UserId { get; set; } + /// + /// 文件大小 kb + /// + [SugarColumn(ColumnName = "size")] + public double Size { get; set; } + /// + /// 文件名称 + /// + [SugarColumn(ColumnName = "file_name")] + public string FileName { get; set; } + /// + /// 会议房间Id + /// + [SugarColumn(ColumnName = "room_id")] + public string RoomId { get; set; } + /// + /// 下载次数 + /// + [SugarColumn(ColumnName = "download_count")] + public int DownloadCount { get; set; } + } +} diff --git a/WGShare.Domain/Entities/Tenant.cs b/WGShare.Domain/Entities/Tenant.cs new file mode 100644 index 0000000..9d547eb --- /dev/null +++ b/WGShare.Domain/Entities/Tenant.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SqlSugar; +using Yitter.IdGenerator; +namespace WGShare.Domain.Entities +{ + /// + /// 租户表 + /// + [SugarTable("tenant")] + public class Tenant + { + /// + /// + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true)] + public string Id { get; set; } = YitIdHelper.NextId().ToString(); + /// + /// 是否删除 + /// 默认值: b'0' + /// + [SugarColumn(ColumnName = "is_delete")] + public bool IsDelete { get; set; } + /// + /// 创建时间 + /// 默认值: CURRENT_TIMESTAMP + /// + [SugarColumn(ColumnName = "create_time", IsOnlyIgnoreInsert = true, IsOnlyIgnoreUpdate = true)] + public DateTime CreateTime { get; set; } + /// + /// 修改时间 + /// + [SugarColumn(ColumnName = "modify_time", IsOnlyIgnoreInsert = true, IsOnlyIgnoreUpdate = true)] + public DateTime ModifyTime { get; set; } + /// + /// 租户名称 + /// + [SugarColumn(ColumnName = "tenant_name")] + public string TenantName { get; set; } + } +} diff --git a/WGShare.Domain/Entities/User.cs b/WGShare.Domain/Entities/User.cs new file mode 100644 index 0000000..60e466a --- /dev/null +++ b/WGShare.Domain/Entities/User.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SqlSugar; +using Yitter.IdGenerator; +namespace WGShare.Domain.Entities +{ + /// + /// 用户表 + /// + [SugarTable("user")] + public class User + { + /// + /// + /// + [SugarColumn(ColumnName = "id", IsPrimaryKey = true)] + public string Id { get; set; } = YitIdHelper.NextId().ToString(); + /// + /// 是否删除 + /// 默认值: b'0' + /// + [SugarColumn(ColumnName = "is_delete")] + public bool IsDelete { get; set; } + /// + /// 创建时间 + /// 默认值: CURRENT_TIMESTAMP + /// + [SugarColumn(ColumnName = "create_time", IsOnlyIgnoreInsert = true, IsOnlyIgnoreUpdate = true)] + public DateTime CreateTime { get; set; } + /// + /// 修改时间 + /// + [SugarColumn(ColumnName = "modify_time", IsOnlyIgnoreInsert = true, IsOnlyIgnoreUpdate = true)] + public DateTime ModifyTime { get; set; } + /// + /// 用户名称 + /// + [SugarColumn(ColumnName = "user_name")] + public string UserName { get; set; } + /// + /// 账号 + /// + [SugarColumn(ColumnName = "account")] + public string Account { get; set; } + /// + /// 密码 + /// + [SugarColumn(ColumnName = "pwd")] + public string Pwd { get; set; } + /// + /// + /// + [SugarColumn(ColumnName = "role_id")] + public string RoleId { get; set; } + /// + /// 租户id + /// + [SugarColumn(ColumnName = "tenant_id")] + public string TenantId { get; set; } + + [SugarColumn(IsIgnore = true)] + public string RoleName { get; set; } + + + [SugarColumn(IsIgnore = true)] + public string TenantName { get; set; } + } +} diff --git a/WGShare.Domain/Entities/UserPrem.cs b/WGShare.Domain/Entities/UserPrem.cs new file mode 100644 index 0000000..cf1a74f --- /dev/null +++ b/WGShare.Domain/Entities/UserPrem.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SqlSugar; +namespace WGShare.Domain.Entities +{ + /// + /// 用户权限关系表 + /// + [SugarTable("user_perm")] + public class UserPrem + { + /// + /// 用户Id + /// + [SugarColumn(ColumnName = "user_id", IsPrimaryKey = true)] + public string UserId { get; set; } + /// + /// 权限Id + /// + [SugarColumn(ColumnName = "perm_id", IsPrimaryKey = true)] + public string PermId { get; set; } + } +} diff --git a/WGShare.Domain/Enums/MenuType.cs b/WGShare.Domain/Enums/MenuType.cs new file mode 100644 index 0000000..5112be6 --- /dev/null +++ b/WGShare.Domain/Enums/MenuType.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WGShare.Domain.Enums +{ + /// + /// 菜单类型 + /// + public enum MenuType + { + Menu = 0, + Button + } +} diff --git a/WGShare.Domain/FriendlyException/ErrorCode.cs b/WGShare.Domain/FriendlyException/ErrorCode.cs new file mode 100644 index 0000000..4134ea3 --- /dev/null +++ b/WGShare.Domain/FriendlyException/ErrorCode.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WGShare.Domain.FriendlyException +{ + /// + /// 错误代码 + /// + public class ErrorCode + { + /// + /// 业务逻辑错误 + /// + public const int x1000 = 1000; + + } +} diff --git a/WGShare.Domain/FriendlyException/ExceptionNotice.cs b/WGShare.Domain/FriendlyException/ExceptionNotice.cs new file mode 100644 index 0000000..0ebd78e --- /dev/null +++ b/WGShare.Domain/FriendlyException/ExceptionNotice.cs @@ -0,0 +1,44 @@ +using System.Net.Http.Json; + +namespace WGShare.Domain.FriendlyException +{ + /// + /// 异常通知 + /// + public class ExceptionNotice + { + private static HttpClient httpClient = new HttpClient() + { + BaseAddress = new Uri("https://oapi.dingtalk.com/robot/send?access_token=6ddafcada8f44f4bad4a7314c4d9bd19a895ded0a1ba1afdaff5dd01a5af6781"), + }; + + /// + /// 发送异常信息 + /// + /// 异常 + /// 异常来源(用于显示) + /// + public static async Task SendAsync(Exception exp, string expSrc) + { +#if DEBUG + Console.WriteLine("*************** Excpetion ***************"); + Console.WriteLine(exp.Message, exp); + Console.WriteLine("*************** Excpetion ***************"); + return true; +#endif + + var reponse = await httpClient.PostAsync(string.Empty, JsonContent.Create(new + { + msgtype = "markdown", + markdown = new + { + title = "WGShare异常", + text = $"WGShare异常.描述:{exp.Message}\n详情:{exp}" + }, + })); + return reponse.IsSuccessStatusCode; + + } + } + +} diff --git a/WGShare.Domain/FriendlyException/Exceptions/FriendlyInternalException.cs b/WGShare.Domain/FriendlyException/Exceptions/FriendlyInternalException.cs new file mode 100644 index 0000000..e08be9b --- /dev/null +++ b/WGShare.Domain/FriendlyException/Exceptions/FriendlyInternalException.cs @@ -0,0 +1,19 @@ +using System; + +namespace WGShare.Domain.FriendlyException.Exceptions +{ + /// + /// Api内部错误(错误细节不暴露给外部) + /// + public class FriendlyInternalException : Exception + { + public int ErrorCode { get; private set; } + public object FriendlyData { get; private set; } + + public FriendlyInternalException(string message, object friendlyData = null, int errorCode = FriendlyException.ErrorCode.x1000) : base(message) + { + ErrorCode = errorCode; + FriendlyData = friendlyData; + } + } +} diff --git a/WGShare.Domain/FriendlyException/Oops.cs b/WGShare.Domain/FriendlyException/Oops.cs new file mode 100644 index 0000000..58fc93c --- /dev/null +++ b/WGShare.Domain/FriendlyException/Oops.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WGShare.Domain.FriendlyException.Exceptions; + +namespace WGShare.Domain.FriendlyException +{ + /// + /// 异常抛出帮助类 + /// + public static class Oops + { + public static FriendlyInternalException Oh(string message) + { + return new FriendlyInternalException(message); + } + + + /// + /// 删除失败异常 + /// + /// + public static FriendlyInternalException OhDeleteFailed() + { + return new FriendlyInternalException("删除失败!"); + } + + /// + /// 数据不存在异常 + /// + /// + public static FriendlyInternalException OhDataNotExists() + { + return new FriendlyInternalException("数据不存在!"); + } + + /// + /// 更新失败异常 + /// + /// + public static FriendlyInternalException OhUpdateFailed() + { + return new FriendlyInternalException("更新失败!"); + } + + /// + /// 新增失败异常 + /// + /// + public static FriendlyInternalException OhAddFailed() + { + return new FriendlyInternalException("新增失败!"); + } + + /// + /// 业务处理失败自定义消息 + /// + /// + public static FriendlyInternalException OhBusinessFailed(string msg, object data) + { + return new FriendlyInternalException(msg, data, 200); + } + + /// + /// 操作失败 + /// + /// + public static FriendlyInternalException OperationFailed() + { + return new FriendlyInternalException("操作失败!"); + } + } +} diff --git a/WGShare.Domain/GeneralModel/PagedBaseDto.cs b/WGShare.Domain/GeneralModel/PagedBaseDto.cs new file mode 100644 index 0000000..3b6e673 --- /dev/null +++ b/WGShare.Domain/GeneralModel/PagedBaseDto.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WGShare.Domain.GeneralModel +{ + /// + /// 分页查询基础DTO + /// + public class PagedBaseDto + { + /// + /// 当前页码 + /// + public int PageIndex { get; set; } = 1; + + /// + /// 分页大小 + /// + public int PageSize { get; set; } = 10; + } +} diff --git a/WGShare.Domain/GeneralModel/PagedResult.cs b/WGShare.Domain/GeneralModel/PagedResult.cs new file mode 100644 index 0000000..0a43033 --- /dev/null +++ b/WGShare.Domain/GeneralModel/PagedResult.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WGShare.Domain.GeneralModel +{ + /// + /// 统一分页返回结果模型 + /// + /// + public class PagedResult + { + public PagedResult() { } + public PagedResult(IEnumerable list, int total) + { + Total = total; + Items = list; + } + + public int Total { get; set; } + public IEnumerable Items { get; private set; } + + public static PagedResult Create(IEnumerable list, int total) + { + return new PagedResult(list, total); + } + } +} diff --git a/WGShare.Domain/GeneralModel/UniformResult.cs b/WGShare.Domain/GeneralModel/UniformResult.cs new file mode 100644 index 0000000..2dc2fb6 --- /dev/null +++ b/WGShare.Domain/GeneralModel/UniformResult.cs @@ -0,0 +1,46 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WGShare.Domain.GeneralModel +{ + /// + /// 统一返回结果模型 + /// + /// + public class UniformResult + { + public UniformResult(T data, int code = 200, string msg = "success") + { + this.data = data; + this.code = code; + message = msg; + } + + /// + /// 消息 + /// + public string message { get; set; } = "success"; + + /// + /// 返回代码 + /// + public int code { get; set; } + + /// + /// 数据 + /// + public T data { get; set; } + + public static UniformResult Create(T data, int code = 200, string msg = "success") + { + return new UniformResult(data, code, msg); + } + + } + + +} diff --git a/WGShare.Domain/WGShare.Domain.csproj b/WGShare.Domain/WGShare.Domain.csproj new file mode 100644 index 0000000..3b09112 --- /dev/null +++ b/WGShare.Domain/WGShare.Domain.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + +