2025-10-12 16:42:26 +08:00
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
|
using Volo.Abp.Domain.Services;
|
|
|
|
|
|
using Yi.Framework.AiHub.Domain.Entities;
|
|
|
|
|
|
using Yi.Framework.AiHub.Domain.Shared.Enums;
|
|
|
|
|
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Yi.Framework.AiHub.Domain.Managers;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 尊享包管理器
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class PremiumPackageManager : DomainService
|
|
|
|
|
|
{
|
|
|
|
|
|
private readonly ISqlSugarRepository<PremiumPackageAggregateRoot, Guid> _premiumPackageRepository;
|
|
|
|
|
|
private readonly ILogger<PremiumPackageManager> _logger;
|
2025-10-16 09:35:25 +08:00
|
|
|
|
private readonly ISqlSugarRepository<AiRechargeAggregateRoot> _rechargeRepository;
|
2025-10-12 16:42:26 +08:00
|
|
|
|
public PremiumPackageManager(
|
|
|
|
|
|
ISqlSugarRepository<PremiumPackageAggregateRoot, Guid> premiumPackageRepository,
|
2025-10-16 09:35:25 +08:00
|
|
|
|
ILogger<PremiumPackageManager> logger, ISqlSugarRepository<AiRechargeAggregateRoot> rechargeRepository)
|
2025-10-12 16:42:26 +08:00
|
|
|
|
{
|
|
|
|
|
|
_premiumPackageRepository = premiumPackageRepository;
|
|
|
|
|
|
_logger = logger;
|
2025-10-16 09:35:25 +08:00
|
|
|
|
_rechargeRepository = rechargeRepository;
|
2025-10-12 16:42:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 为用户创建尊享包
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="userId">用户ID</param>
|
|
|
|
|
|
/// <param name="goodsType">商品类型</param>
|
|
|
|
|
|
/// <param name="totalAmount">支付金额</param>
|
|
|
|
|
|
/// <param name="expireMonths">过期月数,0或null表示永久</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public async Task<PremiumPackageAggregateRoot> CreatePremiumPackageAsync(
|
|
|
|
|
|
Guid userId,
|
|
|
|
|
|
GoodsTypeEnum goodsType,
|
|
|
|
|
|
decimal totalAmount,
|
|
|
|
|
|
int? expireMonths = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!goodsType.IsPremiumPackage())
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new UserFriendlyException($"商品类型 {goodsType} 不是尊享包商品");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var tokenAmount = goodsType.GetTokenAmount();
|
|
|
|
|
|
var packageName = goodsType.GetDisplayName();
|
|
|
|
|
|
|
|
|
|
|
|
var premiumPackage = new PremiumPackageAggregateRoot(userId, tokenAmount, packageName)
|
|
|
|
|
|
{
|
|
|
|
|
|
PurchaseAmount = totalAmount
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 设置到期时间
|
|
|
|
|
|
if (expireMonths.HasValue && expireMonths.Value > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
premiumPackage.SetExpireDateTime(DateTime.Now.AddMonths(expireMonths.Value));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
await _premiumPackageRepository.InsertAsync(premiumPackage);
|
|
|
|
|
|
|
2025-10-16 09:35:25 +08:00
|
|
|
|
// 创建充值记录
|
|
|
|
|
|
var rechargeRecord = new AiRechargeAggregateRoot
|
|
|
|
|
|
{
|
|
|
|
|
|
UserId = userId,
|
|
|
|
|
|
RechargeAmount = totalAmount,
|
|
|
|
|
|
Content = packageName,
|
|
|
|
|
|
ExpireDateTime = premiumPackage.ExpireDateTime,
|
|
|
|
|
|
Remark = "自助充值",
|
2025-10-20 10:18:24 +08:00
|
|
|
|
ContactInfo = null,
|
|
|
|
|
|
RechargeType = RechargeTypeEnum.PremiumPackage
|
2025-10-16 09:35:25 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 保存充值记录到数据库
|
|
|
|
|
|
await _rechargeRepository.InsertAsync(rechargeRecord);
|
|
|
|
|
|
|
2025-10-12 16:42:26 +08:00
|
|
|
|
_logger.LogInformation(
|
|
|
|
|
|
$"用户 {userId} 购买尊享包成功: {packageName}, Token数量: {tokenAmount}, 金额: {totalAmount}");
|
|
|
|
|
|
|
|
|
|
|
|
return premiumPackage;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 消耗用户尊享包的Token
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="userId">用户ID</param>
|
|
|
|
|
|
/// <param name="tokenCount">需要消耗的Token数量</param>
|
|
|
|
|
|
/// <returns>是否消耗成功</returns>
|
2025-10-14 22:34:05 +08:00
|
|
|
|
public async Task<bool> TryConsumeTokensAsync(Guid userId, long tokenCount)
|
2025-10-12 16:42:26 +08:00
|
|
|
|
{
|
|
|
|
|
|
// 获取用户所有可用的尊享包,按剩余token升序排列(优先消耗快用完的)
|
|
|
|
|
|
var availablePackages = await _premiumPackageRepository._DbQueryable
|
2025-10-12 21:12:21 +08:00
|
|
|
|
.Where(x => x.UserId == userId && x.IsActive)
|
2025-10-14 22:34:05 +08:00
|
|
|
|
.OrderBy(x => x.CreationTime)
|
2025-10-12 16:42:26 +08:00
|
|
|
|
.ToListAsync();
|
|
|
|
|
|
|
|
|
|
|
|
if (!availablePackages.Any())
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogWarning($"用户 {userId} 没有可用的尊享包");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 过滤掉已过期的包
|
|
|
|
|
|
var validPackages = availablePackages
|
|
|
|
|
|
.Where(p => p.IsAvailable())
|
|
|
|
|
|
.ToList();
|
|
|
|
|
|
|
|
|
|
|
|
if (!validPackages.Any())
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogWarning($"用户 {userId} 的尊享包已全部过期");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-14 22:34:05 +08:00
|
|
|
|
var firstPackage = validPackages.First();
|
|
|
|
|
|
// 直接扣除最早的token包需要消耗的token,允许扣减到负数
|
|
|
|
|
|
firstPackage.ConsumeTokens(tokenCount);
|
|
|
|
|
|
await _premiumPackageRepository.UpdateAsync(firstPackage);
|
2025-10-12 16:42:26 +08:00
|
|
|
|
|
2025-10-14 22:34:05 +08:00
|
|
|
|
return true;
|
2025-10-12 16:42:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取用户可用的尊享包总Token数
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="userId">用户ID</param>
|
|
|
|
|
|
/// <returns>可用Token总数</returns>
|
|
|
|
|
|
public async Task<long> GetAvailableTokensAsync(Guid userId)
|
|
|
|
|
|
{
|
2025-10-12 21:12:21 +08:00
|
|
|
|
return await _premiumPackageRepository._DbQueryable
|
2025-10-12 16:42:26 +08:00
|
|
|
|
.Where(x => x.UserId == userId && x.IsActive && x.RemainingTokens > 0)
|
2025-10-13 22:09:47 +08:00
|
|
|
|
.Where(p => p.IsActive)
|
|
|
|
|
|
.Where(p => !p.ExpireDateTime.HasValue || p.ExpireDateTime.Value >= DateTime.Now)
|
2025-10-12 21:12:21 +08:00
|
|
|
|
.SumAsync(p => p.RemainingTokens);
|
2025-10-12 16:42:26 +08:00
|
|
|
|
}
|
2025-10-12 21:12:21 +08:00
|
|
|
|
}
|