2026-03-07 22:45:51 +08:00
|
|
|
|
using SqlSugar;
|
2026-03-10 16:33:19 +08:00
|
|
|
|
using YD_Event.Application.Auth;
|
2026-01-17 12:52:58 +08:00
|
|
|
|
using YD_Event.Application.Points.Dtos;
|
|
|
|
|
|
using YD_Event.Core.Entities;
|
|
|
|
|
|
using YD_Event.Core.Enum;
|
|
|
|
|
|
|
|
|
|
|
|
namespace YD_Event.Application.Points;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 积分记录管理
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class PointsRecordService : BaseService<PointsRecord>, ITransient
|
|
|
|
|
|
{
|
|
|
|
|
|
private readonly ISqlSugarRepository<PointsRecord> _repository;
|
2026-03-07 22:45:51 +08:00
|
|
|
|
private readonly ISqlSugarRepository<YD_Event.Core.Entities.AppUser> _appUserRepository;
|
2026-03-10 16:33:19 +08:00
|
|
|
|
private readonly ISqlSugarRepository<PointsRule> _pointsRuleRepository;
|
2026-05-08 10:54:08 +08:00
|
|
|
|
private readonly ISqlSugarRepository<YD_Event.Core.Entities.Project> _projectRepository;
|
2026-03-30 17:06:12 +08:00
|
|
|
|
private readonly ISqlSugarClient _db;
|
2026-03-10 16:33:19 +08:00
|
|
|
|
private readonly AuthManager _authManager;
|
2026-01-17 12:52:58 +08:00
|
|
|
|
|
2026-03-07 22:45:51 +08:00
|
|
|
|
public PointsRecordService(
|
|
|
|
|
|
ISqlSugarRepository<PointsRecord> repository,
|
|
|
|
|
|
ISqlSugarRepository<YD_Event.Core.Entities.AppUser> appUserRepository,
|
2026-03-10 16:33:19 +08:00
|
|
|
|
ISqlSugarRepository<PointsRule> pointsRuleRepository,
|
2026-05-08 10:54:08 +08:00
|
|
|
|
ISqlSugarRepository<YD_Event.Core.Entities.Project> projectRepository,
|
2026-03-30 17:06:12 +08:00
|
|
|
|
ISqlSugarClient db,
|
2026-03-10 16:33:19 +08:00
|
|
|
|
AuthManager authManager) : base(repository)
|
2026-01-17 12:52:58 +08:00
|
|
|
|
{
|
|
|
|
|
|
_repository = repository;
|
2026-03-07 22:45:51 +08:00
|
|
|
|
_appUserRepository = appUserRepository;
|
2026-03-10 16:33:19 +08:00
|
|
|
|
_pointsRuleRepository = pointsRuleRepository;
|
2026-05-08 10:54:08 +08:00
|
|
|
|
_projectRepository = projectRepository;
|
2026-03-30 17:06:12 +08:00
|
|
|
|
_db = db;
|
2026-03-10 16:33:19 +08:00
|
|
|
|
_authManager = authManager;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2026-03-12 10:30:13 +08:00
|
|
|
|
/// 获取用户当前积分余额 (PC用户)
|
2026-03-10 16:33:19 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
[DisplayName("获取用户当前积分余额")]
|
|
|
|
|
|
[HttpGet("balance")]
|
|
|
|
|
|
public async Task<UserPointsOverviewDto> GetBalance()
|
|
|
|
|
|
{
|
|
|
|
|
|
var userId = _authManager.UserId;
|
2026-03-30 17:06:12 +08:00
|
|
|
|
var certification = await _db.Queryable<MerchantCertification>()
|
|
|
|
|
|
.FirstAsync(c => c.UserId == userId && c.AuditStatus == AuditStatus.Pass && !c.DeleteMark);
|
2026-03-10 16:33:19 +08:00
|
|
|
|
|
|
|
|
|
|
decimal balance;
|
2026-03-30 17:06:12 +08:00
|
|
|
|
if (certification != null)
|
2026-03-10 16:33:19 +08:00
|
|
|
|
{
|
2026-03-30 17:06:12 +08:00
|
|
|
|
// 单位认证用户:查询单位认证ID的积分
|
2026-03-10 16:33:19 +08:00
|
|
|
|
balance = await _repository.AsQueryable()
|
2026-03-30 17:06:12 +08:00
|
|
|
|
.Where(x => x.MerchantCertificationId == certification.Id)
|
2026-03-10 16:33:19 +08:00
|
|
|
|
.SumAsync(x => x.Points);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2026-03-30 17:06:12 +08:00
|
|
|
|
// 个人用户:查询个人积分
|
2026-03-10 16:33:19 +08:00
|
|
|
|
balance = await _repository.AsQueryable()
|
2026-03-30 17:06:12 +08:00
|
|
|
|
.Where(x => x.UserId == userId && x.MerchantCertificationId == null)
|
2026-03-10 16:33:19 +08:00
|
|
|
|
.SumAsync(x => x.Points);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return new UserPointsOverviewDto { CurrentBalance = balance };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2026-03-12 10:30:13 +08:00
|
|
|
|
/// 查询积分明细列表 (PC用户)
|
2026-03-10 16:33:19 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="input"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
[DisplayName("查询积分明细列表")]
|
|
|
|
|
|
[HttpGet("logs")]
|
|
|
|
|
|
public async Task<PageResult<UserPointsLogDto>> GetLogs([FromQuery] UserPointsQueryInput input)
|
|
|
|
|
|
{
|
|
|
|
|
|
var userId = _authManager.UserId;
|
2026-03-30 17:06:12 +08:00
|
|
|
|
var certification = await _db.Queryable<MerchantCertification>()
|
|
|
|
|
|
.FirstAsync(c => c.UserId == userId && c.AuditStatus == AuditStatus.Pass && !c.DeleteMark);
|
2026-03-10 16:33:19 +08:00
|
|
|
|
|
|
|
|
|
|
var query = _repository.AsQueryable()
|
|
|
|
|
|
.LeftJoin<EventInfo>((pr, e) => pr.EventId == e.Id)
|
2026-04-27 09:18:46 +08:00
|
|
|
|
.LeftJoin<YD_Event.Core.Entities.EventProject>((pr, e, ep) => pr.ProjectId == ep.Id)
|
|
|
|
|
|
.LeftJoin<YD_Event.Core.Entities.Project>((pr, e, ep, p) => ep.ProjectId == p.Id)
|
2026-05-08 13:36:29 +08:00
|
|
|
|
.LeftJoin<EventResult>((pr, e, ep, p, er) => pr.ResultId == er.Id && !er.DeleteMark)
|
|
|
|
|
|
.LeftJoin<YD_Event.Core.Entities.AppUser>((pr, e, ep, p, er, u) => pr.UserId == u.Id)
|
2026-03-10 16:33:19 +08:00
|
|
|
|
.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);
|
|
|
|
|
|
|
2026-03-30 17:06:12 +08:00
|
|
|
|
if (certification != null)
|
2026-03-10 16:33:19 +08:00
|
|
|
|
{
|
2026-03-30 17:06:12 +08:00
|
|
|
|
// 单位认证用户:查询单位认证ID的积分记录
|
|
|
|
|
|
query = query.Where(pr => pr.MerchantCertificationId == certification.Id);
|
2026-03-10 16:33:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2026-03-30 17:06:12 +08:00
|
|
|
|
// 个人查询:按 UserId 过滤,且排除单位认证记录
|
|
|
|
|
|
query = query.Where(pr => pr.UserId == userId && pr.MerchantCertificationId == null);
|
2026-03-10 16:33:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-08 13:36:29 +08:00
|
|
|
|
var result = await query.Select((pr, e, ep, p, er, u) => new UserPointsLogDto
|
2026-03-10 16:33:19 +08:00
|
|
|
|
{
|
|
|
|
|
|
Id = pr.Id,
|
|
|
|
|
|
Type = pr.Type,
|
|
|
|
|
|
Action = e.EventName ?? pr.Remark ?? "未知动作",
|
|
|
|
|
|
ProjectName = p.Name,
|
2026-05-08 13:36:29 +08:00
|
|
|
|
GroupName = er.GroupName,
|
2026-03-10 16:33:19 +08:00
|
|
|
|
ParticipantName = u.Name, // 显示关联用户的姓名
|
2026-04-27 09:18:46 +08:00
|
|
|
|
Rank = er.Rank > 0 ? er.Rank : null, // 使用 EventResult 中的名次
|
2026-03-10 16:33:19 +08:00
|
|
|
|
Points = pr.Points,
|
|
|
|
|
|
CreatedTime = pr.CreatedTime
|
|
|
|
|
|
})
|
|
|
|
|
|
.ToPagedListAsync(input);
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2026-03-12 10:30:13 +08:00
|
|
|
|
/// 积分规则说明接口 (PC用户)
|
2026-03-10 16:33:19 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
[DisplayName("积分规则说明接口")]
|
|
|
|
|
|
[HttpGet("rules")]
|
|
|
|
|
|
[AllowAnonymous]
|
|
|
|
|
|
public async Task<List<PointsRule>> GetRules()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 返回所有启用的积分规则
|
|
|
|
|
|
return await _pointsRuleRepository.AsQueryable()
|
|
|
|
|
|
.Where(x => x.Status == AvailabilityStatus.Enable)
|
|
|
|
|
|
.Includes(x => x.Details) // 包含明细
|
|
|
|
|
|
.OrderBy(x => x.CreatedTime)
|
|
|
|
|
|
.ToListAsync();
|
2026-01-17 12:52:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 积分记录分页查询
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[DisplayName("积分记录分页查询")]
|
2026-03-07 22:45:51 +08:00
|
|
|
|
[HttpGet("list")]
|
|
|
|
|
|
public async Task<PageResult<PointsRecordListOutput>> List([FromQuery] PointsRecordQueryInput input)
|
2026-01-17 12:52:58 +08:00
|
|
|
|
{
|
2026-03-07 22:45:51 +08:00
|
|
|
|
if (input.UserType == 0) // 普通用户
|
|
|
|
|
|
{
|
|
|
|
|
|
var query = _appUserRepository.AsQueryable()
|
|
|
|
|
|
.WhereIF(!string.IsNullOrWhiteSpace(input.Keyword), u =>
|
|
|
|
|
|
u.Name.Contains(input.Keyword) ||
|
|
|
|
|
|
u.Mobile.Contains(input.Keyword));
|
|
|
|
|
|
|
|
|
|
|
|
// 关联查询积分
|
|
|
|
|
|
// 注意:这里需要根据时间范围筛选积分记录,还是筛选最后有积分变动的用户?
|
|
|
|
|
|
// 需求:时间范围筛选。通常指筛选在该时间范围内有积分变动的记录,或者只统计该时间范围内的积分。
|
|
|
|
|
|
// 但“积分额度”通常指总积分。
|
|
|
|
|
|
// 如果时间范围筛选是指“只看某段时间的积分情况”,那么积分额度应该是该段时间内的总和。
|
|
|
|
|
|
// 如果是指“筛选某段时间有活动的用户”,积分额度可能是总积分。
|
|
|
|
|
|
// 考虑到“积分额度排序”,通常是总积分。
|
|
|
|
|
|
// 让我们假设:时间范围筛选是指筛选在该时间范围内有积分变动的用户,积分额度为当前总积分。
|
|
|
|
|
|
// 或者:积分额度 = 该时间范围内的积分总和。
|
|
|
|
|
|
// 根据管理后台惯例,如果有时间筛选,通常列表显示的是该时间段的数据统计。
|
|
|
|
|
|
// 让我们采用:积分额度 = 该时间范围内的积分总和(如果没有时间筛选,就是所有时间)。
|
|
|
|
|
|
|
|
|
|
|
|
// 使用子查询或 LeftJoin 计算积分
|
|
|
|
|
|
var result = await query
|
|
|
|
|
|
.Select(u => new PointsRecordListOutput
|
|
|
|
|
|
{
|
|
|
|
|
|
UserId = u.Id,
|
|
|
|
|
|
UserType = 0,
|
|
|
|
|
|
Name = u.Name,
|
|
|
|
|
|
Phone = u.Mobile,
|
|
|
|
|
|
IdentityInfo = u.IdCardImageUrl, // 身份证图片
|
|
|
|
|
|
TotalPoints = SqlFunc.Subqueryable<PointsRecord>()
|
2026-05-08 13:36:29 +08:00
|
|
|
|
.Where(p => p.UserId == u.Id && !p.DeleteMark && p.MerchantCertificationId == null)
|
2026-03-07 22:45:51 +08:00
|
|
|
|
.WhereIF(input.StartTime.HasValue, p => p.CreatedTime >= input.StartTime)
|
|
|
|
|
|
.WhereIF(input.EndTime.HasValue, p => p.CreatedTime <= input.EndTime)
|
|
|
|
|
|
.Sum(p => p.Points), // 实时计算
|
|
|
|
|
|
LastUpdateTime = SqlFunc.Subqueryable<PointsRecord>()
|
2026-05-08 13:36:29 +08:00
|
|
|
|
.Where(p => p.UserId == u.Id && !p.DeleteMark && p.MerchantCertificationId == null)
|
2026-03-07 22:45:51 +08:00
|
|
|
|
.WhereIF(input.StartTime.HasValue, p => p.CreatedTime >= input.StartTime)
|
|
|
|
|
|
.WhereIF(input.EndTime.HasValue, p => p.CreatedTime <= input.EndTime)
|
|
|
|
|
|
.Max(p => p.CreatedTime)
|
|
|
|
|
|
})
|
|
|
|
|
|
.MergeTable() // 将上面的 Select 结果作为临时表,以便进行后续的 Where 和 OrderBy
|
|
|
|
|
|
.WhereIF(input.StartTime.HasValue || input.EndTime.HasValue, x => x.LastUpdateTime != null) // 如果有时间筛选,只显示有记录的用户
|
|
|
|
|
|
.OrderByIF(!string.IsNullOrWhiteSpace(input.SortPoints), x => x.TotalPoints, input.SortPoints == "asc" ? OrderByType.Asc : OrderByType.Desc)
|
|
|
|
|
|
.OrderByDescending(x => x.LastUpdateTime) // 默认按更新时间倒序
|
|
|
|
|
|
.ToPagedListAsync(input);
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
else // 单位用户
|
|
|
|
|
|
{
|
2026-04-21 11:43:49 +08:00
|
|
|
|
// 单位用户:查询SysUser,关联MerchantCertification
|
|
|
|
|
|
var query = _db.Queryable<SysUser>()
|
|
|
|
|
|
.InnerJoin<MerchantCertification>((s, m) => s.Id == m.UserId && !m.DeleteMark)
|
|
|
|
|
|
.Where((s, m) => !s.DeleteMark)
|
|
|
|
|
|
.WhereIF(!string.IsNullOrWhiteSpace(input.Keyword), (s, m) =>
|
|
|
|
|
|
s.Name.Contains(input.Keyword) ||
|
|
|
|
|
|
m.MerchantName.Contains(input.Keyword) ||
|
2026-03-07 22:45:51 +08:00
|
|
|
|
m.ContactPhone.Contains(input.Keyword));
|
|
|
|
|
|
|
|
|
|
|
|
var result = await query
|
2026-04-21 11:43:49 +08:00
|
|
|
|
.Select((s, m) => new PointsRecordListOutput
|
2026-03-07 22:45:51 +08:00
|
|
|
|
{
|
2026-04-21 11:43:49 +08:00
|
|
|
|
UserId = m.Id, // 使用MerchantCertificationId作为标识
|
2026-03-07 22:45:51 +08:00
|
|
|
|
UserType = 1,
|
2026-04-21 11:43:49 +08:00
|
|
|
|
Name = m.MerchantName, // 显示单位名称
|
2026-03-07 22:45:51 +08:00
|
|
|
|
Phone = m.ContactPhone,
|
|
|
|
|
|
IdentityInfo = m.CreditCode, // 统一社会信用代码
|
|
|
|
|
|
TotalPoints = SqlFunc.Subqueryable<PointsRecord>()
|
2026-04-22 11:40:12 +08:00
|
|
|
|
.Where(p => p.MerchantCertificationId == m.Id && !p.DeleteMark)
|
|
|
|
|
|
.WhereIF(input.StartTime.HasValue, p => p.CreatedTime >= input.StartTime)
|
|
|
|
|
|
.WhereIF(input.EndTime.HasValue, p => p.CreatedTime <= input.EndTime)
|
|
|
|
|
|
.Sum(p => p.Points),
|
2026-03-07 22:45:51 +08:00
|
|
|
|
LastUpdateTime = SqlFunc.Subqueryable<PointsRecord>()
|
2026-04-22 11:40:12 +08:00
|
|
|
|
.Where(p => p.MerchantCertificationId == m.Id && !p.DeleteMark)
|
|
|
|
|
|
.WhereIF(input.StartTime.HasValue, p => p.CreatedTime >= input.StartTime)
|
|
|
|
|
|
.WhereIF(input.EndTime.HasValue, p => p.CreatedTime <= input.EndTime)
|
|
|
|
|
|
.Max(p => p.CreatedTime)
|
2026-03-07 22:45:51 +08:00
|
|
|
|
})
|
|
|
|
|
|
.MergeTable()
|
|
|
|
|
|
.WhereIF(input.StartTime.HasValue || input.EndTime.HasValue, x => x.LastUpdateTime != null)
|
|
|
|
|
|
.OrderByIF(!string.IsNullOrWhiteSpace(input.SortPoints), x => x.TotalPoints, input.SortPoints == "asc" ? OrderByType.Asc : OrderByType.Desc)
|
|
|
|
|
|
.OrderByDescending(x => x.LastUpdateTime)
|
|
|
|
|
|
.ToPagedListAsync(input);
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
2026-01-17 12:52:58 +08:00
|
|
|
|
}
|
2026-03-07 22:45:51 +08:00
|
|
|
|
|
2026-01-17 12:52:58 +08:00
|
|
|
|
/// <summary>
|
2026-03-07 22:45:51 +08:00
|
|
|
|
/// 积分明细查询
|
2026-01-17 12:52:58 +08:00
|
|
|
|
/// </summary>
|
2026-03-07 22:45:51 +08:00
|
|
|
|
[DisplayName("积分明细查询")]
|
|
|
|
|
|
[HttpGet("detail/{userId}")]
|
|
|
|
|
|
public async Task<PageResult<PointsDetailOutput>> Detail([FromQuery] PointsDetailQueryInput input)
|
2026-01-17 12:52:58 +08:00
|
|
|
|
{
|
2026-03-07 22:45:51 +08:00
|
|
|
|
if (input.UserType == 0) // 普通用户
|
|
|
|
|
|
{
|
2026-04-21 11:43:49 +08:00
|
|
|
|
var query = _repository.AsQueryable()
|
|
|
|
|
|
.LeftJoin<EventInfo>((p, e) => p.EventId == e.Id)
|
2026-05-08 09:25:07 +08:00
|
|
|
|
.LeftJoin<EventProject>((p, e, ep) => p.ProjectId == ep.Id)
|
|
|
|
|
|
.LeftJoin<YD_Event.Core.Entities.Project>((p, e, ep, pr) => ep.ProjectId == pr.Id)
|
2026-05-08 13:36:29 +08:00
|
|
|
|
.LeftJoin<EventResult>((p, e, ep, pr, er) => p.ResultId == er.Id && !er.DeleteMark)
|
|
|
|
|
|
.Where((p, e, ep, pr, er) => !p.DeleteMark)
|
|
|
|
|
|
.Where((p, e, ep, pr, er) => p.UserId == input.UserId)
|
|
|
|
|
|
.Where((p, e, ep, pr, er) => p.MerchantCertificationId == null)
|
|
|
|
|
|
.WhereIF(input.Type.HasValue, (p, e, ep, pr, er) => p.Type == input.Type)
|
|
|
|
|
|
.OrderByDescending((p, e, ep, pr, er) => p.CreatedTime);
|
2026-03-07 22:45:51 +08:00
|
|
|
|
|
|
|
|
|
|
return await query
|
2026-05-08 13:36:29 +08:00
|
|
|
|
.Select((p, e, ep, pr, er) => new PointsDetailOutput
|
2026-03-07 22:45:51 +08:00
|
|
|
|
{
|
|
|
|
|
|
CreatedTime = p.CreatedTime,
|
|
|
|
|
|
Type = p.Type,
|
|
|
|
|
|
Action = e.EventName,
|
|
|
|
|
|
Item = pr.Name,
|
2026-05-08 13:36:29 +08:00
|
|
|
|
Group = er.GroupName,
|
2026-03-07 22:45:51 +08:00
|
|
|
|
Points = p.Points,
|
|
|
|
|
|
Remark = p.Remark
|
|
|
|
|
|
}).ToPagedListAsync(input);
|
2026-01-17 12:52:58 +08:00
|
|
|
|
|
2026-03-07 22:45:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
else // 单位用户
|
2026-01-17 12:52:58 +08:00
|
|
|
|
{
|
2026-04-22 11:40:12 +08:00
|
|
|
|
// 单位用户:查询该单位认证下所有PointsRecord的积分记录
|
2026-04-21 11:43:49 +08:00
|
|
|
|
// input.UserId 在这里是 MerchantCertificationId
|
|
|
|
|
|
var query = _repository.AsQueryable()
|
|
|
|
|
|
.LeftJoin<EventInfo>((p, e) => p.EventId == e.Id)
|
2026-05-08 09:25:07 +08:00
|
|
|
|
.LeftJoin<EventProject>((p, e, ep) => p.ProjectId == ep.Id)
|
|
|
|
|
|
.LeftJoin<YD_Event.Core.Entities.Project>((p, e, ep, pr) => ep.ProjectId == pr.Id)
|
2026-05-08 13:36:29 +08:00
|
|
|
|
.LeftJoin<YD_Event.Core.Entities.AppUser>((p, e, ep, pr, u) => p.UserId == u.Id && !u.DeleteMark)
|
|
|
|
|
|
.LeftJoin<EventResult>((p, e, ep, pr, u, er) => p.ResultId == er.Id && !er.DeleteMark)
|
|
|
|
|
|
.LeftJoin<EventRegistrationPerson>((p, e, ep, pr, u, er, per) => er.RegistrationPersonId == per.Id && !per.DeleteMark)
|
|
|
|
|
|
.Where((p, e, ep, pr, u, er, per) => !p.DeleteMark)
|
|
|
|
|
|
.Where((p, e, ep, pr, u, er, per) => p.MerchantCertificationId == input.UserId)
|
|
|
|
|
|
.WhereIF(input.Type.HasValue, (p, e, ep, pr, u, er, per) => p.Type == input.Type)
|
|
|
|
|
|
.OrderByDescending((p, e, ep, pr, u, er, per) => p.CreatedTime);
|
2026-03-07 22:45:51 +08:00
|
|
|
|
|
2026-05-08 10:54:08 +08:00
|
|
|
|
var rawData = await query
|
2026-05-08 13:36:29 +08:00
|
|
|
|
.Select((p, e, ep, pr, u, er, per) => new
|
2026-03-07 22:45:51 +08:00
|
|
|
|
{
|
2026-05-08 10:54:08 +08:00
|
|
|
|
PointRecordId = p.Id,
|
2026-03-07 22:45:51 +08:00
|
|
|
|
CreatedTime = p.CreatedTime,
|
|
|
|
|
|
Type = p.Type,
|
|
|
|
|
|
Action = e.EventName,
|
|
|
|
|
|
Item = pr.Name,
|
2026-05-08 10:54:08 +08:00
|
|
|
|
ProjectId = pr.Id,
|
2026-05-08 13:36:29 +08:00
|
|
|
|
Group = er.GroupName,
|
2026-03-07 22:45:51 +08:00
|
|
|
|
Points = p.Points,
|
|
|
|
|
|
Remark = p.Remark,
|
2026-05-08 10:54:08 +08:00
|
|
|
|
ParticipantName = u.Name,
|
|
|
|
|
|
ParticipantId = u.Id,
|
|
|
|
|
|
RegistrationItemId = per.RegistrationItemId
|
|
|
|
|
|
})
|
|
|
|
|
|
.ToListAsync();
|
|
|
|
|
|
|
|
|
|
|
|
// 收集所有项目ID
|
|
|
|
|
|
var projectIds = rawData.Where(d => d.ProjectId > 0).Select(d => d.ProjectId).Distinct().ToList();
|
|
|
|
|
|
// 获取项目信息,判断是否是团队项目
|
|
|
|
|
|
var projects = new Dictionary<long, YD_Event.Core.Entities.Project>();
|
|
|
|
|
|
if (projectIds.Any())
|
|
|
|
|
|
{
|
|
|
|
|
|
var projectList = await _projectRepository.GetListAsync(p => projectIds.Contains(p.Id));
|
|
|
|
|
|
projects = projectList.ToDictionary(p => p.Id);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理数据
|
|
|
|
|
|
var processedData = new List<PointsDetailOutput>();
|
|
|
|
|
|
var teamRegistrationItemIds = new List<long>();
|
|
|
|
|
|
|
|
|
|
|
|
// 先处理团队项目,收集需要查询的 RegistrationItemId
|
|
|
|
|
|
foreach (var item in rawData)
|
|
|
|
|
|
{
|
|
|
|
|
|
var isTeamProject = false;
|
|
|
|
|
|
if (item.ProjectId > 0 && projects.TryGetValue(item.ProjectId, out var project))
|
|
|
|
|
|
{
|
|
|
|
|
|
isTeamProject = project.ProjectType == YD_Event.Core.Enum.ProjectTypeEnum.TeamSpeed ||
|
|
|
|
|
|
project.ProjectType == YD_Event.Core.Enum.ProjectTypeEnum.TeamFreestyle;
|
|
|
|
|
|
}
|
2026-03-07 22:45:51 +08:00
|
|
|
|
|
2026-05-08 10:54:08 +08:00
|
|
|
|
if (isTeamProject)
|
|
|
|
|
|
{
|
|
|
|
|
|
teamRegistrationItemIds.Add(item.RegistrationItemId);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 查询团队项目的团队成员
|
|
|
|
|
|
Dictionary<long, string> teamPersonDict = new Dictionary<long, string>();
|
|
|
|
|
|
if (teamRegistrationItemIds.Any())
|
|
|
|
|
|
{
|
|
|
|
|
|
var distinctTeamIds = teamRegistrationItemIds.Distinct().ToList();
|
|
|
|
|
|
// 查询同一 RegistrationItemId 的所有 EventRegistrationPerson,获取姓名
|
|
|
|
|
|
var teamPersons = await _db.Queryable<EventRegistrationPerson>()
|
|
|
|
|
|
.Where(per => distinctTeamIds.Contains(per.RegistrationItemId) && !per.DeleteMark)
|
|
|
|
|
|
.Select(per => new { per.RegistrationItemId, per.Name })
|
|
|
|
|
|
.ToListAsync();
|
|
|
|
|
|
|
|
|
|
|
|
// 按 RegistrationItemId 分组
|
|
|
|
|
|
teamPersonDict = teamPersons
|
|
|
|
|
|
.GroupBy(p => p.RegistrationItemId)
|
|
|
|
|
|
.ToDictionary(
|
|
|
|
|
|
g => g.Key,
|
|
|
|
|
|
g => string.Join(", ", g.Select(p => p.Name).Distinct().OrderBy(n => n))
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 构建最终输出
|
|
|
|
|
|
foreach (var item in rawData)
|
|
|
|
|
|
{
|
|
|
|
|
|
var isTeamProject = false;
|
|
|
|
|
|
if (item.ProjectId > 0 && projects.TryGetValue(item.ProjectId, out var project))
|
|
|
|
|
|
{
|
|
|
|
|
|
isTeamProject = project.ProjectType == YD_Event.Core.Enum.ProjectTypeEnum.TeamSpeed ||
|
|
|
|
|
|
project.ProjectType == YD_Event.Core.Enum.ProjectTypeEnum.TeamFreestyle;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string participantName = item.ParticipantName;
|
|
|
|
|
|
if (isTeamProject)
|
|
|
|
|
|
{
|
|
|
|
|
|
string names;
|
|
|
|
|
|
if (teamPersonDict.TryGetValue(item.RegistrationItemId, out names))
|
|
|
|
|
|
{
|
|
|
|
|
|
participantName = names;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
processedData.Add(new PointsDetailOutput
|
|
|
|
|
|
{
|
|
|
|
|
|
CreatedTime = item.CreatedTime,
|
|
|
|
|
|
Type = item.Type,
|
|
|
|
|
|
Action = item.Action,
|
|
|
|
|
|
Item = item.Item,
|
|
|
|
|
|
Group = item.Group,
|
|
|
|
|
|
Points = item.Points,
|
|
|
|
|
|
Remark = item.Remark,
|
|
|
|
|
|
ParticipantName = participantName,
|
|
|
|
|
|
ParticipantId = item.ParticipantId
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 重新排序
|
|
|
|
|
|
processedData = processedData.OrderByDescending(x => x.CreatedTime).ToList();
|
|
|
|
|
|
|
|
|
|
|
|
// 手动分页
|
|
|
|
|
|
var total = processedData.Count;
|
|
|
|
|
|
var pageSize = input.PageSize > 0 ? input.PageSize : 10;
|
|
|
|
|
|
var pageNo = input.PageNo > 0 ? input.PageNo - 1 : 0;
|
|
|
|
|
|
var pagedData = processedData.Skip(pageNo * pageSize).Take(pageSize).ToList();
|
|
|
|
|
|
|
|
|
|
|
|
return new PageResult<PointsDetailOutput>
|
|
|
|
|
|
{
|
|
|
|
|
|
PageNo = input.PageNo,
|
|
|
|
|
|
PageSize = pageSize,
|
|
|
|
|
|
Total = total,
|
|
|
|
|
|
Pages = (int)Math.Ceiling((double)total / pageSize),
|
|
|
|
|
|
Rows = pagedData
|
|
|
|
|
|
};
|
2026-03-07 22:45:51 +08:00
|
|
|
|
}
|
2026-01-17 12:52:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|