using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using OfficeOpenXml.FormulaParsing.Excel.Functions.Math; using WIDESEA_Core.BaseRepository; using WIDESEA_Core.BaseServices; using WIDESEA_DTO.BasicInfo; using WIDESEA_IBasicInfoServices; using WIDESEA_Model.Models; namespace WIDESEA_BasicInfoServices { public class ActivationCodeService : ServiceBase>, IActivationCodeService { private readonly IRepository _charMappingRepository; private readonly IRepository _runtimeCodeRepository; private readonly IRepository _productRepository; public ActivationCodeService(IRepository BaseDal, IRepository charMappingRepository, IRepository runtimeCodeRepository, IRepository productRepository) : base(BaseDal) { _charMappingRepository = charMappingRepository; _runtimeCodeRepository = runtimeCodeRepository; _productRepository = productRepository; } /// /// 生成激活码 /// /// 包含运行码、设备ID和产品名称的数据传输对象 /// 生成的激活码 public string GenerateActivationCode(ActivationCodeDTO activationDTO) { // 查询运行码对应的模型 Dt_RuntimeCode runtimeCodeModel = _runtimeCodeRepository.QueryFirst(x => x.RuntimeCode == activationDTO.RuntimeCode); // 1. 检查运行码是否已存在 if (runtimeCodeModel == null) { throw new InvalidOperationException($"无效的运行码: {activationDTO.RuntimeCode}"); } // 查询激活码对应的模型 Dt_ActivationCode activationCodeModel = BaseDal.QueryFirst(x => x.RuntimeCode == activationDTO.RuntimeCode); // 2. 检查激活码是否已存在 if (activationCodeModel != null) { return activationCodeModel.ActivationCode; } int productId = -1; // 查询产品对应的模型 Dt_Products product = _productRepository.QueryFirst(x => x.ProductName == activationDTO.ProductName); if (product != null) { productId = product.Id; } // 3. 检查设备ID和产品ID是否匹配 if (runtimeCodeModel.DeviceId != activationDTO.DeviceId || runtimeCodeModel.ProductId != productId) { throw new InvalidOperationException($"设备ID或产品ID不匹配: {activationDTO.DeviceId}, {productId}"); } // 4. 生成激活码 // 去除运行码中的"-"字符 string baseRandom = activationDTO.RuntimeCode.Replace("-", string.Empty); // 查询字符映射字典 Dictionary mappingDict = _charMappingRepository.QueryData().ToDictionary(x => x.InputChar.ToCharArray().FirstOrDefault(), x => (x.OutputChar.ToCharArray().FirstOrDefault(), x.ShiftFactor)); char[] result = new char[baseRandom.Length]; int length = baseRandom.Length; // 遍历运行码的每个字符进行转换 for (int i = 0; i < length; i++) { char current = baseRandom[i]; if (current == '-') continue; if (!mappingDict.TryGetValue(current, out var mapping)) throw new InvalidOperationException($"无效字符: {current}"); // 特殊变换:每5个字符增加复杂度 char mappedChar = (i % 5 == 4) ? ApplySpecialTransform(mapping.output, mapping.shift) : mapping.output; result[i] = mappedChar; } // 格式化激活码 string activationCode = FormatCode(new string(result)); // 5. 存储激活码 StoredActivationCode(activationDTO.DeviceId, baseRandom, activationCode, activationDTO.RuntimeCode, productId); return activationCode; } /// /// 对输入字符进行基于ASCII码的二次变换。 /// /// 要变换的字符。 /// 字符的位置,用于计算变换值。 /// 变换后的字符。 private char ApplySpecialTransform(char c, int position) { // 将字符转换为ASCII码 int ascii = (int)c; // 计算变换后的ASCII码值,基于字符的位置进行偏移,并确保结果在0-35范围内 int transformed = (ascii + position) % 36 + 48; // 如果变换后的ASCII码值在':'到'@'之间(即字符'9'到字符'@'),则再偏移7个位置 if (transformed >= ':' && transformed <= '@') { transformed += 7; } // 将变换后的ASCII码值转换回字符并返回 return (char)transformed; } /// /// 将原始字符串格式化为XXXXX-XXXXX-XXXXX-XXXXX-XXXXX的形式 /// /// 需要格式化的原始字符串,长度必须为25个字符 private string FormatCode(string raw) { // 格式化为XXXXX-XXXXX-XXXXX-XXXXX-XXXXX return string.Join("-", raw.Substring(0, 5), raw.Substring(5, 5), raw.Substring(10, 5), raw.Substring(15, 5), raw.Substring(20, 5)); } /// /// 存储激活码信息到数据库 /// /// 设备ID,用于标识特定设备 /// 基础随机码,用于生成激活码的随机字符串 /// 激活码,用于产品激活的唯一代码 /// 运行时码,用于验证激活状态的代码 /// 产品ID,用于标识不同的产品 private void StoredActivationCode(string deviceId, string baseRandom, string activationCode, string runtimeCode, int productId) { Dt_ActivationCode activationRecord = new Dt_ActivationCode { MappedRandom = baseRandom, ActivationCode = activationCode, DeviceId = deviceId, IsUsed = false, ProductId = productId, ExpiresTime = null, RuntimeCode = runtimeCode }; BaseDal.AddData(activationRecord); } } }