AppointmentService.java 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. package thyyxxk.wxservice_server.service;
  2. import com.alibaba.fastjson.JSONObject;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.stereotype.Service;
  6. import org.springframework.web.client.RestTemplate;
  7. import thyyxxk.wxservice_server.config.exception.ExceptionEnum;
  8. import thyyxxk.wxservice_server.constant.Constants;
  9. import thyyxxk.wxservice_server.constant.Gender;
  10. import thyyxxk.wxservice_server.dao.AppointmentDao;
  11. import thyyxxk.wxservice_server.entity.BriefPatInfo;
  12. import thyyxxk.wxservice_server.entity.ResultVo;
  13. import thyyxxk.wxservice_server.entity.appointment.*;
  14. import thyyxxk.wxservice_server.factory.thmz.ThmzService;
  15. import thyyxxk.wxservice_server.factory.thmz.model.QueryMzDoctorRequest;
  16. import thyyxxk.wxservice_server.factory.thmz.model.QueryMzyReqrecRequest;
  17. import thyyxxk.wxservice_server.factory.thmz.model.QueryRegisterCostRequest;
  18. import thyyxxk.wxservice_server.factory.thmz.model.QueryUnitCodeRequest;
  19. import thyyxxk.wxservice_server.utils.*;
  20. import java.text.SimpleDateFormat;
  21. import java.util.*;
  22. /**
  23. * @author dj
  24. */
  25. @Slf4j
  26. @Service
  27. public class AppointmentService {
  28. private static final Boolean NORMAL_CLASSES = Boolean.FALSE;
  29. private static final Boolean NIGHT_CLASSES = Boolean.TRUE;
  30. private static final List<MzClass> mzClasses = new ArrayList<>();
  31. private static final List<MzClass> nightMzClasses = new ArrayList<>();
  32. private final AppointmentDao dao;
  33. private final RedisLikeService redis;
  34. private final ElectronicHealthCardService healthCardService;
  35. private final WxRefundService wxRefundService;
  36. private final ThmzService thmzService;
  37. private static final int[] ampmValue = new int[]{830, 900, 930, 1000, 1030, 1100, 1130, 1200, 1430, 1500, 1530, 1600, 1630, 1700, 1730};
  38. private static final String[] ampmLabel = new String[]{"a1","a2","a3","a4","a5","a6","a7","a8","p1","p2","p3","p4","p5","p6","p7"};
  39. @Autowired
  40. public AppointmentService(AppointmentDao dao, RedisLikeService redis, ElectronicHealthCardService healthCardService, WxRefundService wxRefundService, ThmzService thmzService) {
  41. this.dao = dao;
  42. this.redis = redis;
  43. this.healthCardService = healthCardService;
  44. this.wxRefundService = wxRefundService;
  45. this.thmzService = thmzService;
  46. }
  47. public ResultVo<List<MzClass>> getAllDepartments() {
  48. if (ListUtil.notEmpty(mzClasses)) {
  49. return ResultVoUtil.success(mzClasses);
  50. }
  51. log.info("重新获取门诊科室并缓存。");
  52. ResultVo<List<Map<String, Object>>> mzClassResponse = thmzService.getMzClass();
  53. if (mzClassResponse.getCode() != ExceptionEnum.SUCCESS.getCode()) {
  54. return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR, mzClassResponse.getMessage());
  55. }
  56. List<Map<String, Object>> tempMzClasses = mzClassResponse.getData();
  57. tempMzClasses.sort(Comparator.comparing(obj -> (int) obj.get("sortCode")));
  58. String[] dateRange = new String[]{null, null};
  59. for (Map<String, Object> mzClass : tempMzClasses) {
  60. fetchMzDepartmentsByMzClasses(mzClass, NORMAL_CLASSES, dateRange);
  61. }
  62. return ResultVoUtil.success(mzClasses);
  63. }
  64. public ResultVo<List<MzClass>> getAllNightDepartments() {
  65. if (ListUtil.notEmpty(nightMzClasses)) {
  66. return ResultVoUtil.success(nightMzClasses);
  67. }
  68. log.info("重新获取夜间门诊科室并缓存。");
  69. ResultVo<List<Map<String, Object>>> mzClassResponse = thmzService.getMzClass();
  70. if (mzClassResponse.getCode() != ExceptionEnum.SUCCESS.getCode()) {
  71. return ResultVoUtil.fail(ExceptionEnum.NETWORK_ERROR, mzClassResponse.getMessage());
  72. }
  73. List<Map<String, Object>> tempMzClasses = mzClassResponse.getData();
  74. tempMzClasses.sort(Comparator.comparing(obj -> (int) obj.get("sortCode")));
  75. String[] oneWeekOffset = DateUtil.getOneWeekOffset();
  76. for (Map<String, Object> mzClass : tempMzClasses) {
  77. fetchMzDepartmentsByMzClasses(mzClass, NIGHT_CLASSES, oneWeekOffset);
  78. }
  79. return ResultVoUtil.success(nightMzClasses);
  80. }
  81. private void fetchMzDepartmentsByMzClasses(Map<String, Object> mzClass,
  82. boolean nightClinic, String[] dateRange) {
  83. String mzClassCode = mzClass.get("code").toString();
  84. QueryUnitCodeRequest request = new QueryUnitCodeRequest.Builder()
  85. .mzClass(mzClassCode).p4Request(nightClinic)
  86. .beginTime(dateRange[0]).endTime(dateRange[1]).build();
  87. ResultVo<List<Map<String, Object>>> queryUnitCodeResponse = thmzService.getUnitCodeByMzClass(request);
  88. if (queryUnitCodeResponse.getCode() == ExceptionEnum.SUCCESS.getCode()) {
  89. List<Map<String, Object>> mzDepartments = queryUnitCodeResponse.getData();
  90. List<MzDept> departmentList = new ArrayList<>();
  91. for (Map<String, Object> tempDepartment : mzDepartments) {
  92. String sortCode = (String) tempDepartment.get("sortCode");
  93. if (!StringUtil.isDigit(sortCode)) {
  94. sortCode = "9999";
  95. }
  96. MzDept department = new MzDept(tempDepartment.get("code").toString(),
  97. tempDepartment.get("name").toString(), Integer.parseInt(sortCode));
  98. List<Map<String, Object>> tempChildren = CastUtil.cast(tempDepartment.get("children"));
  99. if (ListUtil.notEmpty(tempChildren)) {
  100. List<MzDept> children = new ArrayList<>();
  101. for (Map<String, Object> tempChild : tempChildren) {
  102. String childSortCode = (String) tempChild.get("sortCode");
  103. if (!StringUtil.isDigit(childSortCode)) {
  104. childSortCode = "9999";
  105. }
  106. children.add(new MzDept(tempChild.get("code").toString(),
  107. tempChild.get("name").toString(), Integer.parseInt(childSortCode)));
  108. }
  109. children.sort(Comparator.comparing(MzDept::getSortNo));
  110. department.setChildren(children);
  111. }
  112. departmentList.add(department);
  113. }
  114. if (departmentList.isEmpty()) {
  115. return;
  116. }
  117. departmentList.sort(Comparator.comparing(MzDept::getSortNo));
  118. if (nightClinic) {
  119. nightMzClasses.add(new MzClass(mzClassCode, mzClass.get("name").toString(), departmentList));
  120. } else {
  121. mzClasses.add(new MzClass(mzClassCode, mzClass.get("name").toString(), departmentList));
  122. }
  123. }
  124. }
  125. public ResultVo<String> refreshMzClasses() {
  126. mzClasses.clear();
  127. log.info("门诊科室缓存已重置。");
  128. return ResultVoUtil.success("门诊科室缓存已重置。");
  129. }
  130. public ResultVo<String> refreshNightMzClasses() {
  131. nightMzClasses.clear();
  132. log.info("夜间门诊科室缓存已重置。");
  133. return ResultVoUtil.success("夜间门诊科室缓存已重置。");
  134. }
  135. public ResultVo<Map<String, Object>> getSourcesByDate(GetSourcesByDateParam param) {
  136. Integer[] sourceArray = new Integer[7];
  137. Calendar calendar = Calendar.getInstance();
  138. SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
  139. for (int i = 0; i < 7; i++) {
  140. sourceArray[i] = 0;
  141. int addNum = i == 0 ? 0 : 1;
  142. calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) + addNum);
  143. String date = format.format(calendar.getTime());
  144. QueryMzDoctorRequest request = new QueryMzDoctorRequest.Builder()
  145. .requestDay(date).unitCode(param.getDept()).build();
  146. ResultVo<List<Map<String, Object>>> queryMzDoctorResponse =
  147. thmzService.getDoctorByDateAndDept(request);
  148. if (queryMzDoctorResponse.getCode() != ExceptionEnum.SUCCESS.getCode()) {
  149. sourceArray[i] = 0;
  150. continue;
  151. }
  152. for (Map<String, Object> item : queryMzDoctorResponse.getData()) {
  153. if (!param.getNightClinic() || (Boolean) item.get("isP4Request")) {
  154. sourceArray[i] = 1;
  155. break;
  156. }
  157. }
  158. }
  159. Map<String, Object> resultMap = new HashMap<>();
  160. resultMap.put("description", dao.selectDeptDescription(param.getDept()));
  161. resultMap.put("sources", sourceArray);
  162. return ResultVoUtil.success(resultMap);
  163. }
  164. public ResultVo<List<Map<String, Object>>> getDoctorSources(GetDoctorSourcesParam param) {
  165. QueryMzDoctorRequest request = new QueryMzDoctorRequest.Builder()
  166. .requestDay(param.getDate()).unitCode(param.getDeptCode()).build();
  167. ResultVo<List<Map<String, Object>>> response =
  168. thmzService.getDoctorByDateAndDept(request);
  169. if (response.getCode() != ExceptionEnum.SUCCESS.getCode()) {
  170. return response;
  171. }
  172. if (param.getNightClinic()) {
  173. response.getData().removeIf(map -> !((Boolean) map.get("isP4Request")));
  174. }
  175. for (Map<String, Object> map : response.getData()) {
  176. DoctorInfo info = dao.selectPortraitAndIntroduction(map.get("doctorCode").toString());
  177. if (null != info) {
  178. map.put("portrait", info.getPortrait());
  179. map.put("introduction", info.getIntroduction());
  180. }
  181. }
  182. response.getData().sort((o1, o2) -> {
  183. Integer i1 = Integer.parseInt(o1.get("empTitCode").toString());
  184. Integer i2 = Integer.parseInt(o2.get("empTitCode").toString());
  185. int diff = i1 - i2;
  186. return Integer.compare(diff, 0);
  187. });
  188. return response;
  189. }
  190. public ResultVo<List<Map<String, Object>>> getDoctorArrangement(GetDoctorSourcesParam param) {
  191. QueryMzDoctorRequest request = new QueryMzDoctorRequest.Builder()
  192. .requestDay(param.getDate()).unitCode(param.getDeptCode())
  193. .doctorCode(param.getDoctorCode()).build();
  194. ResultVo<List<Map<String, Object>>> response = thmzService.getDoctorsArrangement(request);
  195. if (response.getCode() != ExceptionEnum.SUCCESS.getCode()) {
  196. return response;
  197. }
  198. String today = DateUtil.formatDatetime(new Date(), "yyyy-MM-dd");
  199. if (param.getNeedExcludePassedTime() && param.getDate().equals(today)) {
  200. int currentHourMinute = DateUtil.parseHourMinuteToInteger();
  201. int validAmpmIndex = 0;
  202. for (int i = 0; i < ampmValue.length; i++) {
  203. if (currentHourMinute < ampmValue[i]) {
  204. validAmpmIndex = i;
  205. break;
  206. }
  207. }
  208. for (Map<String, Object> map : response.getData()) {
  209. for (int i = 0; i < validAmpmIndex; i++) {
  210. map.remove(ampmLabel[i]);
  211. }
  212. }
  213. }
  214. if (response.getData().isEmpty()) {
  215. return ResultVoUtil.fail(ExceptionEnum.SLIGHTLY_ERROR);
  216. }
  217. return response;
  218. }
  219. public ResultVo<Integer[]> getSourcesByDateAndDoctor(GetDoctorSourcesParam param) {
  220. Integer[] source = new Integer[7];
  221. source[0] = getDoctorArrangement(param).getCode();
  222. Calendar calendar = Calendar.getInstance();
  223. SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
  224. for (int i = 1; i < source.length; i++) {
  225. calendar.add(Calendar.DATE, 1);
  226. param.setDate(dateFormat.format(calendar.getTime()));
  227. source[i] = getDoctorArrangement(param).getCode();
  228. }
  229. return ResultVoUtil.success(source);
  230. }
  231. public ResultVo<Map<String, Object>> getGhFee(GetGhFeeParam param) {
  232. QueryRegisterCostRequest request = new QueryRegisterCostRequest.Builder()
  233. .mzyRequestId(param.getMzyRequestId())
  234. .patientId(param.getPatientId()).build();
  235. return thmzService.getRegisterCost(request);
  236. }
  237. public ResultVo<DoctorInfo> getDoctorInfo(String doctorCode, String openId) {
  238. DoctorInfo doctor = dao.selectDoctorInfo(doctorCode, openId);
  239. if (null == doctor) {
  240. return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "未找到医生信息!");
  241. }
  242. return ResultVoUtil.success(doctor);
  243. }
  244. public ResultVo<String> checkAppointmentRequirements(String patientId, String deptCode) {
  245. String idCard = dao.selectPatientIdCard(patientId);
  246. if (!IdCardUtil.isValidatedIdCard(idCard)) {
  247. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "您在我院绑定的身份证号不是有效的身份证号," +
  248. "请前往【个人中心 - 我的就诊人 - 就诊人信息】进行修改。");
  249. }
  250. String mzClass = dao.selectMzClass(deptCode);
  251. if (Constants.MzClass.GYNAECOLOGY.equals(mzClass)) {
  252. if (IdCardUtil.getGenderByIdCard(idCard) == Gender.MALE) {
  253. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "男性无法在妇产科挂号,请选择其他科室。");
  254. }
  255. }
  256. if (Constants.MzDept.isPediatrics(deptCode)) {
  257. if (IdCardUtil.getAgeByIdCard(idCard) >= 18) {
  258. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "成年人无法在儿科相关科室挂号,请选择其他科室。");
  259. }
  260. }
  261. return ResultVoUtil.success();
  262. }
  263. public ResultVo<String> getDoctorQrCode(String doctorCode) {
  264. final String qywxToken = PropertiesUtil.getLocalProperty("qywxToken");
  265. final String userid = redis.getEmployeeCodeRs(doctorCode);
  266. final String url = String.format("https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=%s&userid=%s", qywxToken, userid);
  267. RestTemplate restTemplate = new RestTemplate();
  268. final String result = restTemplate.getForObject(url, String.class);
  269. JSONObject json = JSONObject.parseObject(result);
  270. return ResultVoUtil.success(json.getString("qr_code"));
  271. }
  272. public ResultVo<List<Map<String, String>>> getPaidMzGhList(String patientId) {
  273. healthCardService.reportHisData(patientId, "01010111", null, null);
  274. return thmzService.getPaidMzGhList(patientId);
  275. }
  276. public ResultVo<List<MzyReqrec>> listMzyReqrec(BriefPatInfo patInfo) {
  277. QueryMzyReqrecRequest request = new QueryMzyReqrecRequest.Builder()
  278. .patientId(patInfo.getPatientId()).payMark(patInfo.getPayMark()).build();
  279. return thmzService.listMzyReqrec(request);
  280. }
  281. public ResultVo<MzyReqrec> getMzyReqrecInfo(BriefPatInfo patInfo) {
  282. QueryMzyReqrecRequest request = new QueryMzyReqrecRequest.Builder()
  283. .patientId(patInfo.getPatientId()).times(patInfo.getTimes())
  284. .onlyShowUnpaid(patInfo.filterUnpaidReq()).build();
  285. return thmzService.getMzyReqrecInfo(request);
  286. }
  287. public ResultVo<String> cancelReqrec(MzyReqrec mzyReq) {
  288. ResultVo<String> cancelReqResponse = cancelReqFromHis(mzyReq);
  289. if (cancelReqResponse.getCode() == ExceptionEnum.SUCCESS.getCode()) {
  290. return wxRefundService.autoRefund(mzyReq.getPsordnum(), "自助退号。");
  291. }
  292. return cancelReqResponse;
  293. }
  294. public ResultVo<String> cancelReqFromHis(MzyReqrec mzyReq) {
  295. if (invalidCancelReqrec(mzyReq)) {
  296. return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "仅支持最近15天内尚未就诊的微信自助挂号。");
  297. }
  298. QueryMzyReqrecRequest request = new QueryMzyReqrecRequest.Builder()
  299. .patientId(mzyReq.getPatientId()).times(mzyReq.getTimes()).build();
  300. return thmzService.cancelReqFromHis(request);
  301. }
  302. private boolean invalidCancelReqrec(MzyReqrec mzyReq) {
  303. return !ThmzUtil.validRefundTime(new Date(), mzyReq.getRequestDayStr())
  304. || null == mzyReq.getPaymode() || mzyReq.getVisitedMark().equals("1")
  305. || mzyReq.getCancelMark().equals("1");
  306. }
  307. }