DrgApiClient.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Net.Http;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using System.Web.Script.Serialization;
  8. namespace DRG.DRGInterfaceClient
  9. {
  10. /// <summary>DRG 平台接口 HTTP 客户端(复用 HISAutoSyncService/ConfigApiClient 模式)。</summary>
  11. internal static class DrgApiClient
  12. {
  13. // 单天数据量较大时 02010067 可能较慢,超时放宽到 300 秒
  14. private static readonly HttpClient _http = new HttpClient { Timeout = TimeSpan.FromSeconds(300) };
  15. private static readonly JavaScriptSerializer _json = new JavaScriptSerializer();
  16. // ===== 通用调用(所有调用均带 session) =====
  17. public static async Task<Dictionary<string, object>> CallAsync(
  18. string code, object paramObj, Dictionary<string, object> session)
  19. {
  20. AppConfig cfg = Config.Current;
  21. var payload = new Dictionary<string, object>
  22. {
  23. { "code", code },
  24. { "params", new[] { paramObj } },
  25. { "session", new[] { session ?? new Dictionary<string, object>() } }
  26. };
  27. string json = _json.Serialize(payload);
  28. var req = new HttpRequestMessage(HttpMethod.Post, cfg.Endpoint);
  29. req.Content = new StringContent(json, Encoding.UTF8, "application/json");
  30. req.Headers.TryAddWithoutValidation("Authorization", "Basic " + cfg.AuthToken);
  31. var sw = Stopwatch.StartNew();
  32. try
  33. {
  34. var resp = await _http.SendAsync(req).ConfigureAwait(false);
  35. var text = await resp.Content.ReadAsStringAsync().ConfigureAwait(false);
  36. sw.Stop();
  37. Logger.Info(string.Format("[{0}] 请求: {1}", code, json));
  38. Logger.Info(string.Format("[{0}] HTTP {1} 耗时{2}ms 响应: {3}",
  39. code, (int)resp.StatusCode, sw.ElapsedMilliseconds, text));
  40. try { return _json.Deserialize<Dictionary<string, object>>(text); }
  41. catch (Exception ex)
  42. {
  43. Logger.Error("解析响应失败:" + code, ex);
  44. return ErrorDict(ex);
  45. }
  46. }
  47. catch (Exception ex)
  48. {
  49. sw.Stop();
  50. Logger.Error(string.Format("调用异常 [{0}] 耗时{1}ms", code, sw.ElapsedMilliseconds), ex);
  51. return ErrorDict(ex);
  52. }
  53. }
  54. // ===== 业务接口 =====
  55. public static Task<Dictionary<string, object>> QueryHospitalInfoAsync(
  56. string active, string descripts, Dictionary<string, object> session)
  57. {
  58. return CallAsync("01010064", new { active = active ?? "", descripts = descripts ?? "" }, session);
  59. }
  60. public static Task<Dictionary<string, object>> GetSyncConfigAsync(
  61. string hospCode, Dictionary<string, object> session)
  62. {
  63. return CallAsync("02010079", new { hospCode }, session);
  64. }
  65. public static Task<Dictionary<string, object>> GetInpatientDataAsync(
  66. string hospCode, string stDate, string endDate, string synFlag, Dictionary<string, object> session)
  67. {
  68. return CallAsync("02010067",
  69. new { admID = "", hospID = hospCode, stDate, endDate, SynFlag = synFlag }, session);
  70. }
  71. // ===== 响应解析辅助 =====
  72. public static bool IsOk(Dictionary<string, object> resp)
  73. {
  74. if (resp == null) return false;
  75. return resp.TryGetValue("errorCode", out object ec)
  76. && ec != null && ec.ToString() == "0";
  77. }
  78. public static string GetError(Dictionary<string, object> resp)
  79. {
  80. if (resp == null) return "响应为空";
  81. var msg = resp.TryGetValue("errorMessage", out object m) ? (m ?? "").ToString() : "";
  82. var ec = resp.TryGetValue("errorCode", out object e) ? (e ?? "").ToString() : "";
  83. return string.IsNullOrEmpty(msg) ? ("errorCode=" + ec) : msg;
  84. }
  85. public static Dictionary<string, object> GetResult(Dictionary<string, object> resp)
  86. {
  87. if (resp == null) return null;
  88. if (resp.TryGetValue("result", out object r) && r is Dictionary<string, object> dict) return dict;
  89. return null;
  90. }
  91. public static object[] GetResultArray(Dictionary<string, object> resp)
  92. {
  93. if (resp == null) return null;
  94. if (resp.TryGetValue("result", out object r))
  95. {
  96. if (r is object[] arr) return arr;
  97. if (r is System.Collections.ArrayList list)
  98. return (object[])list.ToArray(typeof(object));
  99. }
  100. return null;
  101. }
  102. // ===== 模型解析 =====
  103. public static HospitalInfoItem ParseHospital(Dictionary<string, object> d)
  104. {
  105. if (d == null) return new HospitalInfoItem();
  106. return new HospitalInfoItem
  107. {
  108. id = GetStr(d, "id"),
  109. hospCode = GetStr(d, "hospCode"),
  110. code = GetStr(d, "code"),
  111. descripts = GetStr(d, "descripts"),
  112. MedinsLv = GetStr(d, "MedinsLv")
  113. };
  114. }
  115. public static SyncConfig ParseSyncConfig(Dictionary<string, object> r)
  116. {
  117. if (r == null) return null;
  118. return new SyncConfig
  119. {
  120. syncType = GetStr(r, "syncType"),
  121. frequency = GetStr(r, "frequency"),
  122. scheduledTime = GetStr(r, "scheduledTime"),
  123. lookbackDays = GetInt(r, "lookbackDays", 3),
  124. enabled = GetBool(r, "enabled", false),
  125. synFlag = GetStr(r, "synFlag", "Y"),
  126. warningFlag = GetStr(r, "warningFlag", "Y"),
  127. status = GetStr(r, "status"),
  128. errorMessage = GetStr(r, "errorMessage")
  129. };
  130. }
  131. /// <summary>根据 syncType 与 lookbackDays 计算 02010067 的日期区间(yyyy-MM-dd)。</summary>
  132. public static (string stDate, string endDate) ComputeDateRange(
  133. string syncType, int lookbackDays, int fullSyncStartDays)
  134. {
  135. string today = DateTime.Now.ToString("yyyy-MM-dd");
  136. if (syncType == "full")
  137. {
  138. string st = fullSyncStartDays > 0
  139. ? DateTime.Now.AddDays(-fullSyncStartDays).ToString("yyyy-MM-dd")
  140. : "";
  141. return (st, today);
  142. }
  143. int lb = lookbackDays > 0 ? lookbackDays : 3;
  144. return (DateTime.Now.AddDays(-lb).ToString("yyyy-MM-dd"), today);
  145. }
  146. // ===== 按天分批 =====
  147. /// <summary>
  148. /// 按天拆分日期区间:结束日期晚于开始日期(跨度&gt;1 天)时,拆成每天一段(Item1=Item2=当天);
  149. /// 否则(同一天、开始日期为空或日期非法)返回原区间单段,保持原有一次性调用行为。
  150. /// 目的:避免一次性请求过大区间导致 02010067 接口服务超时。
  151. /// </summary>
  152. public static List<Tuple<string, string>> SplitByDay(string stDate, string endDate)
  153. {
  154. var list = new List<Tuple<string, string>>();
  155. DateTime st, ed;
  156. if (string.IsNullOrWhiteSpace(stDate)
  157. || !DateTime.TryParse(stDate, out st)
  158. || !DateTime.TryParse(endDate, out ed)
  159. || ed.Date <= st.Date)
  160. {
  161. list.Add(Tuple.Create(stDate, endDate));
  162. return list;
  163. }
  164. for (DateTime d = st.Date; d <= ed.Date; d = d.AddDays(1))
  165. {
  166. string day = d.ToString("yyyy-MM-dd");
  167. list.Add(Tuple.Create(day, day));
  168. }
  169. return list;
  170. }
  171. // ===== 内部工具 =====
  172. public static string GetStr(Dictionary<string, object> d, string k, string def = "")
  173. {
  174. if (d.TryGetValue(k, out object v) && v != null) return v.ToString();
  175. return def;
  176. }
  177. public static int GetInt(Dictionary<string, object> d, string k, int def)
  178. {
  179. if (d.TryGetValue(k, out object v) && v != null)
  180. {
  181. if (v is int i) return i;
  182. if (v is long l) return (int)l;
  183. if (int.TryParse(v.ToString(), out int r)) return r;
  184. }
  185. return def;
  186. }
  187. public static bool GetBool(Dictionary<string, object> d, string k, bool def)
  188. {
  189. if (d.TryGetValue(k, out object v) && v != null)
  190. {
  191. var s = v.ToString();
  192. if (s == "1" || string.Equals(s, "true", StringComparison.OrdinalIgnoreCase)
  193. || string.Equals(s, "Y", StringComparison.OrdinalIgnoreCase)) return true;
  194. if (s == "0" || string.Equals(s, "false", StringComparison.OrdinalIgnoreCase)
  195. || string.Equals(s, "N", StringComparison.OrdinalIgnoreCase)) return false;
  196. }
  197. return def;
  198. }
  199. private static Dictionary<string, object> ErrorDict(Exception ex)
  200. {
  201. return new Dictionary<string, object>
  202. {
  203. { "errorCode", "-1" },
  204. { "errorMessage", "异常: " + ex.Message }
  205. };
  206. }
  207. }
  208. }