小程序金额计算
This commit is contained in:
parent
d573fb73c4
commit
532ad46ca0
@ -454,22 +454,23 @@ public class MyController : IDynamicApiController
|
||||
.LeftJoin<EventProject>((p, e, ep) => p.ProjectId == ep.Id)
|
||||
.LeftJoin<ProjectEntity>((p, e, ep, pr) => ep.ProjectId == pr.Id)
|
||||
.LeftJoin<EventProjectGroup>((p, e, ep, pr, pg) => p.ProjectGroupId == pg.Id)
|
||||
.LeftJoin<EventResult>((p, e, ep, pr, pg, r) => p.ResultId == r.Id && !r.DeleteMark)
|
||||
// 小程序端只查看个人积分:UserId = 当前用户且 MerchantCertificationId = null
|
||||
.Where((p, e, ep, pr, pg) => p.UserId == userId && p.MerchantCertificationId == null && !p.DeleteMark);
|
||||
.Where((p, e, ep, pr, pg, r) => p.UserId == userId && p.MerchantCertificationId == null && !p.DeleteMark);
|
||||
|
||||
if (input.Type.HasValue)
|
||||
{
|
||||
var typeFilter = (PointsOperationType)input.Type.Value;
|
||||
query = query.Where((p, e, ep, pr, pg) => p.Type == typeFilter);
|
||||
query = query.Where((p, e, ep, pr, pg, r) => p.Type == typeFilter);
|
||||
}
|
||||
|
||||
// 如果前端指定了 MerchantCertificationId,优先使用前端的(保持向后兼容)
|
||||
if (input.MerchantCertificationId.HasValue)
|
||||
{
|
||||
query = query.Where((p, e, ep, pr, pg) => p.MerchantCertificationId == input.MerchantCertificationId.Value);
|
||||
query = query.Where((p, e, ep, pr, pg, r) => p.MerchantCertificationId == input.MerchantCertificationId.Value);
|
||||
}
|
||||
|
||||
var resultQuery = query.Select((p, e, ep, pr, pg) => new MyPointsRecordDto
|
||||
var resultQuery = query.Select((p, e, ep, pr, pg, r) => new MyPointsRecordDto
|
||||
{
|
||||
Id = p.Id,
|
||||
Title = p.Remark ?? (p.Type == PointsOperationType.Acquire ? "获取积分" : "消耗积分"),
|
||||
@ -479,7 +480,7 @@ public class MyController : IDynamicApiController
|
||||
Points = p.Points,
|
||||
Type = (int)p.Type,
|
||||
CreatedTime = p.CreatedTime,
|
||||
Rank = 1 // 积分记录表暂无名次字段,后续若有需要可补充
|
||||
Rank = r.Rank > 0 ? r.Rank : null // 从成绩记录中获取名次
|
||||
})
|
||||
.OrderByDescending(p => p.CreatedTime);
|
||||
|
||||
|
||||
@ -1653,6 +1653,15 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
.OrderBy(x => x.StartRank)
|
||||
.ToListAsync();
|
||||
|
||||
// 获取所有 EventProject 和对应的 Project 信息,用于判断项目类型
|
||||
var eventProjects = await _eventProjectRepository.AsQueryable()
|
||||
.Where(ep => ep.EventId == input.EventId)
|
||||
.ToListAsync();
|
||||
var projectIds = eventProjects.Select(ep => ep.ProjectId).Distinct().ToList();
|
||||
var projects = await _projectRepository.GetListAsync(p => projectIds.Contains(p.Id));
|
||||
var projectDict = projects.ToDictionary(p => p.Id);
|
||||
|
||||
// 查询所有成绩记录,包含 RegistrationItemId
|
||||
var results = await _resultRepository.AsQueryable()
|
||||
.InnerJoin<EventRegistrationPerson>((r, p) => r.RegistrationPersonId == p.Id)
|
||||
.Where((r, p) => r.EventId == input.EventId && r.Rank > 0)
|
||||
@ -1665,7 +1674,8 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
Rank = r.Rank,
|
||||
ParticipantName = r.ParticipantName,
|
||||
ProjectGroupId = p.EventProjectGroupId,
|
||||
RegistrationId = p.RegistrationId
|
||||
RegistrationId = p.RegistrationId,
|
||||
RegistrationItemId = p.RegistrationItemId
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
@ -1688,54 +1698,156 @@ public class EventScoreService : BaseService<EventResult>, ITransient
|
||||
int successCount = 0;
|
||||
int skipCount = 0;
|
||||
var pointsRecords = new List<PointsRecord>();
|
||||
var processedTeams = new HashSet<string>();
|
||||
|
||||
foreach (var result in results)
|
||||
// 先按 ProjectId 分组
|
||||
var projectGroups = results.GroupBy(r => r.ProjectId);
|
||||
|
||||
foreach (var projectGroup in projectGroups)
|
||||
{
|
||||
if (processedResultIds.Contains(result.ResultId))
|
||||
var projectId = projectGroup.Key;
|
||||
var eventProject = eventProjects.FirstOrDefault(ep => ep.Id == projectId);
|
||||
if (eventProject == null || !projectDict.TryGetValue(eventProject.ProjectId, out var project))
|
||||
{
|
||||
skipCount++;
|
||||
// 找不到项目,跳过
|
||||
foreach (var result in projectGroup)
|
||||
{
|
||||
skipCount++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
int pointsToAward = 0;
|
||||
var isTeamProject = project.ProjectType == ProjectTypeEnum.TeamSpeed ||
|
||||
project.ProjectType == ProjectTypeEnum.TeamFreestyle;
|
||||
|
||||
if (pointsRule.ParticipationPoints.HasValue && pointsRule.ParticipationPoints.Value > 0)
|
||||
if (isTeamProject)
|
||||
{
|
||||
pointsToAward += pointsRule.ParticipationPoints.Value;
|
||||
}
|
||||
|
||||
var matchingDetail = ruleDetails.FirstOrDefault(d => result.Rank >= d.StartRank && result.Rank <= d.EndRank);
|
||||
if (matchingDetail != null)
|
||||
{
|
||||
pointsToAward += matchingDetail.Points;
|
||||
}
|
||||
|
||||
if (pointsToAward > 0)
|
||||
{
|
||||
// 从 EventRegistration 获取归属单位 ID
|
||||
long? merchantCertId = null;
|
||||
if (registrationDict.TryGetValue(result.RegistrationId, out var reg))
|
||||
// 团队项目:按 RegistrationItemId 分组,每组只发放一条记录
|
||||
var teamGroups = projectGroup.GroupBy(r => new { r.RegistrationItemId, r.ProjectGroupId, r.GroupName });
|
||||
foreach (var teamGroup in teamGroups)
|
||||
{
|
||||
merchantCertId = reg.MerchantCertificationId;
|
||||
var groupKey = $"team_{teamGroup.Key.RegistrationItemId}_{teamGroup.Key.ProjectGroupId}";
|
||||
if (processedTeams.Contains(groupKey))
|
||||
{
|
||||
// 这个团队已经发过了
|
||||
skipCount += teamGroup.Count();
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查团队中是否有结果已发放
|
||||
var hasProcessed = teamGroup.Any(r => processedResultIds.Contains(r.ResultId));
|
||||
if (hasProcessed)
|
||||
{
|
||||
skipCount += teamGroup.Count();
|
||||
continue;
|
||||
}
|
||||
|
||||
// 取团队第一个成员计算积分
|
||||
var teamResult = teamGroup.OrderBy(r => r.ResultId).First();
|
||||
|
||||
int pointsToAward = 0;
|
||||
|
||||
if (pointsRule.ParticipationPoints.HasValue && pointsRule.ParticipationPoints.Value > 0)
|
||||
{
|
||||
pointsToAward += pointsRule.ParticipationPoints.Value;
|
||||
}
|
||||
|
||||
var matchingDetail = ruleDetails.FirstOrDefault(d => teamResult.Rank >= d.StartRank && teamResult.Rank <= d.EndRank);
|
||||
if (matchingDetail != null)
|
||||
{
|
||||
pointsToAward += matchingDetail.Points;
|
||||
}
|
||||
|
||||
if (pointsToAward > 0)
|
||||
{
|
||||
// 从 EventRegistration 获取归属单位 ID
|
||||
long? merchantCertId = null;
|
||||
if (registrationDict.TryGetValue(teamResult.RegistrationId, out var reg))
|
||||
{
|
||||
merchantCertId = reg.MerchantCertificationId;
|
||||
}
|
||||
|
||||
var record = new PointsRecord
|
||||
{
|
||||
Id = _idGenerator.NextId(),
|
||||
UserId = teamResult.UserId,
|
||||
Type = PointsOperationType.Acquire,
|
||||
EventId = input.EventId,
|
||||
ProjectId = teamResult.ProjectId,
|
||||
ProjectGroupId = teamResult.ProjectGroupId,
|
||||
ResultId = teamResult.ResultId,
|
||||
MerchantCertificationId = merchantCertId,
|
||||
Points = pointsToAward,
|
||||
Remark = eventInfo.EventName,
|
||||
Status = AvailabilityStatus.Enable,
|
||||
CreatedTime = DateTime.Now
|
||||
};
|
||||
pointsRecords.Add(record);
|
||||
successCount++;
|
||||
processedTeams.Add(groupKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
skipCount += teamGroup.Count();
|
||||
}
|
||||
}
|
||||
|
||||
var record = new PointsRecord
|
||||
}
|
||||
else
|
||||
{
|
||||
// 个人项目:按原来的逻辑处理
|
||||
foreach (var result in projectGroup)
|
||||
{
|
||||
Id = _idGenerator.NextId(),
|
||||
UserId = result.UserId,
|
||||
Type = PointsOperationType.Acquire,
|
||||
EventId = input.EventId,
|
||||
ProjectId = result.ProjectId,
|
||||
ProjectGroupId = result.ProjectGroupId,
|
||||
ResultId = result.ResultId,
|
||||
MerchantCertificationId = merchantCertId,
|
||||
Points = pointsToAward,
|
||||
Remark = eventInfo.EventName,
|
||||
Status = AvailabilityStatus.Enable,
|
||||
CreatedTime = DateTime.Now
|
||||
};
|
||||
pointsRecords.Add(record);
|
||||
successCount++;
|
||||
if (processedResultIds.Contains(result.ResultId))
|
||||
{
|
||||
skipCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
int pointsToAward = 0;
|
||||
|
||||
if (pointsRule.ParticipationPoints.HasValue && pointsRule.ParticipationPoints.Value > 0)
|
||||
{
|
||||
pointsToAward += pointsRule.ParticipationPoints.Value;
|
||||
}
|
||||
|
||||
var matchingDetail = ruleDetails.FirstOrDefault(d => result.Rank >= d.StartRank && result.Rank <= d.EndRank);
|
||||
if (matchingDetail != null)
|
||||
{
|
||||
pointsToAward += matchingDetail.Points;
|
||||
}
|
||||
|
||||
if (pointsToAward > 0)
|
||||
{
|
||||
// 从 EventRegistration 获取归属单位 ID
|
||||
long? merchantCertId = null;
|
||||
if (registrationDict.TryGetValue(result.RegistrationId, out var reg))
|
||||
{
|
||||
merchantCertId = reg.MerchantCertificationId;
|
||||
}
|
||||
|
||||
var record = new PointsRecord
|
||||
{
|
||||
Id = _idGenerator.NextId(),
|
||||
UserId = result.UserId,
|
||||
Type = PointsOperationType.Acquire,
|
||||
EventId = input.EventId,
|
||||
ProjectId = result.ProjectId,
|
||||
ProjectGroupId = result.ProjectGroupId,
|
||||
ResultId = result.ResultId,
|
||||
MerchantCertificationId = merchantCertId,
|
||||
Points = pointsToAward,
|
||||
Remark = eventInfo.EventName,
|
||||
Status = AvailabilityStatus.Enable,
|
||||
CreatedTime = DateTime.Now
|
||||
};
|
||||
pointsRecords.Add(record);
|
||||
successCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
skipCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1960,7 +1960,18 @@ public class UnifiedRegistrationService : ITransient
|
||||
var projectIds = eventProjects.Select(ep => ep.ProjectId).Distinct().ToList();
|
||||
var baseProjects = await _projectRepository.GetListAsync(x => projectIds.Contains(x.Id));
|
||||
|
||||
int totalParticipantCount = items.Sum(i => i.PersonCount);
|
||||
// 根据收费模式决定使用哪种人数计算金额(和 CreateRegistrationDetailsAsync 保持一致)
|
||||
int countForCalculation;
|
||||
if (feeConfig != null && feeConfig.ChargeMode == ChargeMode.UnitPriceEvent)
|
||||
{
|
||||
// 单价(赛事)模式:预览时默认按1个人计算(因为是同一个用户报名多个项目)
|
||||
countForCalculation = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 其他模式(包括单价项目):使用实际人数
|
||||
countForCalculation = items.Sum(i => i.PersonCount);
|
||||
}
|
||||
|
||||
var unifiedItems = items.Select(i => new UnifiedRegistrationItemInput
|
||||
{
|
||||
@ -1968,7 +1979,7 @@ public class UnifiedRegistrationService : ITransient
|
||||
Persons = new List<UnifiedPersonInput>(new UnifiedPersonInput[i.PersonCount])
|
||||
}).ToList();
|
||||
|
||||
var totalAmount = CalculateTotalAmount(feeConfig, eventProjects, unifiedItems, totalParticipantCount);
|
||||
var totalAmount = CalculateTotalAmount(feeConfig, eventProjects, unifiedItems, countForCalculation);
|
||||
|
||||
var eventProjectsDict = eventProjects.ToDictionary(p => p.Id);
|
||||
var baseProjectsDict = baseProjects.ToDictionary(p => p.Id);
|
||||
|
||||
@ -14,6 +14,7 @@ public class PointsRecordService : BaseService<PointsRecord>, ITransient
|
||||
private readonly ISqlSugarRepository<PointsRecord> _repository;
|
||||
private readonly ISqlSugarRepository<YD_Event.Core.Entities.AppUser> _appUserRepository;
|
||||
private readonly ISqlSugarRepository<PointsRule> _pointsRuleRepository;
|
||||
private readonly ISqlSugarRepository<YD_Event.Core.Entities.Project> _projectRepository;
|
||||
private readonly ISqlSugarClient _db;
|
||||
private readonly AuthManager _authManager;
|
||||
|
||||
@ -21,12 +22,14 @@ public class PointsRecordService : BaseService<PointsRecord>, ITransient
|
||||
ISqlSugarRepository<PointsRecord> repository,
|
||||
ISqlSugarRepository<YD_Event.Core.Entities.AppUser> appUserRepository,
|
||||
ISqlSugarRepository<PointsRule> pointsRuleRepository,
|
||||
ISqlSugarRepository<YD_Event.Core.Entities.Project> projectRepository,
|
||||
ISqlSugarClient db,
|
||||
AuthManager authManager) : base(repository)
|
||||
{
|
||||
_repository = repository;
|
||||
_appUserRepository = appUserRepository;
|
||||
_pointsRuleRepository = pointsRuleRepository;
|
||||
_projectRepository = projectRepository;
|
||||
_db = db;
|
||||
_authManager = authManager;
|
||||
}
|
||||
@ -269,25 +272,133 @@ public class PointsRecordService : BaseService<PointsRecord>, ITransient
|
||||
.LeftJoin<YD_Event.Core.Entities.Project>((p, e, ep, pr) => ep.ProjectId == pr.Id)
|
||||
.LeftJoin<ProjectGroup>((p, e, ep, pr, pg) => p.ProjectGroupId == pg.Id)
|
||||
.LeftJoin<YD_Event.Core.Entities.AppUser>((p, e, ep, pr, pg, u) => p.UserId == u.Id && !u.DeleteMark)
|
||||
.Where((p, e, ep, pr, pg, u) => !p.DeleteMark)
|
||||
.Where((p, e, ep, pr, pg, u) => p.MerchantCertificationId == input.UserId)
|
||||
.WhereIF(input.Type.HasValue, (p, e, ep, pr, pg, u) => p.Type == input.Type)
|
||||
.OrderByDescending((p, e, ep, pr, pg, u) => p.CreatedTime);
|
||||
.LeftJoin<EventResult>((p, e, ep, pr, pg, u, er) => p.ResultId == er.Id && !er.DeleteMark)
|
||||
.LeftJoin<EventRegistrationPerson>((p, e, ep, pr, pg, u, er, per) => er.RegistrationPersonId == per.Id && !per.DeleteMark)
|
||||
.Where((p, e, ep, pr, pg, u, er, per) => !p.DeleteMark)
|
||||
.Where((p, e, ep, pr, pg, u, er, per) => p.MerchantCertificationId == input.UserId)
|
||||
.WhereIF(input.Type.HasValue, (p, e, ep, pr, pg, u, er, per) => p.Type == input.Type)
|
||||
.OrderByDescending((p, e, ep, pr, pg, u, er, per) => p.CreatedTime);
|
||||
|
||||
return await query
|
||||
.Select((p, e, ep, pr, pg, u) => new PointsDetailOutput
|
||||
var rawData = await query
|
||||
.Select((p, e, ep, pr, pg, u, er, per) => new
|
||||
{
|
||||
PointRecordId = p.Id,
|
||||
CreatedTime = p.CreatedTime,
|
||||
Type = p.Type,
|
||||
Action = e.EventName,
|
||||
Item = pr.Name,
|
||||
ProjectId = pr.Id,
|
||||
ProjectType = pr.ProjectType,
|
||||
Group = pg.GroupName,
|
||||
Points = p.Points,
|
||||
Remark = p.Remark,
|
||||
ParticipantName = u.Name, // 参赛人姓名
|
||||
ParticipantId = u.Id // 参赛人ID
|
||||
}).ToPagedListAsync(input);
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user