using System; using System.Collections.Generic; using System.Diagnostics; using System.Net.Http; using System.Text; using System.Threading.Tasks; using System.Web.Script.Serialization; namespace DRG.DRGInterfaceClient { /// DRG 平台接口 HTTP 客户端(复用 HISAutoSyncService/ConfigApiClient 模式)。 internal static class DrgApiClient { // 单天数据量较大时 02010067 可能较慢,超时放宽到 300 秒 private static readonly HttpClient _http = new HttpClient { Timeout = TimeSpan.FromSeconds(300) }; private static readonly JavaScriptSerializer _json = new JavaScriptSerializer(); // ===== 通用调用(所有调用均带 session) ===== public static async Task> CallAsync( string code, object paramObj, Dictionary session) { AppConfig cfg = Config.Current; var payload = new Dictionary { { "code", code }, { "params", new[] { paramObj } }, { "session", new[] { session ?? new Dictionary() } } }; string json = _json.Serialize(payload); var req = new HttpRequestMessage(HttpMethod.Post, cfg.Endpoint); req.Content = new StringContent(json, Encoding.UTF8, "application/json"); req.Headers.TryAddWithoutValidation("Authorization", "Basic " + cfg.AuthToken); var sw = Stopwatch.StartNew(); try { var resp = await _http.SendAsync(req).ConfigureAwait(false); var text = await resp.Content.ReadAsStringAsync().ConfigureAwait(false); sw.Stop(); Logger.Info(string.Format("[{0}] 请求: {1}", code, json)); Logger.Info(string.Format("[{0}] HTTP {1} 耗时{2}ms 响应: {3}", code, (int)resp.StatusCode, sw.ElapsedMilliseconds, text)); try { return _json.Deserialize>(text); } catch (Exception ex) { Logger.Error("解析响应失败:" + code, ex); return ErrorDict(ex); } } catch (Exception ex) { sw.Stop(); Logger.Error(string.Format("调用异常 [{0}] 耗时{1}ms", code, sw.ElapsedMilliseconds), ex); return ErrorDict(ex); } } // ===== 业务接口 ===== public static Task> QueryHospitalInfoAsync( string active, string descripts, Dictionary session) { return CallAsync("01010064", new { active = active ?? "", descripts = descripts ?? "" }, session); } public static Task> GetSyncConfigAsync( string hospCode, Dictionary session) { return CallAsync("02010079", new { hospCode }, session); } public static Task> GetInpatientDataAsync( string hospCode, string stDate, string endDate, string synFlag, Dictionary session) { return CallAsync("02010067", new { admID = "", hospID = hospCode, stDate, endDate, SynFlag = synFlag }, session); } // ===== 响应解析辅助 ===== public static bool IsOk(Dictionary resp) { if (resp == null) return false; return resp.TryGetValue("errorCode", out object ec) && ec != null && ec.ToString() == "0"; } public static string GetError(Dictionary resp) { if (resp == null) return "响应为空"; var msg = resp.TryGetValue("errorMessage", out object m) ? (m ?? "").ToString() : ""; var ec = resp.TryGetValue("errorCode", out object e) ? (e ?? "").ToString() : ""; return string.IsNullOrEmpty(msg) ? ("errorCode=" + ec) : msg; } public static Dictionary GetResult(Dictionary resp) { if (resp == null) return null; if (resp.TryGetValue("result", out object r) && r is Dictionary dict) return dict; return null; } public static object[] GetResultArray(Dictionary resp) { if (resp == null) return null; if (resp.TryGetValue("result", out object r)) { if (r is object[] arr) return arr; if (r is System.Collections.ArrayList list) return (object[])list.ToArray(typeof(object)); } return null; } // ===== 模型解析 ===== public static HospitalInfoItem ParseHospital(Dictionary d) { if (d == null) return new HospitalInfoItem(); return new HospitalInfoItem { id = GetStr(d, "id"), hospCode = GetStr(d, "hospCode"), code = GetStr(d, "code"), descripts = GetStr(d, "descripts"), MedinsLv = GetStr(d, "MedinsLv") }; } public static SyncConfig ParseSyncConfig(Dictionary r) { if (r == null) return null; return new SyncConfig { syncType = GetStr(r, "syncType"), frequency = GetStr(r, "frequency"), scheduledTime = GetStr(r, "scheduledTime"), lookbackDays = GetInt(r, "lookbackDays", 3), enabled = GetBool(r, "enabled", false), synFlag = GetStr(r, "synFlag", "Y"), warningFlag = GetStr(r, "warningFlag", "Y"), status = GetStr(r, "status"), errorMessage = GetStr(r, "errorMessage") }; } /// 根据 syncType 与 lookbackDays 计算 02010067 的日期区间(yyyy-MM-dd)。 public static (string stDate, string endDate) ComputeDateRange( string syncType, int lookbackDays, int fullSyncStartDays) { string today = DateTime.Now.ToString("yyyy-MM-dd"); if (syncType == "full") { string st = fullSyncStartDays > 0 ? DateTime.Now.AddDays(-fullSyncStartDays).ToString("yyyy-MM-dd") : ""; return (st, today); } int lb = lookbackDays > 0 ? lookbackDays : 3; return (DateTime.Now.AddDays(-lb).ToString("yyyy-MM-dd"), today); } // ===== 按天分批 ===== /// /// 按天拆分日期区间:结束日期晚于开始日期(跨度>1 天)时,拆成每天一段(Item1=Item2=当天); /// 否则(同一天、开始日期为空或日期非法)返回原区间单段,保持原有一次性调用行为。 /// 目的:避免一次性请求过大区间导致 02010067 接口服务超时。 /// public static List> SplitByDay(string stDate, string endDate) { var list = new List>(); DateTime st, ed; if (string.IsNullOrWhiteSpace(stDate) || !DateTime.TryParse(stDate, out st) || !DateTime.TryParse(endDate, out ed) || ed.Date <= st.Date) { list.Add(Tuple.Create(stDate, endDate)); return list; } for (DateTime d = st.Date; d <= ed.Date; d = d.AddDays(1)) { string day = d.ToString("yyyy-MM-dd"); list.Add(Tuple.Create(day, day)); } return list; } // ===== 内部工具 ===== public static string GetStr(Dictionary d, string k, string def = "") { if (d.TryGetValue(k, out object v) && v != null) return v.ToString(); return def; } public static int GetInt(Dictionary d, string k, int def) { if (d.TryGetValue(k, out object v) && v != null) { if (v is int i) return i; if (v is long l) return (int)l; if (int.TryParse(v.ToString(), out int r)) return r; } return def; } public static bool GetBool(Dictionary d, string k, bool def) { if (d.TryGetValue(k, out object v) && v != null) { var s = v.ToString(); if (s == "1" || string.Equals(s, "true", StringComparison.OrdinalIgnoreCase) || string.Equals(s, "Y", StringComparison.OrdinalIgnoreCase)) return true; if (s == "0" || string.Equals(s, "false", StringComparison.OrdinalIgnoreCase) || string.Equals(s, "N", StringComparison.OrdinalIgnoreCase)) return false; } return def; } private static Dictionary ErrorDict(Exception ex) { return new Dictionary { { "errorCode", "-1" }, { "errorMessage", "异常: " + ex.Message } }; } } }