CommonUtil.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. // 麻省理工学院许可证
  2. //
  3. // 版权所有 (c) 2021-2023 zuohuaijun,大名科技(天津)有限公司 联系电话/微信:18020030720 QQ:515096995
  4. //
  5. // 特此免费授予获得本软件的任何人以处理本软件的权利,但须遵守以下条件:在所有副本或重要部分的软件中必须包括上述版权声明和本许可声明。
  6. //
  7. // 软件按“原样”提供,不提供任何形式的明示或暗示的保证,包括但不限于对适销性、适用性和非侵权的保证。
  8. // 在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是因合同、侵权或其他方式引起的,与软件或其使用或其他交易有关。
  9. using Magicodes.ExporterAndImporter.Core.Models;
  10. using Nest;
  11. using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
  12. using System.Xml;
  13. using System.Xml.Linq;
  14. using System.Xml.Serialization;
  15. using static SKIT.FlurlHttpClient.Wechat.Api.Models.CgibinTagsMembersGetBlackListResponse.Types;
  16. namespace Admin.NET.Core;
  17. /// <summary>
  18. /// 通用工具类
  19. /// </summary>
  20. public static class CommonUtil
  21. {
  22. /// <summary>
  23. /// 生成百分数
  24. /// </summary>
  25. /// <param name="PassCount"></param>
  26. /// <param name="allCount"></param>
  27. /// <returns></returns>
  28. public static string ExecPercent(decimal PassCount, decimal allCount)
  29. {
  30. string res = "";
  31. if (allCount > 0)
  32. {
  33. var value = (double)Math.Round(PassCount / allCount * 100, 1);
  34. if (value < 0)
  35. res = Math.Round(value + 5 / Math.Pow(10, 0 + 1), 0, MidpointRounding.AwayFromZero).ToString();
  36. else
  37. res = Math.Round(value, 0, MidpointRounding.AwayFromZero).ToString();
  38. }
  39. if (res == "") res = "0";
  40. return res + "%";
  41. }
  42. /// <summary>
  43. /// 获取服务地址
  44. /// </summary>
  45. /// <returns></returns>
  46. public static string GetLocalhost()
  47. {
  48. string result = $"{App.HttpContext.Request.Scheme}://{App.HttpContext.Request.Host.Value}";
  49. // 代理模式:获取真正的本机地址
  50. // X-Original-Host=原始请求
  51. // X-Forwarded-Server=从哪里转发过来
  52. if (App.HttpContext.Request.Headers.ContainsKey("Origin")) // 配置成完整的路径如(结尾不要带"/"),比如 https://www.abc.com
  53. result = $"{App.HttpContext.Request.Headers["Origin"]}";
  54. else if (App.HttpContext.Request.Headers.ContainsKey("X-Original")) // 配置成完整的路径如(结尾不要带"/"),比如 https://www.abc.com
  55. result = $"{App.HttpContext.Request.Headers["X-Original"]}";
  56. else if (App.HttpContext.Request.Headers.ContainsKey("X-Original-Host"))
  57. result = $"{App.HttpContext.Request.Scheme}://{App.HttpContext.Request.Headers["X-Original-Host"]}";
  58. return result;
  59. }
  60. /// <summary>
  61. /// 对象序列化XML
  62. /// </summary>
  63. /// <typeparam name="T"></typeparam>
  64. /// <param name="obj"></param>
  65. /// <returns></returns>
  66. public static string SerializeObjectToXml<T>(T obj)
  67. {
  68. if (obj == null) return string.Empty;
  69. var xs = new XmlSerializer(obj.GetType());
  70. var stream = new MemoryStream();
  71. var setting = new XmlWriterSettings
  72. {
  73. Encoding = new UTF8Encoding(false), // 不包含BOM
  74. Indent = true // 设置格式化缩进
  75. };
  76. using (var writer = XmlWriter.Create(stream, setting))
  77. {
  78. var ns = new XmlSerializerNamespaces();
  79. ns.Add("", ""); // 去除默认命名空间
  80. xs.Serialize(writer, obj, ns);
  81. }
  82. return Encoding.UTF8.GetString(stream.ToArray());
  83. }
  84. /// <summary>
  85. /// 字符串转XML格式
  86. /// </summary>
  87. /// <param name="xmlStr"></param>
  88. /// <returns></returns>
  89. public static XElement SerializeStringToXml(string xmlStr)
  90. {
  91. try
  92. {
  93. return XElement.Parse(xmlStr);
  94. }
  95. catch
  96. {
  97. return null;
  98. }
  99. }
  100. /// <summary>
  101. /// 导出模板Excel
  102. /// </summary>
  103. /// <returns></returns>
  104. public static async Task<IActionResult> ExportExcelTemplate<T>() where T : class,new()
  105. {
  106. IImporter importer = new ExcelImporter();
  107. var res=await importer.GenerateTemplateBytes<T>();
  108. return new FileContentResult(res, "application/octet-stream") { FileDownloadName = typeof(T).Name+".xlsx" };
  109. }
  110. /// <summary>
  111. /// 导出数据excel
  112. /// </summary>
  113. /// <returns></returns>
  114. public static async Task<IActionResult> ExportExcelData<T>(ICollection<T> data) where T : class, new()
  115. {
  116. var export = new ExcelExporter();
  117. var res = await export.ExportAsByteArray<T>(data);
  118. return new FileContentResult(res, "application/octet-stream") { FileDownloadName = typeof(T).Name + ".xlsx" };
  119. }
  120. /// <summary>
  121. /// 导出数据excel,包括字典转换
  122. /// </summary>
  123. /// <returns></returns>
  124. public static async Task<IActionResult> ExportExcelData<TSource, TTarget>(ISugarQueryable<TSource> query, Func<TSource, TTarget, TTarget> action = null)
  125. where TSource : class, new() where TTarget : class, new ()
  126. {
  127. var PropMappings = GetExportPropertMap< TSource, TTarget >();
  128. var data = query.ToList();
  129. //相同属性复制值,字典值转换
  130. var result = new List<TTarget>();
  131. foreach (var item in data)
  132. {
  133. var newData = new TTarget();
  134. foreach (var dict in PropMappings)
  135. {
  136. var targeProp = dict.Value.Item3;
  137. if (targeProp != null)
  138. {
  139. var propertyInfo = dict.Value.Item2;
  140. var sourceVal = propertyInfo.GetValue(item, null);
  141. if (sourceVal == null)
  142. {
  143. continue;
  144. }
  145. var map = dict.Value.Item1;
  146. if (map != null && map.ContainsKey(sourceVal))
  147. {
  148. var newVal = map[sourceVal];
  149. targeProp.SetValue(newData, newVal);
  150. }
  151. else
  152. {
  153. if (targeProp.PropertyType.FullName == propertyInfo.PropertyType.FullName)
  154. {
  155. targeProp.SetValue(newData, sourceVal);
  156. }
  157. else
  158. {
  159. var newVal = sourceVal.ToString().ParseTo(targeProp.PropertyType);
  160. targeProp.SetValue(newData, newVal);
  161. }
  162. }
  163. }
  164. if (action != null)
  165. {
  166. newData = action(item, newData);
  167. }
  168. }
  169. result.Add(newData);
  170. }
  171. var export = new ExcelExporter();
  172. var res = await export.ExportAsByteArray(result);
  173. return new FileContentResult(res, "application/octet-stream") { FileDownloadName = typeof(TTarget).Name + ".xlsx" };
  174. }
  175. /// <summary>
  176. /// 导入数据Excel
  177. /// </summary>
  178. /// <param name="file"></param>
  179. /// <returns></returns>
  180. public static async Task<ICollection<T>> ImportExcelData<T>([Required] IFormFile file) where T : class, new()
  181. {
  182. IImporter importer = new ExcelImporter();
  183. var res = await importer.Import<T>(file.OpenReadStream());
  184. string message = string.Empty;
  185. if (res.HasError)
  186. {
  187. if (res.Exception != null)
  188. message += $"\r\n{res.Exception.Message}";
  189. foreach (DataRowErrorInfo drErrorInfo in res.RowErrors)
  190. {
  191. int rowNum = drErrorInfo.RowIndex;
  192. foreach (var item in drErrorInfo.FieldErrors)
  193. message += $"\r\n{item.Key}:{item.Value}(文件第{drErrorInfo.RowIndex}行)";
  194. }
  195. message += "字段缺失:" + string.Join(",", res.TemplateErrors.Select(m => m.RequireColumnName).ToList());
  196. throw Oops.Oh("导入异常:" + message);
  197. }
  198. return res.Data;
  199. }
  200. //例:List<Dm_ApplyDemo> ls = CommonUtil.ParseList<Dm_ApplyDemoInport, Dm_ApplyDemo>(importResult.Data);
  201. /// <summary>
  202. /// 对象转换 含字典转换
  203. /// </summary>
  204. /// <typeparam name="TSource"></typeparam>
  205. /// <typeparam name="TTarget"></typeparam>
  206. /// <param name="data"></param>
  207. /// <param name="action"></param>
  208. /// <returns></returns>
  209. public static List<TTarget> ParseList<TSource, TTarget>(IEnumerable<TSource> data, Func<TSource, TTarget, TTarget> action=null) where TTarget : new()
  210. {
  211. Dictionary<string, Tuple<Dictionary<string, object>, PropertyInfo, PropertyInfo>> PropMappings = GetImportPropertMap<TSource, TTarget>();
  212. //相同属性复制值,字典值转换
  213. var result = new List<TTarget>();
  214. foreach (var item in data)
  215. {
  216. var newData = new TTarget();
  217. foreach (var dict in PropMappings)
  218. {
  219. var targeProp = dict.Value.Item3;
  220. if (targeProp != null)
  221. {
  222. var propertyInfo = dict.Value.Item2;
  223. var sourceVal = propertyInfo.GetValue(item, null);
  224. if (sourceVal == null)
  225. {
  226. continue;
  227. }
  228. var map = dict.Value.Item1;
  229. if (map != null && map.ContainsKey(sourceVal.ToString()))
  230. {
  231. var newVal = map[sourceVal.ToString()];
  232. targeProp.SetValue(newData, newVal);
  233. }
  234. else
  235. {
  236. if (targeProp.PropertyType.FullName == propertyInfo.PropertyType.FullName)
  237. {
  238. targeProp.SetValue(newData, sourceVal);
  239. }
  240. else
  241. {
  242. var newVal = sourceVal.ToString().ParseTo(targeProp.PropertyType);
  243. targeProp.SetValue(newData, newVal);
  244. }
  245. }
  246. }
  247. }
  248. if (action != null)
  249. {
  250. newData = action(item, newData);
  251. }
  252. if (newData != null)
  253. result.Add(newData);
  254. }
  255. return result;
  256. }
  257. /// <summary>
  258. /// 获取导入属性映射
  259. /// </summary>
  260. /// <typeparam name="TSource"></typeparam>
  261. /// <typeparam name="TTarget"></typeparam>
  262. /// <returns>整理导入对象的 属性名称, 字典数据,原属性信息,目标属性信息 </returns>
  263. private static Dictionary<string, Tuple<Dictionary<string, object>, PropertyInfo, PropertyInfo>> GetImportPropertMap<TSource, TTarget>() where TTarget : new()
  264. {
  265. var dictService = App.GetService<SqlSugarRepository<SysDictData>>();
  266. //整理导入对象的 属性名称,<字典数据,原属性信息,目标属性信息>
  267. Dictionary<string, Tuple<Dictionary<string, object>, PropertyInfo, PropertyInfo>> PropMappings =
  268. new Dictionary<string, Tuple<Dictionary<string, object>, PropertyInfo, PropertyInfo>>();
  269. var TSourceProps = typeof(TSource).GetProperties().ToList();
  270. var TTargetProps = typeof(TTarget).GetProperties().ToDictionary(m => m.Name);
  271. foreach (var propertyInfo in TSourceProps)
  272. {
  273. var attrs = propertyInfo.GetCustomAttribute<ImportDictAttribute>();
  274. if (attrs != null && !string.IsNullOrWhiteSpace(attrs.TypeCode))
  275. {
  276. var targetProp = TTargetProps[attrs.TargetPropName];
  277. var MappingValues = dictService.Context.Queryable<SysDictType, SysDictData>((a, b) =>
  278. new JoinQueryInfos(JoinType.Inner, a.Id == b.DictTypeId))
  279. .Where(a => a.Code == attrs.TypeCode)
  280. .Where((a, b) => a.Status == StatusEnum.Enable && b.Status == StatusEnum.Enable)
  281. .Select((a, b) => new
  282. {
  283. Label = b.Value,
  284. Value = b.Code
  285. }).ToList()
  286. .ToDictionary(m => m.Label, m => m.Value.ParseTo(targetProp.PropertyType));
  287. PropMappings.Add(propertyInfo.Name, new Tuple<Dictionary<string, object>, PropertyInfo, PropertyInfo>(
  288. MappingValues, propertyInfo, targetProp
  289. ));
  290. }
  291. else
  292. {
  293. PropMappings.Add(propertyInfo.Name, new Tuple<Dictionary<string, object>, PropertyInfo, PropertyInfo>(
  294. null, propertyInfo, TTargetProps.ContainsKey(propertyInfo.Name) ? TTargetProps[propertyInfo.Name] : null
  295. ));
  296. }
  297. }
  298. return PropMappings;
  299. }
  300. /// <summary>
  301. /// 获取导出属性映射
  302. /// </summary>
  303. /// <typeparam name="TSource"></typeparam>
  304. /// <typeparam name="TTarget"></typeparam>
  305. /// <returns>整理导入对象的 属性名称, 字典数据,原属性信息,目标属性信息 </returns>
  306. private static Dictionary<string, Tuple<Dictionary<object,string>, PropertyInfo, PropertyInfo>> GetExportPropertMap<TSource, TTarget>() where TTarget : new()
  307. {
  308. var dictService = App.GetService<SqlSugarRepository<SysDictData>>();
  309. //整理导入对象的 属性名称,<字典数据,原属性信息,目标属性信息>
  310. Dictionary<string, Tuple<Dictionary<object,string>, PropertyInfo, PropertyInfo>> PropMappings =
  311. new Dictionary<string, Tuple<Dictionary<object,string>, PropertyInfo, PropertyInfo>>();
  312. var TargetProps = typeof(TTarget).GetProperties().ToList();
  313. var SourceProps = typeof(TSource).GetProperties().ToDictionary(m => m.Name);
  314. foreach (var propertyInfo in TargetProps)
  315. {
  316. var attrs = propertyInfo.GetCustomAttribute<ImportDictAttribute>();
  317. if (attrs != null && !string.IsNullOrWhiteSpace(attrs.TypeCode))
  318. {
  319. var targetProp = SourceProps[attrs.TargetPropName];
  320. var MappingValues = dictService.Context.Queryable<SysDictType, SysDictData>((a, b) =>
  321. new JoinQueryInfos(JoinType.Inner, a.Id == b.DictTypeId))
  322. .Where(a => a.Code == attrs.TypeCode)
  323. .Where((a, b) => a.Status == StatusEnum.Enable && b.Status == StatusEnum.Enable)
  324. .Select((a, b) => new
  325. {
  326. Label = b.Value,
  327. Value = b.Code
  328. }).ToList()
  329. .ToDictionary(m => m.Value.ParseTo(targetProp.PropertyType), m => m.Label);
  330. PropMappings.Add(propertyInfo.Name, new Tuple<Dictionary<object,string>, PropertyInfo, PropertyInfo>(
  331. MappingValues, targetProp, propertyInfo
  332. ));
  333. }
  334. else
  335. {
  336. PropMappings.Add(propertyInfo.Name, new Tuple<Dictionary<object,string>, PropertyInfo, PropertyInfo>(
  337. null, SourceProps.ContainsKey(propertyInfo.Name) ? SourceProps[propertyInfo.Name] : null, propertyInfo
  338. ));
  339. }
  340. }
  341. return PropMappings;
  342. }
  343. /// <summary>
  344. /// 获取属性映射
  345. /// </summary>
  346. /// <typeparam name="TSource"></typeparam>
  347. /// <typeparam name="TTarget"></typeparam>
  348. /// <returns>整理导入对象的 属性名称, 字典数据,原属性信息,目标属性信息 </returns>
  349. private static Dictionary<string, Tuple<string, string>> GetExportDicttMap< TTarget>() where TTarget : new()
  350. {
  351. var dictService = App.GetService<SqlSugarRepository<SysDictData>>();
  352. //整理导入对象的 属性名称,目标属性名,字典Code
  353. Dictionary<string, Tuple<string, string>> PropMappings = new Dictionary<string, Tuple<string, string>>();
  354. var TTargetProps = typeof(TTarget).GetProperties();
  355. foreach (var propertyInfo in TTargetProps)
  356. {
  357. var attrs = propertyInfo.GetCustomAttribute<ImportDictAttribute>();
  358. if (attrs != null && !string.IsNullOrWhiteSpace(attrs.TypeCode))
  359. {
  360. PropMappings.Add(propertyInfo.Name, new Tuple<string, string>( attrs.TargetPropName,attrs.TypeCode ));
  361. }
  362. }
  363. return PropMappings;
  364. }
  365. }