using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Text; using System.Threading.Tasks; using WMS.Web.Core.Dto; using WMS.Web.Domain.IService.Public; using WMS.Web.Domain.Options; using WMS.Web.Core.Internal.Results; using WMS.Web.Core.Dto.LingXing; using System.Json; using System.Net.Http; using NPOI.POIFS.Crypt.Dsig; using NPOI.SS.Formula.Functions; using System.Configuration; using System.Linq; using System.Net; using System.Text.RegularExpressions; using System.Security.Cryptography; using System.Reflection; using WMS.Web.Core.Help; using static System.Net.WebRequestMethods; using WMS.Web.Domain.Values; using WMS.Web.Core.Dto.JuShuiTan; namespace WMS.Web.Domain.Services.Public { /// /// 领星服务接口 /// public class LingXingService : ILingXingService { private readonly IHttpClientService _httpClientService; private readonly ILogger _logger; private readonly IMemoryCache _memoryCache; private int hours = 10;//过期时间 默认10小时 private readonly lingXingOptions _option; public LingXingService(IHttpClientService httpClientService, ILogger logger, IMemoryCache memoryCache, IOptions option) { this._memoryCache = memoryCache; this._httpClientService = httpClientService; this._logger = logger; _option = option?.Value; } public async Task> Login() { string endStr = "/api/auth-server/oauth/access-token"; var formData = new MultipartFormDataContent(); formData.Add(new StringContent(_option.AppId), "appId"); formData.Add(new StringContent(_option.AppSecret), "appSecret"); var res = await _httpClientService.PostAsync(_option.Url + endStr, formData, null); if (res.code != "200") { _logger.LogInformation($"领星获取授权失败:{res.msg}"); return Result.ReFailure(ResultCodes.LingXingTokenError); } string token = res.data.access_token; return Result.ReSuccess(token); } /// /// 获取所有仓库 /// /// public async Task>> GetStock() { var stock_list = _memoryCache.Get>("lingxing_stock"); if (stock_list != null && stock_list.Count > 0) return Result>.ReSuccess(stock_list); //默认获取本地仓库 如果需要海外仓 另外需传参数type var request = new LingXingRequest(); var resUrl = await GetStr("/erp/sc/data/local_inventory/warehouse", request); if (!resUrl.IsSuccess) return Result>.ReFailure(ResultCodes.LingXingUrlError); var res = await _httpClientService.PostAsync(resUrl.Data, JsonConvert.SerializeObject(request), null); if (res.Code != 0) return Result>.ReFailure(ResultCodes.LingXingDataError); var list = JsonConvert.DeserializeObject>(res.Data.ToString()); //设置缓存 _memoryCache.Set("lingxing_stock", list, new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromMinutes(DateTimeUtil.GetTotalMinutesTimeSpan()))); return Result>.ReSuccess(list); } /// /// 获取所有店铺 /// /// /// public async Task>> GetSeller() { var seller_list = _memoryCache.Get>("lingxing_seller"); if (seller_list != null && seller_list.Count > 0) return Result>.ReSuccess(seller_list); var request = new LingXingKongRequest(); var resUrl = await GetStr("/erp/sc/data/seller/lists", request); if (!resUrl.IsSuccess) return Result>.ReFailure(ResultCodes.LingXingUrlError); var res = await _httpClientService.GetAsync(resUrl.Data); if (res.Code != 0) return Result>.ReFailure(ResultCodes.LingXingDataError); var list = JsonConvert.DeserializeObject>(res.Data.ToString()); //设置缓存 _memoryCache.Set("lingxing_seller", list, new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromMinutes(DateTimeUtil.GetTotalMinutesTimeSpan()))); return Result>.ReSuccess(list); } /// /// 获取即使库存 /// /// /// /// public async Task>> GetInventory(LingXingInventoryRequest dto) { var resUrl = await GetStr("/erp/sc/routing/data/local_inventory/inventoryDetails", dto); if (!resUrl.IsSuccess) return Result>.ReFailure(ResultCodes.LingXingUrlError); List list = new List(); var res = await _httpClientService.PostAsync(resUrl.Data, JsonConvert.SerializeObject(dto), null); if (res.Code != 0) return Result>.ReFailure(ResultCodes.LingXingDataError); list.AddRange(JsonConvert.DeserializeObject>(res.Data.ToString())); int num = res.Total / 800; for (int i = 1; i <= num; i++) { dto.offset = i; if (i == num) dto.length = res.Total - (num * 800); resUrl = await GetStr("/erp/sc/routing/data/local_inventory/inventoryDetails", dto); if (!resUrl.IsSuccess) return Result>.ReFailure(ResultCodes.LingXingUrlError); res = await _httpClientService.PostAsync(resUrl.Data, JsonConvert.SerializeObject(dto), null); if (res.Code != 0) return Result>.ReFailure(ResultCodes.LingXingDataError); list.AddRange(JsonConvert.DeserializeObject>(res.Data.ToString())); } return Result>.ReSuccess(list.Where(w => w.Product_Total > 0 && w.Product_Valid_Num > 0).ToList()); } #region 基础函数 public async Task> GetStr(string urlStr, T data) { var res = await Login(); if (!res.IsSuccess) return res; LxSignInfo lxSign = new LxSignInfo(); lxSign.access_token = res.Data; lxSign.app_key = _option.AppId; lxSign.timestamp = DateTime.Now.DateTimeToTimeStamp().ToString(); #region ASCII排序 Dictionary testParamDics = new Dictionary(); var ssi = GetEntityPropertyToDic(testParamDics, lxSign.GetType().GetProperties(), lxSign);//把签名参数实体转化为键值对 var ssdata = GetEntityPropertyToDic(testParamDics, data.GetType().GetProperties(), data);//把参数实体转化为键值对 // List> list = new List>(); Dictionary list = new Dictionary(); //string[] arrays = new string[data]; foreach (var item in typeof(LxSignInfo).GetProperties()) { //KeyValueInfo keys = new KeyValueInfo(); //keys.Key = item.Name; //keys.Value = ssi[$"{item.Name}"].ToString(); //list.Add(keys); list.Add(item.Name, ssi[$"{item.Name}"].ToString()); } foreach (var item in typeof(T).GetProperties()) { //KeyValueInfo keys = new KeyValueInfo(); //keys.Key = item.Name; //keys.Value = JsonConvert.SerializeObject(ssdata[$"{item.Name}"]); //if (ssdata[$"{item.Name}"] == null) { list.Add(keys); continue; } //if (string.IsNullOrEmpty(ssdata[$"{item.Name}"].ToString())) //{ // continue;//跳过值为NULL的 //} if (ssdata[$"{item.Name}"] == null) { list.Add(item.Name, JsonConvert.SerializeObject(ssdata[$"{item.Name}"])); continue; } if (string.IsNullOrEmpty(ssdata[$"{item.Name}"].ToString())) { continue;//跳过值为NULL的 } list.Add(item.Name, JsonConvert.SerializeObject(ssdata[$"{item.Name}"])); } string[] arrays = new string[list.Count]; int i = 0; foreach (var item in list) { arrays[i] = item.Key; i++; } Array.Sort(arrays, string.CompareOrdinal); //ASCII排序 string sig = null; int j = 0; foreach (var item in arrays) { string key = list.Where(a => a.Key == item).ToList()[0].Key.ToString(); string value = list.Where(a => a.Key == item).ToList()[0].Value.ToString(); #region 清除嵌套外的字段值的双引号 if (value.IndexOf("{", StringComparison.OrdinalIgnoreCase) > -1) { } else { value = Regex.Replace(value, @"[\""]+", "");//去掉双引号 } #endregion if (j == i - 1) { sig += $"{key}={value}"; } else { sig += $"{key}={value}&"; } j++; } #endregion #region MD5加密转大写+AES/ECB/PKCS5PADDING加密 //sig = Regex.Replace(sig, @"[\""]+", "");//去掉双引号 var md5 = MD5Encrypt(sig, false); var signs = Encrypt(md5, lxSign.app_key); #endregion #region 字符转义 signs = WebUtility.UrlEncode(signs); #endregion #region 形成签名地址 var url = _option.Url + urlStr; var ret = $"{url}?app_key={lxSign.app_key}&access_token={lxSign.access_token}×tamp={lxSign.timestamp}&sign={signs}"; return Result.ReSuccess(ret); #endregion } /// /// 32位MD5加密 /// /// 要加密字符串 /// 是否以小写方式返回 /// public static string MD5Encrypt(string strText, bool IsLower = true) { MD5 md5 = new MD5CryptoServiceProvider(); byte[] bytes = System.Text.Encoding.UTF8.GetBytes(strText); bytes = md5.ComputeHash(bytes); md5.Clear(); string ret = ""; for (int i = 0; i < bytes.Length; i++) { ret += Convert.ToString(bytes[i], 16).PadLeft(2, '0'); } if (IsLower == false) { return ret.PadLeft(32, '0').ToUpper(); } return ret.PadLeft(32, '0'); } /// /// AES加密 /// /// 需要加密的字符串 /// 32位密钥 ///向量(默认偏移量) /// 加密后的字符串 public static string Encrypt(string str, string key) { try { Byte[] keyArray = System.Text.Encoding.UTF8.GetBytes(key); Byte[] toEncryptArray = System.Text.Encoding.UTF8.GetBytes(str); var rijndael = new System.Security.Cryptography.RijndaelManaged(); rijndael.Key = keyArray; rijndael.Mode = System.Security.Cryptography.CipherMode.ECB; rijndael.Padding = System.Security.Cryptography.PaddingMode.PKCS7; rijndael.IV = System.Text.Encoding.UTF8.GetBytes(key); System.Security.Cryptography.ICryptoTransform cTransform = rijndael.CreateEncryptor(); Byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length); return Convert.ToBase64String(resultArray, 0, resultArray.Length); } catch (Exception ex) { //YellowJLog("调用AES加密方法异常,异常原因:" + ex.Message, "加密异常"); return ""; } } /// /// 类实体的属性与值转化成键值对形式 /// /// /// /// /// public static Dictionary GetEntityPropertyToDic(Dictionary inParam, PropertyInfo[] infos, T Entity) { foreach (var info in infos) { var itemTpe = info.PropertyType; //实体中有嵌套类的处理 if (itemTpe.IsClass && !itemTpe.Name.Equals("String", StringComparison.OrdinalIgnoreCase)) { //if (info.GetValue(Entity) == null) continue; //GetEntityPropertyToDic(inParam, itemTpe.GetProperties(), info.GetValue(Entity)); //inParam.Add(info.Name, info.GetValue(JsonConvert.SerializeObject(Entity), null)); inParam.Add(info.Name, info.GetValue(Entity, null)); } else { inParam.Add(info.Name, info.GetValue(Entity, null)); //sig = Regex.Replace(sig, @"[\""]+", "");//去掉双引号 } } return inParam; } #endregion } public class LxSignInfo { public string access_token { get; set; } public string app_key { get; set; } public string timestamp { get; set; } } }