ExportDataManager.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. using Avalonia.Controls;
  2. using Emgu.CV.Cuda;
  3. using fis.Helpers;
  4. using fis.Log;
  5. using fis.Managers;
  6. using fis.Managers.Interfaces;
  7. using fis.Utilities;
  8. using fis.Utilities.FFMPEG;
  9. using fis.Win.Dev.Managers.Interfaces;
  10. using fis.Win.Dev.Managers.Modules.Storage;
  11. using fis.Win.Dev.Managers.RPC;
  12. using Newtonsoft.Json;
  13. using NPOI.POIFS.Crypt.Dsig;
  14. using System;
  15. using System.Collections.Generic;
  16. using System.Diagnostics;
  17. using System.IO;
  18. using System.Linq;
  19. using System.Security.Policy;
  20. using System.Text;
  21. using System.Threading.Tasks;
  22. using WingInterfaceLibrary.DTO.Common;
  23. using WingInterfaceLibrary.ResearchEdition;
  24. using Avalonia.Controls;
  25. using Avalonia.Interactivity;
  26. using Avalonia;
  27. namespace fis.Win.Dev.Managers
  28. {
  29. internal class ExportDataManager : IExportDataManager
  30. {
  31. string currentDataId = "";
  32. bool _isCancel = false;
  33. internal ExportDataManager()
  34. {
  35. HttpHelper.OnDownloadProgressChanged += OnDowloadProgressChanged;
  36. HttpHelper.DownloadFinished += OnDownloadFinished;
  37. }
  38. private void OnDownloadFinished(object? sender, bool e)
  39. {
  40. var args = new List<string>() {
  41. "1.0",
  42. ((int)ExportStatus.Finished).ToString(),
  43. currentDataId,
  44. };
  45. UpdateProgress(args);
  46. }
  47. private void OnDowloadProgressChanged(object? sender, double e)
  48. {
  49. var progress = e / 100;
  50. var args = new List<string>() {
  51. progress.ToString(),
  52. ((int)ExportStatus.Downloading).ToString(),
  53. currentDataId,
  54. };
  55. UpdateProgress(args);
  56. }
  57. private void UpdateProgress(List<string> args)
  58. {
  59. if (AppManager.IsVStation)
  60. {
  61. BrowserManager.SlaveBrowser.ExecuteJS(TargetMethodName.UpdateExportProgess, args);
  62. }
  63. else
  64. {
  65. BrowserManager.MainBrowser.ExecuteJS(TargetMethodName.UpdateExportProgess, args);
  66. }
  67. }
  68. public async void ExportDatas(List<ExportDataInfo> exportDataInfos, string name, string path)
  69. {
  70. _isCancel = false;
  71. var targetPath = Path.Combine(path, name);
  72. if (!Directory.Exists(targetPath))
  73. {
  74. Directory.CreateDirectory(targetPath);
  75. }
  76. foreach (var data in exportDataInfos)
  77. {
  78. if (_isCancel)
  79. {
  80. return;
  81. }
  82. currentDataId = data.Id;
  83. var dataName = HttpHelper.RemoveInvalidFileNameChars(data.Name);
  84. var fileName = Path.Combine(targetPath, dataName);
  85. if (File.Exists(fileName))
  86. {
  87. File.Delete(fileName);
  88. }
  89. await HttpHelper.DownloadFile(data.Url, new FileInfo(fileName));
  90. if (data.Url.EndsWith("vid") || fileName.EndsWith("vid"))
  91. {
  92. var converter = new VideoFFmpegHelper(fileName);
  93. var pathDest = Path.Combine(targetPath, GetFileNameWithoutExt(data.Url));
  94. converter.ConvertVidToMpeg4(pathDest);
  95. converter.Dispose();
  96. File.Delete(fileName);
  97. }
  98. }
  99. }
  100. public async Task ExportDatasAsync(ProjectSampleDataExportResult projectInfo, string path, string imageType, string videoType)
  101. {
  102. _isCancel = false;
  103. ///如果未指定文件夹名称,则由用户选择
  104. if (string.IsNullOrEmpty(path))
  105. {
  106. var dialog = new OpenFolderDialog();
  107. dialog.Directory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
  108. Window window;
  109. if (AppManager.IsVStation)
  110. {
  111. var manager = AppManager.Get<ISecondaryWindowManager>();
  112. window = manager.SlaveWindow;
  113. }
  114. else
  115. {
  116. window = AppManager.MainWindow;
  117. }
  118. var result = await dialog.ShowAsync(window);
  119. if (result != null)
  120. {
  121. path = result;
  122. }
  123. else
  124. {
  125. _CancelExportDatas(projectInfo);
  126. return;
  127. }
  128. }
  129. try
  130. {
  131. ///根目录文件夹名称
  132. var rootPathName = projectInfo.Name + "数据导出_" + DateTime.Now.ToString("yyyy-MM-dd-HHmmss");
  133. rootPathName = HttpHelper.RemoveInvalidFileNameChars(rootPathName);
  134. var rootPath = Path.Combine(path, rootPathName);
  135. if (!Directory.Exists(rootPath))
  136. {
  137. Directory.CreateDirectory(rootPath);
  138. }
  139. var resourcesManager = AppManager.Get<IResourceManager>();
  140. var reportFileStream = resourcesManager.GetManifestResourceStream("fis.Win.Resources.labReport.report.html");
  141. if (reportFileStream != null)
  142. {
  143. // 使用文件流将数据写入文件
  144. using (FileStream fileStream = new FileStream(Path.Combine(rootPath, "数据汇总预览报告.html"), FileMode.Create, FileAccess.Write))
  145. {
  146. await reportFileStream.CopyToAsync(fileStream);
  147. }
  148. }
  149. var exportReportStructure = new ExportReportStructure();
  150. exportReportStructure.ReportTitle = projectInfo.Name + DateTime.Now.ToString("yyyy-MM-dd");
  151. List<SampleDataInfo> sampleDataInfos = new List<SampleDataInfo>();
  152. var excelUrl = projectInfo.ExportExcelUrl;
  153. if (!string.IsNullOrEmpty(excelUrl))
  154. {
  155. Uri uri = new Uri(excelUrl);
  156. string absolutePath = uri.AbsolutePath;
  157. int lastSlashIndex = absolutePath.LastIndexOf('/');
  158. string fileNameWithExtension = absolutePath.Substring(lastSlashIndex + 1);
  159. int lastDotIndex = fileNameWithExtension.LastIndexOf('.');
  160. // 去掉文件后缀
  161. string fileName = (lastDotIndex == -1) ? fileNameWithExtension : fileNameWithExtension.Substring(0, lastDotIndex);
  162. currentDataId = fileName;
  163. await HttpHelper.DownloadFile(excelUrl, new FileInfo(Path.Combine(rootPath, "测量结果.xlsx")));
  164. }
  165. IList<SampleDetailInfo> sampleDetailList = projectInfo.SampleDetailList;
  166. foreach (SampleDetailInfo sampleDetail in sampleDetailList)
  167. {
  168. var sampleDataInfo = new SampleDataInfo();
  169. List<ExamDataInfo> ExamDataInfos = new List<ExamDataInfo>();
  170. if (sampleDetail.SampleRemedicalBasicList.Count == 0)
  171. {
  172. continue;
  173. }
  174. List<DataItemDTO> patientInfos = sampleDetail.PatientInfo;
  175. string patientPath = "";
  176. string patientName = "";
  177. if (patientInfos.Any((e) => e.Key == "Name") || patientInfos.Any((e) => e.Key == "AnimalInfoName"))
  178. {
  179. patientName = patientInfos.FirstOrDefault((e) => e.Key == "Name" || e.Key == "AnimalInfoName")?.Value ?? "";
  180. patientName = Base64Decryptor.DecryptBase64(patientName);
  181. patientName = HttpHelper.RemoveInvalidFileNameChars(patientName);
  182. patientPath = Path.Combine(rootPath, patientName);
  183. if (!Directory.Exists(patientPath))
  184. {
  185. Directory.CreateDirectory(patientPath);
  186. }
  187. sampleDataInfo.Title = patientName;
  188. }
  189. if (string.IsNullOrEmpty(patientName))
  190. {
  191. DateTime startDate = new DateTime(1971, 1, 1, 0, 0, 0, DateTimeKind.Utc);
  192. DateTime currentDate = DateTime.UtcNow;
  193. TimeSpan timeSpan = currentDate - startDate;
  194. double totalMilliseconds = timeSpan.TotalMilliseconds;
  195. patientName = "未命名" + totalMilliseconds.ToString();
  196. sampleDataInfo.Title = patientName;
  197. }
  198. IList<SampleRemedicalBasicInfo> sampleRemedicalBasicList = sampleDetail.SampleRemedicalBasicList;
  199. List<ExamDataInfo> examDataInfos = new List<ExamDataInfo>();
  200. foreach (SampleRemedicalBasicInfo sampleRemedicalBasicInfo in sampleRemedicalBasicList)
  201. {
  202. var examDataInfo = new ExamDataInfo();
  203. string examDate = sampleRemedicalBasicInfo.RemedicalName;
  204. examDataInfo.Title = examDate;
  205. List<string> imagePathList = new List<string>();
  206. List<string> measureDataList = new List<string>();
  207. List<string> measureDataPathList = new List<string>();
  208. string patientScanTypePath = Path.Combine(patientPath, examDate);
  209. if (!Directory.Exists(patientScanTypePath))
  210. {
  211. Directory.CreateDirectory(patientScanTypePath);
  212. }
  213. IList<SampleRemedicalInfoDTO> sampleRemedicalInfoList = sampleRemedicalBasicInfo.SampleRemedicalInfoList;
  214. int index = 1;
  215. foreach (SampleRemedicalInfoDTO sampleRemedicalInfoDTO in sampleRemedicalInfoList)
  216. {
  217. string fileExtentName = ".jpg";
  218. bool isVid = false;
  219. var fileDataType = sampleRemedicalInfoDTO.FileDataType;
  220. if (sampleRemedicalInfoDTO.IsAnalysisResult)
  221. {
  222. fileExtentName = ".png";
  223. }
  224. else
  225. {
  226. switch (fileDataType)
  227. {
  228. case WingInterfaceLibrary.Enum.SampleRemedicalFileDataTypeEnum.VinnoVidSingle:
  229. case WingInterfaceLibrary.Enum.SampleRemedicalFileDataTypeEnum.ThirdVidMovie:
  230. case WingInterfaceLibrary.Enum.SampleRemedicalFileDataTypeEnum.ThirdVidSingle:
  231. case WingInterfaceLibrary.Enum.SampleRemedicalFileDataTypeEnum.VinnoVidMovie:
  232. isVid = true;
  233. fileExtentName = ".vid";
  234. break;
  235. case WingInterfaceLibrary.Enum.SampleRemedicalFileDataTypeEnum.Image:
  236. case WingInterfaceLibrary.Enum.SampleRemedicalFileDataTypeEnum.AnalysisImage:
  237. case WingInterfaceLibrary.Enum.SampleRemedicalFileDataTypeEnum.MeasurementImage:
  238. fileExtentName = ".jpg";
  239. break;
  240. case WingInterfaceLibrary.Enum.SampleRemedicalFileDataTypeEnum.AnalysisVideo:
  241. fileExtentName = ".mp4";
  242. break;
  243. }
  244. }
  245. string fileNameNoExtName = examDate + "_" + index.ToString();
  246. string fileName = fileNameNoExtName + fileExtentName;
  247. string filePath = Path.Combine(patientScanTypePath, fileName);
  248. currentDataId = sampleRemedicalInfoDTO.BusinessCode;
  249. var imageUrl = sampleRemedicalInfoDTO.ImageUrl;
  250. if (sampleRemedicalInfoDTO.IsAnalysisResult)
  251. {
  252. imageUrl = sampleRemedicalInfoDTO.CoverImgUrl;
  253. }
  254. await HttpHelper.DownloadFile(imageUrl, new FileInfo(filePath));
  255. string prePath = patientName + "/" + examDate + "/";
  256. if (isVid)
  257. {
  258. bool isSingle = true;
  259. var converter = new VideoFFmpegHelper(filePath);
  260. if (converter.ImageCount > 1)
  261. {
  262. isSingle = false;
  263. }
  264. var pathDest = Path.Combine(rootPath,patientScanTypePath, fileNameNoExtName);
  265. converter.ConvertVidToImage(pathDest, imageType, videoType);
  266. if (videoType == "1")
  267. {
  268. converter.ConvertVidToMpeg4(pathDest);
  269. }
  270. converter.Dispose();
  271. File.Delete(filePath);
  272. imagePathList.Add(prePath + fileNameNoExtName + (isSingle ? (imageType == "0" ? ".jpg" : ".png") : (videoType == "0" ? ".mp4" : ".avi")));
  273. }
  274. else
  275. {
  276. imagePathList.Add(prePath + fileName);
  277. }
  278. measureDataList.Add("");
  279. measureDataPathList.Add("");
  280. var sampleRemedicalMeasuredList = sampleRemedicalInfoDTO.SampleRemedicalMeasuredList;
  281. if (sampleRemedicalMeasuredList != null && sampleRemedicalMeasuredList.Count > 0)
  282. {
  283. int measureIndex = 0;
  284. foreach (SampleRemedicalMeasuredInfoDTO sampleRemedicalMeasuredInfoDTO in sampleRemedicalMeasuredList)
  285. {
  286. measureIndex++;
  287. string measureImageUrl = sampleRemedicalMeasuredInfoDTO.MeasuredFileToken;
  288. string measuredData = sampleRemedicalMeasuredInfoDTO.MeasuredData;
  289. ///测量结果图像
  290. if (!string.IsNullOrEmpty(measureImageUrl))
  291. {
  292. var measureName = fileNameNoExtName + "_测量图像_" + measureIndex.ToString() + ".jpg";
  293. string fileMeasureImagePath = Path.Combine(patientScanTypePath, measureName);
  294. await HttpHelper.DownloadFile(measureImageUrl, new FileInfo(fileMeasureImagePath));
  295. imagePathList.Add(prePath + measureName);
  296. }
  297. ///测量结果字符串
  298. if (!string.IsNullOrEmpty(measuredData))
  299. {
  300. var measureResultName = fileNameNoExtName + "_测量结果_" + measureIndex.ToString() + ".txt";
  301. string fileMeasureResultPath = Path.Combine(patientScanTypePath, measureResultName);
  302. File.WriteAllText(fileMeasureResultPath, measuredData);
  303. measureDataPathList.Add(prePath + measureResultName);
  304. measureDataList.Add(measuredData);
  305. }
  306. }
  307. }
  308. index++;
  309. }
  310. examDataInfo.MeasureDataList = measureDataList;
  311. examDataInfo.ImagePathList = imagePathList;
  312. examDataInfo.MeasureDataPathList = measureDataPathList;
  313. examDataInfos.Add(examDataInfo);
  314. }
  315. sampleDataInfo.ExamDataInfos = examDataInfos;
  316. sampleDataInfos.Add(sampleDataInfo);
  317. }
  318. exportReportStructure.SampleData = sampleDataInfos;
  319. var json = JsonConvert.SerializeObject(exportReportStructure);
  320. if (json != null)
  321. {
  322. var content = "const exportStructurejsonData = " + json;
  323. File.WriteAllText(Path.Combine(rootPath, "ReportDataStructure.js"), content);
  324. }
  325. }
  326. catch (Exception e)
  327. {
  328. Logger.WriteShellLog($"ExportDatasAsync ex:{e}");
  329. }
  330. }
  331. private void _CancelExportDatas(ProjectSampleDataExportResult projectInfo)
  332. {
  333. var excelUrl = projectInfo.ExportExcelUrl;
  334. if (!string.IsNullOrEmpty(excelUrl))
  335. {
  336. Uri uri = new Uri(excelUrl);
  337. string absolutePath = uri.AbsolutePath;
  338. int lastSlashIndex = absolutePath.LastIndexOf('/');
  339. string fileNameWithExtension = absolutePath.Substring(lastSlashIndex + 1);
  340. int lastDotIndex = fileNameWithExtension.LastIndexOf('.');
  341. // 去掉文件后缀
  342. string fileName = (lastDotIndex == -1) ? fileNameWithExtension : fileNameWithExtension.Substring(0, lastDotIndex);
  343. var args = new List<string>() {
  344. "1.0",
  345. ((int)ExportStatus.Cancelled).ToString(),
  346. fileName,
  347. };
  348. UpdateProgress(args);
  349. }
  350. IList<SampleDetailInfo> sampleDetailList = projectInfo.SampleDetailList;
  351. foreach (var sampleDetail in sampleDetailList)
  352. {
  353. IList<SampleRemedicalBasicInfo> sampleRemedicalBasicList = sampleDetail.SampleRemedicalBasicList;
  354. foreach (var sampleRemedicalBasicInfo in sampleRemedicalBasicList)
  355. {
  356. IList<SampleRemedicalInfoDTO> sampleRemedicalInfoList = sampleRemedicalBasicInfo.SampleRemedicalInfoList;
  357. foreach (SampleRemedicalInfoDTO sampleRemedicalInfoDTO in sampleRemedicalInfoList)
  358. {
  359. var currentDataId = sampleRemedicalInfoDTO.BusinessCode;
  360. var args = new List<string>() {
  361. "1.0",
  362. ((int)ExportStatus.Cancelled).ToString(),
  363. currentDataId,
  364. };
  365. UpdateProgress(args);
  366. }
  367. }
  368. }
  369. }
  370. public void CancelExport()
  371. {
  372. _isCancel = true;
  373. }
  374. private string GetFileNameWithoutExt(string fileToken)
  375. {
  376. string[] fragments = fileToken.Split('/');
  377. string lastFragment = fragments.Last();
  378. return lastFragment.Split('.')[0];
  379. }
  380. public void Dispose()
  381. {
  382. }
  383. }
  384. }