EmrServer.java 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064
  1. package thyyxxk.webserver.service.zhuyuanyisheng.emr;
  2. import cn.hutool.core.codec.Base64;
  3. import cn.hutool.core.convert.Convert;
  4. import cn.hutool.core.util.StrUtil;
  5. import cn.hutool.extra.spring.SpringUtil;
  6. import cn.hutool.http.HttpRequest;
  7. import com.alibaba.fastjson.JSON;
  8. import com.alibaba.fastjson.JSONArray;
  9. import com.alibaba.fastjson.JSONObject;
  10. import com.alibaba.fastjson.serializer.SerializerFeature;
  11. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  12. import com.dtflys.forest.Forest;
  13. import com.dtflys.forest.http.ForestRequest;
  14. import com.dtflys.forest.interceptor.Interceptor;
  15. import com.dtflys.forest.reflection.ForestMethod;
  16. import com.dtflys.forest.utils.ForestDataType;
  17. import lombok.RequiredArgsConstructor;
  18. import lombok.extern.slf4j.Slf4j;
  19. import org.apache.commons.collections4.ListUtils;
  20. import org.jetbrains.annotations.NotNull;
  21. import org.springframework.beans.factory.annotation.Value;
  22. import org.springframework.scheduling.annotation.Scheduled;
  23. import org.springframework.stereotype.Service;
  24. import org.springframework.transaction.annotation.Transactional;
  25. import thyyxxk.webserver.config.envionment.ApiUrl;
  26. import thyyxxk.webserver.config.envionment.ArchiveConfig;
  27. import thyyxxk.webserver.config.envionment.SystemConfig;
  28. import thyyxxk.webserver.config.exception.ExceptionEnum;
  29. import thyyxxk.webserver.constants.Capacity;
  30. import thyyxxk.webserver.constants.EmrType;
  31. import thyyxxk.webserver.dao.his.LoginDao;
  32. import thyyxxk.webserver.dao.his.zhuyuanyisheng.emr.EmrFolderDao;
  33. import thyyxxk.webserver.dao.his.zhuyuanyisheng.emr.EmrPatientDao;
  34. import thyyxxk.webserver.entity.ResultVo;
  35. import thyyxxk.webserver.entity.datamodify.YzTemperature;
  36. import thyyxxk.webserver.entity.dictionary.CodeName;
  37. import thyyxxk.webserver.entity.drg.AuxiliaryFillingOfDiagnosis;
  38. import thyyxxk.webserver.entity.fluorescenceTest.FluorescenceSpecimenResult;
  39. import thyyxxk.webserver.entity.login.UserInfo;
  40. import thyyxxk.webserver.entity.medicalinsurance.inpatient.ZyPatientInfo;
  41. import thyyxxk.webserver.entity.outpatient.thmz.MzEmrPatientData;
  42. import thyyxxk.webserver.entity.zhuyuanyisheng.ZyZkList;
  43. import thyyxxk.webserver.entity.zhuyuanyisheng.emr.*;
  44. import thyyxxk.webserver.entity.zhuyuanyisheng.jianyanjiancha.YshYjReq;
  45. import thyyxxk.webserver.entity.zhuyuanyisheng.shoushu.OpRecord;
  46. import thyyxxk.webserver.http.drg.DrgWebApi;
  47. import thyyxxk.webserver.service.PublicServer;
  48. import thyyxxk.webserver.service.hutoolcache.ExtraCache;
  49. import thyyxxk.webserver.service.externalhttp.emr.EmrEditor;
  50. import thyyxxk.webserver.service.hutoolcache.UserCache;
  51. import thyyxxk.webserver.utils.*;
  52. import javax.annotation.PostConstruct;
  53. import java.util.*;
  54. import java.util.stream.Collectors;
  55. @Service
  56. @Slf4j
  57. @RequiredArgsConstructor
  58. public class EmrServer {
  59. private final EmrPatientDao dao;
  60. private final EmrEditor emr;
  61. private final EmrFolderDao folderDao;
  62. private final PublicServer publicServer;
  63. private final LoginDao loginDao;
  64. private final ExtraCache extraCache;
  65. private final UserCache userCache;
  66. private static final ArchiveConfig archiveConfig = SpringUtil.getBean(ArchiveConfig.class);
  67. private static String emrToken = null;
  68. private static String EMR_URL;
  69. public static final String THIS_IS_DIR = "This is Dir";
  70. private final DrgWebApi drgWebApi;
  71. private final ApiUrl apiUrl;
  72. private final SystemConfig systemConfig;
  73. @Value("${forest.variables.emrUrl}")
  74. public void setUrl(String key) {
  75. EMR_URL = key;
  76. }
  77. public static class EmrInterceptor implements Interceptor<String> {
  78. @Override
  79. public void onInvokeMethod(ForestRequest request, ForestMethod method, Object[] args) {
  80. request.addHeader("emr-token", emrToken);
  81. }
  82. }
  83. @PostConstruct
  84. @Scheduled(cron = "* * */12 * * ?")
  85. public void token() {
  86. if (EMR_URL == null) {
  87. return;
  88. }
  89. try {
  90. String URL = EMR_URL.replace("/emr/runtime/api/v1", "");
  91. String result = HttpRequest.post(URL + "/emr/runtime/api/v1/oauth/token")
  92. .header("Authorization", "Basic " + Base64.encode("user:dc71ccfec05b799ad52360c48d504019"))
  93. .form("grant_type", "client_credentials").execute().body();
  94. JSONObject data = JSONObject.parseObject(result);
  95. emrToken = data.getString("access_token");
  96. } catch (Exception ignored) {
  97. }
  98. }
  99. /**
  100. * 获取这个患者这个住院次数的全部电子病历
  101. *
  102. * @param patNo 住院号
  103. * @param times 住院次数
  104. * @return 数据
  105. */
  106. public ResultVo<List<EmrPatientData>> getPatientDataTree(String patNo, Integer times) {
  107. List<EmrPatientData> list = dao.getPatientData(patNo, times);
  108. List<EmrPatientData> folder = extraCache.getValue("电子病历文件夹", () -> folderDao.getFolderByName("HOSPITAL"));
  109. folder = JSONObject.parseArray(JSONObject.toJSONString(folder), EmrPatientData.class);
  110. if (ListUtil.isBlank(list)) {
  111. return ResultVoUtil.success(folder);
  112. }
  113. folder.addAll(list);
  114. Map<String, EmrPatientData> folderMap = new HashMap<>();
  115. List<EmrPatientData> result = new ArrayList<>();
  116. folder.add(EmrPatientData.builder()
  117. .id(null)
  118. .emrDocumentId("noFolder")
  119. .name("可拖动病历调整到合适文件夹,右键确认排序")
  120. .emrCategoryCode(THIS_IS_DIR)
  121. .sort(0)
  122. .children(new ArrayList<>())
  123. .parent(null)
  124. .build());
  125. for (EmrPatientData item : folder) {
  126. folderMap.put(item.getEmrDocumentId(), item);
  127. if (item.getParent() == null) {
  128. if ("group-category".equals(item.getType()))
  129. result.add(item);
  130. }
  131. }
  132. for (EmrPatientData item : folder) {
  133. String key = item.getParent();
  134. EmrPatientData parent = folderMap.get(key);
  135. if (parent != null) {
  136. if (parent.getChildren() == null) {
  137. parent.setChildren(new ArrayList<>());
  138. }
  139. parent.getChildren().add(item);
  140. } else {
  141. if (THIS_IS_DIR.equals(item.getEmrCategoryCode())) {
  142. continue;
  143. }
  144. EmrPatientData no = folderMap.get("noFolder");
  145. no.getChildren().add(item);
  146. }
  147. }
  148. result.sort(Comparator.comparing((o) -> o.getSort() == null ? 0 : o.getSort()));
  149. return ResultVoUtil.success(result);
  150. }
  151. public ResultVo<Map<String, List<JSONObject>>> getEmrTree(String type) {
  152. Map<String, List<JSONObject>> map = new HashMap<>(Capacity.TWO);
  153. if ("all".equals(type)) {
  154. map.put("all", wholeHospitalTemplate());
  155. map.put("dept", getDeptTemplate());
  156. } else if ("dept".equals(type)) {
  157. map.put("dept", getDeptTemplate());
  158. } else if ("hosp".equals(type)) {
  159. map.put("all", wholeHospitalTemplate());
  160. }
  161. return ResultVoUtil.success(map);
  162. }
  163. private List<JSONObject> getDeptTemplate() {
  164. UserInfo user = userCache.getUserInfoByToken();
  165. JSONArray data = new JSONArray();
  166. data.addAll(emr.getDeptList(user.getDeptCode()));
  167. if (ListUtil.notBlank(user.getPartTimeDept())) {
  168. user.getPartTimeDept().forEach(item -> {
  169. data.addAll(emr.getDeptList(item));
  170. });
  171. }
  172. return emrToTree(data);
  173. }
  174. /**
  175. * 获取 整个医院模板
  176. */
  177. private List<JSONObject> wholeHospitalTemplate() {
  178. JSONArray data;
  179. if (StrUtil.isBlank(systemConfig.getEmrZyDeptCode())) {
  180. data = emr.getEmrTree();
  181. } else {
  182. data = emr.getDeptList(systemConfig.getEmrZyDeptCode());
  183. }
  184. return emrToTree(data);
  185. }
  186. /**
  187. * 电子病历转成树状图 二次封装
  188. *
  189. * @param data 模板数据
  190. * @return 返回
  191. */
  192. public List<JSONObject> emrToTree(JSONArray data) {
  193. List<JSONObject> tree = new ArrayList<>();
  194. if (data.isEmpty()) {
  195. return tree;
  196. }
  197. emrArrToTree(data, tree);
  198. return tree;
  199. }
  200. /**
  201. * 电子病历转成树状图
  202. *
  203. * @param data 电子病历
  204. * @param tree 树
  205. */
  206. public static void emrArrToTree(JSONArray data, List<JSONObject> tree) {
  207. Map<String, JSONObject> map = new HashMap<>(data.size());
  208. for (int i = 0; i < data.size(); i++) {
  209. JSONObject item = data.getJSONObject(i);
  210. if (item.get("parent") == null) {
  211. tree.add(item);
  212. }
  213. map.put(item.getString("_id"), item);
  214. }
  215. for (int i = 0; i < data.size(); i++) {
  216. JSONObject item = data.getJSONObject(i);
  217. if (map.containsKey(item.getString("parent"))) {
  218. JSONObject parentList = map.get(item.getString("parent"));
  219. parentList.computeIfAbsent("children", k -> new JSONArray());
  220. parentList.getJSONArray("children").add(item);
  221. }
  222. }
  223. }
  224. /**
  225. * 获取电子病历的片段
  226. *
  227. * @return 树
  228. */
  229. public ResultVo<List<JSONObject>> getSnippetTree() {
  230. JSONArray data = emr.getSnippetByDept(systemConfig.getEmrZyDeptCode());
  231. List<JSONObject> tree = new ArrayList<>();
  232. emrArrToTree(data, tree);
  233. return ResultVoUtil.success(tree);
  234. }
  235. /**
  236. * 提取患者数据元
  237. *
  238. * @param param 结构化文档
  239. */
  240. public Map<String, Object> extractDataElement(EmrPatientData param) {
  241. EmrDataExtract emrDataExtract = dao.extractDataSource(param.getEmrCategoryCode());
  242. if (emrDataExtract == null) {
  243. return new HashMap<>();
  244. }
  245. // 获取 需要提取的数据元
  246. List<String> strings = JSON.parseArray(emrDataExtract.getDataExtract(), String.class);
  247. // 获取前端传入的数据元
  248. Map<String, Object> extractedData = getStringObjectMap(param, strings);
  249. EmrDataElement emrDataElement = dao.obtainPatientSOriginalData(param.getPatNo(), param.getTimes());
  250. if (emrDataElement == null) {
  251. // 创建的病历可以解锁了
  252. dao.insertDataSource(param.getPatNo(), param.getTimes(), JSON.toJSONString(extractedData));
  253. } else {
  254. JSONObject jsonObject = JSONObject.parseObject(emrDataElement.getDataElement());
  255. jsonObject.putAll(extractedData);
  256. dao.updatePatientDataSource(param.getPatNo(), param.getTimes(), JSON.toJSONString(jsonObject));
  257. }
  258. return extractedData;
  259. }
  260. @NotNull
  261. private static Map<String, Object> getStringObjectMap(EmrPatientData param, List<String> strings) {
  262. JSONObject elementData = param.getEmrDataElement();
  263. // 提取到的数据
  264. Map<String, Object> extractedData = new HashMap<>(strings.size());
  265. for (String el : strings) {
  266. if (elementData.containsKey(el)) {
  267. JSONObject item;
  268. try {
  269. item = elementData.getJSONObject(el);
  270. } catch (Exception ignore) {
  271. throw new RuntimeException("数据元提取失败,但病历保存成功。数据元名称:【" + el + "】,粘贴时请使用(文本粘贴)。");
  272. }
  273. Object value = item.get("value");
  274. if (value != null) {
  275. extractedData.put(el, value);
  276. }
  277. }
  278. }
  279. return extractedData;
  280. }
  281. /**
  282. * 保存电子病历
  283. *
  284. * @param param 参数
  285. * @return 提示
  286. */
  287. @Transactional(rollbackFor = Exception.class)
  288. public ResultVo<Map<String, Object>> insertEmrData(EmrPatientData param) {
  289. EmrPatientData patientData = dao.getCategoryCodeByDocumentId(param.getEmrDocumentId());
  290. // TM的新增病历也是用的这个方法,所以要考虑没有id的病历
  291. if (patientData != null) {
  292. if (!SignCompleteEnum.INIT.getCode().equals(patientData.getSignComplete())) {
  293. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "患者完成电子签名无法修改。");
  294. }
  295. if (patientData.getDelFlag() == 1) {
  296. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "病历已删除。");
  297. }
  298. }
  299. JSONObject saveJson = new JSONObject();
  300. saveJson.put("document", param.getDocumentData());
  301. try {
  302. emr.saveDocument(saveJson);
  303. } catch (Exception e) {
  304. return ResultVoUtil.fail(ExceptionEnum.EMR_SAVE, "病历保存错误,请重试!" + e.getMessage());
  305. }
  306. param.setCreateId(TokenUtil.getInstance().getTokenUserId());
  307. Integer isUpdated = dao.whetherThereIsAMedicalRecord(param.getEmrDocumentId());
  308. if (isUpdated != null) {
  309. dao.updateCreatedTemplate(param);
  310. insertAFragmentOfTheCourseOfTheDisease(isUpdated, param.getFragment());
  311. } else {
  312. // 新增的时候插入数据
  313. ZyPatientInfo patInfo = publicServer.getPatInfo(param.getPatNo(), param.getTimes());
  314. param.setReferPhysician(patInfo.getReferPhysician());
  315. param.setConsultPhysician(patInfo.getConsultPhysician());
  316. param.setDeptDirector(patInfo.getDeptDirector());
  317. dao.emrInsertForTheFirstTime(param);
  318. insertAFragmentOfTheCourseOfTheDisease(param.getId(), param.getFragment());
  319. }
  320. Map<String, Object> extractedData;
  321. try {
  322. extractedData = extractDataElement(param);
  323. } catch (Exception e) {
  324. return ResultVoUtil.fail(ExceptionEnum.EMR_EXTRACT_OBJECTS, e.getMessage());
  325. }
  326. return ResultVoUtil.success(extractedData);
  327. }
  328. /**
  329. * 插入病程记录的片段
  330. *
  331. * @param id 病程记录
  332. * @param fragment 片段
  333. */
  334. private void insertAFragmentOfTheCourseOfTheDisease(Integer id, List<EmrProgressNote> fragment) {
  335. if (ListUtil.isBlank(fragment)) {
  336. return;
  337. }
  338. dao.delOldFragment(id);
  339. List<List<EmrProgressNote>> lists = ListUtils.partition(fragment, 50);
  340. for (List<EmrProgressNote> list : lists) {
  341. dao.insertFragment(list, id);
  342. }
  343. }
  344. /**
  345. * 根据患者的电子病历 id 来删除
  346. * 这里用的是逻辑删除
  347. *
  348. * @param documentId 电子病历id
  349. * @return 删除电子病历的同时需要删除, 提取到的数据源.
  350. */
  351. public ResultVo<List<String>> deletePatientEmrByDocumentId(String documentId) {
  352. EmrPatientData patientData = dao.getCategoryCodeByDocumentId(documentId);
  353. if (!SignCompleteEnum.INIT.getCode().equals(patientData.getSignComplete())) {
  354. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "患者完成电子签名无法删除。");
  355. }
  356. // 医务部可以自由删除其他医生的病历
  357. if (!publicServer.needRule(38)) {
  358. if (!patientData.getCreateId().equals(TokenUtil.getInstance().getTokenUserId())) {
  359. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "创建人不是你无法删除。");
  360. }
  361. }
  362. EmrDataExtract emrDataExtract = dao.extractDataSource(patientData.getEmrCategoryCode());
  363. List<String> strings = new ArrayList<>();
  364. if (emrDataExtract != null) {
  365. // 获取 需要提取的数据元
  366. strings = JSON.parseArray(emrDataExtract.getDataExtract(), String.class);
  367. // 获取到已经提取的数据
  368. EmrDataElement emrDataElement = dao.obtainPatientSOriginalData(patientData.getPatNo(), patientData.getTimes());
  369. // 转 json
  370. JSONObject jsonObject = JSONObject.parseObject(emrDataElement.getDataElement());
  371. for (String string : strings) {
  372. // 删除提取到的数据
  373. jsonObject.remove(string);
  374. }
  375. // 更新患者数据元
  376. dao.updatePatientDataSource(patientData.getPatNo(), patientData.getTimes(), JSON.toJSONString(jsonObject));
  377. }
  378. // 删除病历
  379. dao.deletePatientEmrByDocumentId(documentId, TokenUtil.getInstance().getTokenUserId());
  380. return ResultVoUtil.success(strings);
  381. }
  382. /**
  383. * 查询患者是否有指定的病历了
  384. *
  385. * @param param 住院号,住院次数,病历编码
  386. * @return 返回 Boolean
  387. */
  388. public ResultVo<Boolean> queryWhetherThePatientHasASpecifiedMedicalRecord(EmrPatientData param) {
  389. return ResultVoUtil.success(dao.queryWhetherThePatientHasASpecifiedMedicalRecord(param.getPatNo(), param.getTimes(), param.getEmrCategoryCode()) == 1);
  390. }
  391. /**
  392. * 医生诊断热缩
  393. *
  394. * @param userCode 医生编码
  395. * @param code 诊断 code
  396. * @param tableName 表名
  397. */
  398. public void hotSearchSorting(String userCode, String code, String tableName) {
  399. boolean insert = dao.queryWhetherThereIsHotSearch(userCode, code, tableName) == 0;
  400. if (insert) {
  401. dao.hotSearchSorting(userCode, code, tableName);
  402. } else {
  403. dao.updateHotSearch(userCode, code, tableName);
  404. }
  405. }
  406. /**
  407. * 根据文档 id 提交病历
  408. *
  409. * @param documentId 文档id
  410. * @return 返回数据
  411. */
  412. public ResultVo<String> submitMedicalRecord(String documentId) {
  413. String userCode = TokenUtil.getInstance().getTokenUserId();
  414. String createdId = dao.getDocumentIdCreatedBy(documentId);
  415. if (userCode.equals(createdId)) {
  416. dao.updateSubmissionFlag(documentId, userCode);
  417. return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE, "提交成功");
  418. }
  419. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "创建人不一致无法修改。");
  420. }
  421. public ResultVo<String> audit(String documentId) {
  422. String userCode = TokenUtil.getInstance().getTokenUserId();
  423. int count = dao.updateAuditByDocumentId(documentId, userCode);
  424. if (count > 0) {
  425. return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE, "审核成功");
  426. }
  427. return ResultVoUtil.success(ExceptionEnum.NO_DATA_EXIST, "操作失败,可能原因,已经审核完成或还未保存。");
  428. }
  429. /**
  430. * 获取电子病历数据
  431. *
  432. * @param panNo 住院号
  433. * @param times 住院次数
  434. * @param etType 类型
  435. * @return 返回数据
  436. */
  437. public JSONArray getEmrData(String panNo, Integer times, EmrType etType) {
  438. // 查询这个病历的 唯一 id
  439. List<String> idList = dao.getDocumentIdByPatietn(panNo, times, etType.getName());
  440. JSONArray returnArray = new JSONArray();
  441. if (ListUtil.isBlank(idList)) {
  442. return returnArray;
  443. }
  444. Map<String, JSONObject> surgicalSequencing = new TreeMap<>();
  445. for (String s : idList) {
  446. JSONObject jsonObject = emr.getEditorJsonDataByDocumentId(s);
  447. if (etType.getCode() == EmrType.DIAGNOSIS.getCode()) {
  448. returnArray.addAll(extractDiagnosis(jsonObject));
  449. } else if (etType.getCode() == EmrType.OPERATION.getCode()) {
  450. String key = DateUtil.formatDatetime(jsonObject.getJSONObject("手术日期").getDate("value"));
  451. surgicalSequencing.put(key, jsonObject);
  452. }
  453. }
  454. if (!surgicalSequencing.isEmpty()) {
  455. for (Map.Entry<String, JSONObject> item : surgicalSequencing.entrySet()) {
  456. returnArray.add(item.getValue());
  457. }
  458. }
  459. return returnArray;
  460. }
  461. /**
  462. * 获取患者提取到的数据
  463. *
  464. * @param patNo 住院号
  465. * @param times 次数
  466. * @return 返回 json
  467. */
  468. public JSONObject getEmrPatientData(String patNo, Integer times) {
  469. String js = dao.getEmrPatientData(patNo, times);
  470. if (StringUtil.isBlank(js)) {
  471. return new JSONObject();
  472. }
  473. return JSON.parseObject(js);
  474. }
  475. /**
  476. * 获取患者的手术
  477. *
  478. * @param patNo 获取住院号
  479. * @param times 获取住院次数
  480. * @return 返回数据
  481. */
  482. public JSONArray getPatientSurgery(String patNo, Integer times) {
  483. List<String> idList = dao.getDocumentIdByPatietn(patNo, times, "shoushujilu");
  484. JSONArray returnArray = new JSONArray();
  485. if (ListUtil.isBlank(idList)) {
  486. return returnArray;
  487. }
  488. Map<String, JSONObject> surgicalSequencing = new TreeMap<>();
  489. for (String s : idList) {
  490. JSONObject jsonObject = emr.getEditorJsonDataByDocumentId(s);
  491. JSONObject surgeryDate = jsonObject.getJSONObject("手术日期");
  492. if (null == surgeryDate) {
  493. continue;
  494. }
  495. String key = DateUtil.formatDatetime(surgeryDate.getDate("value"));
  496. if (StringUtil.isBlank(key)) {
  497. continue;
  498. }
  499. surgicalSequencing.put(key, jsonObject);
  500. }
  501. if (!surgicalSequencing.isEmpty()) {
  502. for (Map.Entry<String, JSONObject> item : surgicalSequencing.entrySet()) {
  503. returnArray.add(item.getValue());
  504. }
  505. }
  506. return returnArray;
  507. }
  508. private JSONArray extractDiagnosis(JSONObject jsonObject) {
  509. JSONObject diagnosis = jsonObject.getJSONObject("入院诊断");
  510. if (diagnosis != null) {
  511. JSONArray diagnosisArr = diagnosis.getJSONArray("value");
  512. if (diagnosisArr != null) {
  513. return diagnosisArr;
  514. }
  515. }
  516. return new JSONArray();
  517. }
  518. public ResultVo<String> getDrgIntelligentGrouping(String patNo, Integer times) {
  519. if (StrUtil.isBlank(apiUrl.getDrgWebApi())) {
  520. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "未找到DRG服务");
  521. }
  522. // 获取诊断
  523. JSONArray diagnosis = getEmrData(patNo, times, EmrType.DIAGNOSIS);
  524. // 获取手术
  525. JSONArray operation = getEmrData(patNo, times, EmrType.OPERATION);
  526. int ledgerSn = publicServer.getLedgerSn(patNo, times);
  527. // 获取患者数据
  528. Map<String, String> mapData = dao.drgPatientInfo(patNo, times, ledgerSn);
  529. if (mapData == null) {
  530. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "没有查询到患者信息。");
  531. }
  532. mapData.put("visit_id", patNo + "_" + times + "_" + ledgerSn);
  533. mapData.put("bah", patNo + "_" + times);
  534. for (int i = 0; i < diagnosis.size(); i++) {
  535. JSONObject item = diagnosis.getJSONObject(i);
  536. if (i == 0) {
  537. mapData.put("jbdm", item.getString("code"));
  538. mapData.put("zyzd", item.getString("name"));
  539. } else {
  540. mapData.put("jbdm" + i, item.getString("code"));
  541. }
  542. }
  543. int operationIndex = 1;
  544. for (int i = 0; i < operation.size(); i++) {
  545. JSONObject item = operation.getJSONObject(i);
  546. JSONArray list;
  547. try {
  548. list = item.getJSONObject("手术名称").getJSONArray("value");
  549. } catch (Exception e) {
  550. continue;
  551. }
  552. if (list == null) {
  553. continue;
  554. }
  555. for (int a = 0; a < list.size(); a++) {
  556. JSONObject valueList = list.getJSONObject(a);
  557. mapData.put("ssjczbm" + operationIndex, valueList.getString("code"));
  558. if (operationIndex == 1) {
  559. mapData.put("ssjczmc" + operationIndex, valueList.getString("name"));
  560. }
  561. operationIndex++;
  562. }
  563. }
  564. AuxiliaryFillingOfDiagnosis data = EntityCopy.Copy(mapData, AuxiliaryFillingOfDiagnosis.class);
  565. String toJsonStr = JSON.toJSONString(data, SerializerFeature.WriteNullStringAsEmpty);
  566. return drgWebApi.getDrgIntelligentGrouping(JSON.parseObject(toJsonStr));
  567. }
  568. /**
  569. * 获取患者最大的住院次数
  570. *
  571. * @param patNo 住院号
  572. * @return 返回最大次数
  573. */
  574. public ResultVo<Integer> getDischargeTimes(String patNo) {
  575. Integer times = dao.getMaxTimes(patNo);
  576. if (times == null) {
  577. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "没有查询到患者信息。");
  578. }
  579. return ResultVoUtil.success(times);
  580. }
  581. public ResultVo<JSONObject> getExtractDataElement(String patNo, Integer times) {
  582. Map<String, String> map = dao.selectEmrDataElement(patNo, times);
  583. if (map == null) {
  584. return ResultVoUtil.success();
  585. } else {
  586. return ResultVoUtil.success(JSONObject.parseObject(map.get("data_element")));
  587. }
  588. }
  589. public ResultVo<List<CodeName>> getAllWards() {
  590. return ResultVoUtil.success(loginDao.getAllWards());
  591. }
  592. /**
  593. * 获取患者已经被删除的病历,管理员不需要限制
  594. *
  595. * @param patNo 住院号
  596. * @return 返回
  597. */
  598. public ResultVo<List<EmrPatientData>> getDeleteMedicalRecord(String patNo) {
  599. Integer times = dao.getAdmissTimes(patNo);
  600. if (times == null) {
  601. return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "出院患者无法恢复病历,如果要恢复请先召回在院。");
  602. }
  603. String userCode = TokenUtil.getInstance().getTokenUserId();
  604. if (publicServer.needRule()) {
  605. userCode = "";
  606. }
  607. return ResultVoUtil.success(dao.selectEmrDeteles(patNo, times, userCode));
  608. }
  609. public ResultVo<JSONObject> getInvalidByDocumentId(String id) {
  610. return ResultVoUtil.success(emr.getInvalidByDocumentIdApi(id));
  611. }
  612. /**
  613. * 恢复电子病历
  614. *
  615. * @param documentId 电子病历文档
  616. * @return 返回提示
  617. */
  618. public ResultVo<String> resumeMedicalRecords(String documentId) {
  619. EmrPatientData data = dao.selectemPatientDataOne(documentId);
  620. if (data.getDelFlag() == 0) {
  621. return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "病历已经被恢复了请勿重复点击");
  622. }
  623. Integer times = dao.getAdmissTimes(data.getPatNo());
  624. if (times == null) {
  625. return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "出院患者无法恢复病历,如果要恢复请先召回在院。");
  626. }
  627. dao.updateDeleteFlag(data.getId());
  628. TryUtil.ignoreErr(() -> {
  629. JSONObject param = new JSONObject();
  630. param.put("_id", documentId);
  631. param.put("valid", 1);
  632. emr.resumeMedicalRecords(documentId, param);
  633. });
  634. return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE, "病历恢复成功。");
  635. }
  636. /**
  637. * 查询出院患者的申请
  638. *
  639. * @param flag 1 只查询自己的 2 查询审核的
  640. * @return 提示
  641. */
  642. public ResultVo<List<DischargedEmrModifyApply>> getDisReqEmr(Integer flag) {
  643. QueryWrapper<?> qw = new QueryWrapper<>();
  644. if (flag == 1) {
  645. qw.eq("req_id", TokenUtil.getInstance().getTokenUserId());
  646. } else if (flag == 2) {
  647. qw.eq("req_status", 0);
  648. }
  649. qw.ge("edit_date", DateUtil.formatDatetime(new Date(), DateUtil.DATE));
  650. return ResultVoUtil.success(dao.getDisReqEmr(qw));
  651. }
  652. public ResultVo<List<DischargedEmrModifyApply>> downloadTheDischargeEdit(String start, String end) {
  653. return ResultVoUtil.success(dao.selectDisReqEmyDownload(start, end));
  654. }
  655. /**
  656. * 申请出院患者修改
  657. *
  658. * @param param 参数
  659. * @return 提示
  660. */
  661. @Transactional(rollbackFor = Exception.class)
  662. public ResultVo<String> saveDisEmrReq(DischargedEmrModifyApply param) {
  663. param.setReqId(TokenUtil.getInstance().getTokenUserId());
  664. int num = dao.deleteRequest(param.getPatNo());
  665. dao.insertApplicationEmrDis(param);
  666. if (num > 0) {
  667. return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE, "修改原申请成功。");
  668. } else {
  669. return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE, "申请成功。");
  670. }
  671. }
  672. /**
  673. * 删除申请
  674. *
  675. * @param patNo 住院号
  676. * @return 提示
  677. */
  678. public ResultVo<String> deleteDisEmrDis(String patNo) {
  679. dao.deleteRequest(patNo);
  680. return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE, "操作成功。");
  681. }
  682. /**
  683. * 通过申请
  684. *
  685. * @param patNo 住院号
  686. * @return 提示
  687. */
  688. public ResultVo<String> adoptEmrDisReq(String patNo) {
  689. int num = dao.adoptEmrDisReq(patNo, null, 1);
  690. if (num > 0) {
  691. return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE);
  692. }
  693. return ResultVoUtil.fail(ExceptionEnum.INTERNAL_SERVER_ERROR, "操作失败,原申请可能已经被删除了。");
  694. }
  695. /**
  696. * 拒绝出院患者申请
  697. *
  698. * @param patNo 住院号
  699. * @param reviewNotes 审核信息
  700. * @return 提示
  701. */
  702. public ResultVo<String> refuseEmrDisReq(String patNo, String reviewNotes) {
  703. int num = dao.adoptEmrDisReq(patNo, reviewNotes, 2);
  704. if (num > 0) {
  705. return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE);
  706. }
  707. return ResultVoUtil.fail(ExceptionEnum.INTERNAL_SERVER_ERROR, "操作失败,原申请可能已经被删除了。");
  708. }
  709. /**
  710. * 查询出院患者是否已经通过了编辑
  711. *
  712. * @param patNo 住院号
  713. * @return Boolean
  714. */
  715. public ResultVo<Boolean> isDisReqEdit(String patNo) {
  716. QueryWrapper<?> qw = new QueryWrapper<>();
  717. qw.eq("pat_no", patNo);
  718. qw.eq("req_status", 1);
  719. qw.ge("edit_date", DateUtil.formatDatetime(new Date(), DateUtil.DATE));
  720. List<DischargedEmrModifyApply> list = dao.getDisReqEmr(qw);
  721. if (ListUtil.isBlank(list)) {
  722. return ResultVoUtil.success(false);
  723. } else {
  724. return ResultVoUtil.success(true);
  725. }
  726. }
  727. public ResultVo<Object> getHistory(String documentId) {
  728. return ResultVoUtil.success(emr.getHistory(documentId));
  729. }
  730. public ResultVo<List<MedicalHistoryPrompts>> getEmrTips() {
  731. return ResultVoUtil.success(dao.selectEmrTips(TokenUtil.getInstance().getTokenUserId()));
  732. }
  733. public ResultVo<String> addEmrTips(MedicalHistoryPrompts param) {
  734. UserInfo userInfo = userCache.getUserInfoByToken();
  735. param.setDept(userInfo.getDeptCode());
  736. param.setCreatorId(userInfo.getCode());
  737. dao.insertEmrTips(param);
  738. return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE);
  739. }
  740. public ResultVo<String> updateEmrTips(MedicalHistoryPrompts param) {
  741. if (param.getId() == null) {
  742. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "id 为空无法更新。");
  743. }
  744. dao.updateEmrTips(param);
  745. return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE);
  746. }
  747. public ResultVo<String> deleteEmrTips(Integer id) {
  748. dao.delEmrTips(id);
  749. return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE);
  750. }
  751. /**
  752. * 在病程记录中获取文本数据
  753. *
  754. * @param name 名称
  755. * @return 返回数据
  756. */
  757. public ResultVo<List<MedicalHistoryPrompts>> getEmrTipsData(String name, int typeCode) {
  758. QueryWrapper<?> qw = new QueryWrapper<>();
  759. UserInfo us = userCache.getUserInfoByToken();
  760. if (typeCode == 1) {
  761. qw.eq("creator_id", us.getCode());
  762. } else if (typeCode == 2) {
  763. qw.eq("dept", us.getDeptCode());
  764. }
  765. qw.like("query_key", name)
  766. .eq("type_code", typeCode)
  767. .orderByDesc("count");
  768. return ResultVoUtil.success(dao.getEmrTipsData(qw));
  769. }
  770. public ResultVo<List<ZyPatientInfo>> getListOfDischargedPatients(String patNo) {
  771. List<ZyPatientInfo> list = dao.getListOfDischargedPatients(patNo);
  772. if (ListUtil.isBlank(list)) {
  773. return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "没有" + patNo + "的出院记录。");
  774. }
  775. return ResultVoUtil.success(list);
  776. }
  777. public ResultVo<JSONObject> getYzTemperature(YzTemperatureParam param) {
  778. JSONObject js = new JSONObject();
  779. QueryWrapper<?> qw = new QueryWrapper<>();
  780. qw.eq("inpatient_no", param.getPatNo())
  781. .eq("admiss_times", param.getTimes())
  782. .ge("CONVERT(varchar(10), rec_date, 23)", param.getStartTime())
  783. .le("CONVERT(varchar(10), rec_date, 23)", param.getEndTime());
  784. List<YzTemperature> list = dao.getYzTemperature(qw);
  785. if (ListUtil.isBlank(list)) {
  786. return ResultVoUtil.success(js);
  787. }
  788. Map<Date, YzTemperature> map = new LinkedHashMap<>(list.size());
  789. for (YzTemperature item : list) {
  790. Date key = item.getTempDate();
  791. if (map.containsKey(key)) {
  792. YzTemperature yz = map.get(key);
  793. yz.setOtherInfo(nullToEmpty(yz.getOtherInfo()) + nullToEmpty(item.getOtherInfo()));
  794. } else {
  795. map.put(key, item);
  796. }
  797. }
  798. js.put("list", list);
  799. js.put("map", map);
  800. return ResultVoUtil.success(js);
  801. }
  802. public ResultVo<List<YshYjReq>> getExamine(String patNo, Integer times) {
  803. return ResultVoUtil.success(dao.getExamine(patNo, times));
  804. }
  805. private String nullToEmpty(String str) {
  806. if (StringUtil.isBlank(str)) {
  807. return "";
  808. }
  809. return str;
  810. }
  811. public ResultVo<ZyZkList> whetherItExistsInTheDepartment(String patNo, Integer times) {
  812. ZyZkList zk = dao.getMaxTransferDateByPatNo(patNo, times);
  813. if (zk != null) {
  814. zk.setTimeout(DateUtil.moreThanHours(zk.getOpTime(), 48));
  815. }
  816. return ResultVoUtil.success(zk);
  817. }
  818. public ResultVo<String> electronicMedicalRecordSequencing(List<EmrPatientData> data) {
  819. if (ListUtil.isBlank(data)) {
  820. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "请选择有效的分类数据。");
  821. }
  822. ListUtil.batchList(data, EmrPatientDao.class, (m, item) -> {
  823. m.updateTheNode(item.getParent(), item.getId());
  824. });
  825. return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE, "操作成功。");
  826. }
  827. public ResultVo<Map<String, List<EmrPatientData>>> getPastHistory(String patNo, Integer times) {
  828. List<EmrPatientData> list = dao.getHisPatInfo(patNo, times);
  829. if (ListUtil.isBlank(list)) {
  830. return ResultVoUtil.success(new HashMap<>());
  831. }
  832. Map<String, List<EmrPatientData>> grouping = list.stream().collect(
  833. Collectors.groupingBy(item -> item.getTimes().toString())
  834. );
  835. return ResultVoUtil.success(grouping);
  836. }
  837. public ResultVo<Map<Integer, List<MzEmrPatientData>>> getMzPatientDataByPatNo(String patNo) {
  838. String mzNo = dao.getMzNoByPatNo(patNo);
  839. Map<Integer, List<MzEmrPatientData>> map1 = new HashMap<>();
  840. if (StringUtil.isBlank(mzNo)) {
  841. return ResultVoUtil.success(map1);
  842. }
  843. List<MzEmrPatientData> mzList = dao.getEmrPatientMz(mzNo);
  844. if (ListUtil.isBlank(mzList)) {
  845. return ResultVoUtil.success(map1);
  846. }
  847. Map<Integer, List<MzEmrPatientData>> map = mzList.stream().collect(
  848. Collectors.groupingBy(MzEmrPatientData::getTimes)
  849. );
  850. return ResultVoUtil.success(map);
  851. }
  852. public ResultVo<List<FluorescenceSpecimenResult>> getFluorescenceSpecimenResult(String patNo, Integer times) {
  853. return ResultVoUtil.success(dao.selectFluorescenceSpecimenResult(patNo, times));
  854. }
  855. public ResultVo<List<OpRecord>> getOpRecordList(String patNo, Integer times) {
  856. return ResultVoUtil.success(dao.getOpRecordList(patNo, times));
  857. }
  858. public String getEmrToken() {
  859. return emrToken;
  860. }
  861. private static String createEmr(JSONObject param) {
  862. if (StrUtil.isBlank(archiveConfig.getArchiveUrl())) {
  863. throw new RuntimeException("电子病历生成路径为空");
  864. }
  865. param.put("emrToken", emrToken);
  866. String text = Forest.post(archiveConfig.getEmrArchiveUrl())
  867. .contentTypeJson()
  868. .addBody(param)
  869. .bodyType(ForestDataType.JSON)
  870. .addHeader("emr-token", emrToken)
  871. .execute(String.class);
  872. int index = text.lastIndexOf("<br/>buffer:,");
  873. if (index != -1) {
  874. String[] split = text.substring(text.lastIndexOf("<br/>buffer:,") + 13).split(",");
  875. return Base64.encode(Convert.toPrimitiveByteArray(split));
  876. }
  877. throw new RuntimeException(text);
  878. }
  879. public static String getPdfBase(String documentId) {
  880. JSONObject param = new JSONObject();
  881. param.put("emrToken", true);
  882. param.put("stream", true);
  883. param.put("arcive", false);
  884. param.put("patientId", false);
  885. param.put("params", new JSONObject() {{
  886. put("documentId", documentId);
  887. }});
  888. param.put("fileName", "病历pdf");
  889. param.put("type", "document");
  890. return createEmr(param);
  891. }
  892. public static String getPdfBase64ByTemplate(cn.hutool.json.JSONObject template, Object data) {
  893. JSONObject param = new JSONObject();
  894. param.put("emrToken", true);
  895. param.put("stream", true);
  896. param.put("arcive", false);
  897. param.put("patientId", false);
  898. param.put("params", new JSONObject() {{
  899. put("document", template);
  900. put("appContext", data);
  901. }});
  902. param.put("fileName", "病历pdf");
  903. param.put("type", "template");
  904. return createEmr(param);
  905. }
  906. public static String getPdfBase64ByCategoryId(String id, String categoryCode, Object data) {
  907. JSONObject param = new JSONObject();
  908. param.put("emrToken", true);
  909. param.put("stream", true);
  910. param.put("arcive", false);
  911. param.put("patientId", false);
  912. param.put("params", new JSONObject() {{
  913. put("categoryId", id);
  914. put("categoryCode", categoryCode);
  915. put("appContext", new JSONObject() {{
  916. put("data", data);
  917. }});
  918. }});
  919. param.put("fileName", "病历pdf");
  920. param.put("type", "template");
  921. return createEmr(param);
  922. }
  923. public ResultVo<String> newDir(EmrPatientData data) {
  924. data.setEmrDocumentId(SnowFlakeId.instance().nextId());
  925. data.setCreateDate(new Date());
  926. data.setCreateId(TokenUtil.getInstance().getTokenUserId());
  927. data.setEmrCategoryCode(THIS_IS_DIR);
  928. if (data.getParent() == null) {
  929. return ResultVoUtil.success(ExceptionEnum.LOGICAL_ERROR, "父节点为空请重新创建!");
  930. }
  931. dao.insert(data);
  932. return ResultVoUtil.success();
  933. }
  934. public ResultVo<String> delDir(String dirId) {
  935. boolean dirHasFile = dao.dirHasFile(dirId);
  936. if (dirHasFile) {
  937. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "文件夹下面还存在文件无法删除。");
  938. }
  939. int i = dao.delDir(dirId, TokenUtil.getInstance().getTokenUserId());
  940. if (i > 0) {
  941. return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE);
  942. }
  943. return ResultVoUtil.success(ExceptionEnum.LOGICAL_ERROR, "无法删除,创建人不是你,或者这个是文件。");
  944. }
  945. public ResultVo<String> rename(String name, String documentId) {
  946. int i = dao.rename(name, documentId);
  947. if (i > 0) {
  948. return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_EL_MESSAGE);
  949. }
  950. return ResultVoUtil.success(ExceptionEnum.LOGICAL_ERROR, "重命名失败。");
  951. }
  952. public String findEmrByCode(String patNo, Integer times, String code) {
  953. return dao.findEmrByCode(patNo, times, code);
  954. }
  955. }