导出功能合并,项目参与人数重新获取

This commit is contained in:
马梓彭 2026-03-31 17:38:36 +08:00
parent 10fb96434c
commit 5abbae9e6c
10 changed files with 540 additions and 95 deletions

View File

@ -137,8 +137,8 @@ public class AppUserService : BaseService<AppUserEntity>, ITransient
[DisplayName("统一新增/编辑成员")]
public async Task SaveUnifiedMember(CreateOrUpdateMemberInput input)
{
// 仅在新增领队/教练时验证验证码
if (!input.Id.HasValue && (input.PersonType == PersonType.Leader || input.PersonType == PersonType.Coach))
// 仅在新增运动员时验证验证码
if (!input.Id.HasValue && input.PersonType == PersonType.Athlete)
{
if (string.IsNullOrWhiteSpace(input.VerificationCode))
{

View File

@ -1,4 +1,5 @@
using YD_Event.Application.Event.Dtos;
using YD_Event.Core.Domain.Export;
using YD_Event.Core.Entities;
using MiniExcelLibs;
using SqlSugar;
@ -154,9 +155,10 @@ public class EventArrangementService : BaseService<YD_Event.Core.Entities.Projec
int venueCount = proj.VenueCount > 0 ? proj.VenueCount : 1;
// 获取参赛人员(排序:组别 -> ID)
// 放宽查询条件,只要不是取消状态的报名都包含进来
var persons = await _personRepository.AsQueryable()
.InnerJoin<EventRegistration>((p, r) => p.RegistrationId == r.Id)
.Where((p, r) => p.ProjectId == eventProj.Id && (r.PaymentStatus == 1 || r.RegistrationStatus == 2))
.Where((p, r) => p.ProjectId == eventProj.Id && r.RegistrationStatus != 4)
.OrderBy(p => p.GroupName)
.OrderBy(p => p.Id)
.Select((p, r) => new {
@ -205,92 +207,67 @@ public class EventArrangementService : BaseService<YD_Event.Core.Entities.Projec
var eventInfo = await _eventInfoRepository.GetFirstAsync(x => x.Id == eventId);
var data = await Preview(eventId);
// 设置 EPPlus 许可证上下文
ExcelPackage.LicenseContext = OfficeOpenXml.LicenseContext.NonCommercial;
using var package = new ExcelPackage();
var worksheet = package.Workbook.Worksheets.Add("编排表");
// 第一行:赛事标题(合并单元格 A1:G1)
worksheet.Cells["A1:G1"].Merge = true;
worksheet.Cells["A1"].Value = eventInfo?.EventName ?? "赛事编排表";
// 设置标题样式
var titleStyle = worksheet.Cells["A1:G1"].Style;
titleStyle.Font.Bold = true;
titleStyle.Font.Size = 14;
titleStyle.HorizontalAlignment = ExcelHorizontalAlignment.Center;
titleStyle.VerticalAlignment = ExcelVerticalAlignment.Center;
titleStyle.Fill.PatternType = ExcelFillStyle.Solid;
titleStyle.Fill.BackgroundColor.SetColor(Color.FromArgb(255, 217, 179)); // 浅橙色
// 第二行:列标题
string[] headers = { "时间", "参赛项目", "参赛组别", "参赛队伍", "运动员姓名", "场次", "场地" };
for (int i = 0; i < headers.Length; i++)
var exporter = new ArrangementExporter(data, eventInfo);
return await exporter.ExportAsync();
}
/// <summary>
/// 编排导出器
/// </summary>
private class ArrangementExporter : ExcelExportBase
{
private readonly List<ArrangementPreviewOutput> _data;
private readonly EventInfo _eventInfo;
public ArrangementExporter(List<ArrangementPreviewOutput> data, EventInfo eventInfo)
{
worksheet.Cells[2, i + 1].Value = headers[i];
_data = data ?? new List<ArrangementPreviewOutput>();
_eventInfo = eventInfo;
}
// 设置列标题样式
var headerStyle = worksheet.Cells["A2:G2"].Style;
headerStyle.Font.Bold = true;
headerStyle.Font.Size = 11;
headerStyle.HorizontalAlignment = ExcelHorizontalAlignment.Center;
headerStyle.VerticalAlignment = ExcelVerticalAlignment.Center;
headerStyle.Fill.PatternType = ExcelFillStyle.Solid;
headerStyle.Fill.BackgroundColor.SetColor(Color.FromArgb(204, 255, 204)); // 浅绿色
headerStyle.Border.Top.Style = ExcelBorderStyle.Thin;
headerStyle.Border.Bottom.Style = ExcelBorderStyle.Thin;
headerStyle.Border.Left.Style = ExcelBorderStyle.Thin;
headerStyle.Border.Right.Style = ExcelBorderStyle.Thin;
// 填充数据行
for (int i = 0; i < data.Count; i++)
public override async Task<byte[]> ExportAsync()
{
var item = data[i];
int rowIndex = i + 3;
worksheet.Cells[rowIndex, 1].Value = item.TimeRange;
worksheet.Cells[rowIndex, 2].Value = item.ProjectName;
worksheet.Cells[rowIndex, 3].Value = item.GroupName;
worksheet.Cells[rowIndex, 4].Value = item.TeamName ?? "";
worksheet.Cells[rowIndex, 5].Value = item.AthleteName;
worksheet.Cells[rowIndex, 6].Value = item.SessionIndex;
worksheet.Cells[rowIndex, 7].Value = item.VenueIndex;
// 设置数据行样式
var rowStyle = worksheet.Cells[$"A{rowIndex}:G{rowIndex}"].Style;
rowStyle.HorizontalAlignment = ExcelHorizontalAlignment.Center;
rowStyle.VerticalAlignment = ExcelVerticalAlignment.Center;
rowStyle.Border.Top.Style = ExcelBorderStyle.Thin;
rowStyle.Border.Bottom.Style = ExcelBorderStyle.Thin;
rowStyle.Border.Left.Style = ExcelBorderStyle.Thin;
rowStyle.Border.Right.Style = ExcelBorderStyle.Thin;
// 交替行颜色
if (i % 2 == 1)
CreateWorksheet("编排表");
// 第一行:赛事标题(合并单元格 A1:G1)
var titleColor = Color.FromArgb(255, 217, 179);
SetMergeTitle(_eventInfo?.EventName ?? "赛事编排表", 1, 1, 1, 7, titleColor, 14);
// 第二行:列标题
var headers = new[] { "时间", "参赛项目", "参赛组别", "参赛队伍", "运动员姓名", "场次", "场地" };
var headerColor = Color.FromArgb(204, 255, 204);
SetHeaders(headers, 2, headerColor, 11);
// 填充数据行
var alternateBgColor = Color.FromArgb(240, 255, 240);
for (int i = 0; i < _data.Count; i++)
{
rowStyle.Fill.PatternType = ExcelFillStyle.Solid;
rowStyle.Fill.BackgroundColor.SetColor(Color.FromArgb(240, 255, 240)); // 更浅的绿色
var item = _data[i];
int rowIndex = i + 3;
Worksheet.Cells[rowIndex, 1].Value = item.TimeRange;
Worksheet.Cells[rowIndex, 2].Value = item.ProjectName;
Worksheet.Cells[rowIndex, 3].Value = item.GroupName;
Worksheet.Cells[rowIndex, 4].Value = item.TeamName ?? "";
Worksheet.Cells[rowIndex, 5].Value = item.AthleteName;
Worksheet.Cells[rowIndex, 6].Value = item.SessionIndex;
Worksheet.Cells[rowIndex, 7].Value = item.VenueIndex;
SetDataRowStyle(rowIndex, 7, alternateBgColor, i % 2 == 1);
}
// 设置列宽
var widths = new double[] { 12, 18, 15, 25, 15, 8, 8 };
SetColumnWidths(widths);
// 设置行高
SetRowHeight(1, 30);
SetRowHeight(2, 25);
// 冻结首行和首列
FreezePanes(3, 1);
return await GetAsByteArrayAsync();
}
// 设置列宽
worksheet.Column(1).Width = 12; // 时间
worksheet.Column(2).Width = 18; // 参赛项目
worksheet.Column(3).Width = 15; // 参赛组别
worksheet.Column(4).Width = 25; // 参赛队伍
worksheet.Column(5).Width = 15; // 运动员姓名
worksheet.Column(6).Width = 8; // 场次
worksheet.Column(7).Width = 8; // 场地
// 设置行高
worksheet.Row(1).Height = 30; // 标题行
worksheet.Row(2).Height = 25; // 列标题行
// 冻结首行和首列
worksheet.View.FreezePanes(3, 1);
return await package.GetAsByteArrayAsync();
}
}

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using YD_Event.Application.Event.Dtos;
using YD_Event.Application.Project;
using YD_Event.Core.Entities;
using YD_Event.Core.Enum;
using SqlSugar;
@ -49,6 +50,7 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient
private readonly WeChatPayService _weChatPayService;
private readonly IOptionsMonitor<YD_Event.Core.Options.WechatTenpayClientOptions> _wechatTenpayClientOptionsMonitor;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ProjectService _projectService;
public UserEventRegistrationService(
ISqlSugarRepository<EventInfo> eventRepository,
@ -70,7 +72,8 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient
IIdGenerator idGenerator,
WeChatPayService weChatPayService,
IOptionsMonitor<YD_Event.Core.Options.WechatTenpayClientOptions> wechatTenpayClientOptionsMonitor,
IHttpContextAccessor httpContextAccessor)
IHttpContextAccessor httpContextAccessor,
ProjectService projectService)
{
_eventRepository = eventRepository;
_unitRepository = unitRepository;
@ -92,6 +95,7 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient
_weChatPayService = weChatPayService;
_wechatTenpayClientOptionsMonitor = wechatTenpayClientOptionsMonitor;
_httpContextAccessor = httpContextAccessor;
_projectService = projectService;
}
/// <summary>
@ -188,15 +192,24 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient
var projectIds = eventProjects.Select(x => x.ProjectId).Distinct().ToList();
var baseProjects = await _projectRepository.GetListAsync(x => projectIds.Contains(x.Id) && x.Status == AvailabilityStatus.Enable);
var completionStats = await _projectService.GetProjectStatisticsBatchAsync(
projectIds,
ProjectService.ProjectStatisticType.CompletionCount);
output.Projects = eventProjects.Select(ep =>
{
var p = baseProjects.FirstOrDefault(b => b.Id == ep.ProjectId);
var completionCount = 0;
if (p != null && completionStats.TryGetValue(p.Id, out var count))
{
completionCount = count;
}
return new UserEventProjectListOutput
{
Id = ep.Id,
Name = p?.Name ?? "",
Fee = ep.Price / 100m,
CompletionCount = p?.CompletionCount ?? 0
CompletionCount = completionCount
};
}).Where(x => !string.IsNullOrEmpty(x.Name)).ToList();
@ -227,16 +240,25 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient
var projectIds = eventProjects.Select(x => x.ProjectId).Distinct().ToList();
var baseProjects = await _projectRepository.GetListAsync(x => projectIds.Contains(x.Id) && x.Status == AvailabilityStatus.Enable);
var completionStats = await _projectService.GetProjectStatisticsBatchAsync(
projectIds,
ProjectService.ProjectStatisticType.CompletionCount);
return eventProjects.Select(ep =>
{
var p = baseProjects.FirstOrDefault(b => b.Id == ep.ProjectId);
var completionCount = 0;
if (p != null && completionStats.TryGetValue(p.Id, out var count))
{
completionCount = count;
}
return new UserEventProjectListOutput
{
Id = ep.Id,
Name = p?.Name ?? "",
Fee = ep.Price / 100m,
TeamSize = 1, // 默认为1
CompletionCount = p?.CompletionCount ?? 0
TeamSize = 1,
CompletionCount = completionCount
};
}).Where(x => !string.IsNullOrEmpty(x.Name)).ToList();
}

View File

@ -2,6 +2,7 @@ using YD_Event.Application.Project.Dtos;
using YD_Event.Core.Entities;
using Mapster;
using SqlSugar;
using Microsoft.Extensions.Logging;
namespace YD_Event.Application.Project;
@ -13,18 +14,27 @@ public class ProjectService : BaseService<YD_Event.Core.Entities.Project>, ITran
private readonly ISqlSugarRepository<YD_Event.Core.Entities.Project> _repository;
private readonly ISqlSugarRepository<ProjectGroup> _groupRepository;
private readonly ISqlSugarRepository<ProjectType> _typeRepository;
private readonly ISqlSugarRepository<EventProject> _eventProjectRepository;
private readonly ISqlSugarRepository<EventParticipationRecord> _participationRecordRepository;
private readonly IIdGenerator _idGenerator;
private readonly ILogger<ProjectService> _logger;
public ProjectService(
ISqlSugarRepository<YD_Event.Core.Entities.Project> repository,
ISqlSugarRepository<ProjectGroup> groupRepository,
ISqlSugarRepository<ProjectType> typeRepository,
IIdGenerator idGenerator) : base(repository)
ISqlSugarRepository<EventProject> eventProjectRepository,
ISqlSugarRepository<EventParticipationRecord> participationRecordRepository,
IIdGenerator idGenerator,
ILogger<ProjectService> logger) : base(repository)
{
_repository = repository;
_groupRepository = groupRepository;
_typeRepository = typeRepository;
_eventProjectRepository = eventProjectRepository;
_participationRecordRepository = participationRecordRepository;
_idGenerator = idGenerator;
_logger = logger;
}
/// <summary>
@ -60,6 +70,19 @@ public class ProjectService : BaseService<YD_Event.Core.Entities.Project>, ITran
})
.ToPagedListAsync(input);
var projectIds = result.Rows.Select(x => x.Id).ToList();
if (projectIds.Any())
{
var stats = await GetProjectStatisticsBatchAsync(projectIds, ProjectStatisticType.CompletionCount);
foreach (var item in result.Rows)
{
if (stats.TryGetValue(item.Id, out var count))
{
item.CompletionCount = count;
}
}
}
return result;
}
@ -70,7 +93,6 @@ public class ProjectService : BaseService<YD_Event.Core.Entities.Project>, ITran
[UnitOfWork]
public async Task Add(AddProjectInput input)
{
// 检查项目名称是否重复
var isExist = await _repository.IsAnyAsync(x => x.Name == input.Name);
if (isExist) throw new InvalidOperationException("该项目名称已存在");
@ -104,7 +126,6 @@ public class ProjectService : BaseService<YD_Event.Core.Entities.Project>, ITran
var entity = await _repository.GetByIdAsync(input.Id);
if (entity == null) throw new InvalidOperationException("项目不存在");
// 如果修改了名称,检查是否重复
if (entity.Name != input.Name)
{
var isExist = await _repository.IsAnyAsync(x => x.Name == input.Name && x.Id != input.Id);
@ -115,7 +136,6 @@ public class ProjectService : BaseService<YD_Event.Core.Entities.Project>, ITran
entity.UpdatedTime = DateTime.Now;
await _repository.UpdateAsync(entity);
// Update groups: Delete old, Insert new
await _groupRepository.DeleteAsync(x => x.ProjectId == entity.Id);
if (input.Groups != null && input.Groups.Any())
@ -161,7 +181,137 @@ public class ProjectService : BaseService<YD_Event.Core.Entities.Project>, ITran
var groups = await _groupRepository.GetListAsync(x => x.ProjectId == id);
dto.Groups = groups.Adapt<List<ProjectGroupDto>>();
dto.CompletionCount = await GetProjectStatisticAsync(id, ProjectStatisticType.CompletionCount);
return dto;
}
/// <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;
}
}

View File

@ -4965,6 +4965,11 @@
导出编排
</summary>
</member>
<member name="T:YD_Event.Application.Event.EventArrangementService.ArrangementExporter">
<summary>
编排导出器
</summary>
</member>
<member name="T:YD_Event.Application.Event.EventRecordService">
<summary>
参赛记录管理
@ -7634,6 +7639,37 @@
获取项目详情
</summary>
</member>
<member name="T:YD_Event.Application.Project.ProjectService.ProjectStatisticType">
<summary>
项目统计类型
</summary>
</member>
<member name="F:YD_Event.Application.Project.ProjectService.ProjectStatisticType.ParticipationCount">
<summary>
参赛人数
</summary>
</member>
<member name="F:YD_Event.Application.Project.ProjectService.ProjectStatisticType.CompletionCount">
<summary>
完成人数
</summary>
</member>
<member name="M:YD_Event.Application.Project.ProjectService.GetProjectStatisticAsync(System.Int64,YD_Event.Application.Project.ProjectService.ProjectStatisticType)">
<summary>
获取项目统计数据(单个项目)
</summary>
<param name="projectId">项目ID</param>
<param name="statisticType">统计类型</param>
<returns>统计数值</returns>
</member>
<member name="M:YD_Event.Application.Project.ProjectService.GetProjectStatisticsBatchAsync(System.Collections.Generic.List{System.Int64},YD_Event.Application.Project.ProjectService.ProjectStatisticType)">
<summary>
批量获取项目统计数据(性能优化,避免N+1查询)
</summary>
<param name="projectIds">项目ID列表</param>
<param name="statisticType">统计类型</param>
<returns>字典,Key为项目ID,Value为统计数值</returns>
</member>
<member name="T:YD_Event.Application.Project.ProjectTypeService">
<summary>
项目类型管理

View File

@ -0,0 +1,146 @@
using OfficeOpenXml;
using OfficeOpenXml.Style;
using System.Drawing;
namespace YD_Event.Core.Domain.Export;
/// <summary>
/// Excel 导出基类
/// </summary>
public abstract class ExcelExportBase
{
protected ExcelPackage Package { get; private set; }
protected ExcelWorksheet Worksheet { get; private set; }
protected ExcelExportBase()
{
ExcelPackage.LicenseContext = OfficeOpenXml.LicenseContext.NonCommercial;
Package = new ExcelPackage();
}
/// <summary>
/// 创建工作表
/// </summary>
protected void CreateWorksheet(string sheetName)
{
Worksheet = Package.Workbook.Worksheets.Add(sheetName);
}
/// <summary>
/// 设置合并单元格标题
/// </summary>
protected void SetMergeTitle(string title, int startRow, int startCol, int endRow, int endCol, Color? bgColor = null, int fontSize = 14)
{
var range = Worksheet.Cells[startRow, startCol, endRow, endCol];
range.Merge = true;
range.Value = title;
var style = range.Style;
style.Font.Bold = true;
style.Font.Size = fontSize;
style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
style.VerticalAlignment = ExcelVerticalAlignment.Center;
if (bgColor.HasValue)
{
style.Fill.PatternType = ExcelFillStyle.Solid;
style.Fill.BackgroundColor.SetColor(bgColor.Value);
}
}
/// <summary>
/// 设置列标题
/// </summary>
protected void SetHeaders(string[] headers, int rowIndex, Color? bgColor = null, int fontSize = 11)
{
for (int i = 0; i < headers.Length; i++)
{
Worksheet.Cells[rowIndex, i + 1].Value = headers[i];
}
var headerRange = Worksheet.Cells[rowIndex, 1, rowIndex, headers.Length];
var style = headerRange.Style;
style.Font.Bold = true;
style.Font.Size = fontSize;
style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
style.VerticalAlignment = ExcelVerticalAlignment.Center;
if (bgColor.HasValue)
{
style.Fill.PatternType = ExcelFillStyle.Solid;
style.Fill.BackgroundColor.SetColor(bgColor.Value);
}
SetCellBorders(headerRange, ExcelBorderStyle.Thin);
}
/// <summary>
/// 设置单元格边框
/// </summary>
protected void SetCellBorders(ExcelRange range, ExcelBorderStyle borderStyle)
{
range.Style.Border.Top.Style = borderStyle;
range.Style.Border.Bottom.Style = borderStyle;
range.Style.Border.Left.Style = borderStyle;
range.Style.Border.Right.Style = borderStyle;
}
/// <summary>
/// 设置数据行样式
/// </summary>
protected void SetDataRowStyle(int rowIndex, int colCount, Color? alternateBgColor = null, bool isAlternate = false)
{
var range = Worksheet.Cells[rowIndex, 1, rowIndex, colCount];
var style = range.Style;
style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
style.VerticalAlignment = ExcelVerticalAlignment.Center;
SetCellBorders(range, ExcelBorderStyle.Thin);
if (isAlternate && alternateBgColor.HasValue)
{
style.Fill.PatternType = ExcelFillStyle.Solid;
style.Fill.BackgroundColor.SetColor(alternateBgColor.Value);
}
}
/// <summary>
/// 设置列宽
/// </summary>
protected void SetColumnWidths(double[] widths)
{
for (int i = 0; i < widths.Length; i++)
{
Worksheet.Column(i + 1).Width = widths[i];
}
}
/// <summary>
/// 设置行高
/// </summary>
protected void SetRowHeight(int rowIndex, double height)
{
Worksheet.Row(rowIndex).Height = height;
}
/// <summary>
/// 冻结窗格
/// </summary>
protected void FreezePanes(int rowOffset, int colOffset)
{
Worksheet.View.FreezePanes(rowOffset, colOffset);
}
/// <summary>
/// 生成字节数组
/// </summary>
protected async Task<byte[]> GetAsByteArrayAsync()
{
return await Package.GetAsByteArrayAsync();
}
/// <summary>
/// 执行导出
/// </summary>
public abstract Task<byte[]> ExportAsync();
}

View File

@ -46,9 +46,9 @@ public class EventParticipationRecord : Entity<long>, ISoftDelete, ICreatedUserI
public string GroupName { get; set; }
/// <summary>
/// 参赛状态:0-未参赛,1-已参赛,2-已完赛,3-退赛
/// 参赛状态
/// </summary>
public int ParticipationStatus { get; set; }
public ParticipationStatus ParticipationStatus { get; set; }
/// <summary>
/// 参赛时间

View File

@ -0,0 +1,33 @@
using System.ComponentModel;
namespace YD_Event.Core.Enum;
/// <summary>
/// 参赛状态枚举
/// </summary>
public enum ParticipationStatus
{
/// <summary>
/// 未参赛
/// </summary>
[Description("未参赛")]
NotParticipated = 0,
/// <summary>
/// 已参赛
/// </summary>
[Description("已参赛")]
Participated = 1,
/// <summary>
/// 已完赛
/// </summary>
[Description("已完赛")]
Completed = 2,
/// <summary>
/// 退赛
/// </summary>
[Description("退赛")]
Withdrawn = 3
}

View File

@ -27,6 +27,7 @@
<PackageReference Include="QuestPDF" Version="2025.12.1" />
<PackageReference Include="QRCoder" Version="1.4.3" />
<PackageReference Include="DocumentFormat.OpenXml" Version="2.20.0" />
<PackageReference Include="EPPlus" Version="7.1.0" />
<PackageReference Include="SkiaSharp" Version="3.119.1" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="3.119.1" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.210" />

View File

@ -433,6 +433,61 @@
是否绘制静区
</summary>
</member>
<member name="T:YD_Event.Core.Domain.Export.ExcelExportBase">
<summary>
Excel 导出基类
</summary>
</member>
<member name="M:YD_Event.Core.Domain.Export.ExcelExportBase.CreateWorksheet(System.String)">
<summary>
创建工作表
</summary>
</member>
<member name="M:YD_Event.Core.Domain.Export.ExcelExportBase.SetMergeTitle(System.String,System.Int32,System.Int32,System.Int32,System.Int32,System.Nullable{System.Drawing.Color},System.Int32)">
<summary>
设置合并单元格标题
</summary>
</member>
<member name="M:YD_Event.Core.Domain.Export.ExcelExportBase.SetHeaders(System.String[],System.Int32,System.Nullable{System.Drawing.Color},System.Int32)">
<summary>
设置列标题
</summary>
</member>
<member name="M:YD_Event.Core.Domain.Export.ExcelExportBase.SetCellBorders(OfficeOpenXml.ExcelRange,OfficeOpenXml.Style.ExcelBorderStyle)">
<summary>
设置单元格边框
</summary>
</member>
<member name="M:YD_Event.Core.Domain.Export.ExcelExportBase.SetDataRowStyle(System.Int32,System.Int32,System.Nullable{System.Drawing.Color},System.Boolean)">
<summary>
设置数据行样式
</summary>
</member>
<member name="M:YD_Event.Core.Domain.Export.ExcelExportBase.SetColumnWidths(System.Double[])">
<summary>
设置列宽
</summary>
</member>
<member name="M:YD_Event.Core.Domain.Export.ExcelExportBase.SetRowHeight(System.Int32,System.Double)">
<summary>
设置行高
</summary>
</member>
<member name="M:YD_Event.Core.Domain.Export.ExcelExportBase.FreezePanes(System.Int32,System.Int32)">
<summary>
冻结窗格
</summary>
</member>
<member name="M:YD_Event.Core.Domain.Export.ExcelExportBase.GetAsByteArrayAsync">
<summary>
生成字节数组
</summary>
</member>
<member name="M:YD_Event.Core.Domain.Export.ExcelExportBase.ExportAsync">
<summary>
执行导出
</summary>
</member>
<member name="T:YD_Event.Core.Entities.Entity`1">
<summary>
表实体继承
@ -1341,7 +1396,7 @@
</member>
<member name="P:YD_Event.Core.Entities.EventParticipationRecord.ParticipationStatus">
<summary>
参赛状态:0-未参赛,1-已参赛,2-已完赛,3-退赛
参赛状态
</summary>
</member>
<member name="P:YD_Event.Core.Entities.EventParticipationRecord.ParticipationTime">
@ -4297,6 +4352,31 @@
已完成
</summary>
</member>
<member name="T:YD_Event.Core.Enum.ParticipationStatus">
<summary>
参赛状态枚举
</summary>
</member>
<member name="F:YD_Event.Core.Enum.ParticipationStatus.NotParticipated">
<summary>
未参赛
</summary>
</member>
<member name="F:YD_Event.Core.Enum.ParticipationStatus.Participated">
<summary>
已参赛
</summary>
</member>
<member name="F:YD_Event.Core.Enum.ParticipationStatus.Completed">
<summary>
已完赛
</summary>
</member>
<member name="F:YD_Event.Core.Enum.ParticipationStatus.Withdrawn">
<summary>
退赛
</summary>
</member>
<member name="T:YD_Event.Core.Enum.PersonType">
<summary>
人员角色类型