From fc6f9261d2a21bbdadb8af2c1b9ae85d7c8468c5 Mon Sep 17 00:00:00 2001 From: wangsq Date: Wed, 9 Sep 2026 10:27:19 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BD=8F=E9=99=A2=E5=8C=BB=E4=BF=9D=E7=BB=93?= =?UTF-8?q?=E7=AE=97=E7=A7=BB=E9=99=A4=E6=B5=8B=E8=AF=95=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=20=E9=A2=84=E9=97=AE=E8=AF=8A=E8=B0=83=E6=95=B4token=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E7=9A=84=E9=85=8D=E7=BD=AE=E5=92=8C=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ynxbd/common/TestA.java | 11 - .../action/healthcard/HCPreConsultAction.java | 6 +- .../ynxbd/common/dao/his/HisInHospDao.java | 2 +- .../common/healthcard/HCPreConsultHelper.java | 301 ++++++++---------- .../healthcard/config/HCPreConsultConfig.java | 156 ++++++++- .../ynxbd/common/service/InHospService.java | 11 +- src/main/resources/hc-config.xml | 4 +- 7 files changed, 299 insertions(+), 192 deletions(-) diff --git a/src/main/java/com/ynxbd/common/TestA.java b/src/main/java/com/ynxbd/common/TestA.java index 87b0168..c846281 100644 --- a/src/main/java/com/ynxbd/common/TestA.java +++ b/src/main/java/com/ynxbd/common/TestA.java @@ -1,14 +1,6 @@ package com.ynxbd.common; -import com.ynxbd.common.bean.enums.MerchantEnum; -import com.ynxbd.common.dao.his.HisAccountDao; -import com.ynxbd.common.dao.his.HisRegisterDao; -import com.ynxbd.common.helper.common.LocalDateHelper; -import com.ynxbd.common.result.JsonResult; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.codec.digest.DigestUtils; - -import java.time.LocalDateTime; @Slf4j public class TestA { @@ -132,7 +124,4 @@ public class TestA { // System.out.println(removeIds); // } - public static void main(String[] args) { - - } } \ No newline at end of file diff --git a/src/main/java/com/ynxbd/common/action/healthcard/HCPreConsultAction.java b/src/main/java/com/ynxbd/common/action/healthcard/HCPreConsultAction.java index e8389bb..12a9255 100644 --- a/src/main/java/com/ynxbd/common/action/healthcard/HCPreConsultAction.java +++ b/src/main/java/com/ynxbd/common/action/healthcard/HCPreConsultAction.java @@ -237,7 +237,7 @@ public class HCPreConsultAction extends BaseAction { if (order == null) { return Result.error("未找到挂号订单"); } - String url = HCPreConsultHelper.getH5DoctorURL(order.getOutTradeNo(), deptCode, deptName, doctCode, doctName, redirectUrl); + String url = HCPreConsultHelper.getH5DoctorURL(order.getOpenid(), order.getOutTradeNo(), deptCode, deptName, doctCode, doctName, redirectUrl); return Result.success(url); } catch (Exception e) { return Result.error(e); @@ -262,7 +262,7 @@ public class HCPreConsultAction extends BaseAction { if (order == null) { return Result.error("未找到挂号订单"); } - JSONObject data = HCPreConsultHelper.getPreDiagnosisReportByCaseId(order.getOutTradeNo(), deptCode, deptName, doctCode, doctName); + JSONObject data = HCPreConsultHelper.getPreDiagnosisReportByCaseId(order.getOpenid(), order.getOutTradeNo(), deptCode, deptName, doctCode, doctName); return Result.success(data); } catch (Exception e) { return Result.error(e); @@ -287,7 +287,7 @@ public class HCPreConsultAction extends BaseAction { if (order == null) { return Result.error("未找到挂号订单"); } - JSONObject data = HCPreConsultHelper.getPreDiagnosisReportDialogues(order.getOutTradeNo(), deptCode, deptName, doctCode, doctName); + JSONObject data = HCPreConsultHelper.getPreDiagnosisReportDialogues(order.getOpenid(), order.getOutTradeNo(), deptCode, deptName, doctCode, doctName); return Result.success(data); } catch (Exception e) { return Result.error(e); diff --git a/src/main/java/com/ynxbd/common/dao/his/HisInHospDao.java b/src/main/java/com/ynxbd/common/dao/his/HisInHospDao.java index b660819..e2be563 100644 --- a/src/main/java/com/ynxbd/common/dao/his/HisInHospDao.java +++ b/src/main/java/com/ynxbd/common/dao/his/HisInHospDao.java @@ -86,7 +86,7 @@ public class HisInHospDao { * @return 住院记录 */ public JsonResult queryOutPatientRecords(String openid, String patientId, String hisYBZF) { - return HisFactory.His(HisConfig.hasDevMedOpenId(openid, HisEnum.Query_OutPatientRecords)).getJsonResult(HisEnum.Query_OutPatientRecords, params -> { + return HisFactory.His().getJsonResult(HisEnum.Query_OutPatientRecords, params -> { params.put("PatientID", patientId); params.put("CallNo", HisConfig.WECHAT_CALL_NO); params.put("YDZF", ObjectUtils.isEmpty(hisYBZF) ? "" : hisYBZF); // [住院]医保 diff --git a/src/main/java/com/ynxbd/common/healthcard/HCPreConsultHelper.java b/src/main/java/com/ynxbd/common/healthcard/HCPreConsultHelper.java index 15ba67e..4fa6e35 100644 --- a/src/main/java/com/ynxbd/common/healthcard/HCPreConsultHelper.java +++ b/src/main/java/com/ynxbd/common/healthcard/HCPreConsultHelper.java @@ -5,6 +5,7 @@ import com.google.gson.*; import com.ynxbd.common.bean.Patient; import com.ynxbd.common.bean.enums.MerchantEnum; import com.ynxbd.common.bean.pay.Register; +import com.ynxbd.common.bean.sms.SmsTemplate; import com.ynxbd.common.healthcard.config.HCPreConsultConfig; import com.ynxbd.common.helper.common.CodeHelper; import com.ynxbd.common.helper.common.JsonHelper; @@ -15,6 +16,7 @@ import com.ynxbd.wx.config.WeChatConfig; import lombok.extern.slf4j.Slf4j; import okhttp3.Headers; import org.apache.commons.lang3.ObjectUtils; +import org.ehcache.Cache; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; @@ -23,30 +25,29 @@ import java.util.*; @Slf4j public class HCPreConsultHelper { + public static JSONObject post(String url, OkHttpHelper.MapParams params, OkHttpHelper.Header header) { return OkHttpHelper.postJson(url, params, header); } - public static void setHeader(Headers.Builder headers) { + public static void setHeader(Headers.Builder headers, String token, Map request, String openId) { headers.add("Content-Type", "application/json"); -// String timestamp = String.valueOf(System.currentTimeMillis()); -// headers.add("god-portal-signature", HCPreConsultConfig.toHmacSha256Example(HCPreConsultConfig.SECRET_KEY, HCPreConsultConfig.HOSP_ID + timestamp)); -// headers.add("god-portal-timestamp", timestamp); -// headers.add("god-portal-request-id", CodeHelper.get32UUID()); - - // https://open.ai.tengmed.com/openAccess/docs/access#14 -// headers.add("Th-Auth-Type", "Th-Auth-Hc"); -// headers.add("Th-Auth-Hc-App-Token", appToken); -// headers.add("Th-Auth-Hc-HospitalId", HCPreConsultConfig.APP_HOSP_ID); -// headers.add("Th-Auth-Hc-Timestamp", String.valueOf(Instant.now().getEpochSecond())); -// headers.add("Th-Auth-Hc-Sign", signValue); -// headers.add("Th-Auth-Hc-BusinessId", businessId); -// headers.add("Th-Auth-Hc-ChannelNum", "0"); -// headers.add("Th-Auth-Hc-Relate-AppId", WeChatConfig.APP_ID); -// headers.add("Th-Auth-Hc-Relate-OpenId", wxOpenId); -// // 自定义追踪ID -// headers.add("god-portal-request-id", UUID.randomUUID().toString()); + String timestamp = String.valueOf(Instant.now().getEpochSecond()); + String sign = HCPreConsultConfig.calculateSign(request, token, openId, timestamp); + + headers.add("Th-Auth-Type", "Th-Auth-Hc"); + headers.add("Th-Auth-Hc-App-Token", token); + headers.add("Th-Auth-Hc-HospitalId", HCPreConsultConfig.APP_HOSP_ID); + headers.add("Th-Auth-Hc-Timestamp", timestamp); + if (sign != null) { + headers.add("Th-Auth-Hc-Sign", sign); + } + headers.add("Th-Auth-Hc-BusinessId", HCPreConsultConfig.BUSINESS_ID); + + headers.add("Th-Auth-Hc-ChannelNum", "0"); + headers.add("Th-Auth-Hc-Relate-AppId", WeChatConfig.APP_ID); + headers.add("Th-Auth-Hc-Relate-OpenId", openId); } public static String filterDoctorId(String doctorId) { @@ -189,50 +190,74 @@ public class HCPreConsultHelper { /** - * 7.3.1-获取预问诊报告数据 + * 7.2 接入方式一:打开完整页面 */ - public static JSONObject getPreDiagnosisReportByCaseId(String registerId, String departmentId, String departmentName, String doctorId, String doctorName) throws ServiceException { - String url = "https://wechat.wecity.qq.com/trpcapi/GuideThOpenAdpterServer/GetPreDiagnosisReportByCaseId"; + public static String getH5DoctorURL(String openId, String registerId, String departmentId, String departmentName, String doctorId, String doctorName, String redirectUrl) throws ServiceException { + String token = getH5DoctorLoginToken(doctorId, doctorName); + if (ObjectUtils.isEmpty(token)) { + throw new ServiceException("token获取失败"); + } + String url = HCPreConsultConfig.IS_DEV + ? "https://dev-aimedical.wecity.qq.com/toolbox/prediagnosis.html?token=${token}®isteredid=${registeredid}&departmentId=${departmentId}&doctorId=${doctorId}&subHospitalId=&redirectUrl=" + : "https://aimedical.wecity.qq.com/toolbox/prediagnosis.html?token=${token}®isteredid=${registeredid}&departmentId=${departmentId}&doctorId=${doctorId}&subHospitalId=&redirectUrl="; + + url = url.replace("${token}", token) + .replace("${registeredid}", registerId) + .replace("${departmentId}", departmentId) + .replace("${doctorId}", doctorId); + return url + redirectUrl; + } + + /** + * 7.2.1 通过 HisToolLoginIn接口获取 token + */ + public static String getH5DoctorLoginToken(String doctorId, String doctorName) { + String url = "https://aimedical.wecity.qq.com/cgi-bin/v1/Diagnosis/RationalDrugServer/RationalDrugServant/HisToolLogin"; Map data = new HashMap<>(); - data.put("partnerId", HCPreConsultConfig.PARTNER_ID); - data.put("caseId", registerId); - data.put("doctorId", doctorId); - data.put("doctorName", doctorName); - data.put("departmentId", departmentId); - data.put("departmentName", departmentName); + data.put("partner_id", HCPreConsultConfig.SCENE_PARTNER_ID); + data.put("doctor_id", doctorId); + data.put("doctor_name", doctorName); Map header = new HashMap<>(); - header.put("hospitalId", HCPreConsultConfig.HOSP_ID); - header.put("subHospitalId", ""); + header.put("hospital_id", HCPreConsultConfig.DOCTOR_PC_HOSP_ID); + header.put("sub_hospital_id", ""); JSONObject resultJson = post(url, params -> { params.put("data", data); params.put("header", header); - - log.info("[7.3.1-获取预问诊报告数据] 入参:{}", JsonHelper.toJsonString(params)); - }, HCPreConsultHelper::setHeader); - log.info("[7.3.1-获取预问诊报告数据] resp={}", resultJson); + log.info("[7.2.1 通过 HisToolLoginIn接口获取 token] 入参:{}", JsonHelper.toJsonString(params)); + }, headers -> { + String timestamp = String.valueOf(System.currentTimeMillis()); + headers.add("god-portal-signature", HCPreConsultConfig.toHmacSha256Example(HCPreConsultConfig.DOCTOR_PC_SECRET_KEY, HCPreConsultConfig.DOCTOR_PC_HOSP_ID + timestamp)); + headers.add("god-portal-timestamp", timestamp); + headers.add("god-portal-request-id", CodeHelper.get32UUID()); + }); + log.error("[7.2.1 通过 HisToolLoginIn接口获取 token] resp={}", JsonHelper.toJsonString(resultJson)); String code = resultJson.getString("retcode"); String message = resultJson.getString("retmsg"); String reqId = resultJson.getString("request_id"); if (!"0".equals(code)) { - log.error("[7.3.1-获取预问诊报告数据]失败[rid:{}] code={}, message={}", reqId, code, message); - throw new ServiceException(message); + log.error("[7.2.1 通过 HisToolLoginIn接口获取 token]失败[rid:{}] code={}, message={}", reqId, code, message); + return null; } JSONObject dataJson = resultJson.getJSONObject("data"); if (dataJson == null) { - throw new ServiceException("[7.3.1-获取预问诊报告数据]data返回为空"); + log.error("[7.2.1 通过 HisToolLoginIn接口获取 token]data返回为空"); + return null; } - return dataJson; + return dataJson.getString("token"); } /** - * 7.3.2-获取预问诊对话记录 + * 7.3.1-获取预问诊报告数据 */ - public static JSONObject getPreDiagnosisReportDialogues(String registerId, String departmentId, String departmentName, String doctorId, String doctorName) throws ServiceException { - String url = "https://wechat.wecity.qq.com/trpcapi/GuideThOpenAdpterServer/GetPreDiagnosisReportDialogues"; + public static JSONObject getPreDiagnosisReportByCaseId(String openId, String registerId, String departmentId, String departmentName, String doctorId, String doctorName) throws ServiceException { + String url = "https://wechat.wecity.qq.com/trpcapi/GuideThOpenAdpterServer/GetPreDiagnosisReportByCaseId"; + + Map request = new HashMap<>(); + Map data = new HashMap<>(); data.put("partnerId", HCPreConsultConfig.PARTNER_ID); data.put("caseId", registerId); @@ -243,182 +268,124 @@ public class HCPreConsultHelper { Map header = new HashMap<>(); header.put("hospitalId", HCPreConsultConfig.HOSP_ID); + header.put("subHospitalId", ""); - JSONObject resultJson = post(url, params -> { - params.put("data", data); - params.put("header", header); + request.put("data", data); + request.put("header", header); - log.info("[7.3.2-获取预问诊对话记录] 入参:{}", JsonHelper.toJsonString(params)); - }, HCPreConsultHelper::setHeader); - log.info("[7.3.2-获取预问诊对话记录] resp={}", resultJson); + String token = HCPreConsultConfig.getCacheToken(); + if (token == null) { + throw new ServiceException("[7.3.1-获取预问诊报告数据]获取token失败"); + } + + JSONObject resultJson = post(url, params -> { + params.put("request", request); + log.info("[7.3.1-获取预问诊报告数据] 入参:{}", JsonHelper.toJsonString(request)); + }, headers -> { + HCPreConsultHelper.setHeader(headers, token, request, openId); + }); + log.info("[7.3.1-获取预问诊报告数据] resp={}", resultJson); String code = resultJson.getString("retcode"); String message = resultJson.getString("retmsg"); String reqId = resultJson.getString("request_id"); if (!"0".equals(code)) { - log.error("[7.3.2-获取预问诊对话记录]失败[rid:{}] code={}, message={}", reqId, code, message); + log.error("[7.3.1-获取预问诊报告数据]失败[rid:{}] code={}, message={}", reqId, code, message); throw new ServiceException(message); } JSONObject dataJson = resultJson.getJSONObject("data"); if (dataJson == null) { - throw new ServiceException("[7.3.2-获取预问诊对话记录]data返回为空"); + throw new ServiceException("[7.3.1-获取预问诊报告数据]data返回为空"); } return dataJson; } - /** - * 7.2 接入方式一:打开完整页面 + * 7.3.2-获取预问诊对话记录 */ - public static String getH5DoctorURL(String registerId, String departmentId, String departmentName, String doctorId, String doctorName, String redirectUrl) throws ServiceException { - String token = getH5DoctorLoginToken(doctorId, doctorName); - if (ObjectUtils.isEmpty(token)) { - throw new ServiceException("token获取失败"); - } - String url = HCPreConsultConfig.IS_DEV - ? "https://dev-aimedical.wecity.qq.com/toolbox/prediagnosis.html?token=${token}®isteredid=${registeredid}&departmentId=${departmentId}&doctorId=${doctorId}&subHospitalId=&redirectUrl=" - : "https://aimedical.wecity.qq.com/toolbox/prediagnosis.html?token=${token}®isteredid=${registeredid}&departmentId=${departmentId}&doctorId=${doctorId}&subHospitalId=&redirectUrl="; - - url = url.replace("${token}", token) - .replace("${registeredid}", registerId) - .replace("${departmentId}", departmentId) - .replace("${doctorId}", doctorId); - return url + redirectUrl; - } + public static JSONObject getPreDiagnosisReportDialogues(String openId, String registerId, String departmentId, String departmentName, String doctorId, String doctorName) throws ServiceException { + String url = "https://wechat.wecity.qq.com/trpcapi/GuideThOpenAdpterServer/GetPreDiagnosisReportDialogues"; - /** - * 7.2.1 通过 HisToolLoginIn接口获取 token - */ - public static String getH5DoctorLoginToken(String doctorId, String doctorName) throws ServiceException { - String url = HCPreConsultConfig.IS_DEV - ? "https://dev-aimedical.wecity.qq.com/cgi-bin/v1/Diagnosis/RationalDrugServer/RationalDrugServant/HisToolLogin" - : "https://aimedical.wecity.qq.com/cgi-bin/v1/Diagnosis/RationalDrugServer/RationalDrugServant/HisToolLogin"; + Map request = new HashMap<>(); Map data = new HashMap<>(); - data.put("partner_id", HCPreConsultConfig.PARTNER_ID); - data.put("doctor_id", doctorId); - data.put("doctor_name", doctorName); + data.put("partnerId", HCPreConsultConfig.PARTNER_ID); + data.put("caseId", registerId); + data.put("doctorId", doctorId); + data.put("doctorName", doctorName); + data.put("departmentId", departmentId); + data.put("departmentName", departmentName); Map header = new HashMap<>(); - header.put("hospital_id", HCPreConsultConfig.HOSP_ID); - header.put("sub_hospital_id", ""); + header.put("hospitalId", HCPreConsultConfig.HOSP_ID); + + request.put("data", data); + request.put("header", header); - log.info("[7.2.1 通过 HisToolLoginIn接口获取 token] 入参:data={}, header={}", data, header); + String token = HCPreConsultConfig.getCacheToken(); + if (token == null) { + throw new ServiceException("[7.3.2-获取预问诊对话记录]获取token失败"); + } JSONObject resultJson = post(url, params -> { - params.put("data", data); - params.put("header", header); - }, HCPreConsultHelper::setHeader); + params.put("request", request); + log.info("[7.3.2-获取预问诊对话记录] 入参:{}", JsonHelper.toJsonString(request)); + }, headers -> HCPreConsultHelper.setHeader(headers, token, request, openId)); + log.info("[7.3.2-获取预问诊对话记录] resp={}", resultJson); String code = resultJson.getString("retcode"); String message = resultJson.getString("retmsg"); String reqId = resultJson.getString("request_id"); if (!"0".equals(code)) { - log.error("[7.2.1 通过 HisToolLoginIn接口获取 token]失败[rid:{}] code={}, message={}", reqId, code, message); + log.error("[7.3.2-获取预问诊对话记录]失败[rid:{}] code={}, message={}", reqId, code, message); throw new ServiceException(message); } JSONObject dataJson = resultJson.getJSONObject("data"); if (dataJson == null) { - throw new ServiceException("[7.2.1 通过 HisToolLoginIn接口获取 token]data返回为空"); + throw new ServiceException("[7.3.2-获取预问诊对话记录]data返回为空"); } - return dataJson.getString("token"); + return dataJson; } + + /** * GetAppToken */ - public static String GetAppToken(String wxOpenId) throws ServiceException { + public static String getAppToken() { JSONObject resultJson = post("https://wechat.wecity.qq.com/trpcapi/THOpenAuth/GetAppToken", params -> { - params.put("appId", HCPreConsultConfig.APP_ID); + params.put("appId", HCPreConsultConfig.APP_ID); // 开发商 ID(平台分配) }, headers -> { - Map params = new HashMap<>(); + headers.set("Content-Type", "application/json"); String timestamp = String.valueOf(Instant.now().getEpochSecond()); - headers.add("Content-Type", "application/json"); - headers.add("Th-Auth-Type", "Th-Auth-Hc"); - headers.add("Th-Auth-Hc-HospitalId", HCPreConsultConfig.APP_HOSP_ID); - headers.add("Th-Auth-Hc-Timestamp", timestamp); - headers.add("Th-Auth-Hc-ChannelNum", "0"); - headers.add("Th-Auth-Hc-Relate-AppId", WeChatConfig.APP_ID); - headers.add("Th-Auth-Hc-Relate-OpenId", wxOpenId); - // appId + channelNum + hospitalId + timestamp + relateAppId -// String sign = HCPreConsultConfig.APP_ID + "0" + HCPreConsultConfig.APP_HOSP_ID + timestamp + WeChatConfig.APP_ID; -// calculateSign(headers, HCPreConsultConfig.APP_SECRET); + String sign = HCPreConsultConfig.calculateSign(timestamp); + + headers.set("Th-Auth-Type", "Th-Auth-Hc"); + headers.set("Th-Auth-Hc-HospitalId", HCPreConsultConfig.APP_HOSP_ID); + headers.set("Th-Auth-Hc-Timestamp", timestamp); + headers.set("Th-Auth-Hc-ChannelNum", "0"); +// headers.set("Th-Auth-Hc-Relate-AppId", WeChatConfig.APP_ID); + if (sign != null) { + headers.set("Th-Auth-Hc-Sign", sign); + } + + log.warn("[预问诊-医生端]获取token appId={}, headers={\"Th-Auth-Type\": \"{}\", \"Th-Auth-Hc-HospitalId\": \"{}\", \"Th-Auth-Hc-Timestamp\": \"{}\", \"Th-Auth-Hc-ChannelNum\": \"0\", \"Th-Auth-Hc-Sign\":\"{}\"}", + HCPreConsultConfig.APP_ID, "Th-Auth-Hc", HCPreConsultConfig.APP_HOSP_ID, timestamp, sign); }); - String code = resultJson.getString("retcode"); - String message = resultJson.getString("retmsg"); - String reqId = resultJson.getString("request_id"); + log.warn("[预问诊-医生端]获取token 响应数据:{}", JsonHelper.toJsonString(resultJson)); + String code = resultJson.getString("code"); + String message = resultJson.getString("message"); + String reqId = resultJson.getString("th-request-id"); if (!"0".equals(code)) { - log.error("[7.2.1 通过 HisToolLoginIn接口获取 token]失败[rid:{}] code={}, message={}", reqId, code, message); - throw new ServiceException(message); + log.error("[预问诊-医生端]获取token失败[rid:{}] code={}, message={}", reqId, code, message); + return null; } JSONObject dataJson = resultJson.getJSONObject("data"); if (dataJson == null) { - throw new ServiceException("[7.2.1 通过 HisToolLoginIn接口获取 token]data返回为空"); - } - return dataJson.getString("token"); - } - - - private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create(); - - /** - * 递归对 JSON 对象的 key 排序 - */ - private static JsonElement sortKeys(JsonElement element) { - if (element.isJsonObject()) { - JsonObject sorted = new JsonObject(); - TreeMap map = new TreeMap<>(); - for (Map.Entry entry : element.getAsJsonObject().entrySet()) { - map.put(entry.getKey(), sortKeys(entry.getValue())); - } - for (Map.Entry entry : map.entrySet()) { - sorted.add(entry.getKey(), entry.getValue()); - } - return sorted; - } else if (element.isJsonArray()) { - JsonArray sorted = new JsonArray(); - for (JsonElement item : element.getAsJsonArray()) { - sorted.add(sortKeys(item)); - } - return sorted; - } - return element; - } - - /** - * 格式化参数值为签名用字符串 - */ - private static String formatValue(Object value) { - if (value == null) return null; - if (value instanceof String) { - String s = (String) value; - return (s.isEmpty() || s.equals("null")) ? null : s; + log.error("[预问诊-医生端]获取token返回data为空"); + return null; } - if (value instanceof Boolean) return value.toString(); - if (value instanceof Number) return value.toString(); - // Map / List / JsonElement → JSON 紧凑序列化,key 排序 - JsonElement json = GSON.toJsonTree(value); - JsonElement sorted = sortKeys(json); - return GSON.toJson(sorted); + return dataJson.getString("app_token"); } - /** - * 计算签名:按 key 排序拼接 + appSecret → SHA256 → Base64 - */ - public static String calculateSign(Map params, String appSecret) throws Exception { - List keys = new ArrayList<>(params.keySet()); - Collections.sort(keys); - - StringBuilder sb = new StringBuilder(); - for (String key : keys) { - String fv = formatValue(params.get(key)); - if (fv == null) continue; - if (sb.length() > 0) sb.append("&"); - sb.append(key).append("=").append(fv); - } - sb.append(appSecret); - MessageDigest digest = MessageDigest.getInstance("SHA-256"); - byte[] hash = digest.digest(sb.toString().getBytes(StandardCharsets.UTF_8)); - return Base64.getEncoder().encodeToString(hash); - } } diff --git a/src/main/java/com/ynxbd/common/healthcard/config/HCPreConsultConfig.java b/src/main/java/com/ynxbd/common/healthcard/config/HCPreConsultConfig.java index 96595d9..10313f4 100644 --- a/src/main/java/com/ynxbd/common/healthcard/config/HCPreConsultConfig.java +++ b/src/main/java/com/ynxbd/common/healthcard/config/HCPreConsultConfig.java @@ -1,17 +1,22 @@ package com.ynxbd.common.healthcard.config; +import com.google.gson.*; +import com.ynxbd.common.config.EhCacheConfig; +import com.ynxbd.common.healthcard.HCPreConsultHelper; import com.ynxbd.common.healthcard.HCSignHelper; import com.ynxbd.common.helper.common.HMACHelper; import com.ynxbd.common.helper.common.XmlConfigHelper; +import com.ynxbd.wx.config.WeChatConfig; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; +import org.ehcache.Cache; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import javax.servlet.http.HttpServletRequest; import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.List; +import java.security.MessageDigest; +import java.util.*; // 预问诊 @@ -29,12 +34,20 @@ public class HCPreConsultConfig { public static final String HOSP_ID; // 医院ID public static final String SECRET_KEY; // 密钥:医生端问诊报告获取使用 public static final String DEV_OPEN_IDS; // 用于测试的openid + public static final String DOCTOR_PC_HOSP_ID; // 用于测试的openid + public static final String DOCTOR_PC_SECRET_KEY; // 用于测试的openid public static final boolean IS_DEV; public static final boolean IS_DEV_PUSH_SUBSCRIBE_MESSAGE; public static final boolean IS_DEBUG; public static final boolean IS_ENABLE; + public static final String BUSINESS_ID = "p_ipc"; + + private static final String TOKEN_CACHE_NAME = "doctor_token"; + // 缓存 + public static Cache CACHE; + static { XmlConfigHelper config = new XmlConfigHelper().read("hc-config.xml", "pre_consult"); IS_ENABLE = config.getBoolean("is_enable", false); @@ -52,13 +65,49 @@ public class HCPreConsultConfig { SECRET_KEY = config.getString("secret_key"); PARTNER_ID = config.getString("partner_id"); TOKEN = config.getString("token"); + // 医生 SCENE_PARTNER_ID = config.getString("scene_partner_id"); + DOCTOR_PC_HOSP_ID = config.getString("doctor_pc_hosp_id"); + DOCTOR_PC_SECRET_KEY = config.getString("doctor_pc_secret_key"); + DEV_OPEN_IDS = config.getString("dev_open_ids"); if (PARTNER_ID == null) { log.error("[预问诊]读取配置文件[hc-config.xml]失败"); } + createCache(); + } + + private synchronized static void createCache() { + if (CACHE == null) { + // 创建一个缓存实例(5分钟最大存活时间) + CACHE = EhCacheConfig.createCacheTTL(String.class, String.class, "hc_pre_consult", 7000L); + } + } + + public static String getCacheToken() { + if (CACHE.containsKey(TOKEN_CACHE_NAME)) { + return CACHE.get(TOKEN_CACHE_NAME); + } + + String appToken = HCPreConsultHelper.getAppToken(); + if (!ObjectUtils.isEmpty(appToken)) { + CACHE.put(TOKEN_CACHE_NAME, appToken); + } + return appToken; + } + + public static String getHisToolLoginCacheToken(String doctorId, String doctorName) { + if (CACHE.containsKey(doctorId)) { + return CACHE.get(doctorId); + } + + String appToken = HCPreConsultHelper.getH5DoctorLoginToken(doctorId, doctorName); + if (!ObjectUtils.isEmpty(appToken)) { + CACHE.put(doctorId, appToken); + } + return appToken; } public static boolean hasDevOpenId(String openid) { @@ -127,6 +176,109 @@ public class HCPreConsultConfig { } + /** + * 计算签名:按 key 排序拼接 + appSecret → SHA256 → Base64 + */ + public static String calculateSign(String timestamp) { + try { + String sb = "appId=" + APP_ID + + "&channelNum=" + "0" + + "&hospitalId=" + APP_HOSP_ID + + "×tamp=" + timestamp + + APP_SECRET; + + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] hash = digest.digest(sb.getBytes(StandardCharsets.UTF_8)); + return Base64.getEncoder().encodeToString(hash); + } catch (Exception e) { + log.error("[预问诊]签名生成失败:", e); + return null; + } + } + + + private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create(); + + /** + * 递归对 JSON 对象的 key 排序 + */ + private static JsonElement sortKeys(JsonElement element) { + if (element.isJsonObject()) { + JsonObject sorted = new JsonObject(); + TreeMap map = new TreeMap<>(); + for (Map.Entry entry : element.getAsJsonObject().entrySet()) { + map.put(entry.getKey(), sortKeys(entry.getValue())); + } + for (Map.Entry entry : map.entrySet()) { + sorted.add(entry.getKey(), entry.getValue()); + } + return sorted; + } else if (element.isJsonArray()) { + JsonArray sorted = new JsonArray(); + for (JsonElement item : element.getAsJsonArray()) { + sorted.add(sortKeys(item)); + } + return sorted; + } + return element; + } + + /** + * 格式化参数值为签名用字符串 + */ + private static String formatValue(Object value) { + if (value == null) return null; + if (value instanceof String) { + String s = (String) value; + return (s.isEmpty() || s.equals("null")) ? null : s; + } + if (value instanceof Boolean) return value.toString(); + if (value instanceof Number) return value.toString(); + // Map / List / JsonElement → JSON 紧凑序列化,key 排序 + JsonElement json = GSON.toJsonTree(value); + JsonElement sorted = sortKeys(json); + return GSON.toJson(sorted); + } + + + /** + * 计算签名:按 key 排序拼接 + appSecret → SHA256 → Base64 + */ + public static String calculateSign(Map request, String appToken, String openId, String timestamp) { + try { + Map params = new HashMap<>(); + params.put("appId", APP_ID); + params.put("appToken", appToken); + params.put("businessId", BUSINESS_ID); + params.put("channelNum", "0"); + params.put("hospitalId", APP_HOSP_ID); + params.put("relateAppId", WeChatConfig.APP_ID); + params.put("relateOpenId", openId); + params.put("timestamp", timestamp); + params.put("request", request); + + List keys = new ArrayList<>(params.keySet()); + Collections.sort(keys); + + StringBuilder sb = new StringBuilder(); + for (String key : keys) { + String fv = formatValue(params.get(key)); + if (fv == null) continue; + if (sb.length() > 0) sb.append("&"); + sb.append(key).append("=").append(fv); + } + sb.append(APP_SECRET); + log.warn("[sign]{}", sb); + + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] hash = digest.digest(sb.toString().getBytes(StandardCharsets.UTF_8)); + return Base64.getEncoder().encodeToString(hash); + } catch (Exception e) { + log.error("[预问诊]签名生成失败:", e); + return null; + } + } + // /** // * 签名验证 // */ diff --git a/src/main/java/com/ynxbd/common/service/InHospService.java b/src/main/java/com/ynxbd/common/service/InHospService.java index 640adcc..6ac07a0 100644 --- a/src/main/java/com/ynxbd/common/service/InHospService.java +++ b/src/main/java/com/ynxbd/common/service/InHospService.java @@ -185,14 +185,11 @@ public class InHospService { } List inHospList = resp.getDataMapList(InHospitalList.class, "Items", "Item"); - List medInHospList = new ArrayList<>(); - if (ObjectUtils.isEmpty(HisConfig.DEV_MED_OPENID_S) || HisConfig.hasDevMedOpenId(openid, null)) { // 无测试用户 ||是测试用户 - JsonResult medResp = new HisInHospDao().queryOutPatientRecords(openid, patientId, "1"); // 医保 - if (!medResp.success()) { - throw new ServiceException(medResp.getMessage()); - } - medInHospList = medResp.getDataMapList(InHospitalList.class, "Items", "Item"); + JsonResult medResp = new HisInHospDao().queryOutPatientRecords(openid, patientId, "1"); // 医保 + if (!medResp.success()) { + throw new ServiceException(medResp.getMessage()); } + List medInHospList = medResp.getDataMapList(InHospitalList.class, "Items", "Item"); List dataList = new ArrayList<>(); for (InHospitalList item : medInHospList) { diff --git a/src/main/resources/hc-config.xml b/src/main/resources/hc-config.xml index 305fe3d..ac9cab3 100644 --- a/src/main/resources/hc-config.xml +++ b/src/main/resources/hc-config.xml @@ -68,13 +68,15 @@ 34edf7cd14e646ae9c1bbca791b7b685 b26188e6142d43b88f01453853d52a0a 31737 + 800002723 + ZSQB8uErQydVVtTA 800002580 20009250 ##akgdaS!SwZRam^ c4a39049d4b1c29ffaa9a312687fdcfc - 100000861 + 100000861 oeso-t62kkoRwLVVkSkwmmjPfUXk