新增京颐支付类型

新增formData类型的参数接收和进行文件上传
部分配置调整
debug
王绍全 21 hours ago
parent 3d36e15159
commit 2a53cbf4fd
  1. 53
      src/main/java/com/ynxbd/common/TestA.java
  2. 12
      src/main/java/com/ynxbd/common/action/PatientAction.java
  3. 18
      src/main/java/com/ynxbd/common/action/XBDAction.java
  4. 235
      src/main/java/com/ynxbd/common/action/base/BaseAction.java
  5. 57
      src/main/java/com/ynxbd/common/action/healthcard/HCReportAction.java
  6. 71
      src/main/java/com/ynxbd/common/action/pay/JYPayAction.java
  7. 14
      src/main/java/com/ynxbd/common/action/pay/MedicalAction.java
  8. 4
      src/main/java/com/ynxbd/common/action/pay/PayAction.java
  9. 25
      src/main/java/com/ynxbd/common/action/test/TestAction.java
  10. 21
      src/main/java/com/ynxbd/common/bean/enums/MerchantEnum.java
  11. 19
      src/main/java/com/ynxbd/common/bean/form/FormBlob.java
  12. 73
      src/main/java/com/ynxbd/common/bean/form/FormData.java
  13. 63
      src/main/java/com/ynxbd/common/bean/pay/ReqOrder.java
  14. 4
      src/main/java/com/ynxbd/common/config/interceptor/MethodInterceptor.java
  15. 45
      src/main/java/com/ynxbd/common/helper/common/RSAHelper.java
  16. 6
      src/main/java/com/ynxbd/common/helper/common/SmsHelper.java
  17. 4
      src/main/java/com/ynxbd/common/helper/xbd/XBDHttpHelper.java
  18. 15
      src/main/java/com/ynxbd/common/helper/xbd/XbdConfigHelper.java
  19. 30
      src/main/java/com/ynxbd/common/service/PEISService.java
  20. 7
      src/main/java/com/ynxbd/common/service/PayService.java
  21. 113
      src/main/java/com/ynxbd/jy/bean/JYOrder.java
  22. 35
      src/main/java/com/ynxbd/jy/bean/JYRefund.java
  23. 39
      src/main/java/com/ynxbd/jy/bean/enums/JYBusinessTypeEnum.java
  24. 26
      src/main/java/com/ynxbd/jy/bean/enums/JYOrderTypeDetailEnum.java
  25. 44
      src/main/java/com/ynxbd/jy/bean/enums/JYOrderTypeEnum.java
  26. 36
      src/main/java/com/ynxbd/jy/helper/JYPayConfig.java
  27. 353
      src/main/java/com/ynxbd/jy/helper/JYPayHelper.java
  28. 64
      src/main/java/com/ynxbd/wx/config/MessagePushConfig.java
  29. 1
      src/main/java/com/ynxbd/wx/wxfactory/payment/WXPayUtility.java
  30. 10
      src/main/resources/copy/healthcard/石林县人民医院-hc-config.xml
  31. 9
      src/main/resources/hc-config.xml
  32. 11
      src/main/resources/jy-config.xml
  33. 4
      src/main/resources/jy-pay-config.xml
  34. 4
      src/main/resources/xbd-config.xml

@ -1,42 +1,31 @@
package com.ynxbd.common;
import com.ynxbd.wx.wxfactory.AesWxHelper;
import cn.hutool.core.util.HexUtil;
import com.ynxbd.common.helper.common.RSAHelper;
public class TestA {
// public static void main(String[] args) {
// String respXML = "<Response>\n" +
// "\t<TransactionCode>1002</TransactionCode>\n" +
// "\t<ResponseCode>0</ResponseCode>\n" +
// "\t<ResponseMessage>成功</ResponseMessage>\n" +
// "\t<PatientID>932606</PatientID>\n" +
// "\t<Empi_Id>300349719</Empi_Id>\n" +
// "\t<HISTrasNo>137087</HISTrasNo>\n" +
// "</Response>";
// JsonResult result = JsonResult.xmlToBean(respXML, JsonResultEnum.SYS_HIS);
// if (result == null) {
// return;
// }
// Patient patient = result.dataMapToBean(Patient.class);
// System.out.println(patient);
// }
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class TestA {
private static final String PUB_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5klqI5STWTcbfjR093j+hvCEjNlZMQscIJg8jxZGqKW84AdFmSqPWEPu9ilqP+QUASiVSZ1QevGr2DWODFZ8Zw35aDA2bqCEprUx81gDdVPO7H7Bij+r8zAg8fT2c0Bi5rFq0xWMEQiTI+CyWwc5prOpquJU/P5yauEAdkRzlDwIDAQAB";
// public static void main(String[] args) {
// System.out.println(AesWxHelper.encode("524404"));
//
// String dataJson = "[{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":3,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":3,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":3,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"},{\"deptCode\":\"94085\",\"deptName\":\"便民门诊\",\"description\":\"医师\",\"surplusSources\":4,\"title\":\"医师\",\"titleCode\":\"医师\"}]\n";
public static void main(String[] args) throws Exception{
String content = "533103198212184014";
byte[] bytes = RSAHelper.enBytePKCS1Padding(content, PUB_KEY);
System.out.println("【Java最终hex】:" + HexUtil.encodeHexStr(bytes));
}
//
// List<Doctor> doctors = JsonHelper.parseArray(dataJson, Doctor.class);
// doctors = new DoctorService().doctorListFilter(doctors);
// System.out.println(doctors);
// }
// public static void main(String[] args) {
// // System.out.println(AesWxHelper.encode("624091"));
//
// // System.out.println(AesWxHelper.decode("A25BF2DD5820B151B8AB2E333E05565E"));
// }
// public static void main(String[] args) throws Exception {
// String content = "533103198212184014";
// String encrypt = RSAHelper.enPKCS1Padding(content, PUB_KEY);
// System.out.println(HexUtil.encodeHexStr(encrypt));
// }
}

@ -278,13 +278,13 @@ public class PatientAction extends BaseAction {
return Result.error("[医共体]不支持无证绑定!");
}
fTel = getString("fTel");
fName = getString("fName");
fIDCardNo = getString("fIDCardNo");
fTel = getReqParamByKey("fTel");
fName = getReqParamByKey("fName");
fIDCardNo = getReqParamByKey("fIDCardNo");
mTel = getString("mTel");
mName = getString("mName");
mIDCardNo = getString("mIDCardNo");
mTel = getReqParamByKey("mTel");
mName = getReqParamByKey("mName");
mIDCardNo = getReqParamByKey("mIDCardNo");
Result result = new PatientService().noCardParamsValid(fTel, fName, fIDCardNo, mTel, mName, mIDCardNo);
if (!result.isOK()) {

@ -1,5 +1,7 @@
package com.ynxbd.common.action;
import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.asymmetric.RSA;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ynxbd.common.action.base.BaseAction;
@ -10,8 +12,9 @@ import com.ynxbd.common.bean.xbd.MedicalRecord;
import com.ynxbd.common.config.interceptor.AesDecode;
import com.ynxbd.common.helper.common.Base64Helper;
import com.ynxbd.common.helper.common.JsonHelper;
import com.ynxbd.common.helper.common.RSAHelper;
import com.ynxbd.common.helper.xbd.XBDEnum;
import com.ynxbd.common.helper.xbd.XBDHelper;
import com.ynxbd.common.helper.xbd.XbdConfigHelper;
import com.ynxbd.common.helper.xbd.XBDHttpHelper;
import com.ynxbd.common.result.Result;
import com.ynxbd.common.result.ResultEnum;
@ -25,6 +28,7 @@ import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.List;
/**
@ -54,7 +58,7 @@ public class XBDAction extends BaseAction {
public Result cloudFilm(String info) {
try {
log.info("[云胶片]info={}", info);
String path = XBDHelper.outTeamDao.getCloudFilmPath(info);
String path = XbdConfigHelper.outTeamDao.getCloudFilmPath(info);
return Result.success(path);
} catch (Exception e) {
log.error("[云胶片]{}", e.getMessage());
@ -280,20 +284,16 @@ public class XBDAction extends BaseAction {
}
/**
* 查询体检报告
* 查询体检影像报告
*/
@Action("getPeisByCardNo")
public Result getPeisByCardNo(@AesDecode String cardNo, String begDate, String endDate) {
log.info("[查询体检记录] cardNo={}, begDate={}, endDate={}", cardNo, begDate, endDate);
log.info("[体检影像报告]查询 cardNo={}, begDate={}, endDate={}", cardNo, begDate, endDate);
if (ObjectUtils.isEmpty(cardNo) || ObjectUtils.isEmpty(begDate) || ObjectUtils.isEmpty(endDate)) {
return Result.error(ResultEnum.PARAM_IS_DEFECT);
}
String encode = Base64Helper.encode(cardNo);
if (ObjectUtils.isEmpty(encode)) {
return Result.error(ResultEnum.PARAM_IS_INVALID);
}
try {
JSONArray dataList = new PEISService().queryPEISRecordByCardNo(encode, begDate, endDate);
JSONArray dataList = new PEISService().queryPEISRecordByCardNo(cardNo, begDate, endDate);
for (int i = 0; i < dataList.size(); i++) {
JSONObject dataItem = dataList.getJSONObject(i);
String eid = dataItem.getString("eid");

@ -1,6 +1,8 @@
package com.ynxbd.common.action.base;
import com.alibaba.fastjson.JSONObject;
import com.ynxbd.common.bean.form.FormBlob;
import com.ynxbd.common.bean.form.FormData;
import com.ynxbd.common.helper.common.HttpHelper;
import com.ynxbd.common.helper.common.JsonHelper;
import com.ynxbd.wx.wxfactory.AesWxHelper;
@ -9,6 +11,8 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.action.ServletRequestAware;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper;
import org.apache.struts2.dispatcher.multipart.UploadedFile;
import org.slf4j.MDC;
import javax.servlet.ServletContext;
@ -17,8 +21,9 @@ import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.*;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.nio.file.Files;
import java.util.*;
import java.util.function.Function;
/**
@ -45,7 +50,7 @@ public class BaseAction implements Serializable, ServletRequestAware {
MDC.remove("ip");
MDC.put("ip", HttpHelper.getIpAddress(request));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
log.error("", e);
}
this.request = request;
@ -80,60 +85,61 @@ public class BaseAction implements Serializable, ServletRequestAware {
return ServletActionContext.getServletContext();
}
protected String getString(String param) {
String parameter = this.request.getParameter(param);
if ("".equals(parameter)) {
return null;
}
return parameter;
}
protected String decodeReqString(String param) {
return AesWxHelper.decode(param);
}
protected Integer getInteger(String param) {
try {
String val = this.request.getParameter(param);
return StringUtils.isEmpty(val) ? null : Integer.valueOf(val);
} catch (Exception e) {
protected String getReqParamByKey(String key) {
String val = this.request.getParameter(key);
if ("".equals(val)) {
return null;
}
return val;
}
protected Long getLong(String param) {
/**
* 通用转换方法
*
* @param key key
* @param clazz 目标类型 Integer.class / Long.class / BigDecimal.class ...
* @return 转换后对象/格式错误返回null
*/
@SuppressWarnings("unchecked")
protected <T> T getReqParamByKey(String key, Class<T> clazz) {
try {
String val = this.request.getParameter(param);
return StringUtils.isEmpty(val) ? null : Long.valueOf(val);
} catch (Exception e) {
if (clazz == null) {
return null;
}
}
protected Double getDouble(String param) {
try {
String val = this.request.getParameter(param);
return StringUtils.isEmpty(val) ? null : Double.valueOf(val);
} catch (Exception e) {
String val = this.request.getParameter(key);
if (StringUtils.isEmpty(val)) {
return null;
}
}
val = val.trim();
protected BigDecimal getBigDecimal(String param) {
try {
String val = this.request.getParameter(param);
return StringUtils.isEmpty(val) ? null : new BigDecimal(val);
} catch (Exception e) {
Function<String, ?> converter;
if (String.class == clazz) {
return clazz.cast(val);
} else if (Integer.class == clazz) {
converter = Integer::valueOf;
} else if (Long.class == clazz) {
converter = Long::valueOf;
} else if (Double.class == clazz) {
converter = Double::valueOf;
} else if (BigDecimal.class == clazz) {
converter = BigDecimal::new;
} else if (Boolean.class == clazz) {
if (!val.equalsIgnoreCase("true") && !val.equalsIgnoreCase("false")) {
return null;
}
converter = Boolean::valueOf;
} else {
log.error("不支持的类型:{}", clazz.getName());
return null;
}
protected Boolean getBoolean(String param) {
try {
String val = this.request.getParameter(param);
return StringUtils.isEmpty(val) ? null : Boolean.valueOf(val);
Object obj = converter.apply(val);
return (T) obj;
} catch (Exception e) {
return null;
}
@ -218,4 +224,157 @@ public class BaseAction implements Serializable, ServletRequestAware {
Map<String, String> params = reqParamsToMap();
return JsonHelper.parseObject(JsonHelper.toJsonString(params), clazz);
}
/**
* Struts2获取FormData[表单参数+上传文件]
*/
protected FormData getReqFormData() {
MultiPartRequestWrapper multiWrapper = null;
if (request instanceof MultiPartRequestWrapper) {
multiWrapper = (MultiPartRequestWrapper) request;
}
if (multiWrapper == null) {
log.info("[请求类型]不是-multipart/form-data");
return null;
}
if (multiWrapper.hasErrors()) { // 检查上传解析是否报错
log.error("[multipart解析]存在错误:{}", multiWrapper.getErrors());
return null;
}
FormData formData = new FormData();
Map<String, String> params = new HashMap<>();
Map<String, FormBlob> files = new HashMap<>();
// ========= 读取普通表单文本参数 =========
Enumeration<?> parameterNames = multiWrapper.getParameterNames();
String field;
String[] values;
while (parameterNames.hasMoreElements()) {
field = (String) parameterNames.nextElement();
values = multiWrapper.getParameterValues(field);
if (values != null && values.length > 0) {
params.put(field, values[0]);
}
}
// ========= 读取所有上传文件 =========
Enumeration<String> fileFieldEnum = multiWrapper.getFileParameterNames();
String fileName;
FormBlob formBlob;
UploadedFile[] uploadedFiles;
while (fileFieldEnum.hasMoreElements()) {
field = fileFieldEnum.nextElement();
uploadedFiles = multiWrapper.getFiles(field);
if (uploadedFiles == null) {
continue;
}
for (UploadedFile uf : uploadedFiles) {
if (!uf.isFile()) {
continue;
}
formBlob = new FormBlob();
fileName = uf.getOriginalName();
if (fileName != null) { // 清除IE浏览器全路径文件名
int idx = fileName.lastIndexOf("\\");
if (idx > 0) {
fileName = fileName.substring(idx + 1);
}
}
formBlob.setFileName(fileName);
formBlob.setContentType(uf.getContentType());
try {
byte[] data = null;
Object contentObj = uf.getContent();
if (contentObj instanceof byte[]) {
data = (byte[]) contentObj;
} else if (contentObj instanceof File) {
File tempFile = (File) contentObj;
data = Files.readAllBytes(tempFile.toPath());
}
if (data != null) {
formBlob.setContent(data);
files.put(field, formBlob);
}
} catch (Exception e) {
log.error("解析上传文件失败,field={}, fileName={}", field, fileName, e);
}
}
}
formData.setData(params);
formData.setFiles(files);
return formData;
}
// /**
// * 获取FormData
// */
// protected FormData getFormData() {
// try {
// boolean isMultipart = ServletFileUpload.isMultipartContent(request);
// if (!isMultipart) {
// System.out.println("[请求类型]不是multipart/form-data");
// return null;
// }
//
// // 判断是否multipart请求(使用Struts工具方法)
// MultiPartRequestWrapper multiWrapper = RequestUtils.getMultiPartRequestWrapper(request);
// if (multiWrapper == null) {
// System.out.println("[请求类型]不是multipart/form-data");
// return null;
// }
//
// FormData formData = new FormData();
// Map<String, String> params = new HashMap<>();
// ArrayList<FormBlob> files = new ArrayList<>();
//
// String a = null;
// // 1. 获取所有普通表单字段
// Enumeration<String> paramNames = multiWrapper.getParameterNames();
//
// String a = request.getParameter("a");
// System.out.println(a);
//
// // 初始化解析器
// FileItemFactory factory = new DiskFileItemFactory();
// ServletFileUpload upload = new ServletFileUpload(factory);
// // 限制最大文件 10MB,根据截图业务调整
// upload.setFileSizeMax(10 * 1024 * 1024L);
//
// List<FileItem> itemList = upload.parseRequest(request);
// FormData formData = new FormData();
//
// Map<String, String> params = new HashMap<>();
// ArrayList<FormBlob> files = new ArrayList<>();
// // 遍历所有上传项
// FormBlob formBlob;
// for (FileItem item : itemList) {
// System.out.println(item.getFieldName());
// if (item.isFormField()) { // 普通文本参数
// params.put(item.getFieldName(), item.getString("UTF-8"));
// } else {
// formBlob = new FormBlob(); // 文件
// formBlob.setFileName(item.getName());
// formBlob.setContent(item.get());
// formBlob.setContentType(item.getContentType());
// files.add(formBlob);
// }
// }
// formData.setFiles(files);
// formData.setData(params);
//
// return formData;
// } catch (Exception e) {
// log.error(e.getMessage());
// return null;
// }
// }
//
}

@ -2,11 +2,15 @@ package com.ynxbd.common.action.healthcard;
import com.alibaba.fastjson.JSONObject;
import com.ynxbd.common.action.base.BaseAction;
import com.ynxbd.common.bean.form.FormBlob;
import com.ynxbd.common.bean.form.FormData;
import com.ynxbd.common.config.healthcard.HCReportConfig;
import com.ynxbd.common.config.healthcard.HCSignHelper;
import com.ynxbd.common.config.interceptor.AesDecode;
import com.ynxbd.common.helper.common.Base64Helper;
import com.ynxbd.common.helper.http.OkHttpHelper;
import com.ynxbd.common.result.Result;
import com.ynxbd.common.result.ResultEnum;
import com.ynxbd.wx.wxfactory.AesWxHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
@ -18,42 +22,65 @@ import java.util.Map;
@Namespace("/hc_report")
public class HCReportAction extends BaseAction {
// 报告解读:https://open.ai.tengmed.com/openAccess/docs/access#6
@Action("pushUserReport")
public Result pushUserReport(@AesDecode String patientId, String reportId, String healthCardId, String msgId, String reportContent) {
public Result pushUserReport() {
FormData formData = getReqFormData();
if (formData == null) {
return Result.error(ResultEnum.PARAM_IS_BLANK);
}
FormBlob reportFile = formData.getFiles().get("reportContent");
if (reportFile == null || reportFile.getContent() == null) {
return Result.error(ResultEnum.PARAM_IS_BLANK);
}
String reportContentBase64 = Base64Helper.encode(reportFile.getContent());
if (reportContentBase64 == null) {
return Result.error(ResultEnum.PARAM_IS_INVALID);
}
String patientId = AesWxHelper.decode(formData.getParamByKey("patientId", String.class));
String healthCardId = formData.getParamByKey("healthCardId", String.class);
String reportId = formData.getParamByKey("reportId", String.class);
String msgId = formData.getParamByKey("msgId", String.class);
log.info("[报告解读] msgId={}, patientId={}, reportId={}", msgId, patientId, reportId);
if (patientId == null || healthCardId == null || reportId == null || msgId == null) {
return Result.error(ResultEnum.PARAM_IS_DEFECT);
}
String url = HCReportConfig.IS_DEV
? "https://med-biz-pre.wecity.qq.com/api/report/PushUserReport/"
: "https://med-biz.wecity.qq.com/api/report/PushUserReport/";
HCSignHelper config = HCReportConfig.createSign();
String requestId = config.getRequestId();
Map<String, Object> reqHead = new HashMap<>();
reqHead.put("requestId", requestId);
Map<String, Object> textReportInfo = new HashMap<>();
// Map<String, Object> textReportInfo = new HashMap<>();
// Map<String, Object> patientInfo = new HashMap<>();
// Map<String, Object> reportInfo = new HashMap<>();
// partnerId:合作方ID 腾讯健康提供
JSONObject jsonObject = OkHttpHelper.postJson(url + HCReportConfig.PARTNER_ID, params -> {
params.put("reqHead", reqHead);
params.put("hospitalId", HCReportConfig.HOSP_ID);
params.put("outerId", reportId);
params.put("healthCardId", healthCardId);
params.put("patientId", patientId);
params.put("msgId", msgId);
params.put("reportFileType", 2); // [ 1:pdf;2:图片;3:文本]
params.put("reportContent", reportContent); // 报告内容:报告文件base64编码、体积需要在30MB以内 当reportFileType 取值为 1, 2时,将报告文件base64编码放在该字段
params.put("textReportInfo", textReportInfo); // 当reportFileType 取值为 3 时,将文本报告内容放下该字段。
JSONObject jsonObject = OkHttpHelper.postJson(url + HCReportConfig.PARTNER_ID, req -> {
req.put("reqHead", reqHead);
req.put("hospitalId", HCReportConfig.HOSP_ID);
req.put("outerId", reportId);
req.put("healthCardId", healthCardId);
req.put("patientId", patientId);
req.put("msgId", msgId);
req.put("reportFileType", 2); // [ 1:pdf;2:图片;3:文本]
req.put("reportContent", reportContentBase64); // 报告内容:报告文件base64编码、体积需要在30MB以内 当reportFileType 取值为 1, 2时,将报告文件base64编码放在该字段
// req.put("textReportInfo", textReportInfo); // 当reportFileType 取值为 3 时,将文本报告内容放下该字段。
// log.warn("[报告解读] req={}", JsonHelper.toJsonString(req));
}, headers -> {
headers.add("Content-Type", "application/json");
headers.add("god-portal-signature", config.getSignature());
headers.add("god-portal-timestamp", config.getTimestamp());
headers.add("god-portal-request-id", requestId);
});
log.warn("[报告解读] resp={}", jsonObject);
log.info("[报告解读] msgId={}, patientId={}, reportId={}, resp={}", msgId, patientId, reportId, jsonObject);
return Result.success();
}
}

@ -0,0 +1,71 @@
package com.ynxbd.common.action.pay;
import com.ynxbd.bcm.config.BCMHelper;
import com.ynxbd.common.action.base.BaseAction;
import com.ynxbd.common.bean.pay.PayResult;
import com.ynxbd.common.helper.common.DateHelper;
import com.ynxbd.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import java.math.BigDecimal;
@Slf4j
@Namespace("/jy_pay")
public class JYPayAction extends BaseAction {
/**
* 交行处方支付通知
*
* @return 是否成功
*/
@Action("notify")
public Result notify(String notifyType) {
// if (ObjectUtils.isEmpty(notifyType)) {
// Result.respJson(BCMHelper.respError(String.format("【京颐】获取回调参数失败,结束请求 notifyType={%s}", notifyType)));
// return null;
// }
try {
PayResult notifyInfo = BCMHelper.payNotify(request);
Result.respJson(BCMHelper.respOk()); // 成功
String openid = notifyInfo.getOpenid();
String bankTransNo = notifyInfo.getTransId();
String outTradeNo = notifyInfo.getOutTradeNo();
BigDecimal totalFee = notifyInfo.getTotalFee();
String payInfo = notifyInfo.getInfo();
String payDate = DateHelper.getCurDate();
String payTime = DateHelper.getCurTime();
String bankMerchantNo = notifyInfo.getBankMerchantNo();
log.info("【京颐】[{}] 收到通知 outTradeNo={}, bankTransNo={}, bankMerchantNo={}", notifyType, outTradeNo, bankTransNo, bankMerchantNo);
switch (PEnum.toEnum(notifyType)) {
case RECIPE:
// openid = new RecipeService().queryOpenIdByOutTradeNo(outTradeNo);
// new RecipeService().recipeListPay(MerchantEnum.JY, totalFee.toString(), openid, outTradeNo, bankTransNo, bankMerchantNo, payDate, payTime, payInfo);
//
break;
case REG: // 挂号
// try {
// openid = new RegService().queryOpenIdByOutTradeNo(outTradeNo);
// new RegService().regPaidNotify(MerchantEnum.JY, totalFee, openid, bankTransNo, outTradeNo, bankMerchantNo, payDate, payTime, payInfo, new Date());
// } catch (ServiceException e) {
// log.info("【京颐]挂号通知错误 outTradeNo={}, bankTransNo={}, message={}", outTradeNo, bankTransNo, e.getMessage());
// }
break;
default:
log.info("【京颐】通知类型错误,结束请求");
break;
}
} catch (Exception e) {
log.error(e.getMessage());
}
return null;
}
}

@ -63,7 +63,7 @@ public class MedicalAction extends BaseAction {
MedicalInfo medicalInfo;
switch (PEnum.toEnum(callNo)) {
case REG:
Boolean isSplitTime = getBoolean("isSplitTime");
Boolean isSplitTime = getReqParamByKey("isSplitTime", Boolean.class);
Register reg = new Register().getRegParams(new RequestParams(request), true);
if ("*".equals(reg.getRegCode())) {
@ -77,10 +77,10 @@ public class MedicalAction extends BaseAction {
break;
case RECIPE:
String ybAttrib = getString("ybAttrib");
String ybBZCode = getString("ybBZCode");
String ybBZName = getString("ybBZName");
String recipeJson = getString("recipeJson"); // 处方JSON集 [{ recipeId: item.id, recipeFee: item.amount }]
String ybAttrib = getReqParamByKey("ybAttrib");
String ybBZCode = getReqParamByKey("ybBZCode");
String ybBZName = getReqParamByKey("ybBZName");
String recipeJson = getReqParamByKey("recipeJson"); // 处方JSON集 [{ recipeId: item.id, recipeFee: item.amount }]
log.info("[医保-处方]上传明细下单 treatNum={}, ybAttrib={}, ybBZCode={}, ybBZName={}, recipeJson={}", treatNum, ybAttrib, ybBZCode, ybBZName, recipeJson);
if (treatNum == null || recipeJson == null) {
return Result.error(ResultEnum.PARAM_IS_DEFECT);
@ -207,11 +207,11 @@ public class MedicalAction extends BaseAction {
familyType, familyName, familyCardNo, medicalCardInstId, medicalCardId);
case RECIPE:
String recipeJson = getString("recipeJson");
String recipeJson = getReqParamByKey("recipeJson");
if (recipeJson == null) {
return Result.error(ResultEnum.PARAM_IS_BLANK);
}
String payWay = getString("payWay");
String payWay = getReqParamByKey("payWay");
return new MedicalService().createRxOrder(payCode, payOpenId, openid, patientId, cardNo, realName, ip,
payOrdId, payAuthNo, mdTrtId, chrgBchno, mdUserId,
totalFee, acctFee, hifpFee, insuranceFee, cashFee,

@ -13,7 +13,7 @@ import com.ynxbd.common.dao.his.HisRecipeDao;
import com.ynxbd.common.dao.sys.SysUserDao;
import com.ynxbd.common.helper.common.*;
import com.ynxbd.common.helper.his.HisHelper;
import com.ynxbd.common.helper.xbd.XBDHelper;
import com.ynxbd.common.helper.xbd.XbdConfigHelper;
import com.ynxbd.common.result.JsonResult;
import com.ynxbd.common.result.Result;
import com.ynxbd.common.result.ResultEnum;
@ -887,7 +887,7 @@ public class PayAction extends BaseAction {
return Result.error(ResultEnum.PAY_TYPE_ERROR);
}
if (ObjectUtils.isEmpty(XBDHelper.PEIS_URL)) {
if (ObjectUtils.isEmpty(XbdConfigHelper.PEIS_URL)) {
return Result.error(ResultEnum.SYSTEM_CONFIG_ERROR);
}

@ -1,27 +1,26 @@
package com.ynxbd.common.action.test;
import com.ynxbd.common.action.base.BaseAction;
import com.ynxbd.common.bean.pay.Register;
import com.ynxbd.common.bean.form.FormBlob;
import com.ynxbd.common.bean.form.FormData;
import com.ynxbd.common.bean.sms.SmsTempEnum;
import com.ynxbd.common.helper.common.Base64Helper;
import com.ynxbd.common.helper.common.DateHelper;
import com.ynxbd.common.helper.common.SmsHelper;
import com.ynxbd.common.result.Result;
import com.ynxbd.common.result.ResultEnum;
import com.ynxbd.common.result.ServiceException;
import com.ynxbd.wx.config.MessagePushConfig;
import com.ynxbd.wx.config.TZReserveConfig;
import com.ynxbd.wx.config.WeChatConfig;
import com.ynxbd.wx.wxfactory.WxMedHelper;
import com.ynxbd.wx.wxfactory.WxPayHelper;
import com.ynxbd.wx.wxfactory.medical.WxMedConfig;
import com.ynxbd.wx.wxfactory.medical.models.WxMedOrder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;
/**
* @Author wsq
@ -126,25 +125,23 @@ public class TestAction extends BaseAction {
@Action("r_test")
public Result r_test() throws ServiceException {
String url = WeChatConfig.getHttpsBaseURL() + "ali_qrcode" + "?p=123";
System.out.println(url);
System.out.println();
return Result.redirect("/wx/test02/log_test");
return Result.success();
}
@Action("wx_push_test")
public Result wx_push_test() {
System.out.println("HOST_URL:" + MessagePushConfig.HOST_URL);
System.out.println("[挂号]缴费通知:" + MessagePushConfig.REG_PAID_URL);
System.out.println("[挂号]取消预约:" + MessagePushConfig.REG_CANCEL_URL);
System.out.println("[挂号]AI:" + MessagePushConfig.REG_AI_URL);
System.out.println("[挂号]缴费通知:" + MessagePushConfig.REG_PAID_API);
System.out.println("[挂号]取消预约:" + MessagePushConfig.REG_CANCEL_API);
System.out.println("[挂号]AI:" + MessagePushConfig.REG_AI_API);
System.out.println("[处方]缴费通知:" + MessagePushConfig.RX_PAID_URL);
System.out.println("[处方]缴费通知:" + MessagePushConfig.RX_PAID_API);
System.out.println("产科建档:" + MessagePushConfig.OBS_DOCUMENT_URL);
System.out.println("产科建档:" + MessagePushConfig.OBS_DOCUMENT_API);
return Result.success();
}
// @Action("lock")
// public String lock() {
// return Result.success(update());

@ -58,6 +58,14 @@ public enum MerchantEnum {
"",
WX.PAY_WAY_IN, WX.PAY_WAY_QR, WX.PAY_WAY_MICRO),
ALI_MEDICAL("ali_medical", "【支付宝医保】", AliConfig.APP_ID, ALI.OUT_TRADE_NO_PREFIX,
AliMedConfig.IS_DEV,
"3",
"25,26,27,28,29,30",
"ali_pay/medical_notify",
"",
"10", "11", "12"),
BCM("bcm", "【交行】", "", "BCM",
false,
"4",
@ -66,14 +74,13 @@ public enum MerchantEnum {
"",
"20", "21", "22"),
ALI_MEDICAL("ali_medical", "【支付宝医保】", AliConfig.APP_ID, ALI.OUT_TRADE_NO_PREFIX,
AliMedConfig.IS_DEV,
"3",
"25,26,27,28,29,30",
"ali_pay/medical_notify",
JY("jy", "【京颐】", "", "JY",
false,
"4",
"",
"10", "11", "12"),
"jy_pay/notify",
"",
WX.PAY_WAY_IN, WX.PAY_WAY_QR, WX.PAY_WAY_MICRO),
;

@ -0,0 +1,19 @@
package com.ynxbd.common.bean.form;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
@NoArgsConstructor
public class FormBlob {
// 内容
private byte[] content;
// 文件名
private String fileName;
// 内容类型
private String contentType;
}

@ -0,0 +1,73 @@
package com.ynxbd.common.bean.form;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
@Getter
@Setter
@ToString
@NoArgsConstructor
@Slf4j
public class FormData {
private Map<String, FormBlob> files;
private Map<String, String> data;
/**
* 通用转换方法
*
* @param param key
* @param clazz 目标类型 Integer.class / Long.class / BigDecimal.class ...
* @return 转换后对象/格式错误返回null
*/
@SuppressWarnings("unchecked")
public <T> T getParamByKey(String param, Class<T> clazz) {
try {
if (clazz == null) {
return null;
}
String val = data.get(param);
if (StringUtils.isEmpty(val)) {
return null;
}
val = val.trim();
Function<String, ?> converter;
if (String.class == clazz) {
return clazz.cast(val);
} else if (Integer.class == clazz) {
converter = Integer::valueOf;
} else if (Long.class == clazz) {
converter = Long::valueOf;
} else if (Double.class == clazz) {
converter = Double::valueOf;
} else if (BigDecimal.class == clazz) {
converter = BigDecimal::new;
} else if (Boolean.class == clazz) {
if (!val.equalsIgnoreCase("true") && !val.equalsIgnoreCase("false")) {
return null;
}
converter = Boolean::valueOf;
} else {
log.error("不支持的类型:{}", clazz.getName());
return null;
}
Object obj = converter.apply(val);
return (T) obj;
} catch (Exception e) {
return null;
}
}
}

@ -0,0 +1,63 @@
package com.ynxbd.common.bean.pay;
import com.ynxbd.jy.bean.JYOrder;
import com.ynxbd.jy.bean.enums.JYBusinessTypeEnum;
import com.ynxbd.jy.bean.enums.JYOrderTypeEnum;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
import java.math.BigDecimal;
// 医保请求参数
@Setter
@Getter
@ToString
@NoArgsConstructor
public class ReqOrder implements Serializable {
private static final long serialVersionUID = 2026072810440001L;
// 现金部分
public BigDecimal cashFee;
// 医保金额-个账 + 统筹支付金额
public BigDecimal insuranceFee;
// 医保-个人账户支付金额
public BigDecimal acctFee;
// 医保-统筹支付金额
public BigDecimal hifpFee;
// 订单金额
public BigDecimal totalFee;
// ip
public String ip;
// 回退地址
public String returnUrl;
// 医院HIS系统订单号
public String serialNo;
// 参考医保结构体(医疗机构透传医保)
public String requestContent;
// 亲情移动支付时
public String extendInfo;
// 门诊号 | 住院号
public String treatNum;
// 患者id
public String patientId;
// 患者姓名
public String patientName;
//
public String patientAge;
// 患者性别。综合支付对应用权限控制是否必传 1男 2女 9其他 最大不超过4位
public String patientGender;
public String patientIdCardNo;
public String patientTel;
public JYOrder jyOrder;
}

@ -4,6 +4,7 @@ import com.ynxbd.common.helper.common.AesHelper;
import com.ynxbd.common.helper.common.ErrorHelper;
import com.ynxbd.common.helper.common.JsonHelper;
import com.ynxbd.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.struts2.ActionContext;
import org.apache.struts2.ActionInvocation;
@ -21,6 +22,7 @@ import java.util.List;
/**
* 方法拦截器
*/
@Slf4j
public class MethodInterceptor extends org.apache.struts2.interceptor.AbstractInterceptor {
@ -133,7 +135,7 @@ public class MethodInterceptor extends org.apache.struts2.interceptor.AbstractIn
}
return "SUCCESS";
} catch (Exception e) {
e.printStackTrace();
log.error("", e);
if (e.getMessage() == null) {
System.out.println("异常1");
Throwable cause = e.getCause();

@ -106,7 +106,6 @@ public class RSAHelper {
}
/**
* RSA私钥解密
*
@ -154,6 +153,50 @@ public class RSAHelper {
return null;
}
public static PublicKey getPublicKey(String base64PubKey) {
try {
byte[] keyBytes = java.util.Base64.getDecoder().decode(base64PubKey);
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(spec);
} catch (Exception e) {
log.error("", e);
return null;
}
}
/**
* PKCS8 格式私钥字符串转 PrivateKey
*
* @param privateKeyStr /不带头尾标记的base64私钥
* @return PrivateKey
*/
public static PrivateKey getPrivateKey(String privateKeyStr) {
try {
// 去除头尾标记、换行、空格
String privateKeyPEM = privateKeyStr
.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s+", "");
byte[] keyBytes = java.util.Base64.getDecoder().decode(privateKeyPEM);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(spec);
} catch (Exception e) {
log.error("", e);
return null;
}
}
// 加密方法(PKCS#1 v1.5填充)
public static byte[] enBytePKCS1Padding(String content, String base64PublicKey) throws Exception {
PublicKey publicKey = getPublicKey(base64PublicKey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] rawData = content.getBytes(StandardCharsets.UTF_8);
return cipher.doFinal(rawData);
}
// 加密方法(PKCS#1 v1.5填充)
public static String enPKCS1Padding(String plaintext, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");

@ -178,7 +178,11 @@ public class SmsHelper {
* @param smsTemplate 模板参数
*/
public static boolean sendAli(String template, String tel, String signName, SmsTemplate smsTemplate) {
if (StringUtils.isEmpty(signName)) {
if (ObjectUtils.isEmpty(tel)) {
System.out.println("[短信]tel参数为空!");
return false;
}
if (ObjectUtils.isEmpty(signName)) {
signName = SIGN_NAME;
}

@ -78,7 +78,7 @@ public class XBDHttpHelper {
private static String UsePost(String methodName, RequestBody requestBody) {
OkHttpClient httpClient = OkHttpHelper.creatClient();
Headers.Builder headersBuilder = new Headers.Builder();
HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(XBDHelper.CASEBOOK_URL + "/api/SqlContext/PostMethodByNameEncryption")).newBuilder();
HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(XbdConfigHelper.CASEBOOK_URL + "/api/SqlContext/PostMethodByNameEncryption")).newBuilder();
try (Response response = httpClient.newCall(new Request.Builder().url(urlBuilder.build()).post(requestBody).headers(headersBuilder.build()).build()).execute()) {
JSONObject respJson = respFilter(response, methodName);
String code = respJson.getString("Code");
@ -171,7 +171,7 @@ public class XBDHttpHelper {
private static String UseGet(String methodName, Object paramDic) {
try {
OkHttpClient httpClient = OkHttpHelper.creatClient();
HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(XBDHelper.CASEBOOK_URL + "/api/SqlContext/ExecMethodByNameEncryption")).newBuilder();
HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(XbdConfigHelper.CASEBOOK_URL + "/api/SqlContext/ExecMethodByNameEncryption")).newBuilder();
// 加密序列化
String paramJson = JSONObject.toJSONString(paramDic == null ? "" : paramDic);
log.info("[病历GET]未加密前get请求入参:[methodName:{}] {}", methodName, paramJson);

@ -11,7 +11,7 @@ import lombok.extern.slf4j.Slf4j;
* @date 2023/3/30 17:02
*/
@Slf4j
public class XBDHelper {
public class XbdConfigHelper {
private static final String PACS_CLOUD_URL;
public static final String CASEBOOK_URL;
public static final String PEIS_URL;
@ -19,19 +19,16 @@ public class XBDHelper {
public static OutTeamDao outTeamDao;
static {
XmlConfigHelper config = new XmlConfigHelper().read("xbd-config.xml", "tz_sms");
XmlConfigHelper config = new XmlConfigHelper().read("xbd-config.xml", "xbd");
PACS_CLOUD_URL = config.getString("pacs_cloud_url");
PACS_CLOUD_URL = config.getString("pacs_cloud_url", "");
CASEBOOK_URL = config.getString("casebook_url");
CASEBOOK_URL = config.getString("casebook_url", "");
PEIS_URL = config.getString("peis_url", "");
PEIS_URL = config.getString("peis_url");
if (PACS_CLOUD_URL == null) {
log.error("新八达200团队配置文件读取失败");
}
outTeamDao = new OutTeamDao(PACS_CLOUD_URL);
}
}

@ -1,5 +1,6 @@
package com.ynxbd.common.service;
import cn.hutool.core.util.HexUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ynxbd.common.action.pay.PEnum;
@ -9,8 +10,9 @@ import com.ynxbd.common.bean.pay.PEISOrderInfo;
import com.ynxbd.common.bean.pay.PEISReserve;
import com.ynxbd.common.dao.peis.PEISDao;
import com.ynxbd.common.helper.common.JsonHelper;
import com.ynxbd.common.helper.common.RSAHelper;
import com.ynxbd.common.helper.http.OkHttpHelper;
import com.ynxbd.common.helper.xbd.XBDHelper;
import com.ynxbd.common.helper.xbd.XbdConfigHelper;
import com.ynxbd.common.result.*;
import lombok.extern.slf4j.Slf4j;
import okhttp3.FormBody;
@ -18,6 +20,7 @@ import okhttp3.RequestBody;
import org.apache.commons.lang3.ObjectUtils;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.Date;
/**
@ -102,7 +105,7 @@ public class PEISService {
return;
}
JsonResult jsonResult = postForm(XBDHelper.PEIS_URL + "/wxUse/wxPay", params -> {
JsonResult jsonResult = postForm(XbdConfigHelper.PEIS_URL + "/wxUse/wxPay", params -> {
params.put("orderNo", noticeOrderNo);
params.put("payStatus", "OK");
params.put("payFailReason", "");
@ -138,7 +141,7 @@ public class PEISService {
* @return bean
*/
public PEISOrderInfo queryPEISOrderByNoticeOrderNo(String noticeOrderNo) throws ServiceException {
JsonResult jsonResult = get(XBDHelper.PEIS_URL + "/wxUse/GetOrder", params -> {
JsonResult jsonResult = get(XbdConfigHelper.PEIS_URL + "/wxUse/GetOrder", params -> {
params.put("orderNo", noticeOrderNo);
});
log.info("[体检预约]订单查询 {}", JsonHelper.toJsonString(jsonResult));
@ -224,7 +227,7 @@ public class PEISService {
* @return bool
*/
public boolean cancelPEISReserve(String noticeOrderNo, String refundStatus, String refundFailReason) throws ServiceException {
JsonResult jsonResult = postForm(XBDHelper.PEIS_URL + "/wxUse/wxRefund", params -> {
JsonResult jsonResult = postForm(XbdConfigHelper.PEIS_URL + "/wxUse/wxRefund", params -> {
params.put("orderNo", noticeOrderNo);
params.put("refundStatus", refundStatus); // 退费状态(成功:OK,失败:FAIL)
params.put("refundFailReason", refundFailReason);
@ -238,19 +241,28 @@ public class PEISService {
return true;
}
public JSONArray queryPEISRecordByCardNo(String cardNo, String begDate, String endDate) throws ServiceException {
/**
* 体检影像报告
*
* @param cardNo 加密后的证件号
* @param begDate 开始时间
* @param endDate 结束时间
*/
public JSONArray queryPEISRecordByCardNo(String cardNo, String begDate, String endDate) throws Exception {
String enIdCard = HexUtil.encodeHexStr(RSAHelper.enBytePKCS1Padding(cardNo, "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5klqI5STWTcbfjR093j+hvCEjNlZMQscIJg8jxZGqKW84AdFmSqPWEPu9ilqP+QUASiVSZ1QevGr2DWODFZ8Zw35aDA2bqCEprUx81gDdVPO7H7Bij+r8zAg8fT2c0Bi5rFq0xWMEQiTI+CyWwc5prOpquJU/P5yauEAdkRzlDwIDAQAB"));
RequestBody formBody = new FormBody.Builder().
add("enIdCard", cardNo)
add("enIdCard", enIdCard)
.add("begDate", begDate)
.add("endDate", endDate)
.build();
String result = OkHttpHelper.post(XBDHelper.PEIS_URL + "/WxUse/GetPeisOfPacsResult", formBody);
String result = OkHttpHelper.post(XbdConfigHelper.PEIS_URL + "/WxUse/GetPeisOfPacsResult", formBody);
if (ObjectUtils.isEmpty(result)) {
throw new ServiceException("请求失败");
throw new ServiceException("[体检]请求异常");
}
JSONObject jsonResult = JsonHelper.parseObject(result);
if (jsonResult == null) {
throw new ServiceException("请求失败");
throw new ServiceException("[体检]请求解析失败");
}
String code = jsonResult.getString("code");
String message = jsonResult.getString("message");

@ -3,6 +3,7 @@ package com.ynxbd.common.service;
import com.alibaba.fastjson.JSONObject;
import com.ynxbd.ali.helper.AliHelper;
import com.ynxbd.bcm.config.BCMHelper;
import com.ynxbd.common.action.pay.JYPayAction;
import com.ynxbd.common.action.pay.PEnum;
import com.ynxbd.common.bean.enums.MerchantEnum;
import com.ynxbd.common.bean.pay.*;
@ -15,6 +16,7 @@ import com.ynxbd.common.result.Result;
import com.ynxbd.common.result.ResultEnum;
import com.ynxbd.common.result.ServiceException;
import com.ynxbd.common.service.cache.PayCache;
import com.ynxbd.jy.helper.JYPayHelper;
import com.ynxbd.wx.wxfactory.WxMedHelper;
import com.ynxbd.wx.wxfactory.WxPayHelper;
import com.ynxbd.wx.wxfactory.payment.jsapi.models.WxPayNotify;
@ -551,9 +553,12 @@ public class PayService {
} else if (MerchantEnum.ALI.equals(merchantEnum)) { // 支付宝下单
return AliHelper.createOrder(merchantEnum, title, outTradeNo, totalFee, notifyType, payOpenId);
} else if (MerchantEnum.BCM.equals(merchantEnum)) {
} else if (MerchantEnum.BCM.equals(merchantEnum)) { // 交行
return BCMHelper.createOrder(merchantEnum, title, outTradeNo, totalFee, notifyType);
} else if (MerchantEnum.JY.equals(merchantEnum)) { // 京颐
return JYPayHelper.createOrder(merchantEnum, title, outTradeNo, totalFee, notifyType, ip, payOpenId, msgOpenId, new ReqOrder());
}
return null;
}

@ -0,0 +1,113 @@
package com.ynxbd.jy.bean;
import com.ynxbd.common.bean.pay.Order;
import com.ynxbd.common.bean.pay.ReqOrder;
import com.ynxbd.jy.bean.enums.JYBusinessTypeEnum;
import com.ynxbd.jy.bean.enums.JYOrderTypeDetailEnum;
import com.ynxbd.jy.bean.enums.JYOrderTypeEnum;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
@Slf4j
@Getter
@Setter
@ToString
@NoArgsConstructor
public class JYOrder extends ReqOrder {
private String clinicNo;
private String hisTransDoneTime;
private String hisOperatorNo;
private String hisOperatorName;
private String receiptNo;
// ==================================
private String applicationId;
private String merchantId;
// 应用方订单号
private String merOrderNum;
// 支付平台订单号
private String orderId;
// 支付平台支付流水号
private String orderTransId;
// 支付网关订单号
private String threeTradeNo;
// 银行流水号
private String finalTransNo;
// 订单金额
private String orderAmt;
// 退款金额
private String refundAmt;
// 支付交易发起时间
private String tranDateTime;
// 支付时间-YYYYMMDDHHMMSS(订单支付时间)未支付时,为空字符串
private String paymentTime;
// 支付方式
private String payType;
// 订单状态[详见字典数据5.2 没有发生过退款业务的数据会包含此字段,如果发生过退款业务,则不会返回此字段,请以退款明细中状态为准;]
private String orderState;
// 订单状态描述
private String orderStateMessage;
// 订单费用类型[如:001:挂号费 002:医疗费 详见字典数据5.2订单费用类型]
private String orderType;
// 微信公众号用户标识
private String openId;
// 订单最后退款次数,未退款时无此字段。
private String refundCount;
// 订单最后退款时间,未退款时无此字段。
private String refundTime;
// 商户ID
private String appId;
// 商户号
private String merchantNo;
// 医保局返回信息
private String responseContent;
// 由接入方生成的签名
private String signValue;
// ====================================
// 支付类型明细
private String orderTypeDetail;
public JYOrderTypeEnum orderTypeEnum;
public JYBusinessTypeEnum businessTypeEnum;
// 支付类型明细
public JYOrderTypeDetailEnum orderTypeDetailEnum;
public int toInsurancePayType() {
int payType = 0;
if (super.totalFee.compareTo(super.insuranceFee) == 0) {
payType = 2; // 医保
} else if (super.totalFee.compareTo(super.cashFee) == 0) {
payType = 1; // 现金(1)
} else {
payType = 3; // 医保+现金
}
return payType;
}
public int toConsumeType() {
if (acctFee == null || insuranceFee == null) {
return 0;
}
if (acctFee.compareTo(BigDecimal.ZERO) > 0 && insuranceFee.compareTo(BigDecimal.ZERO) > 0) {
return 0; // 0:统筹+个账
}
if (acctFee.compareTo(BigDecimal.ZERO) > 0 && insuranceFee.compareTo(BigDecimal.ZERO) == 0) {
return 1; // 1:个账
}
if (acctFee.compareTo(BigDecimal.ZERO) == 0 && insuranceFee.compareTo(BigDecimal.ZERO) > 0) {
return 2; // 2:统筹
}
return 0;
}
}

@ -0,0 +1,35 @@
package com.ynxbd.jy.bean;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Getter
@Setter
@ToString
@NoArgsConstructor
public class JYRefund {
// 支付平台退款流水号
private String orderTransId;
// 应用方退款流水号
private String refundTransId;
// 支付网关流水号
private String threeTransId;
// 银行流水号
private String finalTransId;
// 退款金额
private String refundAmt;
// 交易流水状态
private String transState;
// 交易流水状态描述
private String transStateMessage;
// 交易代码[002撤销 004退费 005冲正 详细请参考数据字典5.2;$n为下标,从0开始编号]
private String transCode;
// 退款(冲正、撤销)请求创建时间YYYYMMDDHHMMSS ;$n为下标,从0开始编号
private String tranDateTime;
// 退款(冲正、撤销)请求完成时间YYYYMMDDHHMMSS ;$n为下标,从0开始编号
private String refundTime;
}

@ -0,0 +1,39 @@
package com.ynxbd.jy.bean.enums;
import lombok.ToString;
@ToString
public enum JYBusinessTypeEnum {
B101("B101", "预约"),
B102("B102", "挂号"),
B201("B201", "门诊缴费"),
B202("B202", "门诊预缴"),
B301("B301", "住院预缴"),
B302("B302", "住院结算补交"),
B401("B401", "卡押金"),
B999("B999", "其他");
public final String CODE;
public final String DESC;
JYBusinessTypeEnum(String CODE, String DESC) {
this.CODE = CODE;
this.DESC = DESC;
}
/**
* 根据code获取枚举
*/
public static JYBusinessTypeEnum findEnum(String code) {
if (code == null) {
return null;
}
for (JYBusinessTypeEnum item : values()) {
if (item.CODE.equals(code)) {
return item;
}
}
return null;
}
}

@ -0,0 +1,26 @@
package com.ynxbd.jy.bean.enums;
import lombok.ToString;
@ToString
public enum JYOrderTypeDetailEnum {
RegPay("RegPay", "挂号支付"),
DiagPay("DiagPay", "诊间支付"),
CovidExamPay("CovidExamPay", "新冠检测费用(核酸)"),
InHospPay("InHospPay", "住院费支付"),
PharmacyPay("PharmacyPay", "药店支付"),
InsurancePay("InsurancePay", "保险费支付"),
IntRegPay("IntRegPay", "互联网医院挂号支付"),
IntReDiagPay("IntReDiagPay", "互联网医院复诊支付"),
IntPscPay("IntPscPay", "互联网医院处方支付"),
CvidAntigenPay("CvidAntigenPay", "新冠抗原检测");
public final String CODE;
public final String DESC;
JYOrderTypeDetailEnum(String CODE, String DESC) {
this.CODE = CODE;
this.DESC = DESC;
}
}

@ -0,0 +1,44 @@
package com.ynxbd.jy.bean.enums;
import lombok.ToString;
@ToString
public enum JYOrderTypeEnum {
_001("001", "挂号费"),
_002("002", "医药费"),
_003("003", "住院预交金"),
_004("004", "药品费"),
_005("005", "就诊卡充值"),
_006("006", "新农合缴费"),
_007("007", "网费充值"),
_008("008", "健康卡充值"),
_010("010", "咨询费"),
_012("012", "复印费"),
_101("101", "陪诊费"),
_801("801", "停车费"),
_902("902", "卡押金"),
_903("903", "住院结算补交"),
_904("904", "体检费"),
_905("905", "处方药品费"),
_906("906", "陪护床押金"),
_907("907", "病历押金"),
_908("908", "病理切片押金");
public final String CODE;
public final String NAME;
JYOrderTypeEnum(String CODE, String name) {
this.CODE = CODE;
this.NAME = name;
}
public static JYOrderTypeEnum findEnum(String code) {
for (JYOrderTypeEnum value : JYOrderTypeEnum.values()) {
if (value.CODE.equals(code)) {
return value;
}
}
return null;
}
}

@ -0,0 +1,36 @@
package com.ynxbd.jy.helper;
import com.ynxbd.common.helper.common.XmlConfigHelper;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class JYPayConfig {
private JYPayConfig() {
}
// 请求地址
public final static String URL;
// 应用编号
public final static String APPLICATION_ID;
// 应用商户编号
public final static String MERCHANT_ID;
public final static String HOSP_ID;
public final static String PRIVATE_KEY;
static {
XmlConfigHelper config = new XmlConfigHelper().read("xbd-config.xml", "pay");
URL = config.getString("url");
APPLICATION_ID = config.getString("application_id");
MERCHANT_ID = config.getString("merchant_id");
HOSP_ID = config.getString("hosp_id");
PRIVATE_KEY = config.getString("private_key");
if (URL == null) {
log.error("[京颐-支付]配置文件读取失败");
}
}
}

@ -2,17 +2,24 @@ package com.ynxbd.jy.helper;
import com.alibaba.fastjson.JSONObject;
import com.ynxbd.common.bean.enums.MerchantEnum;
import com.ynxbd.common.bean.pay.ReqOrder;
import com.ynxbd.common.helper.common.ErrorHelper;
import com.ynxbd.common.helper.common.JsonHelper;
import com.ynxbd.common.helper.common.RSAHelper;
import com.ynxbd.common.helper.http.OkHttpHelper;
import com.ynxbd.jy.bean.JYOrder;
import com.ynxbd.wx.config.WeChatConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import weixin.popular.api.PayMchAPI;
import weixin.popular.bean.paymch.Unifiedorder;
import weixin.popular.bean.paymch.UnifiedorderResult;
import java.math.BigDecimal;
import java.util.UUID;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.Signature;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
// 京颐支付
@Slf4j
@ -31,70 +38,284 @@ public class JYPayHelper {
* @param msgOpenId 用于推送的openId
* @return 成功返回 json, 否则返回null
*/
public static JSONObject createOrder(MerchantEnum merchantEnum, String title, String totalFee, String outTradeNo, String notifyType, String ip, String payOpenId, String msgOpenId) {
// try {
// if (ObjectUtils.isEmpty(payOpenId) || ObjectUtils.isEmpty(outTradeNo)
// || merchantEnum == null || totalFee == null || notifyType == null) {
// log.info("【京硕】下单参数缺失");
// return null;
// }
//
// String cents;
// try {
// cents = new BigDecimal(totalFee).movePointRight(2).toString(); // 金额转换=>单位分
// } catch (Exception e) {
// ErrorHelper.println(e);
// log.info("【京硕】统一下单金额转换异常");
// return null;
// }
//
// String appId = merchantEnum.APP_ID;
// String mchId = WeChatConfig.MCH_ID;
// String mchKey = WeChatConfig.MCH_KEY;
// String nonce = UUID.randomUUID().toString().replace("-", "");
//
// Unifiedorder unifiedorder = new Unifiedorder();
// unifiedorder.setAppid(appId);
// unifiedorder.setMch_id(mchId);
// unifiedorder.setNonce_str(nonce);
// unifiedorder.setOpenid(payOpenId);
// unifiedorder.setOut_trade_no(outTradeNo);
// unifiedorder.setBody(title);
//
// unifiedorder.setTotal_fee(cents); // 金额分
// unifiedorder.setSpbill_create_ip(ip);
// unifiedorder.setNotify_url(WeChatConfig.getBaseURL() + merchantEnum.NOTIFY_URL);
// unifiedorder.setTrade_type("JSAPI");
// // 额外参数
// unifiedorder.setAttach(notifyType);
//
// log.info("【京硕】统一下单 {},{},{},{},{},{},{},{}", appId, mchId, nonce, title, outTradeNo, totalFee, ip, merchantEnum.NOTIFY_URL);
//
// // 微信统一下单
// UnifiedorderResult unifiedorderResult = PayMchAPI.payUnifiedorder(unifiedorder, mchKey);
// log.info("【京硕】统一下单返回:{}", JsonHelper.toJsonString(unifiedorderResult));
// if (unifiedorderResult == null) {
// log.info("【京硕】统一下单失败");
// return null;
// }
public static JSONObject createOrder(MerchantEnum merchantEnum, String title, String totalFee, String outTradeNo, String notifyType, String ip, String payOpenId, String msgOpenId, ReqOrder reqOrder) {
try {
if (ObjectUtils.isEmpty(payOpenId) || ObjectUtils.isEmpty(outTradeNo)
|| merchantEnum == null || totalFee == null || notifyType == null) {
log.info("【京硕】下单参数缺失");
return null;
}
String cents;
try {
cents = new BigDecimal(totalFee).movePointRight(2).toString(); // 金额转换=>单位分
} catch (Exception e) {
ErrorHelper.println(e);
log.info("【京硕】下单金额转换异常");
return null;
}
log.info("【京硕】下单 {},{},{},{},{}", title, outTradeNo, totalFee, ip, merchantEnum.NOTIFY_URL);
JYOrder jyOrder = reqOrder.jyOrder;
Map<String, String> req = new HashMap<>();
req.put("openId", payOpenId);
req.put("hospitalId", JYPayConfig.HOSP_ID); // 医院ID
req.put("applicationId", JYPayConfig.APPLICATION_ID);
req.put("merchantId", JYPayConfig.MERCHANT_ID);
req.put("merOrderNum", outTradeNo); // 商户订单号
req.put("hisOrderNum", null); // HIS订单号:可以为发票号[该接口若不传,在业务完成后调用2.1.6接口]
req.put("hisTransNum", null); // HIS流水号:可以为发票号[该接口若不传,在业务完成后调用2.1.6接口]
// 金额
req.put("orderAmt", cents); // 交易金额:只接收整数,单位:分,例如100表示壹圆整;支付宝医保支付传总金额
req.put("orderType", jyOrder.orderTypeEnum.CODE); // 如:001:挂号费 002:医药费;
req.put("backURL", WeChatConfig.getBaseURL() + merchantEnum.NOTIFY_URL); // 商户异步回调地址:后台发起异步回调地址, 扫码枪支付方式无需回调的可以不
// params.put("backParamsType", "key-value"); // 商户异步回调入参格式:后台发起异步回调时参数格式,取值有:key-value和json,默认值是key-value。
req.put("payType", "WX_PUBLIC"); // 如:UPOP_APP, UPOP_WEB;详见附录5.1[微信公众号支付(WX_PUBLIC)]
req.put("bussinessType", jyOrder.businessTypeEnum.CODE); // 业务类型:综合支付对应用权限控制是否必传 最大不超过4位,详见数据字典5.2 该接口若不传,需要调用2.1.6接口再次更新
req.put("patientName", reqOrder.getPatientName()); // 微信医保支付必传。其余支付方式若该接口若不传,需要调用2.1.6接口再次更新
req.put("patientGender", reqOrder.getPatientGender()); // 患者性别。综合支付对应用权限控制是否必传 1男 2女 9其他 最大不超过4位 该接口若不传,需要调用2.1.6接口再次更新
req.put("patientAge", reqOrder.getPatientAge()); // 患者年龄。综合支付对应用权限控制是否必传 该接口若不传,需要调用2.1.6接口再次更新
req.put("patientIdNo", reqOrder.getPatientTel()); // 微信医保支付必传。其余支付方式若该接口若不传,需要调用2.1.6接口再次更新
req.put("patientPhoneNumber", reqOrder.getPatientTel()); // 综合支付对应用权限控制是否必传 最大不超过16位 该接口若不传,需要调用2.1.6接口再次更新
req.put("patientId", reqOrder.getPatientId()); // 患者ID:综合支付对应用权限控制是否必传 最大不超过32位 该接口若不传,需要调用2.1.6接口再次更新
req.put("patientCardNo", reqOrder.getPatientId()); // 患者卡号:综合支付对应用权限控制是否必传 最大不超过32位该接口若不传,需要调用2.1.6接口再次更新
req.put("clinicNo", reqOrder.getTreatNum()); // 门诊号:综合支付对应用权限控制是否必传 最大不超过32位该接口若不传,需要调用2.1.6接口再次更新
req.put("inpNo", reqOrder.getTreatNum()); // 住院号:综合支付对应用权限控制是否必传 最大不超过32位该接口若不传,需要调用2.1.6接口再次更新
req.put("hisTransDoneTime", null); // HIS业务完成时间:综合支付对应用权限控制是否必传 YYYY-MM-DD HH:MM:SS 该接口若不传,需要调用2.1.6接口再次更新
req.put("hisOperatorNo", jyOrder.getHisOperatorNo()); // HIS操作员编号:综合支付对应用权限控制是否必传HIS操作员编号和HIS操作员姓名必须成对出现该接口若不传,需要调用2.1.6接口再次更新
req.put("hisOperatorName", jyOrder.getHisOperatorName()); // HIS操作员姓名:综合支付对应用权限控制是否必传 HIS操作员编号和HIS操作员姓名必须成对出现 该接口若不传,需要调用2.1.6接口再次更新
req.put("receiptNo", null); // 综合支付对应用权限控制是否必传最大不超过200位 该接口若不传,需要调用2.1.6接口再次更新
req.put("remarks", ""); // 备注 建行渠道格式为json,参考样式:{"REMARK1":"REM1","REMARK2":"REM2"} 农行渠道参考样式:{"TerminalNo":"1234567"}
// 医保支付======================================
// params.put("orderTotalAmt", cents); // orderTotalAmt:微信医保支付必传,有社保交易数据时,订单总金额=自费实际金额+社保金额+减免金额
// params.put("orderTypeDetail", jyOrder.orderTypeDetailEnum.CODE); // 支付类型明细:由接入方生成的签名,支付平台根据该字段对入参进行验签;签名生成规则参考4加签验签规则
// params.put("cashFee", reqOrder.getCashFee()); // 现金需要支付的金额:单位为分>=0 线下预结算模式填实际自费金额
// params.put("insuranceFee", reqOrder.getInsuranceFee()); // 单位为分>=0填实际医保金额
//
// String result_code = unifiedorderResult.getResult_code();
// // 下单是否成功
// Boolean sign_status = unifiedorderResult.getSign_status();
// if (!SUCCESS.equals(result_code) || sign_status == null || !sign_status) {
// log.info("【京硕】统一下单返回异常信息:sign_status={}, err_code=[ {} ], err_code_des=[ {} ]", sign_status, unifiedorderResult.getErr_code(), unifiedorderResult.getErr_code_des());
// return null;
// }
// String json = weixin.popular.util.PayUtil.generateMchPayJsRequestJson(unifiedorderResult.getPrepay_id(), appId, mchKey);
// if (json != null) {
// return JsonHelper.parseObject(json);
// }
// } catch (Exception e) {
// log.error("【京硕】统一下单异常信息:{}", e.getMessage());
// ErrorHelper.println(e);
// }
// return null;
// params.put("allowFeeChange", "0"); // 是否允许预结算费用发生变化:0:不允许;1:允许 当医保局返回的预结算金额与医院上传的金额不一致时,此字段为0则直接报错,为1则以医保局金额为准
// params.put("spbillCreateIp", reqOrder.getIp()); // 用户端ip
// params.put("returnUrl", reqOrder.getReturnUrl()); // 调用方可以在链接中加上支付单号,回跳后查询调用方订单状态,如果订单已支付则成功, 如果订单未支付则进行查单操作确认订单结果。不论成功或者失败均会回跳
// params.put("insurancePayType", jyOrder.toInsurancePayType()); // 微信医保支付方式:1:现金;2:医保;3:现金+医保
// params.put("consumeType", jyOrder.toConsumeType()); // 医保部分扣费类型:0:统筹+个账;1:个账;2:统筹。默认为0
// params.put("userCardType", "1"); // 1 居民身份证
// params.put("isDept", "4"); // 医保标识:is_dept=4 医保电子凭证支付;
// params.put("serialNo", reqOrder.getSerialNo()); // 医院HIS系统订单号
// params.put("requestContent", reqOrder.getRequestContent()); // 参考医保结构体(医疗机构透传医保) 示例: {"payAuthNo":"AUTH****","payOrdId":"ORD****","setlLatlnt":"118.096435,24.485407"} payAuthNo:授权码 payOrdId:对应处方上传的出参单号 setlLatlnt:用户地理定位信息, 经纬度信息,如“118.096435,24.485407”。未获取到用户定位时,传“0,0”。
//// params.put("extendInfo", ""); //亲情移动支付时,为必填。 (就诊亲属姓名md5 - rel_user_name_md5,就诊亲属身份证件号md5 - rel_user_card_no_md5 ) { "rel_user_name_md5": "XXX","rel_user_card_no_md5": "XXX"} MD5为32位小写,uft-8编码(身份证中如果有字母需要转成大写再做MD5)
String signValue = createSign(req);
if (signValue == null) {
return null;
}
req.put("signValue", signValue); // 数字签名:由接入方生成的签名,支付平台根据该字段对入参进行验签;签名生成规则参考4加签验签规则
JSONObject resp = OkHttpHelper.postJson(JYPayConfig.URL + "/qy_iips_pay/paycore/prePayOrder", params -> {
params.putAll(req);
}, headers -> {
headers.add("content-type", "application/x-www-form-urlencoded");
});
log.info("【京硕】下单返回 {}", JsonHelper.toJsonString(resp));
} catch (Exception e) {
log.error("【京硕】下单异常信息:", e);
}
return null;
}
/**
* 支付状态查询
*
* @param merchantEnum 枚举
* @param title 商品标题
* @param totalFee 订单金额
* @param outTradeNo 订单号
* @return 成功返回 json, 否则返回null
*/
public static JSONObject queryPayOrderInfo(MerchantEnum merchantEnum, String title, String totalFee, String outTradeNo, String bankTransNo, String tradeNo) {
try {
log.info("【京硕】支付状态查询 {},{},{},{}", title, outTradeNo, totalFee, merchantEnum.NOTIFY_URL);
if (ObjectUtils.isEmpty(outTradeNo) && ObjectUtils.isEmpty(bankTransNo) && ObjectUtils.isEmpty(tradeNo)) {
return null;
}
if (ObjectUtils.isEmpty(outTradeNo) && (ObjectUtils.isEmpty(bankTransNo) || ObjectUtils.isEmpty(tradeNo))) {
return null;
}
Map<String, String> req = new HashMap<>();
req.put("applicationId", JYPayConfig.APPLICATION_ID);
req.put("merchantId", JYPayConfig.MERCHANT_ID);
req.put("merOrderNum", outTradeNo); // 商户订单号
req.put("orderId", bankTransNo); // 支付平台订单号
req.put("outTransNo", tradeNo); // 应用流水号:应用流水号outTransNo”和“支付平台订单号orderId”这两个参数必须同时传。该参数指“应用方流水号”,不许有重复
String signValue = createSign(req);
if (signValue == null) {
return null;
}
req.put("signValue", signValue); // 应用流水号:应用流水号outTransNo”和“支付平台订单号orderId”这两个参数必须同时传。该参数指“应用方流水号”,不许有重复
JSONObject resp = OkHttpHelper.postJson(JYPayConfig.URL + "/qy_iips_pay/paycore/queryPayOrderInfo", params -> {
params.putAll(req);
}, headers -> {
headers.add("content-type", "application/x-www-form-urlencoded");
});
log.info("【京硕】支付状态查询返回 {}", JsonHelper.toJsonString(resp));
} catch (Exception e) {
log.error("【京硕】支付状态查询异常信息:", e);
}
return null;
}
/**
* 退款申请
*
* @param merchantEnum 枚举
* @param title 商品标题
* @param totalFee 订单金额
* @param outTradeNo 订单号
* @return 成功返回 json, 否则返回null
*/
public static JSONObject refundPayOrder(MerchantEnum merchantEnum, String title, String totalFee, String outTradeNo, String bankTransNo, String tradeNo, String sign) {
try {
log.info("【京硕】退款申请 {},{},{},{}", title, outTradeNo, totalFee, merchantEnum.NOTIFY_URL);
if (ObjectUtils.isEmpty(outTradeNo) && ObjectUtils.isEmpty(bankTransNo) && ObjectUtils.isEmpty(tradeNo)) {
return null;
}
if (ObjectUtils.isEmpty(outTradeNo) && (ObjectUtils.isEmpty(bankTransNo) || ObjectUtils.isEmpty(tradeNo))) {
return null;
}
Map<String, String> req = new HashMap<>();
req.put("applicationId", JYPayConfig.APPLICATION_ID);
req.put("merchantId", JYPayConfig.MERCHANT_ID);
req.put("merOrderNum", outTradeNo); // 商户订单号
req.put("orderId", bankTransNo); // 支付平台订单号
req.put("outTransNo", tradeNo); // 应用流水号:应用流水号outTransNo”和“支付平台订单号orderId”这两个参数必须同时传。该参数指“应用方流水号”,不许有重复
req.put("signValue", sign); // 应用流水号:应用流水号outTransNo”和“支付平台订单号orderId”这两个参数必须同时传。该参数指“应用方流水号”,不许有重复
req.put("refundStateSync", "0"); // 退费状态是否同步返回[0:否,1:是,不传默认为否 若传值为1,则退款状态不明确,开始轮询]
req.put("requestContent", "0"); // 微信医保支付必传。示例:{“payOrdId”:”******”,“ref_reason”:”******”ref_reason  退款原因payOrdId: 对应处方上传的出参单号
String signValue = createSign(req);
if (signValue == null) {
return null;
}
req.put("signValue", signValue); // 数字签名:由接入方生成的签名,支付平台根据该字段对入参进行验签;签名生成规则参考4加签验签规则
JSONObject resp = OkHttpHelper.postJson(JYPayConfig.URL + "/qy_iips_pay/paycore/refundPayOrder", params -> {
params.putAll(req);
}, headers -> {
headers.add("content-type", "application/x-www-form-urlencoded");
});
log.info("【京硕】退款申请返回 {}", JsonHelper.toJsonString(resp));
} catch (Exception e) {
log.error("【京硕】退款申请异常信息:", e);
}
return null;
}
/**
* 更新业务信息
*
* @param merchantEnum 枚举
* @param title 商品标题
* @param totalFee 订单金额
* @param outTradeNo 订单号
* @return 成功返回 json, 否则返回null
*/
public static JSONObject modifyBusinessInfo(MerchantEnum merchantEnum, String title, String totalFee, String outTradeNo, String bankTransNo, String tradeNo, String sign) {
try {
log.info("【京硕】更新业务信息 {},{},{},{}", title, outTradeNo, totalFee, merchantEnum.NOTIFY_URL);
if (ObjectUtils.isEmpty(outTradeNo) && ObjectUtils.isEmpty(bankTransNo) && ObjectUtils.isEmpty(tradeNo)) {
return null;
}
if (ObjectUtils.isEmpty(outTradeNo) && (ObjectUtils.isEmpty(bankTransNo) || ObjectUtils.isEmpty(tradeNo))) {
return null;
}
JSONObject resp = OkHttpHelper.postJson(JYPayConfig.URL + "/qy_iips_pay/paycore/modifyBusinessInfo", params -> {
params.put("applicationId", JYPayConfig.APPLICATION_ID); // 应用编号
params.put("merchantId", JYPayConfig.MERCHANT_ID); // 应用商户编号
// params.put("merOrderNum", merOrderNum); // 商户订单号
// params.put("refundTransId", refundTransId); // 商户退款流水号,非支付交易必传
// params.put("orderId", orderId); // 支付平台订单号
// params.put("orderTransId", orderTransId); // 支付平台流水号
// params.put("hisOrderNum", hisOrderNum); // HIS订单号,对账场景必传
// params.put("hisTransNum", hisTransNum); // HIS交易流水号,对账场景必传
// params.put("hisTransAmt", hisTransAmt); // 交易金额,单位:分,整数
// params.put("bussinessType", bussinessType); // 业务类型,最大4位
// params.put("patientName", patientName); // 患者姓名
// params.put("patientGender", patientGender); // 患者性别:1男 2女 9其他
// params.put("patientAge", patientAge); // 患者年龄
// params.put("patientIdNo", patientIdNo); // 患者身份证号,最长18位
// params.put("patientPhoneNumber", patientPhoneNumber); // 患者手机号码,最长16位
// params.put("patientId", patientId); // 患者ID
// params.put("patientCardNo", patientCardNo); // 患者卡号
// params.put("clinicNo", clinicNo); // 门诊号
// params.put("inpNo", inpNo); // 住院号
// params.put("hisTransDoneTime", hisTransDoneTime); // HIS业务完成时间 YYYY-MM-DD HH:MM:SS
// params.put("hisOperatorNo", hisOperatorNo); // HIS操作员编号
// params.put("hisOperatorName", hisOperatorName); // HIS操作员姓名
// params.put("receiptNo", receiptNo); // HIS票据号
// params.put("hospitalId", hospitalId); // 医院ID
// params.put("iipsApiVersion", iipsApiVersion); // API版本号,不传默认v1.0
}, headers -> {
headers.add("content-type", "application/x-www-form-urlencoded");
});
log.info("【京硕】更新业务信息返回 {}", JsonHelper.toJsonString(resp));
} catch (Exception e) {
log.error("【京硕】更新业务信息异常信息:", e);
}
return null;
}
/**
* 可选排除signValue自身标准支付签名规范推荐
*
* @param params 原始参数map
* @return 待签名字符串
*/
public static String createSign(Map<String, String> params) {
try {
String signString = buildSignString(params);
return sign(signString, RSAHelper.getPrivateKey(JYPayConfig.PRIVATE_KEY));
} catch (Exception e) {
log.error("", e);
return null;
}
}
/**
* 可选排除signValue自身标准支付签名规范推荐
*
* @param params 原始参数map
* @return 待签名字符串
*/
public static String buildSignString(Map<String, String> params) {
return params.entrySet().stream().filter(entry -> entry.getValue() != null && !entry.getValue().trim().isEmpty() && !"signValue".equals(entry.getKey()))
.sorted(Map.Entry.comparingByKey())
.map(entry -> entry.getKey() + "=" + entry.getValue())
.collect(Collectors.joining("&"));
}
/**
* 使用私钥按照指定算法进行签名
*
* @param message 待签名串
* @param privateKey 签名用私钥对象
* @return 签名结果
*/
public static String sign(String message, PrivateKey privateKey) throws Exception {
Signature signature = Signature.getInstance("SHA256WithRSA");
signature.initSign(privateKey);
signature.update(message.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(signature.sign());
}
}

@ -28,30 +28,31 @@ public class MessagePushConfig {
*/
public static final String HOST_URL;
// [挂号]导航推送
// [挂号]导航推送 https://map.ipsmap.com?id=opBdKy87Gs&appKey=fnAs1mE5HP&poi=科室编码
public static final boolean REG_NAVIGATE_IS_ENABLE;
public static final String REG_NAVIGATE_URL;
public static final String REG_NAVIGATE_API;
// [挂号]缴费通知
public static final boolean REG_PAID_IS_ENABLE;
public static final String REG_PAID_URL;
public static final String REG_PAID_API;
// [挂号]取消预约
public static final boolean REG_CANCEL_IS_ENABLE;
public static final String REG_CANCEL_URL;
public static final String REG_CANCEL_API;
// [挂号]AI
public static final String REG_AI_URL;
public static final boolean REG_AI_IS_ENABLE;
public static final String REG_AI_API;
// [处方]缴费通知
public static final boolean RX_PAID_IS_ENABLE;
public static final String RX_PAID_URL;
public static final String RX_PAID_API;
// 产科建档
public static final boolean OBS_DOCUMENT_IS_ENABLE;
public static final String OBS_DOCUMENT_URL;
public static final String OBS_DOCUMENT_API;
static {
XmlConfigHelper config = new XmlConfigHelper().read("wx-msg-push.xml");
@ -64,32 +65,32 @@ public class MessagePushConfig {
// [挂号]导航推送
XmlConfigHelper regNavigateConfig = config.getConfigNode("reg_navigate");
REG_NAVIGATE_IS_ENABLE = regNavigateConfig.getBoolean("is_enable", false);
REG_NAVIGATE_URL = HOST_URL + regNavigateConfig.getString("api");
REG_NAVIGATE_API = HOST_URL + regNavigateConfig.getString("api");
// [挂号]缴费通知
XmlConfigHelper regPaidConfig = config.getConfigNode("reg_paid");
REG_PAID_IS_ENABLE = regPaidConfig.getBoolean("is_enable", false);
REG_PAID_URL = HOST_URL + regPaidConfig.getString("api");
REG_PAID_API = HOST_URL + regPaidConfig.getString("api");
// [挂号]取消预约
XmlConfigHelper regCancelConfig = config.getConfigNode("reg_cancel");
REG_CANCEL_IS_ENABLE = regCancelConfig.getBoolean("is_enable", false);
REG_CANCEL_URL = HOST_URL + regCancelConfig.getString("api");
REG_CANCEL_API = HOST_URL + regCancelConfig.getString("api");
// [挂号]AI
XmlConfigHelper regAIConfig = config.getConfigNode("reg_ai");
REG_AI_IS_ENABLE = regAIConfig.getBoolean("is_enable", false);
REG_AI_URL = HOST_URL + regAIConfig.getString("api");
REG_AI_API = HOST_URL + regAIConfig.getString("api");
// [处方]缴费通知
XmlConfigHelper rxPaidConfig = config.getConfigNode("rx_paid");
RX_PAID_IS_ENABLE = rxPaidConfig.getBoolean("is_enable", false);
RX_PAID_URL = HOST_URL + rxPaidConfig.getString("api");
RX_PAID_API = HOST_URL + rxPaidConfig.getString("api");
// 产科建档
XmlConfigHelper obsDocumentConfig = config.getConfigNode("obs_document");
OBS_DOCUMENT_IS_ENABLE = obsDocumentConfig.getBoolean("is_enable", false);
OBS_DOCUMENT_URL = HOST_URL + obsDocumentConfig.getString("api");
OBS_DOCUMENT_API = HOST_URL + obsDocumentConfig.getString("api");
}
@ -100,7 +101,7 @@ public class MessagePushConfig {
*/
public static void regNavigatePush(MerchantEnum merchantEnum, Register reg) {
try {
if (!merchantEnum.equals(MerchantEnum.WX) || !REG_NAVIGATE_IS_ENABLE || ObjectUtils.isEmpty(REG_NAVIGATE_URL)) {
if (!merchantEnum.equals(MerchantEnum.WX) || !REG_NAVIGATE_IS_ENABLE || ObjectUtils.isEmpty(REG_NAVIGATE_API)) {
return;
}
@ -112,14 +113,14 @@ public class MessagePushConfig {
String doctName = reg.getDoctName();
String deptName = reg.getDeptName();
String deptCode = reg.getDeptCode();
if (openid == null || patientId == null) {
log.warn("[推送]挂号导航通知失败,参数缺失~openid={}, patientId={}", openid, patientId);
if (ObjectUtils.isEmpty(openid) || ObjectUtils.isEmpty(patientId)) {
log.warn("[推送]挂号导航通知失败,参数缺失 openid={}, patientId={}", openid, patientId);
return;
}
Patient patient = new PatientDao().selectByOpenidAndEPId(openid, patientId);
if (patient == null) {
log.warn("[推送]挂号导航通知失败,患者信息不存在~");
log.warn("[推送]挂号导航通知失败,未找到患者信息");
return;
}
@ -127,7 +128,7 @@ public class MessagePushConfig {
String time = (ObjectUtils.isEmpty(begTime) || ObjectUtils.isEmpty(endTime)) ? "" : (" " + begTime + "-" + endTime);
OkHttpHelper.getAsync(REG_NAVIGATE_URL, params -> {
OkHttpHelper.getAsync(REG_NAVIGATE_API, params -> {
params.put("patientName", patient.getName() + " ID:" + patientId);
params.put("content", "就诊时间:" + regDate + time);
params.put("deptName", deptName);
@ -145,8 +146,7 @@ public class MessagePushConfig {
*/
public static void regPush(MerchantEnum merchantEnum, Register reg) {
try {
if (!merchantEnum.equals(MerchantEnum.WX)
|| !REG_PAID_IS_ENABLE || reg == null || ObjectUtils.isEmpty(REG_PAID_URL)) {
if (!merchantEnum.equals(MerchantEnum.WX) || !REG_PAID_IS_ENABLE || reg == null || ObjectUtils.isEmpty(REG_PAID_API)) {
return;
}
@ -174,7 +174,7 @@ public class MessagePushConfig {
String time = (ObjectUtils.isEmpty(begTime) || ObjectUtils.isEmpty(endTime)) ? "" : (" " + begTime + "-" + endTime);
OkHttpHelper.getAsync(REG_PAID_URL, params -> {
OkHttpHelper.getAsync(REG_PAID_API, params -> {
params.put("openId", DesEncryptHelper.enCode(openid));
params.put("patientName", patient.getName() + " ID:" + patientId);
params.put("deptName", deptName);
@ -196,7 +196,7 @@ public class MessagePushConfig {
*/
public static void regAI(MerchantEnum merchantEnum, Register reg) {
try {
if (!merchantEnum.equals(MerchantEnum.WX) || !REG_AI_IS_ENABLE || reg == null || ObjectUtils.isEmpty(REG_AI_URL)) {
if (!merchantEnum.equals(MerchantEnum.WX) || !REG_AI_IS_ENABLE || reg == null || ObjectUtils.isEmpty(REG_AI_API)) {
return;
}
@ -219,7 +219,7 @@ public class MessagePushConfig {
.add("url", url)
.add("organizeName", ORGANIZENAME)
.build();
OkHttpHelper.post(REG_AI_URL, requestBody);
OkHttpHelper.post(REG_AI_API, requestBody);
} catch (Exception e) {
log.warn("[推送]AI智能问诊推送通知错误-{}", e.getMessage());
}
@ -246,7 +246,7 @@ public class MessagePushConfig {
.add("url", url)
.add("organizeName", ORGANIZENAME)
.build();
OkHttpHelper.post(REG_AI_URL, requestBody);
OkHttpHelper.post(REG_AI_API, requestBody);
}
@ -257,7 +257,7 @@ public class MessagePushConfig {
*/
public static void regAIReport(String patientId, String outTradeNo, String openId) {
try {
if (!REG_AI_IS_ENABLE || ObjectUtils.isEmpty(REG_AI_URL)) {
if (!REG_AI_IS_ENABLE || ObjectUtils.isEmpty(REG_AI_API)) {
return;
}
log.info("[推送]AI问诊报告推送...");
@ -277,7 +277,7 @@ public class MessagePushConfig {
.add("url", url)
.add("organizeName", ORGANIZENAME)
.build();
OkHttpHelper.post(REG_AI_URL, requestBody);
OkHttpHelper.post(REG_AI_API, requestBody);
} catch (Exception e) {
log.warn("[推送]AI问诊报告推送通知错误-{}", e.getMessage());
}
@ -293,7 +293,7 @@ public class MessagePushConfig {
public static void regObsDocument(MerchantEnum merchantEnum, Register reg) {
try {
if (!merchantEnum.equals(MerchantEnum.WX)
|| reg == null || ObjectUtils.isEmpty(OBS_DOCUMENT_URL)) {
|| reg == null || ObjectUtils.isEmpty(OBS_DOCUMENT_API)) {
return;
}
@ -311,7 +311,7 @@ public class MessagePushConfig {
.add("organizeName", ORGANIZENAME)
.add("buttonName", "进入产科建档系统")
.build();
OkHttpHelper.post(OBS_DOCUMENT_URL, requestBody);
OkHttpHelper.post(OBS_DOCUMENT_API, requestBody);
} catch (Exception e) {
log.warn("[推送]产科建档推送通知错误-{}", e.getMessage());
}
@ -324,7 +324,7 @@ public class MessagePushConfig {
public static void regCancelPush(MerchantEnum merchantEnum, Register reg) {
try {
if (!merchantEnum.equals(MerchantEnum.WX)
|| !REG_CANCEL_IS_ENABLE || reg == null || ObjectUtils.isEmpty(REG_CANCEL_URL)) {
|| !REG_CANCEL_IS_ENABLE || reg == null || ObjectUtils.isEmpty(REG_CANCEL_API)) {
return;
}
log.info("[推送]取消预约...");
@ -350,7 +350,7 @@ public class MessagePushConfig {
String time = (ObjectUtils.isEmpty(begTime) || ObjectUtils.isEmpty(endTime)) ? "" : (" " + begTime + "-" + endTime);
OkHttpHelper.getAsync(REG_CANCEL_URL, params -> {
OkHttpHelper.getAsync(REG_CANCEL_API, params -> {
params.put("openId", DesEncryptHelper.enCode(openid));
params.put("patientName", patient.getName() + " ID:" + patientId);
params.put("deptName", deptName);
@ -370,7 +370,7 @@ public class MessagePushConfig {
*/
public static void recipePush(List<Recipe> recipeList, String treatNum, String patientId, String openid, String tip) {
try {
if (!RX_PAID_IS_ENABLE || ObjectUtils.isEmpty(RX_PAID_URL)) {
if (!RX_PAID_IS_ENABLE || ObjectUtils.isEmpty(RX_PAID_API)) {
return;
}
@ -394,7 +394,7 @@ public class MessagePushConfig {
return;
}
OkHttpHelper.getAsync(RX_PAID_URL, params -> {
OkHttpHelper.getAsync(RX_PAID_API, params -> {
params.put("openId", DesEncryptHelper.enCode(openid));
params.put("patientName", patient.getName() + " ID:" + patientId);
params.put("content", tip);

@ -91,6 +91,7 @@ public class WXPayUtility {
.create();
private static final char[] SYMBOLS =
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
private static final SecureRandom random = new SecureRandom();
/**

@ -1,18 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<config>
<!-- 报告解读 -->
<report>
<report name="报告解读">
<is_dev></is_dev>
<partner_id></partner_id>
<token></token>
</report>
<!-- 智能导诊 -->
<ai_guidance>
<ai_guidance name="智能导诊">
<!-- 是否开启 -->
<is_enable>true</is_enable>
<!-- 是否为分时段挂号(默认true) -->
<is_split_time_reg>true</is_split_time_reg>
<is_split_time_reg>false</is_split_time_reg>
<!-- 合作方ID -->
<partner_id>100000637</partner_id>
<!-- 密钥token -->
@ -25,6 +23,6 @@
<hosp_intro name="医院介绍">暂无介绍</hosp_intro>
<hosp_level name="医院等级">二级甲等</hosp_level>
<hosp_address name="医院地址">暂无地址</hosp_address>
<hosp_tel name="联系方式">0871-67798120</hosp_tel>
<hosp_tel name="联系方式"></hosp_tel>
</ai_guidance>
</config>

@ -1,11 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<config>
<report name="报告解读">
<is_dev mame="是否为测试环境">true</is_dev>
<hosp_id name="医院ID">31737</hosp_id>
<partner_id name="合作方ID">20009251</partner_id>
<token name="密钥token">3bee9edc0a2f41ac911b9b714c854cad</token>
<partner_id name="合作方ID">20009250</partner_id>
<token name="密钥token">c4a39049d4b1c29ffaa9a312687fdcfc</token>
<!-- 测试环境 -->
<dev_partner_id>20009250</dev_partner_id>
<dev_token>3bee9edc0a2f41ac911b9b714c854cad</dev_token>
@ -23,8 +22,8 @@
<partner_id>34edf7cd14e646ae9c1bbca791b7b685</partner_id>
<!-- AI版:电子健康卡AppSecret(管理>开发商接入) | 旧版:Token(腾讯提供)-->
<partner_secret>b26188e6142d43b88f01453853d52a0a</partner_secret>
<!-- -->
<dev_partner_secret>b26188e6142d43b88f01453853d52a0a</dev_partner_secret>
<!-- 测试密钥token -->
<dev_partner_secret name="测试token">b26188e6142d43b88f01453853d52a0a</dev_partner_secret>
<branch_id>800002723</branch_id>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<config>
<pay name="支付配置">
<url>http://127.0.0.1</url>
<application_id name="应用编号">1</application_id>
<merchant_id name="应用商户编号">1</merchant_id>
<public_key>MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD1eiOktZm8bUwjHA2bFlrULg9v/VAmBfUWb8/1+xyZH5eSa7itvAG2Kdzv7L59nRIspXyO6ZW+gGmofnX8CqI5ofLrpissgoqZadNfz5v/k2Q78YTBM8BEMwkrPwOsbFX62poPSKr4kZRHgMADJkgS6AhsaDNBLdH6uRE8R0H6lQIDAQAB</public_key>
<private_key>MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAPV6I6S1mbxtTCMcDZsWWtQuD2/9UCYF9RZvz/X7HJkfl5JruK28AbYp3O/svn2dEiylfI7plb6Aaah+dfwKojmh8uumKyyCiplp01/Pm/+TZDvxhMEzwEQzCSs/A6xsVframg9IqviRlEeAwAMmSBLoCGxoM0Et0fq5ETxHQfqVAgMBAAECgYAf8F9Y2+P/1zyzyL+gcR0qRD/v80aNW/MSk0O8noqPBcRD4c4qlK6oU/QSJ3x1fY1Sz8lQEuZP3gdhS+rv+zY2BjbfSq4HcZexmbBmh0NQ4Swd7i0hfkSM+koHZjVoPY/FJ/TW/Ks3iV+kpAZuVLCh60B66H8y9K5xu331nLxeYQJBAPzFeQPVJThxIBbk5g8/fYD/gbglEGqdurTJlo9tmCuqzty19fApBE+41ir9Sl2vguDnY1d9Zbuf1AlS21jsVx0CQQD4nNC1FyDKK6GxQvOm6Do+b663ft0WK7dum0c4pM57VPTRqxag4p6lYCu5KYmVvUL20KGE5LVZ9LaOIMIurD/ZAkEA4z4My1tFuPZKqQpjoXWsuNn7nrcDiTX/8iQBDTSzxx4qFtYnIh9d1uYO9Fr+DjeJa/PZpYAAg6rujutEcy8WKQJARir0WPgjIAx6gW5VGHmY3sBkvpOG0Ngb2JLo4hrZ0ENlKbwxEc2EW0aucH9BvsqBGOo/fCOU78O6tpiWVdf12QJAP8ENPIBQCLwHq0U5bzV+X94BmuOfTAqwvy/r6XQcOct0k/M/Lln0FUcPwAb6rl/1R55Xj1/DxI2UbTc4KNNpng==</private_key>
</pay>
</config>

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<config>
</config>

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<config>
<xbd>
<peis_url name="体检预约"></peis_url>
<peis_url name="体检预约">http://200.200.200.71:5050/peisReserve</peis_url>
<pacs_cloud_url name="云胶片">http://192.168.0.183:3307/wx3307</pacs_cloud_url>
<casebook_url name="病历复印">http://192.168.0.183:3307/wx3307</casebook_url>
<casebook_url name="病历复印"></casebook_url>
</xbd>
<rm_lis name="瑞美LIS">

Loading…
Cancel
Save