WorklistSQLServerHandler.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. // Copyright (c) 2012-2020 fo-dicom contributors.
  2. // Licensed under the Microsoft Public License (MS-PL).
  3. using Dicom;
  4. using System;
  5. using System.Data;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Text.RegularExpressions;
  9. using System.Net;
  10. using System.IO;
  11. using System.Security.Cryptography;
  12. using Newtonsoft.Json;
  13. using System.Configuration;
  14. using System.Globalization;
  15. using System.Text;
  16. namespace Worklist_SCP.Model
  17. {
  18. public class WorklistSQLServerHandler
  19. {
  20. private static string HospitalName = ConfigurationManager.AppSettings["HospitalName"];
  21. private static string HospitalId = ConfigurationManager.AppSettings["HospitalId"];
  22. private static string ScheduledAET = ConfigurationManager.AppSettings["ScheduledAET"];
  23. private static string ModalityStringInt = ConfigurationManager.AppSettings["ModalityStringInt"];
  24. private static bool isChinese = "TRUE".Equals(ConfigurationManager.AppSettings["Chinese"]);
  25. private static void cache(List<View_PACS> hisBeans)
  26. {
  27. try
  28. {
  29. var Cache_Url = ConfigurationManager.AppSettings["Cache_Url"];
  30. List<Tmp> datas = new List<Tmp>();
  31. foreach (View_PACS hisBean in hisBeans)
  32. {
  33. datas.Add(new Tmp(hisBean.INPATIENTNO, hisBean.NAME, hisBean.zyh, hisBean.cwh, hisBean.PARTOFCHECK));
  34. }
  35. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Cache_Url);
  36. string postDataStr = "data=" + JsonConvert.SerializeObject(datas);
  37. request.Method = "POST";
  38. request.ContentType = "application/x-www-form-urlencoded";
  39. //request.ContentLength = DicomEncoding.GetEncoding("utf-8").GetByteCount(postDataStr);
  40. //request.ContentLength = DicomEncoding.Default.GetByteCount(postDataStr);
  41. Stream myRequestStream = request.GetRequestStream();
  42. //StreamWriter myStreamWriter = new StreamWriter(myRequestStream, DicomEncoding.Default);
  43. StreamWriter myStreamWriter = new StreamWriter(myRequestStream);
  44. myStreamWriter.Write(postDataStr);
  45. myStreamWriter.Close();
  46. HttpWebResponse response = (HttpWebResponse)request.GetResponse();
  47. Stream myResponseStream = response.GetResponseStream();
  48. StreamReader myStreamReader = new StreamReader(myResponseStream, DicomEncoding.GetEncoding("utf-8"));
  49. string retString = myStreamReader.ReadToEnd();
  50. myStreamReader.Close();
  51. myResponseStream.Close();
  52. Console.WriteLine($"服务器缓存 请求结果:{retString} 请求参数: {postDataStr}");
  53. } catch(Exception e)
  54. {
  55. Console.WriteLine($"请求失败 :{e.Message}");
  56. }
  57. }
  58. private static List<View_PACS> getHisBeans()
  59. {
  60. var SQL_IP = ConfigurationManager.AppSettings["SQL_IP"];
  61. var SQL_DB = ConfigurationManager.AppSettings["SQL_DB"];
  62. var SQL_USER = ConfigurationManager.AppSettings["SQL_USER"];
  63. var SQL_Password = ConfigurationManager.AppSettings["SQL_Password"];
  64. var ModalityConfig = ConfigurationManager.AppSettings["Modality"];
  65. //var dataSource = "Data Source=192.168.1.52;Initial Catalog=QiHIS;Persist Security Info=True;MultipleActiveResultSets=true;User ID=Lis999;Password=054805;Connect Timeout=30;min pool size=1;connection lifetime=15";
  66. var dataSource = "Data Source=" + SQL_IP + ";Initial Catalog=" + SQL_DB + "; Persist Security Info=True;MultipleActiveResultSets=true;User ID=" + SQL_USER + ";Password=" + SQL_Password + ";Connect Timeout=30;min pool size=1;connection lifetime=15";
  67. IFreeSql fsql = new FreeSql.FreeSqlBuilder()
  68. .UseConnectionString(FreeSql.DataType.SqlServer, dataSource)
  69. .UseAutoSyncStructure(false) //自动同步实体结构【开发环境必备】
  70. //.UseMonitorCommand(cmd => Console.Write(cmd.CommandText))
  71. .Build();
  72. var hisBeans = fsql.Select<View_PACS>()
  73. //.Where(b => b.CHECK_TYPE == ModalityConfig)
  74. //.Where(b => ModalityConfig.Split(',').Contains(b.CHECK_TYPE))
  75. .Where(b => b.LODGEDATE > DateTime.Now.AddDays(-7))
  76. .OrderByDescending(b => b.LODGEDATE)
  77. //.Skip(100)
  78. //.Limit(10) //第100行-110行的记录
  79. .ToList();
  80. return hisBeans;
  81. }
  82. private static List<WorklistItem> conversionWorklistItems(List<View_PACS> hisBeans) {
  83. List<WorklistItem> exams = new List<WorklistItem>();
  84. foreach (View_PACS hisBean in hisBeans)
  85. {
  86. exams.Add(conversionWorklistItem(hisBean));
  87. }
  88. return exams;
  89. }
  90. private static WorklistItem conversionWorklistItem(View_PACS hisBean) {
  91. WorklistItem exam = new WorklistItem();
  92. exam.AccessionNumber = hisBean.LODGENO;
  93. exam.PatientID = hisBean.INPATIENTNO;
  94. exam.Surname = hisBean.NAME;
  95. //exam.Name = TinyPinyin.Core.PinyinHelper.GetPinyin(hisBean.NAME);
  96. //exam.Name = TinyPinyin.Core.PinyinHelper.GetPinyin(hisBean.NAME);
  97. exam.Name = isChinese ? hisBean.NAME : TinyPinyin.Core.PinyinHelper.GetPinyin(hisBean.NAME);
  98. //exam.Name = TransferEncoding(Encoding.Default, Encoding.UTF32, hisBean.NAME);
  99. exam.Forename = "";
  100. exam.Title = "";
  101. exam.Sex = fixSex(hisBean.SEX);
  102. exam.DateOfBirth = hisBean.BIRTHDATE.Date;
  103. //exam.DateOfBirth = DateTime.ParseExact(hisBean.BIRTHDATE, "M/d/Y H:m:s", CultureInfo.InvariantCulture);
  104. //exam.ReferringPhysician = TinyPinyin.Core.PinyinHelper.GetPinyin(hisBean.LODGEDOCTOR);
  105. exam.ReferringPhysician = isChinese ? hisBean.LODGEDOCTOR: TinyPinyin.Core.PinyinHelper.GetPinyin(hisBean.LODGEDOCTOR);
  106. //exam.PerformingPhysician = TinyPinyin.Core.PinyinHelper.GetPinyin(hisBean.LODGESECTION);
  107. exam.PerformingPhysician = isChinese ? hisBean.LODGESECTION: TinyPinyin.Core.PinyinHelper.GetPinyin(hisBean.LODGESECTION);
  108. exam.Modality = hisBean.CHECK_TYPE;
  109. exam.ExamDateAndTime = hisBean.LODGEDATE;
  110. //exam.ExamDateAndTime = DateTime.ParseExact(hisBean.LODGEDATE, "M/d/Y H:m:s", CultureInfo.InvariantCulture);
  111. exam.ExamRoom = hisBean.BEDNO;
  112. exam.ExamDescription = "";
  113. // exam.StudyUID = "1.2.840.01053932350.3.152.235.2.12.187636473";
  114. // exam.StudyUID = "1.2.156.14702.3.3506.80065049053.20201024.10350685";
  115. exam.StudyUID = generatStudyUid(exam.PatientID, exam.AccessionNumber, exam.ExamDateAndTime);
  116. exam.ProcedureID = "";
  117. exam.ProcedureStepID = "";
  118. //exam.HospitalName = TinyPinyin.Core.PinyinHelper.GetPinyin(HospitalName);
  119. exam.HospitalName = isChinese ? HospitalName : TinyPinyin.Core.PinyinHelper.GetPinyin(HospitalName);
  120. exam.HospitalId = HospitalId;
  121. exam.ScheduledAET = ScheduledAET;
  122. return exam;
  123. }
  124. private static String fixSex(String sex) {
  125. if ("男".Equals(sex))
  126. {
  127. return "M";
  128. }
  129. if("女".Equals(sex))
  130. {
  131. return "F";
  132. }
  133. return "O";
  134. }
  135. // "1.2.840.xxxxx.3.152.235.2.12.187636473"
  136. // 1 Identifies ISO
  137. // 2 Identifies ANSI Member Body
  138. // 840 Country code of a specific Member Body (U.S. for ANSI)
  139. // xxxxx Identifies a specific Organization.(assigned by ANSI)
  140. // 3 Manufacturer defined device type
  141. // 152 Manufacturer defined serial number
  142. // 235 Study number
  143. // 2 Series number
  144. // 12 Image number
  145. // 187636473 Encoded date and time stamp of image acquisition
  146. private static string generatStudyUid(string PatientID, string AccessionNumber, DateTime ExamDateAndTime) {
  147. return "1.2.156.14702.3." + ModalityStringInt + "." + PatientID + "." + AccessionNumber + "." + GetTimeStamp(ExamDateAndTime);
  148. }
  149. private static string GetTimeStamp()
  150. {
  151. TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0);
  152. return Convert.ToInt64(ts.TotalSeconds).ToString();
  153. }
  154. private static string GetTimeStamp(DateTime dateTime)
  155. {
  156. TimeSpan ts = dateTime - new DateTime(1970, 1, 1, 0, 0, 0, 0);
  157. return Convert.ToInt64(ts.TotalSeconds).ToString();
  158. }
  159. public static IEnumerable<DicomDataset> FilterWorklistItems(DicomDataset request)
  160. {
  161. var patientName = request.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty);
  162. var PatientID = request.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty);
  163. var api = ConfigurationManager.AppSettings["API"];
  164. var AETitleConfig = ConfigurationManager.AppSettings["AETitle"];
  165. var CallingAEConfig = ConfigurationManager.AppSettings["CallingAE"];
  166. var ModalityConfig = ConfigurationManager.AppSettings["Modality"];
  167. var paramStr = $"patientName={patientName}&PatientID={PatientID}";
  168. DicomDataset procedureStep = null;
  169. if (request.Contains(DicomTag.ScheduledProcedureStepSequence))
  170. {
  171. procedureStep = request.GetSequence(DicomTag.ScheduledProcedureStepSequence).First();
  172. var scheduledStationAET = procedureStep.GetSingleValueOrDefault(DicomTag.ScheduledStationAETitle, string.Empty);
  173. var performingPhysician = procedureStep.GetSingleValueOrDefault(DicomTag.PerformingPhysicianName, string.Empty);
  174. var modality = procedureStep.GetSingleValueOrDefault(DicomTag.Modality, string.Empty);
  175. var scheduledProcedureStepStartDateTime = procedureStep.GetSingleValueOrDefault(DicomTag.ScheduledProcedureStepStartDateTime, string.Empty);
  176. var procedureStepLocation = procedureStep.GetSingleValueOrDefault(DicomTag.ScheduledProcedureStepLocation, string.Empty);
  177. var procedureDescription = procedureStep.GetSingleValueOrDefault(DicomTag.ScheduledProcedureStepDescription, string.Empty);
  178. paramStr = $"AETitleConfig={AETitleConfig}&CallingAEConfig={CallingAEConfig}&ModalityConfig={ModalityConfig}&patientName={patientName}&PatientID={PatientID}&scheduledStationAET={scheduledStationAET}&performingPhysician={performingPhysician}&modality={modality}&scheduledProcedureStepStartDateTime={scheduledProcedureStepStartDateTime}&procedureStepLocation={procedureStepLocation}&procedureDescription={procedureDescription}";
  179. }
  180. Console.WriteLine($"Http request url: {api} paramStr: {paramStr}");
  181. List<View_PACS> hisBeans = getHisBeans();
  182. cache(hisBeans);
  183. Console.WriteLine($"hisbeans: {JsonConvert.SerializeObject(hisBeans)}");
  184. List<WorklistItem> exams = conversionWorklistItems(hisBeans);
  185. Console.WriteLine($"exams: {JsonConvert.SerializeObject(exams)}");
  186. var results = exams.ToList();
  187. // Parsing result
  188. foreach (var result in results)
  189. {
  190. var resultingSPS = new DicomDataset();
  191. var resultDataset = new DicomDataset();
  192. var resultingSPSSequence = new DicomSequence(DicomTag.ScheduledProcedureStepSequence, resultingSPS);
  193. if (procedureStep != null)
  194. {
  195. resultDataset.Add(resultingSPSSequence);
  196. }
  197. // add results to "main" dataset
  198. AddIfExistsInRequest(resultDataset, request, DicomTag.AccessionNumber, result.AccessionNumber); // T2
  199. AddIfExistsInRequest(resultDataset, request, DicomTag.InstitutionName, result.HospitalName);
  200. //AddIfExistsInRequest(resultDataset, request, DicomTag.InstitutionCodeSequence, result.HospitalId);
  201. AddIfExistsInRequest(resultDataset, request, DicomTag.ReferringPhysicianName, result.ReferringPhysician); // T2
  202. //AddIfExistsInRequest(resultDataset, request, DicomTag.PatientName, TransferEncoding(Encoding.Default, Encoding.GetEncoding("GB18030") , result.Name)); //T1
  203. //AddIfExistsInRequest(resultDataset, request, DicomTag.PatientName, result.Surname + "^" + result.Forename + "^^" + result.Title); //T1
  204. AddIfExistsInRequest(resultDataset, request, DicomTag.PatientName, result.Name); //T1
  205. AddIfExistsInRequest(resultDataset, request, DicomTag.ModalitiesInStudy, result.Modality); // T1
  206. AddIfExistsInRequest(resultDataset, request, DicomTag.PatientID, result.PatientID); // T1
  207. AddIfExistsInRequest(resultDataset, request, DicomTag.PatientBirthDate, result.DateOfBirth); // T2
  208. AddIfExistsInRequest(resultDataset, request, DicomTag.PatientSex, result.Sex); //T2
  209. AddIfExistsInRequest(resultDataset, request, DicomTag.StudyInstanceUID, result.StudyUID); // T1
  210. AddIfExistsInRequest(resultDataset, request, DicomTag.RequestingPhysician, result.ReferringPhysician); //T2
  211. AddIfExistsInRequest(resultDataset, request, DicomTag.RequestedProcedureDescription, result.ExamDescription); //T1C
  212. AddIfExistsInRequest(resultDataset, request, DicomTag.RequestedProcedureID, result.ProcedureID); // T1
  213. //AddIfExistsInRequest(resultDataset, request, DicomTag.SpecificCharacterSet, "ISO_IR 192");
  214. //ISO_IR 192 utf8
  215. //ISO_IR 100 GB18030
  216. // Scheduled Procedure Step sequence T1
  217. // add results to procedure step dataset
  218. // Return if requested
  219. if (procedureStep != null)
  220. {
  221. AddIfExistsInRequest(resultingSPS, procedureStep, DicomTag.ModalitiesInStudy, result.Modality); // T1
  222. AddIfExistsInRequest(resultingSPS, procedureStep, DicomTag.ScheduledStationAETitle, result.ScheduledAET); // T1
  223. AddIfExistsInRequest(resultingSPS, procedureStep, DicomTag.ScheduledProcedureStepStartDate, result.ExamDateAndTime); //T1
  224. AddIfExistsInRequest(resultingSPS, procedureStep, DicomTag.ScheduledProcedureStepStartTime, result.ExamDateAndTime); //T1
  225. AddIfExistsInRequest(resultingSPS, procedureStep, DicomTag.Modality, result.Modality); // T1
  226. AddIfExistsInRequest(resultingSPS, procedureStep, DicomTag.ScheduledPerformingPhysicianName, result.PerformingPhysician); //T2
  227. AddIfExistsInRequest(resultingSPS, procedureStep, DicomTag.ScheduledProcedureStepDescription, result.ExamDescription); // T1C
  228. AddIfExistsInRequest(resultingSPS, procedureStep, DicomTag.ScheduledProcedureStepID, result.ProcedureStepID); // T1
  229. AddIfExistsInRequest(resultingSPS, procedureStep, DicomTag.ScheduledStationName, result.ExamRoom); //T2
  230. AddIfExistsInRequest(resultingSPS, procedureStep, DicomTag.ScheduledProcedureStepLocation, result.ExamRoom); //T2
  231. }
  232. // Put blanks in for unsupported fields which are type 2 (i.e. must have a value even if NULL)
  233. // In a real server, you may wish to support some or all of these, but they are not commonly supported
  234. AddIfExistsInRequest(resultDataset, request, DicomTag.SpecificCharacterSet, "GB18030"); // Ref//d Study Sequence
  235. AddIfExistsInRequest(resultDataset, request, DicomTag.ReferencedStudySequence, new DicomDataset()); // Ref//d Study Sequence
  236. AddIfExistsInRequest(resultDataset, request, DicomTag.Priority, ""); // Priority
  237. AddIfExistsInRequest(resultDataset, request, DicomTag.PatientTransportArrangements, ""); // Transport Arrangements
  238. AddIfExistsInRequest(resultDataset, request, DicomTag.AdmissionID, ""); // Admission ID
  239. AddIfExistsInRequest(resultDataset, request, DicomTag.CurrentPatientLocation, ""); // Patient Location
  240. AddIfExistsInRequest(resultDataset, request, DicomTag.ReferencedPatientSequence, new DicomDataset()); // Ref//d Patient Sequence
  241. AddIfExistsInRequest(resultDataset, request, DicomTag.PatientWeight, ""); // Weight
  242. AddIfExistsInRequest(resultDataset, request, DicomTag.ConfidentialityConstraintOnPatientDataDescription, ""); // Confidentiality Constraint
  243. // Send Reponse Back
  244. yield return resultDataset;
  245. }
  246. }
  247. private static string TransferEncoding(Encoding srcEncoding, Encoding dstEncoding, string srcStr)
  248. {
  249. byte[] srcBytes = srcEncoding.GetBytes(srcStr);
  250. byte[] bytes = Encoding.Convert(srcEncoding, dstEncoding, srcBytes);
  251. return dstEncoding.GetString(bytes);
  252. }
  253. //Splits patient name into 2 separte strings surname and forename and send then to the addstringcondition subroutine.
  254. internal static IQueryable<WorklistItem> AddNameCondition(IQueryable<WorklistItem> exams, string dicomName)
  255. {
  256. if (string.IsNullOrEmpty(dicomName) || dicomName == "*")
  257. {
  258. return exams;
  259. }
  260. var personName = new DicomPersonName(DicomTag.PatientName, dicomName);
  261. if (dicomName.Contains("*"))
  262. {
  263. var firstNameRegex = new Regex("^" + Regex.Escape(personName.First).Replace("\\*", ".*") + "$");
  264. var lastNameRegex = new Regex("^" + Regex.Escape(personName.Last).Replace("\\*", ".*") + "$");
  265. exams = exams.Where(x => firstNameRegex.IsMatch(x.Forename) || lastNameRegex.IsMatch(x.Surname));
  266. }
  267. else
  268. {
  269. exams = exams.Where(x => (x.Forename.Equals(personName.First) && x.Surname.Equals(personName.Last)));
  270. }
  271. return exams;
  272. }
  273. internal static IQueryable<WorklistItem> AddDateCondition(IQueryable<WorklistItem> exams, string dateCondition)
  274. {
  275. if (!string.IsNullOrEmpty(dateCondition) && dateCondition != "*")
  276. {
  277. var range = new DicomDateTime(DicomTag.ScheduledProcedureStepStartDate, dateCondition).Get<DicomDateRange>();
  278. exams = exams.Where(x => range.Contains(x.ExamDateAndTime));
  279. }
  280. return exams;
  281. }
  282. internal static void AddIfExistsInRequest<T>(DicomDataset result, DicomDataset request, DicomTag tag, T value)
  283. {
  284. // Only send items which have been requested
  285. if (request.Contains(tag))
  286. {
  287. if (value == null)
  288. {
  289. value = default;
  290. }
  291. result.AddOrUpdate(tag, value);
  292. }
  293. }
  294. }
  295. }