赛事项目关联表重构

This commit is contained in:
马梓彭 2026-03-18 16:25:49 +08:00
parent b1e918e5cb
commit 11b90517ee
14 changed files with 670 additions and 286 deletions

View File

@ -18,6 +18,7 @@ public class EventClientController : IDynamicApiController
{
private readonly ISqlSugarRepository<EventInfo> _eventRepository;
private readonly ISqlSugarRepository<YD_Event.Core.Entities.Project> _projectRepository;
private readonly ISqlSugarRepository<EventProject> _eventProjectRepository;
private readonly ISqlSugarRepository<ProjectGroup> _groupRepository;
private readonly ISqlSugarRepository<EventRegistration> _registrationRepository;
private readonly ISqlSugarRepository<EventRegistrationItem> _registrationItemRepository;
@ -31,6 +32,7 @@ public class EventClientController : IDynamicApiController
public EventClientController(
ISqlSugarRepository<EventInfo> eventRepository,
ISqlSugarRepository<YD_Event.Core.Entities.Project> projectRepository,
ISqlSugarRepository<EventProject> eventProjectRepository,
ISqlSugarRepository<ProjectGroup> groupRepository,
ISqlSugarRepository<EventRegistration> registrationRepository,
ISqlSugarRepository<EventRegistrationItem> registrationItemRepository,
@ -43,6 +45,7 @@ public class EventClientController : IDynamicApiController
{
_eventRepository = eventRepository;
_projectRepository = projectRepository;
_eventProjectRepository = eventProjectRepository;
_groupRepository = groupRepository;
_registrationRepository = registrationRepository;
_registrationItemRepository = registrationItemRepository;
@ -164,18 +167,22 @@ public class EventClientController : IDynamicApiController
if (evt == null) throw Oops.Bah("赛事不存在");
// 获取项目及组别
var projects = await _projectRepository.AsQueryable()
var eventProjects = await _eventProjectRepository.AsQueryable()
.Where(ep => ep.EventId == id)
.ToListAsync();
var projectIds = eventProjects.Select(ep => ep.ProjectId).Distinct().ToList();
var baseProjects = await _projectRepository.AsQueryable()
.LeftJoin<ProjectType>((p, t) => p.ProjectTypeId == t.Id)
.Where(p => p.EventId == id && !p.DeleteMark && p.Status == AvailabilityStatus.Enable)
.Where(p => projectIds.Contains(p.Id) && !p.DeleteMark && p.Status == AvailabilityStatus.Enable)
.Select((p, t) => new {
p.Id,
p.Name,
p.Fee,
TypeName = t.Name
})
.ToListAsync();
var projectIds = projects.Select(p => p.Id).ToList();
var groups = await _groupRepository.AsQueryable()
.Where(g => projectIds.Contains(g.ProjectId) && !g.DeleteMark)
.ToListAsync();
@ -222,20 +229,24 @@ public class EventClientController : IDynamicApiController
LogoUrl = u.LogoUrl
}).ToList(),
Projects = projects.Select(p => new EventProjectDto
Projects = eventProjects.Select(ep =>
{
Id = p.Id,
Name = p.Name,
TypeName = p.TypeName,
Fee = p.Fee,
Groups = groups.Where(g => g.ProjectId == p.Id).Select(g => new EventProjectGroupDto
var bp = baseProjects.FirstOrDefault(b => b.Id == ep.ProjectId);
return new EventProjectDto
{
Id = g.Id,
GroupName = g.GroupName,
GenderRequirement = g.Gender == Gender.Male ? "男" : (g.Gender == Gender.Female ? "女" : "不限"),
AgeRequirement = $"{g.BirthDateStart:yyyy-MM-dd} 至 {g.BirthDateEnd:yyyy-MM-dd}"
}).ToList()
}).ToList()
Id = ep.Id,
Name = bp?.Name ?? "",
TypeName = bp?.TypeName ?? "",
Fee = ep.Price / 100m,
Groups = groups.Where(g => g.ProjectId == ep.ProjectId).Select(g => new EventProjectGroupDto
{
Id = g.Id,
GroupName = g.GroupName,
GenderRequirement = g.Gender == Gender.Male ? "男" : (g.Gender == Gender.Female ? "女" : "不限"),
AgeRequirement = $"{g.BirthDateStart:yyyy-MM-dd} 至 {g.BirthDateEnd:yyyy-MM-dd}"
}).ToList()
};
}).Where(x => !string.IsNullOrEmpty(x.Name)).ToList()
};
return detail;
@ -306,8 +317,11 @@ public class EventClientController : IDynamicApiController
foreach (var item in input.Items)
{
var project = await _projectRepository.GetFirstAsync(p => p.Id == item.ProjectId);
if (project == null) throw Oops.Bah($"项目不存在: {item.ProjectId}");
var eventProject = await _eventProjectRepository.GetFirstAsync(p => p.Id == item.ProjectId);
if (eventProject == null) throw Oops.Bah($"项目不存在: {item.ProjectId}");
var project = await _projectRepository.GetFirstAsync(p => p.Id == eventProject.ProjectId);
if (project == null) throw Oops.Bah($"关联基础项目不存在: {item.ProjectId}");
// 校验组别
// 略,假设前端传参正确,或需根据 GroupId 查
@ -323,9 +337,9 @@ public class EventClientController : IDynamicApiController
ProjectId = item.ProjectId,
ProjectName = project.Name,
GroupName = item.GroupName,
UnitPrice = project.Fee,
UnitPrice = eventProject.Price / 100m,
PersonCount = item.Persons.Count,
TotalPrice = project.Fee * item.Persons.Count,
TotalPrice = (eventProject.Price / 100m) * item.Persons.Count,
CreatedUserId = userId,
CreatedTime = DateTime.Now
};

View File

@ -300,40 +300,45 @@ public class AddEventInput
public class EventProjectInput
{
/// <summary>
/// 项目ID (更新时使用)
/// 赛事项目ID (更新时使用)
/// </summary>
public long? Id { get; set; }
/// <summary>
/// 项目名称
/// 项目ID
/// </summary>
[Required(ErrorMessage = "项目名称不能为空")]
public string Name { get; set; }
[Required(ErrorMessage = "项目ID不能为空")]
public long ProjectId { get; set; }
/// <summary>
/// 项目名称 (显示用)
/// </summary>
public string? Name { get; set; }
/// <summary>
/// 项目类型ID
/// 项目类型ID (显示用)
/// </summary>
public long ProjectTypeId { get; set; }
public long? ProjectTypeId { get; set; }
/// <summary>
/// 项目类型名称 (显示用)
/// </summary>
public string? ProjectTypeName { get; set; }
/// <summary>
/// 完成人数
/// </summary>
public int CompletionCount { get; set; }
/// <summary>
/// 比赛时长(分)
/// 性别要求
/// </summary>
public int DurationMinutes { get; set; }
public Gender GenderType { get; set; }
/// <summary>
/// 比赛时长(秒)
/// 比赛时长(分) (显示用)
/// </summary>
public int DurationSeconds { get; set; }
public int? DurationMinutes { get; set; }
/// <summary>
/// 比赛时长(秒) (显示用)
/// </summary>
public int? DurationSeconds { get; set; }
/// <summary>
/// 项目费用(Step 4)
@ -348,7 +353,44 @@ public class EventProjectInput
/// <summary>
/// 组别列表
/// </summary>
public List<ProjectGroupInput> Groups { get; set; }
public List<EventProjectGroupInput> Groups { get; set; }
}
/// <summary>
/// 赛事项目组别输入
/// </summary>
public class EventProjectGroupInput
{
/// <summary>
/// 赛事项目组别ID (更新时使用)
/// </summary>
public long? Id { get; set; }
/// <summary>
/// 关联的项目组别ID
/// </summary>
[Required(ErrorMessage = "项目组别ID不能为空")]
public long ProjectGroupId { get; set; }
/// <summary>
/// 组别名称 (显示用)
/// </summary>
public string? GroupName { get; set; }
/// <summary>
/// 出生日期起始日期 (显示用)
/// </summary>
public DateTime? BirthDateStart { get; set; }
/// <summary>
/// 出生日期结束日期 (显示用)
/// </summary>
public DateTime? BirthDateEnd { get; set; }
/// <summary>
/// 性别要求 (显示用)
/// </summary>
public Gender? Gender { get; set; }
}
/// <summary>

View File

@ -170,6 +170,30 @@ public class SaveFeeConfigInput
/// 费用配置
/// </summary>
public EventFeeConfigInput FeeConfig { get; set; }
/// <summary>
/// 项目单价列表(当收费模式为“单价(项目)”时填写)
/// </summary>
public List<ProjectFeeInput>? ProjectFees { get; set; }
}
/// <summary>
/// 项目费用输入
/// </summary>
public class ProjectFeeInput
{
/// <summary>
/// 项目ID
/// </summary>
[Required(ErrorMessage = "项目ID不能为空")]
public long ProjectId { get; set; }
/// <summary>
/// 项目单价
/// </summary>
[Required(ErrorMessage = "项目单价不能为空")]
[Range(0.01, (double)decimal.MaxValue, ErrorMessage = "项目单价必须大于0")]
public decimal Fee { get; set; }
}
/// <summary>

View File

@ -10,6 +10,7 @@ namespace YD_Event.Application.Event;
/// </summary>
public class EventArrangementService : BaseService<YD_Event.Core.Entities.Project>, ITransient
{
private readonly ISqlSugarRepository<EventProject> _eventProjectRepository;
private readonly ISqlSugarRepository<YD_Event.Core.Entities.Project> _projectRepository;
private readonly ISqlSugarRepository<ProjectGroup> _groupRepository;
private readonly ISqlSugarRepository<EventRegistrationPerson> _personRepository;
@ -17,12 +18,14 @@ public class EventArrangementService : BaseService<YD_Event.Core.Entities.Projec
private readonly ISqlSugarRepository<ProjectType> _projectTypeRepository;
public EventArrangementService(
ISqlSugarRepository<EventProject> eventProjectRepository,
ISqlSugarRepository<YD_Event.Core.Entities.Project> projectRepository,
ISqlSugarRepository<ProjectGroup> groupRepository,
ISqlSugarRepository<EventRegistrationPerson> personRepository,
ISqlSugarRepository<EventRegistration> registrationRepository,
ISqlSugarRepository<ProjectType> projectTypeRepository) : base(projectRepository)
{
_eventProjectRepository = eventProjectRepository;
_projectRepository = projectRepository;
_groupRepository = groupRepository;
_personRepository = personRepository;
@ -36,10 +39,12 @@ public class EventArrangementService : BaseService<YD_Event.Core.Entities.Projec
[DisplayName("获取编排项目列表")]
public async Task<List<ArrangementProjectListOutput>> GetList(long eventId)
{
var projects = await _projectRepository.GetListAsync(x => x.EventId == eventId);
var eventProjects = await _eventProjectRepository.GetListAsync(x => x.EventId == eventId);
var projectIds = eventProjects.Select(x => x.ProjectId).Distinct().ToList();
var projects = await _projectRepository.GetListAsync(x => projectIds.Contains(x.Id));
projects = projects.OrderBy(x => x.SortIndex).ToList();
var groups = await _groupRepository.GetListAsync(x => projects.Select(p => p.Id).Contains(x.ProjectId));
var groups = await _groupRepository.GetListAsync(x => projectIds.Contains(x.ProjectId));
// 获取项目类型信息
var typeIds = projects.Select(x => x.ProjectTypeId).Distinct().ToList();
@ -54,13 +59,16 @@ public class EventArrangementService : BaseService<YD_Event.Core.Entities.Projec
.ToListAsync();
var result = new List<ArrangementProjectListOutput>();
foreach (var proj in projects)
foreach (var eventProj in eventProjects)
{
var proj = projects.FirstOrDefault(x => x.Id == eventProj.ProjectId);
if (proj == null) continue;
var type = types.FirstOrDefault(x => x.Id == proj.ProjectTypeId);
var dto = new ArrangementProjectListOutput
{
ProjectId = proj.Id,
ProjectId = eventProj.Id,
ProjectName = proj.Name,
ProjectType = type?.Name ?? "未知类型",
DurationSeconds = proj.DurationSeconds,
@ -72,7 +80,7 @@ public class EventArrangementService : BaseService<YD_Event.Core.Entities.Projec
var projGroups = groups.Where(g => g.ProjectId == proj.Id).ToList();
foreach (var group in projGroups)
{
var countObj = counts.FirstOrDefault(c => c.ProjectId == proj.Id && c.GroupName == group.GroupName);
var countObj = counts.FirstOrDefault(c => c.ProjectId == eventProj.Id && c.GroupName == group.GroupName);
dto.Groups.Add(new ArrangementGroupDto
{
GroupName = group.GroupName,
@ -98,15 +106,22 @@ public class EventArrangementService : BaseService<YD_Event.Core.Entities.Projec
[DisplayName("更新编排设置")]
public async Task Update(ArrangementUpdateInput input)
{
var eventProjectIds = input.Settings.Select(x => x.ProjectId).ToList();
var eventProjects = await _eventProjectRepository.GetListAsync(x => eventProjectIds.Contains(x.Id));
foreach (var setting in input.Settings)
{
await _projectRepository.UpdateAsync(x => new YD_Event.Core.Entities.Project
{
VenueCount = setting.VenueCount,
SortIndex = setting.SortIndex,
DurationSeconds = setting.DurationSeconds,
DurationMinutes = setting.DurationSeconds / 60
}, x => x.Id == setting.ProjectId);
var ep = eventProjects.FirstOrDefault(x => x.Id == setting.ProjectId);
if (ep != null)
{
await _projectRepository.UpdateAsync(x => new YD_Event.Core.Entities.Project
{
VenueCount = setting.VenueCount,
SortIndex = setting.SortIndex,
DurationSeconds = setting.DurationSeconds,
DurationMinutes = setting.DurationSeconds / 60
}, x => x.Id == ep.ProjectId);
}
}
}
@ -117,20 +132,25 @@ public class EventArrangementService : BaseService<YD_Event.Core.Entities.Projec
public async Task<List<ArrangementPreviewOutput>> Preview(long eventId)
{
// 1. 获取项目(按顺序)
var projects = await _projectRepository.GetListAsync(x => x.EventId == eventId);
var eventProjects = await _eventProjectRepository.GetListAsync(x => x.EventId == eventId);
var projectIds = eventProjects.Select(x => x.ProjectId).Distinct().ToList();
var projects = await _projectRepository.GetListAsync(x => projectIds.Contains(x.Id));
projects = projects.OrderBy(x => x.SortIndex).ToList();
var result = new List<ArrangementPreviewOutput>();
// 2. 生成排期
foreach (var proj in projects)
foreach (var eventProj in eventProjects)
{
var proj = projects.FirstOrDefault(x => x.Id == eventProj.ProjectId);
if (proj == null) continue;
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 == proj.Id && (r.PaymentStatus == 1 || r.RegistrationStatus == 2))
.Where((p, r) => p.ProjectId == eventProj.Id && (r.PaymentStatus == 1 || r.RegistrationStatus == 2))
.OrderBy(p => p.GroupName)
.OrderBy(p => p.Id)
.Select((p, r) => new {

View File

@ -19,6 +19,8 @@ public class EventService : BaseService<EventInfo>, ITransient
private readonly ISqlSugarRepository<SysCity> _cityRepository;
private readonly ISqlSugarRepository<SysDistrict> _districtRepository;
private readonly ISqlSugarRepository<YD_Event.Core.Entities.Project> _projectRepository;
private readonly ISqlSugarRepository<EventProject> _eventProjectRepository;
private readonly ISqlSugarRepository<EventProjectGroup> _eventProjectGroupRepository;
private readonly ISqlSugarRepository<ProjectGroup> _projectGroupRepository;
private readonly ISqlSugarRepository<ProjectType> _projectTypeRepository;
private readonly ISqlSugarRepository<EventRegistrationLimit> _registrationLimitRepository;
@ -37,6 +39,8 @@ public class EventService : BaseService<EventInfo>, ITransient
ISqlSugarRepository<SysCity> cityRepository,
ISqlSugarRepository<SysDistrict> districtRepository,
ISqlSugarRepository<YD_Event.Core.Entities.Project> projectRepository,
ISqlSugarRepository<EventProject> eventProjectRepository,
ISqlSugarRepository<EventProjectGroup> eventProjectGroupRepository,
ISqlSugarRepository<ProjectGroup> projectGroupRepository,
ISqlSugarRepository<ProjectType> projectTypeRepository,
ISqlSugarRepository<EventRegistrationLimit> registrationLimitRepository,
@ -54,6 +58,8 @@ public class EventService : BaseService<EventInfo>, ITransient
_cityRepository = cityRepository;
_districtRepository = districtRepository;
_projectRepository = projectRepository;
_eventProjectRepository = eventProjectRepository;
_eventProjectGroupRepository = eventProjectGroupRepository;
_projectGroupRepository = projectGroupRepository;
_projectTypeRepository = projectTypeRepository;
_registrationLimitRepository = registrationLimitRepository;
@ -171,28 +177,62 @@ public class EventService : BaseService<EventInfo>, ITransient
}
// 4. 获取项目列表 (Step 3)
var projects = await _projectRepository.GetListAsync(x => x.EventId == id);
if (projects.Any())
var eventProjects = await _eventProjectRepository.GetListAsync(x => x.EventId == id);
if (eventProjects.Any())
{
var projectIds = projects.Select(x => x.Id).ToList();
var groups = await _projectGroupRepository.GetListAsync(x => projectIds.Contains(x.ProjectId));
var projectLimits = await _projectLimitRepository.GetListAsync(x => projectIds.Contains(x.ProjectId));
var eventProjectIds = eventProjects.Select(x => x.Id).ToList();
var eventProjectGroups = await _eventProjectGroupRepository.GetListAsync(x => eventProjectIds.Contains(x.EventProjectId));
var projectLimits = await _projectLimitRepository.GetListAsync(x => eventProjectIds.Contains(x.ProjectId));
// 获取关联的原始项目信息
var projectIds = eventProjects.Select(x => x.ProjectId).Distinct().ToList();
var baseProjects = await _projectRepository.GetListAsync(x => projectIds.Contains(x.Id));
var baseProjectGroups = await _projectGroupRepository.GetListAsync(x => projectIds.Contains(x.ProjectId));
// 获取项目类型信息
var typeIds = projects.Select(x => x.ProjectTypeId).Distinct().ToList();
var typeIds = baseProjects.Select(x => x.ProjectTypeId).Distinct().ToList();
var types = await _projectTypeRepository.GetListAsync(x => typeIds.Contains(x.Id));
output.Projects = projects.Select(p =>
output.Projects = eventProjects.Select(ep =>
{
var dto = p.Adapt<EventProjectInput>();
var type = types.FirstOrDefault(x => x.Id == p.ProjectTypeId);
if (type != null)
var baseProj = baseProjects.FirstOrDefault(p => p.Id == ep.ProjectId);
var dto = new EventProjectInput
{
dto.ProjectTypeName = type.Name;
Id = ep.Id,
ProjectId = ep.ProjectId,
GenderType = ep.GenderType,
Fee = ep.Price / 100m,
Name = baseProj?.Name,
ProjectTypeId = baseProj?.ProjectTypeId,
DurationMinutes = baseProj?.DurationMinutes,
DurationSeconds = baseProj?.DurationSeconds
};
if (baseProj != null)
{
var type = types.FirstOrDefault(x => x.Id == baseProj.ProjectTypeId);
if (type != null)
{
dto.ProjectTypeName = type.Name;
}
}
dto.Groups = groups.Where(g => g.ProjectId == p.Id).Select(g => g.Adapt<ProjectGroupInput>()).ToList();
var limit = projectLimits.FirstOrDefault(l => l.ProjectId == p.Id);
var epGroups = eventProjectGroups.Where(g => g.EventProjectId == ep.Id).ToList();
dto.Groups = epGroups.Select(eg =>
{
var baseGroup = baseProjectGroups.FirstOrDefault(bg => bg.Id == eg.ProjectGroupId);
return new EventProjectGroupInput
{
Id = eg.Id,
ProjectGroupId = eg.ProjectGroupId,
GroupName = baseGroup?.GroupName,
BirthDateStart = baseGroup?.BirthDateStart,
BirthDateEnd = baseGroup?.BirthDateEnd,
Gender = baseGroup?.Gender
};
}).ToList();
var limit = projectLimits.FirstOrDefault(l => l.ProjectId == ep.Id);
if (limit != null) dto.LimitCount = limit.LimitCount;
return dto;
}).ToList();
@ -266,29 +306,43 @@ public class EventService : BaseService<EventInfo>, ITransient
// 2. 自定义字段 (JSON) - Already in eventInfo
var projectFees = new List<ProjectFeeInput>();
// 3. 保存项目信息 (Step 3)
if (input.Projects != null && input.Projects.Any())
{
foreach (var projInput in input.Projects)
{
var project = projInput.Adapt<YD_Event.Core.Entities.Project>();
project.Id = _idGenerator.NewLong();
project.EventId = eventInfo.Id;
project.Status = AvailabilityStatus.Enable;
project.CreatedTime = DateTime.Now;
await _projectRepository.InsertAsync(project);
var eventProject = new EventProject
{
Id = _idGenerator.NewLong(),
EventId = eventInfo.Id,
ProjectId = projInput.ProjectId,
GenderType = projInput.GenderType,
Price = (int)(projInput.Fee * 100),
CreatedTime = DateTime.Now
};
await _eventProjectRepository.InsertAsync(eventProject);
projectFees.Add(new ProjectFeeInput { ProjectId = eventProject.Id, Fee = projInput.Fee });
// 保存项目分组
if (projInput.Groups != null && projInput.Groups.Any())
{
var groups = projInput.Groups.Select(g =>
{
var group = g.Adapt<ProjectGroup>();
group.Id = _idGenerator.NewLong();
group.ProjectId = project.Id;
var group = new EventProjectGroup
{
Id = _idGenerator.NewLong(),
EventId = eventInfo.Id,
EventProjectId = eventProject.Id,
ProjectId = projInput.ProjectId,
ProjectGroupId = g.ProjectGroupId,
CreatedTime = DateTime.Now
};
return group;
}).ToList();
await _projectGroupRepository.InsertRangeAsync(groups);
await _eventProjectGroupRepository.InsertRangeAsync(groups);
}
// 保存项目报名限制 (Step 3 - Project Limit)
@ -298,8 +352,9 @@ public class EventService : BaseService<EventInfo>, ITransient
{
Id = _idGenerator.NewLong(),
EventId = eventInfo.Id,
ProjectId = project.Id,
LimitCount = projInput.LimitCount.Value
ProjectId = eventProject.Id,
LimitCount = projInput.LimitCount.Value,
CreatedTime = DateTime.Now
};
await _projectLimitRepository.InsertAsync(projLimit);
}
@ -318,10 +373,18 @@ public class EventService : BaseService<EventInfo>, ITransient
// 5. 保存费用配置 (Step 4)
if (input.FeeConfig != null)
{
var feeConfig = input.FeeConfig.Adapt<EventFeeConfig>();
feeConfig.Id = _idGenerator.NewLong();
feeConfig.EventId = eventInfo.Id;
await _feeConfigRepository.InsertAsync(feeConfig);
// 满足 SaveFeeConfig 的前置状态要求
eventInfo.ProcessStatus = ProcessStatus.ProjectConfigCompleted;
await _repository.UpdateAsync(eventInfo);
var feeConfigInput = new SaveFeeConfigInput
{
EventId = eventInfo.Id,
FeeConfig = input.FeeConfig,
ProjectFees = projectFees
};
await SaveFeeConfig(feeConfigInput);
}
}
@ -366,38 +429,52 @@ public class EventService : BaseService<EventInfo>, ITransient
// 2. 更新自定义字段 (JSON) - Updated in eventInfo
var projectFees = new List<ProjectFeeInput>();
// 3. 更新项目信息
var oldProjects = await _projectRepository.GetListAsync(x => x.EventId == input.Id);
var oldProjectIds = oldProjects.Select(x => x.Id).ToList();
var oldEventProjects = await _eventProjectRepository.GetListAsync(x => x.EventId == input.Id);
var oldEventProjectIds = oldEventProjects.Select(x => x.Id).ToList();
if (oldProjectIds.Any())
if (oldEventProjectIds.Any())
{
await _projectGroupRepository.DeleteAsync(x => oldProjectIds.Contains(x.ProjectId));
await _projectLimitRepository.DeleteAsync(x => oldProjectIds.Contains(x.ProjectId));
await _projectRepository.DeleteAsync(x => x.EventId == input.Id);
await _eventProjectGroupRepository.DeleteAsync(x => oldEventProjectIds.Contains(x.EventProjectId));
await _projectLimitRepository.DeleteAsync(x => oldEventProjectIds.Contains(x.ProjectId));
await _eventProjectRepository.DeleteAsync(x => x.EventId == input.Id);
}
if (input.Projects != null && input.Projects.Any())
{
foreach (var projInput in input.Projects)
{
var project = projInput.Adapt<YD_Event.Core.Entities.Project>();
project.Id = _idGenerator.NewLong();
project.EventId = eventInfo.Id;
project.Status = AvailabilityStatus.Enable;
project.CreatedTime = DateTime.Now;
await _projectRepository.InsertAsync(project);
var eventProject = new EventProject
{
Id = _idGenerator.NewLong(),
EventId = eventInfo.Id,
ProjectId = projInput.ProjectId,
GenderType = projInput.GenderType,
Price = (int)(projInput.Fee * 100),
CreatedTime = DateTime.Now
};
await _eventProjectRepository.InsertAsync(eventProject);
projectFees.Add(new ProjectFeeInput { ProjectId = eventProject.Id, Fee = projInput.Fee });
if (projInput.Groups != null && projInput.Groups.Any())
{
var groups = projInput.Groups.Select(g =>
{
var group = g.Adapt<ProjectGroup>();
group.Id = _idGenerator.NewLong();
group.ProjectId = project.Id;
var group = new EventProjectGroup
{
Id = _idGenerator.NewLong(),
EventId = eventInfo.Id,
EventProjectId = eventProject.Id,
ProjectId = projInput.ProjectId,
ProjectGroupId = g.ProjectGroupId,
CreatedTime = DateTime.Now
};
return group;
}).ToList();
await _projectGroupRepository.InsertRangeAsync(groups);
await _eventProjectGroupRepository.InsertRangeAsync(groups);
}
if (projInput.LimitCount.HasValue)
@ -406,8 +483,9 @@ public class EventService : BaseService<EventInfo>, ITransient
{
Id = _idGenerator.NewLong(),
EventId = eventInfo.Id,
ProjectId = project.Id,
LimitCount = projInput.LimitCount.Value
ProjectId = eventProject.Id,
LimitCount = projInput.LimitCount.Value,
CreatedTime = DateTime.Now
};
await _projectLimitRepository.InsertAsync(projLimit);
}
@ -425,13 +503,23 @@ public class EventService : BaseService<EventInfo>, ITransient
}
// 5. 更新费用配置
await _feeConfigRepository.DeleteAsync(x => x.EventId == input.Id);
if (input.FeeConfig != null)
{
var feeConfig = input.FeeConfig.Adapt<EventFeeConfig>();
feeConfig.Id = _idGenerator.NewLong();
feeConfig.EventId = eventInfo.Id;
await _feeConfigRepository.InsertAsync(feeConfig);
// 满足 SaveFeeConfig 的前置状态要求
if (eventInfo.ProcessStatus < ProcessStatus.ProjectConfigCompleted)
{
eventInfo.ProcessStatus = ProcessStatus.ProjectConfigCompleted;
await _repository.UpdateAsync(eventInfo);
}
var feeConfigInput = new SaveFeeConfigInput
{
EventId = eventInfo.Id,
FeeConfig = input.FeeConfig,
ProjectFees = projectFees
};
await SaveFeeConfig(feeConfigInput);
}
}
@ -629,37 +717,47 @@ public class EventService : BaseService<EventInfo>, ITransient
}
// 1. 更新项目信息 (全量替换)
var oldProjects = await _projectRepository.GetListAsync(x => x.EventId == input.EventId);
var oldProjectIds = oldProjects.Select(x => x.Id).ToList();
var oldEventProjects = await _eventProjectRepository.GetListAsync(x => x.EventId == input.EventId);
var oldEventProjectIds = oldEventProjects.Select(x => x.Id).ToList();
if (oldProjectIds.Any())
if (oldEventProjectIds.Any())
{
await _projectGroupRepository.DeleteAsync(x => oldProjectIds.Contains(x.ProjectId));
await _projectLimitRepository.DeleteAsync(x => oldProjectIds.Contains(x.ProjectId));
await _projectRepository.DeleteAsync(x => x.EventId == input.EventId);
await _eventProjectGroupRepository.DeleteAsync(x => oldEventProjectIds.Contains(x.EventProjectId));
await _projectLimitRepository.DeleteAsync(x => oldEventProjectIds.Contains(x.ProjectId));
await _eventProjectRepository.DeleteAsync(x => x.EventId == input.EventId);
}
if (input.Projects != null && input.Projects.Any())
{
foreach (var projInput in input.Projects)
{
var project = projInput.Adapt<YD_Event.Core.Entities.Project>();
project.Id = _idGenerator.NewLong();
project.EventId = input.EventId;
project.Status = AvailabilityStatus.Enable;
project.CreatedTime = DateTime.Now;
await _projectRepository.InsertAsync(project);
var eventProject = new EventProject
{
Id = _idGenerator.NewLong(),
EventId = input.EventId,
ProjectId = projInput.ProjectId,
GenderType = projInput.GenderType,
Price = (int)(projInput.Fee * 100),
CreatedTime = DateTime.Now
};
await _eventProjectRepository.InsertAsync(eventProject);
if (projInput.Groups != null && projInput.Groups.Any())
{
var groups = projInput.Groups.Select(g =>
{
var group = g.Adapt<ProjectGroup>();
group.Id = _idGenerator.NewLong();
group.ProjectId = project.Id;
var group = new EventProjectGroup
{
Id = _idGenerator.NewLong(),
EventId = input.EventId,
EventProjectId = eventProject.Id,
ProjectId = projInput.ProjectId,
ProjectGroupId = g.ProjectGroupId,
CreatedTime = DateTime.Now
};
return group;
}).ToList();
await _projectGroupRepository.InsertRangeAsync(groups);
await _eventProjectGroupRepository.InsertRangeAsync(groups);
}
if (projInput.LimitCount.HasValue)
@ -668,8 +766,9 @@ public class EventService : BaseService<EventInfo>, ITransient
{
Id = _idGenerator.NewLong(),
EventId = input.EventId,
ProjectId = project.Id,
LimitCount = projInput.LimitCount.Value
ProjectId = eventProject.Id,
LimitCount = projInput.LimitCount.Value,
CreatedTime = DateTime.Now
};
await _projectLimitRepository.InsertAsync(projLimit);
}
@ -711,6 +810,40 @@ public class EventService : BaseService<EventInfo>, ITransient
throw new InvalidOperationException("请先完成项目配置");
}
// 验证单价(项目)模式下的项目单价
if (input.FeeConfig != null && input.FeeConfig.ChargeMode == ChargeMode.UnitPriceProject)
{
if (input.ProjectFees == null || !input.ProjectFees.Any())
{
throw new InvalidOperationException("收费模式为“单价(项目)”时,必须提供项目单价信息");
}
var projectIds = input.ProjectFees.Select(x => x.ProjectId).ToList();
var eventProjects = await _eventProjectRepository.GetListAsync(x => x.EventId == input.EventId && projectIds.Contains(x.Id));
foreach (var feeInput in input.ProjectFees)
{
if (feeInput.Fee <= 0)
{
throw new InvalidOperationException("项目单价必须大于0");
}
// 格式验证:最多保留两位小数
if (Math.Round(feeInput.Fee, 2) != feeInput.Fee)
{
throw new InvalidOperationException("项目单价格式不正确,最多保留两位小数");
}
var proj = eventProjects.FirstOrDefault(p => p.Id == feeInput.ProjectId);
if (proj != null)
{
proj.Price = (int)(feeInput.Fee * 100);
proj.UpdatedTime = DateTime.Now;
await _eventProjectRepository.UpdateAsync(proj);
}
}
}
// 更新费用配置
await _feeConfigRepository.DeleteAsync(x => x.EventId == input.EventId);
if (input.FeeConfig != null)
@ -719,6 +852,9 @@ public class EventService : BaseService<EventInfo>, ITransient
feeConfig.Id = _idGenerator.NewLong();
feeConfig.EventId = input.EventId;
await _feeConfigRepository.InsertAsync(feeConfig);
// 更新赛事的 ChargeMode
eventInfo.ChargeMode = feeConfig.ChargeMode;
}
// 生成二维码URL

View File

@ -20,7 +20,10 @@ public class UserCompetitionService : IDynamicApiController, ITransient
{
private readonly ISqlSugarRepository<EventInfo> _eventRepository;
private readonly ISqlSugarRepository<EventUnit> _unitRepository;
private readonly ISqlSugarRepository<EventProject> _eventProjectRepository;
private readonly ISqlSugarRepository<EventProjectGroup> _eventProjectGroupRepository;
private readonly ISqlSugarRepository<YD_Event.Core.Entities.Project> _projectRepository;
private readonly ISqlSugarRepository<ProjectGroup> _projectGroupRepository;
private readonly ISqlSugarRepository<EventRegistration> _registrationRepository;
private readonly ISqlSugarRepository<EventRegistrationItem> _registrationItemRepository;
private readonly ISqlSugarRepository<EventRegistrationPerson> _registrationPersonRepository;
@ -37,7 +40,10 @@ public class UserCompetitionService : IDynamicApiController, ITransient
public UserCompetitionService(
ISqlSugarRepository<EventInfo> eventRepository,
ISqlSugarRepository<EventUnit> unitRepository,
ISqlSugarRepository<EventProject> eventProjectRepository,
ISqlSugarRepository<EventProjectGroup> eventProjectGroupRepository,
ISqlSugarRepository<YD_Event.Core.Entities.Project> projectRepository,
ISqlSugarRepository<ProjectGroup> projectGroupRepository,
ISqlSugarRepository<EventRegistration> registrationRepository,
ISqlSugarRepository<EventRegistrationItem> registrationItemRepository,
ISqlSugarRepository<EventRegistrationPerson> registrationPersonRepository,
@ -53,7 +59,10 @@ public class UserCompetitionService : IDynamicApiController, ITransient
{
_eventRepository = eventRepository;
_unitRepository = unitRepository;
_eventProjectRepository = eventProjectRepository;
_eventProjectGroupRepository = eventProjectGroupRepository;
_projectRepository = projectRepository;
_projectGroupRepository = projectGroupRepository;
_registrationRepository = registrationRepository;
_registrationItemRepository = registrationItemRepository;
_registrationPersonRepository = registrationPersonRepository;
@ -146,14 +155,21 @@ public class UserCompetitionService : IDynamicApiController, ITransient
};
}
var projects = await _projectRepository.GetListAsync(x => x.EventId == id && x.Status == AvailabilityStatus.Enable);
output.Projects = projects.Select(p => new UserEventProjectListOutput
var eventProjects = await _eventProjectRepository.GetListAsync(x => x.EventId == id);
var projectIds = eventProjects.Select(x => x.ProjectId).Distinct().ToList();
var baseProjects = await _projectRepository.GetListAsync(x => projectIds.Contains(x.Id) && x.Status == AvailabilityStatus.Enable);
output.Projects = eventProjects.Select(ep =>
{
Id = p.Id,
Name = p.Name,
Fee = p.Fee,
CompletionCount = p.CompletionCount
}).ToList();
var p = baseProjects.FirstOrDefault(b => b.Id == ep.ProjectId);
return new UserEventProjectListOutput
{
Id = ep.Id,
Name = p?.Name ?? "",
Fee = ep.Price / 100m,
CompletionCount = p?.CompletionCount ?? 0
};
}).Where(x => !string.IsNullOrEmpty(x.Name)).ToList();
var userId = _authManager.UserId;
var registration = await _registrationRepository.GetFirstAsync(x => x.EventId == id && x.CreatedUserId == userId && !x.DeleteMark);
@ -178,16 +194,22 @@ public class UserCompetitionService : IDynamicApiController, ITransient
[HttpGet("projects/{eventId}")]
public async Task<List<UserEventProjectListOutput>> GetProjects([FromRoute] long eventId)
{
var projects = await _projectRepository.GetListAsync(x => x.EventId == eventId && x.Status == AvailabilityStatus.Enable);
return projects.Select(p => new UserEventProjectListOutput
var eventProjects = await _eventProjectRepository.GetListAsync(x => x.EventId == eventId);
var projectIds = eventProjects.Select(x => x.ProjectId).Distinct().ToList();
var baseProjects = await _projectRepository.GetListAsync(x => projectIds.Contains(x.Id) && x.Status == AvailabilityStatus.Enable);
return eventProjects.Select(ep =>
{
Id = p.Id,
Name = p.Name,
Fee = p.Fee,
TeamSize = 1, // 默认为1
CompletionCount = p.CompletionCount
}).ToList();
var p = baseProjects.FirstOrDefault(b => b.Id == ep.ProjectId);
return new UserEventProjectListOutput
{
Id = ep.Id,
Name = p?.Name ?? "",
Fee = ep.Price / 100m,
TeamSize = 1, // 默认为1
CompletionCount = p?.CompletionCount ?? 0
};
}).Where(x => !string.IsNullOrEmpty(x.Name)).ToList();
}
/// <summary>
@ -269,23 +291,26 @@ public class UserCompetitionService : IDynamicApiController, ITransient
await _registrationItemRepository.DeleteAsync(x => x.RegistrationId == registration.Id);
await _registrationPersonRepository.DeleteAsync(x => x.RegistrationId == registration.Id);
var projects = await _projectRepository.GetListAsync(x => input.ProjectIds.Contains(x.Id));
var eventProjects = await _eventProjectRepository.GetListAsync(x => input.ProjectIds.Contains(x.Id));
var baseProjectIds = eventProjects.Select(x => x.ProjectId).ToList();
var baseProjects = await _projectRepository.GetListAsync(x => baseProjectIds.Contains(x.Id));
var members = await _userRepository.GetListAsync(x => input.MemberIds.Contains(x.Id));
decimal totalAmount = 0;
int totalPersonCount = 0;
foreach (var project in projects)
foreach (var eventProject in eventProjects)
{
var baseProject = baseProjects.FirstOrDefault(x => x.Id == eventProject.ProjectId);
var item = new EventRegistrationItem
{
Id = _idGenerator.NewLong(),
RegistrationId = registration.Id,
ProjectId = project.Id,
ProjectName = project.Name,
UnitPrice = project.Fee,
ProjectId = eventProject.Id,
ProjectName = baseProject?.Name ?? "",
UnitPrice = eventProject.Price / 100m,
PersonCount = members.Count(),
TotalPrice = project.Fee * members.Count(),
TotalPrice = (eventProject.Price / 100m) * members.Count(),
CreatedUserId = userId,
CreatedTime = DateTime.Now
};
@ -301,7 +326,7 @@ public class UserCompetitionService : IDynamicApiController, ITransient
Id = _idGenerator.NewLong(),
RegistrationId = registration.Id,
RegistrationItemId = item.Id,
ProjectId = project.Id,
ProjectId = eventProject.Id,
Name = member.Name,
Gender = member.Gender,
IdCard = member.IdCardNumber,

View File

@ -10,11 +10,6 @@ namespace YD_Event.Application.Project.Dtos;
/// </summary>
public class ProjectQueryInput : Pagination
{
/// <summary>
/// 赛事ID
/// </summary>
public long? EventId { get; set; }
/// <summary>
/// 项目名称 (模糊查询)
/// </summary>
@ -28,12 +23,6 @@ public class ProjectQueryInput : Pagination
public class AddProjectInput
{
/// <summary>
/// 关联的赛事ID
/// </summary>
[Required(ErrorMessage = "赛事ID不能为空")]
public long EventId { get; set; }
/// <summary>
/// 项目名称
/// </summary>
@ -125,11 +114,6 @@ public class ProjectDto
/// </summary>
public long Id { get; set; }
/// <summary>
/// 关联的赛事ID
/// </summary>
public long EventId { get; set; }
/// <summary>
/// 项目名称
/// </summary>

View File

@ -35,7 +35,6 @@ public class ProjectService : BaseService<YD_Event.Core.Entities.Project>, ITran
{
var query = _repository.AsQueryable()
.LeftJoin<ProjectType>((p, pt) => p.ProjectTypeId == pt.Id)
.WhereIF(input.EventId.HasValue, (p, pt) => p.EventId == input.EventId)
.WhereIF(!string.IsNullOrWhiteSpace(input.ProjectName), (p, pt) => p.Name.Contains(input.ProjectName))
.WhereIF(input.ProjectTypeId.HasValue, (p, pt) => p.ProjectTypeId == input.ProjectTypeId)
.OrderByDescending((p, pt) => p.Id);
@ -43,7 +42,6 @@ public class ProjectService : BaseService<YD_Event.Core.Entities.Project>, ITran
var result = await query.Select((p, pt) => new ProjectDto
{
Id = p.Id,
EventId = p.EventId,
Name = p.Name,
ProjectTypeId = p.ProjectTypeId,
ProjectTypeName = pt.Name,
@ -72,9 +70,9 @@ public class ProjectService : BaseService<YD_Event.Core.Entities.Project>, ITran
[UnitOfWork]
public async Task Add(AddProjectInput input)
{
// 检查项目名称在同一赛事中是否重复
var isExist = await _repository.IsAnyAsync(x => x.EventId == input.EventId && x.Name == input.Name);
if (isExist) throw new InvalidOperationException("该项目名称在当前赛事中已存在");
// 检查项目名称是否重复
var isExist = await _repository.IsAnyAsync(x => x.Name == input.Name);
if (isExist) throw new InvalidOperationException("该项目名称已存在");
var entity = input.Adapt<YD_Event.Core.Entities.Project>();
entity.Id = _idGenerator.NewLong();
@ -109,8 +107,8 @@ public class ProjectService : BaseService<YD_Event.Core.Entities.Project>, ITran
// 如果修改了名称,检查是否重复
if (entity.Name != input.Name)
{
var isExist = await _repository.IsAnyAsync(x => x.EventId == input.EventId && x.Name == input.Name && x.Id != input.Id);
if (isExist) throw new InvalidOperationException("该项目名称在当前赛事中已存在");
var isExist = await _repository.IsAnyAsync(x => x.Name == input.Name && x.Id != input.Id);
if (isExist) throw new InvalidOperationException("该项目名称已存在");
}
input.Adapt(entity);

View File

@ -3540,17 +3540,22 @@
</member>
<member name="P:YD_Event.Application.Event.Dtos.EventProjectInput.Id">
<summary>
项目ID (更新时使用)
赛事项目ID (更新时使用)
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.EventProjectInput.ProjectId">
<summary>
项目ID
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.EventProjectInput.Name">
<summary>
项目名称
项目名称 (显示用)
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.EventProjectInput.ProjectTypeId">
<summary>
项目类型ID
项目类型ID (显示用)
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.EventProjectInput.ProjectTypeName">
@ -3558,19 +3563,19 @@
项目类型名称 (显示用)
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.EventProjectInput.CompletionCount">
<member name="P:YD_Event.Application.Event.Dtos.EventProjectInput.GenderType">
<summary>
完成人数
性别要求
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.EventProjectInput.DurationMinutes">
<summary>
比赛时长(分)
比赛时长(分) (显示用)
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.EventProjectInput.DurationSeconds">
<summary>
比赛时长(秒)
比赛时长(秒) (显示用)
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.EventProjectInput.Fee">
@ -3588,6 +3593,41 @@
组别列表
</summary>
</member>
<member name="T:YD_Event.Application.Event.Dtos.EventProjectGroupInput">
<summary>
赛事项目组别输入
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.EventProjectGroupInput.Id">
<summary>
赛事项目组别ID (更新时使用)
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.EventProjectGroupInput.ProjectGroupId">
<summary>
关联的项目组别ID
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.EventProjectGroupInput.GroupName">
<summary>
组别名称 (显示用)
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.EventProjectGroupInput.BirthDateStart">
<summary>
出生日期起始日期 (显示用)
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.EventProjectGroupInput.BirthDateEnd">
<summary>
出生日期结束日期 (显示用)
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.EventProjectGroupInput.Gender">
<summary>
性别要求 (显示用)
</summary>
</member>
<member name="T:YD_Event.Application.Event.Dtos.EventRegistrationLimitInput">
<summary>
报名限制输入
@ -3948,6 +3988,26 @@
费用配置
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.SaveFeeConfigInput.ProjectFees">
<summary>
项目单价列表(当收费模式为“单价(项目)”时填写)
</summary>
</member>
<member name="T:YD_Event.Application.Event.Dtos.ProjectFeeInput">
<summary>
项目费用输入
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.ProjectFeeInput.ProjectId">
<summary>
项目ID
</summary>
</member>
<member name="P:YD_Event.Application.Event.Dtos.ProjectFeeInput.Fee">
<summary>
项目单价
</summary>
</member>
<member name="T:YD_Event.Application.Event.Dtos.EventProgressOutput">
<summary>
赛事进度输出
@ -7184,11 +7244,6 @@
项目查询输入
</summary>
</member>
<member name="P:YD_Event.Application.Project.Dtos.ProjectQueryInput.EventId">
<summary>
赛事ID
</summary>
</member>
<member name="P:YD_Event.Application.Project.Dtos.ProjectQueryInput.ProjectName">
<summary>
项目名称 (模糊查询)
@ -7199,11 +7254,6 @@
项目类型ID
</summary>
</member>
<member name="P:YD_Event.Application.Project.Dtos.AddProjectInput.EventId">
<summary>
关联的赛事ID
</summary>
</member>
<member name="P:YD_Event.Application.Project.Dtos.AddProjectInput.Name">
<summary>
项目名称
@ -7284,11 +7334,6 @@
ID
</summary>
</member>
<member name="P:YD_Event.Application.Project.Dtos.ProjectDto.EventId">
<summary>
关联的赛事ID
</summary>
</member>
<member name="P:YD_Event.Application.Project.Dtos.ProjectDto.Name">
<summary>
项目名称

View File

@ -149,7 +149,7 @@
"ALiYunSMS": {
"Endpoint": "dysmsapi.aliyuncs.com",
"Sign": "oVpeH1PpDUnWTcBrUSSYkQNS4Fex8Y",
"Template": "SMS_147140268"
"Template": "SMS_254100608"
},
// 阿里云ORC识别
"AliyunOCR": {

View File

@ -0,0 +1,47 @@
using SqlSugar;
using YD_Event.Core.Enum;
namespace YD_Event.Core.Entities;
/// <summary>
/// 赛事项目关联表
/// </summary>
public class EventProject : Entity<long>, ICreatedTime, IUpdatedTime
{
/// <summary>
/// 赛事ID
/// </summary>
public long EventId { get; set; }
/// <summary>
/// 项目ID
/// </summary>
public long ProjectId { get; set; }
/// <summary>
/// 性别要求 (男/女/不限)
/// </summary>
public Gender GenderType { get; set; }
/// <summary>
/// 价格(单位:分)
/// </summary>
public int Price { get; set; }
/// <summary>
/// 赛事项目组别列表(导航属性)
/// </summary>
[SugarColumn(IsIgnore = true)]
public List<EventProjectGroup>? Groups { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreatedTime { get; set; }
/// <summary>
/// 更新时间
/// </summary>
[SugarColumn(IsNullable = true)]
public DateTime? UpdatedTime { get; set; }
}

View File

@ -0,0 +1,55 @@
using YD_Event.Core.Enum;
namespace YD_Event.Core.Entities;
/// <summary>
/// 赛事项目组别表
/// </summary>
[SugarTable("EventProjectGroup")]
public class EventProjectGroup : Entity<long>, ISoftDelete, ICreatedUserId, ICreatedTime, IUpdatedUserId, IUpdatedTime
{
/// <summary>
/// 赛事ID
/// </summary>
public long EventId { get; set; }
/// <summary>
/// 赛事项目ID
/// </summary>
public long EventProjectId { get; set; }
/// <summary>
/// 关联的项目ID
/// </summary>
public long ProjectId { get; set; }
/// <summary>
/// 关联的项目组别ID
/// </summary>
public long ProjectGroupId { get; set; }
/// <summary>
/// 标记删除
/// </summary>
public bool DeleteMark { get; set; }
/// <summary>
/// 创建人
/// </summary>
public long CreatedUserId { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreatedTime { get; set; }
/// <summary>
/// 更新人
/// </summary>
public long? UpdatedUserId { get; set; }
/// <summary>
/// 更新时间
/// </summary>
public DateTime? UpdatedTime { get; set; }
}

View File

@ -9,11 +9,6 @@ namespace YD_Event.Core.Entities;
[SugarTable("Project")]
public class Project : Entity<long>, ISoftDelete, ICreatedUserId, ICreatedTime, IUpdatedUserId, IUpdatedTime, IAvailability
{
/// <summary>
/// 关联的赛事ID
/// </summary>
public long EventId { get; set; }
/// <summary>
/// 项目名称
/// </summary>

View File

@ -209,17 +209,6 @@
高度
</summary>
</member>
<member name="T:YD_Event.Core.Domain.Certificate.CertificateDocument">
<summary>
证书文档
</summary>
</member>
<member name="M:YD_Event.Core.Domain.Certificate.CertificateDocument.GeneratePdf">
<summary>
生成PDF
</summary>
<returns>PDF字节数组</returns>
</member>
<member name="T:YD_Event.Core.Domain.Certificate.DocxTemplateParser">
<summary>
DOCX模板解析器
@ -805,81 +794,6 @@
更新时间
</summary>
</member>
<member name="T:YD_Event.Core.Entities.CertificateElement">
<summary>
证书元素表 (CertificateElement)
</summary>
</member>
<member name="P:YD_Event.Core.Entities.CertificateElement.TemplateId">
<summary>
模板ID (关联 CertificateTemplate)
</summary>
</member>
<member name="P:YD_Event.Core.Entities.CertificateElement.Type">
<summary>
元素类型: Text, Image, QRCode
</summary>
</member>
<member name="P:YD_Event.Core.Entities.CertificateElement.FieldName">
<summary>
字段名/标签 (维护用)
</summary>
</member>
<member name="P:YD_Event.Core.Entities.CertificateElement.BindingKey">
<summary>
绑定键 (业务数据字段)
</summary>
</member>
<member name="P:YD_Event.Core.Entities.CertificateElement.X">
<summary>
X坐标 (px)
</summary>
</member>
<member name="P:YD_Event.Core.Entities.CertificateElement.Y">
<summary>
Y坐标 (px)
</summary>
</member>
<member name="P:YD_Event.Core.Entities.CertificateElement.Width">
<summary>
宽度 (px)
</summary>
</member>
<member name="P:YD_Event.Core.Entities.CertificateElement.Height">
<summary>
高度 (px)
</summary>
</member>
<member name="P:YD_Event.Core.Entities.CertificateElement.FontFamily">
<summary>
字体
</summary>
</member>
<member name="P:YD_Event.Core.Entities.CertificateElement.FontSize">
<summary>
字号
</summary>
</member>
<member name="P:YD_Event.Core.Entities.CertificateElement.Color">
<summary>
颜色代码 #RRGGBB
</summary>
</member>
<member name="P:YD_Event.Core.Entities.CertificateElement.StyleJson">
<summary>
额外样式 JSON
</summary>
</member>
<member name="P:YD_Event.Core.Entities.CertificateElement.Sort">
<summary>
排序
</summary>
</member>
<member name="P:YD_Event.Core.Entities.CertificateElement.DeleteMark">
<summary>
软删除
</summary>
</member>
<member name="T:YD_Event.Core.Entities.CertificatePlaceholder">
<summary>
证书占位符表 (CertificatePlaceholder)
@ -1540,6 +1454,96 @@
更新时间
</summary>
</member>
<member name="T:YD_Event.Core.Entities.EventProject">
<summary>
赛事项目关联表
</summary>
</member>
<member name="P:YD_Event.Core.Entities.EventProject.EventId">
<summary>
赛事ID
</summary>
</member>
<member name="P:YD_Event.Core.Entities.EventProject.ProjectId">
<summary>
项目ID
</summary>
</member>
<member name="P:YD_Event.Core.Entities.EventProject.GenderType">
<summary>
性别要求 (男/女/不限)
</summary>
</member>
<member name="P:YD_Event.Core.Entities.EventProject.Price">
<summary>
价格(单位:分)
</summary>
</member>
<member name="P:YD_Event.Core.Entities.EventProject.Groups">
<summary>
赛事项目组别列表(导航属性)
</summary>
</member>
<member name="P:YD_Event.Core.Entities.EventProject.CreatedTime">
<summary>
创建时间
</summary>
</member>
<member name="P:YD_Event.Core.Entities.EventProject.UpdatedTime">
<summary>
更新时间
</summary>
</member>
<member name="T:YD_Event.Core.Entities.EventProjectGroup">
<summary>
赛事项目组别表
</summary>
</member>
<member name="P:YD_Event.Core.Entities.EventProjectGroup.EventId">
<summary>
赛事ID
</summary>
</member>
<member name="P:YD_Event.Core.Entities.EventProjectGroup.EventProjectId">
<summary>
赛事项目ID
</summary>
</member>
<member name="P:YD_Event.Core.Entities.EventProjectGroup.ProjectId">
<summary>
关联的项目ID
</summary>
</member>
<member name="P:YD_Event.Core.Entities.EventProjectGroup.ProjectGroupId">
<summary>
关联的项目组别ID
</summary>
</member>
<member name="P:YD_Event.Core.Entities.EventProjectGroup.DeleteMark">
<summary>
标记删除
</summary>
</member>
<member name="P:YD_Event.Core.Entities.EventProjectGroup.CreatedUserId">
<summary>
创建人
</summary>
</member>
<member name="P:YD_Event.Core.Entities.EventProjectGroup.CreatedTime">
<summary>
创建时间
</summary>
</member>
<member name="P:YD_Event.Core.Entities.EventProjectGroup.UpdatedUserId">
<summary>
更新人
</summary>
</member>
<member name="P:YD_Event.Core.Entities.EventProjectGroup.UpdatedTime">
<summary>
更新时间
</summary>
</member>
<member name="T:YD_Event.Core.Entities.EventProjectRegistrationLimit">
<summary>
赛事项目报名限制表
@ -2751,11 +2755,6 @@
项目表
</summary>
</member>
<member name="P:YD_Event.Core.Entities.Project.EventId">
<summary>
关联的赛事ID
</summary>
</member>
<member name="P:YD_Event.Core.Entities.Project.Name">
<summary>
项目名称