|
|
@@ -1,7 +1,8 @@
|
|
|
package thyyxxk.webserver.service.ca;
|
|
|
|
|
|
import cn.hutool.core.codec.Base64;
|
|
|
-import cn.hutool.core.convert.Convert;
|
|
|
+import cn.hutool.core.date.DateUnit;
|
|
|
+import cn.hutool.core.date.DateUtil;
|
|
|
import cn.hutool.core.io.FileUtil;
|
|
|
import cn.hutool.core.util.IdUtil;
|
|
|
import cn.hutool.core.util.IdcardUtil;
|
|
|
@@ -12,11 +13,11 @@ import cn.hutool.crypto.asymmetric.RSA;
|
|
|
import cn.hutool.json.JSONArray;
|
|
|
import cn.hutool.json.JSONObject;
|
|
|
import cn.hutool.json.JSONUtil;
|
|
|
-import com.alibaba.fastjson.JSON;
|
|
|
import com.dtflys.forest.Forest;
|
|
|
import com.dtflys.forest.http.ForestRequest;
|
|
|
import com.dtflys.forest.logging.LogConfiguration;
|
|
|
import com.dtflys.forest.utils.ForestDataType;
|
|
|
+import com.dtflys.forest.utils.RequestNameValue;
|
|
|
import lombok.*;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.jetbrains.annotations.NotNull;
|
|
|
@@ -24,6 +25,7 @@ import org.springframework.stereotype.Service;
|
|
|
import thyyxxk.webserver.config.Assertion;
|
|
|
import thyyxxk.webserver.config.envionment.ArchiveConfig;
|
|
|
import thyyxxk.webserver.config.envionment.CaData;
|
|
|
+import thyyxxk.webserver.config.envionment.SystemConfig;
|
|
|
import thyyxxk.webserver.config.exception.BizException;
|
|
|
import thyyxxk.webserver.config.exception.ExceptionEnum;
|
|
|
import thyyxxk.webserver.constants.YesOrNo;
|
|
|
@@ -33,7 +35,6 @@ import thyyxxk.webserver.entity.ResultVo;
|
|
|
import thyyxxk.webserver.entity.ca.*;
|
|
|
import thyyxxk.webserver.entity.ca.dto.CaSignData;
|
|
|
import thyyxxk.webserver.entity.login.UserInfo;
|
|
|
-import thyyxxk.webserver.service.hutoolcache.CaCache;
|
|
|
import thyyxxk.webserver.service.hutoolcache.UserCache;
|
|
|
import thyyxxk.webserver.service.zhuyuanyisheng.emr.EmrServer;
|
|
|
import thyyxxk.webserver.utils.R;
|
|
|
@@ -44,7 +45,9 @@ import java.io.UnsupportedEncodingException;
|
|
|
import java.net.URLDecoder;
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
import java.util.ArrayList;
|
|
|
+import java.util.Date;
|
|
|
import java.util.List;
|
|
|
+import java.util.Set;
|
|
|
|
|
|
@Slf4j
|
|
|
@Service
|
|
|
@@ -54,10 +57,10 @@ public class CaServer implements Assertion {
|
|
|
private final String archivePath;
|
|
|
private final static String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKAc+jzqVKHsjNdyuDGL7u6zZR55j87l+0GGT4/yEV+K8ZtL1GoIgOD6vv6eEg2iOwl6Wh6hq8XR4cIyzVyvMZ35dIw3oGN89ObtuCha7gLOmWYUIGVnkUBkLFeIdwe4F8bq1q15o7azsTVekSyNJf/wnxWMp8ibtvO41T8DIzZPAgMBAAECgYAeeLVVD4Gw2VyKij4sy8Var1CQxrDMPu+c7ktJCVguFzrZA8r2rQyeBIqB2aJ07smOibcJ+lm/Ca0N8O4tc/gcm4g/JsjBALFUmqyCkLQpRyIbz8V9uAmrLcchT74GS727Uv4KVTmQNDZTPIDdSZWSJ8S+WKmj8q3wUF1HLF1eXQJBAOC7D6xIB2XNS6Voa7C7m8aeg53lfcDUVJ6m0YFdvMbsU2cnlxnCSX1OsghFuVQLKcGeN+aXiTEileb3pAl2RC0CQQC2ZDtDb+1OmLmRNugp29Pmm8MM8KpktfqiBFi92Q747XwEeMgLi3qetq1wDT4dgvyURs2McsbF7diVtFv7DMXrAkAoYzXj3mYF86k+ps+DyZOrVF2PCOlauE4k3RIVz8TXcy1iAolzRalzbastNWqjIgZ1F3wwYtdzDyYlhifi03BZAkEArkgidPMbwDGhiAf+WhkrZz1JaTECsM9PGcergGVLsENFcQR0qstxtPz7x4lv5EVI0urA+Man93OptIsuJTr0VwJAd86EbHyOn5Lah7ptPGsmsqkrdMZcJ3chRj6pDtvb0A2lhaJfDRxmAiWCnviPhTApH6/1WRzBqc1ZTymyRTF9kA==";
|
|
|
private final static String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCgHPo86lSh7IzXcrgxi+7us2UeeY/O5ftBhk+P8hFfivGbS9RqCIDg+r7+nhINojsJeloeoavF0eHCMs1crzGd+XSMN6BjfPTm7bgoWu4CzplmFCBlZ5FAZCxXiHcHuBfG6tateaO2s7E1XpEsjSX/8J8VjKfIm7bzuNU/AyM2TwIDAQAB";
|
|
|
- private final CaCache cache;
|
|
|
private final UserCache userCache;
|
|
|
private final ArchiveConfig archiveConfig;
|
|
|
private final CaSignDataDao caSignDataDao;
|
|
|
+ private final SystemConfig systemConfig;
|
|
|
|
|
|
private final PatientIdCardTypeDao patientIdCardTypeDao;
|
|
|
|
|
|
@@ -65,18 +68,14 @@ public class CaServer implements Assertion {
|
|
|
|
|
|
RSA idCardRsa = new RSA(privateKey, publicKey);
|
|
|
|
|
|
- public CaServer(CaData caData, CaCache cache, UserCache userCache, ArchiveConfig archiveConfig, CaSignDataDao caSignDataDao, PatientIdCardTypeDao patientIdCardTypeDao) {
|
|
|
+ public CaServer(CaData caData, UserCache userCache, ArchiveConfig archiveConfig, CaSignDataDao caSignDataDao, PatientIdCardTypeDao patientIdCardTypeDao, SystemConfig systemConfig) {
|
|
|
this.caData = caData;
|
|
|
this.archivePath = archiveConfig.getPath() + "/archive/emr";
|
|
|
- this.cache = cache;
|
|
|
this.userCache = userCache;
|
|
|
this.caSignDataDao = caSignDataDao;
|
|
|
this.patientIdCardTypeDao = patientIdCardTypeDao;
|
|
|
this.archiveConfig = archiveConfig;
|
|
|
- }
|
|
|
-
|
|
|
- private String getRedisKey(String documentId) {
|
|
|
- return "ca-emr-" + documentId;
|
|
|
+ this.systemConfig = systemConfig;
|
|
|
}
|
|
|
|
|
|
public List<CaReturn.CaData> sendBatchByCode(CaSignClass.Send send) {
|
|
|
@@ -428,8 +427,18 @@ public class CaServer implements Assertion {
|
|
|
* @return 数据
|
|
|
*/
|
|
|
public ResultVo<CaSignClass.H5Return> h5EventSign(CaSignClass.H5EventSign value) {
|
|
|
- JSONObject ret = new JSONObject();
|
|
|
+ String id = CaSignData.getId(value.getDocumentId(), value.getSource());
|
|
|
+ CaSignData caSignData = caSignDataDao.selectById(id);
|
|
|
String uuid = IdUtil.simpleUUID();
|
|
|
+ if (caSignData != null) {
|
|
|
+ if (caSignData.getSignComplete()) {
|
|
|
+ return R.fail(ExceptionEnum.LOGICAL_ERROR, "病历已经完成,签名了。");
|
|
|
+ }
|
|
|
+ return R.fail(ExceptionEnum.LOGICAL_ERROR, "病历已经在签名");
|
|
|
+ }
|
|
|
+ String returnUrl = StrUtil.join("/",
|
|
|
+ caData.getHBoardSign().getReturnUrl(), id);
|
|
|
+ JSONObject ret = new JSONObject();
|
|
|
CaData.HBoardSign app = caData.getHBoardSign();
|
|
|
ret.set("api_key", app.getApiKey());
|
|
|
ret.set("api_secret", app.getApiSecret());
|
|
|
@@ -441,6 +450,7 @@ public class CaServer implements Assertion {
|
|
|
set("page", "0");
|
|
|
set("content", URLUtil.encode(value.getContent()));
|
|
|
}});
|
|
|
+ set("return_url", returnUrl);
|
|
|
}});
|
|
|
String execute = Forest
|
|
|
.post(caData.getHBoardSign().getUrl() + "/seal/h5EventSign")
|
|
|
@@ -448,47 +458,154 @@ public class CaServer implements Assertion {
|
|
|
.bodyType(ForestDataType.JSON)
|
|
|
.execute(String.class);
|
|
|
|
|
|
- return getStringResultVo(execute, uuid);
|
|
|
- }
|
|
|
+ // 组装签名人的信息
|
|
|
+ JSONArray jsonArray = new JSONArray();
|
|
|
+ jsonArray.put(CaSignClass.MoreEventSignData.builder()
|
|
|
+ .content(value.getContent())
|
|
|
+ .signType(value.getSignType())
|
|
|
+ .signTypeName(getSignTypeName(value.getSignType()))
|
|
|
+ .idCard(idCardRsa.decryptStr(value.getIdCard(), KeyType.PrivateKey))
|
|
|
+ .signName(value.getName())
|
|
|
+ .signOpinion(value.getSignOpinion())
|
|
|
+ .build());
|
|
|
+
|
|
|
+ CaSignClass.H5Return h5Return = getStringResultVo(execute);
|
|
|
+
|
|
|
+ H5ssmInfo ssmInfo = H5ssmInfo.builder()
|
|
|
+ .name(value.getName())
|
|
|
+ .signUrl(h5Return.getSignUrl())
|
|
|
+ .extSignUrl(h5Return.getExtSignUrl())
|
|
|
+ .sendTime(DateUtil.date())
|
|
|
+ .build();
|
|
|
|
|
|
+ // 组装短信发送的信息,让医生能重试
|
|
|
+ ret.set("ssmInfo", ssmInfo);
|
|
|
|
|
|
- @NotNull
|
|
|
- private ResultVo<CaSignClass.H5Return> getStringResultVo(String execute,
|
|
|
- String caDocumentId) {
|
|
|
- JSONObject rst = JSONUtil.parseObj(execute);
|
|
|
- String msg = URLUtil.decode(rst.getByPath("ret_msg", String.class));
|
|
|
- if (0 == rst.getByPath("ret_code", Integer.class)) {
|
|
|
- CaSignClass.H5Return build = CaSignClass.H5Return.builder()
|
|
|
- .result(rst.getByPath("sign_url", String.class))
|
|
|
- .caDocumentId(caDocumentId)
|
|
|
- .uuid("")
|
|
|
- .build();
|
|
|
- return ResultVoUtil.success(build);
|
|
|
+ CaSignData logData = CaSignData.builder()
|
|
|
+ .documentId(id)
|
|
|
+ .patNo(value.getPatNo())
|
|
|
+ .times(value.getTimes())
|
|
|
+ .caId(uuid)
|
|
|
+ .value(ret.toJSONString(0))
|
|
|
+ .createStaff(TokenUtil.getInstance().getTokenUserId())
|
|
|
+ .signType(CaSignData.SignType.H5_HTTP)
|
|
|
+ .signComplete(false)
|
|
|
+ .source(value.getSource().getCode())
|
|
|
+ .relationship(jsonArray.toJSONString(0))
|
|
|
+ .build();
|
|
|
+ caSignDataDao.insert(logData);
|
|
|
+
|
|
|
+ JSONObject ssmRst = ssmData(ssmInfo, value.getPhone());
|
|
|
+
|
|
|
+ if (ssmRst.getInt("code") != 0) {
|
|
|
+ return R.fail(ExceptionEnum.LOGICAL_ERROR,
|
|
|
+ "发送短信失败但是病历已生成,带签名文书" +
|
|
|
+ ssmRst.getStr("message"),
|
|
|
+ h5Return);
|
|
|
}
|
|
|
- return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST, "签名失败" + msg);
|
|
|
+
|
|
|
+ return R.ok(ExceptionEnum.SUCCESS_AND_EL_MESSAGE, h5Return);
|
|
|
}
|
|
|
|
|
|
- public ResultVo<JSONObject> downloadSealV2(String id, String documentId) {
|
|
|
- JSONObject ret = new JSONObject();
|
|
|
- ret.set("api_key", caData.getHBoardSign().getApiKey());
|
|
|
- ret.set("api_secret", caData.getHBoardSign().getApiSecret());
|
|
|
- ret.set("data", new JSONObject() {{
|
|
|
- set("document_no", id);
|
|
|
- }});
|
|
|
- String execute = Forest
|
|
|
- .post(caData.getHBoardSign().getUrl() + "/v2/seal/download")
|
|
|
- .addBody(ret)
|
|
|
+ // 这里不保存 手机号因为医生可能会选错
|
|
|
+ @Data
|
|
|
+ @Builder
|
|
|
+ @AllArgsConstructor
|
|
|
+ @NoArgsConstructor
|
|
|
+ public static class H5ssmInfo {
|
|
|
+ private String name;
|
|
|
+ private String signUrl;
|
|
|
+ private String extSignUrl;
|
|
|
+ private Date sendTime;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private JSONObject ssmData(H5ssmInfo info, String phone) {
|
|
|
+ return Forest.post(systemConfig.getMagicApi() + "/public/sms/sendMessageOne")
|
|
|
+ .addHeader("content-type", "application/json")
|
|
|
+ .addBody(new JSONObject() {{
|
|
|
+ set("templateId", "mb465551e87fdf4146aa745492c99a2812");
|
|
|
+ set("key", "zyb5beed2597b243608841cb719b5d4135");
|
|
|
+ set("data", new JSONArray() {{
|
|
|
+ add(new JSONObject() {{
|
|
|
+ set("phone", phone);
|
|
|
+ set("content", new JSONObject() {{
|
|
|
+ set("name", info.getName());
|
|
|
+ set("url", info.getSignUrl());
|
|
|
+ }});
|
|
|
+ }});
|
|
|
+ }});
|
|
|
+ }})
|
|
|
.bodyType(ForestDataType.JSON)
|
|
|
- .execute(String.class);
|
|
|
+ .execute(JSONObject.class);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Data
|
|
|
+ public static class RetrySMSParams {
|
|
|
+ private String phone;
|
|
|
+ private String documentId;
|
|
|
+ private CaSignClass.SignSourceEnum source;
|
|
|
+ }
|
|
|
+
|
|
|
+ public ResultVo<String> retrySMS(RetrySMSParams info) {
|
|
|
+ CaSignData caSignData = caSignDataDao.selectById(CaSignData.getId(info.getDocumentId(), info.getSource()));
|
|
|
+ if (caSignData == null) {
|
|
|
+ return R.fail(ExceptionEnum.NO_DATA_EXIST, "还没有发起签名请求。");
|
|
|
+ } else {
|
|
|
+ if (caSignData.getSignComplete()) {
|
|
|
+ return R.fail(ExceptionEnum.NO_DATA_EXIST, "病历签名完成无法发送。");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ JSONObject caParamsValue = JSONUtil.parseObj(caSignData.getValue());
|
|
|
+ H5ssmInfo ssmInfo = caParamsValue.getBean("ssmInfo", H5ssmInfo.class);
|
|
|
+
|
|
|
+ long between = DateUtil.between(DateUtil.date(), ssmInfo.getSendTime(), DateUnit.SECOND);
|
|
|
+
|
|
|
+ int maxSecond = 30;
|
|
|
+
|
|
|
+ if (between <= maxSecond) {
|
|
|
+ return R.fail(ExceptionEnum.ERROR_EL_MESSAGE, StrUtil.format("发送的太频繁了,请【{}】秒后,重试", maxSecond - between));
|
|
|
+ }
|
|
|
+
|
|
|
+ JSONObject ssmRst = ssmData(ssmInfo, info.getPhone());
|
|
|
+ ssmInfo.setSendTime(DateUtil.date());
|
|
|
+
|
|
|
+ caParamsValue.set("ssmInfo", ssmInfo);
|
|
|
+ // 重新更新时间
|
|
|
+ caSignDataDao.updateById(CaSignData.builder()
|
|
|
+ .documentId(caSignData.getDocumentId())
|
|
|
+ .value(caParamsValue.toJSONString(0))
|
|
|
+ .build());
|
|
|
+
|
|
|
+ if (ssmRst.getInt("code") != 0) {
|
|
|
+ return R.fail(ExceptionEnum.LOGICAL_ERROR,
|
|
|
+ "发送短信失败但是病历已生成,带签名文书" +
|
|
|
+ ssmRst.getStr("message")
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ return R.ok(ExceptionEnum.SUCCESS_AND_EL_MESSAGE, "发送成功");
|
|
|
+ }
|
|
|
+
|
|
|
+ @NotNull
|
|
|
+ private CaSignClass.H5Return getStringResultVo(String execute) {
|
|
|
JSONObject rst = JSONUtil.parseObj(execute);
|
|
|
String msg = URLUtil.decode(rst.getByPath("ret_msg", String.class));
|
|
|
if (0 == rst.getByPath("ret_code", Integer.class)) {
|
|
|
- return ResultVoUtil.success(rst);
|
|
|
+ return CaSignClass.H5Return.builder()
|
|
|
+ .signUrl(rst.getByPath("sign_url", String.class))
|
|
|
+ .extSignUrl(rst.getByPath("ext_sign_url", String.class))
|
|
|
+ .build();
|
|
|
}
|
|
|
- return ResultVoUtil.fail(ExceptionEnum.NO_DATA_EXIST, msg);
|
|
|
+ throw new BizException(ExceptionEnum.NO_DATA_EXIST, "签名失败" + msg);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+ /**
|
|
|
+ * 取消平板的签名
|
|
|
+ *
|
|
|
+ * @param id ca 的唯一id
|
|
|
+ */
|
|
|
public void cancelSignature(String id) {
|
|
|
JSONObject ret = new JSONObject();
|
|
|
CaData.HBoardSign app = caData.getHBoardSign();
|
|
|
@@ -520,16 +637,13 @@ public class CaServer implements Assertion {
|
|
|
if (caSignData == null) {
|
|
|
return R(-1, "病历不存在");
|
|
|
}
|
|
|
-
|
|
|
- JSONObject appDownload = appDownload(caSignData.getCaId());
|
|
|
-
|
|
|
CaSignClass.Upload build = CaSignClass.Upload
|
|
|
.builder()
|
|
|
.patNo(caSignData.getPatNo())
|
|
|
.times(caSignData.getTimes())
|
|
|
- .file(appDownload.getStr("pdf"))
|
|
|
+ .file(data.getStr("pdf"))
|
|
|
.fileName(document.replace(caSignData.getSource(), ""))
|
|
|
- .caData(appDownload.getStr("signed"))
|
|
|
+ .caData(data.getStr("signed", ""))
|
|
|
.build();
|
|
|
|
|
|
CaSignData updateData = CaSignData.builder().signComplete(true).documentId(document).build();
|
|
|
@@ -545,6 +659,35 @@ public class CaServer implements Assertion {
|
|
|
}};
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 这个是下载
|
|
|
+ *
|
|
|
+ * @param bizSn
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public JSONObject sealDownload(String bizSn) {
|
|
|
+ JSONObject data = new JSONObject() {{
|
|
|
+ set("api_key", caData.getHBoardSign().getApiKey());
|
|
|
+ set("api_secret", caData.getHBoardSign().getApiSecret());
|
|
|
+ set("data", new JSONObject() {{
|
|
|
+ set("document_no", bizSn);
|
|
|
+ }});
|
|
|
+ }};
|
|
|
+ JSONObject execute = Forest
|
|
|
+ .post(caData.getHBoardSign().getUrl() + "/v2/seal/download")
|
|
|
+ .bodyType(ForestDataType.JSON)
|
|
|
+ .addBody(data.toJSONString(0))
|
|
|
+ .execute(JSONObject.class);
|
|
|
+
|
|
|
+ execute.set("ret_msg", URLUtil.decode(execute.getStr("ret_msg")));
|
|
|
+ log.info("返回:{}", execute);
|
|
|
+
|
|
|
+ if (execute.getInt("ret_code") != 0) {
|
|
|
+ throw new BizException(ExceptionEnum.LOGICAL_ERROR, execute.getStr("ret_msg"));
|
|
|
+ }
|
|
|
+ return execute;
|
|
|
+ }
|
|
|
+
|
|
|
public JSONObject appDownload(String bizSn) {
|
|
|
JSONObject data = new JSONObject() {{
|
|
|
set("api_key", caData.getHBoardSign().getApiKey());
|
|
|
@@ -569,23 +712,22 @@ public class CaServer implements Assertion {
|
|
|
return execute;
|
|
|
}
|
|
|
|
|
|
- public String uploadBase64(CaSignClass.Upload upload) {
|
|
|
+ public void uploadBase64(CaSignClass.Upload upload) {
|
|
|
byte[] file = Base64.decode(upload.getFile());
|
|
|
String tmpPath = "/" + upload.getPatNo()
|
|
|
+ "/" + upload.getTimes()
|
|
|
+ "/emr"
|
|
|
+ "/" + upload.getFileName();
|
|
|
String pdfPath = tmpPath + ".pdf";
|
|
|
- String caPath = "/" + upload.getPatNo()
|
|
|
- + "/" + upload.getTimes()
|
|
|
- + "/ca/"
|
|
|
- + upload.getFileName()
|
|
|
- + ".txt";
|
|
|
+// String caPath = "/" + upload.getPatNo()
|
|
|
+// + "/" + upload.getTimes()
|
|
|
+// + "/ca/"
|
|
|
+// + upload.getFileName()
|
|
|
+// + ".txt";
|
|
|
|
|
|
// 写入CA数据
|
|
|
- FileUtil.writeString(upload.getCaData(), archivePath + caPath, StandardCharsets.UTF_8);
|
|
|
+// FileUtil.writeString(upload.getCaData(), archivePath + caPath, StandardCharsets.UTF_8);
|
|
|
FileUtil.writeBytes(file, archivePath + pdfPath);
|
|
|
- return "/archive" + pdfPath;
|
|
|
}
|
|
|
|
|
|
public ResultVo<List<PatientIdCardType>> getIdCardTypeList(String patNo) {
|
|
|
@@ -736,4 +878,22 @@ public class CaServer implements Assertion {
|
|
|
}
|
|
|
|
|
|
|
|
|
+ private String getSignTypeName(String type) {
|
|
|
+ if (StrUtil.isBlank(type)) {
|
|
|
+ return "朋友";
|
|
|
+ }
|
|
|
+ switch (type) {
|
|
|
+ case "1":
|
|
|
+ return "亲属";
|
|
|
+ case "2":
|
|
|
+ return "患者签名";
|
|
|
+ case "4":
|
|
|
+ return "伴侣";
|
|
|
+ case "3":
|
|
|
+ default:
|
|
|
+ return "朋友";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
}
|