using Microsoft.Extensions.Logging; using Volo.Abp.Domain.Services; using Yi.Framework.AiHub.Domain.Entities; using Yi.Framework.SqlSugarCore.Abstractions; namespace Yi.Framework.AiHub.Domain.Managers; /// /// 翻牌管理器 - 负责翻牌核心业务逻辑 /// public class CardFlipManager : DomainService { private readonly ISqlSugarRepository _cardFlipTaskRepository; private readonly ISqlSugarRepository _invitationRecordRepository; private readonly InviteCodeManager _inviteCodeManager; private readonly ILogger _logger; // 翻牌规则配置 public const int MAX_FREE_FLIPS = 7; // 免费翻牌次数 public const int MAX_INVITE_FLIPS = 3; // 邀请解锁翻牌次数 public const int TOTAL_MAX_FLIPS = 10; // 总最大翻牌次数 private const int EIGHTH_FLIP = 8; // 第8次翻牌 private const int NINTH_FLIP = 9; // 第9次翻牌 private const int TENTH_FLIP = 10; // 第10次翻牌 private const long EIGHTH_MIN_REWARD = 1000000; // 第8次最小奖励 100w private const long EIGHTH_MAX_REWARD = 3000000; // 第8次最大奖励 300w private const long NINTH_MIN_REWARD = 1000000; // 第9次最小奖励 100w private const long NINTH_MAX_REWARD = 5000000; // 第9次最大奖励 500w private const long TENTH_MIN_REWARD = 1000000; // 第10次最小奖励 100w private const long TENTH_MAX_REWARD = 10000000; // 第10次最大奖励 1000w public CardFlipManager( ISqlSugarRepository cardFlipTaskRepository, ISqlSugarRepository invitationRecordRepository, InviteCodeManager inviteCodeManager, ILogger logger) { _cardFlipTaskRepository = cardFlipTaskRepository; _invitationRecordRepository = invitationRecordRepository; _inviteCodeManager = inviteCodeManager; _logger = logger; } /// /// 获取或创建本周任务 /// public async Task GetOrCreateWeeklyTaskAsync( Guid userId, DateTime weekStart, bool createIfNotExists) { var task = await _cardFlipTaskRepository._DbQueryable .Where(x => x.UserId == userId && x.WeekStartDate == weekStart) .FirstAsync(); if (task == null && createIfNotExists) { task = new CardFlipTaskAggregateRoot(userId, weekStart); await _cardFlipTaskRepository.InsertAsync(task); } return task; } /// /// 获取已翻牌的顺序列表 /// public List GetFlippedOrder(CardFlipTaskAggregateRoot task) { return task.FlippedOrder ?? new List(); } /// /// 执行翻牌逻辑 /// /// 用户ID /// 翻牌序号 /// 本周开始日期 /// 翻牌结果 public async Task ExecuteFlipAsync(Guid userId, int flipNumber, DateTime weekStart) { // 验证翻牌序号 if (flipNumber < 1 || flipNumber > TOTAL_MAX_FLIPS) { throw new UserFriendlyException($"翻牌序号必须在1-{TOTAL_MAX_FLIPS}之间"); } // 获取或创建本周任务 var task = await GetOrCreateWeeklyTaskAsync(userId, weekStart, createIfNotExists: true); // 验证翻牌次数 if (task.TotalFlips >= TOTAL_MAX_FLIPS) { throw new UserFriendlyException("本周翻牌次数已用完,请下周再来!"); } // 验证该牌是否已经翻过 var flippedOrder = GetFlippedOrder(task); if (flippedOrder.Contains(flipNumber)) { throw new UserFriendlyException($"第 {flipNumber} 号牌已经翻过了!"); } // 判断翻牌类型 var flipType = DetermineFlipType(task); // 验证是否有足够的次数 if (!CanUseFlipType(task, flipType)) { throw new UserFriendlyException(GetFlipTypeErrorMessage(flipType)); } // 如果是邀请类型翻牌,必须验证用户本周填写的邀请码数量足够 if (flipType == FlipType.Invite) { // 查询本周已使用的邀请码数量 var weeklyInviteCodeUsedCount = await _invitationRecordRepository._DbQueryable .Where(x => x.InvitedUserId == userId) .Where(x => x.InvitationTime >= weekStart) .CountAsync(); // 本周填写的邀请码数量必须 >= 即将使用的邀请翻牌次数 // 例如: 要翻第8次(InviteFlipsUsed=0->1), 需要至少填写了1个邀请码 // 要翻第9次(InviteFlipsUsed=1->2), 需要至少填写了2个邀请码 // 要翻第10次(InviteFlipsUsed=2->3), 需要至少填写了3个邀请码 var requiredInviteCodeCount = task.InviteFlipsUsed + 1; if (weeklyInviteCodeUsedCount < requiredInviteCodeCount) { throw new UserFriendlyException($"需要先使用{requiredInviteCodeCount}个他人邀请码才能解锁第{task.TotalFlips + 1}次翻牌"); } } // 计算翻牌结果(基于当前是第几次翻牌,而不是卡片序号) var flipCount = task.TotalFlips + 1; // 当前这次翻牌是第几次 var result = CalculateFlipResult(flipCount); // 将卡片序号信息也返回 result.FlipNumber = flipNumber; // 更新翻牌次数(必须在记录奖励之前,因为需要先确定是第几次) task.IncrementFlip(flipType); // 记录翻牌顺序 if (task.FlippedOrder == null) { task.FlippedOrder = new List(); } task.FlippedOrder.Add(flipNumber); // 如果中奖,记录奖励金额(用于后续查询显示) if (result.IsWin) { if (flipCount == EIGHTH_FLIP) { task.SetEighthReward(result.RewardAmount); } else if (flipCount == NINTH_FLIP) { task.SetNinthReward(result.RewardAmount); } else if (flipCount == TENTH_FLIP) { task.SetTenthReward(result.RewardAmount); } } await _cardFlipTaskRepository.UpdateAsync(task); _logger.LogInformation($"用户 {userId} 完成第 {flipNumber} 次翻牌,中奖:{result.IsWin}"); return result; } /// /// 判断是否可以翻牌 /// public bool CanFlipCard(CardFlipTaskAggregateRoot? task) { if (task == null) return true; // 没有任务记录,可以开始翻牌 return task.TotalFlips < TOTAL_MAX_FLIPS; } /// /// 判断翻牌类型 /// public FlipType DetermineFlipType(CardFlipTaskAggregateRoot task) { if (task.FreeFlipsUsed < MAX_FREE_FLIPS) { return FlipType.Free; } else { return FlipType.Invite; } } /// /// 判断是否可以使用该翻牌类型 /// public bool CanUseFlipType(CardFlipTaskAggregateRoot task, FlipType flipType) { return flipType switch { FlipType.Free => task.FreeFlipsUsed < MAX_FREE_FLIPS, FlipType.Invite => task.InviteFlipsUsed < MAX_INVITE_FLIPS, _ => false }; } /// /// 计算翻牌结果 /// /// 第几次翻牌(1-10) private FlipResult CalculateFlipResult(int flipCount) { var result = new FlipResult { FlipNumber = 0, // 稍后会被设置为实际的卡片序号 IsWin = false }; // 前7次固定失败 if (flipCount <= 7) { result.IsWin = false; result.RewardDesc = "很遗憾,未中奖"; } // 第8次中奖 (邀请码解锁) else if (flipCount == EIGHTH_FLIP) { var rewardAmount = GenerateRandomReward(EIGHTH_MIN_REWARD, EIGHTH_MAX_REWARD); result.IsWin = true; result.RewardAmount = rewardAmount; result.RewardDesc = $"恭喜获得尊享包 {rewardAmount / 10000}w tokens!"; } // 第9次中奖 (邀请码解锁) else if (flipCount == NINTH_FLIP) { var rewardAmount = GenerateRandomReward(NINTH_MIN_REWARD, NINTH_MAX_REWARD); result.IsWin = true; result.RewardAmount = rewardAmount; result.RewardDesc = $"恭喜获得尊享包 {rewardAmount / 10000}w tokens!"; } // 第10次中奖 (邀请码解锁) else if (flipCount == TENTH_FLIP) { var rewardAmount = GenerateRandomReward(TENTH_MIN_REWARD, TENTH_MAX_REWARD); result.IsWin = true; result.RewardAmount = rewardAmount; result.RewardDesc = $"恭喜获得尊享包 {rewardAmount / 10000}w tokens!"; } return result; } /// /// 获取翻牌类型错误提示 /// private string GetFlipTypeErrorMessage(FlipType flipType) { return flipType switch { FlipType.Free => "免费翻牌次数已用完", FlipType.Invite => "需要使用邀请码解锁更多次数", _ => "无法翻牌" }; } /// /// 生成随机奖励金额 (最小单位100w) /// private long GenerateRandomReward(long min, long max) { var random = new Random(); const long unit = 1000000; // 100w的单位 // 将min和max转换为100w的倍数 long minUnits = min / unit; long maxUnits = max / unit; // 在倍数范围内随机 long randomUnits = random.Next((int)minUnits, (int)maxUnits + 1); // 返回100w的倍数 return randomUnits * unit; } /// /// 获取本周开始日期(周一) /// public static DateTime GetWeekStartDate(DateTime date) { var dayOfWeek = (int)date.DayOfWeek; // 将周日(0)转换为7 if (dayOfWeek == 0) dayOfWeek = 7; // 计算本周一的日期 var monday = date.Date.AddDays(-(dayOfWeek - 1)); return monday; } /// /// 获取翻牌类型描述 /// public static string GetFlipTypeDesc(int flipNumber) { if (flipNumber <= MAX_FREE_FLIPS) { return "免费"; } else { return "邀请解锁"; } } } /// /// 翻牌结果 /// public class FlipResult { /// /// 翻牌序号 /// public int FlipNumber { get; set; } /// /// 是否中奖 /// public bool IsWin { get; set; } /// /// 奖励金额 /// public long RewardAmount { get; set; } /// /// 奖励描述 /// public string RewardDesc { get; set; } = string.Empty; }