This commit is contained in:
zpc 2026-01-25 16:04:50 +08:00
parent 678ae9316e
commit 3fd4799459
5 changed files with 406 additions and 3 deletions

View File

@ -0,0 +1,73 @@
namespace HoneyBox.Core.Interfaces;
/// <summary>
/// 奖励发放服务接口
/// </summary>
public interface IRewardService
{
/// <summary>
/// 发放奖励
/// </summary>
/// <param name="userId">用户ID</param>
/// <param name="rewardId">奖励ID业务标识</param>
/// <param name="source">奖励来源描述</param>
/// <returns>发放结果</returns>
Task<RewardSendResult> SendRewardAsync(int userId, string rewardId, string source = "系统奖励");
/// <summary>
/// 发放奖励(带倍数)
/// </summary>
/// <param name="userId">用户ID</param>
/// <param name="rewardId">奖励ID业务标识</param>
/// <param name="multiple">倍数</param>
/// <param name="source">奖励来源描述</param>
/// <returns>发放结果</returns>
Task<RewardSendResult> SendRewardMultipleAsync(int userId, string rewardId, int multiple, string source = "系统奖励");
}
/// <summary>
/// 奖励发放结果
/// </summary>
public class RewardSendResult
{
/// <summary>
/// 是否成功
/// </summary>
public bool Success { get; set; }
/// <summary>
/// 消息
/// </summary>
public string Message { get; set; } = string.Empty;
/// <summary>
/// 发放详情列表
/// </summary>
public List<RewardSendDetail> Details { get; set; } = new();
}
/// <summary>
/// 单个奖励发放详情
/// </summary>
public class RewardSendDetail
{
/// <summary>
/// 奖励记录ID
/// </summary>
public int RewardId { get; set; }
/// <summary>
/// 奖励类型
/// </summary>
public int RewardType { get; set; }
/// <summary>
/// 是否成功
/// </summary>
public bool Success { get; set; }
/// <summary>
/// 消息
/// </summary>
public string Message { get; set; } = string.Empty;
}

View File

@ -16,6 +16,7 @@ public class LotteryEngine : ILotteryEngine
{
private readonly HoneyBoxDbContext _dbContext;
private readonly IInventoryManager _inventoryManager;
private readonly IRewardService _rewardService;
private readonly ILogger<LotteryEngine> _logger;
/// <summary>
@ -36,10 +37,12 @@ public class LotteryEngine : ILotteryEngine
public LotteryEngine(
HoneyBoxDbContext dbContext,
IInventoryManager inventoryManager,
IRewardService rewardService,
ILogger<LotteryEngine> 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
}
}
/// <summary>
/// 处理奖品绑定奖励发放
/// </summary>
/// <param name="userId">用户ID</param>
/// <param name="rewardId">奖励ID</param>
/// <param name="prizeTitle">奖品标题</param>
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);
// 奖励发放失败不影响抽奖结果
}
}
/// <inheritdoc />
/// <remarks>
/// 多次无限赏抽奖流程:
@ -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();
}

View File

@ -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;
/// <summary>
/// 奖励发放服务实现
/// 支持发放钻石、UU币、达达券、优惠券等奖励
/// </summary>
public class RewardService : IRewardService
{
private readonly HoneyBoxDbContext _dbContext;
private readonly ILogger<RewardService> _logger;
public RewardService(HoneyBoxDbContext dbContext, ILogger<RewardService> logger)
{
_dbContext = dbContext;
_logger = logger;
}
/// <inheritdoc />
public async Task<RewardSendResult> SendRewardAsync(int userId, string rewardId, string source = "系统奖励")
{
return await SendRewardInternalAsync(userId, rewardId, 1, source);
}
/// <inheritdoc />
public async Task<RewardSendResult> SendRewardMultipleAsync(int userId, string rewardId, int multiple, string source = "系统奖励")
{
return await SendRewardInternalAsync(userId, rewardId, multiple, source);
}
/// <summary>
/// 内部发放奖励方法
/// </summary>
private async Task<RewardSendResult> 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;
}
/// <summary>
/// 发放单个奖励
/// </summary>
private async Task<RewardSendDetail> 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;
}
/// <summary>
/// 增加钻石
/// </summary>
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);
}
/// <summary>
/// 增加UU币积分
/// </summary>
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);
}
/// <summary>
/// 增加达达券
/// </summary>
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);
}
/// <summary>
/// 发放优惠券
/// </summary>
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, "优惠券发放成功");
}
}

View File

@ -175,13 +175,22 @@ public class ServiceModule : Module
return new InventoryManager(dbContext, logger);
}).As<IInventoryManager>().InstancePerLifetimeScope();
// 注册奖励发放服务
builder.Register(c =>
{
var dbContext = c.Resolve<HoneyBoxDbContext>();
var logger = c.Resolve<ILogger<RewardService>>();
return new RewardService(dbContext, logger);
}).As<IRewardService>().InstancePerLifetimeScope();
// 注册抽奖引擎服务
builder.Register(c =>
{
var dbContext = c.Resolve<HoneyBoxDbContext>();
var inventoryManager = c.Resolve<IInventoryManager>();
var rewardService = c.Resolve<IRewardService>();
var logger = c.Resolve<ILogger<LotteryEngine>>();
return new LotteryEngine(dbContext, inventoryManager, logger);
return new LotteryEngine(dbContext, inventoryManager, rewardService, logger);
}).As<ILotteryEngine>().InstancePerLifetimeScope();
// 注册抽奖服务

View File

@ -715,6 +715,11 @@ public class PrizeProbability
/// 销售时间
/// </summary>
public DateTime? SaleTime { get; set; }
/// <summary>
/// 奖励ID用于发放绑定奖励
/// </summary>
public string? RewardId { get; set; }
}
#endregion