住院医保结算移除测试环境

预问诊调整token获取的配置和请求地址
debug
王绍全 2 days ago
parent 7cea8e6dc4
commit fc6f9261d2
  1. 11
      src/main/java/com/ynxbd/common/TestA.java
  2. 6
      src/main/java/com/ynxbd/common/action/healthcard/HCPreConsultAction.java
  3. 2
      src/main/java/com/ynxbd/common/dao/his/HisInHospDao.java
  4. 301
      src/main/java/com/ynxbd/common/healthcard/HCPreConsultHelper.java
  5. 156
      src/main/java/com/ynxbd/common/healthcard/config/HCPreConsultConfig.java
  6. 11
      src/main/java/com/ynxbd/common/service/InHospService.java
  7. 4
      src/main/resources/hc-config.xml

@ -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) {
}
}

@ -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);

@ -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); // [住院]医保

@ -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<String, Object> 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}&registeredid=${registeredid}&departmentId=${departmentId}&doctorId=${doctorId}&subHospitalId=&redirectUrl="
: "https://aimedical.wecity.qq.com/toolbox/prediagnosis.html?token=${token}&registeredid=${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<String, Object> 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<String, Object> 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<String, Object> request = new HashMap<>();
Map<String, Object> data = new HashMap<>();
data.put("partnerId", HCPreConsultConfig.PARTNER_ID);
data.put("caseId", registerId);
@ -243,182 +268,124 @@ public class HCPreConsultHelper {
Map<String, Object> 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}&registeredid=${registeredid}&departmentId=${departmentId}&doctorId=${doctorId}&subHospitalId=&redirectUrl="
: "https://aimedical.wecity.qq.com/toolbox/prediagnosis.html?token=${token}&registeredid=${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<String, Object> request = new HashMap<>();
Map<String, Object> 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<String, Object> 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<String, Object> 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<String, JsonElement> map = new TreeMap<>();
for (Map.Entry<String, JsonElement> entry : element.getAsJsonObject().entrySet()) {
map.put(entry.getKey(), sortKeys(entry.getValue()));
}
for (Map.Entry<String, JsonElement> 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<String, Object> params, String appSecret) throws Exception {
List<String> 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);
}
}

@ -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<String, String> 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 +
"&timestamp=" + 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<String, JsonElement> map = new TreeMap<>();
for (Map.Entry<String, JsonElement> entry : element.getAsJsonObject().entrySet()) {
map.put(entry.getKey(), sortKeys(entry.getValue()));
}
for (Map.Entry<String, JsonElement> 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<String, Object> request, String appToken, String openId, String timestamp) {
try {
Map<String, Object> 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<String> 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;
}
}
// /**
// * 签名验证
// */

@ -185,14 +185,11 @@ public class InHospService {
}
List<InHospitalList> inHospList = resp.getDataMapList(InHospitalList.class, "Items", "Item");
List<InHospitalList> 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<InHospitalList> medInHospList = medResp.getDataMapList(InHospitalList.class, "Items", "Item");
List<InHospitalList> dataList = new ArrayList<>();
for (InHospitalList item : medInHospList) {

@ -68,13 +68,15 @@
<app_id name="[开发者ID]">34edf7cd14e646ae9c1bbca791b7b685</app_id>
<app_secret name="[开发者密钥]">b26188e6142d43b88f01453853d52a0a</app_secret>
<app_hosp_id name="[机构ID]">31737</app_hosp_id>
<doctor_pc_hosp_id name="[医生端医院ID-邮件单独提供]">800002723</doctor_pc_hosp_id>
<doctor_pc_secret_key name="[医生端密钥-邮件单独提供]">ZSQB8uErQydVVtTA</doctor_pc_secret_key>
<!-- 腾讯提供 -->
<hosp_id>800002580</hosp_id>
<partner_id>20009250</partner_id>
<secret_key>##akgdaS!SwZRam^</secret_key>
<token>c4a39049d4b1c29ffaa9a312687fdcfc</token>
<scene_partner_id name="[scene_data]">100000861</scene_partner_id>
<scene_partner_id name="[scene_data|医生端]">100000861</scene_partner_id>
<dev_open_ids>oeso-t62kkoRwLVVkSkwmmjPfUXk</dev_open_ids>
</pre_consult>

Loading…
Cancel
Save