feat: 完成激活码功能
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Volo.Abp;
|
||||
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;
|
||||
|
||||
public class ActivationCodeRedeemContext
|
||||
{
|
||||
public ActivationCodeAggregateRoot ActivationCode { get; set; } = default!;
|
||||
public string PackageName { get; set; } = string.Empty;
|
||||
public ActivationCodeGoodsAttribute Goods { get; set; } = default!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 激活码管理器
|
||||
/// </summary>
|
||||
public class ActivationCodeManager : DomainService
|
||||
{
|
||||
private readonly ISqlSugarRepository<ActivationCodeAggregateRoot, Guid> _activationCodeRepository;
|
||||
private readonly ISqlSugarRepository<ActivationCodeRecordAggregateRoot, Guid> _activationCodeRecordRepository;
|
||||
private readonly ILogger<ActivationCodeManager> _logger;
|
||||
|
||||
public ActivationCodeManager(
|
||||
ISqlSugarRepository<ActivationCodeAggregateRoot, Guid> activationCodeRepository,
|
||||
ISqlSugarRepository<ActivationCodeRecordAggregateRoot, Guid> activationCodeRecordRepository,
|
||||
ILogger<ActivationCodeManager> logger)
|
||||
{
|
||||
_activationCodeRepository = activationCodeRepository;
|
||||
_activationCodeRecordRepository = activationCodeRecordRepository;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<List<ActivationCodeAggregateRoot>> CreateBatchAsync(ActivationCodeGoodsTypeEnum goodsType,
|
||||
int count, bool isReusable, bool isSameTypeOnce, string? remark)
|
||||
{
|
||||
if (count <= 0)
|
||||
{
|
||||
throw new UserFriendlyException("生成数量必须大于0");
|
||||
}
|
||||
|
||||
var entities = new List<ActivationCodeAggregateRoot>();
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var code = await GenerateUniqueActivationCodeAsync();
|
||||
entities.Add(new ActivationCodeAggregateRoot
|
||||
{
|
||||
Code = code,
|
||||
GoodsType = goodsType,
|
||||
IsReusable = isReusable,
|
||||
IsSameTypeOnce = isSameTypeOnce,
|
||||
UsedCount = 0,
|
||||
Remark = remark
|
||||
});
|
||||
}
|
||||
|
||||
await _activationCodeRepository.InsertRangeAsync(entities);
|
||||
return entities;
|
||||
}
|
||||
|
||||
public async Task<ActivationCodeRedeemContext> RedeemAsync(Guid userId, string code)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(code))
|
||||
{
|
||||
throw new UserFriendlyException("激活码不能为空");
|
||||
}
|
||||
|
||||
var trimmedCode = code.Trim();
|
||||
var activationCode = await _activationCodeRepository._DbQueryable
|
||||
.Where(x => x.Code == trimmedCode)
|
||||
.FirstAsync();
|
||||
|
||||
if (activationCode == null)
|
||||
{
|
||||
throw new UserFriendlyException("激活码不存在");
|
||||
}
|
||||
|
||||
var hasUsedCurrentCode = await _activationCodeRecordRepository._DbQueryable
|
||||
.Where(x => x.UserId == userId && x.ActivationCodeId == activationCode.Id)
|
||||
.AnyAsync();
|
||||
|
||||
if (hasUsedCurrentCode)
|
||||
{
|
||||
throw new UserFriendlyException("该激活码已被你使用过");
|
||||
}
|
||||
|
||||
if (!activationCode.IsReusable && activationCode.UsedCount > 0)
|
||||
{
|
||||
throw new UserFriendlyException("该激活码已被使用");
|
||||
}
|
||||
|
||||
if (activationCode.IsSameTypeOnce)
|
||||
{
|
||||
var hasUsedSameType = await _activationCodeRecordRepository._DbQueryable
|
||||
.Where(x => x.UserId == userId && x.GoodsType == activationCode.GoodsType)
|
||||
.AnyAsync();
|
||||
|
||||
if (hasUsedSameType)
|
||||
{
|
||||
throw new UserFriendlyException("该类型激活码每个用户只能兑换一次");
|
||||
}
|
||||
}
|
||||
|
||||
var goods = activationCode.GoodsType.GetGoods();
|
||||
if (goods == null)
|
||||
{
|
||||
throw new UserFriendlyException("激活码商品类型无效");
|
||||
}
|
||||
|
||||
var packageName = string.IsNullOrWhiteSpace(goods.Content)
|
||||
? goods.DisplayName
|
||||
: $"{goods.DisplayName} {goods.Content}";
|
||||
|
||||
activationCode.UsedCount += 1;
|
||||
await _activationCodeRepository.UpdateAsync(activationCode);
|
||||
|
||||
var record = new ActivationCodeRecordAggregateRoot
|
||||
{
|
||||
ActivationCodeId = activationCode.Id,
|
||||
Code = activationCode.Code,
|
||||
UserId = userId,
|
||||
GoodsType = activationCode.GoodsType,
|
||||
RedeemTime = DateTime.Now,
|
||||
Remark = "激活码兑换"
|
||||
};
|
||||
await _activationCodeRecordRepository.InsertAsync(record);
|
||||
|
||||
_logger.LogInformation("用户 {UserId} 兑换激活码 {Code} 成功", userId, activationCode.Code);
|
||||
|
||||
return new ActivationCodeRedeemContext
|
||||
{
|
||||
ActivationCode = activationCode,
|
||||
PackageName = packageName,
|
||||
Goods = goods
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<string> GenerateUniqueActivationCodeAsync()
|
||||
{
|
||||
string code;
|
||||
do
|
||||
{
|
||||
code = GenerateActivationCode();
|
||||
} while (await _activationCodeRepository._DbQueryable.AnyAsync(x => x.Code == code));
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
private string GenerateActivationCode()
|
||||
{
|
||||
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
var random = new Random();
|
||||
var builder = new StringBuilder(16);
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
builder.Append(chars[random.Next(chars.Length)]);
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user