2026-03-01 22:32:44 +08:00
|
|
|
|
using YD_Event.Application.Project.Dtos;
|
|
|
|
|
|
using YD_Event.Core.Entities;
|
2026-04-12 16:11:20 +08:00
|
|
|
|
using YD_Event.Core.Enum;
|
2026-03-08 15:46:19 +08:00
|
|
|
|
using Mapster;
|
|
|
|
|
|
using SqlSugar;
|
2026-03-31 17:38:36 +08:00
|
|
|
|
using Microsoft.Extensions.Logging;
|
2026-04-12 16:11:20 +08:00
|
|
|
|
using Easy.Core;
|
2026-03-01 22:32:44 +08:00
|
|
|
|
|
|
|
|
|
|
namespace YD_Event.Application.Project;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 项目管理
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class ProjectService : BaseService<YD_Event.Core.Entities.Project>, ITransient
|
|
|
|
|
|
{
|
|
|
|
|
|
private readonly ISqlSugarRepository<YD_Event.Core.Entities.Project> _repository;
|
|
|
|
|
|
private readonly ISqlSugarRepository<ProjectGroup> _groupRepository;
|
2026-03-31 17:38:36 +08:00
|
|
|
|
private readonly ISqlSugarRepository<EventProject> _eventProjectRepository;
|
|
|
|
|
|
private readonly ISqlSugarRepository<EventParticipationRecord> _participationRecordRepository;
|
2026-03-01 22:32:44 +08:00
|
|
|
|
private readonly IIdGenerator _idGenerator;
|
2026-03-31 17:38:36 +08:00
|
|
|
|
private readonly ILogger<ProjectService> _logger;
|
2026-03-01 22:32:44 +08:00
|
|
|
|
|
|
|
|
|
|
public ProjectService(
|
|
|
|
|
|
ISqlSugarRepository<YD_Event.Core.Entities.Project> repository,
|
|
|
|
|
|
ISqlSugarRepository<ProjectGroup> groupRepository,
|
2026-03-31 17:38:36 +08:00
|
|
|
|
ISqlSugarRepository<EventProject> eventProjectRepository,
|
|
|
|
|
|
ISqlSugarRepository<EventParticipationRecord> participationRecordRepository,
|
|
|
|
|
|
IIdGenerator idGenerator,
|
|
|
|
|
|
ILogger<ProjectService> logger) : base(repository)
|
2026-03-01 22:32:44 +08:00
|
|
|
|
{
|
|
|
|
|
|
_repository = repository;
|
|
|
|
|
|
_groupRepository = groupRepository;
|
2026-03-31 17:38:36 +08:00
|
|
|
|
_eventProjectRepository = eventProjectRepository;
|
|
|
|
|
|
_participationRecordRepository = participationRecordRepository;
|
2026-03-01 22:32:44 +08:00
|
|
|
|
_idGenerator = idGenerator;
|
2026-03-31 17:38:36 +08:00
|
|
|
|
_logger = logger;
|
2026-03-01 22:32:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 项目分页查询
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[DisplayName("项目分页查询")]
|
2026-03-08 15:46:19 +08:00
|
|
|
|
public async Task<PageResult<ProjectDto>> Page(ProjectQueryInput input)
|
2026-03-01 22:32:44 +08:00
|
|
|
|
{
|
2026-03-08 15:46:19 +08:00
|
|
|
|
var query = _repository.AsQueryable()
|
2026-04-12 16:11:20 +08:00
|
|
|
|
.WhereIF(!string.IsNullOrWhiteSpace(input.ProjectName), p => p.Name.Contains(input.ProjectName))
|
|
|
|
|
|
.WhereIF(input.ProjectType.HasValue, p => p.ProjectType == (ProjectTypeEnum)input.ProjectType.Value)
|
|
|
|
|
|
.OrderByDescending(p => p.Id);
|
2026-03-08 15:46:19 +08:00
|
|
|
|
|
2026-04-12 16:11:20 +08:00
|
|
|
|
var list = await query.Select(p => new ProjectDto
|
2026-03-08 15:46:19 +08:00
|
|
|
|
{
|
|
|
|
|
|
Id = p.Id,
|
|
|
|
|
|
Name = p.Name,
|
2026-04-12 16:11:20 +08:00
|
|
|
|
ProjectType = (long)p.ProjectType,
|
2026-06-10 13:25:53 +08:00
|
|
|
|
CompletionCountType = p.CompletionCountType,
|
2026-03-08 15:46:19 +08:00
|
|
|
|
CompletionCount = p.CompletionCount,
|
2026-06-10 13:25:53 +08:00
|
|
|
|
CompletionCountMin = p.CompletionCountMin,
|
|
|
|
|
|
CompletionCountMax = p.CompletionCountMax,
|
2026-03-08 15:46:19 +08:00
|
|
|
|
Fee = p.Fee,
|
|
|
|
|
|
DurationMinutes = p.DurationMinutes,
|
|
|
|
|
|
DurationSeconds = p.DurationSeconds,
|
2026-07-18 13:12:58 +08:00
|
|
|
|
Remark = p.Remark,
|
2026-03-08 15:46:19 +08:00
|
|
|
|
VenueCount = p.VenueCount,
|
|
|
|
|
|
SortIndex = p.SortIndex,
|
|
|
|
|
|
Status = p.Status,
|
|
|
|
|
|
DeleteMark = p.DeleteMark,
|
|
|
|
|
|
CreatedUserId = p.CreatedUserId,
|
|
|
|
|
|
CreatedTime = p.CreatedTime,
|
|
|
|
|
|
UpdatedUserId = p.UpdatedUserId,
|
|
|
|
|
|
UpdatedTime = p.UpdatedTime
|
|
|
|
|
|
})
|
|
|
|
|
|
.ToPagedListAsync(input);
|
|
|
|
|
|
|
2026-04-12 16:11:20 +08:00
|
|
|
|
foreach (var item in list.Rows)
|
|
|
|
|
|
{
|
|
|
|
|
|
item.ProjectTypeName = ((ProjectTypeEnum)item.ProjectType).Description();
|
2026-06-10 13:25:53 +08:00
|
|
|
|
// 生成完成人数显示文本
|
|
|
|
|
|
if (item.CompletionCountType == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
item.CompletionCountDisplay = item.CompletionCount.HasValue ? $"{item.CompletionCount.Value}人" : "0人";
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var min = item.CompletionCountMin ?? 0;
|
|
|
|
|
|
var max = item.CompletionCountMax ?? 0;
|
|
|
|
|
|
item.CompletionCountDisplay = $"{min}-{max}人";
|
|
|
|
|
|
}
|
2026-04-12 16:11:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return list;
|
2026-03-01 22:32:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 添加项目
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[DisplayName("添加项目")]
|
|
|
|
|
|
[UnitOfWork]
|
|
|
|
|
|
public async Task Add(AddProjectInput input)
|
|
|
|
|
|
{
|
2026-06-10 13:25:53 +08:00
|
|
|
|
// 验证完成人数字段
|
|
|
|
|
|
if (input.CompletionCountType == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 单一值模式
|
|
|
|
|
|
if (!input.CompletionCount.HasValue || input.CompletionCount.Value < 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw Oops.Bah("请填写有效的完成人数");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// 范围值模式
|
|
|
|
|
|
if (!input.CompletionCountMin.HasValue || !input.CompletionCountMax.HasValue)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw Oops.Bah("请填写完成人数最小值和最大值");
|
|
|
|
|
|
}
|
|
|
|
|
|
if (input.CompletionCountMin.Value < 0 || input.CompletionCountMax.Value < 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw Oops.Bah("完成人数不能为负数");
|
|
|
|
|
|
}
|
|
|
|
|
|
if (input.CompletionCountMin.Value > input.CompletionCountMax.Value)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw Oops.Bah("完成人数最小值不能大于最大值");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-01 22:32:44 +08:00
|
|
|
|
var entity = input.Adapt<YD_Event.Core.Entities.Project>();
|
2026-03-08 15:46:19 +08:00
|
|
|
|
entity.Id = _idGenerator.NewLong();
|
|
|
|
|
|
entity.CreatedTime = DateTime.Now;
|
|
|
|
|
|
entity.Status = Core.Enum.AvailabilityStatus.Enable;
|
2026-06-10 13:25:53 +08:00
|
|
|
|
|
2026-03-01 22:32:44 +08:00
|
|
|
|
await _repository.InsertAsync(entity);
|
|
|
|
|
|
|
|
|
|
|
|
if (input.Groups != null && input.Groups.Any())
|
|
|
|
|
|
{
|
2026-03-08 15:46:19 +08:00
|
|
|
|
var groups = input.Groups.Select(g =>
|
2026-03-01 22:32:44 +08:00
|
|
|
|
{
|
2026-03-08 15:46:19 +08:00
|
|
|
|
var group = g.Adapt<ProjectGroup>();
|
|
|
|
|
|
group.Id = _idGenerator.NewLong();
|
|
|
|
|
|
group.ProjectId = entity.Id;
|
|
|
|
|
|
return group;
|
|
|
|
|
|
}).ToList();
|
2026-03-01 22:32:44 +08:00
|
|
|
|
await _groupRepository.InsertRangeAsync(groups);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 更新项目
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[DisplayName("更新项目")]
|
|
|
|
|
|
[UnitOfWork]
|
|
|
|
|
|
public async Task Update(UpdateProjectInput input)
|
|
|
|
|
|
{
|
|
|
|
|
|
var entity = await _repository.GetByIdAsync(input.Id);
|
2026-03-08 15:46:19 +08:00
|
|
|
|
if (entity == null) throw new InvalidOperationException("项目不存在");
|
2026-03-01 22:32:44 +08:00
|
|
|
|
|
2026-06-10 13:25:53 +08:00
|
|
|
|
// 验证完成人数字段
|
|
|
|
|
|
if (input.CompletionCountType == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 单一值模式
|
|
|
|
|
|
if (!input.CompletionCount.HasValue || input.CompletionCount.Value < 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw Oops.Bah("请填写有效的完成人数");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// 范围值模式
|
|
|
|
|
|
if (!input.CompletionCountMin.HasValue || !input.CompletionCountMax.HasValue)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw Oops.Bah("请填写完成人数最小值和最大值");
|
|
|
|
|
|
}
|
|
|
|
|
|
if (input.CompletionCountMin.Value < 0 || input.CompletionCountMax.Value < 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw Oops.Bah("完成人数不能为负数");
|
|
|
|
|
|
}
|
|
|
|
|
|
if (input.CompletionCountMin.Value > input.CompletionCountMax.Value)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw Oops.Bah("完成人数最小值不能大于最大值");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-01 22:32:44 +08:00
|
|
|
|
input.Adapt(entity);
|
2026-03-08 15:46:19 +08:00
|
|
|
|
entity.UpdatedTime = DateTime.Now;
|
2026-03-01 22:32:44 +08:00
|
|
|
|
await _repository.UpdateAsync(entity);
|
|
|
|
|
|
|
2026-06-06 23:34:12 +08:00
|
|
|
|
await _groupRepository.SoftDeleteAsync(x => x.ProjectId == entity.Id);
|
2026-03-01 22:32:44 +08:00
|
|
|
|
|
|
|
|
|
|
if (input.Groups != null && input.Groups.Any())
|
|
|
|
|
|
{
|
2026-03-08 15:46:19 +08:00
|
|
|
|
var groups = input.Groups.Select(g =>
|
2026-03-01 22:32:44 +08:00
|
|
|
|
{
|
2026-03-08 15:46:19 +08:00
|
|
|
|
var group = g.Adapt<ProjectGroup>();
|
|
|
|
|
|
group.Id = _idGenerator.NewLong();
|
|
|
|
|
|
group.ProjectId = entity.Id;
|
|
|
|
|
|
return group;
|
|
|
|
|
|
}).ToList();
|
2026-03-01 22:32:44 +08:00
|
|
|
|
await _groupRepository.InsertRangeAsync(groups);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 删除项目
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[DisplayName("删除项目")]
|
|
|
|
|
|
[UnitOfWork]
|
2026-03-08 15:46:19 +08:00
|
|
|
|
public async Task Delete(List<long> ids)
|
2026-03-01 22:32:44 +08:00
|
|
|
|
{
|
2026-04-10 22:39:32 +08:00
|
|
|
|
_logger.LogInformation("开始删除项目:项目ID列表={Ids}", string.Join(",", ids));
|
|
|
|
|
|
|
|
|
|
|
|
// 检查项目是否被赛事使用
|
|
|
|
|
|
var hasEventProjects = await _eventProjectRepository.IsAnyAsync(x => ids.Contains(x.ProjectId));
|
|
|
|
|
|
if (hasEventProjects)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogWarning("删除失败:部分项目正在被赛事使用");
|
|
|
|
|
|
throw new InvalidOperationException("部分项目正在被赛事使用,无法删除。请先从赛事中移除这些项目。");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否有报名数据关联
|
|
|
|
|
|
var eventProjectIds = await _eventProjectRepository.AsQueryable()
|
|
|
|
|
|
.Where(x => ids.Contains(x.ProjectId))
|
|
|
|
|
|
.Select(x => x.Id)
|
|
|
|
|
|
.ToListAsync();
|
|
|
|
|
|
|
|
|
|
|
|
if (eventProjectIds.Any())
|
|
|
|
|
|
{
|
|
|
|
|
|
var hasParticipations = await _participationRecordRepository.IsAnyAsync(x =>
|
|
|
|
|
|
eventProjectIds.Contains(x.ProjectId) && !x.DeleteMark);
|
|
|
|
|
|
|
|
|
|
|
|
if (hasParticipations)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogWarning("删除失败:部分项目已有报名数据");
|
|
|
|
|
|
throw new InvalidOperationException("部分项目已有报名数据,为保证数据完整性,无法删除。");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-06 23:34:12 +08:00
|
|
|
|
// 执行删除 - 软删
|
|
|
|
|
|
await _repository.SoftDeleteByIdsAsync(ids);
|
|
|
|
|
|
await _groupRepository.SoftDeleteAsync(x => ids.Contains(x.ProjectId));
|
2026-04-10 22:39:32 +08:00
|
|
|
|
|
|
|
|
|
|
_logger.LogInformation("删除项目成功:项目ID列表={Ids}", string.Join(",", ids));
|
2026-03-01 22:32:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取项目详情
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[DisplayName("获取项目详情")]
|
2026-03-08 15:46:19 +08:00
|
|
|
|
public async Task<ProjectDto> Detail(long id)
|
2026-03-01 22:32:44 +08:00
|
|
|
|
{
|
|
|
|
|
|
var p = await _repository.GetByIdAsync(id);
|
2026-03-08 15:46:19 +08:00
|
|
|
|
if (p == null) throw new InvalidOperationException("项目不存在");
|
2026-03-01 22:32:44 +08:00
|
|
|
|
|
|
|
|
|
|
var dto = p.Adapt<ProjectDto>();
|
2026-04-12 16:11:20 +08:00
|
|
|
|
dto.ProjectType = (long)p.ProjectType;
|
|
|
|
|
|
dto.ProjectTypeName = p.ProjectType.Description();
|
2026-06-10 13:25:53 +08:00
|
|
|
|
|
|
|
|
|
|
// 生成完成人数显示文本
|
|
|
|
|
|
if (dto.CompletionCountType == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
dto.CompletionCountDisplay = dto.CompletionCount.HasValue ? $"{dto.CompletionCount.Value}人" : "0人";
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var min = dto.CompletionCountMin ?? 0;
|
|
|
|
|
|
var max = dto.CompletionCountMax ?? 0;
|
|
|
|
|
|
dto.CompletionCountDisplay = $"{min}-{max}人";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-08 15:46:19 +08:00
|
|
|
|
var groups = await _groupRepository.GetListAsync(x => x.ProjectId == id);
|
|
|
|
|
|
dto.Groups = groups.Adapt<List<ProjectGroupDto>>();
|
|
|
|
|
|
|
2026-03-01 22:32:44 +08:00
|
|
|
|
return dto;
|
|
|
|
|
|
}
|
2026-03-31 17:38:36 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 项目统计类型
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public enum ProjectStatisticType
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 参赛人数
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
ParticipationCount = 1,
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 完成人数
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
CompletionCount = 2
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取项目统计数据(单个项目)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="projectId">项目ID</param>
|
|
|
|
|
|
/// <param name="statisticType">统计类型</param>
|
|
|
|
|
|
/// <returns>统计数值</returns>
|
|
|
|
|
|
[DisplayName("获取项目统计数据")]
|
|
|
|
|
|
public async Task<int> GetProjectStatisticAsync(long projectId, ProjectStatisticType statisticType)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (projectId <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogWarning("Invalid projectId: {ProjectId}", projectId);
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var eventProjectIds = await _eventProjectRepository.AsQueryable()
|
|
|
|
|
|
.Where(ep => ep.ProjectId == projectId)
|
|
|
|
|
|
.Select(ep => ep.Id)
|
|
|
|
|
|
.ToListAsync();
|
|
|
|
|
|
|
|
|
|
|
|
if (!eventProjectIds.Any())
|
|
|
|
|
|
{
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var query = _participationRecordRepository.AsQueryable()
|
|
|
|
|
|
.Where(pr => eventProjectIds.Contains(pr.ProjectId) && !pr.DeleteMark);
|
|
|
|
|
|
|
|
|
|
|
|
switch (statisticType)
|
|
|
|
|
|
{
|
|
|
|
|
|
case ProjectStatisticType.ParticipationCount:
|
|
|
|
|
|
query = query.Where(pr => pr.ParticipationStatus == ParticipationStatus.Participated || pr.ParticipationStatus == ParticipationStatus.Completed);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case ProjectStatisticType.CompletionCount:
|
|
|
|
|
|
query = query.Where(pr => pr.ParticipationStatus == ParticipationStatus.Completed);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
_logger.LogWarning("Unknown statistic type: {StatisticType}", statisticType);
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var count = await query.CountAsync();
|
|
|
|
|
|
return count;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 批量获取项目统计数据(性能优化,避免N+1查询)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="projectIds">项目ID列表</param>
|
|
|
|
|
|
/// <param name="statisticType">统计类型</param>
|
|
|
|
|
|
/// <returns>字典,Key为项目ID,Value为统计数值</returns>
|
|
|
|
|
|
[DisplayName("批量获取项目统计数据")]
|
|
|
|
|
|
public async Task<Dictionary<long, int>> GetProjectStatisticsBatchAsync(List<long> projectIds, ProjectStatisticType statisticType)
|
|
|
|
|
|
{
|
|
|
|
|
|
var result = new Dictionary<long, int>();
|
|
|
|
|
|
|
|
|
|
|
|
if (projectIds == null || !projectIds.Any())
|
|
|
|
|
|
{
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var projectId in projectIds)
|
|
|
|
|
|
{
|
|
|
|
|
|
result[projectId] = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var eventProjects = await _eventProjectRepository.AsQueryable()
|
|
|
|
|
|
.Where(ep => projectIds.Contains(ep.ProjectId))
|
|
|
|
|
|
.Select(ep => new { ep.Id, ep.ProjectId })
|
|
|
|
|
|
.ToListAsync();
|
|
|
|
|
|
|
|
|
|
|
|
if (!eventProjects.Any())
|
|
|
|
|
|
{
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var eventProjectIds = eventProjects.Select(ep => ep.Id).ToList();
|
|
|
|
|
|
|
|
|
|
|
|
var query = _participationRecordRepository.AsQueryable()
|
|
|
|
|
|
.Where(pr => eventProjectIds.Contains(pr.ProjectId) && !pr.DeleteMark);
|
|
|
|
|
|
|
|
|
|
|
|
switch (statisticType)
|
|
|
|
|
|
{
|
|
|
|
|
|
case ProjectStatisticType.ParticipationCount:
|
|
|
|
|
|
query = query.Where(pr => pr.ParticipationStatus == ParticipationStatus.Participated || pr.ParticipationStatus == ParticipationStatus.Completed);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case ProjectStatisticType.CompletionCount:
|
|
|
|
|
|
query = query.Where(pr => pr.ParticipationStatus == ParticipationStatus.Completed);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
_logger.LogWarning("Unknown statistic type: {StatisticType}", statisticType);
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var records = await query.ToListAsync();
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var record in records)
|
|
|
|
|
|
{
|
|
|
|
|
|
var projectId = eventProjects.FirstOrDefault(ep => ep.Id == record.ProjectId)?.ProjectId;
|
|
|
|
|
|
if (projectId.HasValue && result.ContainsKey(projectId.Value))
|
|
|
|
|
|
{
|
|
|
|
|
|
result[projectId.Value]++;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
2026-03-01 22:32:44 +08:00
|
|
|
|
}
|