平安校园
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

205 lines
7.7 KiB

  1. //
  2. namespace SafeCampus.System;
  3. /// <summary>
  4. /// <inheritdoc cref="IImportExportService"/>
  5. /// </summary>
  6. public class ImportExportService : IImportExportService
  7. {
  8. #region 导入
  9. /// <inheritdoc/>
  10. public void ImportVerification(IFormFile file, int maxSize = 30, string[] allowTypes = null)
  11. {
  12. if (file == null) throw Oops.Bah("文件不能为空");
  13. if (file.Length > maxSize * 1024 * 1024) throw Oops.Bah($"文件大小不允许超过{maxSize}M");
  14. var fileSuffix = Path.GetExtension(file.FileName).ToLower().Split(".")[1];// 文件后缀
  15. var allowTypeS = allowTypes == null ? new[] { "xlsx" } : allowTypes;//允许上传的文件类型
  16. if (!allowTypeS.Contains(fileSuffix)) throw Oops.Bah(errorMessage: "文件格式错误");
  17. }
  18. /// <inheritdoc/>
  19. public ImportPreviewOutput<T> TemplateDataVerification<T>(ImportResult<T> importResult) where T : ImportTemplateInput
  20. {
  21. if (importResult.Exception != null) throw Oops.Bah("导入异常,请检查文件格式!");
  22. ////遍历模板错误
  23. importResult.TemplateErrors.ForEach(error =>
  24. {
  25. if (error.Message.Contains("not found")) throw Oops.Bah($"列[{error.RequireColumnName}]未找到");
  26. throw Oops.Bah($"列[{error.RequireColumnName}]:{error.Message}");
  27. });
  28. if (importResult.Data == null)
  29. throw Oops.Bah("文件数据格式有误,请重新导入!");
  30. //导入结果输出
  31. var importPreview = new ImportPreviewOutput<T> { HasError = importResult.HasError };
  32. var headerMap = new Dictionary<string, string>();
  33. //遍历导入的表头列表信息
  34. importResult.ImporterHeaderInfos.ForEach(it =>
  35. {
  36. headerMap.Add(it.Header.Name, it.PropertyName);
  37. var tableColumns = new TableColumns
  38. { Title = it.Header.Name.Split("(")[0], DataIndex = it.PropertyName.FirstCharToLower() };//定义表头,部分表头有说明用(分组去掉说明
  39. var antTableAttribute = it.PropertyInfo.GetCustomAttribute<AntTableAttribute>();//获取表格特性
  40. if (antTableAttribute != null)
  41. {
  42. tableColumns.Date = antTableAttribute.IsDate;
  43. tableColumns.Ellipsis = antTableAttribute.Ellipsis;
  44. tableColumns.Width = antTableAttribute.Width;
  45. }
  46. importPreview.TableColumns.Add(tableColumns);//添加到表头
  47. });
  48. //导入的数据转集合
  49. var data = importResult.Data.ToList();
  50. var systemError = new string[] { };//系统错误提示
  51. //遍历错误列,将错误字典中的中文改成英文跟实体对应
  52. importResult.RowErrors.ForEach(row =>
  53. {
  54. IDictionary<string, string> fieldErrors = new Dictionary<string, string>();//定义字典
  55. //遍历错误列,赋值给新的字典
  56. row.FieldErrors.ForEach(it =>
  57. {
  58. var errrVaule = it.Value;
  59. //value xx Invalid, please fill in the correct integer value!
  60. //value xx Invalid, please fill in the correct date and time format!
  61. if (it.Value.Contains("Invalid"))//如果错误信息有Invalid就提示格式错误
  62. errrVaule = $"{it.Key}格式错误";
  63. fieldErrors.Add(headerMap[it.Key], errrVaule);
  64. });
  65. row.FieldErrors = fieldErrors;//替换新的字典
  66. row.RowIndex -= 2;//下表与列表中的下标一致
  67. data[row.RowIndex].HasError = true;//错误的行HasError = true
  68. data[row.RowIndex].ErrorInfo = fieldErrors;//替换新的字典
  69. });
  70. data = data.OrderByDescending(it => it.HasError).ToList();//排序
  71. importPreview.Data = data;//重新赋值data
  72. return importPreview;
  73. }
  74. /// <inheritdoc/>
  75. public async Task<FileStreamResult> GenerateTemplate<T>(string fileName) where T : class, new()
  76. {
  77. IImporter importer = new ExcelImporter();
  78. var byteArray = await importer.GenerateTemplateBytes<T>();
  79. var result = GetFileStreamResult(byteArray, fileName);
  80. return result;
  81. }
  82. /// <inheritdoc/>
  83. public FileStreamResult GenerateLocalTemplate(string fileName, string templateFolder = "Template")
  84. {
  85. var folder = App.WebHostEnvironment.WebRootPath.CombinePath(templateFolder);
  86. return GetFileStreamResult(folder, fileName, true);
  87. }
  88. /// <inheritdoc/>
  89. public async Task<ImportPreviewOutput<T>> GetImportPreview<T>(IFormFile file) where T : ImportTemplateInput, new()
  90. {
  91. ImportVerification(file);//验证文件
  92. IImporter importer = new ExcelImporter();
  93. using var fileStream = file.OpenReadStream();//获取文件流
  94. var import = await importer.Import<T>(fileStream);//导入的文件转化为带入结果
  95. var importPreview = TemplateDataVerification(import);//验证数据完整度
  96. return importPreview;
  97. }
  98. /// <inheritdoc/>
  99. public ImportResultOutPut<T> GetImportResultPreview<T>(List<T> data, out List<T> importData) where T : ImportTemplateInput
  100. {
  101. //定义结果
  102. var result = new ImportResultOutPut<T> { Total = data.Count };
  103. //可以导入的数据
  104. importData = data.Where(it => it.HasError == false).ToList();
  105. //如果有错误
  106. if (importData.Count != data.Count)
  107. {
  108. result.Success = false;
  109. result.Data = data.Where(it => it.HasError).ToList();
  110. result.FailCount = data.Count - importData.Count;
  111. }
  112. result.ImportCount = importData.Count;
  113. return result;
  114. }
  115. #endregion 导入
  116. #region 导出
  117. public async Task<FileStreamResult> Export<T>(List<T> data, string fileName) where T : class, new()
  118. {
  119. IExporter exporter = new ExcelExporter();
  120. var byteArray = await exporter.ExportAsByteArray(data);
  121. var result = GetFileStreamResult(byteArray, fileName);
  122. return result;
  123. }
  124. #endregion 导出
  125. #region 方法
  126. /// <summary>
  127. /// 获取文件流
  128. /// </summary>
  129. /// <param name="path"></param>
  130. /// <param name="fileName"></param>
  131. /// <param name="isPathFolder"></param>
  132. /// <returns></returns>
  133. public FileStreamResult GetFileStreamResult(string path, string fileName, bool isPathFolder = false)
  134. {
  135. fileName = GetFileName(fileName);
  136. if (isPathFolder) path = path.CombinePath(fileName);
  137. //文件转流
  138. var result = new FileStreamResult(new FileStream(path, FileMode.Open), "application/octet-stream") { FileDownloadName = fileName };
  139. return result;
  140. }
  141. /// <summary>
  142. /// 获取文件流
  143. /// </summary>
  144. /// <param name="byteArray"></param>
  145. /// <param name="fileName"></param>
  146. /// <returns></returns>
  147. public FileStreamResult GetFileStreamResult(byte[] byteArray, string fileName)
  148. {
  149. fileName = GetFileName(fileName);
  150. //文件转流
  151. var result = new FileStreamResult(new MemoryStream(byteArray), "application/octet-stream") { FileDownloadName = fileName };
  152. return result;
  153. }
  154. /// <summary>
  155. /// 获取文件名
  156. /// </summary>
  157. /// <param name="fileName"></param>
  158. /// <returns></returns>
  159. public string GetFileName(string fileName)
  160. {
  161. if (!fileName.Contains("."))
  162. fileName = fileName + ".xlsx";
  163. fileName = HttpUtility.UrlEncode(fileName, Encoding.GetEncoding("UTF-8"));//文件名转utf8不然前端下载会乱码
  164. return fileName;
  165. }
  166. /// <summary>
  167. /// 获取本地模板路径
  168. /// </summary>
  169. /// <returns></returns>
  170. public string GetTemplateFolder()
  171. {
  172. var folder = App.WebHostEnvironment.WebRootPath.CombinePath("Template");
  173. return folder;
  174. }
  175. #endregion 方法
  176. }