From 8ed012bba8e1940f363377ddffe7a35bb92f94bd Mon Sep 17 00:00:00 2001 From: glz <694770232@qq.com> Date: Tue, 2 Jun 2026 14:10:43 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E5=9F=BA=E7=A1=80=E6=9E=B6=E6=9E=84=E4=B8=8E=E5=AE=9E?= =?UTF-8?q?=E4=BD=93=E4=BD=93=E7=B3=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 替换原有自定义生命周期接口为通用基础服务体系 - 将所有实体基类替换为带雪花ID的SqlSugarBaseEntity - 迁移DTO到Models项目并统一管理 - 移除冗余的Repository层实现,改用通用基础服务 - 添加Yitter.IdGenerator雪花ID生成支持 - 重构SqlSugar数据库上下文与依赖注入配置 - 新增微信用户、用户勋章、背包等实体与配套服务 - 整理分页查询与结果封装类 - 优化WebApi控制器结构 --- .../Helpers/JsonConverterUtil.cs | 37 ++ .../Dto/AuthDto.cs | 93 ---- .../Dto/WeChatDto.cs | 38 -- .../IAdminAuthService.cs | 4 +- .../IAdminUserService.cs | 3 +- .../IBaseService.cs | 60 ++- .../IDependency.cs | 15 - .../IWxUserService.cs | 33 ++ .../Autofac/AutofacModuleRegister.cs | 11 +- .../Context/ServiceContext.cs | 75 ++++ .../Dto/Admin}/AdminUserDto.cs | 2 +- .../Dto/Admin/AuthDto.cs | 40 ++ .../Dto/PageListModel.cs | 66 ++- .../Dto/PageQueryModel.cs | 42 +- .../Dto/WeChat/WeChatDto.cs | 198 +++++++++ .../Entity/AdminUser.cs | 9 +- .../Entity/BaseEntity.cs | 43 -- .../Entity/CheckInConfig.cs | 10 +- .../Entity/CheckInRecord.cs | 14 +- .../Entity/CommunityMessage.cs | 15 +- .../Entity/Journal.cs | 14 +- .../Entity/Medal.cs | 110 +++-- .../Entity/MessageComment.cs | 15 +- .../Entity/MessageLike.cs | 14 +- QYZH.InteractiveMagazine.Models/Entity/Pet.cs | 14 +- .../Entity/PetEvolution.cs | 9 +- .../Entity/PetFeedingRecord.cs | 15 +- .../Entity/PointsRecord.cs | 15 +- .../Entity/Product.cs | 9 +- .../Entity/SqlSugarBaseEntity.cs | 63 +++ .../Entity/TemplateSentence.cs | 10 +- .../Entity/User.cs | 71 --- .../Entity/WxUser.cs | 80 ++++ .../Entity/{UserBag.cs => WxUserBag.cs} | 6 +- .../Entity/{UserMedal.cs => WxUserMedal.cs} | 6 +- .../QYZH.InteractiveMagazine.Models.csproj | 2 + .../AdminUserRepository.cs | 13 - .../BaseRepository.cs | 403 ++++++++++++------ .../Core/SqlSugarExtension.cs | 160 +++++++ .../Core/SqlSugarManager.cs | 51 +++ .../IAdminUserRepository.cs | 8 - .../IBaseRepository.cs | 160 +++---- ...QYZH.InteractiveMagazine.Repository.csproj | 4 +- .../SqlSugarDbContext.cs | 99 ----- .../AdminAuthService.cs | 48 +-- .../AdminUserService.cs | 122 ++---- .../BaseService.cs | 201 --------- .../WxUserService.cs | 191 +++++++++ .../Controllers/AdminController.cs | 18 + .../Controllers/WxUserController.cs | 121 ++++++ QYZH.InteractiveMagazine.WebApi/Program.cs | 43 +- 51 files changed, 1762 insertions(+), 1141 deletions(-) create mode 100644 QYZH.InteractiveMagazine.Common/Helpers/JsonConverterUtil.cs delete mode 100644 QYZH.InteractiveMagazine.IService/Dto/AuthDto.cs delete mode 100644 QYZH.InteractiveMagazine.IService/Dto/WeChatDto.cs delete mode 100644 QYZH.InteractiveMagazine.IService/IDependency.cs create mode 100644 QYZH.InteractiveMagazine.IService/IWxUserService.cs create mode 100644 QYZH.InteractiveMagazine.Infrastructure/Context/ServiceContext.cs rename {QYZH.InteractiveMagazine.IService/Dto => QYZH.InteractiveMagazine.Models/Dto/Admin}/AdminUserDto.cs (97%) create mode 100644 QYZH.InteractiveMagazine.Models/Dto/Admin/AuthDto.cs create mode 100644 QYZH.InteractiveMagazine.Models/Dto/WeChat/WeChatDto.cs delete mode 100644 QYZH.InteractiveMagazine.Models/Entity/BaseEntity.cs create mode 100644 QYZH.InteractiveMagazine.Models/Entity/SqlSugarBaseEntity.cs delete mode 100644 QYZH.InteractiveMagazine.Models/Entity/User.cs create mode 100644 QYZH.InteractiveMagazine.Models/Entity/WxUser.cs rename QYZH.InteractiveMagazine.Models/Entity/{UserBag.cs => WxUserBag.cs} (92%) rename QYZH.InteractiveMagazine.Models/Entity/{UserMedal.cs => WxUserMedal.cs} (90%) delete mode 100644 QYZH.InteractiveMagazine.Repository/AdminUserRepository.cs create mode 100644 QYZH.InteractiveMagazine.Repository/Core/SqlSugarExtension.cs create mode 100644 QYZH.InteractiveMagazine.Repository/Core/SqlSugarManager.cs delete mode 100644 QYZH.InteractiveMagazine.Repository/IAdminUserRepository.cs delete mode 100644 QYZH.InteractiveMagazine.Repository/SqlSugarDbContext.cs delete mode 100644 QYZH.InteractiveMagazine.Service/BaseService.cs create mode 100644 QYZH.InteractiveMagazine.Service/WxUserService.cs create mode 100644 QYZH.InteractiveMagazine.WebApi/Controllers/WxUserController.cs diff --git a/QYZH.InteractiveMagazine.Common/Helpers/JsonConverterUtil.cs b/QYZH.InteractiveMagazine.Common/Helpers/JsonConverterUtil.cs new file mode 100644 index 0000000..2fc39a4 --- /dev/null +++ b/QYZH.InteractiveMagazine.Common/Helpers/JsonConverterUtil.cs @@ -0,0 +1,37 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace QYZH.InteractiveMagazine.Common.Helpers +{ + public class JsonConverterUtil + { + public class DateTimeNullConverter : JsonConverter + { + public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + => string.IsNullOrEmpty(reader.GetString()) ? default : ParseDateTime(reader.GetString()); + + public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options) + => writer.WriteStringValue(value?.ToString("yyyy-MM-dd HH:mm:ss")); + } + + public class DateTimeConverter : JsonConverter + { + public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var dateTime = ParseDateTime(reader.GetString()); + return dateTime == null ? DateTime.MinValue : dateTime.Value; + } + + public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) + => writer.WriteStringValue(value.ToString("yyyy-MM-dd HH:mm:ss")); + } + + public static DateTime? ParseDateTime(string dateStr) + { + if (System.Text.RegularExpressions.Regex.IsMatch(dateStr, @"^\d{4}[/-]") && DateTime.TryParse(dateStr, null, System.Globalization.DateTimeStyles.AssumeLocal, out var dateVal)) + return dateVal; + return null; + } + } +} diff --git a/QYZH.InteractiveMagazine.IService/Dto/AuthDto.cs b/QYZH.InteractiveMagazine.IService/Dto/AuthDto.cs deleted file mode 100644 index 512eb85..0000000 --- a/QYZH.InteractiveMagazine.IService/Dto/AuthDto.cs +++ /dev/null @@ -1,93 +0,0 @@ -namespace QYZH.InteractiveMagazine.IService.Dto; - -/// -/// 登录输入 -/// -public class LoginInput -{ - /// - /// 账号 - /// - public string Account { get; set; } = string.Empty; - - /// - /// 密码 - /// - public string Password { get; set; } = string.Empty; -} - -/// -/// 注册输入 -/// -public class RegisterInput -{ - /// - /// 账号 - /// - public string Account { get; set; } = string.Empty; - - /// - /// 密码 - /// - public string Password { get; set; } = string.Empty; - - /// - /// 用户名 - /// - public string UserName { get; set; } = string.Empty; -} - -/// -/// 登录输出 -/// -public class LoginOutput -{ - /// - /// 访问令牌 - /// - public string Token { get; set; } = string.Empty; - - /// - /// 用户ID - /// - public long UserId { get; set; } - - /// - /// 用户名 - /// - public string UserName { get; set; } = string.Empty; - - /// - /// 刷新令牌 - /// - public string RefreshToken { get; set; } = string.Empty; -} - -public class AdminLoginInput -{ - public string UserName { get; set; } = string.Empty; - - public string Password { get; set; } = string.Empty; -} - -public class AdminLoginOutput -{ - public string Token { get; set; } = string.Empty; - - public long UserId { get; set; } - - public string UserName { get; set; } = string.Empty; - - public string Type { get; set; } = string.Empty; -} - -public class AdminUserInfoOutput -{ - public long UserId { get; set; } - - public string UserName { get; set; } = string.Empty; - - public string Type { get; set; } = string.Empty; - - public string Status { get; set; } = string.Empty; -} diff --git a/QYZH.InteractiveMagazine.IService/Dto/WeChatDto.cs b/QYZH.InteractiveMagazine.IService/Dto/WeChatDto.cs deleted file mode 100644 index f2f3709..0000000 --- a/QYZH.InteractiveMagazine.IService/Dto/WeChatDto.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace QYZH.InteractiveMagazine.IService.Dto; - -/// -/// 微信登录输出 -/// -public class WeChatLoginOutput -{ - /// - /// 访问令牌 - /// - public string Token { get; set; } = string.Empty; - - /// - /// 用户ID - /// - public long UserId { get; set; } - - /// - /// 用户名 - /// - public string UserName { get; set; } = string.Empty; - - /// - /// 微信OpenId - /// - public string OpenId { get; set; } = string.Empty; -} - -/// -/// 微信手机号获取输出 -/// -public class WeChatPhoneNumberOutput -{ - /// - /// 手机号 - /// - public string PhoneNumber { get; set; } = string.Empty; -} diff --git a/QYZH.InteractiveMagazine.IService/IAdminAuthService.cs b/QYZH.InteractiveMagazine.IService/IAdminAuthService.cs index d04a986..e136590 100644 --- a/QYZH.InteractiveMagazine.IService/IAdminAuthService.cs +++ b/QYZH.InteractiveMagazine.IService/IAdminAuthService.cs @@ -1,8 +1,10 @@ using QYZH.InteractiveMagazine.IService.Dto; +using QYZH.InteractiveMagazine.Models.Dto; +using QYZH.InteractiveMagazine.Models.Entity; namespace QYZH.InteractiveMagazine.IService; -public interface IAdminAuthService +public interface IAdminAuthService : IBaseService { Task LoginAsync(AdminLoginInput input); diff --git a/QYZH.InteractiveMagazine.IService/IAdminUserService.cs b/QYZH.InteractiveMagazine.IService/IAdminUserService.cs index 9849629..902339a 100644 --- a/QYZH.InteractiveMagazine.IService/IAdminUserService.cs +++ b/QYZH.InteractiveMagazine.IService/IAdminUserService.cs @@ -1,12 +1,13 @@ using QYZH.InteractiveMagazine.IService.Dto; using QYZH.InteractiveMagazine.Models.Dto; +using QYZH.InteractiveMagazine.Models.Entity; namespace QYZH.InteractiveMagazine.IService; /// /// 管理员用户服务接口 /// -public interface IAdminUserService +public interface IAdminUserService : IBaseService { /// /// 创建管理员 diff --git a/QYZH.InteractiveMagazine.IService/IBaseService.cs b/QYZH.InteractiveMagazine.IService/IBaseService.cs index ee50497..4a0cd98 100644 --- a/QYZH.InteractiveMagazine.IService/IBaseService.cs +++ b/QYZH.InteractiveMagazine.IService/IBaseService.cs @@ -1,51 +1,39 @@ -using QYZH.InteractiveMagazine.Models.Dto; +using System.Linq.Expressions; namespace QYZH.InteractiveMagazine.IService; /// -/// 基础服务接口 +/// 基础服务定义 /// -/// 实体类型 +/// public interface IBaseService where T : class, new() { - /// - /// 根据ID获取实体 - /// - /// 实体ID - /// 实体对象 - Task GetByIdAsync(long id); + Task GetFirstAsync(Expression> whereExpression); /// - /// 获取所有实体列表 + /// 根据条件表达式查询单条数据 /// - /// 实体列表 - Task> GetListAsync(); + /// 表达式 + /// 泛型实体 + Task GetByIdAsync(Expression> expression) where R : class; - /// - /// 获取分页列表 - /// - /// 分页查询参数 - /// 分页数据 - Task> GetPageListAsync(PageQueryModel pageQuery); + Task GetByExpressionAsync(Expression> expression) where R : class; - /// - /// 新增实体 - /// - /// 实体对象 - /// 是否成功 - Task InsertAsync(T entity); + Task> GetListByExpression(Expression> expression) where T2 : class; - /// - /// 更新实体 - /// - /// 实体对象 - /// 是否成功 - Task UpdateAsync(T entity); + Task UpdateAsync(T updateObj); - /// - /// 根据ID删除实体 - /// - /// 实体ID - /// 是否成功 - Task DeleteByIdAsync(long id); + ///// + ///// 根据指定条件更新指定列 eg:Update(new SysUser(){ Status = 1 }, it => new { it.Status }, f => f.Userid == 1)); + ///// 只更新Status列,条件是包含 + ///// + ///// 实体类 + ///// 要更新列的表达式 + ///// where表达式 + ///// + //Task UpdateAsync(T entity, Expression> expression, Expression> where); + + Task UpdateAsync(Expression> columns, Expression> whereExpression); + + Task UpdateAsync(Expression> columns, Expression> where); } diff --git a/QYZH.InteractiveMagazine.IService/IDependency.cs b/QYZH.InteractiveMagazine.IService/IDependency.cs deleted file mode 100644 index 6ebb143..0000000 --- a/QYZH.InteractiveMagazine.IService/IDependency.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace QYZH.InteractiveMagazine.IService; - -/// -/// 单例生命周期标记接口 -/// -public interface ISingletonDependency -{ -} - -/// -/// 瞬时生命周期标记接口 -/// -public interface ITransientDependency -{ -} diff --git a/QYZH.InteractiveMagazine.IService/IWxUserService.cs b/QYZH.InteractiveMagazine.IService/IWxUserService.cs new file mode 100644 index 0000000..3ed85e7 --- /dev/null +++ b/QYZH.InteractiveMagazine.IService/IWxUserService.cs @@ -0,0 +1,33 @@ +using QYZH.InteractiveMagazine.IService.Dto; +using QYZH.InteractiveMagazine.Models.Dto; +using QYZH.InteractiveMagazine.Models.Entity; + +namespace QYZH.InteractiveMagazine.IService; + +public interface IWxUserService : IBaseService +{ + /// + /// 创建微信用户 + /// + Task CreateAsync(WxUserInput input); + + /// + /// 更新微信用户 + /// + Task UpdateAsync(long id, WxUserInput input); + + /// + /// 删除微信用户(软删除) + /// + Task DeleteAsync(long id); + + /// + /// 根据ID获取微信用户 + /// + Task GetByIdAsync(long id); + + /// + /// 分页查询微信用户列表 + /// + Task> GetListAsync(WxUserQueryInput input); +} diff --git a/QYZH.InteractiveMagazine.Infrastructure/Autofac/AutofacModuleRegister.cs b/QYZH.InteractiveMagazine.Infrastructure/Autofac/AutofacModuleRegister.cs index 06fcdfe..b99c900 100644 --- a/QYZH.InteractiveMagazine.Infrastructure/Autofac/AutofacModuleRegister.cs +++ b/QYZH.InteractiveMagazine.Infrastructure/Autofac/AutofacModuleRegister.cs @@ -17,17 +17,8 @@ namespace QYZH.InteractiveMagazine.Infrastructure.Autofacs /// protected override void Load(ContainerBuilder builder) { - //注册Repository(只注册接口,遵循依赖倒置原则) - builder.RegisterAssemblyTypes(GetAssemblyByName($"{_assemblyName}.Repository")) - .Where(t => t.Name.EndsWith("Repository") && !t.IsAbstract) - .AsImplementedInterfaces() - .InstancePerLifetimeScope(); - //注册Service - builder.RegisterAssemblyTypes(GetAssemblyByName($"{_assemblyName}.Service")) - .Where(t => t.Name.EndsWith("Service") && !t.IsAbstract) - .AsImplementedInterfaces() - .InstancePerLifetimeScope(); + builder.RegisterAssemblyTypes(GetAssemblyByName($"{_assemblyName}.Service")).Where(t => t.Name.EndsWith("Service")).AsImplementedInterfaces().InstancePerLifetimeScope(); } /// diff --git a/QYZH.InteractiveMagazine.Infrastructure/Context/ServiceContext.cs b/QYZH.InteractiveMagazine.Infrastructure/Context/ServiceContext.cs new file mode 100644 index 0000000..46616e0 --- /dev/null +++ b/QYZH.InteractiveMagazine.Infrastructure/Context/ServiceContext.cs @@ -0,0 +1,75 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +namespace QYZH.InteractiveMagazine.Infrastructure.Context +{ + /// + /// 应用程序上下文 + /// + public static class ServiceContext + { + public static IServiceProvider ServiceProvider; + + public static void UseServiceContext(this IApplicationBuilder applicationBuilder) + { + ServiceProvider = applicationBuilder.ApplicationServices; + } + + public static void UseServiceContext(this IServiceCollection services) + { + ServiceProvider = services.BuildServiceProvider(); + } + + /// + /// 获取对象实例 + /// + /// + /// + public static T GetService() + { + return ServiceProvider.GetService(); + } + + /// + /// 获取Scope对象实例 + /// + /// + /// + public static T GetScopeService() + { + var scope = ServiceProvider.CreateScope(); + return scope.ServiceProvider.GetService(); + } + + /// + /// 获取对象实例 + /// + /// + /// + public static T GetRequiredService() + { + return ServiceProvider.GetRequiredService(); + } + + /// + /// 获取对象实例 + /// + /// + /// + public static T GetOptionsMonitor() + { + return ServiceProvider.GetService>().CurrentValue; + } + + /// + /// 获取对象实例 + /// + /// + /// + public static T GetOptions() where T : class, new() + { + return ServiceProvider.GetService>().Value; + } + } +} \ No newline at end of file diff --git a/QYZH.InteractiveMagazine.IService/Dto/AdminUserDto.cs b/QYZH.InteractiveMagazine.Models/Dto/Admin/AdminUserDto.cs similarity index 97% rename from QYZH.InteractiveMagazine.IService/Dto/AdminUserDto.cs rename to QYZH.InteractiveMagazine.Models/Dto/Admin/AdminUserDto.cs index 8f331e5..51584b3 100644 --- a/QYZH.InteractiveMagazine.IService/Dto/AdminUserDto.cs +++ b/QYZH.InteractiveMagazine.Models/Dto/Admin/AdminUserDto.cs @@ -1,6 +1,6 @@ using QYZH.InteractiveMagazine.Models.Dto; -namespace QYZH.InteractiveMagazine.IService.Dto; +namespace QYZH.InteractiveMagazine.Models.Dto; /// /// 管理员创建/更新输入 diff --git a/QYZH.InteractiveMagazine.Models/Dto/Admin/AuthDto.cs b/QYZH.InteractiveMagazine.Models/Dto/Admin/AuthDto.cs new file mode 100644 index 0000000..88214e8 --- /dev/null +++ b/QYZH.InteractiveMagazine.Models/Dto/Admin/AuthDto.cs @@ -0,0 +1,40 @@ +namespace QYZH.InteractiveMagazine.Models.Dto; + + +/// +/// 管理员登录输入 +/// +public class AdminLoginInput +{ + /// + /// 用户名 + /// + public string UserName { get; set; } = string.Empty; + + /// + /// 密码 + /// + public string Password { get; set; } = string.Empty; +} + +public class AdminLoginOutput +{ + public string Token { get; set; } = string.Empty; + + public long UserId { get; set; } + + public string UserName { get; set; } = string.Empty; + + public string Type { get; set; } = string.Empty; +} + +public class AdminUserInfoOutput +{ + public long UserId { get; set; } + + public string UserName { get; set; } = string.Empty; + + public string Type { get; set; } = string.Empty; + + public string Status { get; set; } = string.Empty; +} diff --git a/QYZH.InteractiveMagazine.Models/Dto/PageListModel.cs b/QYZH.InteractiveMagazine.Models/Dto/PageListModel.cs index 5c44d88..ec05591 100644 --- a/QYZH.InteractiveMagazine.Models/Dto/PageListModel.cs +++ b/QYZH.InteractiveMagazine.Models/Dto/PageListModel.cs @@ -1,33 +1,73 @@ namespace QYZH.InteractiveMagazine.Models.Dto; /// -/// 分页输出 +/// 通用分页信息类 /// -/// 数据类型 public class PageListModel { /// - /// 页码 + /// 每页行数 /// - public int PageIndex { get; set; } - + public int PageSize { get; set; } = 10; /// - /// 每页条数 + /// 当前页 /// - public int PageSize { get; set; } - + public int PageIndex { get; set; } = 1; /// /// 总记录数 /// - public long TotalCount { get; set; } - + public int TotalNum { get; set; } /// /// 总页数 /// - public int TotalPages => PageSize > 0 ? (int)Math.Ceiling((double)TotalCount / PageSize) : 0; + public int TotalPage + { + get + { + if (TotalNum > 0) + return TotalNum % PageSize == 0 ? TotalNum / PageSize : TotalNum / PageSize + 1; + else + return 0; + } + } + + public List Result { get; set; } /// - /// 数据列表 + /// 额外数据 /// - public List? List { get; set; } + public Dictionary Extra { get; set; } = new Dictionary(); + /// + /// 是否有上一页 + /// + public bool HasPrev + { + get + { + return PageIndex > 1; + } + } + + /// + /// 下一页是否可用 + /// + public bool HasNext + { + get + { + return TotalPage > PageIndex; + } + } + + public PageListModel() + { + } + + public PageListModel(List result, int pageIndex, int pageSize, int totalNum) + { + PageIndex = pageIndex; + PageSize = pageSize; + TotalNum = totalNum; + Result = result; + } } diff --git a/QYZH.InteractiveMagazine.Models/Dto/PageQueryModel.cs b/QYZH.InteractiveMagazine.Models/Dto/PageQueryModel.cs index 3231c4c..1d1eefc 100644 --- a/QYZH.InteractiveMagazine.Models/Dto/PageQueryModel.cs +++ b/QYZH.InteractiveMagazine.Models/Dto/PageQueryModel.cs @@ -1,27 +1,57 @@ namespace QYZH.InteractiveMagazine.Models.Dto; /// -/// 分页查询输入 +/// 通用分页查询类 /// public class PageQueryModel { /// - /// 页码,默认1 + ///当前页 /// public int PageIndex { get; set; } = 1; /// - /// 每页条数,默认10 + ///每页条数 /// public int PageSize { get; set; } = 10; /// /// 排序字段 /// - public string? SortField { get; set; } + public string Sort { get; set; } = string.Empty; + /// + /// 排序类型,前端传入的是"ascending","descending" + /// + public string SortType { get; set; } = string.Empty; /// - /// 排序方式(asc/desc) + /// 关键字 /// - public string? SortOrder { get; set; } + public string? KeyWord { get; set; } +} + + +/// +/// 分页查询泛型类 +/// +/// 查询参数类型 +public class PageQueryModel : PageQueryModel where T : class, new() +{ + /// + /// 查询参数 + /// + public T Params { get; set; } = new T(); + + public TP ConvertTo() where TP : class + { + if (Params != null) + { + return Params as TP; + } + return default; + } + + public int Start => (PageIndex - 1) * PageSize + 1; + + public int End => PageIndex * PageSize; } diff --git a/QYZH.InteractiveMagazine.Models/Dto/WeChat/WeChatDto.cs b/QYZH.InteractiveMagazine.Models/Dto/WeChat/WeChatDto.cs new file mode 100644 index 0000000..9502b5e --- /dev/null +++ b/QYZH.InteractiveMagazine.Models/Dto/WeChat/WeChatDto.cs @@ -0,0 +1,198 @@ +using QYZH.InteractiveMagazine.Models.Dto; + +namespace QYZH.InteractiveMagazine.IService.Dto; + +/// +/// 微信登录输出 +/// +public class WeChatLoginOutput +{ + /// + /// 访问令牌 + /// + public string Token { get; set; } = string.Empty; + + /// + /// 用户ID + /// + public long UserId { get; set; } + + /// + /// 用户名 + /// + public string UserName { get; set; } = string.Empty; + + /// + /// 微信OpenId + /// + public string OpenId { get; set; } = string.Empty; +} + +/// +/// 微信用户创建/更新输入 +/// +public class WxUserInput +{ + /// + /// 微信OpenId + /// + public string OpenId { get; set; } = string.Empty; + + /// + /// 微信UnionId + /// + public string? UnionId { get; set; } + + /// + /// 昵称 + /// + public string? NickName { get; set; } + + /// + /// 头像地址 + /// + public string? AvatarUrl { get; set; } + + /// + /// 手机号 + /// + public string? Phone { get; set; } + + /// + /// 积分余额 + /// + public int Points { get; set; } = 0; + + /// + /// 用户类型: Normal, VIP + /// + public string Type { get; set; } = "Normal"; + + /// + /// 状态: Active, Disabled + /// + public string Status { get; set; } = "Active"; + + /// + /// 密码,默认手机后4位 + /// + public string? Pwd { get; set; } + + /// + /// 当前成长值 + /// + public int GrowthPoints { get; set; } = 0; +} + +/// +/// 微信用户输出 +/// +public class WxUserOutput +{ + /// + /// 主键ID + /// + public long Id { get; set; } + + /// + /// 微信OpenId + /// + public string OpenId { get; set; } = string.Empty; + + /// + /// 微信UnionId + /// + public string? UnionId { get; set; } + + /// + /// 昵称 + /// + public string? NickName { get; set; } + + /// + /// 头像地址 + /// + public string? AvatarUrl { get; set; } + + /// + /// 手机号 + /// + public string? Phone { get; set; } + + /// + /// 积分余额 + /// + public int Points { get; set; } + + /// + /// 用户类型 + /// + public string Type { get; set; } = string.Empty; + + /// + /// 状态 + /// + public string Status { get; set; } = string.Empty; + + /// + /// 当前成长值 + /// + public int GrowthPoints { get; set; } + + /// + /// 创建人 + /// + public string? CreatedBy { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreatedAt { get; set; } + + /// + /// 更新人 + /// + public string? UpdatedBy { get; set; } + + /// + /// 更新时间 + /// + public DateTime? UpdatedAt { get; set; } +} + +/// +/// 微信用户分页查询输入 +/// +public class WxUserQueryInput : PageQueryModel +{ + /// + /// 昵称(模糊查询) + /// + public string? NickName { get; set; } + + /// + /// 手机号(模糊查询) + /// + public string? Phone { get; set; } + + /// + /// 用户类型 + /// + public string? Type { get; set; } + + /// + /// 状态 + /// + public string? Status { get; set; } +} + +/// +/// 微信手机号获取输出 +/// +public class WeChatPhoneNumberOutput +{ + /// + /// 手机号 + /// + public string PhoneNumber { get; set; } = string.Empty; +} diff --git a/QYZH.InteractiveMagazine.Models/Entity/AdminUser.cs b/QYZH.InteractiveMagazine.Models/Entity/AdminUser.cs index 9e391b6..9c625e5 100644 --- a/QYZH.InteractiveMagazine.Models/Entity/AdminUser.cs +++ b/QYZH.InteractiveMagazine.Models/Entity/AdminUser.cs @@ -6,19 +6,12 @@ namespace QYZH.InteractiveMagazine.Models.Entity ///后台管理员表 /// [SugarTable("AdminUser")] - public partial class AdminUser : BaseEntity + public partial class AdminUser : SqlSugarBaseEntity { public AdminUser(){ } - /// - /// Desc:主键 - /// Default: - /// Nullable:False - /// - [SugarColumn(IsPrimaryKey=true,IsIdentity=true)] - public new int Id { get; set; } /// /// Desc:用户名 diff --git a/QYZH.InteractiveMagazine.Models/Entity/BaseEntity.cs b/QYZH.InteractiveMagazine.Models/Entity/BaseEntity.cs deleted file mode 100644 index 9558235..0000000 --- a/QYZH.InteractiveMagazine.Models/Entity/BaseEntity.cs +++ /dev/null @@ -1,43 +0,0 @@ -using SqlSugar; - -namespace QYZH.InteractiveMagazine.Models.Entity; - -/// -/// 基础实体类 -/// -public abstract class BaseEntity -{ - /// - /// 主键Id - /// - [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] - public long Id { get; set; } - - /// - /// 是否已删除 - /// - [SugarColumn(IsIgnore = false)] - public bool IsDeleted { get; set; } = false; - - /// - /// 创建人 - /// - [SugarColumn(Length = 50)] - public string? CreatedBy { get; set; } = "System"; - - /// - /// 创建时间 - /// - public DateTime CreatedAt { get; set; } = DateTime.Now; - - /// - /// 更新人 - /// - [SugarColumn(Length = 50)] - public string? UpdatedBy { get; set; } = "System"; - - /// - /// 更新时间 - /// - public DateTime? UpdatedAt { get; set; } = DateTime.Now; -} diff --git a/QYZH.InteractiveMagazine.Models/Entity/CheckInConfig.cs b/QYZH.InteractiveMagazine.Models/Entity/CheckInConfig.cs index c3e21c7..46acea5 100644 --- a/QYZH.InteractiveMagazine.Models/Entity/CheckInConfig.cs +++ b/QYZH.InteractiveMagazine.Models/Entity/CheckInConfig.cs @@ -6,19 +6,13 @@ namespace QYZH.InteractiveMagazine.Models.Entity ///签到配置表 /// [SugarTable("CheckInConfig")] - public partial class CheckInConfig : BaseEntity + public partial class CheckInConfig : SqlSugarBaseEntity { public CheckInConfig(){ } - /// - /// Desc:主键 - /// Default: - /// Nullable:False - /// - [SugarColumn(IsPrimaryKey=true,IsIdentity=true)] - public new int Id {get;set;} + /// /// Desc:连续签到天数 diff --git a/QYZH.InteractiveMagazine.Models/Entity/CheckInRecord.cs b/QYZH.InteractiveMagazine.Models/Entity/CheckInRecord.cs index 6e45624..32de233 100644 --- a/QYZH.InteractiveMagazine.Models/Entity/CheckInRecord.cs +++ b/QYZH.InteractiveMagazine.Models/Entity/CheckInRecord.cs @@ -6,18 +6,18 @@ namespace QYZH.InteractiveMagazine.Models.Entity ///签到记录表 /// [SugarTable("CheckInRecord")] - public partial class CheckInRecord : BaseEntity + public partial class CheckInRecord : SqlSugarBaseEntity { public CheckInRecord(){ } - /// - /// Desc:用户Id - /// Default: - /// Nullable:False - /// - public long UserId {get;set;} + /// + /// Desc:用户Id + /// Default: + /// Nullable:False + /// + public long UserId {get;set;} /// /// Desc:签到日期 diff --git a/QYZH.InteractiveMagazine.Models/Entity/CommunityMessage.cs b/QYZH.InteractiveMagazine.Models/Entity/CommunityMessage.cs index bf99952..5e7286e 100644 --- a/QYZH.InteractiveMagazine.Models/Entity/CommunityMessage.cs +++ b/QYZH.InteractiveMagazine.Models/Entity/CommunityMessage.cs @@ -6,18 +6,19 @@ namespace QYZH.InteractiveMagazine.Models.Entity ///社区预置消息表 /// [SugarTable("CommunityMessage")] - public partial class CommunityMessage : BaseEntity + public partial class CommunityMessage : SqlSugarBaseEntity { public CommunityMessage(){ } - /// - /// Desc:期刊Id - /// Default: - /// Nullable:False - /// - public long JournalId {get;set;} + + /// + /// Desc:期刊Id + /// Default: + /// Nullable:False + /// + public long JournalId {get;set;} /// /// Desc:消息内容 diff --git a/QYZH.InteractiveMagazine.Models/Entity/Journal.cs b/QYZH.InteractiveMagazine.Models/Entity/Journal.cs index 05d39ec..48773a0 100644 --- a/QYZH.InteractiveMagazine.Models/Entity/Journal.cs +++ b/QYZH.InteractiveMagazine.Models/Entity/Journal.cs @@ -6,18 +6,18 @@ namespace QYZH.InteractiveMagazine.Models.Entity ///期刊表 /// [SugarTable("Journal")] - public partial class Journal : BaseEntity + public partial class Journal : SqlSugarBaseEntity { public Journal(){ } - /// - /// Desc:期刊号 - /// Default: - /// Nullable:False - /// - public int IssueNumber {get;set;} + /// + /// Desc:期刊号 + /// Default: + /// Nullable:False + /// + public int IssueNumber {get;set;} /// /// Desc:期刊标题 diff --git a/QYZH.InteractiveMagazine.Models/Entity/Medal.cs b/QYZH.InteractiveMagazine.Models/Entity/Medal.cs index aa48eaa..3a3e5b7 100644 --- a/QYZH.InteractiveMagazine.Models/Entity/Medal.cs +++ b/QYZH.InteractiveMagazine.Models/Entity/Medal.cs @@ -6,74 +6,68 @@ namespace QYZH.InteractiveMagazine.Models.Entity ///勋章定义表 /// [SugarTable("Medal")] - public partial class Medal : BaseEntity + public partial class Medal : SqlSugarBaseEntity { - public Medal(){ + public Medal() + { - } - /// - /// Desc:主键 - /// Default: - /// Nullable:False - /// - [SugarColumn(IsPrimaryKey=true,IsIdentity=true)] - public new int Id {get;set;} + } - /// - /// Desc:勋章名称 - /// Default: - /// Nullable:False - /// - public string Name {get;set;} + /// + /// Desc:勋章名称 + /// Default: + /// Nullable:False + /// + public string Name { get; set; } - /// - /// Desc:获得条件描述 - /// Default: - /// Nullable:True - /// - public string Description {get;set;} + /// + /// Desc:获得条件描述 + /// Default: + /// Nullable:True + /// + public string Description { get; set; } - /// - /// Desc:图片地址 - /// Default: - /// Nullable:True - /// - public string ImageUrl {get;set;} + /// + /// Desc:图片地址 + /// Default: + /// Nullable:True + /// + public string ImageUrl { get; set; } - /// - /// Desc:条件类型: EvolutionCount, FeedingCount等 - /// Default: - /// Nullable:False - /// - public string ConditionType {get;set;} + /// + /// Desc:条件类型: EvolutionCount, FeedingCount等 + /// Default: + /// Nullable:False + /// + public string ConditionType { get; set; } - /// - /// Desc:条件阈值 - /// Default: - /// Nullable:False - /// - public int ConditionValue {get;set;} + /// + /// Desc:条件阈值 + /// Default: + /// Nullable:False + /// + public int ConditionValue { get; set; } - /// - /// Desc:排序 - /// Default:0 - /// Nullable:False - /// - public int SortOrder {get;set;} + /// + /// Desc:排序 + /// Default:0 + /// Nullable:False + /// + public int SortOrder { get; set; } - /// - /// Desc:勋章的类型: Pet, Community - /// Default:Pet - /// Nullable:False - /// - public string Type {get;set;} + /// + /// Desc:勋章的类型: Pet, Community + /// Default:Pet + /// Nullable:False + /// + public string Type { get; set; } - /// - /// Desc:状态: Active, Inactive - /// Default:Active - /// Nullable:False - /// - public string Status {get;set;} + /// + /// Desc:状态: Active, Inactive + /// Default:Active + /// Nullable:False + /// + public string Status { get; set; } } } diff --git a/QYZH.InteractiveMagazine.Models/Entity/MessageComment.cs b/QYZH.InteractiveMagazine.Models/Entity/MessageComment.cs index a1d0f03..a31ca90 100644 --- a/QYZH.InteractiveMagazine.Models/Entity/MessageComment.cs +++ b/QYZH.InteractiveMagazine.Models/Entity/MessageComment.cs @@ -6,18 +6,19 @@ namespace QYZH.InteractiveMagazine.Models.Entity ///模板评论表 /// [SugarTable("MessageComment")] - public partial class MessageComment : BaseEntity + public partial class MessageComment : SqlSugarBaseEntity { public MessageComment(){ } - /// - /// Desc:用户Id - /// Default: - /// Nullable:False - /// - public long UserId {get;set;} + + /// + /// Desc:用户Id + /// Default: + /// Nullable:False + /// + public long UserId {get;set;} /// /// Desc:消息Id diff --git a/QYZH.InteractiveMagazine.Models/Entity/MessageLike.cs b/QYZH.InteractiveMagazine.Models/Entity/MessageLike.cs index 55a87db..aa65c12 100644 --- a/QYZH.InteractiveMagazine.Models/Entity/MessageLike.cs +++ b/QYZH.InteractiveMagazine.Models/Entity/MessageLike.cs @@ -6,18 +6,18 @@ namespace QYZH.InteractiveMagazine.Models.Entity ///点赞记录表 /// [SugarTable("MessageLike")] - public partial class MessageLike : BaseEntity + public partial class MessageLike : SqlSugarBaseEntity { public MessageLike(){ } - /// - /// Desc:用户Id - /// Default: - /// Nullable:False - /// - public long UserId {get;set;} + /// + /// Desc:用户Id + /// Default: + /// Nullable:False + /// + public long UserId {get;set;} /// /// Desc:消息Id diff --git a/QYZH.InteractiveMagazine.Models/Entity/Pet.cs b/QYZH.InteractiveMagazine.Models/Entity/Pet.cs index 180175d..950ce04 100644 --- a/QYZH.InteractiveMagazine.Models/Entity/Pet.cs +++ b/QYZH.InteractiveMagazine.Models/Entity/Pet.cs @@ -6,18 +6,18 @@ namespace QYZH.InteractiveMagazine.Models.Entity ///宠物实例表 /// [SugarTable("Pet")] - public partial class Pet : BaseEntity + public partial class Pet : SqlSugarBaseEntity { public Pet(){ } - /// - /// Desc:用户Id - /// Default: - /// Nullable:False - /// - public long UserId {get;set;} + /// + /// Desc:用户Id + /// Default: + /// Nullable:False + /// + public long UserId {get;set;} /// /// Desc:宠物昵称 diff --git a/QYZH.InteractiveMagazine.Models/Entity/PetEvolution.cs b/QYZH.InteractiveMagazine.Models/Entity/PetEvolution.cs index 7b8f9f0..be6fd5d 100644 --- a/QYZH.InteractiveMagazine.Models/Entity/PetEvolution.cs +++ b/QYZH.InteractiveMagazine.Models/Entity/PetEvolution.cs @@ -6,19 +6,12 @@ namespace QYZH.InteractiveMagazine.Models.Entity ///宠物进化链定义表 /// [SugarTable("PetEvolution")] - public partial class PetEvolution : BaseEntity + public partial class PetEvolution : SqlSugarBaseEntity { public PetEvolution(){ } - /// - /// Desc:主键 - /// Default: - /// Nullable:False - /// - [SugarColumn(IsPrimaryKey=true,IsIdentity=true)] - public new int Id {get;set;} /// /// Desc:阶段名称 diff --git a/QYZH.InteractiveMagazine.Models/Entity/PetFeedingRecord.cs b/QYZH.InteractiveMagazine.Models/Entity/PetFeedingRecord.cs index 02465db..bd1891c 100644 --- a/QYZH.InteractiveMagazine.Models/Entity/PetFeedingRecord.cs +++ b/QYZH.InteractiveMagazine.Models/Entity/PetFeedingRecord.cs @@ -6,18 +6,19 @@ namespace QYZH.InteractiveMagazine.Models.Entity ///宠物喂养记录表 /// [SugarTable("PetFeedingRecord")] - public partial class PetFeedingRecord : BaseEntity + public partial class PetFeedingRecord : SqlSugarBaseEntity { public PetFeedingRecord(){ } - /// - /// Desc:宠物Id - /// Default: - /// Nullable:False - /// - public long PetId {get;set;} + + /// + /// Desc:宠物Id + /// Default: + /// Nullable:False + /// + public long PetId {get;set;} /// /// Desc:用户Id diff --git a/QYZH.InteractiveMagazine.Models/Entity/PointsRecord.cs b/QYZH.InteractiveMagazine.Models/Entity/PointsRecord.cs index 30cb5eb..8db8262 100644 --- a/QYZH.InteractiveMagazine.Models/Entity/PointsRecord.cs +++ b/QYZH.InteractiveMagazine.Models/Entity/PointsRecord.cs @@ -6,18 +6,19 @@ namespace QYZH.InteractiveMagazine.Models.Entity ///积分流水记录表 /// [SugarTable("PointsRecord")] - public partial class PointsRecord : BaseEntity + public partial class PointsRecord : SqlSugarBaseEntity { public PointsRecord(){ } - /// - /// Desc:用户Id - /// Default: - /// Nullable:False - /// - public long UserId {get;set;} + + /// + /// Desc:用户Id + /// Default: + /// Nullable:False + /// + public long UserId {get;set;} /// /// Desc:变动数值 diff --git a/QYZH.InteractiveMagazine.Models/Entity/Product.cs b/QYZH.InteractiveMagazine.Models/Entity/Product.cs index 2160df3..0508825 100644 --- a/QYZH.InteractiveMagazine.Models/Entity/Product.cs +++ b/QYZH.InteractiveMagazine.Models/Entity/Product.cs @@ -6,19 +6,12 @@ namespace QYZH.InteractiveMagazine.Models.Entity ///虚拟商品表 /// [SugarTable("Product")] - public partial class Product : BaseEntity + public partial class Product : SqlSugarBaseEntity { public Product(){ } - /// - /// Desc:主键 - /// Default: - /// Nullable:False - /// - [SugarColumn(IsPrimaryKey=true,IsIdentity=true)] - public new int Id {get;set;} /// /// Desc:商品名称 diff --git a/QYZH.InteractiveMagazine.Models/Entity/SqlSugarBaseEntity.cs b/QYZH.InteractiveMagazine.Models/Entity/SqlSugarBaseEntity.cs new file mode 100644 index 0000000..4de11ee --- /dev/null +++ b/QYZH.InteractiveMagazine.Models/Entity/SqlSugarBaseEntity.cs @@ -0,0 +1,63 @@ +using SqlSugar; +using Yitter.IdGenerator; + +namespace QYZH.InteractiveMagazine.Models.Entity +{ + public class SqlSugarBaseEntity + { + + /// + /// Desc:主键 + /// Default: + /// Nullable:False + /// + public long Id { get; set; } = YitIdHelper.NextId(); + /// + /// Desc:状态 0禁用 1启用 + /// Default:1 + /// Nullable:False + /// + [SugarColumn(ColumnName = "Status")] + public string Status { get; set; } + + /// + /// Desc:是否删除 + /// Default:b'0' + /// Nullable:False + /// + [SugarColumn(ColumnName = "IsDeleted")] + public bool IsDeleted { get; set; } = false; + + /// + /// Desc:创建人 + /// Default: + /// Nullable:False + /// + [SugarColumn(ColumnName = "CreatedBy", IsOnlyIgnoreUpdate = true)] + public string CreatedBy { get; set; } + + /// + /// Desc:创建时间 + /// Default: + /// Nullable:False + /// + [SugarColumn(ColumnName = "CreatedAt", IsOnlyIgnoreUpdate = true)] + public DateTime CreatedAt { get; set; } + + /// + /// Desc:修改人 + /// Default: + /// Nullable:True + /// + [SugarColumn(ColumnName = "updatedBy", IsOnlyIgnoreInsert = true)] + public string UpdatedBy { get; set; } + + /// + /// Desc:修改时间 + /// Default: + /// Nullable:True + /// + [SugarColumn(ColumnName = "UpdatedAt", IsOnlyIgnoreInsert = true)] + public DateTime? UpdatedAt { get; set; } + } +} diff --git a/QYZH.InteractiveMagazine.Models/Entity/TemplateSentence.cs b/QYZH.InteractiveMagazine.Models/Entity/TemplateSentence.cs index acf5f66..9bfd70e 100644 --- a/QYZH.InteractiveMagazine.Models/Entity/TemplateSentence.cs +++ b/QYZH.InteractiveMagazine.Models/Entity/TemplateSentence.cs @@ -6,19 +6,13 @@ namespace QYZH.InteractiveMagazine.Models.Entity ///固定模板言论表 /// [SugarTable("TemplateSentence")] - public partial class TemplateSentence : BaseEntity + public partial class TemplateSentence : SqlSugarBaseEntity { public TemplateSentence(){ } - /// - /// Desc:主键 - /// Default: - /// Nullable:False - /// - [SugarColumn(IsPrimaryKey=true,IsIdentity=true)] - public new int Id {get;set;} + /// /// Desc:模板内容 diff --git a/QYZH.InteractiveMagazine.Models/Entity/User.cs b/QYZH.InteractiveMagazine.Models/Entity/User.cs deleted file mode 100644 index 67f617a..0000000 --- a/QYZH.InteractiveMagazine.Models/Entity/User.cs +++ /dev/null @@ -1,71 +0,0 @@ -using SqlSugar; - -namespace QYZH.InteractiveMagazine.Models.Entity -{ - /// - ///用户表 - /// - [SugarTable("User")] - public partial class User : BaseEntity - { - public User(){ - - - } - /// - /// Desc:微信OpenId - /// Default: - /// Nullable:False - /// - public string OpenId {get;set;} - - /// - /// Desc:微信UnionId - /// Default: - /// Nullable:True - /// - public string UnionId {get;set;} - - /// - /// Desc:昵称 - /// Default: - /// Nullable:True - /// - public string NickName {get;set;} - - /// - /// Desc:头像地址 - /// Default: - /// Nullable:True - /// - public string AvatarUrl {get;set;} - - /// - /// Desc:手机号 - /// Default: - /// Nullable:True - /// - public string Phone {get;set;} - - /// - /// Desc:积分余额 - /// Default:0 - /// Nullable:False - /// - public int Points {get;set;} - - /// - /// Desc:用户类型: Normal, VIP - /// Default:Normal - /// Nullable:False - /// - public string Type {get;set;} - - /// - /// Desc:状态: Active, Disabled - /// Default:Active - /// Nullable:False - /// - public string Status {get;set;} - } -} diff --git a/QYZH.InteractiveMagazine.Models/Entity/WxUser.cs b/QYZH.InteractiveMagazine.Models/Entity/WxUser.cs new file mode 100644 index 0000000..1fc011b --- /dev/null +++ b/QYZH.InteractiveMagazine.Models/Entity/WxUser.cs @@ -0,0 +1,80 @@ +using SqlSugar; + +namespace QYZH.InteractiveMagazine.Models.Entity +{ + /// + ///用户表 + /// + [SugarTable("WxUser")] + public partial class WxUser : SqlSugarBaseEntity + { + /// + /// Desc:微信OpenId + /// Default: + /// Nullable:False + /// + public string OpenId { get; set; } + + /// + /// Desc:微信UnionId + /// Default: + /// Nullable:True + /// + public string UnionId { get; set; } + + /// + /// Desc:昵称 + /// Default: + /// Nullable:True + /// + public string NickName { get; set; } + + /// + /// Desc:头像地址 + /// Default: + /// Nullable:True + /// + public string AvatarUrl { get; set; } + + /// + /// Desc:手机号 + /// Default: + /// Nullable:True + /// + public string Phone { get; set; } + + /// + /// Desc:积分余额 + /// Default:0 + /// Nullable:False + /// + public int Points { get; set; } + + /// + /// Desc:用户类型: Normal, VIP + /// Default:Normal + /// Nullable:False + /// + public string Type { get; set; } + + /// + /// Desc:状态: Active, Disabled + /// Default:Active + /// Nullable:False + /// + public string Status { get; set; } + + /// + /// Desc:密码,默认手机后4位 + /// Default:Active + /// Nullable:False + /// + public string Pwd { get; set; } + /// + /// Desc:当前成长值 + /// Default:0 + /// Nullable:False + /// + public int GrowthPoints { get; set; } + } +} diff --git a/QYZH.InteractiveMagazine.Models/Entity/UserBag.cs b/QYZH.InteractiveMagazine.Models/Entity/WxUserBag.cs similarity index 92% rename from QYZH.InteractiveMagazine.Models/Entity/UserBag.cs rename to QYZH.InteractiveMagazine.Models/Entity/WxUserBag.cs index de6a09e..7f10440 100644 --- a/QYZH.InteractiveMagazine.Models/Entity/UserBag.cs +++ b/QYZH.InteractiveMagazine.Models/Entity/WxUserBag.cs @@ -5,10 +5,10 @@ namespace QYZH.InteractiveMagazine.Models.Entity /// ///用户背包表 /// - [SugarTable("UserBag")] - public partial class UserBag : BaseEntity + [SugarTable("WxUserBag")] + public partial class WxUserBag : SqlSugarBaseEntity { - public UserBag(){ + public WxUserBag(){ } diff --git a/QYZH.InteractiveMagazine.Models/Entity/UserMedal.cs b/QYZH.InteractiveMagazine.Models/Entity/WxUserMedal.cs similarity index 90% rename from QYZH.InteractiveMagazine.Models/Entity/UserMedal.cs rename to QYZH.InteractiveMagazine.Models/Entity/WxUserMedal.cs index c30a3b9..884c68e 100644 --- a/QYZH.InteractiveMagazine.Models/Entity/UserMedal.cs +++ b/QYZH.InteractiveMagazine.Models/Entity/WxUserMedal.cs @@ -5,10 +5,10 @@ namespace QYZH.InteractiveMagazine.Models.Entity /// ///用户勋章表 /// - [SugarTable("UserMedal")] - public partial class UserMedal : BaseEntity + [SugarTable("WxUserMedal")] + public partial class WxUserMedal : SqlSugarBaseEntity { - public UserMedal(){ + public WxUserMedal(){ } diff --git a/QYZH.InteractiveMagazine.Models/QYZH.InteractiveMagazine.Models.csproj b/QYZH.InteractiveMagazine.Models/QYZH.InteractiveMagazine.Models.csproj index 0bb8e11..f145742 100644 --- a/QYZH.InteractiveMagazine.Models/QYZH.InteractiveMagazine.Models.csproj +++ b/QYZH.InteractiveMagazine.Models/QYZH.InteractiveMagazine.Models.csproj @@ -8,7 +8,9 @@ + + diff --git a/QYZH.InteractiveMagazine.Repository/AdminUserRepository.cs b/QYZH.InteractiveMagazine.Repository/AdminUserRepository.cs deleted file mode 100644 index e81d9a9..0000000 --- a/QYZH.InteractiveMagazine.Repository/AdminUserRepository.cs +++ /dev/null @@ -1,13 +0,0 @@ -using QYZH.InteractiveMagazine.Models.Entity; - -namespace QYZH.InteractiveMagazine.Repository; - -public class AdminUserRepository : BaseRepository, IAdminUserRepository -{ - public async Task GetByUserNameAsync(string userName) - { - return await Db.Queryable() - .Where(x => x.UserName == userName) - .FirstAsync(); - } -} diff --git a/QYZH.InteractiveMagazine.Repository/BaseRepository.cs b/QYZH.InteractiveMagazine.Repository/BaseRepository.cs index cbb2414..37bc4c9 100644 --- a/QYZH.InteractiveMagazine.Repository/BaseRepository.cs +++ b/QYZH.InteractiveMagazine.Repository/BaseRepository.cs @@ -1,154 +1,293 @@ +using Mapster; +using Microsoft.Extensions.Logging; +using QYZH.InteractiveMagazine.Infrastructure.Context; using QYZH.InteractiveMagazine.Models.Dto; using SqlSugar; +using SqlSugar.IOC; +using System.Data; using System.Linq.Expressions; -namespace QYZH.InteractiveMagazine.Repository; -/// -/// 基础仓储实现 -/// -/// 实体类型 -public class BaseRepository : IBaseRepository where T : class, new() +namespace QYZH.InteractiveMagazine.Repository { /// - /// SqlSugar 数据库实例 + /// 数据仓库类 /// - protected SqlSugarClient Db => SqlSugarDbContext.GetDb(); - - /// - /// 根据Id获取实体(自动过滤已删除数据) - /// - /// 主键Id - /// 实体对象 - public async Task GetByIdAsync(long id) + /// + public class BaseRepository : SimpleClient where T : class, new() { - return await Db.Queryable().In(id).FirstAsync(); - } - - /// - /// 获取所有列表(自动过滤已删除数据) - /// - /// 实体列表 - public async Task> GetListAsync() - { - return await Db.Queryable().ToListAsync(); - } - - /// - /// 根据条件获取列表(自动过滤已删除数据) - /// - /// 查询条件 - /// 实体列表 - public async Task> GetListByWhereAsync(Expression> where) - { - return await Db.Queryable().Where(where).ToListAsync(); - } - - /// - /// 分页查询(自动过滤已删除数据) - /// - /// 查询条件 - /// 分页参数 - /// 分页结果 - public async Task> GetPageListAsync(Expression> where, PageQueryModel pageQuery) - { - RefAsync total = 0; - - var query = Db.Queryable().Where(where); - - // 处理排序 - if (!string.IsNullOrEmpty(pageQuery.SortField)) + private readonly ILogger> _logger; + public BaseRepository(ISqlSugarClient context = null) : base(context) { - var isAsc = string.IsNullOrEmpty(pageQuery.SortOrder) || - pageQuery.SortOrder.ToLower() == "asc"; - query = isAsc - ? query.OrderBy($"{pageQuery.SortField} asc") - : query.OrderBy($"{pageQuery.SortField} desc"); + Context = DbScoped.SugarScope; + _logger = ServiceContext.GetService>>(); } - var list = await query.ToPageListAsync(pageQuery.PageIndex, pageQuery.PageSize, total); + #region add - return new PageListModel + public IInsertable Insertable(T t) { - PageIndex = pageQuery.PageIndex, - PageSize = pageQuery.PageSize, - TotalCount = total, - List = list - }; + return Context.Insertable(t); + } + + #endregion add + + #region update + public IUpdateable Updateable(T t) + { + return Context.Updateable(t); + } + + public IUpdateable Updateable() + { + return Context.Updateable(); + } + + public IUpdateable Updateable() where T1 : class, new() + { + return Context.Updateable(); + } + + /// + /// 根据指定条件更新指定列 eg:Update(new SysUser(){ Status = 1 }, it => new { it.Status }, f => f.Userid == 1)); + /// 只更新Status列,条件是包含 + /// + /// 实体类 + /// 要更新列的表达式 + /// where表达式 + /// + public async Task UpdateAsync(Expression> columns, Expression> where) + { + return await Context.Updateable().SetColumns(columns).Where(where).ExecuteCommandAsync() > 0; + } + #endregion update + + /// + /// 事务 异步 无返回值 + /// + /// + /// + public async Task UseTranAsync(Func action) + { + Context.Ado.BeginTran();//using不能少 + try + { + await action(); + Context.Ado.CommitTran(); + } + catch (Exception ex) + { + Context.Ado.RollbackTran(); + _logger.LogError($"UseTran 异常:{ex.StackTrace},{ex.Message}"); + throw; + } + } + + /// + /// 事务 异步 返回bool + /// + /// + /// + public async Task UseTranAsync(Func> action) + { + Context.Ado.BeginTran();//using不能少 + try + { + var result = await action(); + if (result) + { + Context.Ado.CommitTran(); + return true; + } + else + { + Context.Ado.RollbackTran(); + return false; + } + } + catch (Exception ex) + { + Context.Ado.RollbackTran(); + _logger.LogError($"UseTran 异常:{ex.StackTrace},{ex.Message}"); + throw; + } + } + + #region delete + public IDeleteable Deleteable() + { + return Context.Deleteable(); + } + #endregion delete + + #region query + + public bool Any(Expression> expression) + { + return Context.Queryable().Any(expression); + } + + public ISugarQueryable Queryable() + { + return Context.Queryable(); + } + + public ISugarQueryable Queryable() + { + return Context.Queryable(); + } + + /// + /// 根据条件表达式查询单条数据 + /// + /// 表达式 + /// 泛型实体 + public Task GetByIdAsync(Expression> expression) where R : class + { + return Context.Queryable().Where(expression).Select().FirstAsync(); + } + + public Task GetByExpressionAsync(Expression> expression) where R : class + { + return Context.Queryable().Where(expression).Select().FirstAsync(); + } + + public Task> GetListByExpression(Expression> expression) where T2 : class + { + return Context.Queryable().Where(expression).Select().ToListAsync(); + } + + /// + /// 根据条件查询分页数据 + /// + /// + /// + /// + public PageListModel GetPages(Expression> where, PageQueryModel parm) + { + var source = Context.Queryable().Where(where); + + return source.ToPage(parm); + } + + /// + /// 分页获取数据 + /// + /// 条件表达式 + /// + /// + /// + /// + public PageListModel GetPages(Expression> where, PageQueryModel parm, Expression> order, OrderByType orderEnum = OrderByType.Asc) + { + var source = Context + .Queryable() + .Where(where) + .OrderByIF(orderEnum == OrderByType.Asc, order, OrderByType.Asc) + .OrderByIF(orderEnum == OrderByType.Desc, order, OrderByType.Desc); + + return source.ToPage(parm); + } + + public PageListModel GetPages(Expression> where, PageQueryModel parm, Expression> order, string orderByType) + { + return GetPages(where, parm, order, orderByType == "desc" ? OrderByType.Desc : OrderByType.Asc); + } + + /// + /// 查询所有数据(无分页,请慎用) + /// + /// + public List GetAll(bool useCache = false, int cacheSecond = 3600) + { + return Context.Queryable().WithCacheIF(useCache, cacheSecond).ToList(); + } + + #endregion query + + /// + /// 此方法不带output返回值 + /// var list = new List(); + /// list.Add(new SugarParameter(ParaName, ParaValue)); input + /// + /// + /// + /// + public DataTable UseStoredProcedureToDataTable(string procedureName, List parameters) + { + return Context.Ado.UseStoredProcedure().GetDataTable(procedureName, parameters); + } + + /// + /// 带output返回值 + /// var list = new List(); + /// list.Add(new SugarParameter(ParaName, ParaValue, true)); output + /// list.Add(new SugarParameter(ParaName, ParaValue)); input + /// + /// + /// + /// + public (DataTable, List) UseStoredProcedureToTuple(string procedureName, List parameters) + { + var result = (Context.Ado.UseStoredProcedure().GetDataTable(procedureName, parameters), parameters); + return result; + } } /// - /// 插入单条记录 + /// 分页查询扩展 /// - /// 实体对象 - /// 是否成功 - public async Task InsertAsync(T entity) + public static class QueryableExtension { - return await Db.Insertable(entity).ExecuteCommandAsync() > 0; - } + /// + /// 读取列表 + /// + /// + /// 查询表单式 + /// 分页参数 + /// + public static PageListModel ToPage(this ISugarQueryable source, PageQueryModel parm) + { + var page = new PageListModel(); + var total = 0; + page.PageSize = parm.PageSize; + page.PageIndex = parm.PageIndex; + if (string.IsNullOrEmpty(parm.Sort)) + { + source.OrderByPropertyName(parm.Sort, parm.SortType.Contains("desc") ? OrderByType.Desc : OrderByType.Asc); + } + page.Result = source + //.OrderByIF(parm.Sort.IsNotEmpty(), $"{parm.Sort.ToSqlFilter()} {(!string.IsNullOrWhiteSpace(parm.SortType) && parm.SortType.Contains("desc") ? "desc" : "asc")}") + .ToPageList(parm.PageIndex, parm.PageSize, ref total); + page.TotalNum = total; + return page; + } - /// - /// 批量插入记录 - /// - /// 实体列表 - /// 是否成功 - public async Task InsertRangeAsync(List entities) - { - return await Db.Insertable(entities).ExecuteCommandAsync() > 0; - } + /// + /// 转指定实体类Dto + /// + /// + /// + /// + /// + /// + public static PageListModel ToPage(this ISugarQueryable source, PageQueryModel parm) + { + var page = new PageListModel(); + var total = 0; + page.PageSize = parm.PageSize; + page.PageIndex = parm.PageIndex; + if (string.IsNullOrEmpty(parm.Sort)) + { + source.OrderByPropertyName(parm.Sort, parm.SortType.Contains("desc") ? OrderByType.Desc : OrderByType.Asc); + } + var result = source + //.OrderByIF(parm.Sort.IsNotEmpty(), $"{parm.Sort.ToSqlFilter()} {(!string.IsNullOrWhiteSpace(parm.SortType) && parm.SortType.Contains("desc") ? "desc" : "asc")}") + .ToPageList(parm.PageIndex, parm.PageSize, ref total); - /// - /// 更新单条记录 - /// - /// 实体对象 - /// 是否成功 - public async Task UpdateAsync(T entity) - { - return await Db.Updateable(entity).ExecuteCommandAsync() > 0; + page.TotalNum = total; + page.Result = result.Adapt>(); + return page; + } } - - /// - /// 批量更新记录 - /// - /// 实体列表 - /// 是否成功 - public async Task UpdateRangeAsync(List entities) - { - return await Db.Updateable(entities).ExecuteCommandAsync() > 0; - } - - /// - /// 根据Id删除记录(软删除,设置 IsDeleted = true) - /// - /// 主键Id - /// 是否成功 - public async Task DeleteByIdAsync(long id) - { - return await Db.Deleteable().In(id).IsLogic().ExecuteCommandAsync() > 0; - } - - /// - /// 根据条件删除记录(软删除,设置 IsDeleted = true) - /// - /// 删除条件 - /// 是否成功 - public async Task DeleteByWhereAsync(Expression> where) - { - return await Db.Deleteable().Where(where).IsLogic().ExecuteCommandAsync() > 0; - } - - /// - /// 根据条件获取记录数(自动过滤已删除数据) - /// - /// 查询条件 - /// 记录数 - public async Task GetCountAsync(Expression> where) - { - return await Db.Queryable().Where(where).CountAsync(); - } - - public ISugarQueryable Queryable() - { - return Db.Queryable(); - } -} +} diff --git a/QYZH.InteractiveMagazine.Repository/Core/SqlSugarExtension.cs b/QYZH.InteractiveMagazine.Repository/Core/SqlSugarExtension.cs new file mode 100644 index 0000000..f2c3a2d --- /dev/null +++ b/QYZH.InteractiveMagazine.Repository/Core/SqlSugarExtension.cs @@ -0,0 +1,160 @@ +using QYZH.InteractiveMagazine.Models.Entity; +using SqlSugar; +using System.Linq.Expressions; +using System.Reflection; + + +namespace QYZH.InteractiveMagazine.Repository.Core +{ + /// + /// sql sugar 管理器 + /// + public static class SqlSugarExtension + { + /// + /// 生成类文件 + /// + /// + /// 生成路径 + /// 名称空间 + public static ISqlSugarClient CreateClassFile(this ISqlSugarClient db, string directoryPath, string nameSpace = "Models") + { + foreach (var item in db.DbMaintenance.GetTableInfoList()) + { + string[] entityNameArray = item.Name.Split('_', StringSplitOptions.RemoveEmptyEntries).ToArray(); + string entityName = string.Join("", entityNameArray.Select(c => c.ToCamelCase())); + db.MappingTables.Add(entityName, item.Name); + foreach (var col in db.DbMaintenance.GetColumnInfosByTableName(item.Name)) + { + var columnNames = col.DbColumnName.ToLower().Split('_', StringSplitOptions.RemoveEmptyEntries).ToArray(); + string columnName = string.Join("", columnNames.Select(c => c.ToCamelCase())); + db.MappingColumns.Add(columnName, col.DbColumnName, entityName); + } + } + db.DbFirst.IsCreateAttribute().CreateClassFile(directoryPath, nameSpace); + return db; + } + + + /// + /// 添加全局过滤器 + /// IsDeleted + /// + /// 数据库Client + /// 程序集名称 + /// + public static ISqlSugarClient SetQueryFilter(this ISqlSugarClient db, string assemblyName) + { + var assembly = Assembly.Load(assemblyName); + + var modelBaseType = typeof(SqlSugarBaseEntity); + var repoBaseType = typeof(SqlSugarBaseEntity); + + var types = assembly.ExportedTypes + .Where(t => (modelBaseType.IsAssignableFrom(t) || repoBaseType.IsAssignableFrom(t)) + && t != modelBaseType && t != repoBaseType + && !t.IsGenericTypeDefinition) + .ToList(); + + foreach (var entityType in types) + { + var property = entityType.GetProperty("IsDeleted", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly); + if (property == null) + { + var baseType = entityType.BaseType; + while (baseType != null && baseType != typeof(object)) + { + property = baseType.GetProperty("IsDeleted", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly); + if (property != null) break; + baseType = baseType.BaseType; + } + } + + if (property == null) continue; + + var propertyType = property.PropertyType; + + Expression filterExpression; + var param = Expression.Parameter(entityType, "it"); + var propertyAccess = Expression.Property(param, property); + + if (propertyType == typeof(bool)) + { + filterExpression = Expression.Equal(propertyAccess, Expression.Constant(false, typeof(bool))); + } + else if (propertyType == typeof(bool?)) + { + filterExpression = Expression.Equal(propertyAccess, Expression.Constant(false, typeof(bool?))); + } + else if (propertyType == typeof(byte)) + { + filterExpression = Expression.Equal(propertyAccess, Expression.Constant((byte)0, typeof(byte))); + } + else if (propertyType == typeof(byte?)) + { + filterExpression = Expression.Equal(propertyAccess, Expression.Constant((byte)0, typeof(byte?))); + } + else + { + continue; + } + + var lambda = Expression.Lambda(filterExpression, param); + db.QueryFilter.AddTableFilter(entityType, lambda); + } + + return db; + } + + /// + /// 添加创建人 创建时间 更新人 更新时间 默认值 + /// + /// + public static ISqlSugarClient SetDefaultValue(this ISqlSugarClient db) + { + #region 创建人 创建时间 更新人 更新时间 默认值 + db.Aop.DataExecuting = (oldValue, entityInfo) => + { + var entityValue = entityInfo.EntityColumnInfo.PropertyInfo.GetValue(entityInfo.EntityValue)?.ToString(); + var currnetUserName = ""; + /*** inset生效 ***/ + if (entityInfo.OperationType == DataFilterType.InsertByObject) + { + if (entityInfo.PropertyName == "CreatedAt" && (string.IsNullOrWhiteSpace(entityValue) || entityValue == DateTime.MinValue.ToString())) + entityInfo.SetValue(DateTime.Now);//修改CreateTime字段 + else if (entityInfo.PropertyName == "CreatedBy" && (string.IsNullOrWhiteSpace(entityValue))) + entityInfo.SetValue(currnetUserName);//修改创建人字段 + else if (entityInfo.PropertyName == "IsDeleted" && string.IsNullOrWhiteSpace(entityValue)) + entityInfo.SetValue("0");//修改CreateTime字段 + + } + + /*** update生效 ***/ + if (entityInfo.OperationType == DataFilterType.UpdateByObject) + { + if (entityInfo.PropertyName == "UpdatedAt" && (string.IsNullOrWhiteSpace(entityValue) || entityValue == DateTime.MinValue.ToString())) + entityInfo.SetValue(DateTime.Now);//修改UpdatedTime字段 + else if (entityInfo.PropertyName == "UpdatedBy" && (string.IsNullOrWhiteSpace(entityValue) || entityValue == "0")) + entityInfo.SetValue(currnetUserName);//修改更新人字段 + } + }; + return db; + #endregion + } + + + /// + /// 把一个字符串转成驼峰规则的字符串 + /// + /// + /// + public static string ToCamelCase(this string str) + { + if (!string.IsNullOrEmpty(str) && str.Length > 1) + { + return char.ToUpperInvariant(str[0]) + str.Substring(1); + } + return str; + } + } +} diff --git a/QYZH.InteractiveMagazine.Repository/Core/SqlSugarManager.cs b/QYZH.InteractiveMagazine.Repository/Core/SqlSugarManager.cs new file mode 100644 index 0000000..60fc190 --- /dev/null +++ b/QYZH.InteractiveMagazine.Repository/Core/SqlSugarManager.cs @@ -0,0 +1,51 @@ +using Microsoft.AspNetCore.Builder; +using QYZH.InteractiveMagazine.Repository.Core; +using Serilog; +using SqlSugar; +using SqlSugar.IOC; + +namespace QYZH.InteractiveMagazine.Repository.Core +{ + /// + /// sql sugar 管理器 + /// + public static class SqlSugarManager + { + /// + /// 获基础信息库对象 (用IOC这块代码不能写到IOC里面) + /// + public static void InitSqlSugarDb(this WebApplicationBuilder builder, IocConfig config) + { + builder.Services.AddSqlSugar(config); + //配置参数 + SugarIocServices.ConfigurationSugar(db => + { + db.Aop.OnLogExecuting = (sql, pars) => + { + //var param = db.GetConnectionScope(0).Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value)); + Log.Information($"【sql语句】{UtilMethods.GetSqlString((DbType)config.DbType, sql, pars)}\n"); + }; + + db.Aop.OnError = (ex) => + { + string sql = $"【错误SQL】{UtilMethods.GetSqlString((DbType)config.DbType, ex.Sql, (SugarParameter[])ex.Parametres)}\r\n"; + Log.Error(ex, $"{sql}\r\n{ex.Message}\r\n{ex.StackTrace}"); + }; + //SQL执行完 + db.Aop.OnLogExecuted = (sql, pars) => + { + //执行完了可以输出SQL执行时间 (OnLogExecutedDelegate) + }; + db.SetDefaultValue().SetQueryFilter(GetAssemblyNames());//.CreateClassFile("C:\\Model"); + }); + } + + private static string GetAssemblyNames() + { + string friendlyName = AppDomain.CurrentDomain.FriendlyName; + string[] source = friendlyName.Split('.'); + string assemblyNames = string.Join(".", source.Take(source.Count() - 1)) + ".Models"; + return assemblyNames; + } + } +} diff --git a/QYZH.InteractiveMagazine.Repository/IAdminUserRepository.cs b/QYZH.InteractiveMagazine.Repository/IAdminUserRepository.cs deleted file mode 100644 index 37537eb..0000000 --- a/QYZH.InteractiveMagazine.Repository/IAdminUserRepository.cs +++ /dev/null @@ -1,8 +0,0 @@ -using QYZH.InteractiveMagazine.Models.Entity; - -namespace QYZH.InteractiveMagazine.Repository; - -public interface IAdminUserRepository : IBaseRepository -{ - Task GetByUserNameAsync(string userName); -} diff --git a/QYZH.InteractiveMagazine.Repository/IBaseRepository.cs b/QYZH.InteractiveMagazine.Repository/IBaseRepository.cs index 6366ab9..f6514d5 100644 --- a/QYZH.InteractiveMagazine.Repository/IBaseRepository.cs +++ b/QYZH.InteractiveMagazine.Repository/IBaseRepository.cs @@ -1,88 +1,102 @@ + using QYZH.InteractiveMagazine.Models.Dto; +using SqlSugar; +using System.Data; using System.Linq.Expressions; -namespace QYZH.InteractiveMagazine.Repository; - -/// -/// 基础仓储接口 -/// -/// 实体类型 -public interface IBaseRepository where T : class, new() +namespace QYZH.InteractiveMagazine.Repository { - /// - /// 根据Id获取实体 - /// - /// 主键Id - /// 实体对象 - Task GetByIdAsync(long id); + public interface IBaseRepository : ISimpleClient where T : class, new() + { + #region add + int Add(T t, bool ignoreNull = true); - /// - /// 获取所有列表 - /// - /// 实体列表 - Task> GetListAsync(); + int Insert(List t); + int Insert(T parm, Expression> iClumns = null, bool ignoreNull = true); - /// - /// 根据条件获取列表 - /// - /// 查询条件 - /// 实体列表 - Task> GetListByWhereAsync(Expression> where); + IInsertable Insertable(T t); - /// - /// 分页查询 - /// - /// 查询条件 - /// 分页参数 - /// 分页结果 - Task> GetPageListAsync(Expression> where, PageQueryModel pageQuery); + IUpdateable Updateable(); + #endregion add - /// - /// 插入单条记录 - /// - /// 实体对象 - /// 是否成功 - Task InsertAsync(T entity); + #region update + int Update(T entity, bool ignoreNullColumns = false, object data = null); - /// - /// 批量插入记录 - /// - /// 实体列表 - /// 是否成功 - Task InsertRangeAsync(List entities); + /// + /// 只更新表达式的值 + /// + /// + /// + /// + int Update(T entity, Expression> expression, bool ignoreAllNull = false); - /// - /// 更新单条记录 - /// - /// 实体对象 - /// 是否成功 - Task UpdateAsync(T entity); + int Update(T entity, Expression> expression, Expression> where); - /// - /// 批量更新记录 - /// - /// 实体列表 - /// 是否成功 - Task UpdateRangeAsync(List entities); + int Update(Expression> columns, Expression> where); + Task UpdateAsync(Expression> columns, Expression> where); - /// - /// 根据Id删除记录(软删除) - /// - /// 主键Id - /// 是否成功 - Task DeleteByIdAsync(long id); + #endregion update - /// - /// 根据条件删除记录(软删除) - /// - /// 删除条件 - /// 是否成功 - Task DeleteByWhereAsync(Expression> where); + /// + /// 事务 同步 + /// + /// + /// + Task UseTranAsync(Func action); - /// - /// 根据条件获取记录数 - /// - /// 查询条件 - /// 记录数 - Task GetCountAsync(Expression> where); + /// + /// 事务 异步 + /// + /// + /// + Task UseTranAsync(Func> action); + + #region delete + IDeleteable Deleteable(); + int Delete(object id, string title = ""); + int DeleteTable(); + bool Truncate(); + + #endregion delete + + #region query + /// + /// 根据条件查询分页数据 + /// + /// + /// + /// + PageListModel GetPages(Expression> where, PageQueryModel parm); + + PageListModel GetPages(Expression> where, PageQueryModel parm, Expression> order, OrderByType orderEnum = OrderByType.Asc); + PageListModel GetPages(Expression> where, PageQueryModel parm, Expression> order, string orderByType); + + bool Any(Expression> expression); + + ISugarQueryable Queryable(); + List GetAll(bool useCache = false, int cacheSecond = 3600); + + List SqlQueryToList(string sql, object obj = null); + + /// + /// 根据主值查询单条数据 + /// + /// 主键值 + /// 泛型实体 + R GetById(object pkValue) where R : class; + + Task GetByExpression(Expression> expression) where R : class; + + Task> GetListByExpression(Expression> expression) where T2 : class; + + #endregion query + + #region Procedure + + DataTable UseStoredProcedureToDataTable(string procedureName, List parameters); + + (DataTable, List) UseStoredProcedureToTuple(string procedureName, List parameters); + + #endregion Procedure + } } diff --git a/QYZH.InteractiveMagazine.Repository/QYZH.InteractiveMagazine.Repository.csproj b/QYZH.InteractiveMagazine.Repository/QYZH.InteractiveMagazine.Repository.csproj index cf19d9f..8b2e7f8 100644 --- a/QYZH.InteractiveMagazine.Repository/QYZH.InteractiveMagazine.Repository.csproj +++ b/QYZH.InteractiveMagazine.Repository/QYZH.InteractiveMagazine.Repository.csproj @@ -2,12 +2,14 @@ + - + + diff --git a/QYZH.InteractiveMagazine.Repository/SqlSugarDbContext.cs b/QYZH.InteractiveMagazine.Repository/SqlSugarDbContext.cs deleted file mode 100644 index b88ddb3..0000000 --- a/QYZH.InteractiveMagazine.Repository/SqlSugarDbContext.cs +++ /dev/null @@ -1,99 +0,0 @@ -using Microsoft.Extensions.Configuration; -using QYZH.InteractiveMagazine.Models.Entity; -using SqlSugar; - -namespace QYZH.InteractiveMagazine.Repository; - -/// -/// SqlSugar 数据库上下文封装(静态类) -/// -public static class SqlSugarDbContext -{ - /// - /// SqlSugarClient 实例 - /// - private static SqlSugarClient? _db; - - /// - /// 配置对象 - /// - private static IConfiguration? _configuration; - - /// - /// 初始化数据库上下文(在应用启动时调用一次) - /// - /// 配置对象 - public static void Init(IConfiguration configuration) - { - _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); - } - - /// - /// 获取 SqlSugarClient 实例 - /// - /// SqlSugarClient 实例 - public static SqlSugarClient GetDb() - { - if (_configuration == null) - { - throw new InvalidOperationException("请先调用 SqlSugarDbContext.Init(configuration) 进行初始化"); - } - - if (_db == null) - { - lock (typeof(SqlSugarDbContext)) - { - if (_db == null) - { - var connectionString = _configuration.GetConnectionString("DefaultConnection"); - if (string.IsNullOrWhiteSpace(connectionString)) - { - throw new InvalidOperationException("未找到连接字符串 DefaultConnection"); - } - - _db = new SqlSugarClient(new ConnectionConfig - { - ConnectionString = connectionString, - DbType = DbType.MySql, - IsAutoCloseConnection = true, - InitKeyType = InitKeyType.Attribute - }, - db => - { - // 配置软删除全局过滤(继承 BaseEntity 的实体都有效) - db.QueryFilter.AddTableFilter(it => it.IsDeleted == false); - - // 开启日志打印 - db.Aop.OnLogExecuting = (sql, pars) => - { - Console.WriteLine($"[SQL执行] {DateTime.Now:yyyy-MM-dd HH:mm:ss}"); - Console.WriteLine($"[SQL语句] {sql}"); - Console.WriteLine($"[SQL参数] {string.Join(", ", pars.Select(p => $"{p.ParameterName}={p.Value}"))}"); - Console.WriteLine(new string('-', 50)); - }; - }); - } - } - } - - return _db; - } - - /// - /// 代码优先初始化(可选) - /// - /// 实体类型数组 - public static void InitializeCodeFirst(params Type[] entityTypes) - { - var db = GetDb(); - - // 创建数据库(如果不存在) - db.DbMaintenance.CreateDatabase(); - - // 初始化表结构 - if (entityTypes != null && entityTypes.Length > 0) - { - db.CodeFirst.InitTables(entityTypes); - } - } -} diff --git a/QYZH.InteractiveMagazine.Service/AdminAuthService.cs b/QYZH.InteractiveMagazine.Service/AdminAuthService.cs index 515bda5..655783f 100644 --- a/QYZH.InteractiveMagazine.Service/AdminAuthService.cs +++ b/QYZH.InteractiveMagazine.Service/AdminAuthService.cs @@ -6,31 +6,23 @@ using QYZH.InteractiveMagazine.Infrastructure.Cache; using QYZH.InteractiveMagazine.IService; using QYZH.InteractiveMagazine.IService.Dto; using QYZH.InteractiveMagazine.Models.Common; +using QYZH.InteractiveMagazine.Models.Dto; using QYZH.InteractiveMagazine.Models.Entity; using QYZH.InteractiveMagazine.Models.Settings; using QYZH.InteractiveMagazine.Repository; namespace QYZH.InteractiveMagazine.Service; -public class AdminAuthService : IAdminAuthService +public class AdminAuthService(BaseRepository adminUserRepository, IConfiguration configuration, ILogger logger) : BaseRepository, IAdminAuthService { - private readonly IAdminUserRepository _adminUserRepository; - private readonly IConfiguration _configuration; - private readonly ILogger _logger; private const string TokenKeyPrefix = "InteractiveMagazine:AdminAuth:Token"; private const string UserInfoKeyPrefix = "InteractiveMagazine:AdminAuth:UserInfo"; - public AdminAuthService(IAdminUserRepository adminUserRepository, IConfiguration configuration, ILogger logger) - { - _adminUserRepository = adminUserRepository; - _configuration = configuration; - _logger = logger; - } public async Task LoginAsync(AdminLoginInput input) { - _logger.LogInformation("管理员登录尝试,用户名: {UserName}", input.UserName); + logger.LogInformation("管理员登录尝试,用户名: {UserName}", input.UserName); if (string.IsNullOrWhiteSpace(input.UserName)) { @@ -42,22 +34,22 @@ public class AdminAuthService : IAdminAuthService throw new BusinessException("密码不能为空", 400); } - var adminUser = await _adminUserRepository.GetByUserNameAsync(input.UserName); + var adminUser = await adminUserRepository.GetFirstAsync(a => a.UserName == input.UserName); if (adminUser == null) { - _logger.LogWarning("管理员登录失败,用户名不存在: {UserName}", input.UserName); + logger.LogWarning("管理员登录失败,用户名不存在: {UserName}", input.UserName); throw new BusinessException("用户名或密码错误", 401); } if (!BCrypt.Net.BCrypt.Verify(input.Password, adminUser.PasswordHash)) { - _logger.LogWarning("管理员登录失败,密码错误: {UserName}", input.UserName); + logger.LogWarning("管理员登录失败,密码错误: {UserName}", input.UserName); throw new BusinessException("用户名或密码错误", 401); } if (adminUser.Status != "Active") { - _logger.LogWarning("管理员登录失败,账号已禁用: {UserName}", input.UserName); + logger.LogWarning("管理员登录失败,账号已禁用: {UserName}", input.UserName); throw new BusinessException("账号已被禁用,请联系系统管理员", 403); } @@ -67,7 +59,7 @@ public class AdminAuthService : IAdminAuthService await RedisHelper.StringSetAsync($"{TokenKeyPrefix}:{adminUser.Id}", token, TimeSpan.FromMinutes(jwtSettings.ExpiryMinutes)); - _logger.LogInformation("管理员登录成功,用户名: {UserName}, ID: {UserId}", input.UserName, adminUser.Id); + logger.LogInformation("管理员登录成功,用户名: {UserName}, ID: {UserId}", input.UserName, adminUser.Id); return new AdminLoginOutput { @@ -80,21 +72,21 @@ public class AdminAuthService : IAdminAuthService public async Task LogoutAsync(long userId) { - _logger.LogInformation("管理员登出,ID: {UserId}", userId); + logger.LogInformation("管理员登出,ID: {UserId}", userId); await RedisHelper.KeyDeleteAsync($"{TokenKeyPrefix}:{userId}"); - _logger.LogInformation("管理员登出成功,ID: {UserId}", userId); + logger.LogInformation("管理员登出成功,ID: {UserId}", userId); } public async Task GetAdminInfoAsync(long userId) { - _logger.LogInformation("获取管理员信息,ID: {UserId}", userId); + logger.LogInformation("获取管理员信息,ID: {UserId}", userId); - var adminUser = await _adminUserRepository.GetByIdAsync(userId); + var adminUser = await adminUserRepository.GetByIdAsync(userId); if (adminUser == null) { - _logger.LogWarning("未找到管理员,ID: {UserId}", userId); + logger.LogWarning("未找到管理员,ID: {UserId}", userId); throw new BusinessException("用户不存在", 404); } @@ -109,7 +101,7 @@ public class AdminAuthService : IAdminAuthService public async Task ChangePasswordAsync(long userId, string oldPassword, string newPassword) { - _logger.LogInformation("管理员修改密码尝试,ID: {UserId}", userId); + logger.LogInformation("管理员修改密码尝试,ID: {UserId}", userId); if (string.IsNullOrWhiteSpace(oldPassword)) { @@ -121,22 +113,22 @@ public class AdminAuthService : IAdminAuthService throw new BusinessException("新密码不能为空", 400); } - var adminUser = await _adminUserRepository.GetByIdAsync(userId); + var adminUser = await adminUserRepository.GetByIdAsync(userId); if (adminUser == null) { - _logger.LogWarning("未找到管理员,ID: {UserId}", userId); + logger.LogWarning("未找到管理员,ID: {UserId}", userId); throw new BusinessException("用户不存在", 404); } if (!BCrypt.Net.BCrypt.Verify(oldPassword, adminUser.PasswordHash)) { - _logger.LogWarning("管理员修改密码失败,原密码错误,ID: {UserId}", userId); + logger.LogWarning("管理员修改密码失败,原密码错误,ID: {UserId}", userId); throw new BusinessException("原密码错误", 400); } adminUser.PasswordHash = BCrypt.Net.BCrypt.HashPassword(newPassword); - var result = await _adminUserRepository.UpdateAsync(adminUser); + var result = await adminUserRepository.UpdateAsync(adminUser); if (!result) { throw new BusinessException("修改密码失败", 500); @@ -144,12 +136,12 @@ public class AdminAuthService : IAdminAuthService await RedisHelper.KeyDeleteAsync($"{TokenKeyPrefix}:{userId}"); - _logger.LogInformation("管理员修改密码成功,ID: {UserId}", userId); + logger.LogInformation("管理员修改密码成功,ID: {UserId}", userId); } private JwtSettings GetJwtSettings() { - var jwtSettings = _configuration.GetSection("JwtSettings").Get() + var jwtSettings = configuration.GetSection("JwtSettings").Get() ?? new JwtSettings { Issuer = "QYZH.InteractiveMagazine", diff --git a/QYZH.InteractiveMagazine.Service/AdminUserService.cs b/QYZH.InteractiveMagazine.Service/AdminUserService.cs index a1dd6d6..027ea62 100644 --- a/QYZH.InteractiveMagazine.Service/AdminUserService.cs +++ b/QYZH.InteractiveMagazine.Service/AdminUserService.cs @@ -7,29 +7,22 @@ using QYZH.InteractiveMagazine.Models.Common; using QYZH.InteractiveMagazine.Models.Dto; using QYZH.InteractiveMagazine.Models.Entity; using QYZH.InteractiveMagazine.Repository; +using SqlSugar; namespace QYZH.InteractiveMagazine.Service; /// /// 管理员用户服务实现 /// -public class AdminUserService : IAdminUserService +public class AdminUserService(BaseRepository adminUserRepository, ILogger logger) : BaseRepository, IAdminUserService { - private readonly IAdminUserRepository _adminUserRepository; - private readonly ILogger _logger; - - public AdminUserService(IAdminUserRepository adminUserRepository, ILogger logger) - { - _adminUserRepository = adminUserRepository; - _logger = logger; - } /// /// 创建管理员 /// public async Task CreateAsync(AdminUserInput input) { - _logger.LogInformation("正在创建管理员,用户名: {UserName}", input.UserName); + logger.LogInformation("正在创建管理员,用户名: {UserName}", input.UserName); if (string.IsNullOrWhiteSpace(input.UserName)) { @@ -42,10 +35,10 @@ public class AdminUserService : IAdminUserService } // 检查用户名是否已存在 - var existingUser = await _adminUserRepository.GetByUserNameAsync(input.UserName); + var existingUser = await adminUserRepository.GetFirstAsync(a => a.UserName == input.UserName); if (existingUser != null) { - _logger.LogWarning("创建管理员失败,用户名已存在: {UserName}", input.UserName); + logger.LogWarning("创建管理员失败,用户名已存在: {UserName}", input.UserName); throw new BusinessException("用户名已存在", 400); } @@ -62,14 +55,14 @@ public class AdminUserService : IAdminUserService IsDeleted = false }; - var result = await _adminUserRepository.InsertAsync(adminUser); + var result = await adminUserRepository.InsertAsync(adminUser); if (!result) { - _logger.LogError("管理员创建失败,用户名: {UserName}", input.UserName); + logger.LogError("管理员创建失败,用户名: {UserName}", input.UserName); throw new BusinessException("创建管理员失败", 500); } - _logger.LogInformation("管理员创建成功,用户名: {UserName}, ID: {Id}", input.UserName, adminUser.Id); + logger.LogInformation("管理员创建成功,用户名: {UserName}, ID: {Id}", input.UserName, adminUser.Id); return MapToOutput(adminUser); } @@ -79,22 +72,22 @@ public class AdminUserService : IAdminUserService /// public async Task UpdateAsync(long id, AdminUserInput input) { - _logger.LogInformation("正在更新管理员,ID: {Id}", id); + logger.LogInformation("正在更新管理员,ID: {Id}", id); - var adminUser = await _adminUserRepository.GetByIdAsync(id); + var adminUser = await adminUserRepository.GetByIdAsync(id); if (adminUser == null) { - _logger.LogWarning("未找到要更新的管理员,ID: {Id}", id); + logger.LogWarning("未找到要更新的管理员,ID: {Id}", id); throw new BusinessException("管理员不存在", 404); } // 如果用户名有变更,检查是否与其他用户重复 if (!string.IsNullOrWhiteSpace(input.UserName) && input.UserName != adminUser.UserName) { - var existingUser = await _adminUserRepository.GetByUserNameAsync(input.UserName.Trim()); + var existingUser = await adminUserRepository.GetFirstAsync(a => a.UserName == input.UserName.Trim()); if (existingUser != null && existingUser.Id != id) { - _logger.LogWarning("更新管理员失败,用户名已存在: {UserName}", input.UserName); + logger.LogWarning("更新管理员失败,用户名已存在: {UserName}", input.UserName); throw new BusinessException("用户名已存在", 400); } @@ -120,14 +113,14 @@ public class AdminUserService : IAdminUserService adminUser.UpdatedBy = "System"; adminUser.UpdatedAt = DateTime.Now; - var result = await _adminUserRepository.UpdateAsync(adminUser); + var result = await adminUserRepository.UpdateAsync(adminUser); if (!result) { - _logger.LogError("管理员更新失败,ID: {Id}", id); + logger.LogError("管理员更新失败,ID: {Id}", id); throw new BusinessException("更新管理员失败", 500); } - _logger.LogInformation("管理员更新成功,ID: {Id}", id); + logger.LogInformation("管理员更新成功,ID: {Id}", id); return MapToOutput(adminUser); } @@ -137,23 +130,23 @@ public class AdminUserService : IAdminUserService /// public async Task DeleteAsync(long id) { - _logger.LogInformation("正在删除管理员,ID: {Id}", id); + logger.LogInformation("正在删除管理员,ID: {Id}", id); - var adminUser = await _adminUserRepository.GetByIdAsync(id); + var adminUser = await adminUserRepository.GetByIdAsync(id); if (adminUser == null) { - _logger.LogWarning("未找到要删除的管理员,ID: {Id}", id); + logger.LogWarning("未找到要删除的管理员,ID: {Id}", id); throw new BusinessException("管理员不存在", 404); } - var result = await _adminUserRepository.DeleteByIdAsync(id); + var result = await adminUserRepository.DeleteByIdAsync(id); if (!result) { - _logger.LogError("管理员删除失败,ID: {Id}", id); + logger.LogError("管理员删除失败,ID: {Id}", id); throw new BusinessException("删除管理员失败", 500); } - _logger.LogInformation("管理员删除成功,ID: {Id}", id); + logger.LogInformation("管理员删除成功,ID: {Id}", id); } /// @@ -161,12 +154,12 @@ public class AdminUserService : IAdminUserService /// public async Task GetByIdAsync(long id) { - _logger.LogInformation("正在获取管理员信息,ID: {Id}", id); + logger.LogInformation("正在获取管理员信息,ID: {Id}", id); - var adminUser = await _adminUserRepository.GetByIdAsync(id); + var adminUser = await adminUserRepository.GetByIdAsync(id); if (adminUser == null) { - _logger.LogWarning("未找到管理员,ID: {Id}", id); + logger.LogWarning("未找到管理员,ID: {Id}", id); throw new BusinessException("管理员不存在", 404); } @@ -178,7 +171,7 @@ public class AdminUserService : IAdminUserService /// public async Task> GetListAsync(AdminUserQueryInput input) { - _logger.LogInformation("正在查询管理员列表,页码: {PageIndex}, 每页条数: {PageSize}", input.PageIndex, input.PageSize); + logger.LogInformation("正在查询管理员列表,页码: {PageIndex}, 每页条数: {PageSize}", input.PageIndex, input.PageSize); if (input.PageIndex <= 0) { @@ -189,62 +182,13 @@ public class AdminUserService : IAdminUserService { throw new BusinessException("每页条数必须在1-100之间", 400); } - - var pageResult = await _adminUserRepository.GetPageListAsync( - BuildQueryExpression(input), - input - ); - - // 转换为输出DTO - var outputList = pageResult.List?.Select(MapToOutput).ToList() ?? new List(); - - return new PageListModel - { - List = outputList, - TotalCount = pageResult.TotalCount, - PageIndex = pageResult.PageIndex, - PageSize = pageResult.PageSize - }; - } - - /// - /// 构建查询表达式 - /// - private static Expression> BuildQueryExpression(AdminUserQueryInput input) - { - Expression> where = x => !x.IsDeleted; - - if (!string.IsNullOrWhiteSpace(input.UserName)) - { - var userName = input.UserName; - Expression> userNameCondition = x => x.UserName.Contains(userName); - where = Expression.Lambda>( - Expression.AndAlso(where.Body, - Expression.Invoke(userNameCondition, where.Parameters[0])), - where.Parameters); - } - - if (!string.IsNullOrWhiteSpace(input.Type)) - { - var type = input.Type; - Expression> typeCondition = x => x.Type == type; - where = Expression.Lambda>( - Expression.AndAlso(where.Body, - Expression.Invoke(typeCondition, where.Parameters[0])), - where.Parameters); - } - - if (!string.IsNullOrWhiteSpace(input.Status)) - { - var status = input.Status; - Expression> statusCondition = x => x.Status == status; - where = Expression.Lambda>( - Expression.AndAlso(where.Body, - Expression.Invoke(statusCondition, where.Parameters[0])), - where.Parameters); - } - - return where; + RefAsync totalNumber = 0; + var pageResult = await adminUserRepository.Queryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.UserName), a => a.UserName == input.UserName) + .OrderByDescending(a => a.CreatedAt) + .Select(a => MapToOutput(a), true) + .ToPageListAsync(input.PageIndex, input.PageSize, totalNumber); + return new PageListModel(pageResult, input.PageIndex, input.PageSize, totalNumber); } /// diff --git a/QYZH.InteractiveMagazine.Service/BaseService.cs b/QYZH.InteractiveMagazine.Service/BaseService.cs deleted file mode 100644 index a94d2d5..0000000 --- a/QYZH.InteractiveMagazine.Service/BaseService.cs +++ /dev/null @@ -1,201 +0,0 @@ -using Microsoft.Extensions.Logging; -using QYZH.InteractiveMagazine.IService; -using QYZH.InteractiveMagazine.Models.Common; -using QYZH.InteractiveMagazine.Models.Dto; -using QYZH.InteractiveMagazine.Models.Entity; -using QYZH.InteractiveMagazine.Repository; - -namespace QYZH.InteractiveMagazine.Service; - -/// -/// 基础服务实现 -/// -/// 实体类型 -public class BaseService : IBaseService where T : class, new() -{ - protected readonly IBaseRepository _repository; - protected readonly ILogger> _logger; - - /// - /// 构造函数 - /// - /// 基础仓储 - /// 日志记录器 - public BaseService(IBaseRepository repository, ILogger> logger) - { - _repository = repository; - _logger = logger; - } - - /// - /// 根据ID获取实体 - /// - /// 实体ID - /// 实体对象 - public async Task GetByIdAsync(long id) - { - _logger.LogInformation("正在获取实体,ID: {Id}", id); - - var entity = await _repository.GetByIdAsync(id); - - if (entity == null) - { - _logger.LogWarning("未找到实体,ID: {Id}", id); - throw new BusinessException($"未找到ID为{id}的记录", 404); - } - - return entity; - } - - /// - /// 获取所有实体列表 - /// - /// 实体列表 - public async Task> GetListAsync() - { - _logger.LogInformation("正在获取所有实体列表"); - return await _repository.GetListAsync(); - } - - /// - /// 获取分页列表 - /// - /// 分页查询参数 - /// 分页数据 - public async Task> GetPageListAsync(PageQueryModel pageQuery) - { - _logger.LogInformation("正在获取分页列表,页码: {PageIndex}, 每页条数: {PageSize}", pageQuery.PageIndex, pageQuery.PageSize); - - if (pageQuery.PageIndex <= 0) - { - throw new BusinessException("页码必须大于0", 400); - } - - if (pageQuery.PageSize <= 0 || pageQuery.PageSize > 100) - { - throw new BusinessException("每页条数必须在1-100之间", 400); - } - - return await _repository.GetPageListAsync(x => true, pageQuery); - } - - /// - /// 新增实体 - /// - /// 实体对象 - /// 是否成功 - public async Task InsertAsync(T entity) - { - if (entity == null) - { - throw new BusinessException("实体对象不能为空", 400); - } - - _logger.LogInformation("正在新增实体,类型: {EntityType}", typeof(T).Name); - - SetAuditFieldsOnInsert(entity); - - var result = await _repository.InsertAsync(entity); - - if (result) - { - _logger.LogInformation("实体新增成功"); - } - else - { - _logger.LogError("实体新增失败"); - throw new BusinessException("新增记录失败", 500); - } - - return result; - } - - /// - /// 更新实体 - /// - /// 实体对象 - /// 是否成功 - public async Task UpdateAsync(T entity) - { - if (entity == null) - { - throw new BusinessException("实体对象不能为空", 400); - } - - _logger.LogInformation("正在更新实体,类型: {EntityType}", typeof(T).Name); - - SetAuditFieldsOnUpdate(entity); - - var result = await _repository.UpdateAsync(entity); - - if (result) - { - _logger.LogInformation("实体更新成功"); - } - else - { - _logger.LogError("实体更新失败"); - throw new BusinessException("更新记录失败", 500); - } - - return result; - } - - /// - /// 根据ID删除实体 - /// - /// 实体ID - /// 是否成功 - public async Task DeleteByIdAsync(long id) - { - _logger.LogInformation("正在删除实体,ID: {Id}", id); - - var entity = await _repository.GetByIdAsync(id); - - if (entity == null) - { - _logger.LogWarning("未找到要删除的实体,ID: {Id}", id); - throw new BusinessException($"未找到ID为{id}的记录", 404); - } - - var result = await _repository.DeleteByIdAsync(id); - - if (result) - { - _logger.LogInformation("实体删除成功,ID: {Id}", id); - } - else - { - _logger.LogError("实体删除失败,ID: {Id}", id); - throw new BusinessException("删除记录失败", 500); - } - - return result; - } - - /// - /// 设置插入时的审计字段 - /// - /// 实体对象 - private static void SetAuditFieldsOnInsert(T entity) - { - if (entity is BaseEntity baseEntity) - { - var now = DateTime.Now; - baseEntity.CreatedAt = now; - baseEntity.UpdatedAt = now; - baseEntity.CreatedBy = baseEntity.CreatedBy ?? "system"; - baseEntity.UpdatedBy = baseEntity.UpdatedBy ?? "system"; - baseEntity.IsDeleted = false; - } - } - - private static void SetAuditFieldsOnUpdate(T entity) - { - if (entity is BaseEntity baseEntity) - { - baseEntity.UpdatedAt = DateTime.Now; - baseEntity.UpdatedBy = baseEntity.UpdatedBy ?? "system"; - } - } -} diff --git a/QYZH.InteractiveMagazine.Service/WxUserService.cs b/QYZH.InteractiveMagazine.Service/WxUserService.cs new file mode 100644 index 0000000..826de96 --- /dev/null +++ b/QYZH.InteractiveMagazine.Service/WxUserService.cs @@ -0,0 +1,191 @@ +using Microsoft.Extensions.Logging; +using QYZH.InteractiveMagazine.IService; +using QYZH.InteractiveMagazine.IService.Dto; +using QYZH.InteractiveMagazine.Models.Common; +using QYZH.InteractiveMagazine.Models.Dto; +using QYZH.InteractiveMagazine.Models.Entity; +using QYZH.InteractiveMagazine.Repository; +using SqlSugar; +using System.Linq.Expressions; + +namespace QYZH.InteractiveMagazine.Service; + +public class WxUserService(BaseRepository wxUserRepository, ILogger _logger) : BaseRepository, IWxUserService +{ + + public async Task CreateAsync(WxUserInput input) + { + _logger.LogInformation("正在创建微信用户,OpenId: {OpenId}", input.OpenId); + + if (string.IsNullOrWhiteSpace(input.OpenId)) + { + throw new BusinessException("OpenId不能为空", 400); + } + + var existingUser = await wxUserRepository.GetFirstAsync(a => a.OpenId == input.OpenId); + if (existingUser != null) + { + _logger.LogWarning("创建微信用户失败,OpenId已存在: {OpenId}", input.OpenId); + throw new BusinessException("OpenId已存在", 400); + } + + var wxUser = new WxUser + { + + OpenId = input.OpenId.Trim(), + UnionId = input.UnionId, + NickName = input.NickName, + AvatarUrl = input.AvatarUrl, + Phone = input.Phone, + Points = input.Points, + Type = input.Type, + Status = input.Status, + Pwd = input.Pwd ?? string.Empty, + GrowthPoints = input.GrowthPoints, + CreatedBy = "System", + UpdatedBy = "System", + CreatedAt = DateTime.Now, + UpdatedAt = DateTime.Now, + IsDeleted = false + }; + + var result = await wxUserRepository.InsertAsync(wxUser); + if (!result) + { + _logger.LogError("微信用户创建失败,OpenId: {OpenId}", input.OpenId); + throw new BusinessException("创建微信用户失败", 500); + } + + _logger.LogInformation("微信用户创建成功,OpenId: {OpenId}, ID: {Id}", input.OpenId, wxUser.Id); + + return MapToOutput(wxUser); + } + + public async Task UpdateAsync(long id, WxUserInput input) + { + _logger.LogInformation("正在更新微信用户,ID: {Id}", id); + + var wxUser = await wxUserRepository.GetByIdAsync(id); + if (wxUser == null) + { + _logger.LogWarning("未找到要更新的微信用户,ID: {Id}", id); + throw new BusinessException("微信用户不存在", 404); + } + + if (!string.IsNullOrWhiteSpace(input.OpenId) && input.OpenId != wxUser.OpenId) + { + var existingUser = await wxUserRepository.GetFirstAsync(a => a.OpenId == input.OpenId.Trim()); + if (existingUser != null && existingUser.Id != id) + { + _logger.LogWarning("更新微信用户失败,OpenId已存在: {OpenId}", input.OpenId); + throw new BusinessException("OpenId已存在", 400); + } + + wxUser.OpenId = input.OpenId.Trim(); + } + + wxUser.UnionId = input.UnionId ?? wxUser.UnionId; + wxUser.NickName = input.NickName ?? wxUser.NickName; + wxUser.AvatarUrl = input.AvatarUrl ?? wxUser.AvatarUrl; + wxUser.Phone = input.Phone ?? wxUser.Phone; + wxUser.Points = input.Points; + wxUser.Type = input.Type ?? wxUser.Type; + wxUser.Status = input.Status ?? wxUser.Status; + wxUser.Pwd = input.Pwd ?? wxUser.Pwd; + wxUser.GrowthPoints = input.GrowthPoints; + + wxUser.UpdatedBy = "System"; + wxUser.UpdatedAt = DateTime.Now; + + var result = await wxUserRepository.UpdateAsync(wxUser); + if (!result) + { + _logger.LogError("微信用户更新失败,ID: {Id}", id); + throw new BusinessException("更新微信用户失败", 500); + } + + _logger.LogInformation("微信用户更新成功,ID: {Id}", id); + + return MapToOutput(wxUser); + } + + public async Task DeleteAsync(long id) + { + _logger.LogInformation("正在删除微信用户,ID: {Id}", id); + + var wxUser = await wxUserRepository.GetByIdAsync(id); + if (wxUser == null) + { + _logger.LogWarning("未找到要删除的微信用户,ID: {Id}", id); + throw new BusinessException("微信用户不存在", 404); + } + + var result = await wxUserRepository.DeleteByIdAsync(id); + if (!result) + { + _logger.LogError("微信用户删除失败,ID: {Id}", id); + throw new BusinessException("删除微信用户失败", 500); + } + + _logger.LogInformation("微信用户删除成功,ID: {Id}", id); + } + + public async Task GetByIdAsync(long id) + { + _logger.LogInformation("正在获取微信用户信息,ID: {Id}", id); + + var wxUser = await wxUserRepository.GetByIdAsync(id); + if (wxUser == null) + { + _logger.LogWarning("未找到微信用户,ID: {Id}", id); + throw new BusinessException("微信用户不存在", 404); + } + + return MapToOutput(wxUser); + } + + public async Task> GetListAsync(WxUserQueryInput input) + { + _logger.LogInformation("正在查询微信用户列表,页码: {PageIndex}, 每页条数: {PageSize}", input.PageIndex, input.PageSize); + + if (input.PageIndex <= 0) + { + throw new BusinessException("页码必须大于0", 400); + } + + if (input.PageSize <= 0 || input.PageSize > 100) + { + throw new BusinessException("每页条数必须在1-100之间", 400); + } + RefAsync totalNumber = 0; + + var pageResult = await wxUserRepository.Queryable() + .WhereIF(!string.IsNullOrWhiteSpace(input.NickName), a => a.NickName == input.NickName) + .OrderByDescending(a => a.CreatedAt) + .Select(a => MapToOutput(a), true) + .ToPageListAsync(input.PageIndex, input.PageSize, totalNumber); + + return new PageListModel(pageResult, input.PageIndex, input.PageSize, totalNumber); + } + + private static WxUserOutput MapToOutput(WxUser wxUser) + { + return new WxUserOutput + { + Id = wxUser.Id, + OpenId = wxUser.OpenId, + UnionId = wxUser.UnionId, + NickName = wxUser.NickName, + AvatarUrl = wxUser.AvatarUrl, + Phone = wxUser.Phone, + Points = wxUser.Points, + Type = wxUser.Type, + Status = wxUser.Status, + GrowthPoints = wxUser.GrowthPoints, + CreatedBy = wxUser.CreatedBy, + CreatedAt = wxUser.CreatedAt, + UpdatedBy = wxUser.UpdatedBy, + UpdatedAt = wxUser.UpdatedAt + }; + } +} diff --git a/QYZH.InteractiveMagazine.WebApi/Controllers/AdminController.cs b/QYZH.InteractiveMagazine.WebApi/Controllers/AdminController.cs index f2e9623..85cb6bf 100644 --- a/QYZH.InteractiveMagazine.WebApi/Controllers/AdminController.cs +++ b/QYZH.InteractiveMagazine.WebApi/Controllers/AdminController.cs @@ -23,6 +23,11 @@ public class AdminController : BaseController _logger = logger; } + /// + /// 登录 + /// + /// 登录输入 + /// 登录结果 [AllowAnonymous] [HttpPost("login")] public async Task> LoginAsync([FromBody] AdminLoginInput input) @@ -31,6 +36,10 @@ public class AdminController : BaseController return Success(result); } + /// + /// 登出 + /// + /// 登出结果 [HttpPost("logout")] public async Task> LogoutAsync() { @@ -44,6 +53,10 @@ public class AdminController : BaseController return Success(new object(), "登出成功"); } + /// + /// 获取管理员信息 + /// + /// 管理员信息 [HttpGet("info")] public async Task> GetAdminInfoAsync() { @@ -57,6 +70,11 @@ public class AdminController : BaseController return Success(result); } + /// + /// 修改密码 + /// + /// 修改密码输入 + /// 修改密码结果 [HttpPost("changePassword")] public async Task> ChangePasswordAsync([FromBody] ChangePasswordInput input) { diff --git a/QYZH.InteractiveMagazine.WebApi/Controllers/WxUserController.cs b/QYZH.InteractiveMagazine.WebApi/Controllers/WxUserController.cs new file mode 100644 index 0000000..539e81b --- /dev/null +++ b/QYZH.InteractiveMagazine.WebApi/Controllers/WxUserController.cs @@ -0,0 +1,121 @@ +using Microsoft.AspNetCore.Mvc; +using QYZH.InteractiveMagazine.IService; +using QYZH.InteractiveMagazine.IService.Dto; +using QYZH.InteractiveMagazine.Models.Common; +using QYZH.InteractiveMagazine.Models.Dto; + +namespace QYZH.InteractiveMagazine.WebApi.Controllers; + +[Route("api/[controller]")] +[ApiController] +public class WxUserController : BaseController +{ + private readonly IWxUserService _wxUserService; + private readonly ILogger _logger; + + public WxUserController(IWxUserService wxUserService, ILogger logger) + { + _wxUserService = wxUserService; + _logger = logger; + } + + [HttpPost("users")] + public async Task> CreateUserAsync([FromBody] WxUserInput input) + { + try + { + var result = await _wxUserService.CreateAsync(input); + return Success(result, "创建微信用户成功"); + } + catch (BusinessException ex) + { + _logger.LogWarning(ex, "创建微信用户业务异常: {Message}", ex.Message); + return BaseResponse.Fail(ex.Message, ex.Code); + } + catch (Exception ex) + { + _logger.LogError(ex, "创建微信用户系统异常,参数:{Input}", input); + return BaseResponse.Fail("创建微信用户失败,请稍后重试", 500); + } + } + + [HttpPut("users/{id}")] + public async Task> UpdateUserAsync(long id, [FromBody] WxUserInput input) + { + try + { + var result = await _wxUserService.UpdateAsync(id, input); + return Success(result, "更新微信用户成功"); + } + catch (BusinessException ex) + { + _logger.LogWarning(ex, "更新微信用户业务异常: {Message}", ex.Message); + return BaseResponse.Fail(ex.Message, ex.Code); + } + catch (Exception ex) + { + _logger.LogError(ex, "更新微信用户系统异常,ID:{Id},参数:{Input}", id, input); + return BaseResponse.Fail("更新微信用户失败,请稍后重试", 500); + } + } + + [HttpDelete("users/{id}")] + public async Task> DeleteUserAsync(long id) + { + try + { + await _wxUserService.DeleteAsync(id); + return Success(new object(), "删除微信用户成功"); + } + catch (BusinessException ex) + { + _logger.LogWarning(ex, "删除微信用户业务异常: {Message}", ex.Message); + return BaseResponse.Fail(ex.Message, ex.Code); + } + catch (Exception ex) + { + _logger.LogError(ex, "删除微信用户系统异常,ID:{Id}", id); + return BaseResponse.Fail("删除微信用户失败,请稍后重试", 500); + } + } + + [HttpGet("users/{id}")] + public async Task> GetUserByIdAsync(long id) + { + try + { + var result = await _wxUserService.GetByIdAsync(id); + return Success(result); + } + catch (BusinessException ex) + { + _logger.LogWarning(ex, "获取微信用户业务异常: {Message}", ex.Message); + return BaseResponse.Fail(ex.Message, ex.Code); + } + catch (Exception ex) + { + _logger.LogError(ex, "获取微信用户系统异常,ID:{Id}", id); + return BaseResponse.Fail("获取微信用户信息失败,请稍后重试", 500); + } + } + + [HttpPost("users/list")] + public async Task>> GetUsersListAsync([FromBody] WxUserQueryInput input) + { + try + { + var result = await _wxUserService.GetListAsync(input); + return Success(result); + } + catch (BusinessException ex) + { + _logger.LogWarning(ex, "查询微信用户列表业务异常: {Message}", ex.Message); + return BaseResponse>.Fail(ex.Message, ex.Code); + } + catch (Exception ex) + { + _logger.LogError(ex, "查询微信用户列表系统异常,参数:{Input}", input); + return BaseResponse>.Fail("查询微信用户列表失败,请稍后重试", 500); + } + } +} diff --git a/QYZH.InteractiveMagazine.WebApi/Program.cs b/QYZH.InteractiveMagazine.WebApi/Program.cs index 05f178b..f93ab28 100644 --- a/QYZH.InteractiveMagazine.WebApi/Program.cs +++ b/QYZH.InteractiveMagazine.WebApi/Program.cs @@ -4,21 +4,38 @@ using BCrypt.Net; using Microsoft.AspNetCore.Mvc; using Microsoft.OpenApi; using QYZH.InteractiveMagazine.Common.Extensions; +using QYZH.InteractiveMagazine.Common.Helpers; +using QYZH.InteractiveMagazine.Infrastructure.Autofacs; +using QYZH.InteractiveMagazine.Infrastructure.Context; using QYZH.InteractiveMagazine.Infrastructure.Extensions; using QYZH.InteractiveMagazine.Infrastructure.Middleware; using QYZH.InteractiveMagazine.Models.Entity; using QYZH.InteractiveMagazine.Models.Enum; using QYZH.InteractiveMagazine.Repository; +using QYZH.InteractiveMagazine.Repository.Core; using Serilog; +using SqlSugar.IOC; using Swashbuckle.AspNetCore.SwaggerGen; using Swashbuckle.AspNetCore.SwaggerUI; -using QYZH.InteractiveMagazine.Infrastructure.Autofacs; +using System.Text.Json.Serialization; +using Yitter.IdGenerator; var builder = WebApplication.CreateBuilder(args); +// 初始化雪花ID生成器 +YitIdHelper.SetIdGenerator(new IdGeneratorOptions() { WorkerId = 1 }); // autofac注入 允许使用autofac作为DI容器 builder.UseAutofac(); +builder.InitSqlSugarDb(new IocConfig() +{ + ConfigId = 0, + DbType = IocDbType.MySql, + ConnectionString = builder.Configuration.GetConnectionString("DefaultConnection"), + IsAutoCloseConnection = true, +}); + + // 配置Serilog Log.Logger = new LoggerConfiguration() .ReadFrom.Configuration(builder.Configuration) @@ -26,13 +43,22 @@ Log.Logger = new LoggerConfiguration() .CreateLogger(); builder.Host.UseSerilog(); - -builder.Services.AddControllers(); +builder.Services.AddControllers(options => +{ + options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true;//Required 不作为必填 +}) +.AddJsonOptions(options => +{ + // 配置返回时间格式转换 + options.JsonSerializerOptions.Converters.Add(new JsonConverterUtil.DateTimeConverter()); + options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles; +}).ConfigureApiBehaviorOptions(opt => opt.SuppressModelStateInvalidFilter = true);//关闭默认模型验证 builder.Services.AddEndpointsApiExplorer(); // 跨域配置 builder.AddCorsRegister(); - +//builder.Services.AddSession(); +builder.Services.AddHttpClient(); // 注册 Swagger 文档 builder.Services.AddSwaggerGen(option => { @@ -88,10 +114,9 @@ builder.Services.AddSwaggerGen(option => builder.Services.AddInfrastructureServices(builder.Configuration); - -// 初始化SqlSugar -SqlSugarDbContext.Init(builder.Configuration); - +//注册 HttpContextAccessor +builder.Services.AddHttpContextAccessor(); +builder.Services.AddScoped(typeof(BaseRepository<>)); // 添加CORS builder.Services.AddCors(options => @@ -118,7 +143,7 @@ var app = builder.Build(); c.DocExpansion(DocExpansion.None); // ->修改界面打开时自动折叠 }); } - +app.UseServiceContext(); app.UseHttpsRedirection(); app.UseCors("AllowAll"); app.UseMiddleware();