From db15e4c68b39d3c93cf64bdef1e73752e49a8958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E6=A2=93=E5=BD=AD?= Date: Tue, 10 Mar 2026 16:33:19 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A7=AF=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Points/Dtos/UserPointsDtos.cs | 92 +++++++++++++++ .../Points/PointsRecordService.cs | 106 +++++++++++++++++- 2 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 YD_Event.Application/Points/Dtos/UserPointsDtos.cs diff --git a/YD_Event.Application/Points/Dtos/UserPointsDtos.cs b/YD_Event.Application/Points/Dtos/UserPointsDtos.cs new file mode 100644 index 0000000..0c7b435 --- /dev/null +++ b/YD_Event.Application/Points/Dtos/UserPointsDtos.cs @@ -0,0 +1,92 @@ +using System.ComponentModel.DataAnnotations; +using YD_Event.Core.Enum; + +namespace YD_Event.Application.Points.Dtos; + +/// +/// 用户积分查询输入 +/// +public class UserPointsQueryInput : Pagination +{ + /// + /// 积分类型(1-获取 2-消耗,不传为全部) + /// + public PointsOperationType? Type { get; set; } + + /// + /// 动作关键字(赛事名称/商品名称) + /// + public string? ActionKeyword { get; set; } + + /// + /// 开始时间 + /// + public DateTime? StartTime { get; set; } + + /// + /// 结束时间 + /// + public DateTime? EndTime { get; set; } +} + +/// +/// 积分明细列表项 +/// +public class UserPointsLogDto +{ + /// + /// 记录ID + /// + public long Id { get; set; } + + /// + /// 积分类型(1-获取 2-消耗) + /// + public PointsOperationType Type { get; set; } + + /// + /// 动作(赛事名称/消费内容) + /// + public string Action { get; set; } + + /// + /// 项目名称 + /// + public string? ProjectName { get; set; } + + /// + /// 组别名称 + /// + public string? GroupName { get; set; } + + /// + /// 参赛人(仅单位账号有效) + /// + public string? ParticipantName { get; set; } + + /// + /// 名次 + /// + public int? Rank { get; set; } + + /// + /// 积分变动 + /// + public decimal Points { get; set; } + + /// + /// 生成时间 + /// + public DateTime CreatedTime { get; set; } +} + +/// +/// 用户积分概览 +/// +public class UserPointsOverviewDto +{ + /// + /// 当前总积分 + /// + public decimal CurrentBalance { get; set; } +} diff --git a/YD_Event.Application/Points/PointsRecordService.cs b/YD_Event.Application/Points/PointsRecordService.cs index 426899c..1a30178 100644 --- a/YD_Event.Application/Points/PointsRecordService.cs +++ b/YD_Event.Application/Points/PointsRecordService.cs @@ -1,4 +1,5 @@ using SqlSugar; +using YD_Event.Application.Auth; using YD_Event.Application.Points.Dtos; using YD_Event.Core.Entities; using YD_Event.Core.Enum; @@ -13,15 +14,118 @@ public class PointsRecordService : BaseService, ITransient private readonly ISqlSugarRepository _repository; private readonly ISqlSugarRepository _appUserRepository; private readonly ISqlSugarRepository _merchantRepository; + private readonly ISqlSugarRepository _pointsRuleRepository; + private readonly AuthManager _authManager; public PointsRecordService( ISqlSugarRepository repository, ISqlSugarRepository appUserRepository, - ISqlSugarRepository merchantRepository) : base(repository) + ISqlSugarRepository merchantRepository, + ISqlSugarRepository pointsRuleRepository, + AuthManager authManager) : base(repository) { _repository = repository; _appUserRepository = appUserRepository; _merchantRepository = merchantRepository; + _pointsRuleRepository = pointsRuleRepository; + _authManager = authManager; + } + + /// + /// 获取用户当前积分余额 (PC端) + /// + /// + [DisplayName("获取用户当前积分余额")] + [HttpGet("balance")] + public async Task GetBalance() + { + var userId = _authManager.UserId; + var merchant = await _merchantRepository.GetFirstAsync(m => m.CreatedUserId == userId); + + // 如果是商户/团队账号,查询商户积分;否则查询个人积分 + decimal balance; + if (merchant != null) + { + balance = await _repository.AsQueryable() + .Where(x => x.MerchantId == merchant.Id) + .SumAsync(x => x.Points); + } + else + { + balance = await _repository.AsQueryable() + .Where(x => x.UserId == userId && x.MerchantId == null) // 个人积分需排除作为商户成员的记录(如果有) + .SumAsync(x => x.Points); + } + + return new UserPointsOverviewDto { CurrentBalance = balance }; + } + + /// + /// 查询积分明细列表 (PC端) + /// + /// + /// + [DisplayName("查询积分明细列表")] + [HttpGet("logs")] + public async Task> GetLogs([FromQuery] UserPointsQueryInput input) + { + var userId = _authManager.UserId; + var merchant = await _merchantRepository.GetFirstAsync(m => m.CreatedUserId == userId); + + var query = _repository.AsQueryable() + .LeftJoin((pr, e) => pr.EventId == e.Id) + .LeftJoin((pr, e, p) => pr.ProjectId == p.Id) + .LeftJoin((pr, e, p, pg) => pr.ProjectGroupId == pg.Id) + .LeftJoin((pr, e, p, pg, u) => pr.UserId == u.Id) + .WhereIF(input.Type.HasValue, pr => pr.Type == input.Type) + .WhereIF(!string.IsNullOrWhiteSpace(input.ActionKeyword), (pr, e) => e.EventName.Contains(input.ActionKeyword) || pr.Remark.Contains(input.ActionKeyword)) + .WhereIF(input.StartTime.HasValue, pr => pr.CreatedTime >= input.StartTime) + .WhereIF(input.EndTime.HasValue, pr => pr.CreatedTime <= input.EndTime) + .OrderByDescending(pr => pr.CreatedTime); + + if (merchant != null) + { + // 商户查询:按 MerchantId 过滤 + query = query.Where(pr => pr.MerchantId == merchant.Id); + } + else + { + // 个人查询:按 UserId 过滤,且排除商户记录 + query = query.Where(pr => pr.UserId == userId && pr.MerchantId == null); + } + + var result = await query.Select((pr, e, p, pg, u) => new UserPointsLogDto + { + Id = pr.Id, + Type = pr.Type, + Action = e.EventName ?? pr.Remark ?? "未知动作", + ProjectName = p.Name, + GroupName = pg.GroupName, + ParticipantName = u.Name, // 显示关联用户的姓名 + Rank = 0, // 暂无法直接关联到名次,需业务侧在写入PointsRecord时记录 + Points = pr.Points, + CreatedTime = pr.CreatedTime + }) + .ToPagedListAsync(input); + + return result; + } + + /// + /// 积分规则说明接口 (PC端) + /// + /// + [DisplayName("积分规则说明接口")] + [HttpGet("rules")] + [AllowAnonymous] + public async Task> GetRules() + { + // 返回所有启用的积分规则 + return await _pointsRuleRepository.AsQueryable() + .Where(x => x.Status == AvailabilityStatus.Enable) + .Includes(x => x.Details) // 包含明细 + .OrderBy(x => x.CreatedTime) + .ToListAsync(); } ///