|
@@ -1,9 +1,19 @@
|
|
|
using Microsoft.Win32;
|
|
|
using StationProbe;
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
using System.IO;
|
|
|
+using System.Text.Encodings.Web;
|
|
|
+using System.Text.Json;
|
|
|
+using System.Text.Unicode;
|
|
|
+using System.Threading;
|
|
|
+using System.Threading.Tasks;
|
|
|
using System.Windows;
|
|
|
using System.Windows.Controls;
|
|
|
+using System.Windows.Input;
|
|
|
+using System.Windows.Media;
|
|
|
using System.Windows.Media.Imaging;
|
|
|
+using System.Windows.Threading;
|
|
|
|
|
|
namespace TestViewer
|
|
|
{
|
|
@@ -15,14 +25,17 @@ namespace TestViewer
|
|
|
private readonly Database _db;
|
|
|
private int _pageIndex = -1;
|
|
|
private int _pageCount = 0;
|
|
|
+ private string _partKey = string.Empty;
|
|
|
+ private string _conclusionKey = string.Empty;
|
|
|
|
|
|
public MainWindow()
|
|
|
{
|
|
|
InitializeComponent();
|
|
|
+ Loading.LoadingChanged += OnLoadingChanged;
|
|
|
var fileDialog = new OpenFileDialog();
|
|
|
fileDialog.Title = "Open database file";
|
|
|
fileDialog.Filter = "*.db|*.db";
|
|
|
- if(fileDialog.ShowDialog() == true)
|
|
|
+ if (fileDialog.ShowDialog() == true)
|
|
|
{
|
|
|
_db = new Database(fileDialog.FileName);
|
|
|
PageIndex.Text = $"{_pageIndex + 1}/{_pageCount}";
|
|
@@ -37,7 +50,19 @@ namespace TestViewer
|
|
|
else
|
|
|
{
|
|
|
Application.Current.Shutdown(0);
|
|
|
- }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void OnLoadingChanged(object? sender, bool e)
|
|
|
+ {
|
|
|
+ if (e)
|
|
|
+ {
|
|
|
+ Dispatcher.Invoke(() => { LoadingMask.Visibility = Visibility.Visible; });
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Dispatcher.Invoke(() => { LoadingMask.Visibility = Visibility.Collapsed; });
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
private void OnBatchTaskSelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
@@ -45,18 +70,20 @@ namespace TestViewer
|
|
|
var batchTask = BatchTaskList.SelectedValue as BatchTask;
|
|
|
if (batchTask != null)
|
|
|
{
|
|
|
- var lastExam = _db.GetLastExam(batchTask.Id);
|
|
|
- if (lastExam != null)
|
|
|
+ Loading.Run(() =>
|
|
|
{
|
|
|
_pageIndex = 0;
|
|
|
- _pageCount = lastExam.PageIndex + 1;
|
|
|
- var exams = _db.GetExams(batchTask.Id, _pageIndex);
|
|
|
- foreach (var exam in exams)
|
|
|
+ _pageCount = _db.GetPageCount(batchTask.Id, _partKey, _conclusionKey);
|
|
|
+ var exams = _db.GetExams(batchTask.Id, _pageIndex, _partKey, _conclusionKey);
|
|
|
+ Dispatcher.Invoke(() =>
|
|
|
{
|
|
|
- ExamList.Items.Add(exam);
|
|
|
- }
|
|
|
- PageIndex.Text = $"{_pageIndex + 1}/{_pageCount}";
|
|
|
- }
|
|
|
+ foreach (var exam in exams)
|
|
|
+ {
|
|
|
+ ExamList.Items.Add(exam);
|
|
|
+ }
|
|
|
+ PageIndex.Text = $"{_pageIndex + 1}/{_pageCount}";
|
|
|
+ });
|
|
|
+ });
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -69,13 +96,117 @@ namespace TestViewer
|
|
|
var exam = ExamList.SelectedValue as Exam;
|
|
|
if (exam != null)
|
|
|
{
|
|
|
- ExamContent.Children.Add(new TextBlock()
|
|
|
+ Dictionary<string, string>? reportContent = null;
|
|
|
+ try
|
|
|
{
|
|
|
- Margin = new Thickness(16),
|
|
|
- Text = exam.Report,
|
|
|
- FontSize = 20,
|
|
|
- TextWrapping = TextWrapping.Wrap
|
|
|
- });
|
|
|
+ reportContent = JsonSerializer.Deserialize<Dictionary<string, string>>(exam.Report);
|
|
|
+ }
|
|
|
+ catch
|
|
|
+ {
|
|
|
+ reportContent = null;
|
|
|
+ }
|
|
|
+ if (reportContent != null)
|
|
|
+ {
|
|
|
+ var partStackPanel = new StackPanel() { Margin = new Thickness(16), Orientation = Orientation.Horizontal };
|
|
|
+ partStackPanel.Children.Add(new TextBlock()
|
|
|
+ {
|
|
|
+ VerticalAlignment = VerticalAlignment.Center,
|
|
|
+ Text = "部位: ",
|
|
|
+ FontWeight = FontWeights.Bold,
|
|
|
+ FontSize = 16,
|
|
|
+ });
|
|
|
+ partStackPanel.Children.Add(new TextBlock()
|
|
|
+ {
|
|
|
+ VerticalAlignment = VerticalAlignment.Center,
|
|
|
+ Text = $"{reportContent["Part"]}",
|
|
|
+ FontSize = 16,
|
|
|
+ });
|
|
|
+ ExamContent.Children.Add(partStackPanel);
|
|
|
+
|
|
|
+ var deviceStackPanel = new StackPanel() { Margin = new Thickness(16), Orientation = Orientation.Horizontal };
|
|
|
+ deviceStackPanel.Children.Add(new TextBlock()
|
|
|
+ {
|
|
|
+ VerticalAlignment = VerticalAlignment.Center,
|
|
|
+ Text = "设备: ",
|
|
|
+ FontWeight = FontWeights.Bold,
|
|
|
+ FontSize = 16,
|
|
|
+ });
|
|
|
+ deviceStackPanel.Children.Add(new TextBlock()
|
|
|
+ {
|
|
|
+ VerticalAlignment = VerticalAlignment.Center,
|
|
|
+ Text = $"{reportContent["Device"]}",
|
|
|
+ FontSize = 16,
|
|
|
+ });
|
|
|
+ ExamContent.Children.Add(deviceStackPanel);
|
|
|
+
|
|
|
+ var conclusionStackPanel = new StackPanel() { Margin = new Thickness(16), Orientation = Orientation.Horizontal };
|
|
|
+ conclusionStackPanel.Children.Add(new TextBlock()
|
|
|
+ {
|
|
|
+ VerticalAlignment = VerticalAlignment.Center,
|
|
|
+ Text = "结论: ",
|
|
|
+ FontWeight = FontWeights.Bold,
|
|
|
+ FontSize = 16,
|
|
|
+ });
|
|
|
+ var conclusion = "无结论";
|
|
|
+ if (!string.IsNullOrEmpty(reportContent["Conclusion"]))
|
|
|
+ {
|
|
|
+ conclusion = reportContent["Conclusion"];
|
|
|
+ }
|
|
|
+ conclusionStackPanel.Children.Add(new TextBlock()
|
|
|
+ {
|
|
|
+ VerticalAlignment = VerticalAlignment.Center,
|
|
|
+ Text = conclusion,
|
|
|
+ FontSize = 16,
|
|
|
+ });
|
|
|
+ ExamContent.Children.Add(conclusionStackPanel);
|
|
|
+
|
|
|
+ ExamContent.Children.Add(new Border() { Height = 1, Width = 2000, BorderBrush = Brushes.Gray, Background = Brushes.Gray });
|
|
|
+
|
|
|
+ ExamContent.Children.Add(new TextBlock()
|
|
|
+ {
|
|
|
+ Width = 2000,
|
|
|
+ Margin = new Thickness(16, 16, 16, 8),
|
|
|
+ Text = $"超声所见:",
|
|
|
+ FontSize = 16,
|
|
|
+ FontWeight = FontWeights.Bold,
|
|
|
+ });
|
|
|
+
|
|
|
+ ExamContent.Children.Add(new TextBlock()
|
|
|
+ {
|
|
|
+ Margin = new Thickness(16, 8, 16, 16),
|
|
|
+ Text = reportContent["Summary"].Replace(@"\n", Environment.NewLine),
|
|
|
+ FontSize = 16,
|
|
|
+ TextWrapping = TextWrapping.Wrap,
|
|
|
+ });
|
|
|
+
|
|
|
+ ExamContent.Children.Add(new TextBlock()
|
|
|
+ {
|
|
|
+ Width = 2000,
|
|
|
+ Margin = new Thickness(16, 16, 16, 8),
|
|
|
+ Text = $"超声提示:",
|
|
|
+ FontSize = 16,
|
|
|
+ FontWeight = FontWeights.Bold,
|
|
|
+ });
|
|
|
+
|
|
|
+ ExamContent.Children.Add(new TextBlock()
|
|
|
+ {
|
|
|
+ Margin = new Thickness(16, 8, 16, 16),
|
|
|
+ Text = reportContent["Comment"].Replace(@"\n", Environment.NewLine),
|
|
|
+ FontSize = 16,
|
|
|
+ TextWrapping = TextWrapping.Wrap,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ ExamContent.Children.Add(new TextBlock()
|
|
|
+ {
|
|
|
+ Margin = new Thickness(16),
|
|
|
+ Text = exam.Report,
|
|
|
+ FontSize = 20,
|
|
|
+ TextWrapping = TextWrapping.Wrap,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ ExamContent.Children.Add(new Border() { Height = 1, Width = 2000, BorderBrush = Brushes.Gray, Background = Brushes.Gray });
|
|
|
var images = _db.GetImages(exam.Id);
|
|
|
foreach (var image in images)
|
|
|
{
|
|
@@ -83,12 +214,45 @@ namespace TestViewer
|
|
|
img.BeginInit();
|
|
|
img.StreamSource = new MemoryStream(image.Data);
|
|
|
img.EndInit();
|
|
|
- ExamContent.Children.Add(new System.Windows.Controls.Image()
|
|
|
- {
|
|
|
- Stretch = System.Windows.Media.Stretch.Uniform,
|
|
|
+ var imageBorder = new Border()
|
|
|
+ {
|
|
|
Margin = new Thickness(16),
|
|
|
- Source = img
|
|
|
- });
|
|
|
+ Width = 200,
|
|
|
+ Height = 200,
|
|
|
+ Background = Brushes.Black,
|
|
|
+ Child = new System.Windows.Controls.Image()
|
|
|
+ {
|
|
|
+ Source = img
|
|
|
+ },
|
|
|
+ Cursor = Cursors.Hand
|
|
|
+
|
|
|
+ };
|
|
|
+ imageBorder.MouseDown += (sender, e) =>
|
|
|
+ {
|
|
|
+ var viewImageWindow = new Window
|
|
|
+ {
|
|
|
+ Owner = this,
|
|
|
+ Background = Brushes.Black,
|
|
|
+ WindowStartupLocation = WindowStartupLocation.CenterOwner
|
|
|
+ };
|
|
|
+ var width = img.Width + 16;
|
|
|
+ var height = img.Height + 16;
|
|
|
+ if (width >= SystemParameters.PrimaryScreenWidth || height >= SystemParameters.PrimaryScreenHeight)
|
|
|
+ {
|
|
|
+ viewImageWindow.WindowState = WindowState.Maximized;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ viewImageWindow.Width = width;
|
|
|
+ viewImageWindow.Height = height;
|
|
|
+ }
|
|
|
+ viewImageWindow.Content = new System.Windows.Controls.Image()
|
|
|
+ {
|
|
|
+ Source = img
|
|
|
+ };
|
|
|
+ viewImageWindow.ShowDialog();
|
|
|
+ };
|
|
|
+ ExamContent.Children.Add(imageBorder);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -103,12 +267,18 @@ namespace TestViewer
|
|
|
{
|
|
|
ExamList.Items.Clear();
|
|
|
_pageIndex++;
|
|
|
- var exams = _db.GetExams(batchTask.Id, _pageIndex);
|
|
|
- foreach (var exam in exams)
|
|
|
+ Loading.Run(() =>
|
|
|
{
|
|
|
- ExamList.Items.Add(exam);
|
|
|
- }
|
|
|
- PageIndex.Text = $"{_pageIndex + 1}/{_pageCount}";
|
|
|
+ var exams = _db.GetExams(batchTask.Id, _pageIndex, _partKey, _conclusionKey);
|
|
|
+ Dispatcher.Invoke(() =>
|
|
|
+ {
|
|
|
+ foreach (var exam in exams)
|
|
|
+ {
|
|
|
+ ExamList.Items.Add(exam);
|
|
|
+ }
|
|
|
+ PageIndex.Text = $"{_pageIndex + 1}/{_pageCount}";
|
|
|
+ });
|
|
|
+ });
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -122,12 +292,152 @@ namespace TestViewer
|
|
|
{
|
|
|
ExamList.Items.Clear();
|
|
|
_pageIndex--;
|
|
|
- var exams = _db.GetExams(batchTask.Id, _pageIndex);
|
|
|
- foreach (var exam in exams)
|
|
|
+ Loading.Run(() =>
|
|
|
+ {
|
|
|
+ var exams = _db.GetExams(batchTask.Id, _pageIndex, _partKey, _conclusionKey);
|
|
|
+ Dispatcher.Invoke(() =>
|
|
|
+ {
|
|
|
+ foreach (var exam in exams)
|
|
|
+ {
|
|
|
+ ExamList.Items.Add(exam);
|
|
|
+ }
|
|
|
+ PageIndex.Text = $"{_pageIndex + 1}/{_pageCount}";
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void OnSearchClick(object sender, RoutedEventArgs e)
|
|
|
+ {
|
|
|
+ _partKey = PartKey.Text;
|
|
|
+ _conclusionKey = ConclusionKey.Text;
|
|
|
+ var batchTask = BatchTaskList.SelectedValue as BatchTask;
|
|
|
+ if (batchTask != null)
|
|
|
+ {
|
|
|
+ ExamList.Items.Clear();
|
|
|
+ Exam[]? exams = null;
|
|
|
+ Loading.Run(() =>
|
|
|
+ {
|
|
|
+ _pageCount = _db.GetPageCount(batchTask.Id, _partKey, _conclusionKey);
|
|
|
+ _pageIndex = 0;
|
|
|
+ exams = _db.GetExams(batchTask.Id, _pageIndex, _partKey, _conclusionKey);
|
|
|
+ Dispatcher.Invoke(() =>
|
|
|
{
|
|
|
- ExamList.Items.Add(exam);
|
|
|
+ foreach (var exam in exams)
|
|
|
+ {
|
|
|
+ ExamList.Items.Add(exam);
|
|
|
+ }
|
|
|
+ PageIndex.Text = $"{_pageIndex + 1}/{_pageCount}";
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void OnExportClick(object sender, RoutedEventArgs e)
|
|
|
+ {
|
|
|
+ var partKey = PartKey.Text;
|
|
|
+ var conclusionKey = ConclusionKey.Text;
|
|
|
+ var batchTask = BatchTaskList.SelectedValue as BatchTask;
|
|
|
+ if (batchTask != null)
|
|
|
+ {
|
|
|
+ FolderBrowserEx.FolderBrowserDialog dialog = new FolderBrowserEx.FolderBrowserDialog();
|
|
|
+ var result = dialog.ShowDialog();
|
|
|
+ if (result == System.Windows.Forms.DialogResult.OK)
|
|
|
+ {
|
|
|
+ var targetFolder = dialog.SelectedFolder;
|
|
|
+ var imageFolder = Path.Combine(targetFolder, "images");
|
|
|
+ if (!Directory.Exists(imageFolder))
|
|
|
+ {
|
|
|
+ Directory.CreateDirectory(imageFolder);
|
|
|
+ }
|
|
|
+ var reportFolder = Path.Combine(targetFolder, "reports");
|
|
|
+ if (!Directory.Exists(reportFolder))
|
|
|
+ {
|
|
|
+ Directory.CreateDirectory(reportFolder);
|
|
|
}
|
|
|
- PageIndex.Text = $"{_pageIndex + 1}/{_pageCount}";
|
|
|
+ var progressWindow = new Window
|
|
|
+ {
|
|
|
+ Title = "导出中...",
|
|
|
+ WindowStartupLocation = WindowStartupLocation.CenterOwner,
|
|
|
+ WindowStyle = WindowStyle.ToolWindow,
|
|
|
+ ResizeMode = ResizeMode.NoResize,
|
|
|
+ Width = 320,
|
|
|
+ Height = 80,
|
|
|
+ Owner = this
|
|
|
+ };
|
|
|
+ var canClose = false;
|
|
|
+ progressWindow.Closing += (s, e) => { e.Cancel = !canClose; };
|
|
|
+
|
|
|
+
|
|
|
+ var progressBar = new ProgressBar
|
|
|
+ {
|
|
|
+ Minimum = 0,
|
|
|
+ Maximum = 100,
|
|
|
+ Value = 0
|
|
|
+ };
|
|
|
+ progressWindow.Content = progressBar;
|
|
|
+ Task.Run(() =>
|
|
|
+ {
|
|
|
+ JsonSerializerOptions opts = new JsonSerializerOptions
|
|
|
+ {
|
|
|
+ WriteIndented = true,
|
|
|
+ Encoder = JavaScriptEncoder.Create(UnicodeRanges.All)
|
|
|
+ };
|
|
|
+ var pageCount = _db.GetPageCount(batchTask.Id, partKey, conclusionKey);
|
|
|
+ if (pageCount > 0)
|
|
|
+ {
|
|
|
+ for (int i = 0; i < pageCount; i++)
|
|
|
+ {
|
|
|
+ var exams = _db.GetExams(batchTask.Id, i, partKey, conclusionKey);
|
|
|
+ for (var j = 0; j < exams.Length; j++)
|
|
|
+ {
|
|
|
+ var exam = exams[j];
|
|
|
+ var images = _db.GetImages(exam.Id);
|
|
|
+ foreach (var image in images)
|
|
|
+ {
|
|
|
+ var fileName = Path.Combine(imageFolder, $"{exam.Id}_{image.Id}.jpg");
|
|
|
+ File.WriteAllBytes(fileName, image.Data);
|
|
|
+ }
|
|
|
+ var reportDic = new Dictionary<string, object>
|
|
|
+ {
|
|
|
+ { "PatientName", exam.PatientName },
|
|
|
+ { "PatientSex", exam.PatientSex },
|
|
|
+ { "PatientAge", exam.PatientAge },
|
|
|
+ { "ExamDate", exam.ExamDate }
|
|
|
+ };
|
|
|
+ Dictionary<string, string>? reportContent = null;
|
|
|
+ try
|
|
|
+ {
|
|
|
+ reportContent = JsonSerializer.Deserialize<Dictionary<string, string>>(exam.Report);
|
|
|
+ }
|
|
|
+ catch
|
|
|
+ {
|
|
|
+ reportContent = null;
|
|
|
+ }
|
|
|
+ if (reportContent != null)
|
|
|
+ {
|
|
|
+ reportDic.Add("Report", reportContent);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ reportDic.Add("Report", exam.Report);
|
|
|
+ }
|
|
|
+ var reportFile = Path.Combine(reportFolder, $"{exam.Id}.txt");
|
|
|
+ File.WriteAllText(reportFile, JsonSerializer.Serialize(reportDic, opts));
|
|
|
+ }
|
|
|
+ var progress = (i + 1) / (double)pageCount * 100;
|
|
|
+ Dispatcher.Invoke(() =>
|
|
|
+ {
|
|
|
+ progressWindow.Title = $"导出中...{(int)progress}%";
|
|
|
+ progressBar.Value = progress;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ canClose = true;
|
|
|
+ Dispatcher.Invoke(progressWindow.Close);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ progressWindow.ShowDialog();
|
|
|
}
|
|
|
}
|
|
|
}
|