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