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!; } /// /// 激活码管理器 /// public class ActivationCodeManager : DomainService { private readonly ISqlSugarRepository _activationCodeRepository; private readonly ISqlSugarRepository _activationCodeRecordRepository; private readonly ILogger _logger; public ActivationCodeManager( ISqlSugarRepository activationCodeRepository, ISqlSugarRepository activationCodeRecordRepository, ILogger logger) { _activationCodeRepository = activationCodeRepository; _activationCodeRecordRepository = activationCodeRecordRepository; _logger = logger; } public async Task> CreateBatchAsync( List<(ActivationCodeGoodsTypeEnum GoodsType, int Count)> items) { var entities = new List(); foreach (var item in items) { if (item.Count <= 0) { throw new UserFriendlyException("生成数量必须大于0"); } var goods = item.GoodsType.GetGoods(); if (goods == null) { throw new UserFriendlyException("激活码商品类型无效"); } for (var i = 0; i < item.Count; i++) { var code = await GenerateUniqueActivationCodeAsync(); entities.Add(new ActivationCodeAggregateRoot { Code = code, GoodsType = item.GoodsType, IsReusable = goods.IsReusable, IsSameTypeOnce = goods.IsSameTypeOnce, UsedCount = 0, Remark = null }); } } await _activationCodeRepository.InsertRangeAsync(entities); return entities; } public async Task 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 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(); } }