MainWindow.xaml.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. using Microsoft.Win32;
  2. using StationProbe;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Text.Encodings.Web;
  7. using System.Text.Json;
  8. using System.Text.Unicode;
  9. using System.Threading.Tasks;
  10. using System.Windows;
  11. using System.Windows.Controls;
  12. using System.Windows.Input;
  13. using System.Windows.Media;
  14. using System.Windows.Media.Imaging;
  15. namespace TestViewer
  16. {
  17. /// <summary>
  18. /// Interaction logic for MainWindow.xaml
  19. /// </summary>
  20. public partial class MainWindow
  21. {
  22. private readonly Database? _db;
  23. private DateTime _startDate = new(2023, 1, 1);
  24. private DateTime _endDate = DateTime.Now;
  25. private int _pageIndex = -1;
  26. private int _pageCount;
  27. private string _partKey = string.Empty;
  28. private string _conclusionKey = string.Empty;
  29. public MainWindow()
  30. {
  31. InitializeComponent();
  32. CreateStart.SelectedDate = _startDate;
  33. CreateStart.DisplayDate = _startDate;
  34. CreateEnd.SelectedDate = _endDate;
  35. CreateEnd.DisplayDate = _endDate;
  36. CreateStart.SelectedDateChanged += (_, _) => { _startDate = CreateStart.SelectedDate.Value.Date; };
  37. CreateEnd.SelectedDateChanged += (_, _) => { _endDate = CreateEnd.SelectedDate.Value.Date.AddDays(1); };
  38. Loading.LoadingChanged += OnLoadingChanged;
  39. var fileDialog = new OpenFileDialog
  40. {
  41. Title = "Open database file",
  42. Filter = "*.db|*.db"
  43. };
  44. if (fileDialog.ShowDialog() == true)
  45. {
  46. _db = new Database(fileDialog.FileName);
  47. PageIndex.Text = $"{_pageIndex + 1}/{_pageCount}";
  48. var batchTasks = _db.GetBatchTasks();
  49. foreach (var task in batchTasks)
  50. {
  51. BatchTaskList.Items.Add(task);
  52. }
  53. BatchTaskList.SelectionChanged += OnBatchTaskSelectionChanged;
  54. ExamList.SelectionChanged += OnExamSelectionChanged;
  55. }
  56. else
  57. {
  58. Application.Current.Shutdown(0);
  59. }
  60. }
  61. private void OnLoadingChanged(object? sender, bool e)
  62. {
  63. if (e)
  64. {
  65. Dispatcher.Invoke(() => { LoadingMask.Visibility = Visibility.Visible; });
  66. }
  67. else
  68. {
  69. Dispatcher.Invoke(() => { LoadingMask.Visibility = Visibility.Collapsed; });
  70. }
  71. }
  72. private void OnBatchTaskSelectionChanged(object sender, SelectionChangedEventArgs e)
  73. {
  74. if (BatchTaskList.SelectedValue is BatchTask batchTask)
  75. {
  76. Loading.Run(() =>
  77. {
  78. _pageIndex = 0;
  79. _pageCount = _db!.GetPageCount(batchTask.Id, _partKey, _conclusionKey,_startDate, _endDate);
  80. var exams = _db.GetExams(batchTask.Id, _pageIndex, _partKey, _conclusionKey, _startDate, _endDate);
  81. Dispatcher.Invoke(() =>
  82. {
  83. foreach (var exam in exams)
  84. {
  85. ExamList.Items.Add(exam);
  86. }
  87. PageIndex.Text = $"{_pageIndex + 1}/{_pageCount}";
  88. });
  89. });
  90. }
  91. }
  92. private void OnExamSelectionChanged(object sender, SelectionChangedEventArgs e)
  93. {
  94. ExamScrollView.ScrollToHome();
  95. ExamContent.Children.Clear();
  96. if (ExamList.SelectedValue is Exam exam)
  97. {
  98. Dictionary<string, string>? reportContent;
  99. try
  100. {
  101. reportContent = JsonSerializer.Deserialize<Dictionary<string, string>>(exam.Report);
  102. }
  103. catch
  104. {
  105. reportContent = null;
  106. }
  107. if (reportContent != null)
  108. {
  109. var partStackPanel = new StackPanel() { Margin = new Thickness(16), Orientation = Orientation.Horizontal };
  110. partStackPanel.Children.Add(new TextBlock()
  111. {
  112. VerticalAlignment = VerticalAlignment.Center,
  113. Text = "部位: ",
  114. FontWeight = FontWeights.Bold,
  115. FontSize = 16,
  116. });
  117. partStackPanel.Children.Add(new TextBlock()
  118. {
  119. VerticalAlignment = VerticalAlignment.Center,
  120. Text = $"{reportContent["Part"]}",
  121. FontSize = 16,
  122. });
  123. ExamContent.Children.Add(partStackPanel);
  124. var deviceStackPanel = new StackPanel() { Margin = new Thickness(16), Orientation = Orientation.Horizontal };
  125. deviceStackPanel.Children.Add(new TextBlock()
  126. {
  127. VerticalAlignment = VerticalAlignment.Center,
  128. Text = "设备: ",
  129. FontWeight = FontWeights.Bold,
  130. FontSize = 16,
  131. });
  132. deviceStackPanel.Children.Add(new TextBlock()
  133. {
  134. VerticalAlignment = VerticalAlignment.Center,
  135. Text = $"{reportContent["Device"]}",
  136. FontSize = 16,
  137. });
  138. ExamContent.Children.Add(deviceStackPanel);
  139. var conclusionStackPanel = new StackPanel() { Margin = new Thickness(16), Orientation = Orientation.Horizontal };
  140. conclusionStackPanel.Children.Add(new TextBlock()
  141. {
  142. VerticalAlignment = VerticalAlignment.Center,
  143. Text = "结论: ",
  144. FontWeight = FontWeights.Bold,
  145. FontSize = 16,
  146. });
  147. var conclusion = "无结论";
  148. if (!string.IsNullOrEmpty(reportContent["Conclusion"]))
  149. {
  150. conclusion = reportContent["Conclusion"];
  151. }
  152. conclusionStackPanel.Children.Add(new TextBlock()
  153. {
  154. VerticalAlignment = VerticalAlignment.Center,
  155. Text = conclusion,
  156. FontSize = 16,
  157. });
  158. ExamContent.Children.Add(conclusionStackPanel);
  159. ExamContent.Children.Add(new Border() { Height = 1, Width = 2000, BorderBrush = Brushes.Gray, Background = Brushes.Gray });
  160. ExamContent.Children.Add(new TextBlock()
  161. {
  162. Width = 2000,
  163. Margin = new Thickness(16, 16, 16, 8),
  164. Text = "超声所见:",
  165. FontSize = 16,
  166. FontWeight = FontWeights.Bold,
  167. });
  168. ExamContent.Children.Add(new TextBlock()
  169. {
  170. Margin = new Thickness(16, 8, 16, 16),
  171. Text = reportContent["Summary"].Replace(@"\n", Environment.NewLine),
  172. FontSize = 16,
  173. TextWrapping = TextWrapping.Wrap,
  174. });
  175. ExamContent.Children.Add(new TextBlock()
  176. {
  177. Width = 2000,
  178. Margin = new Thickness(16, 16, 16, 8),
  179. Text = "超声提示:",
  180. FontSize = 16,
  181. FontWeight = FontWeights.Bold,
  182. });
  183. ExamContent.Children.Add(new TextBlock()
  184. {
  185. Margin = new Thickness(16, 8, 16, 16),
  186. Text = reportContent["Comment"].Replace(@"\n", Environment.NewLine),
  187. FontSize = 16,
  188. TextWrapping = TextWrapping.Wrap,
  189. });
  190. }
  191. else
  192. {
  193. ExamContent.Children.Add(new TextBlock()
  194. {
  195. Margin = new Thickness(16),
  196. Text = exam.Report,
  197. FontSize = 20,
  198. TextWrapping = TextWrapping.Wrap,
  199. });
  200. }
  201. ExamContent.Children.Add(new Border() { Height = 1, Width = 2000, BorderBrush = Brushes.Gray, Background = Brushes.Gray });
  202. var images = _db!.GetImages(exam.Id);
  203. foreach (var image in images)
  204. {
  205. var img = new BitmapImage();
  206. img.BeginInit();
  207. img.StreamSource = new MemoryStream(image.Data);
  208. img.EndInit();
  209. var imageBorder = new Border
  210. {
  211. Margin = new Thickness(16),
  212. Width = 200,
  213. Height = 200,
  214. Background = Brushes.Black,
  215. Child = new System.Windows.Controls.Image()
  216. {
  217. Source = img
  218. },
  219. Cursor = Cursors.Hand
  220. };
  221. imageBorder.MouseDown += (_, _) =>
  222. {
  223. var viewImageWindow = new Window
  224. {
  225. Owner = this,
  226. Background = Brushes.Black,
  227. WindowStartupLocation = WindowStartupLocation.CenterOwner
  228. };
  229. var width = img.Width + 16;
  230. var height = img.Height + 16;
  231. if (width >= SystemParameters.PrimaryScreenWidth || height >= SystemParameters.PrimaryScreenHeight)
  232. {
  233. viewImageWindow.WindowState = WindowState.Maximized;
  234. }
  235. else
  236. {
  237. viewImageWindow.Width = width;
  238. viewImageWindow.Height = height;
  239. }
  240. viewImageWindow.Content = new System.Windows.Controls.Image()
  241. {
  242. Source = img
  243. };
  244. viewImageWindow.ShowDialog();
  245. };
  246. ExamContent.Children.Add(imageBorder);
  247. }
  248. }
  249. }
  250. private void OnNextPageClick(object sender, RoutedEventArgs e)
  251. {
  252. if (_pageIndex < _pageCount - 1)
  253. {
  254. if (BatchTaskList.SelectedValue is BatchTask batchTask)
  255. {
  256. ExamList.Items.Clear();
  257. _pageIndex++;
  258. Loading.Run(() =>
  259. {
  260. var exams = _db!.GetExams(batchTask.Id, _pageIndex, _partKey, _conclusionKey,_startDate, _endDate);
  261. Dispatcher.Invoke(() =>
  262. {
  263. foreach (var exam in exams)
  264. {
  265. ExamList.Items.Add(exam);
  266. }
  267. PageIndex.Text = $"{_pageIndex + 1}/{_pageCount}";
  268. });
  269. });
  270. }
  271. }
  272. }
  273. private void OnPreviousPageClick(object sender, RoutedEventArgs e)
  274. {
  275. if (_pageIndex > 0)
  276. {
  277. if (BatchTaskList.SelectedValue is BatchTask batchTask)
  278. {
  279. ExamList.Items.Clear();
  280. _pageIndex--;
  281. Loading.Run(() =>
  282. {
  283. var exams = _db!.GetExams(batchTask.Id, _pageIndex, _partKey, _conclusionKey, _startDate, _endDate);
  284. Dispatcher.Invoke(() =>
  285. {
  286. foreach (var exam in exams)
  287. {
  288. ExamList.Items.Add(exam);
  289. }
  290. PageIndex.Text = $"{_pageIndex + 1}/{_pageCount}";
  291. });
  292. });
  293. }
  294. }
  295. }
  296. private void OnSearchClick(object sender, RoutedEventArgs e)
  297. {
  298. _partKey = PartKey.Text;
  299. _conclusionKey = ConclusionKey.Text;
  300. if (BatchTaskList.SelectedValue is BatchTask batchTask)
  301. {
  302. ExamList.Items.Clear();
  303. Exam[]? exams;
  304. Loading.Run(() =>
  305. {
  306. _pageCount = _db!.GetPageCount(batchTask.Id, _partKey, _conclusionKey, _startDate, _endDate);
  307. _pageIndex = 0;
  308. exams = _db.GetExams(batchTask.Id, _pageIndex, _partKey, _conclusionKey,_startDate, _endDate);
  309. Dispatcher.Invoke(() =>
  310. {
  311. foreach (var exam in exams)
  312. {
  313. ExamList.Items.Add(exam);
  314. }
  315. PageIndex.Text = $"{_pageIndex + 1}/{_pageCount}";
  316. });
  317. });
  318. }
  319. }
  320. private void OnExportClick(object sender, RoutedEventArgs e)
  321. {
  322. var partKey = PartKey.Text;
  323. var conclusionKey = ConclusionKey.Text;
  324. if (BatchTaskList.SelectedValue is BatchTask batchTask)
  325. {
  326. FolderBrowserEx.FolderBrowserDialog dialog = new FolderBrowserEx.FolderBrowserDialog();
  327. var result = dialog.ShowDialog();
  328. if (result == System.Windows.Forms.DialogResult.OK)
  329. {
  330. var targetFolder = dialog.SelectedFolder;
  331. var imageFolder = Path.Combine(targetFolder, "images");
  332. if (!Directory.Exists(imageFolder))
  333. {
  334. Directory.CreateDirectory(imageFolder);
  335. }
  336. var reportFolder = Path.Combine(targetFolder, "reports");
  337. if (!Directory.Exists(reportFolder))
  338. {
  339. Directory.CreateDirectory(reportFolder);
  340. }
  341. var progressWindow = new Window
  342. {
  343. Title = "导出中...",
  344. WindowStartupLocation = WindowStartupLocation.CenterOwner,
  345. WindowStyle = WindowStyle.ToolWindow,
  346. ResizeMode = ResizeMode.NoResize,
  347. Width = 320,
  348. Height = 80,
  349. Owner = this
  350. };
  351. var canClose = false;
  352. progressWindow.Closing += (_, arg) => { arg.Cancel = !canClose; };
  353. var progressBar = new ProgressBar
  354. {
  355. Minimum = 0,
  356. Maximum = 100,
  357. Value = 0
  358. };
  359. progressWindow.Content = progressBar;
  360. Task.Run(() =>
  361. {
  362. JsonSerializerOptions opts = new JsonSerializerOptions
  363. {
  364. WriteIndented = true,
  365. Encoder = JavaScriptEncoder.Create(UnicodeRanges.All)
  366. };
  367. var pageCount = _db!.GetPageCount(batchTask.Id, partKey, conclusionKey,_startDate, _endDate);
  368. if (pageCount > 0)
  369. {
  370. for (int i = 0; i < pageCount; i++)
  371. {
  372. var exams = _db.GetExams(batchTask.Id, i, partKey, conclusionKey,_startDate, _endDate);
  373. foreach (var exam in exams)
  374. {
  375. var images = _db.GetImages(exam.Id);
  376. foreach (var image in images)
  377. {
  378. var fileName = Path.Combine(imageFolder, $"{exam.Id}_{image.Id}.jpg");
  379. File.WriteAllBytes(fileName, image.Data);
  380. }
  381. var reportDic = new Dictionary<string, object>
  382. {
  383. { "PatientName", exam.PatientName },
  384. { "PatientSex", exam.PatientSex },
  385. { "PatientAge", exam.PatientAge },
  386. { "ExamDate", exam.ExamDate }
  387. };
  388. Dictionary<string, string>? reportContent;
  389. try
  390. {
  391. reportContent = JsonSerializer.Deserialize<Dictionary<string, string>>(exam.Report);
  392. }
  393. catch
  394. {
  395. reportContent = null;
  396. }
  397. if (reportContent != null)
  398. {
  399. reportDic.Add("Report", reportContent);
  400. }
  401. else
  402. {
  403. reportDic.Add("Report", exam.Report);
  404. }
  405. var reportFile = Path.Combine(reportFolder, $"{exam.Id}.txt");
  406. File.WriteAllText(reportFile, JsonSerializer.Serialize(reportDic, opts));
  407. }
  408. var progress = (i + 1) / (double)pageCount * 100;
  409. Dispatcher.Invoke(() =>
  410. {
  411. progressWindow.Title = $"导出中...{(int)progress}%";
  412. progressBar.Value = progress;
  413. });
  414. }
  415. canClose = true;
  416. Dispatcher.Invoke(progressWindow.Close);
  417. }
  418. });
  419. progressWindow.ShowDialog();
  420. }
  421. }
  422. }
  423. }
  424. }