refactor: 重构项目基础架构与实体体系

- 替换原有自定义生命周期接口为通用基础服务体系
- 将所有实体基类替换为带雪花ID的SqlSugarBaseEntity
- 迁移DTO到Models项目并统一管理
- 移除冗余的Repository层实现,改用通用基础服务
- 添加Yitter.IdGenerator雪花ID生成支持
- 重构SqlSugar数据库上下文与依赖注入配置
- 新增微信用户、用户勋章、背包等实体与配套服务
- 整理分页查询与结果封装类
- 优化WebApi控制器结构
This commit is contained in:
glz
2026-06-02 14:10:43 +08:00
parent 831f8ba7f5
commit 8ed012bba8
51 changed files with 1762 additions and 1141 deletions

View File

@ -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<DateTime?>
{
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<DateTime>
{
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;
}
}
}

View File

@ -1,93 +0,0 @@
namespace QYZH.InteractiveMagazine.IService.Dto;
/// <summary>
/// 登录输入
/// </summary>
public class LoginInput
{
/// <summary>
/// 账号
/// </summary>
public string Account { get; set; } = string.Empty;
/// <summary>
/// 密码
/// </summary>
public string Password { get; set; } = string.Empty;
}
/// <summary>
/// 注册输入
/// </summary>
public class RegisterInput
{
/// <summary>
/// 账号
/// </summary>
public string Account { get; set; } = string.Empty;
/// <summary>
/// 密码
/// </summary>
public string Password { get; set; } = string.Empty;
/// <summary>
/// 用户名
/// </summary>
public string UserName { get; set; } = string.Empty;
}
/// <summary>
/// 登录输出
/// </summary>
public class LoginOutput
{
/// <summary>
/// 访问令牌
/// </summary>
public string Token { get; set; } = string.Empty;
/// <summary>
/// 用户ID
/// </summary>
public long UserId { get; set; }
/// <summary>
/// 用户名
/// </summary>
public string UserName { get; set; } = string.Empty;
/// <summary>
/// 刷新令牌
/// </summary>
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;
}

View File

@ -1,38 +0,0 @@
namespace QYZH.InteractiveMagazine.IService.Dto;
/// <summary>
/// 微信登录输出
/// </summary>
public class WeChatLoginOutput
{
/// <summary>
/// 访问令牌
/// </summary>
public string Token { get; set; } = string.Empty;
/// <summary>
/// 用户ID
/// </summary>
public long UserId { get; set; }
/// <summary>
/// 用户名
/// </summary>
public string UserName { get; set; } = string.Empty;
/// <summary>
/// 微信OpenId
/// </summary>
public string OpenId { get; set; } = string.Empty;
}
/// <summary>
/// 微信手机号获取输出
/// </summary>
public class WeChatPhoneNumberOutput
{
/// <summary>
/// 手机号
/// </summary>
public string PhoneNumber { get; set; } = string.Empty;
}

View File

@ -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<AdminUser>
{
Task<AdminLoginOutput> LoginAsync(AdminLoginInput input);

View File

@ -1,12 +1,13 @@
using QYZH.InteractiveMagazine.IService.Dto;
using QYZH.InteractiveMagazine.Models.Dto;
using QYZH.InteractiveMagazine.Models.Entity;
namespace QYZH.InteractiveMagazine.IService;
/// <summary>
/// 管理员用户服务接口
/// </summary>
public interface IAdminUserService
public interface IAdminUserService : IBaseService<AdminUser>
{
/// <summary>
/// 创建管理员

View File

@ -1,51 +1,39 @@
using QYZH.InteractiveMagazine.Models.Dto;
using System.Linq.Expressions;
namespace QYZH.InteractiveMagazine.IService;
/// <summary>
/// 基础服务接口
/// 基础服务定义
/// </summary>
/// <typeparam name="T">实体类型</typeparam>
/// <typeparam name="T"></typeparam>
public interface IBaseService<T> where T : class, new()
{
/// <summary>
/// 根据ID获取实体
/// </summary>
/// <param name="id">实体ID</param>
/// <returns>实体对象</returns>
Task<T?> GetByIdAsync(long id);
Task<T> GetFirstAsync(Expression<Func<T, bool>> whereExpression);
/// <summary>
/// 获取所有实体列表
/// 根据条件表达式查询单条数据
/// </summary>
/// <returns>实体列表</returns>
Task<List<T>> GetListAsync();
/// <param name="expression">表达式</param>
/// <returns>泛型实体</returns>
Task<R> GetByIdAsync<R>(Expression<Func<T, bool>> expression) where R : class;
/// <summary>
/// 获取分页列表
/// </summary>
/// <param name="pageQuery">分页查询参数</param>
/// <returns>分页数据</returns>
Task<PageListModel<T>> GetPageListAsync(PageQueryModel pageQuery);
Task<R> GetByExpressionAsync<R>(Expression<Func<T, bool>> expression) where R : class;
/// <summary>
/// 新增实体
/// </summary>
/// <param name="entity">实体对象</param>
/// <returns>是否成功</returns>
Task<bool> InsertAsync(T entity);
Task<List<T2>> GetListByExpression<T2>(Expression<Func<T, bool>> expression) where T2 : class;
/// <summary>
/// 更新实体
/// </summary>
/// <param name="entity">实体对象</param>
/// <returns>是否成功</returns>
Task<bool> UpdateAsync(T entity);
Task<bool> UpdateAsync(T updateObj);
/// <summary>
/// 根据ID删除实体
/// </summary>
/// <param name="id">实体ID</param>
/// <returns>是否成功</returns>
Task<bool> DeleteByIdAsync(long id);
///// <summary>
///// 根据指定条件更新指定列 egUpdate(new SysUser(){ Status = 1 }, it => new { it.Status }, f => f.Userid == 1));
///// 只更新Status列条件是包含
///// </summary>
///// <param name="entity">实体类</param>
///// <param name="expression">要更新列的表达式</param>
///// <param name="where">where表达式</param>
///// <returns></returns>
//Task<bool> UpdateAsync(T entity, Expression<Func<T, object>> expression, Expression<Func<T, bool>> where);
Task<bool> UpdateAsync(Expression<Func<T, T>> columns, Expression<Func<T, bool>> whereExpression);
Task<bool> UpdateAsync(Expression<Func<T, bool>> columns, Expression<Func<T, bool>> where);
}

View File

@ -1,15 +0,0 @@
namespace QYZH.InteractiveMagazine.IService;
/// <summary>
/// 单例生命周期标记接口
/// </summary>
public interface ISingletonDependency
{
}
/// <summary>
/// 瞬时生命周期标记接口
/// </summary>
public interface ITransientDependency
{
}

View File

@ -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<WxUser>
{
/// <summary>
/// 创建微信用户
/// </summary>
Task<WxUserOutput> CreateAsync(WxUserInput input);
/// <summary>
/// 更新微信用户
/// </summary>
Task<WxUserOutput> UpdateAsync(long id, WxUserInput input);
/// <summary>
/// 删除微信用户(软删除)
/// </summary>
Task DeleteAsync(long id);
/// <summary>
/// 根据ID获取微信用户
/// </summary>
Task<WxUserOutput> GetByIdAsync(long id);
/// <summary>
/// 分页查询微信用户列表
/// </summary>
Task<PageListModel<WxUserOutput>> GetListAsync(WxUserQueryInput input);
}

View File

@ -17,17 +17,8 @@ namespace QYZH.InteractiveMagazine.Infrastructure.Autofacs
/// <param name="builder"></param>
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();
}
/// <summary>

View File

@ -0,0 +1,75 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
namespace QYZH.InteractiveMagazine.Infrastructure.Context
{
/// <summary>
/// 应用程序上下文
/// </summary>
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();
}
/// <summary>
/// 获取对象实例
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T GetService<T>()
{
return ServiceProvider.GetService<T>();
}
/// <summary>
/// 获取Scope对象实例
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T GetScopeService<T>()
{
var scope = ServiceProvider.CreateScope();
return scope.ServiceProvider.GetService<T>();
}
/// <summary>
/// 获取对象实例
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T GetRequiredService<T>()
{
return ServiceProvider.GetRequiredService<T>();
}
/// <summary>
/// 获取对象实例
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T GetOptionsMonitor<T>()
{
return ServiceProvider.GetService<IOptionsMonitor<T>>().CurrentValue;
}
/// <summary>
/// 获取对象实例
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T GetOptions<T>() where T : class, new()
{
return ServiceProvider.GetService<IOptions<T>>().Value;
}
}
}

View File

@ -1,6 +1,6 @@
using QYZH.InteractiveMagazine.Models.Dto;
namespace QYZH.InteractiveMagazine.IService.Dto;
namespace QYZH.InteractiveMagazine.Models.Dto;
/// <summary>
/// 管理员创建/更新输入

View File

@ -0,0 +1,40 @@
namespace QYZH.InteractiveMagazine.Models.Dto;
/// <summary>
/// 管理员登录输入
/// </summary>
public class AdminLoginInput
{
/// <summary>
/// 用户名
/// </summary>
public string UserName { get; set; } = string.Empty;
/// <summary>
/// 密码
/// </summary>
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;
}

View File

@ -1,33 +1,73 @@
namespace QYZH.InteractiveMagazine.Models.Dto;
/// <summary>
/// 分页输出
/// 通用分页信息类
/// </summary>
/// <typeparam name="T">数据类型</typeparam>
public class PageListModel<T>
{
/// <summary>
/// 页码
/// 每页行数
/// </summary>
public int PageIndex { get; set; }
public int PageSize { get; set; } = 10;
/// <summary>
/// 每页条数
/// 当前页
/// </summary>
public int PageSize { get; set; }
public int PageIndex { get; set; } = 1;
/// <summary>
/// 总记录数
/// </summary>
public long TotalCount { get; set; }
public int TotalNum { get; set; }
/// <summary>
/// 总页数
/// </summary>
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<T> Result { get; set; }
/// <summary>
/// 数据列表
/// 额外数据
/// </summary>
public List<T>? List { get; set; }
public Dictionary<string, object> Extra { get; set; } = new Dictionary<string, object>();
/// <summary>
/// 是否有上一页
/// </summary>
public bool HasPrev
{
get
{
return PageIndex > 1;
}
}
/// <summary>
/// 下一页是否可用
/// </summary>
public bool HasNext
{
get
{
return TotalPage > PageIndex;
}
}
public PageListModel()
{
}
public PageListModel(List<T> result, int pageIndex, int pageSize, int totalNum)
{
PageIndex = pageIndex;
PageSize = pageSize;
TotalNum = totalNum;
Result = result;
}
}

View File

@ -1,27 +1,57 @@
namespace QYZH.InteractiveMagazine.Models.Dto;
/// <summary>
/// 分页查询输入
/// 通用分页查询
/// </summary>
public class PageQueryModel
{
/// <summary>
/// 页码默认1
///当前页
/// </summary>
public int PageIndex { get; set; } = 1;
/// <summary>
/// 每页条数默认10
///每页条数
/// </summary>
public int PageSize { get; set; } = 10;
/// <summary>
/// 排序字段
/// </summary>
public string? SortField { get; set; }
public string Sort { get; set; } = string.Empty;
/// <summary>
/// 排序类型,前端传入的是"ascending""descending"
/// </summary>
public string SortType { get; set; } = string.Empty;
/// <summary>
/// 排序方式asc/desc
/// 关键字
/// </summary>
public string? SortOrder { get; set; }
public string? KeyWord { get; set; }
}
/// <summary>
/// 分页查询泛型类
/// </summary>
/// <typeparam name="T">查询参数类型</typeparam>
public class PageQueryModel<T> : PageQueryModel where T : class, new()
{
/// <summary>
/// 查询参数
/// </summary>
public T Params { get; set; } = new T();
public TP ConvertTo<TP>() where TP : class
{
if (Params != null)
{
return Params as TP;
}
return default;
}
public int Start => (PageIndex - 1) * PageSize + 1;
public int End => PageIndex * PageSize;
}

View File

@ -0,0 +1,198 @@
using QYZH.InteractiveMagazine.Models.Dto;
namespace QYZH.InteractiveMagazine.IService.Dto;
/// <summary>
/// 微信登录输出
/// </summary>
public class WeChatLoginOutput
{
/// <summary>
/// 访问令牌
/// </summary>
public string Token { get; set; } = string.Empty;
/// <summary>
/// 用户ID
/// </summary>
public long UserId { get; set; }
/// <summary>
/// 用户名
/// </summary>
public string UserName { get; set; } = string.Empty;
/// <summary>
/// 微信OpenId
/// </summary>
public string OpenId { get; set; } = string.Empty;
}
/// <summary>
/// 微信用户创建/更新输入
/// </summary>
public class WxUserInput
{
/// <summary>
/// 微信OpenId
/// </summary>
public string OpenId { get; set; } = string.Empty;
/// <summary>
/// 微信UnionId
/// </summary>
public string? UnionId { get; set; }
/// <summary>
/// 昵称
/// </summary>
public string? NickName { get; set; }
/// <summary>
/// 头像地址
/// </summary>
public string? AvatarUrl { get; set; }
/// <summary>
/// 手机号
/// </summary>
public string? Phone { get; set; }
/// <summary>
/// 积分余额
/// </summary>
public int Points { get; set; } = 0;
/// <summary>
/// 用户类型: Normal, VIP
/// </summary>
public string Type { get; set; } = "Normal";
/// <summary>
/// 状态: Active, Disabled
/// </summary>
public string Status { get; set; } = "Active";
/// <summary>
/// 密码默认手机后4位
/// </summary>
public string? Pwd { get; set; }
/// <summary>
/// 当前成长值
/// </summary>
public int GrowthPoints { get; set; } = 0;
}
/// <summary>
/// 微信用户输出
/// </summary>
public class WxUserOutput
{
/// <summary>
/// 主键ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 微信OpenId
/// </summary>
public string OpenId { get; set; } = string.Empty;
/// <summary>
/// 微信UnionId
/// </summary>
public string? UnionId { get; set; }
/// <summary>
/// 昵称
/// </summary>
public string? NickName { get; set; }
/// <summary>
/// 头像地址
/// </summary>
public string? AvatarUrl { get; set; }
/// <summary>
/// 手机号
/// </summary>
public string? Phone { get; set; }
/// <summary>
/// 积分余额
/// </summary>
public int Points { get; set; }
/// <summary>
/// 用户类型
/// </summary>
public string Type { get; set; } = string.Empty;
/// <summary>
/// 状态
/// </summary>
public string Status { get; set; } = string.Empty;
/// <summary>
/// 当前成长值
/// </summary>
public int GrowthPoints { get; set; }
/// <summary>
/// 创建人
/// </summary>
public string? CreatedBy { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreatedAt { get; set; }
/// <summary>
/// 更新人
/// </summary>
public string? UpdatedBy { get; set; }
/// <summary>
/// 更新时间
/// </summary>
public DateTime? UpdatedAt { get; set; }
}
/// <summary>
/// 微信用户分页查询输入
/// </summary>
public class WxUserQueryInput : PageQueryModel
{
/// <summary>
/// 昵称(模糊查询)
/// </summary>
public string? NickName { get; set; }
/// <summary>
/// 手机号(模糊查询)
/// </summary>
public string? Phone { get; set; }
/// <summary>
/// 用户类型
/// </summary>
public string? Type { get; set; }
/// <summary>
/// 状态
/// </summary>
public string? Status { get; set; }
}
/// <summary>
/// 微信手机号获取输出
/// </summary>
public class WeChatPhoneNumberOutput
{
/// <summary>
/// 手机号
/// </summary>
public string PhoneNumber { get; set; } = string.Empty;
}

View File

@ -6,19 +6,12 @@ namespace QYZH.InteractiveMagazine.Models.Entity
///后台管理员表
///</summary>
[SugarTable("AdminUser")]
public partial class AdminUser : BaseEntity
public partial class AdminUser : SqlSugarBaseEntity
{
public AdminUser(){
}
/// <summary>
/// Desc:主键
/// Default:
/// Nullable:False
/// </summary>
[SugarColumn(IsPrimaryKey=true,IsIdentity=true)]
public new int Id { get; set; }
/// <summary>
/// Desc:用户名

View File

@ -1,43 +0,0 @@
using SqlSugar;
namespace QYZH.InteractiveMagazine.Models.Entity;
/// <summary>
/// 基础实体类
/// </summary>
public abstract class BaseEntity
{
/// <summary>
/// 主键Id
/// </summary>
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public long Id { get; set; }
/// <summary>
/// 是否已删除
/// </summary>
[SugarColumn(IsIgnore = false)]
public bool IsDeleted { get; set; } = false;
/// <summary>
/// 创建人
/// </summary>
[SugarColumn(Length = 50)]
public string? CreatedBy { get; set; } = "System";
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreatedAt { get; set; } = DateTime.Now;
/// <summary>
/// 更新人
/// </summary>
[SugarColumn(Length = 50)]
public string? UpdatedBy { get; set; } = "System";
/// <summary>
/// 更新时间
/// </summary>
public DateTime? UpdatedAt { get; set; } = DateTime.Now;
}

View File

@ -6,19 +6,13 @@ namespace QYZH.InteractiveMagazine.Models.Entity
///签到配置表
///</summary>
[SugarTable("CheckInConfig")]
public partial class CheckInConfig : BaseEntity
public partial class CheckInConfig : SqlSugarBaseEntity
{
public CheckInConfig(){
}
/// <summary>
/// Desc:主键
/// Default:
/// Nullable:False
/// </summary>
[SugarColumn(IsPrimaryKey=true,IsIdentity=true)]
public new int Id {get;set;}
/// <summary>
/// Desc:连续签到天数

View File

@ -6,18 +6,18 @@ namespace QYZH.InteractiveMagazine.Models.Entity
///签到记录表
///</summary>
[SugarTable("CheckInRecord")]
public partial class CheckInRecord : BaseEntity
public partial class CheckInRecord : SqlSugarBaseEntity
{
public CheckInRecord(){
}
/// <summary>
/// Desc:用户Id
/// Default:
/// Nullable:False
/// </summary>
public long UserId {get;set;}
/// <summary>
/// Desc:用户Id
/// Default:
/// Nullable:False
/// </summary>
public long UserId {get;set;}
/// <summary>
/// Desc:签到日期

View File

@ -6,18 +6,19 @@ namespace QYZH.InteractiveMagazine.Models.Entity
///社区预置消息表
///</summary>
[SugarTable("CommunityMessage")]
public partial class CommunityMessage : BaseEntity
public partial class CommunityMessage : SqlSugarBaseEntity
{
public CommunityMessage(){
}
/// <summary>
/// Desc:期刊Id
/// Default:
/// Nullable:False
/// </summary>
public long JournalId {get;set;}
/// <summary>
/// Desc:期刊Id
/// Default:
/// Nullable:False
/// </summary>
public long JournalId {get;set;}
/// <summary>
/// Desc:消息内容

View File

@ -6,18 +6,18 @@ namespace QYZH.InteractiveMagazine.Models.Entity
///期刊表
///</summary>
[SugarTable("Journal")]
public partial class Journal : BaseEntity
public partial class Journal : SqlSugarBaseEntity
{
public Journal(){
}
/// <summary>
/// Desc:期刊号
/// Default:
/// Nullable:False
/// </summary>
public int IssueNumber {get;set;}
/// <summary>
/// Desc:期刊号
/// Default:
/// Nullable:False
/// </summary>
public int IssueNumber {get;set;}
/// <summary>
/// Desc:期刊标题

View File

@ -6,74 +6,68 @@ namespace QYZH.InteractiveMagazine.Models.Entity
///勋章定义表
///</summary>
[SugarTable("Medal")]
public partial class Medal : BaseEntity
public partial class Medal : SqlSugarBaseEntity
{
public Medal(){
public Medal()
{
}
/// <summary>
/// Desc:主键
/// Default:
/// Nullable:False
/// </summary>
[SugarColumn(IsPrimaryKey=true,IsIdentity=true)]
public new int Id {get;set;}
}
/// <summary>
/// Desc:勋章名称
/// Default:
/// Nullable:False
/// </summary>
public string Name {get;set;}
/// <summary>
/// Desc:勋章名称
/// Default:
/// Nullable:False
/// </summary>
public string Name { get; set; }
/// <summary>
/// Desc:获得条件描述
/// Default:
/// Nullable:True
/// </summary>
public string Description {get;set;}
/// <summary>
/// Desc:获得条件描述
/// Default:
/// Nullable:True
/// </summary>
public string Description { get; set; }
/// <summary>
/// Desc:图片地址
/// Default:
/// Nullable:True
/// </summary>
public string ImageUrl {get;set;}
/// <summary>
/// Desc:图片地址
/// Default:
/// Nullable:True
/// </summary>
public string ImageUrl { get; set; }
/// <summary>
/// Desc:条件类型: EvolutionCount, FeedingCount等
/// Default:
/// Nullable:False
/// </summary>
public string ConditionType {get;set;}
/// <summary>
/// Desc:条件类型: EvolutionCount, FeedingCount等
/// Default:
/// Nullable:False
/// </summary>
public string ConditionType { get; set; }
/// <summary>
/// Desc:条件阈值
/// Default:
/// Nullable:False
/// </summary>
public int ConditionValue {get;set;}
/// <summary>
/// Desc:条件阈值
/// Default:
/// Nullable:False
/// </summary>
public int ConditionValue { get; set; }
/// <summary>
/// Desc:排序
/// Default:0
/// Nullable:False
/// </summary>
public int SortOrder {get;set;}
/// <summary>
/// Desc:排序
/// Default:0
/// Nullable:False
/// </summary>
public int SortOrder { get; set; }
/// <summary>
/// Desc:勋章的类型: Pet, Community
/// Default:Pet
/// Nullable:False
/// </summary>
public string Type {get;set;}
/// <summary>
/// Desc:勋章的类型: Pet, Community
/// Default:Pet
/// Nullable:False
/// </summary>
public string Type { get; set; }
/// <summary>
/// Desc:状态: Active, Inactive
/// Default:Active
/// Nullable:False
/// </summary>
public string Status {get;set;}
/// <summary>
/// Desc:状态: Active, Inactive
/// Default:Active
/// Nullable:False
/// </summary>
public string Status { get; set; }
}
}

View File

@ -6,18 +6,19 @@ namespace QYZH.InteractiveMagazine.Models.Entity
///模板评论表
///</summary>
[SugarTable("MessageComment")]
public partial class MessageComment : BaseEntity
public partial class MessageComment : SqlSugarBaseEntity
{
public MessageComment(){
}
/// <summary>
/// Desc:用户Id
/// Default:
/// Nullable:False
/// </summary>
public long UserId {get;set;}
/// <summary>
/// Desc:用户Id
/// Default:
/// Nullable:False
/// </summary>
public long UserId {get;set;}
/// <summary>
/// Desc:消息Id

View File

@ -6,18 +6,18 @@ namespace QYZH.InteractiveMagazine.Models.Entity
///点赞记录表
///</summary>
[SugarTable("MessageLike")]
public partial class MessageLike : BaseEntity
public partial class MessageLike : SqlSugarBaseEntity
{
public MessageLike(){
}
/// <summary>
/// Desc:用户Id
/// Default:
/// Nullable:False
/// </summary>
public long UserId {get;set;}
/// <summary>
/// Desc:用户Id
/// Default:
/// Nullable:False
/// </summary>
public long UserId {get;set;}
/// <summary>
/// Desc:消息Id

View File

@ -6,18 +6,18 @@ namespace QYZH.InteractiveMagazine.Models.Entity
///宠物实例表
///</summary>
[SugarTable("Pet")]
public partial class Pet : BaseEntity
public partial class Pet : SqlSugarBaseEntity
{
public Pet(){
}
/// <summary>
/// Desc:用户Id
/// Default:
/// Nullable:False
/// </summary>
public long UserId {get;set;}
/// <summary>
/// Desc:用户Id
/// Default:
/// Nullable:False
/// </summary>
public long UserId {get;set;}
/// <summary>
/// Desc:宠物昵称

View File

@ -6,19 +6,12 @@ namespace QYZH.InteractiveMagazine.Models.Entity
///宠物进化链定义表
///</summary>
[SugarTable("PetEvolution")]
public partial class PetEvolution : BaseEntity
public partial class PetEvolution : SqlSugarBaseEntity
{
public PetEvolution(){
}
/// <summary>
/// Desc:主键
/// Default:
/// Nullable:False
/// </summary>
[SugarColumn(IsPrimaryKey=true,IsIdentity=true)]
public new int Id {get;set;}
/// <summary>
/// Desc:阶段名称

View File

@ -6,18 +6,19 @@ namespace QYZH.InteractiveMagazine.Models.Entity
///宠物喂养记录表
///</summary>
[SugarTable("PetFeedingRecord")]
public partial class PetFeedingRecord : BaseEntity
public partial class PetFeedingRecord : SqlSugarBaseEntity
{
public PetFeedingRecord(){
}
/// <summary>
/// Desc:宠物Id
/// Default:
/// Nullable:False
/// </summary>
public long PetId {get;set;}
/// <summary>
/// Desc:宠物Id
/// Default:
/// Nullable:False
/// </summary>
public long PetId {get;set;}
/// <summary>
/// Desc:用户Id

View File

@ -6,18 +6,19 @@ namespace QYZH.InteractiveMagazine.Models.Entity
///积分流水记录表
///</summary>
[SugarTable("PointsRecord")]
public partial class PointsRecord : BaseEntity
public partial class PointsRecord : SqlSugarBaseEntity
{
public PointsRecord(){
}
/// <summary>
/// Desc:用户Id
/// Default:
/// Nullable:False
/// </summary>
public long UserId {get;set;}
/// <summary>
/// Desc:用户Id
/// Default:
/// Nullable:False
/// </summary>
public long UserId {get;set;}
/// <summary>
/// Desc:变动数值

View File

@ -6,19 +6,12 @@ namespace QYZH.InteractiveMagazine.Models.Entity
///虚拟商品表
///</summary>
[SugarTable("Product")]
public partial class Product : BaseEntity
public partial class Product : SqlSugarBaseEntity
{
public Product(){
}
/// <summary>
/// Desc:主键
/// Default:
/// Nullable:False
/// </summary>
[SugarColumn(IsPrimaryKey=true,IsIdentity=true)]
public new int Id {get;set;}
/// <summary>
/// Desc:商品名称

View File

@ -0,0 +1,63 @@
using SqlSugar;
using Yitter.IdGenerator;
namespace QYZH.InteractiveMagazine.Models.Entity
{
public class SqlSugarBaseEntity
{
/// <summary>
/// Desc:主键
/// Default:
/// Nullable:False
/// </summary>
public long Id { get; set; } = YitIdHelper.NextId();
/// <summary>
/// Desc:状态 0禁用 1启用
/// Default:1
/// Nullable:False
/// </summary>
[SugarColumn(ColumnName = "Status")]
public string Status { get; set; }
/// <summary>
/// Desc:是否删除
/// Default:b'0'
/// Nullable:False
/// </summary>
[SugarColumn(ColumnName = "IsDeleted")]
public bool IsDeleted { get; set; } = false;
/// <summary>
/// Desc:创建人
/// Default:
/// Nullable:False
/// </summary>
[SugarColumn(ColumnName = "CreatedBy", IsOnlyIgnoreUpdate = true)]
public string CreatedBy { get; set; }
/// <summary>
/// Desc:创建时间
/// Default:
/// Nullable:False
/// </summary>
[SugarColumn(ColumnName = "CreatedAt", IsOnlyIgnoreUpdate = true)]
public DateTime CreatedAt { get; set; }
/// <summary>
/// Desc:修改人
/// Default:
/// Nullable:True
/// </summary>
[SugarColumn(ColumnName = "updatedBy", IsOnlyIgnoreInsert = true)]
public string UpdatedBy { get; set; }
/// <summary>
/// Desc:修改时间
/// Default:
/// Nullable:True
/// </summary>
[SugarColumn(ColumnName = "UpdatedAt", IsOnlyIgnoreInsert = true)]
public DateTime? UpdatedAt { get; set; }
}
}

View File

@ -6,19 +6,13 @@ namespace QYZH.InteractiveMagazine.Models.Entity
///固定模板言论表
///</summary>
[SugarTable("TemplateSentence")]
public partial class TemplateSentence : BaseEntity
public partial class TemplateSentence : SqlSugarBaseEntity
{
public TemplateSentence(){
}
/// <summary>
/// Desc:主键
/// Default:
/// Nullable:False
/// </summary>
[SugarColumn(IsPrimaryKey=true,IsIdentity=true)]
public new int Id {get;set;}
/// <summary>
/// Desc:模板内容

View File

@ -1,71 +0,0 @@
using SqlSugar;
namespace QYZH.InteractiveMagazine.Models.Entity
{
///<summary>
///用户表
///</summary>
[SugarTable("User")]
public partial class User : BaseEntity
{
public User(){
}
/// <summary>
/// Desc:微信OpenId
/// Default:
/// Nullable:False
/// </summary>
public string OpenId {get;set;}
/// <summary>
/// Desc:微信UnionId
/// Default:
/// Nullable:True
/// </summary>
public string UnionId {get;set;}
/// <summary>
/// Desc:昵称
/// Default:
/// Nullable:True
/// </summary>
public string NickName {get;set;}
/// <summary>
/// Desc:头像地址
/// Default:
/// Nullable:True
/// </summary>
public string AvatarUrl {get;set;}
/// <summary>
/// Desc:手机号
/// Default:
/// Nullable:True
/// </summary>
public string Phone {get;set;}
/// <summary>
/// Desc:积分余额
/// Default:0
/// Nullable:False
/// </summary>
public int Points {get;set;}
/// <summary>
/// Desc:用户类型: Normal, VIP
/// Default:Normal
/// Nullable:False
/// </summary>
public string Type {get;set;}
/// <summary>
/// Desc:状态: Active, Disabled
/// Default:Active
/// Nullable:False
/// </summary>
public string Status {get;set;}
}
}

View File

@ -0,0 +1,80 @@
using SqlSugar;
namespace QYZH.InteractiveMagazine.Models.Entity
{
///<summary>
///用户表
///</summary>
[SugarTable("WxUser")]
public partial class WxUser : SqlSugarBaseEntity
{
/// <summary>
/// Desc:微信OpenId
/// Default:
/// Nullable:False
/// </summary>
public string OpenId { get; set; }
/// <summary>
/// Desc:微信UnionId
/// Default:
/// Nullable:True
/// </summary>
public string UnionId { get; set; }
/// <summary>
/// Desc:昵称
/// Default:
/// Nullable:True
/// </summary>
public string NickName { get; set; }
/// <summary>
/// Desc:头像地址
/// Default:
/// Nullable:True
/// </summary>
public string AvatarUrl { get; set; }
/// <summary>
/// Desc:手机号
/// Default:
/// Nullable:True
/// </summary>
public string Phone { get; set; }
/// <summary>
/// Desc:积分余额
/// Default:0
/// Nullable:False
/// </summary>
public int Points { get; set; }
/// <summary>
/// Desc:用户类型: Normal, VIP
/// Default:Normal
/// Nullable:False
/// </summary>
public string Type { get; set; }
/// <summary>
/// Desc:状态: Active, Disabled
/// Default:Active
/// Nullable:False
/// </summary>
public string Status { get; set; }
/// <summary>
/// Desc:密码默认手机后4位
/// Default:Active
/// Nullable:False
/// </summary>
public string Pwd { get; set; }
/// <summary>
/// Desc:当前成长值
/// Default:0
/// Nullable:False
/// </summary>
public int GrowthPoints { get; set; }
}
}

View File

@ -5,10 +5,10 @@ namespace QYZH.InteractiveMagazine.Models.Entity
///<summary>
///用户背包表
///</summary>
[SugarTable("UserBag")]
public partial class UserBag : BaseEntity
[SugarTable("WxUserBag")]
public partial class WxUserBag : SqlSugarBaseEntity
{
public UserBag(){
public WxUserBag(){
}

View File

@ -5,10 +5,10 @@ namespace QYZH.InteractiveMagazine.Models.Entity
///<summary>
///用户勋章表
///</summary>
[SugarTable("UserMedal")]
public partial class UserMedal : BaseEntity
[SugarTable("WxUserMedal")]
public partial class WxUserMedal : SqlSugarBaseEntity
{
public UserMedal(){
public WxUserMedal(){
}

View File

@ -8,7 +8,9 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Mapster" Version="7.4.0" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.166" />
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
</ItemGroup>
</Project>

View File

@ -1,13 +0,0 @@
using QYZH.InteractiveMagazine.Models.Entity;
namespace QYZH.InteractiveMagazine.Repository;
public class AdminUserRepository : BaseRepository<AdminUser>, IAdminUserRepository
{
public async Task<AdminUser?> GetByUserNameAsync(string userName)
{
return await Db.Queryable<AdminUser>()
.Where(x => x.UserName == userName)
.FirstAsync();
}
}

View File

@ -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;
/// <summary>
/// 基础仓储实现
/// </summary>
/// <typeparam name="T">实体类型</typeparam>
public class BaseRepository<T> : IBaseRepository<T> where T : class, new()
namespace QYZH.InteractiveMagazine.Repository
{
/// <summary>
/// SqlSugar 数据库实例
/// 数据仓库类
/// </summary>
protected SqlSugarClient Db => SqlSugarDbContext.GetDb();
/// <summary>
/// 根据Id获取实体自动过滤已删除数据
/// </summary>
/// <param name="id">主键Id</param>
/// <returns>实体对象</returns>
public async Task<T?> GetByIdAsync(long id)
/// <typeparam name="T"></typeparam>
public class BaseRepository<T> : SimpleClient<T> where T : class, new()
{
return await Db.Queryable<T>().In(id).FirstAsync();
}
/// <summary>
/// 获取所有列表(自动过滤已删除数据)
/// </summary>
/// <returns>实体列表</returns>
public async Task<List<T>> GetListAsync()
{
return await Db.Queryable<T>().ToListAsync();
}
/// <summary>
/// 根据条件获取列表(自动过滤已删除数据)
/// </summary>
/// <param name="where">查询条件</param>
/// <returns>实体列表</returns>
public async Task<List<T>> GetListByWhereAsync(Expression<Func<T, bool>> where)
{
return await Db.Queryable<T>().Where(where).ToListAsync();
}
/// <summary>
/// 分页查询(自动过滤已删除数据)
/// </summary>
/// <param name="where">查询条件</param>
/// <param name="pageQuery">分页参数</param>
/// <returns>分页结果</returns>
public async Task<PageListModel<T>> GetPageListAsync(Expression<Func<T, bool>> where, PageQueryModel pageQuery)
{
RefAsync<int> total = 0;
var query = Db.Queryable<T>().Where(where);
// 处理排序
if (!string.IsNullOrEmpty(pageQuery.SortField))
private readonly ILogger<BaseRepository<T>> _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<ILogger<BaseRepository<T>>>();
}
var list = await query.ToPageListAsync(pageQuery.PageIndex, pageQuery.PageSize, total);
#region add
return new PageListModel<T>
public IInsertable<T> Insertable(T t)
{
PageIndex = pageQuery.PageIndex,
PageSize = pageQuery.PageSize,
TotalCount = total,
List = list
};
return Context.Insertable(t);
}
#endregion add
#region update
public IUpdateable<T> Updateable(T t)
{
return Context.Updateable(t);
}
public IUpdateable<T> Updateable()
{
return Context.Updateable<T>();
}
public IUpdateable<T1> Updateable<T1>() where T1 : class, new()
{
return Context.Updateable<T1>();
}
/// <summary>
/// 根据指定条件更新指定列 egUpdate(new SysUser(){ Status = 1 }, it => new { it.Status }, f => f.Userid == 1));
/// 只更新Status列条件是包含
/// </summary>
/// <param name="entity">实体类</param>
/// <param name="expression">要更新列的表达式</param>
/// <param name="where">where表达式</param>
/// <returns></returns>
public async Task<bool> UpdateAsync(Expression<Func<T, bool>> columns, Expression<Func<T, bool>> where)
{
return await Context.Updateable<T>().SetColumns(columns).Where(where).ExecuteCommandAsync() > 0;
}
#endregion update
/// <summary>
/// 事务 异步 无返回值
/// </summary>
/// <param name="action"></param>
/// <returns></returns>
public async Task UseTranAsync(Func<Task> 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;
}
}
/// <summary>
/// 事务 异步 返回bool
/// </summary>
/// <param name="action"></param>
/// <returns></returns>
public async Task<bool> UseTranAsync(Func<Task<bool>> 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<T> Deleteable()
{
return Context.Deleteable<T>();
}
#endregion delete
#region query
public bool Any(Expression<Func<T, bool>> expression)
{
return Context.Queryable<T>().Any(expression);
}
public ISugarQueryable<T> Queryable()
{
return Context.Queryable<T>();
}
public ISugarQueryable<T1> Queryable<T1>()
{
return Context.Queryable<T1>();
}
/// <summary>
/// 根据条件表达式查询单条数据
/// </summary>
/// <param name="expression">表达式</param>
/// <returns>泛型实体</returns>
public Task<R> GetByIdAsync<R>(Expression<Func<T, bool>> expression) where R : class
{
return Context.Queryable<T>().Where(expression).Select<R>().FirstAsync();
}
public Task<R> GetByExpressionAsync<R>(Expression<Func<T, bool>> expression) where R : class
{
return Context.Queryable<T>().Where(expression).Select<R>().FirstAsync();
}
public Task<List<T2>> GetListByExpression<T2>(Expression<Func<T, bool>> expression) where T2 : class
{
return Context.Queryable<T>().Where(expression).Select<T2>().ToListAsync();
}
/// <summary>
/// 根据条件查询分页数据
/// </summary>
/// <param name="where"></param>
/// <param name="parm"></param>
/// <returns></returns>
public PageListModel<T> GetPages(Expression<Func<T, bool>> where, PageQueryModel parm)
{
var source = Context.Queryable<T>().Where(where);
return source.ToPage(parm);
}
/// <summary>
/// 分页获取数据
/// </summary>
/// <param name="where">条件表达式</param>
/// <param name="parm"></param>
/// <param name="order"></param>
/// <param name="orderEnum"></param>
/// <returns></returns>
public PageListModel<T> GetPages(Expression<Func<T, bool>> where, PageQueryModel parm, Expression<Func<T, object>> order, OrderByType orderEnum = OrderByType.Asc)
{
var source = Context
.Queryable<T>()
.Where(where)
.OrderByIF(orderEnum == OrderByType.Asc, order, OrderByType.Asc)
.OrderByIF(orderEnum == OrderByType.Desc, order, OrderByType.Desc);
return source.ToPage(parm);
}
public PageListModel<T> GetPages(Expression<Func<T, bool>> where, PageQueryModel parm, Expression<Func<T, object>> order, string orderByType)
{
return GetPages(where, parm, order, orderByType == "desc" ? OrderByType.Desc : OrderByType.Asc);
}
/// <summary>
/// 查询所有数据(无分页,请慎用)
/// </summary>
/// <returns></returns>
public List<T> GetAll(bool useCache = false, int cacheSecond = 3600)
{
return Context.Queryable<T>().WithCacheIF(useCache, cacheSecond).ToList();
}
#endregion query
/// <summary>
/// 此方法不带output返回值
/// var list = new List<SugarParameter>();
/// list.Add(new SugarParameter(ParaName, ParaValue)); input
/// </summary>
/// <param name="procedureName"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public DataTable UseStoredProcedureToDataTable(string procedureName, List<SugarParameter> parameters)
{
return Context.Ado.UseStoredProcedure().GetDataTable(procedureName, parameters);
}
/// <summary>
/// 带output返回值
/// var list = new List<SugarParameter>();
/// list.Add(new SugarParameter(ParaName, ParaValue, true)); output
/// list.Add(new SugarParameter(ParaName, ParaValue)); input
/// </summary>
/// <param name="procedureName"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public (DataTable, List<SugarParameter>) UseStoredProcedureToTuple(string procedureName, List<SugarParameter> parameters)
{
var result = (Context.Ado.UseStoredProcedure().GetDataTable(procedureName, parameters), parameters);
return result;
}
}
/// <summary>
/// 插入单条记录
/// 分页查询扩展
/// </summary>
/// <param name="entity">实体对象</param>
/// <returns>是否成功</returns>
public async Task<bool> InsertAsync(T entity)
public static class QueryableExtension
{
return await Db.Insertable(entity).ExecuteCommandAsync() > 0;
}
/// <summary>
/// 读取列表
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source">查询表单式</param>
/// <param name="parm">分页参数</param>
/// <returns></returns>
public static PageListModel<T> ToPage<T>(this ISugarQueryable<T> source, PageQueryModel parm)
{
var page = new PageListModel<T>();
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;
}
/// <summary>
/// 批量插入记录
/// </summary>
/// <param name="entities">实体列表</param>
/// <returns>是否成功</returns>
public async Task<bool> InsertRangeAsync(List<T> entities)
{
return await Db.Insertable(entities).ExecuteCommandAsync() > 0;
}
/// <summary>
/// 转指定实体类Dto
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="T2"></typeparam>
/// <param name="source"></param>
/// <param name="parm"></param>
/// <returns></returns>
public static PageListModel<T2> ToPage<T, T2>(this ISugarQueryable<T> source, PageQueryModel parm)
{
var page = new PageListModel<T2>();
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);
/// <summary>
/// 更新单条记录
/// </summary>
/// <param name="entity">实体对象</param>
/// <returns>是否成功</returns>
public async Task<bool> UpdateAsync(T entity)
{
return await Db.Updateable(entity).ExecuteCommandAsync() > 0;
page.TotalNum = total;
page.Result = result.Adapt<List<T2>>();
return page;
}
}
/// <summary>
/// 批量更新记录
/// </summary>
/// <param name="entities">实体列表</param>
/// <returns>是否成功</returns>
public async Task<bool> UpdateRangeAsync(List<T> entities)
{
return await Db.Updateable(entities).ExecuteCommandAsync() > 0;
}
/// <summary>
/// 根据Id删除记录软删除设置 IsDeleted = true
/// </summary>
/// <param name="id">主键Id</param>
/// <returns>是否成功</returns>
public async Task<bool> DeleteByIdAsync(long id)
{
return await Db.Deleteable<T>().In(id).IsLogic().ExecuteCommandAsync() > 0;
}
/// <summary>
/// 根据条件删除记录(软删除,设置 IsDeleted = true
/// </summary>
/// <param name="where">删除条件</param>
/// <returns>是否成功</returns>
public async Task<bool> DeleteByWhereAsync(Expression<Func<T, bool>> where)
{
return await Db.Deleteable<T>().Where(where).IsLogic().ExecuteCommandAsync() > 0;
}
/// <summary>
/// 根据条件获取记录数(自动过滤已删除数据)
/// </summary>
/// <param name="where">查询条件</param>
/// <returns>记录数</returns>
public async Task<int> GetCountAsync(Expression<Func<T, bool>> where)
{
return await Db.Queryable<T>().Where(where).CountAsync();
}
public ISugarQueryable<T> Queryable()
{
return Db.Queryable<T>();
}
}
}

View File

@ -0,0 +1,160 @@
using QYZH.InteractiveMagazine.Models.Entity;
using SqlSugar;
using System.Linq.Expressions;
using System.Reflection;
namespace QYZH.InteractiveMagazine.Repository.Core
{
/// <summary>
/// sql sugar 管理器
/// </summary>
public static class SqlSugarExtension
{
/// <summary>
/// 生成类文件
/// </summary>
/// <param name="db"></param>
/// <param name="directoryPath">生成路径</param>
/// <param name="nameSpace">名称空间</param>
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;
}
/// <summary>
/// 添加全局过滤器
/// IsDeleted
/// </summary>
/// <param name="db">数据库Client</param>
/// <param name="assemblyName">程序集名称</param>
/// <returns></returns>
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;
}
/// <summary>
/// 添加创建人 创建时间 更新人 更新时间 默认值
/// </summary>
/// <param name="db"></param>
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
}
/// <summary>
/// 把一个字符串转成驼峰规则的字符串
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static string ToCamelCase(this string str)
{
if (!string.IsNullOrEmpty(str) && str.Length > 1)
{
return char.ToUpperInvariant(str[0]) + str.Substring(1);
}
return str;
}
}
}

View File

@ -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
{
/// <summary>
/// sql sugar 管理器
/// </summary>
public static class SqlSugarManager
{
/// <summary>
/// 获基础信息库对象 用IOC这块代码不能写到IOC里面
/// </summary>
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;
}
}
}

View File

@ -1,8 +0,0 @@
using QYZH.InteractiveMagazine.Models.Entity;
namespace QYZH.InteractiveMagazine.Repository;
public interface IAdminUserRepository : IBaseRepository<AdminUser>
{
Task<AdminUser?> GetByUserNameAsync(string userName);
}

View File

@ -1,88 +1,102 @@

using QYZH.InteractiveMagazine.Models.Dto;
using SqlSugar;
using System.Data;
using System.Linq.Expressions;
namespace QYZH.InteractiveMagazine.Repository;
/// <summary>
/// 基础仓储接口
/// </summary>
/// <typeparam name="T">实体类型</typeparam>
public interface IBaseRepository<T> where T : class, new()
namespace QYZH.InteractiveMagazine.Repository
{
/// <summary>
/// 根据Id获取实体
/// </summary>
/// <param name="id">主键Id</param>
/// <returns>实体对象</returns>
Task<T?> GetByIdAsync(long id);
public interface IBaseRepository<T> : ISimpleClient<T> where T : class, new()
{
#region add
int Add(T t, bool ignoreNull = true);
/// <summary>
/// 获取所有列表
/// </summary>
/// <returns>实体列表</returns>
Task<List<T>> GetListAsync();
int Insert(List<T> t);
int Insert(T parm, Expression<Func<T, object>> iClumns = null, bool ignoreNull = true);
/// <summary>
/// 根据条件获取列表
/// </summary>
/// <param name="where">查询条件</param>
/// <returns>实体列表</returns>
Task<List<T>> GetListByWhereAsync(Expression<Func<T, bool>> where);
IInsertable<T> Insertable(T t);
/// <summary>
/// 分页查询
/// </summary>
/// <param name="where">查询条件</param>
/// <param name="pageQuery">分页参数</param>
/// <returns>分页结果</returns>
Task<PageListModel<T>> GetPageListAsync(Expression<Func<T, bool>> where, PageQueryModel pageQuery);
IUpdateable<T> Updateable();
#endregion add
/// <summary>
/// 插入单条记录
/// </summary>
/// <param name="entity">实体对象</param>
/// <returns>是否成功</returns>
Task<bool> InsertAsync(T entity);
#region update
int Update(T entity, bool ignoreNullColumns = false, object data = null);
/// <summary>
/// 批量插入记录
/// </summary>
/// <param name="entities">实体列表</param>
/// <returns>是否成功</returns>
Task<bool> InsertRangeAsync(List<T> entities);
/// <summary>
/// 只更新表达式的值
/// </summary>
/// <param name="entity"></param>
/// <param name="expression"></param>
/// <returns></returns>
int Update(T entity, Expression<Func<T, object>> expression, bool ignoreAllNull = false);
/// <summary>
/// 更新单条记录
/// </summary>
/// <param name="entity">实体对象</param>
/// <returns>是否成功</returns>
Task<bool> UpdateAsync(T entity);
int Update(T entity, Expression<Func<T, object>> expression, Expression<Func<T, bool>> where);
/// <summary>
/// 批量更新记录
/// </summary>
/// <param name="entities">实体列表</param>
/// <returns>是否成功</returns>
Task<bool> UpdateRangeAsync(List<T> entities);
int Update(Expression<Func<T, T>> columns, Expression<Func<T, bool>> where);
Task<int> UpdateAsync(Expression<Func<T, T>> columns, Expression<Func<T, bool>> where);
/// <summary>
/// 根据Id删除记录软删除
/// </summary>
/// <param name="id">主键Id</param>
/// <returns>是否成功</returns>
Task<bool> DeleteByIdAsync(long id);
#endregion update
/// <summary>
/// 根据条件删除记录(软删除)
/// </summary>
/// <param name="where">删除条件</param>
/// <returns>是否成功</returns>
Task<bool> DeleteByWhereAsync(Expression<Func<T, bool>> where);
/// <summary>
/// 事务 同步
/// </summary>
/// <param name="action"></param>
/// <returns></returns>
Task UseTranAsync(Func<Task> action);
/// <summary>
/// 根据条件获取记录数
/// </summary>
/// <param name="where">查询条件</param>
/// <returns>记录数</returns>
Task<int> GetCountAsync(Expression<Func<T, bool>> where);
/// <summary>
/// 事务 异步
/// </summary>
/// <param name="action"></param>
/// <returns></returns>
Task<bool> UseTranAsync(Func<Task<bool>> action);
#region delete
IDeleteable<T> Deleteable();
int Delete(object id, string title = "");
int DeleteTable();
bool Truncate();
#endregion delete
#region query
/// <summary>
/// 根据条件查询分页数据
/// </summary>
/// <param name="where"></param>
/// <param name="parm"></param>
/// <returns></returns>
PageListModel<T> GetPages(Expression<Func<T, bool>> where, PageQueryModel parm);
PageListModel<T> GetPages(Expression<Func<T, bool>> where, PageQueryModel parm, Expression<Func<T, object>> order, OrderByType orderEnum = OrderByType.Asc);
PageListModel<T> GetPages(Expression<Func<T, bool>> where, PageQueryModel parm, Expression<Func<T, object>> order, string orderByType);
bool Any(Expression<Func<T, bool>> expression);
ISugarQueryable<T> Queryable();
List<T> GetAll(bool useCache = false, int cacheSecond = 3600);
List<T> SqlQueryToList(string sql, object obj = null);
/// <summary>
/// 根据主值查询单条数据
/// </summary>
/// <param name="pkValue">主键值</param>
/// <returns>泛型实体</returns>
R GetById<R>(object pkValue) where R : class;
Task<R> GetByExpression<R>(Expression<Func<T, bool>> expression) where R : class;
Task<List<T2>> GetListByExpression<T2>(Expression<Func<T, bool>> expression) where T2 : class;
#endregion query
#region Procedure
DataTable UseStoredProcedureToDataTable(string procedureName, List<SugarParameter> parameters);
(DataTable, List<SugarParameter>) UseStoredProcedureToTuple(string procedureName, List<SugarParameter> parameters);
#endregion Procedure
}
}

View File

@ -2,12 +2,14 @@
<ItemGroup>
<ProjectReference Include="..\QYZH.InteractiveMagazine.Common\QYZH.InteractiveMagazine.Common.csproj" />
<ProjectReference Include="..\QYZH.InteractiveMagazine.Infrastructure\QYZH.InteractiveMagazine.Infrastructure.csproj" />
<ProjectReference Include="..\QYZH.InteractiveMagazine.Models\QYZH.InteractiveMagazine.Models.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
<PackageReference Include="MySqlConnector" Version="2.5.0" />
<PackageReference Include="SqlSugar.IOC" Version="2.0.1" />
<PackageReference Include="SqlSugarCoreNoDrive" Version="5.1.4.213" />
</ItemGroup>
<PropertyGroup>

View File

@ -1,99 +0,0 @@
using Microsoft.Extensions.Configuration;
using QYZH.InteractiveMagazine.Models.Entity;
using SqlSugar;
namespace QYZH.InteractiveMagazine.Repository;
/// <summary>
/// SqlSugar 数据库上下文封装(静态类)
/// </summary>
public static class SqlSugarDbContext
{
/// <summary>
/// SqlSugarClient 实例
/// </summary>
private static SqlSugarClient? _db;
/// <summary>
/// 配置对象
/// </summary>
private static IConfiguration? _configuration;
/// <summary>
/// 初始化数据库上下文(在应用启动时调用一次)
/// </summary>
/// <param name="configuration">配置对象</param>
public static void Init(IConfiguration configuration)
{
_configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
}
/// <summary>
/// 获取 SqlSugarClient 实例
/// </summary>
/// <returns>SqlSugarClient 实例</returns>
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<BaseEntity>(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;
}
/// <summary>
/// 代码优先初始化(可选)
/// </summary>
/// <param name="entityTypes">实体类型数组</param>
public static void InitializeCodeFirst(params Type[] entityTypes)
{
var db = GetDb();
// 创建数据库(如果不存在)
db.DbMaintenance.CreateDatabase();
// 初始化表结构
if (entityTypes != null && entityTypes.Length > 0)
{
db.CodeFirst.InitTables(entityTypes);
}
}
}

View File

@ -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<AdminUser> adminUserRepository, IConfiguration configuration, ILogger<AdminAuthService> logger) : BaseRepository<AdminUser>, IAdminAuthService
{
private readonly IAdminUserRepository _adminUserRepository;
private readonly IConfiguration _configuration;
private readonly ILogger<AdminAuthService> _logger;
private const string TokenKeyPrefix = "InteractiveMagazine:AdminAuth:Token";
private const string UserInfoKeyPrefix = "InteractiveMagazine:AdminAuth:UserInfo";
public AdminAuthService(IAdminUserRepository adminUserRepository, IConfiguration configuration, ILogger<AdminAuthService> logger)
{
_adminUserRepository = adminUserRepository;
_configuration = configuration;
_logger = logger;
}
public async Task<AdminLoginOutput> 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<AdminUserInfoOutput> 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<JwtSettings>()
var jwtSettings = configuration.GetSection("JwtSettings").Get<JwtSettings>()
?? new JwtSettings
{
Issuer = "QYZH.InteractiveMagazine",

View File

@ -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;
/// <summary>
/// 管理员用户服务实现
/// </summary>
public class AdminUserService : IAdminUserService
public class AdminUserService(BaseRepository<AdminUser> adminUserRepository, ILogger<AdminUserService> logger) : BaseRepository<AdminUser>, IAdminUserService
{
private readonly IAdminUserRepository _adminUserRepository;
private readonly ILogger<AdminUserService> _logger;
public AdminUserService(IAdminUserRepository adminUserRepository, ILogger<AdminUserService> logger)
{
_adminUserRepository = adminUserRepository;
_logger = logger;
}
/// <summary>
/// 创建管理员
/// </summary>
public async Task<AdminUserOutput> 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
/// </summary>
public async Task<AdminUserOutput> 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
/// </summary>
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);
}
/// <summary>
@ -161,12 +154,12 @@ public class AdminUserService : IAdminUserService
/// </summary>
public async Task<AdminUserOutput> 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
/// </summary>
public async Task<PageListModel<AdminUserOutput>> 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<AdminUserOutput>();
return new PageListModel<AdminUserOutput>
{
List = outputList,
TotalCount = pageResult.TotalCount,
PageIndex = pageResult.PageIndex,
PageSize = pageResult.PageSize
};
}
/// <summary>
/// 构建查询表达式
/// </summary>
private static Expression<Func<AdminUser, bool>> BuildQueryExpression(AdminUserQueryInput input)
{
Expression<Func<AdminUser, bool>> where = x => !x.IsDeleted;
if (!string.IsNullOrWhiteSpace(input.UserName))
{
var userName = input.UserName;
Expression<Func<AdminUser, bool>> userNameCondition = x => x.UserName.Contains(userName);
where = Expression.Lambda<Func<AdminUser, bool>>(
Expression.AndAlso(where.Body,
Expression.Invoke(userNameCondition, where.Parameters[0])),
where.Parameters);
}
if (!string.IsNullOrWhiteSpace(input.Type))
{
var type = input.Type;
Expression<Func<AdminUser, bool>> typeCondition = x => x.Type == type;
where = Expression.Lambda<Func<AdminUser, bool>>(
Expression.AndAlso(where.Body,
Expression.Invoke(typeCondition, where.Parameters[0])),
where.Parameters);
}
if (!string.IsNullOrWhiteSpace(input.Status))
{
var status = input.Status;
Expression<Func<AdminUser, bool>> statusCondition = x => x.Status == status;
where = Expression.Lambda<Func<AdminUser, bool>>(
Expression.AndAlso(where.Body,
Expression.Invoke(statusCondition, where.Parameters[0])),
where.Parameters);
}
return where;
RefAsync<int> 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<AdminUserOutput>(pageResult, input.PageIndex, input.PageSize, totalNumber);
}
/// <summary>

View File

@ -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;
/// <summary>
/// 基础服务实现
/// </summary>
/// <typeparam name="T">实体类型</typeparam>
public class BaseService<T> : IBaseService<T> where T : class, new()
{
protected readonly IBaseRepository<T> _repository;
protected readonly ILogger<BaseService<T>> _logger;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="repository">基础仓储</param>
/// <param name="logger">日志记录器</param>
public BaseService(IBaseRepository<T> repository, ILogger<BaseService<T>> logger)
{
_repository = repository;
_logger = logger;
}
/// <summary>
/// 根据ID获取实体
/// </summary>
/// <param name="id">实体ID</param>
/// <returns>实体对象</returns>
public async Task<T?> 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;
}
/// <summary>
/// 获取所有实体列表
/// </summary>
/// <returns>实体列表</returns>
public async Task<List<T>> GetListAsync()
{
_logger.LogInformation("正在获取所有实体列表");
return await _repository.GetListAsync();
}
/// <summary>
/// 获取分页列表
/// </summary>
/// <param name="pageQuery">分页查询参数</param>
/// <returns>分页数据</returns>
public async Task<PageListModel<T>> 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);
}
/// <summary>
/// 新增实体
/// </summary>
/// <param name="entity">实体对象</param>
/// <returns>是否成功</returns>
public async Task<bool> 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;
}
/// <summary>
/// 更新实体
/// </summary>
/// <param name="entity">实体对象</param>
/// <returns>是否成功</returns>
public async Task<bool> 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;
}
/// <summary>
/// 根据ID删除实体
/// </summary>
/// <param name="id">实体ID</param>
/// <returns>是否成功</returns>
public async Task<bool> 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;
}
/// <summary>
/// 设置插入时的审计字段
/// </summary>
/// <param name="entity">实体对象</param>
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";
}
}
}

View File

@ -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<WxUser> wxUserRepository, ILogger<WxUserService> _logger) : BaseRepository<WxUser>, IWxUserService
{
public async Task<WxUserOutput> 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<WxUserOutput> 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<WxUserOutput> 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<PageListModel<WxUserOutput>> 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<int> 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<WxUserOutput>(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
};
}
}

View File

@ -23,6 +23,11 @@ public class AdminController : BaseController
_logger = logger;
}
/// <summary>
/// 登录
/// </summary>
/// <param name="input">登录输入</param>
/// <returns>登录结果</returns>
[AllowAnonymous]
[HttpPost("login")]
public async Task<BaseResponse<AdminLoginOutput>> LoginAsync([FromBody] AdminLoginInput input)
@ -31,6 +36,10 @@ public class AdminController : BaseController
return Success(result);
}
/// <summary>
/// 登出
/// </summary>
/// <returns>登出结果</returns>
[HttpPost("logout")]
public async Task<BaseResponse<object>> LogoutAsync()
{
@ -44,6 +53,10 @@ public class AdminController : BaseController
return Success(new object(), "登出成功");
}
/// <summary>
/// 获取管理员信息
/// </summary>
/// <returns>管理员信息</returns>
[HttpGet("info")]
public async Task<BaseResponse<AdminUserInfoOutput>> GetAdminInfoAsync()
{
@ -57,6 +70,11 @@ public class AdminController : BaseController
return Success(result);
}
/// <summary>
/// 修改密码
/// </summary>
/// <param name="input">修改密码输入</param>
/// <returns>修改密码结果</returns>
[HttpPost("changePassword")]
public async Task<BaseResponse<object>> ChangePasswordAsync([FromBody] ChangePasswordInput input)
{

View File

@ -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<WxUserController> _logger;
public WxUserController(IWxUserService wxUserService, ILogger<WxUserController> logger)
{
_wxUserService = wxUserService;
_logger = logger;
}
[HttpPost("users")]
public async Task<BaseResponse<WxUserOutput>> 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<WxUserOutput>.Fail(ex.Message, ex.Code);
}
catch (Exception ex)
{
_logger.LogError(ex, "创建微信用户系统异常,参数:{Input}", input);
return BaseResponse<WxUserOutput>.Fail("创建微信用户失败,请稍后重试", 500);
}
}
[HttpPut("users/{id}")]
public async Task<BaseResponse<WxUserOutput>> 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<WxUserOutput>.Fail(ex.Message, ex.Code);
}
catch (Exception ex)
{
_logger.LogError(ex, "更新微信用户系统异常ID{Id},参数:{Input}", id, input);
return BaseResponse<WxUserOutput>.Fail("更新微信用户失败,请稍后重试", 500);
}
}
[HttpDelete("users/{id}")]
public async Task<BaseResponse<object>> DeleteUserAsync(long id)
{
try
{
await _wxUserService.DeleteAsync(id);
return Success(new object(), "删除微信用户成功");
}
catch (BusinessException ex)
{
_logger.LogWarning(ex, "删除微信用户业务异常: {Message}", ex.Message);
return BaseResponse<object>.Fail(ex.Message, ex.Code);
}
catch (Exception ex)
{
_logger.LogError(ex, "删除微信用户系统异常ID{Id}", id);
return BaseResponse<object>.Fail("删除微信用户失败,请稍后重试", 500);
}
}
[HttpGet("users/{id}")]
public async Task<BaseResponse<WxUserOutput>> GetUserByIdAsync(long id)
{
try
{
var result = await _wxUserService.GetByIdAsync(id);
return Success(result);
}
catch (BusinessException ex)
{
_logger.LogWarning(ex, "获取微信用户业务异常: {Message}", ex.Message);
return BaseResponse<WxUserOutput>.Fail(ex.Message, ex.Code);
}
catch (Exception ex)
{
_logger.LogError(ex, "获取微信用户系统异常ID{Id}", id);
return BaseResponse<WxUserOutput>.Fail("获取微信用户信息失败,请稍后重试", 500);
}
}
[HttpPost("users/list")]
public async Task<BaseResponse<PageListModel<WxUserOutput>>> 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<PageListModel<WxUserOutput>>.Fail(ex.Message, ex.Code);
}
catch (Exception ex)
{
_logger.LogError(ex, "查询微信用户列表系统异常,参数:{Input}", input);
return BaseResponse<PageListModel<WxUserOutput>>.Fail("查询微信用户列表失败,请稍后重试", 500);
}
}
}

View File

@ -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<GlobalExceptionMiddleware>();