using System; using System.Collections.Generic; using System.Linq; using System.Text.Json; using System.Text.Encodings.Web; using System.Threading.Tasks; using YD_Event.Application.Event.Dtos; using YD_Event.Core.Entities; using SqlSugar; namespace YD_Event.Application.Event; /// /// 赛事规则快照服务 - 管理积分规则和退款规则的快照 /// public class EventRuleSnapshotService : ITransient { private readonly ISqlSugarRepository _eventInfoRepository; private readonly ISqlSugarRepository _pointsRuleRepository; private readonly ISqlSugarRepository _pointsRuleDetailRepository; private readonly ISqlSugarRepository _refundConfigRepository; // JSON 序列化选项,支持中文正常显示 private static readonly System.Text.Json.JsonSerializerOptions _jsonOptions = new System.Text.Json.JsonSerializerOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, WriteIndented = false }; public EventRuleSnapshotService( ISqlSugarRepository eventInfoRepository, ISqlSugarRepository pointsRuleRepository, ISqlSugarRepository pointsRuleDetailRepository, ISqlSugarRepository refundConfigRepository) { _eventInfoRepository = eventInfoRepository; _pointsRuleRepository = pointsRuleRepository; _pointsRuleDetailRepository = pointsRuleDetailRepository; _refundConfigRepository = refundConfigRepository; } #region 积分规则快照 /// /// 保存积分规则快照到赛事 /// /// 赛事 ID /// 积分规则 ID /// [DisplayName("保存积分规则快照")] public async Task SavePointsRuleSnapshot(long eventId, long? pointsRuleId) { var eventInfo = await _eventInfoRepository.GetByIdAsync(eventId); if (eventInfo == null) throw new InvalidOperationException("赛事不存在"); if (!pointsRuleId.HasValue || pointsRuleId.Value <= 0) { eventInfo.PointsRuleSnapshot = null; await _eventInfoRepository.UpdateAsync(eventInfo); return; } var pointsRule = await _pointsRuleRepository.GetByIdAsync(pointsRuleId.Value); if (pointsRule == null) throw new InvalidOperationException("积分规则不存在"); var details = await _pointsRuleDetailRepository.GetListAsync(x => x.PointsRuleId == pointsRuleId.Value && !x.DeleteMark); var snapshot = new PointsRuleSnapshotDto { PointsRuleId = pointsRule.Id, RuleName = pointsRule.RuleName, ParticipationPoints = pointsRule.ParticipationPoints, Remark = pointsRule.Remark, Details = details.Select(d => new PointsRuleDetailSnapshotDto { StartRank = d.StartRank, EndRank = d.EndRank, Points = d.Points }).ToList() }; eventInfo.PointsRuleSnapshot = System.Text.Json.JsonSerializer.Serialize(snapshot, _jsonOptions); await _eventInfoRepository.UpdateAsync(eventInfo); } /// /// 获取赛事积分规则快照 /// /// 赛事 ID /// 积分规则快照,如果不存在则返回 null [DisplayName("获取积分规则快照")] public async Task GetPointsRuleSnapshot(long eventId) { var eventInfo = await _eventInfoRepository.GetByIdAsync(eventId); if (eventInfo == null) throw new InvalidOperationException("赛事不存在"); if (string.IsNullOrWhiteSpace(eventInfo.PointsRuleSnapshot)) return null; try { return System.Text.Json.JsonSerializer.Deserialize(eventInfo.PointsRuleSnapshot, _jsonOptions); } catch (Exception) { return null; } } #endregion #region 退款规则快照 /// /// 保存退款规则快照到赛事 /// /// 赛事 ID /// [DisplayName("保存退款规则快照")] public async Task SaveRefundRuleSnapshot(long eventId) { var eventInfo = await _eventInfoRepository.GetByIdAsync(eventId); if (eventInfo == null) throw new InvalidOperationException("赛事不存在"); var refundConfigs = await _refundConfigRepository.GetListAsync(x => x.Status == Core.Enum.AvailabilityStatus.Enable && !x.DeleteMark); if (!refundConfigs.Any()) { eventInfo.RefundRuleSnapshot = null; await _eventInfoRepository.UpdateAsync(eventInfo); return; } var snapshots = refundConfigs.OrderBy(c => c.DayStart).Select(c => new RefundRuleSnapshotDto { RefundConfigId = c.Id, DayStart = c.DayStart, DayEnd = c.DayEnd, DeductPercentage = c.DeductPercentage, Remark = c.Remark }).ToList(); eventInfo.RefundRuleSnapshot = System.Text.Json.JsonSerializer.Serialize(snapshots, _jsonOptions); await _eventInfoRepository.UpdateAsync(eventInfo); } /// /// 获取赛事退款规则快照 /// /// 赛事 ID /// 退款规则快照列表,如果不存在则返回空列表 [DisplayName("获取退款规则快照")] public async Task> GetRefundRuleSnapshot(long eventId) { var eventInfo = await _eventInfoRepository.GetByIdAsync(eventId); if (eventInfo == null) throw new InvalidOperationException("赛事不存在"); if (string.IsNullOrWhiteSpace(eventInfo.RefundRuleSnapshot)) return new List(); try { var snapshots = System.Text.Json.JsonSerializer.Deserialize>(eventInfo.RefundRuleSnapshot, _jsonOptions); return snapshots ?? new List(); } catch (Exception) { return new List(); } } #endregion #region 快捷方法 /// /// 同时保存积分规则和退款规则快照 /// /// 赛事 ID /// 积分规则 ID /// [DisplayName("保存所有规则快照")] public async Task SaveAllRuleSnapshots(long eventId, long? pointsRuleId) { await SavePointsRuleSnapshot(eventId, pointsRuleId); await SaveRefundRuleSnapshot(eventId); } /// /// 根据赛事实体保存快照(用于创建/编辑时) /// /// 赛事实体 /// [DisplayName("根据赛事实体保存快照")] public async Task SaveAllRuleSnapshots(EventInfo eventInfo) { if (eventInfo.PointsRuleId.HasValue && eventInfo.PointsRuleId.Value > 0) { var pointsRule = await _pointsRuleRepository.GetByIdAsync(eventInfo.PointsRuleId.Value); if (pointsRule != null) { var details = await _pointsRuleDetailRepository.GetListAsync(x => x.PointsRuleId == eventInfo.PointsRuleId.Value && !x.DeleteMark); var snapshot = new PointsRuleSnapshotDto { PointsRuleId = pointsRule.Id, RuleName = pointsRule.RuleName, ParticipationPoints = pointsRule.ParticipationPoints, Remark = pointsRule.Remark, Details = details.Select(d => new PointsRuleDetailSnapshotDto { StartRank = d.StartRank, EndRank = d.EndRank, Points = d.Points }).ToList() }; eventInfo.PointsRuleSnapshot = System.Text.Json.JsonSerializer.Serialize(snapshot, _jsonOptions); } } else { eventInfo.PointsRuleSnapshot = null; } var refundConfigs = await _refundConfigRepository.GetListAsync(x => x.Status == Core.Enum.AvailabilityStatus.Enable && !x.DeleteMark); if (refundConfigs.Any()) { var snapshots = refundConfigs.OrderBy(c => c.DayStart).Select(c => new RefundRuleSnapshotDto { RefundConfigId = c.Id, DayStart = c.DayStart, DayEnd = c.DayEnd, DeductPercentage = c.DeductPercentage, Remark = c.Remark }).ToList(); eventInfo.RefundRuleSnapshot = System.Text.Json.JsonSerializer.Serialize(snapshots, _jsonOptions); } else { eventInfo.RefundRuleSnapshot = null; } } #endregion }