321321
This commit is contained in:
parent
678ae9316e
commit
3fd4799459
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
270
server/HoneyBox/src/HoneyBox.Core/Services/RewardService.cs
Normal file
270
server/HoneyBox/src/HoneyBox.Core/Services/RewardService.cs
Normal 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, "优惠券发放成功");
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
|
||||
// 注册抽奖服务
|
||||
|
|
|
|||
|
|
@ -715,6 +715,11 @@ public class PrizeProbability
|
|||
/// 销售时间
|
||||
/// </summary>
|
||||
public DateTime? SaleTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 奖励ID(用于发放绑定奖励)
|
||||
/// </summary>
|
||||
public string? RewardId { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user