From 3fd4799459a652c91921f23173e6af02f08641f5 Mon Sep 17 00:00:00 2001 From: zpc Date: Sun, 25 Jan 2026 16:04:50 +0800 Subject: [PATCH] 321321 --- .../Interfaces/IRewardService.cs | 73 +++++ .../HoneyBox.Core/Services/LotteryEngine.cs | 50 +++- .../HoneyBox.Core/Services/RewardService.cs | 270 ++++++++++++++++++ .../Modules/ServiceModule.cs | 11 +- .../Models/Lottery/LotteryModels.cs | 5 + 5 files changed, 406 insertions(+), 3 deletions(-) create mode 100644 server/HoneyBox/src/HoneyBox.Core/Interfaces/IRewardService.cs create mode 100644 server/HoneyBox/src/HoneyBox.Core/Services/RewardService.cs diff --git a/server/HoneyBox/src/HoneyBox.Core/Interfaces/IRewardService.cs b/server/HoneyBox/src/HoneyBox.Core/Interfaces/IRewardService.cs new file mode 100644 index 00000000..a964dd2d --- /dev/null +++ b/server/HoneyBox/src/HoneyBox.Core/Interfaces/IRewardService.cs @@ -0,0 +1,73 @@ +namespace HoneyBox.Core.Interfaces; + +/// +/// 奖励发放服务接口 +/// +public interface IRewardService +{ + /// + /// 发放奖励 + /// + /// 用户ID + /// 奖励ID(业务标识) + /// 奖励来源描述 + /// 发放结果 + Task SendRewardAsync(int userId, string rewardId, string source = "系统奖励"); + + /// + /// 发放奖励(带倍数) + /// + /// 用户ID + /// 奖励ID(业务标识) + /// 倍数 + /// 奖励来源描述 + /// 发放结果 + Task SendRewardMultipleAsync(int userId, string rewardId, int multiple, string source = "系统奖励"); +} + +/// +/// 奖励发放结果 +/// +public class RewardSendResult +{ + /// + /// 是否成功 + /// + public bool Success { get; set; } + + /// + /// 消息 + /// + public string Message { get; set; } = string.Empty; + + /// + /// 发放详情列表 + /// + public List Details { get; set; } = new(); +} + +/// +/// 单个奖励发放详情 +/// +public class RewardSendDetail +{ + /// + /// 奖励记录ID + /// + public int RewardId { get; set; } + + /// + /// 奖励类型 + /// + public int RewardType { get; set; } + + /// + /// 是否成功 + /// + public bool Success { get; set; } + + /// + /// 消息 + /// + public string Message { get; set; } = string.Empty; +} diff --git a/server/HoneyBox/src/HoneyBox.Core/Services/LotteryEngine.cs b/server/HoneyBox/src/HoneyBox.Core/Services/LotteryEngine.cs index 7b7dac53..280d2254 100644 --- a/server/HoneyBox/src/HoneyBox.Core/Services/LotteryEngine.cs +++ b/server/HoneyBox/src/HoneyBox.Core/Services/LotteryEngine.cs @@ -16,6 +16,7 @@ public class LotteryEngine : ILotteryEngine { private readonly HoneyBoxDbContext _dbContext; private readonly IInventoryManager _inventoryManager; + private readonly IRewardService _rewardService; private readonly ILogger _logger; /// @@ -36,10 +37,12 @@ public class LotteryEngine : ILotteryEngine public LotteryEngine( HoneyBoxDbContext dbContext, IInventoryManager inventoryManager, + IRewardService rewardService, ILogger logger) { _dbContext = dbContext; _inventoryManager = inventoryManager; + _rewardService = rewardService; _logger = logger; } @@ -397,6 +400,9 @@ public class LotteryEngine : ILotteryEngine // 8. 处理翻倍赏逻辑(doubling > 1 时赠送积分) await ProcessDoublingRewardAsync(request.UserId, selectedPrize.Doubling, selectedPrize.Price, selectedPrize.Title); + + // 9. 处理奖品绑定奖励发放 + await ProcessPrizeRewardAsync(request.UserId, selectedPrize.RewardId, selectedPrize.Title); } catch (Exception ex) { @@ -608,6 +614,44 @@ public class LotteryEngine : ILotteryEngine } } + /// + /// 处理奖品绑定奖励发放 + /// + /// 用户ID + /// 奖励ID + /// 奖品标题 + private async Task ProcessPrizeRewardAsync(int userId, string? rewardId, string prizeTitle) + { + try + { + // 如果没有绑定奖励,直接返回 + if (string.IsNullOrWhiteSpace(rewardId)) + { + return; + } + + // 调用奖励服务发放奖励 + var result = await _rewardService.SendRewardAsync(userId, rewardId, $"抽中奖品-{prizeTitle}"); + + if (result.Success) + { + _logger.LogInformation("Prize reward sent: UserId={UserId}, RewardId={RewardId}, Prize={Prize}", + userId, rewardId, prizeTitle); + } + else + { + _logger.LogWarning("Prize reward failed: UserId={UserId}, RewardId={RewardId}, Message={Message}", + userId, rewardId, result.Message); + } + } + catch (Exception ex) + { + _logger.LogError(ex, "Failed to process prize reward: UserId={UserId}, RewardId={RewardId}", + userId, rewardId); + // 奖励发放失败不影响抽奖结果 + } + } + /// /// /// 多次无限赏抽奖流程: @@ -840,7 +884,8 @@ public class LotteryEngine : ILotteryEngine Doubling = p.Doubling, IsLingzhu = p.IsLingzhu, ParentGoodsListId = p.GoodsListId, - SaleTime = p.SaleTime + SaleTime = p.SaleTime, + RewardId = p.RewardId }).ToList(); } @@ -879,7 +924,8 @@ public class LotteryEngine : ILotteryEngine Doubling = p.Doubling, IsLingzhu = p.IsLingzhu, ParentGoodsListId = p.GoodsListId, - SaleTime = p.SaleTime + SaleTime = p.SaleTime, + RewardId = p.RewardId }).ToList(); } diff --git a/server/HoneyBox/src/HoneyBox.Core/Services/RewardService.cs b/server/HoneyBox/src/HoneyBox.Core/Services/RewardService.cs new file mode 100644 index 00000000..360e2ccb --- /dev/null +++ b/server/HoneyBox/src/HoneyBox.Core/Services/RewardService.cs @@ -0,0 +1,270 @@ +using HoneyBox.Core.Interfaces; +using HoneyBox.Model.Data; +using HoneyBox.Model.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; + +namespace HoneyBox.Core.Services; + +/// +/// 奖励发放服务实现 +/// 支持发放钻石、UU币、达达券、优惠券等奖励 +/// +public class RewardService : IRewardService +{ + private readonly HoneyBoxDbContext _dbContext; + private readonly ILogger _logger; + + public RewardService(HoneyBoxDbContext dbContext, ILogger logger) + { + _dbContext = dbContext; + _logger = logger; + } + + /// + public async Task SendRewardAsync(int userId, string rewardId, string source = "系统奖励") + { + return await SendRewardInternalAsync(userId, rewardId, 1, source); + } + + /// + public async Task SendRewardMultipleAsync(int userId, string rewardId, int multiple, string source = "系统奖励") + { + return await SendRewardInternalAsync(userId, rewardId, multiple, source); + } + + /// + /// 内部发放奖励方法 + /// + private async Task SendRewardInternalAsync(int userId, string rewardId, int multiple, string source) + { + var result = new RewardSendResult { Success = false }; + + if (userId <= 0) + { + result.Message = "用户ID不能为空"; + return result; + } + + if (string.IsNullOrWhiteSpace(rewardId)) + { + result.Message = "奖励ID不能为空"; + return result; + } + + try + { + // 获取奖励配置 + var rewards = await _dbContext.Rewards + .Where(r => r.RewardId == rewardId) + .ToListAsync(); + + if (!rewards.Any()) + { + result.Message = "未找到有效奖励"; + _logger.LogWarning("Reward not found: RewardId={RewardId}", rewardId); + return result; + } + + // 获取用户 + var user = await _dbContext.Users.FindAsync(userId); + if (user == null) + { + result.Message = "用户不存在"; + return result; + } + + // 逐个发放奖励 + foreach (var reward in rewards) + { + var detail = await SendSingleRewardAsync(userId, user, reward, multiple, source); + result.Details.Add(detail); + } + + await _dbContext.SaveChangesAsync(); + + result.Success = result.Details.All(d => d.Success); + result.Message = result.Success ? "奖励发放成功" : "部分奖励发放失败"; + + _logger.LogInformation("Reward sent: UserId={UserId}, RewardId={RewardId}, Multiple={Multiple}, Success={Success}", + userId, rewardId, multiple, result.Success); + } + catch (Exception ex) + { + _logger.LogError(ex, "Failed to send reward: UserId={UserId}, RewardId={RewardId}", userId, rewardId); + result.Message = "奖励发放失败"; + } + + return result; + } + + + /// + /// 发放单个奖励 + /// + private async Task SendSingleRewardAsync(int userId, User user, Reward reward, int multiple, string source) + { + var detail = new RewardSendDetail + { + RewardId = reward.Id, + RewardType = reward.RewardType, + Success = false + }; + + var rewardValue = reward.RewardValue * multiple; + + try + { + switch (reward.RewardType) + { + case 1: // 钻石 (Money) + await AddMoneyAsync(userId, user, rewardValue, source); + detail.Success = true; + detail.Message = $"获得钻石*{rewardValue}"; + break; + + case 2: // UU币 (Integral) + await AddIntegralAsync(userId, user, rewardValue, source); + detail.Success = true; + detail.Message = $"获得UU币*{rewardValue}"; + break; + + case 3: // 达达券 (Money2) + await AddMoney2Async(userId, user, rewardValue, source); + detail.Success = true; + detail.Message = $"获得达达券*{rewardValue}"; + break; + + case 4: // 优惠券 + var couponResult = await AddCouponAsync(userId, reward.RewardExtend, (int)rewardValue); + detail.Success = couponResult.success; + detail.Message = couponResult.message; + break; + + default: + detail.Message = "不支持的奖励类型"; + break; + } + } + catch (Exception ex) + { + _logger.LogError(ex, "Failed to send single reward: UserId={UserId}, RewardType={RewardType}", + userId, reward.RewardType); + detail.Message = "奖励发放失败"; + } + + return detail; + } + + /// + /// 增加钻石 + /// + private async Task AddMoneyAsync(int userId, User user, decimal amount, string source) + { + user.Money += amount; + + var profit = new ProfitMoney + { + UserId = userId, + Type = 6, // 奖励赠送 + ChangeMoney = amount, + Money = user.Money, + Content = source, + ShareUid = 0, + CreatedAt = DateTime.Now + }; + _dbContext.ProfitMoneys.Add(profit); + + _logger.LogInformation("Money added: UserId={UserId}, Amount={Amount}, Source={Source}", + userId, amount, source); + } + + /// + /// 增加UU币(积分) + /// + private async Task AddIntegralAsync(int userId, User user, decimal amount, string source) + { + user.Integral += amount; + + var profit = new ProfitIntegral + { + UserId = userId, + Type = 6, // 奖励赠送 + ChangeMoney = amount, + Money = user.Integral, + Content = source, + ShareUid = 0, + CreatedAt = DateTime.Now + }; + _dbContext.ProfitIntegrals.Add(profit); + + _logger.LogInformation("Integral added: UserId={UserId}, Amount={Amount}, Source={Source}", + userId, amount, source); + } + + /// + /// 增加达达券 + /// + private async Task AddMoney2Async(int userId, User user, decimal amount, string source) + { + user.Money2 = (user.Money2 ?? 0) + amount; + + var profit = new ProfitMoney2 + { + UserId = userId, + Type = 6, // 奖励赠送 + ChangeMoney = amount, + Money = user.Money2 ?? 0, + Content = source, + ShareUid = 0, + CreatedAt = DateTime.Now + }; + _dbContext.ProfitMoney2s.Add(profit); + + _logger.LogInformation("Money2 added: UserId={UserId}, Amount={Amount}, Source={Source}", + userId, amount, source); + } + + /// + /// 发放优惠券 + /// + private async Task<(bool success, string message)> AddCouponAsync(int userId, int? couponId, int quantity = 1) + { + if (!couponId.HasValue || couponId.Value <= 0) + { + return (false, "优惠券ID不能为空"); + } + + var coupon = await _dbContext.Coupons.FindAsync(couponId.Value); + if (coupon == null) + { + return (false, "优惠券不存在"); + } + + var ttype = coupon.Ttype ?? 0; + var effectiveDays = coupon.EffectiveDay ?? 7; + + for (int i = 0; i < quantity; i++) + { + var couponReceive = new CouponReceife + { + UserId = userId, + Title = coupon.Title, + Price = coupon.Price, + ManPrice = coupon.ManPrice, + EndTime = DateTime.Now.AddDays(effectiveDays), + CouponId = coupon.Id, + State = 0, // 未使用 + Status = 1, // 启用 + Ttype = ttype, + CreatedAt = DateTime.Now + }; + _dbContext.CouponReceives.Add(couponReceive); + } + + _logger.LogInformation("Coupon added: UserId={UserId}, CouponId={CouponId}, Quantity={Quantity}", + userId, couponId, quantity); + + return (true, "优惠券发放成功"); + } +} diff --git a/server/HoneyBox/src/HoneyBox.Infrastructure/Modules/ServiceModule.cs b/server/HoneyBox/src/HoneyBox.Infrastructure/Modules/ServiceModule.cs index be4d01e6..a1e34d20 100644 --- a/server/HoneyBox/src/HoneyBox.Infrastructure/Modules/ServiceModule.cs +++ b/server/HoneyBox/src/HoneyBox.Infrastructure/Modules/ServiceModule.cs @@ -175,13 +175,22 @@ public class ServiceModule : Module return new InventoryManager(dbContext, logger); }).As().InstancePerLifetimeScope(); + // 注册奖励发放服务 + builder.Register(c => + { + var dbContext = c.Resolve(); + var logger = c.Resolve>(); + return new RewardService(dbContext, logger); + }).As().InstancePerLifetimeScope(); + // 注册抽奖引擎服务 builder.Register(c => { var dbContext = c.Resolve(); var inventoryManager = c.Resolve(); + var rewardService = c.Resolve(); var logger = c.Resolve>(); - return new LotteryEngine(dbContext, inventoryManager, logger); + return new LotteryEngine(dbContext, inventoryManager, rewardService, logger); }).As().InstancePerLifetimeScope(); // 注册抽奖服务 diff --git a/server/HoneyBox/src/HoneyBox.Model/Models/Lottery/LotteryModels.cs b/server/HoneyBox/src/HoneyBox.Model/Models/Lottery/LotteryModels.cs index a93949f8..757e615a 100644 --- a/server/HoneyBox/src/HoneyBox.Model/Models/Lottery/LotteryModels.cs +++ b/server/HoneyBox/src/HoneyBox.Model/Models/Lottery/LotteryModels.cs @@ -715,6 +715,11 @@ public class PrizeProbability /// 销售时间 /// public DateTime? SaleTime { get; set; } + + /// + /// 奖励ID(用于发放绑定奖励) + /// + public string? RewardId { get; set; } } #endregion