项目编排
This commit is contained in:
parent
565ca9cc36
commit
ae03373047
@ -153,4 +153,14 @@ public class ArrangementPreviewOutput
|
|||||||
/// 场地索引
|
/// 场地索引
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int VenueIndex { get; set; }
|
public int VenueIndex { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 项目总时长(秒)
|
||||||
|
/// </summary>
|
||||||
|
public int ProjectTotalDurationSeconds { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 项目总时长(格式化字符串)
|
||||||
|
/// </summary>
|
||||||
|
public string ProjectTotalDuration { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -753,7 +753,7 @@ public class RegistrationItemDTO
|
|||||||
public string TeamName { get; set; }
|
public string TeamName { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 综合状态 (0-待付款, 1-已支付, 2-已取消, 3-已退款, 4-已完成)
|
/// 支付状态:0-未支付/待审核,1-已支付/审核通过,2-支付失败/审核拒绝,3-已退款,4-已取消
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Status { get; set; }
|
public int Status { get; set; }
|
||||||
|
|
||||||
|
|||||||
@ -38,6 +38,47 @@ public class EventArrangementService : BaseService<YD_Event.Core.Entities.Projec
|
|||||||
_eventInfoRepository = eventInfoRepository;
|
_eventInfoRepository = eventInfoRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 格式化时长显示(符号格式:X'X")
|
||||||
|
private string FormatDurationSymbol(int totalSeconds)
|
||||||
|
{
|
||||||
|
if (totalSeconds <= 0)
|
||||||
|
{
|
||||||
|
return "0'0\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
var hours = totalSeconds / 3600;
|
||||||
|
var remainingSecondsAfterHours = totalSeconds % 3600;
|
||||||
|
var minutes = remainingSecondsAfterHours / 60;
|
||||||
|
var seconds = remainingSecondsAfterHours % 60;
|
||||||
|
|
||||||
|
if (hours == 0)
|
||||||
|
{
|
||||||
|
if (seconds == 0)
|
||||||
|
{
|
||||||
|
return $"{minutes}'";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var paddedSeconds = seconds.ToString().PadLeft(2, '0');
|
||||||
|
return $"{minutes}'{paddedSeconds}\"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var result = $"{hours}h";
|
||||||
|
if (minutes > 0 || seconds > 0)
|
||||||
|
{
|
||||||
|
result += $"{minutes}'";
|
||||||
|
if (seconds > 0)
|
||||||
|
{
|
||||||
|
var paddedSeconds = seconds.ToString().PadLeft(2, '0');
|
||||||
|
result += $"{paddedSeconds}\"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取编排项目列表
|
/// 获取编排项目列表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -196,11 +237,40 @@ public class EventArrangementService : BaseService<YD_Event.Core.Entities.Projec
|
|||||||
[DisplayName("编排预览")]
|
[DisplayName("编排预览")]
|
||||||
public async Task<List<ArrangementPreviewOutput>> Preview(long eventId)
|
public async Task<List<ArrangementPreviewOutput>> Preview(long eventId)
|
||||||
{
|
{
|
||||||
// 1. 获取项目(按顺序)
|
// 1. 获取项目列表和统计数据
|
||||||
var eventProjects = await _eventProjectRepository.GetListAsync(x => x.EventId == eventId);
|
var eventProjects = await _eventProjectRepository.GetListAsync(x => x.EventId == eventId);
|
||||||
var projectIds = eventProjects.Select(x => x.ProjectId).Distinct().ToList();
|
var projectIds = eventProjects.Select(x => x.ProjectId).Distinct().ToList();
|
||||||
var projects = await _projectRepository.GetListAsync(x => projectIds.Contains(x.Id));
|
var projects = await _projectRepository.GetListAsync(x => projectIds.Contains(x.Id));
|
||||||
projects = projects.OrderBy(x => x.SortIndex).ToList();
|
projects = projects.OrderBy(x => x.SortIndex).ToList();
|
||||||
|
var groups = await _groupRepository.GetListAsync(x => projectIds.Contains(x.ProjectId));
|
||||||
|
|
||||||
|
// 统计各组别报名人数
|
||||||
|
var counts = await _personRepository.AsQueryable()
|
||||||
|
.InnerJoin<EventRegistration>((p, r) => p.RegistrationId == r.Id)
|
||||||
|
.Where((p, r) => r.EventId == eventId
|
||||||
|
&& r.PaymentStatus != 4
|
||||||
|
&& !p.DeleteMark
|
||||||
|
&& p.PersonType == PersonType.Athlete)
|
||||||
|
.GroupBy((p, r) => new { p.ProjectId, p.GroupName })
|
||||||
|
.Select((p, r) => new { p.ProjectId, p.GroupName, Count = SqlFunc.AggregateCount(p.Id) })
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
// 获取团队数
|
||||||
|
var personWithTeam = await _personRepository.AsQueryable()
|
||||||
|
.InnerJoin<EventRegistration>((p, r) => p.RegistrationId == r.Id)
|
||||||
|
.Where((p, r) => r.EventId == eventId
|
||||||
|
&& r.PaymentStatus != 4
|
||||||
|
&& !p.DeleteMark
|
||||||
|
&& p.PersonType == PersonType.Athlete
|
||||||
|
&& r.TeamName != null)
|
||||||
|
.Select((p, r) => new { p.ProjectId, p.GroupName, r.TeamName })
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var teamCounts = personWithTeam
|
||||||
|
.GroupBy(x => new { x.ProjectId, x.GroupName, x.TeamName })
|
||||||
|
.GroupBy(g => new { g.Key.ProjectId, g.Key.GroupName })
|
||||||
|
.Select(g => new { g.Key.ProjectId, g.Key.GroupName, Count = g.Count() })
|
||||||
|
.ToList();
|
||||||
|
|
||||||
var result = new List<ArrangementPreviewOutput>();
|
var result = new List<ArrangementPreviewOutput>();
|
||||||
|
|
||||||
@ -212,8 +282,7 @@ public class EventArrangementService : BaseService<YD_Event.Core.Entities.Projec
|
|||||||
|
|
||||||
int venueCount = proj.VenueCount > 0 ? proj.VenueCount : 1;
|
int venueCount = proj.VenueCount > 0 ? proj.VenueCount : 1;
|
||||||
|
|
||||||
// 获取参赛人员(排序:组别 -> ID)
|
// 获取参赛人员
|
||||||
// 查询条件:不是取消状态的报名,并且只统计运动员
|
|
||||||
var persons = await _personRepository.AsQueryable()
|
var persons = await _personRepository.AsQueryable()
|
||||||
.InnerJoin<EventRegistration>((p, r) => p.RegistrationId == r.Id)
|
.InnerJoin<EventRegistration>((p, r) => p.RegistrationId == r.Id)
|
||||||
.Where((p, r) => p.ProjectId == eventProj.Id
|
.Where((p, r) => p.ProjectId == eventProj.Id
|
||||||
@ -230,6 +299,39 @@ public class EventArrangementService : BaseService<YD_Event.Core.Entities.Projec
|
|||||||
|
|
||||||
if (!persons.Any()) continue;
|
if (!persons.Any()) continue;
|
||||||
|
|
||||||
|
// 计算项目总时长
|
||||||
|
int totalParticipants = 0;
|
||||||
|
var projGroups = groups.Where(g => g.ProjectId == proj.Id).ToList();
|
||||||
|
foreach (var group in projGroups)
|
||||||
|
{
|
||||||
|
var countObj = counts.FirstOrDefault(c => c.ProjectId == eventProj.Id && c.GroupName == group.GroupName);
|
||||||
|
totalParticipants += countObj?.Count ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int totalTeams = 0;
|
||||||
|
if (proj.IsTeamProject())
|
||||||
|
{
|
||||||
|
totalTeams = teamCounts
|
||||||
|
.Where(tc => tc.ProjectId == eventProj.Id)
|
||||||
|
.Sum(tc => tc.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
int projectTotalDurationSeconds;
|
||||||
|
if (proj.IsTeamProject())
|
||||||
|
{
|
||||||
|
int teamCount = totalTeams > 0 ? totalTeams : 1;
|
||||||
|
int rounds = (int)Math.Ceiling((double)teamCount / venueCount);
|
||||||
|
projectTotalDurationSeconds = rounds * proj.DurationSeconds;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int participantCount = totalParticipants > 0 ? totalParticipants : 1;
|
||||||
|
int rounds = (int)Math.Ceiling((double)participantCount / venueCount);
|
||||||
|
projectTotalDurationSeconds = rounds * proj.DurationSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
string projectTotalDuration = FormatDurationSymbol(projectTotalDurationSeconds);
|
||||||
|
|
||||||
// 分组逻辑
|
// 分组逻辑
|
||||||
int currentRound = 1;
|
int currentRound = 1;
|
||||||
int currentVenue = 1;
|
int currentVenue = 1;
|
||||||
@ -245,7 +347,9 @@ public class EventArrangementService : BaseService<YD_Event.Core.Entities.Projec
|
|||||||
TeamName = person.TeamName,
|
TeamName = person.TeamName,
|
||||||
AthleteName = person.Name,
|
AthleteName = person.Name,
|
||||||
SessionIndex = currentRound,
|
SessionIndex = currentRound,
|
||||||
VenueIndex = currentVenue
|
VenueIndex = currentVenue,
|
||||||
|
ProjectTotalDurationSeconds = projectTotalDurationSeconds,
|
||||||
|
ProjectTotalDuration = projectTotalDuration
|
||||||
});
|
});
|
||||||
|
|
||||||
currentVenue++;
|
currentVenue++;
|
||||||
@ -302,12 +406,47 @@ public class EventArrangementService : BaseService<YD_Event.Core.Entities.Projec
|
|||||||
|
|
||||||
// 填充数据行
|
// 填充数据行
|
||||||
var alternateBgColor = Color.FromArgb(240, 255, 240);
|
var alternateBgColor = Color.FromArgb(240, 255, 240);
|
||||||
|
|
||||||
|
// 按项目分组处理,合并时间列
|
||||||
|
string currentProjectName = null;
|
||||||
|
int projectStartRow = 0;
|
||||||
|
|
||||||
for (int i = 0; i < _data.Count; i++)
|
for (int i = 0; i < _data.Count; i++)
|
||||||
{
|
{
|
||||||
var item = _data[i];
|
var item = _data[i];
|
||||||
int rowIndex = i + 3;
|
int rowIndex = i + 3;
|
||||||
|
|
||||||
Worksheet.Cells[rowIndex, 1].Value = item.TimeRange;
|
// 如果是新项目或最后一行,合并前面的项目时间列
|
||||||
|
if (currentProjectName != item.ProjectName)
|
||||||
|
{
|
||||||
|
// 如果不是第一个项目,合并前一个项目的时间列
|
||||||
|
if (currentProjectName != null && projectStartRow > 0 && i - 1 >= 0)
|
||||||
|
{
|
||||||
|
int mergeEndRow = (i - 1) + 3;
|
||||||
|
if (mergeEndRow > projectStartRow)
|
||||||
|
{
|
||||||
|
var range = Worksheet.Cells[projectStartRow, 1, mergeEndRow, 1];
|
||||||
|
range.Merge = true;
|
||||||
|
// 设置时间列居中对齐
|
||||||
|
for (int r = projectStartRow; r <= mergeEndRow; r++)
|
||||||
|
{
|
||||||
|
Worksheet.Cells[r, 1].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
|
||||||
|
Worksheet.Cells[r, 1].Style.VerticalAlignment = ExcelVerticalAlignment.Center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
currentProjectName = item.ProjectName;
|
||||||
|
projectStartRow = rowIndex;
|
||||||
|
|
||||||
|
// 设置项目总时长
|
||||||
|
Worksheet.Cells[rowIndex, 1].Value = item.ProjectTotalDuration;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 同一项目的其他行不设置时间值(合并后会自动应用)
|
||||||
|
}
|
||||||
|
|
||||||
Worksheet.Cells[rowIndex, 2].Value = item.ProjectName;
|
Worksheet.Cells[rowIndex, 2].Value = item.ProjectName;
|
||||||
Worksheet.Cells[rowIndex, 3].Value = item.GroupName;
|
Worksheet.Cells[rowIndex, 3].Value = item.GroupName;
|
||||||
Worksheet.Cells[rowIndex, 4].Value = item.TeamName ?? "";
|
Worksheet.Cells[rowIndex, 4].Value = item.TeamName ?? "";
|
||||||
@ -318,6 +457,23 @@ public class EventArrangementService : BaseService<YD_Event.Core.Entities.Projec
|
|||||||
SetDataRowStyle(rowIndex, 7, alternateBgColor, i % 2 == 1);
|
SetDataRowStyle(rowIndex, 7, alternateBgColor, i % 2 == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理最后一个项目的合并
|
||||||
|
if (currentProjectName != null && projectStartRow > 0 && _data.Count > 0)
|
||||||
|
{
|
||||||
|
int mergeEndRow = (_data.Count - 1) + 3;
|
||||||
|
if (mergeEndRow > projectStartRow)
|
||||||
|
{
|
||||||
|
var range = Worksheet.Cells[projectStartRow, 1, mergeEndRow, 1];
|
||||||
|
range.Merge = true;
|
||||||
|
// 设置时间列居中对齐
|
||||||
|
for (int r = projectStartRow; r <= mergeEndRow; r++)
|
||||||
|
{
|
||||||
|
Worksheet.Cells[r, 1].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
|
||||||
|
Worksheet.Cells[r, 1].Style.VerticalAlignment = ExcelVerticalAlignment.Center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 设置列宽
|
// 设置列宽
|
||||||
var widths = new double[] { 12, 18, 15, 25, 15, 8, 8 };
|
var widths = new double[] { 12, 18, 15, 25, 15, 8, 8 };
|
||||||
SetColumnWidths(widths);
|
SetColumnWidths(widths);
|
||||||
|
|||||||
@ -265,11 +265,11 @@ public class EventRegistrationService : BaseService<EventRegistration>, ITransie
|
|||||||
};
|
};
|
||||||
|
|
||||||
dto.TeamLeaderInfo = allLeaders.Any()
|
dto.TeamLeaderInfo = allLeaders.Any()
|
||||||
? string.Join(",", allLeaders.Select(l => $"{l.Name}({l.Mobile})/{getGenderText(l.Gender)}"))
|
? string.Join(",", allLeaders.Select(l => $"{l.Name}/{getGenderText(l.Gender)}/{l.Mobile}"))
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
dto.CoachInfo = allCoaches.Any()
|
dto.CoachInfo = allCoaches.Any()
|
||||||
? string.Join(",", allCoaches.Select(c => $"{c.Name}({c.Mobile})/{getGenderText(c.Gender)}"))
|
? string.Join(",", allCoaches.Select(c => $"{c.Name}/{getGenderText(c.Gender)}/{c.Mobile}"))
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1134,8 +1134,9 @@ public class UnifiedRegistrationService : ITransient
|
|||||||
var eventProjectGroups = await _eventProjectGroupRepository.GetListAsync(x => x.EventId == input.EventId && !x.DeleteMark);
|
var eventProjectGroups = await _eventProjectGroupRepository.GetListAsync(x => x.EventId == input.EventId && !x.DeleteMark);
|
||||||
|
|
||||||
// 先获取所有报名信息,供后续检查使用
|
// 先获取所有报名信息,供后续检查使用
|
||||||
|
// 只统计已支付的报名记录(PaymentStatus == 1),避免未支付/已取消的报名占用名额
|
||||||
var eventRegistrations = await _registrationRepository.GetListAsync(x =>
|
var eventRegistrations = await _registrationRepository.GetListAsync(x =>
|
||||||
x.EventId == input.EventId && x.PaymentStatus != 4 && !x.DeleteMark);
|
x.EventId == input.EventId && x.PaymentStatus == 1 && !x.DeleteMark);
|
||||||
var eventRegistrationIds = eventRegistrations.Select(r => r.Id).ToList();
|
var eventRegistrationIds = eventRegistrations.Select(r => r.Id).ToList();
|
||||||
var registrationPersons = await _registrationPersonRepository.GetListAsync(x =>
|
var registrationPersons = await _registrationPersonRepository.GetListAsync(x =>
|
||||||
eventRegistrationIds.Contains(x.RegistrationId) && !x.DeleteMark);
|
eventRegistrationIds.Contains(x.RegistrationId) && !x.DeleteMark);
|
||||||
|
|||||||
@ -112,21 +112,6 @@ public class UserEventRecordService : IDynamicApiController, ITransient
|
|||||||
.ToPagedListAsync(input);
|
.ToPagedListAsync(input);
|
||||||
|
|
||||||
var resultItems = list.Rows.Select(x => {
|
var resultItems = list.Rows.Select(x => {
|
||||||
// 计算综合状态
|
|
||||||
int statusValue = 0;
|
|
||||||
if (x.PaymentStatus == 4)
|
|
||||||
statusValue = 2; // 已取消
|
|
||||||
else if (x.PaymentStatus == 0)
|
|
||||||
statusValue = 0; // 待付款
|
|
||||||
else if (x.PaymentStatus == 1 && string.IsNullOrEmpty(x.MaterialUrl))
|
|
||||||
statusValue = 1; // 已支付
|
|
||||||
else if (x.PaymentStatus == 1 && !string.IsNullOrEmpty(x.MaterialUrl))
|
|
||||||
statusValue = 4; // 已完成/已报名
|
|
||||||
else if (x.PaymentStatus == 2)
|
|
||||||
statusValue = 1; // 审核拒绝
|
|
||||||
else if (x.PaymentStatus == 3)
|
|
||||||
statusValue = 3; // 已退款
|
|
||||||
|
|
||||||
return new RegistrationItemDTO
|
return new RegistrationItemDTO
|
||||||
{
|
{
|
||||||
RegistrationId = x.Id,
|
RegistrationId = x.Id,
|
||||||
@ -141,7 +126,7 @@ public class UserEventRecordService : IDynamicApiController, ITransient
|
|||||||
MatchStartTime = x.MatchStartTime,
|
MatchStartTime = x.MatchStartTime,
|
||||||
MatchEndTime = x.MatchEndTime,
|
MatchEndTime = x.MatchEndTime,
|
||||||
TeamName = x.TeamName,
|
TeamName = x.TeamName,
|
||||||
Status = statusValue,
|
Status = x.PaymentStatus,
|
||||||
CreateTime = x.CreatedTime,
|
CreateTime = x.CreatedTime,
|
||||||
UpdateTime = x.UpdatedTime,
|
UpdateTime = x.UpdatedTime,
|
||||||
PayStatus = x.PaymentStatus,
|
PayStatus = x.PaymentStatus,
|
||||||
|
|||||||
@ -4167,6 +4167,16 @@
|
|||||||
场地索引
|
场地索引
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="P:YD_Event.Application.Event.Dtos.ArrangementPreviewOutput.ProjectTotalDurationSeconds">
|
||||||
|
<summary>
|
||||||
|
项目总时长(秒)
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:YD_Event.Application.Event.Dtos.ArrangementPreviewOutput.ProjectTotalDuration">
|
||||||
|
<summary>
|
||||||
|
项目总时长(格式化字符串)
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
<member name="T:YD_Event.Application.Event.Dtos.EventQueryInput">
|
<member name="T:YD_Event.Application.Event.Dtos.EventQueryInput">
|
||||||
<summary>
|
<summary>
|
||||||
赛事查询输入
|
赛事查询输入
|
||||||
@ -6969,7 +6979,7 @@
|
|||||||
</member>
|
</member>
|
||||||
<member name="P:YD_Event.Application.Event.Dtos.RegistrationItemDTO.Status">
|
<member name="P:YD_Event.Application.Event.Dtos.RegistrationItemDTO.Status">
|
||||||
<summary>
|
<summary>
|
||||||
综合状态 (0-待付款, 1-已支付, 2-已取消, 3-已退款, 4-已完成)
|
支付状态:0-未支付/待审核,1-已支付/审核通过,2-支付失败/审核拒绝,3-已退款,4-已取消
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:YD_Event.Application.Event.Dtos.RegistrationItemDTO.CreateTime">
|
<member name="P:YD_Event.Application.Event.Dtos.RegistrationItemDTO.CreateTime">
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user