From fce96ef468291fb9a0e6a4d34ab371315e9485d4 Mon Sep 17 00:00:00 2001
From: yxh <172933527@qq.com>
Date: 星期六, 03 十月 2026 00:59:44 +0800
Subject: [PATCH] ai优化
---
jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/appointment/AppointmentServiceImpl.java | 1752 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 1,623 insertions(+), 129 deletions(-)
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/appointment/AppointmentServiceImpl.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/appointment/AppointmentServiceImpl.java
index 4be3618..fe54ef3 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/appointment/AppointmentServiceImpl.java
+++ b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/appointment/AppointmentServiceImpl.java
@@ -1,35 +1,47 @@
package cn.lihu.jh.module.ecg.service.appointment;
+import cn.lihu.jh.framework.common.pojo.PageResult;
import cn.lihu.jh.framework.common.util.date.DateUtils;
-import cn.lihu.jh.framework.common.util.date.LocalDateTimeUtils;
+import cn.lihu.jh.framework.common.util.object.BeanUtils;
+import cn.lihu.jh.module.ecg.controller.admin.appointment.vo.AppointmentConfirmReqVO;
+import cn.lihu.jh.module.ecg.controller.admin.appointment.vo.AppointmentPageReqVO;
+import cn.lihu.jh.module.ecg.controller.admin.appointment.vo.AppointmentSaveReqVO;
import cn.lihu.jh.module.ecg.controller.admin.queue.vo.QueueSaveReqVO;
+import cn.lihu.jh.module.ecg.dal.dataobject.appointment.AppointmentDO;
+import cn.lihu.jh.module.ecg.dal.dataobject.patient.PatDetails;
+import cn.lihu.jh.module.ecg.dal.dataobject.queue.QueueDO;
+import cn.lihu.jh.module.ecg.dal.mysql.appointment.AppointmentMapper;
+import cn.lihu.jh.module.ecg.enums.AppointmentTypeEnum;
+import cn.lihu.jh.module.ecg.enums.HisCheckCodeEnum;
+import cn.lihu.jh.module.ecg.enums.HisCheckNameEnum;
+import cn.lihu.jh.module.ecg.enums.HisCheckStatusEnum;
import cn.lihu.jh.module.ecg.feign.RemoteDataService;
-import cn.lihu.jh.module.ecg.feign.RestApiReqBodyVo;
-import cn.lihu.jh.module.ecg.feign.RestApiResult;
-import cn.lihu.jh.module.ecg.feign.dto.AppointmentExternal;
+import cn.lihu.jh.module.ecg.service.config.EcgConfigService;
+import cn.lihu.jh.module.ecg.service.devrent.ApplicationTemplate;
+import cn.lihu.jh.module.ecg.service.his.HisEcgFilter;
import cn.lihu.jh.module.ecg.service.queue.QueueService;
+import cn.lihu.jh.module.ecg.service.queuesequence.QueueSequenceService;
+import cn.lihu.jh.module.ecg.webservice.WebServiceClient;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
-import cn.lihu.jh.module.ecg.controller.admin.appointment.vo.*;
-import cn.lihu.jh.module.ecg.dal.dataobject.appointment.AppointmentDO;
-import cn.lihu.jh.framework.common.pojo.PageResult;
-import cn.lihu.jh.framework.common.util.object.BeanUtils;
-
-import cn.lihu.jh.module.ecg.dal.mysql.appointment.AppointmentMapper;
-
import javax.annotation.Resource;
-import javax.xml.crypto.Data;
-
+import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
-import java.util.ArrayList;
-import java.util.List;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.stream.Collectors;
import static cn.lihu.jh.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.lihu.jh.framework.common.pojo.CommonResult.error;
import static cn.lihu.jh.module.ecg.enums.ErrorCodeConstants.*;
/**
@@ -39,10 +51,27 @@
*/
@Service
@Validated
+@Slf4j
public class AppointmentServiceImpl implements AppointmentService {
+
+ /**
+ * 鎮h�呮�у埆銆屾湭鐭ャ�嶇殑鍏滃簳鍊笺��
+ * <p>
+ * {@code appointment.pat_gender} 鍦ㄦ暟鎹簱涓负 NOT NULL 涓旀棤榛樿鍊�
+ * 锛堝疄娴嬶細{@code Field 'pat_gender' doesn't have a default value}锛夈��
+ * 鑰� {@code S0405} 绛夋姤鏂囩殑鎬у埆瀛楁璺緞涓� {@code S0201ECG} 涓嶅悓銆佷笖鍙兘缂哄け锛�
+ * 瀹归敊鏂板鏃惰嫢鍙栦笉鍒帮紝鎸� 0锛堟湭鐭ワ級鍐欏叆锛岄伩鍏嶆彃鍏ュけ璐ャ��
+ */
+ private static final Byte UNKNOWN_GENDER = (byte) 0;
+
+ @Resource
+ private EcgConfigService ecgConfigService;
@Resource
private RemoteDataService remoteDataService;
+
+ @Resource
+ private QueueSequenceService queueSequenceService;
@Resource
private QueueService queueService;
@@ -50,13 +79,22 @@
@Resource
private AppointmentMapper appointmentMapper;
+ /**
+ * 蹇冪數涓氬姟鍗曞垽瀹氬櫒銆�
+ * <p>
+ * 鐢ㄤ簬 {@code S0405}锛堝叏闄㈤�氱敤鐘舵�佹祦锛夌殑杩囨护锛氶潪蹇冪數鍗曞彧璁版棩蹇椼�佷笉钀藉簱锛�
+ * 閬垮厤鍚� appointment 琛ㄧ亴鍏ユ斁灏�/瓒呭0绛夊叾浠栫瀹ょ殑鏁版嵁銆�
+ */
+ @Resource
+ private HisEcgFilter hisEcgFilter;
+
+ @Autowired
+ private WebServiceClient webServiceClient;
+
@Override
public Long createAppointment(AppointmentSaveReqVO createReqVO) {
// 鎻掑叆
AppointmentDO appointment = BeanUtils.toBean(createReqVO, AppointmentDO.class);
-
- appointment.setBookTime( LocalDateTime.now() );
- appointment.setBookSrc( 1 );
try {
appointmentMapper.insert(appointment);
@@ -78,6 +116,42 @@
}
@Override
+ public void updateAppointmentStatus(AppointmentSaveReqVO updateReqVO) {
+ // 鏍¢獙瀛樺湪
+ validateAppointmentExists(updateReqVO.getId());
+
+ // 鑾峰彇瀹屾暣鐨勯绾︿俊鎭�
+ AppointmentDO appointment = appointmentMapper.selectById(updateReqVO.getId());
+ if (appointment == null) {
+ throw exception(APPOINTMENT_NOT_EXISTS);
+ }
+
+ // 鏇存柊鐘舵��
+ appointment.setStatus(updateReqVO.getStatus());
+
+ // 璋冪敤HIS绯荤粺鏇存柊鐘舵��
+ String action = "S0405";
+ ApplicationTemplate app = new ApplicationTemplate();
+ String statusName = AppointmentTypeEnum.getByType(appointment.getStatus());
+ String message = app.getXML(appointment.getApplyNo(), appointment.getStatus(), statusName, null, appointment.getPatDeptCode(), appointment.getPatDeptDesc(), appointment.getPatWardCode(), appointment.getPatWardDesc(), appointment.getPatBedNo(), appointment.getEpisodeId(), String.valueOf(appointment.getBookSrc()), appointment.getPatId(), appointment.getPatName());
+
+ try {
+ String response = webServiceClient.callJHFWTYRK(action, "", message);
+ if (response.contains("鏇存柊鎴愬姛")) {
+ // 鏇存柊鏈湴鏁版嵁搴�
+ appointmentMapper.updateById(appointment);
+
+
+ } else {
+ throw exception(APPOINTMENT_UPDATE_FAIL);
+ }
+ } catch (Exception e) {
+ log.error("[updateAppointmentStatus][鏇存柊棰勭害鐘舵�佸け璐� appointment({})]", appointment, e);
+ throw exception(APPOINTMENT_UPDATE_FAIL);
+ }
+ }
+
+ @Override
public void deleteAppointment(Long id) {
// 鏍¢獙瀛樺湪
validateAppointmentExists(id);
@@ -96,155 +170,1575 @@
return appointmentMapper.selectById(id);
}
- // TODO 灏氫笉鏀寔, 涓�浣嶆偅鑰呭綋澶╀袱绉嶆鏌ラ」鐩殑鎯呭喌
@Override
- public AppointmentDO getCurAppointmentByPatId(String patId) {
- List<AppointmentDO> appointmentDOList = appointmentMapper.getCurrentPatId( patId );
- return 0 == appointmentDOList.size() ? null : appointmentDOList.get(0);
+ public AppointmentDO getCurAppointmentByPatIdAndCheckType(String patId, Integer checkType) {
+ AppointmentDO appointmentDO = appointmentMapper.getByPatAndCheckTypeAndBookDate(patId, checkType);
+ return appointmentDO;
}
- // TODO 灏氫笉鏀寔, 涓�浣嶆偅鑰呭綋澶╀袱绉嶆鏌ラ」鐩殑鎯呭喌
+ /**
+ * @param patCode 缂栧彿 : !!! 涓嶄竴瀹氬氨鏄湰绯荤粺鐨� 鎮h�呯紪鍙�(patID), 鏍规簮鍦ㄤ簬 妫�鏌ュ崟鎵弿鍑烘潵鐨勭紪鍙� 涓嶄竴瀹氭槸 鏈郴缁熺殑 鎮h�呯紪鍙�(patID)
+ * @return
+ */
@Override
- public AppointmentDO queryAndCreateAppointmentByPatId(String patId) {
- // 鍏堜粠鍖婚櫌骞冲彴鏌ヨ
- List<AppointmentDO> appointmentExtermalList = getAppointmentExtermal( patId );
- for ( int appointmentIndex = 0; appointmentIndex < appointmentExtermalList.size(); appointmentIndex++ ) {
+ public List<AppointmentDO> queryAndCreateAppointmentByPatId(String patCode) {
+ // 浠庡尰闄㈠钩鍙版煡璇�
+ List<AppointmentDO> appointmentExtermalList = appointmentMapper.getCurrentCode(patCode);
+
+ for (int appointmentIndex = 0; appointmentIndex < appointmentExtermalList.size(); appointmentIndex++) {
AppointmentDO appointmentExtermal = appointmentExtermalList.get(appointmentIndex);
- if (null != appointmentExtermal && null != appointmentExtermal.getBookDate() && appointmentExtermal.getBookDate().isEqual(LocalDate.now())) {
- // 鏌ュ埌褰撳ぉ鐨勯绾﹀悗锛屾煡璇B涓� 鏄惁宸茬粡瀛樺湪
- AppointmentDO appointmentDO = appointmentMapper.getCurrentByPatAndCheckType(patId, appointmentExtermal.getBookCheckType());
- if (null == appointmentDO) {
- appointmentMapper.insert(appointmentExtermal);
- return appointmentExtermal;
+ if (null == appointmentExtermal) continue;
+
+ // 浠嶥B鏌ヨ棰勭害锛屾槸鍚﹀凡缁忓瓨鍦�
+ AppointmentDO appointmentDO = appointmentMapper.getByEpisodeIdAndApplyNo(appointmentExtermal.getEpisodeId(), appointmentExtermal.getApplyNo());
+ if (null == appointmentDO) {
+ appointmentMapper.insert(appointmentExtermal);
+ } else {
+ appointmentExtermal.setId(appointmentDO.getId()); // 纭繚 杩斿洖鍊煎寘鍚� appointment id
+
+ // 澶勭悊绗竴娆$‘璁ゆ椂杩樻病鏈夐绾︽椂闂达紝鍐嶆潵纭鏃跺凡鏈夐绾︽椂闂寸殑鎯呭喌
+ if (appointmentDO.getBookDate() != appointmentExtermal.getBookDate()) {
+ appointmentMapper.updateById(appointmentExtermal);
}
- return appointmentDO;
}
}
- List<AppointmentDO> appointmentDOList = appointmentMapper.getCurrentPatId( patId );
- return 0 == appointmentDOList.size() ? null : appointmentDOList.get(0);
+ // 鏌ヨ[queue琛╙琛ュ厖 book_seq_num 鍒拌繑鍥炲�间腑
+ if (!appointmentExtermalList.isEmpty()) {
+ List<Long> appointIdlist = appointmentExtermalList.stream().map(appointmentDO -> appointmentDO.getId()).toList();
+ List<QueueDO> simpleQueueDOList = queueService.selectBookSeqNumByAppointIdList(appointIdlist);
+ if (!simpleQueueDOList.isEmpty()) {
+ Map<Long, Integer> mapAppointIdVsBookSeqNo = simpleQueueDOList.stream().collect(Collectors.toMap(QueueDO::getAppointId, QueueDO::getBookSeqNum));
+ appointmentExtermalList.forEach(appointmentExterma -> appointmentExterma.setBookSeqNum(mapAppointIdVsBookSeqNo.get(appointmentExterma.getId())));
+ }
+ }
+
+ // 涓嶄粠DB鏌ヨ
+ //List<AppointmentDO> appointmentDOList = appointmentMapper.getCurrentPatId( patCode );
+ //return 0 == appointmentDOList.size() ? null : appointmentDOList.get(0);
+
+ return appointmentExtermalList;
}
@Override
public PageResult<AppointmentDO> getAppointmentPage(AppointmentPageReqVO pageReqVO) {
+ //1. 鍏堟牴鎹畃atId鍘绘煡
+ PageResult<AppointmentDO> result = appointmentMapper.selectPage(pageReqVO);
+ log.info("--------------PATID result鐨勫�间负锛歿}", result);
+ if (!result.getList().isEmpty()) {
+ return result;
+ }
+
+ if (StringUtils.isNotEmpty(pageReqVO.getPatId())) {
+ // 2. 鐢� applyNo 鏌ヨ
+ pageReqVO.setApplyNo(pageReqVO.getPatId());
+ pageReqVO.setPatId(null);
+ log.info("------------------ApplyNo pageReqVO鐨勫�间负锛歿}", pageReqVO);
+ result = appointmentMapper.selectPage(pageReqVO);
+ if (!result.getList().isEmpty()) {
+ return result;
+ }
+
+ // 3. 鐢� episodeId 鏌ヨ
+ pageReqVO.setEpisodeId(pageReqVO.getApplyNo());
+ pageReqVO.setPatId(null);
+ pageReqVO.setApplyNo(null);
+ log.info("-----------EpisodeId pageReqVO鐨勫�间负锛歿}", pageReqVO);
+ }
return appointmentMapper.selectPage(pageReqVO);
}
@Override
public List<AppointmentDO> getAppointmentExtermal(String patId) {
- List<AppointmentDO> curAppointDOList = new ArrayList<AppointmentDO>();
-
- RestApiReqBodyVo reqBodyVo = new RestApiReqBodyVo();
- if (18 == patId.length()) {
- reqBodyVo.setSfzh( patId );
- } else {
- reqBodyVo.setMzzyh(patId);
- }
-
- // QueryRisReportList queryEcgRequest
- RestApiResult<AppointmentExternal> result = remoteDataService.httpApi("queryEcgRequest", "ECG", "ECG", reqBodyVo);
- if (0 == result.getRow().size()) {
- return curAppointDOList;
- }
-
- for (int appointIndex=0; appointIndex < result.getRow().size(); appointIndex++ ) {
- AppointmentExternal appointmentExternal = result.getRow().get( appointIndex );
-
- AppointmentDO appointmentDO = BeanUtils.toBean(appointmentExternal, AppointmentDO.class);
- appointmentDO.setPatId(appointmentExternal.getPatientID()); // 鍐呭涓� 韬唤璇佸彿 鎴� 闂ㄨ瘖浣忛櫌鍙�
- appointmentDO.setPatName(appointmentExternal.getPatName());
- appointmentDO.setPatGender(Byte.valueOf(appointmentExternal.getPatgender()));
- appointmentDO.setPatBirthday(DateUtils.ofUTC(appointmentExternal.getEncPatBirthDate()).toLocalDate());
- appointmentDO.setPatIdentityId(appointmentExternal.getIdentityID());
- appointmentDO.setPatAddr(appointmentExternal.getAddress());
- appointmentDO.setPatDeptCode(appointmentExternal.getPatLocDeptCode());
- appointmentDO.setPatDeptDesc(appointmentExternal.getPatLocDeptDesc());
- appointmentDO.setPatWardCode(appointmentExternal.getPatLocWardCode());
- appointmentDO.setPatWardDesc(appointmentExternal.getPatLocWardDesc());
- appointmentDO.setPatMobile(appointmentExternal.getPhone());
- appointmentDO.setPatBedNo(appointmentExternal.getEnBedno());
- appointmentDO.setBookId(appointmentExternal.getReqIdeApplyno());
- appointmentDO.setBookCheckType(getCorrespondingCheckType(appointmentExternal.getPlanDefItemList().getPlanDefItem().getPlanDefItemcode()));
- appointmentDO.setBookTime(DateUtils.ofUTC(appointmentExternal.getReqAuthoredOn())); // 寮�鍗曟椂闂�
-
- // 鍏夊紑鍗曠殑鎯呭喌锛屾病鏈夐绾︽椂闂�
- if (null != appointmentExternal.getReqExtBooktime() ) {
- appointmentDO.setBookDate(DateUtils.ofUTC(appointmentExternal.getReqExtBooktime()).toLocalDate());
- LocalDateTime bookStartTime = DateUtils.ofUTC(appointmentExternal.getReqExtBooktime());
- LocalDateTime bookEndTime = bookStartTime.plusMinutes(30);
- appointmentDO.setBookTimeslot((bookStartTime.getHour() * 100 + bookStartTime.getMinute()) * 10000 + bookEndTime.getHour() * 100 + bookEndTime.getMinute());
- }
-
- appointmentDO.setBookSrc(0);
- appointmentDO.setPaid(1);
-
- curAppointDOList.add( appointmentDO );
- }
-
- return curAppointDOList;
+ return appointmentMapper.getCurrentPatId(patId);
}
+
+// @Override
+// public List<AppointmentDO> getAppointmentExtermal(String patId) {
+// List<AppointmentDO> curAppointDOList = new ArrayList<AppointmentDO>();
+//
+// RestApiReqBodyVo reqBodyVo = new RestApiReqBodyVo();
+// if (18 == patId.length()) {
+// reqBodyVo.setSfzh( patId );
+// } else {
+// reqBodyVo.setMzzyh(patId);
+// }
+//
+// // QueryRisReportList queryEcgRequest
+// RestApiResult<AppointmentExternal> result = remoteDataService.httpApi("queryEcgRequest", "ECG", "ECG", reqBodyVo);
+// if (0 == result.getRow().size()) {
+// return curAppointDOList;
+// }
+//
+// for (int appointIndex=0; appointIndex < result.getRow().size(); appointIndex++ ) {
+// AppointmentExternal appointmentExternal = result.getRow().get( appointIndex );
+//
+// AppointmentDO appointmentDO = BeanUtils.toBean(appointmentExternal, AppointmentDO.class);
+// appointmentDO.setApplyNo( appointmentExternal.getReqIdeApplyno() );
+// appointmentDO.setEpisodeId( appointmentExternal.getEpisodeID() );
+// appointmentDO.setPatSrc( getCorrespondingPatientSource(appointmentExternal.getAdmTypeCode()) );
+// appointmentDO.setPatId(appointmentExternal.getPatientID()); // 鍐呭涓� 韬唤璇佸彿 鎴� 闂ㄨ瘖浣忛櫌鍙�
+// appointmentDO.setPatName(appointmentExternal.getPatName());
+// appointmentDO.setPatGender(Byte.valueOf(appointmentExternal.getPatgender()));
+// appointmentDO.setPatBirthday(DateUtils.ofUTC(appointmentExternal.getEncPatBirthDate()).toLocalDate());
+// appointmentDO.setPatIdentityId(appointmentExternal.getIdentityID());
+// appointmentDO.setPatAddr(appointmentExternal.getAddress());
+// appointmentDO.setPatDeptCode(appointmentExternal.getPatLocDeptCode());
+// appointmentDO.setPatDeptDesc(appointmentExternal.getPatLocDeptDesc());
+// appointmentDO.setPatWardCode(appointmentExternal.getPatLocWardCode());
+// appointmentDO.setPatWardDesc(appointmentExternal.getPatLocWardDesc());
+// appointmentDO.setPatMobile(appointmentExternal.getPhone());
+// appointmentDO.setPatBedNo(appointmentExternal.getEnBedno());
+// appointmentDO.setBookCheckType(getCorrespondingCheckType(appointmentExternal.getPlanDefItemList().getPlanDefItem().getPlanDefItemcode()));
+// appointmentDO.setBookTime(DateUtils.ofUTC(appointmentExternal.getReqAuthoredOn())); // 寮�鍗曟椂闂�
+// appointmentDO.setBookSrc( 0 );
+//
+// // 鍏夊紑鍗曠殑鎯呭喌锛屾病鏈夐绾︽椂闂�
+// if (null != appointmentExternal.getReqExtBooktime() ) {
+// appointmentDO.setBookDate(DateUtils.ofUTC(appointmentExternal.getReqExtBooktime()).toLocalDate());
+// LocalDateTime bookStartTime = DateUtils.ofUTC(appointmentExternal.getReqExtBooktime());
+// LocalDateTime bookEndTime = bookStartTime.plusMinutes( ecgConfigService.getTimeslotLength());
+// appointmentDO.setBookTimeslot((bookStartTime.getHour() * 100 + bookStartTime.getMinute()) * 10000 + bookEndTime.getHour() * 100 + bookEndTime.getMinute());
+// }
+//
+// appointmentDO.setPaid( 0 );
+//
+// curAppointDOList.add( appointmentDO );
+// }
+//
+// return curAppointDOList;
+// }
@Override
@Transactional(rollbackFor = Exception.class)
- public String appoitmentConfirm(AppointmentConfirmReqVO confirmReqVO) {
+ public Integer appoitmentConfirm(AppointmentConfirmReqVO confirmReqVO) {
AppointmentDO appointment = getAppointment(confirmReqVO.getId());
- if (null == appointment)
- throw exception(PATIENT_NOT_EXISTS);
+ if (null == appointment) throw exception(PATIENT_NOT_EXISTS);
- if ( !DateUtils.isToday(appointment.getBookDate()) )
- throw exception( APPOINTMENT_NOT_TODAY);
+ // 鎵嬪姩棰勭害锛岀洿鎺ヨ缃绾︽棩鏈熶负褰撳ぉ
+ if (confirmReqVO.getIsVip() == 1) {
+ appointment.setBookDate(LocalDate.now());
+ }
+
+ if (!DateUtils.isToday(appointment.getBookDate())) throw exception(APPOINTMENT_NOT_TODAY);
+
+
+ // 銆愰渶姹傦細鎺掗槦搴忓彿瑙勫垯銆戞寜 check_type.seq_rule 鍐冲畾鍙栧彿鏂瑰紡锛�
+ // 0=棰勭害鍙凤紙鐢ㄩ绾︾郴缁熷凡涓嬪彂鐨勫彿锛涘綋鍓� HIS 鏈笅鍙戯紝浼氳嚜鍔ㄥ洖閫�鍒扮鍒板簭鍙凤級
+ // 1=绛惧埌搴忓彿锛堝綋澶╁悓妫�鏌ョ被鍨嬭繛缁�掑锛屾瘡 9 涓鐣� 1 涓粰鍔犳�ワ級
+ // 2=鏃舵鍙凤紙鎸� bookTimeslot 浠庡彿姹犲彇鍙� 鈥斺�� 鏀归�犲墠鐨勫師鏈夎涓猴紝涔熸槸鏈厤缃椂鐨勯粯璁わ級
+ boolean urgent = isHisUrgent(appointment);
+ Integer newSeqNo = queueSequenceService.distributeSeqNoByRule(
+ confirmReqVO.getBookCheckType(),
+ confirmReqVO.getBookTimeslot(),
+ appointment.getBookSeqNum(),
+ urgent);
+ log.info("[appoitmentConfirm][鍒嗛厤鎺掗槦搴忓彿] appointmentId={} checkType={} timeslot={} 瑙勫垯鍙栧彿={} 鍔犳��={}",
+ appointment.getId(), confirmReqVO.getBookCheckType(), confirmReqVO.getBookTimeslot(),
+ newSeqNo, urgent);
try {
QueueSaveReqVO queueSaveReqVO = new QueueSaveReqVO();
+ queueSaveReqVO.setApplyNo(appointment.getApplyNo());
+ queueSaveReqVO.setEpisodeId(appointment.getEpisodeId());
+ queueSaveReqVO.setAppointId(appointment.getId());
queueSaveReqVO.setPatId(appointment.getPatId());
queueSaveReqVO.setPatName(appointment.getPatName());
queueSaveReqVO.setPatGender(appointment.getPatGender());
queueSaveReqVO.setBookDate(appointment.getBookDate());
- queueSaveReqVO.setBookTimeslot(appointment.getBookTimeslot());
+ queueSaveReqVO.setBookTimeslot(confirmReqVO.getBookTimeslot()); /*appointment.getBookTimeslot()*/
queueSaveReqVO.setBookCheckType(appointment.getBookCheckType());
+ queueSaveReqVO.setBookSeqNum(newSeqNo);
+ queueSaveReqVO.setIsVip(confirmReqVO.getIsVip());
queueSaveReqVO.setPassed((byte) 0);
queueSaveReqVO.setExpired((byte) 0);
- queueSaveReqVO.setPatDetails( appointment.getPatDeptDesc() + "-" + appointment.getPatWardDesc() + "-" + appointment.getPatBedNo());
+ // 闇�姹�2锛欼SCB銆屾槸鍚﹀簥杈广�嶉殢闃熷垪涓�璧疯惤搴擄紝渚涘睆骞�/椤甸潰灞曠ず
+ queueSaveReqVO.setIsBedside(appointment.getIsBedside());
+ // HIS 鍔犳�ユ爣璁帮紙jjbz=J锛夆啋 鎺掗槦鍔犳�ワ紝涓庝汉宸ユ彃闃熷叡鐢� jump_flag銆�
+ // queue 琛ㄦ寜 "order by jump_flag desc, book_timeslot, create_time" 鍙栧彿锛岀疆 1 鍗充紭鍏堛��
+ if (urgent) {
+ queueSaveReqVO.setJumpFlag((byte) 1);
+ log.info("[appoitmentConfirm][HIS 鍔犳�ユ偅鑰咃紝鎺掗槦鏍囪涓哄姞鎬 applyNo={} patId={}",
+ appointment.getApplyNo(), appointment.getPatId());
+ }
+ queueSaveReqVO.setPatDetails(getPatDetails(appointment));
queueService.queue(queueSaveReqVO);
} catch (DuplicateKeyException duplicateKeyException) {
throw exception(APPOINTMENT_HAVE_QUEUED);
}
- return "纭鎴愬姛";
+ return newSeqNo;
}
- private Integer getCorrespondingCheckType(String strPlanDefItemcode) {
- if (strPlanDefItemcode.equals("691133607"))
- return 100;
- else if (strPlanDefItemcode.equals("201605"))
- return 200;
- else if (strPlanDefItemcode.equals("200327"))
- return 300;
- else if (strPlanDefItemcode.equals("201652"))
- return 400;
- else if (strPlanDefItemcode.equals("502490914"))
- return 500;
- else if (strPlanDefItemcode.equals("419562119"))
- return 600;
- else if (strPlanDefItemcode.equals("201604"))
- return 700;
- else if (strPlanDefItemcode.equals("1202042"))
- return 800;
- else if (strPlanDefItemcode.equals("1202058"))
- return 900;
- else if (strPlanDefItemcode.equals("1202065"))
- return 1000;
- else if (strPlanDefItemcode.equals("559542128"))
- return 1100;
- else if (strPlanDefItemcode.equals("590244511"))
- return 1200;
- else if (strPlanDefItemcode.equals("666454217"))
- return 1300;
- else if (strPlanDefItemcode.equals("720791490"))
- return 1400;
- else if (strPlanDefItemcode.equals("720792077"))
- return 1500;
-
- return 100;
+ /**
+ * 鍒ゆ柇璇ラ绾︽槸鍚︿负 HIS 鏍囪鐨勫姞鎬ュ崟銆�
+ * <p>
+ * 渚濇嵁 {@code appointment.jjbz}锛堟潵婧� HIS 鎶ユ枃 {@code zdy.jjbz}锛夛細
+ * {@code J} / {@code 1} / {@code Y} 瑙嗕负鍔犳�ワ紝鍏朵綑锛堝 {@code N}锛変负甯歌銆�
+ * <p>
+ * <b>娉ㄦ剰</b>锛氬疄娴� 2026-09-17 鏃ュ織涓� 60 鏉� S0201ECG 鐨� {@code jjbz} **鍏ㄤ负 N**锛�
+ * 鏈彇寰� {@code J} 鐨勭湡瀹炴牱渚嬶紝鍥犳璇ュ垎鏀皻鏈粡杩囩湡瀹炴姤鏂囬獙璇併��
+ *
+ * @param appointment 棰勭害璁板綍锛屽彲涓� null
+ * @return true=鍔犳��
+ */
+ private boolean isHisUrgent(AppointmentDO appointment) {
+ if (appointment == null || StringUtils.isEmpty(appointment.getJjbz())) {
+ return false;
+ }
+ String flag = appointment.getJjbz().trim();
+ return "J".equalsIgnoreCase(flag) || "1".equals(flag) || "Y".equalsIgnoreCase(flag);
}
-}
\ No newline at end of file
+
+ private PatDetails getPatDetails(AppointmentDO appointment) { PatDetails patDetails = new PatDetails();
+ patDetails.setAppointmentId(appointment.getId());
+ patDetails.setId(appointment.getPatId());
+ patDetails.setName(appointment.getPatName());
+ patDetails.setMobile(appointment.getPatMobile());
+ patDetails.setDeptCode(appointment.getPatDeptCode());
+ patDetails.setDeptDesc(appointment.getPatDeptDesc());
+ patDetails.setWardCode(appointment.getPatWardCode());
+ patDetails.setWardDesc(appointment.getPatWardDesc());
+ patDetails.setBedNo(appointment.getPatBedNo());
+ patDetails.setSource(appointment.getPatSrc());
+ return patDetails;
+ }
+
+ @Override
+ public Long handleAppointmentCreate(Map<String, Object> dataMap) {
+ if (dataMap == null) {
+ throw exception(APPOINTMENT_CREATE_FAIL);
+ }
+
+ try {
+ // 鍒涘缓AppointmentDO瀵硅薄
+ AppointmentDO appointment = new AppointmentDO();
+
+ // 浠巇ataMap涓彁鍙栨暟鎹�
+ Map<String, Object> encounter = extractEncounter(dataMap);
+ if (encounter == null) {
+ throw exception(APPOINTMENT_CREATE_FAIL);
+ }
+
+ // 璁剧疆灏辫瘖娴佹按鍙�
+ Optional.ofNullable(encounter.get("id")).map(id -> (Map<String, Object>) id).map(id -> (List<?>) id.get("item")).filter(items -> items.size() > 1).map(items -> (Map<String, Object>) items.get(1)).map(item -> (String) item.get("extension")).ifPresent(appointment::setEpisodeId);
+
+ Optional.ofNullable(encounter.get("location")).map(location -> (Map<String, Object>) location).map(location -> (Map<String, Object>) location.get("serviceDeliveryLocation")).map(serviceDeliveryLocation -> (Map<String, Object>) serviceDeliveryLocation.get("location")).map(location -> (Map<String, Object>) location.get("id")).map(id -> (Map<String, Object>) id.get("item")).map(item -> (String) item.get("extension")).ifPresent(appointment::setPatBedNo);
+
+ Optional.ofNullable(dataMap.get("controlActProcess")).map(controlActProcess -> (Map<String, Object>) controlActProcess).map(controlActProcess -> (Map<String, Object>) controlActProcess.get("subject")).map(subject -> (Map<String, Object>) subject.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("zdy")).map(zdy -> {
+ Object ISDN = zdy.get("ISDN");
+ if (ISDN != null) {
+ return ISDN.toString();
+ }
+ return null;
+ }).ifPresent(appointment::setTolerance);
+
+ // 鏄惁搴婅竟锛堥渶姹�2锛夛細zdy.ISCB銆�0=鍚︼紝1=鏄��
+ //
+ // 涓� ISDN 鍚屽湪 zdy 鑷畾涔夊瓧娈靛尯锛屼笖**鍚屽睘瀹樻柟鏂囨。鏈畾涔夌殑 7 涓墿灞曞瓧娈�**
+ // 锛堝疄娴嬬湡瀹炴姤鏂� 26 涓瓧娈碉紝鏂囨。鍙畾涔変簡 19 涓級銆�
+ // 瑙f瀽閫昏緫鎶藉埌 findBedsideFlag锛屼究浜庡崟鍏冩祴璇曘��
+ String bedsideFlag = findBedsideFlag(dataMap);
+ if (bedsideFlag != null) {
+ appointment.setIsBedside(bedsideFlag);
+ }
+
+ // 浼樺厛绾�/鍔犳�ユ爣璁帮紙zdy.jjbz锛歂=甯歌锛孞=鍔犳�ワ級
+ Map<String, Object> zdyNode = dig(dataMap, "controlActProcess", "subject",
+ "observationRequest", "zdy");
+ if (zdyNode != null) {
+ Object jjbz = zdyNode.get("jjbz");
+ if (jjbz != null && StringUtils.isNotEmpty(jjbz.toString().trim())) {
+ appointment.setJjbz(jjbz.toString().trim());
+ }
+ }
+
+ // 妫�鏌ユ柟寮忕紪鐮侊細methodCode.item[0].code
+ // 绫诲瀷瀹夊叏锛歮ethodCode 鐨� item 鍙兘涓嶅瓨鍦紝鍙兘鏄崟涓� Map锛屼篃鍙兘鏄� List
+ Map<String, Object> c2 = dig(dataMap, "controlActProcess", "subject",
+ "observationRequest", "component2", "observationRequest");
+ if (c2 != null) {
+ String methodCode = digText(c2, "methodCode", "item", "code");
+ if (StringUtils.isEmpty(methodCode)) {
+ // 浼� List 鏃� digText 浼氳嚜鍔ㄥ彇棣栧厓绱犲啀涓嬮捇锛岃繖閲屽啀鍏滀竴娆� code
+ methodCode = digText(c2, "methodCode", "item", "part", "value");
+ }
+ if (StringUtils.isNotEmpty(methodCode)) {
+ appointment.setMethodCode(methodCode);
+ }
+ String targetSite = digText(c2, "targetSiteCode", "item", "code");
+ if (StringUtils.isNotEmpty(targetSite)) {
+ appointment.setTargetSiteCode(targetSite);
+ }
+
+ // 鍖诲槺鍙凤細component2.observationRequest.id.item[root=2.16.156.10011.1.28].extension
+ //
+ // 渚濇嵁锛圚IS銆婁氦浜掓湇鍔¢�氱敤鎺ュ彛鏂囨。銆嬶級锛�
+ // 路 6.1 鐢宠鍗曟柊澧炴湇鍔★紙鏈」鐩墍鐢� S0201ECG锛夌殑绀轰緥涓鑺傜偣娉ㄩ噴鍗充负銆屽尰鍢盜D銆嶏細
+ // <id><!--鍖诲槺ID--><item root="2.16.156.10011.1.28" extension=""/></id>
+ // 路 6.4/6.5 妫�鏌ラ绾︾姸鎬佹湇鍔$殑绀轰緥涓悓鏍锋敞閲婁负銆屽尰鍢卞彿銆嶏細
+ // <!-- 鍖诲槺鍙� --> ... <id root="2.16.156.10011.1.28" extension="11"/>
+ // 瀹炴祴 S0201ECG 220 鏉°�丼0202ECG 29 鏉�**鍧囨惡甯﹁鍊间笖鏃犵┖鍊�**
+ // 锛堝舰濡� 112663505 / 112663700锛屼笖鍚屼竴鍖诲槺鍦ㄦ柊澧炰笌鏇存柊鎶ユ枃涓彇鍊间竴鑷达級銆�
+ //
+ // 銆愪负浠�涔堜笉鐢� digText 鐩存帴鍙� item.extension銆�
+ // digText 閬囧埌 List **鍙彇棣栧厓绱�**锛涜�� id.item 鍦ㄩ儴鍒嗘湇鍔′腑鏄暟缁�
+ // 锛堝 6.4 鍚屾椂鍚� 1.24 鐢宠鍗曞彿涓� 1.28 鍖诲槺鍙凤級銆傛晠蹇呴』**鎸� root 鍖归厤**锛�
+ // 鍚﹀垯鍙兘鎶婄敵璇峰崟鍙峰綋鎴愬尰鍢卞彿銆�
+ String doctorAdviceNo = findExtensionByRoot(c2.get("id"), ORDER_NO_ROOT);
+ if (StringUtils.isNotEmpty(doctorAdviceNo)) {
+ appointment.setDoctorAdviceNo(doctorAdviceNo);
+ }
+ }
+
+ // 鍖荤敓寮�鍗曟椂闂�
+ Optional.ofNullable(dataMap.get("controlActProcess")).map(controlActProcess -> (Map<String, Object>) controlActProcess).map(controlActProcess -> (Map<String, Object>) controlActProcess.get("subject")).map(subject -> (Map<String, Object>) subject.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("author")).map(author -> (Map<String, Object>) author.get("time")).map(time -> (String) time.get("value")).map(str -> {
+ try {
+ return new SimpleDateFormat("yyyyMMddHHmmss").parse(str);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }).filter(Objects::nonNull).ifPresent(appointment::setDoctorTime);
+
+ //璁剧疆寮�鍗曞尰鐢熷鍚�
+ Optional.ofNullable(dataMap.get("controlActProcess")).map(controlActProcess -> (Map<String, Object>) controlActProcess).map(controlActProcess -> (Map<String, Object>) controlActProcess.get("subject")).map(subject -> (Map<String, Object>) subject.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("author")).map(author -> (Map<String, Object>) author.get("assignedEntity")).map(assignedEntity -> (Map<String, Object>) assignedEntity.get("assignedPerson")).map(assignedPerson -> (Map<String, Object>) assignedPerson.get("name")).map(name -> (Map<String, Object>) name.get("item")).map(item -> (Map<String, Object>) item.get("part")).map(part -> (String) part.get("value")).ifPresent(appointment::setDoctor);
+
+ //璁剧疆寮�鍗曞尰鐢熺紪鐮�
+ Optional.ofNullable(dataMap.get("controlActProcess")).map(controlActProcess -> (Map<String, Object>) controlActProcess).map(controlActProcess -> (Map<String, Object>) controlActProcess.get("subject")).map(subject -> (Map<String, Object>) subject.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("author")).map(author -> (Map<String, Object>) author.get("assignedEntity")).map(assignedEntity -> (Map<String, Object>) assignedEntity.get("id")).map(id -> (Map<String, Object>) id.get("item")).map(item -> (String) item.get("extension")).ifPresent(appointment::setDoctorCode);
+
+
+ // 璁剧疆鎮h�呮潵婧愮被鍨�
+ Optional.ofNullable(encounter.get("code")).map(code -> (Map<String, Object>) code).map(code -> (String) code.get("code")).map(Integer::parseInt).ifPresent(appointment::setPatSrc);
+
+ // 璁剧疆鎮h�呬俊鎭�
+ Optional.ofNullable(encounter.get("subject")).map(subject -> (Map<String, Object>) subject).map(subject -> (Map<String, Object>) subject.get("patient")).map(patient -> (Map<String, Object>) patient.get("patientPerson")).ifPresent(patientPerson -> {
+ // 璁剧疆鎮h�匢D
+ Optional.ofNullable(encounter.get("subject")).map(subject -> (Map<String, Object>) subject).map(subject -> (Map<String, Object>) subject.get("patient")).map(patient -> (Map<String, Object>) patient.get("id")).map(id -> (Map<String, Object>) id).map(id -> (List<?>) id.get("item")).filter(items -> items.size() > 1).map(items -> (Map<String, Object>) items.get(1)).map(item -> (String) item.get("extension")).ifPresent(appointment::setPatId);
+
+ // 璁剧疆鎮h�呴棬璇婂彿
+ Optional.ofNullable(encounter.get("subject")).map(subject -> (Map<String, Object>) subject).map(subject -> (Map<String, Object>) subject.get("patient")).map(patient -> (Map<String, Object>) patient.get("id")).map(id -> (Map<String, Object>) id).map(id -> (List<?>) id.get("item")).filter(items -> items.size() > 1).map(items -> (Map<String, Object>) items.get(2)).map(item -> (String) item.get("extension")).ifPresent(appointment::setOutpatientNo);
+
+ // 璁剧疆鎮h�呬綇闄㈠彿
+ Optional.ofNullable(encounter.get("subject")).map(subject -> (Map<String, Object>) subject).map(subject -> (Map<String, Object>) subject.get("patient")).map(patient -> (Map<String, Object>) patient.get("id")).map(id -> (Map<String, Object>) id).map(id -> (List<?>) id.get("item")).filter(items -> items.size() > 1).map(items -> (Map<String, Object>) items.get(3)).map(item -> (String) item.get("extension")).ifPresent(appointment::setHospitalNo);
+
+ // 璁剧疆鎮h�呭鍚�
+ Optional.ofNullable(patientPerson.get("name")).map(name -> (Map<String, Object>) name).map(name -> (Map<String, Object>) name.get("item")).map(item -> (Map<String, Object>) item.get("part")).map(part -> (String) part.get("value")).ifPresent(appointment::setPatName);
+
+ // 璁剧疆鎮h�呮墜鏈哄拰鐢佃瘽
+ Optional.ofNullable(patientPerson.get("telecom")).map(telecom -> (Map<String, Object>) telecom).map(telecom -> (Map<String, Object>) telecom.get("item")).map(item -> (String) item.get("value")).ifPresent(phone -> {
+ appointment.setPatMobile(phone);
+ appointment.setPatPhone(phone);
+ });
+
+ // 璁剧疆鎮h�呮�у埆
+ Optional.ofNullable(patientPerson.get("administrativeGenderCode")).map(genderCode -> (Map<String, Object>) genderCode).map(genderCode -> (String) genderCode.get("code")).map(Byte::parseByte).ifPresent(appointment::setPatGender);
+
+ // 璁剧疆鎮h�呯敓鏃�
+ Optional.ofNullable(patientPerson.get("birthTime")).map(birthTime -> (Map<String, Object>) birthTime).map(birthTime -> (String) birthTime.get("value")).map(birthdayStr -> LocalDate.parse(birthdayStr, DateTimeFormatter.ofPattern("yyyyMMdd"))).ifPresent(appointment::setPatBirthday);
+
+ // 璁剧疆鎮h�呭湴鍧�
+ Optional.ofNullable(patientPerson.get("addr")).map(addr -> (Map<String, Object>) addr).map(addr -> (Map<String, Object>) addr.get("item")).map(item -> (Map<String, Object>) item.get("part")).map(part -> (String) part.get("value")).ifPresent(appointment::setPatAddr);
+
+ // 璁剧疆鎮h�呰韩浠借瘉鍙�
+ Optional.ofNullable(patientPerson.get("id")).map(id -> (Map<String, Object>) id).map(id -> (List<?>) id.get("item")).filter(items -> !items.isEmpty()).map(items -> (Map<String, Object>) items.get(0)).map(item -> (String) item.get("extension")).ifPresent(appointment::setPatIdentityId);
+
+ //鎮h�呭尰淇濆崱
+ Optional.ofNullable(patientPerson.get("id")).map(id -> (Map<String, Object>) id).map(id -> (List<?>) id.get("item")).filter(items -> !items.isEmpty()).map(items -> (Map<String, Object>) items.get(1)).map(item -> (String) item.get("extension")).ifPresent(appointment::setMedicalCard);
+ });
+
+ // 璁剧疆鏀粯鐘舵��
+ Optional.ofNullable(dataMap.get("controlActProcess")).map(controlActProcess -> (Map<String, Object>) controlActProcess).map(controlActProcess -> (Map<String, Object>) controlActProcess.get("subject")).map(subject -> (Map<String, Object>) subject.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("zdy")).map(zdy -> {
+ Object payStatus = zdy.get("PayStatus");
+ if (payStatus != null) {
+ try {
+ return Integer.parseInt(payStatus.toString());
+ } catch (NumberFormatException e) {
+ log.warn("PayStatus杞崲澶辫触: {}", payStatus);
+ return null;
+ }
+ }
+ return null;
+ }).ifPresent(appointment::setPaid);
+ // 璁剧疆鐢宠鍗曞彿
+ Optional.ofNullable(dataMap.get("controlActProcess")).map(controlActProcess -> (Map<String, Object>) controlActProcess).map(controlActProcess -> (Map<String, Object>) controlActProcess.get("subject")).map(subject -> (Map<String, Object>) subject.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("id")).map(id -> (Map<String, Object>) id.get("item")).map(item -> (String) item.get("extension")).ifPresent(appointment::setApplyNo);
+
+ //璁剧疆妫�鏌ョ被鍨�
+// String checkType = Optional.ofNullable(dataMap.get("controlActProcess")).map(controlActProcess -> (Map<String, Object>) controlActProcess).map(controlActProcess -> (Map<String, Object>) controlActProcess.get("component2")).map(component2 -> (Map<String, Object>) component2.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("code")).map(code -> (String) code.get("code")).orElseThrow(() -> exception(APPOINTMENT_CREATE_FAIL));
+ String checkType = Optional.ofNullable(dataMap.get("controlActProcess")).map(controlActProcess -> (Map<String, Object>) controlActProcess).map(controlActProcess -> (Map<String, Object>) controlActProcess.get("subject")).map(subject -> (Map<String, Object>) subject.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("component2")).map(component2 -> (Map<String, Object>) component2.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("code")).map(code -> (String) code.get("code")).orElseThrow(() -> exception(APPOINTMENT_CREATE_FAIL));
+ String checkName = Optional.ofNullable(dataMap.get("controlActProcess")).map(controlActProcess -> (Map<String, Object>) controlActProcess).map(controlActProcess -> (Map<String, Object>) controlActProcess.get("subject")).map(subject -> (Map<String, Object>) subject.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("component2")).map(component2 -> (Map<String, Object>) component2.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("code")).map(code -> (Map<String, Object>) code.get("displayName")).map(displayName -> (String) displayName.get("value")).orElseThrow(() -> exception(APPOINTMENT_CREATE_FAIL));
+ // 渚濇嵁妫�鏌ョ被鍨嬭В鏋愭湰鍦� book_check_type銆�
+ // 淇鐐癸紙鍘熷疄鐜版湁缂洪櫡锛夛細
+ // 1. 鍒ゆ柇鍐欐垚 `checkType != null || checkType != ""`锛屾亽涓� true锛�
+ // 2. patSrc 涓� Integer锛宍!= 4` 鍦ㄨ秴鍑� Integer 缂撳瓨鑼冨洿鏃朵細澶辨晥锛屾敼鐢� Objects.equals锛�
+ // 3. HIS 浠g爜鍙兘鏄犲皠涓嶅埌锛岀洿鎺� Integer.valueOf(null) 浼氭姏
+ // NumberFormatException锛堝疄娴嬫棩蹇椾腑鏈� "Cannot parse null string"锛夈��
+ if (Objects.equals(appointment.getPatSrc(), 4)) {
+ String normalizedName = StringUtils.isNotEmpty(checkName)
+ ? checkName.replaceAll("\\s+", "") : null;
+ String mapped = StringUtils.isNotEmpty(normalizedName)
+ ? HisCheckNameEnum.getByName(normalizedName) : null;
+ Integer value = parseIntegerQuietly(mapped);
+ if (value != null) {
+ appointment.setBookCheckType(value);
+ } else {
+ log.warn("[handleAppointmentCreate][浣撴鎮h�呮鏌ラ」鐩悕绉版棤娉曟槧灏刔 checkName={}", checkName);
+ }
+ } else {
+ Integer value = resolveBookCheckTypeFromComponent2(dataMap);
+ if (value != null) {
+ appointment.setBookCheckType(value);
+ } else {
+ log.warn("[handleAppointmentCreate][HIS 妫�鏌ヤ唬鐮佹棤娉曟槧灏勫埌鏈湴妫�鏌ョ被鍨媇 checkType={}", checkType);
+ }
+ }
+
+
+ // 璁剧疆绉戝鍜岀梾鍖轰俊鎭�
+ Optional.ofNullable(encounter.get("location")).map(location -> (Map<String, Object>) location).map(location -> (Map<String, Object>) location.get("serviceDeliveryLocation")).map(location -> (Map<String, Object>) location.get("serviceProviderOrganization")).ifPresent(org -> {
+ // 璁剧疆绉戝浠g爜鍜屽悕绉�
+ Optional.ofNullable(org.get("id")).map(id -> (Map<String, Object>) id).map(id -> (Map<String, Object>) id.get("item")).map(item -> (String) item.get("extension")).ifPresent(appointment::setPatDeptCode);
+
+ Optional.ofNullable(org.get("name")).map(name -> (Map<String, Object>) name).map(name -> (Map<String, Object>) name.get("item")).map(item -> (Map<String, Object>) item.get("part")).map(part -> (String) part.get("value")).ifPresent(appointment::setPatDeptDesc);
+
+ // 璁剧疆鐥呭尯浠g爜鍜屽悕绉�
+ Optional.ofNullable(org.get("asOrganizationPartOf")).map(wardOrg -> (Map<String, Object>) wardOrg).map(wardOrg -> (Map<String, Object>) wardOrg.get("wholeOrganization")).ifPresent(wardOrg -> {
+ Optional.ofNullable(wardOrg.get("id")).map(id -> (Map<String, Object>) id).map(id -> (Map<String, Object>) id.get("item")).map(item -> (String) item.get("extension")).ifPresent(appointment::setPatWardCode);
+ if (appointment.getPatSrc() != null && appointment.getPatSrc() == 4) {
+ //浣撴灏辫繖涓�涓瀹�
+ appointment.setPatDeptDesc("鍋ュ悍绠$悊涓績");
+ } else {
+ Optional.ofNullable(wardOrg.get("name")).map(name -> (Map<String, Object>) name).map(name -> (Map<String, Object>) name.get("item")).map(item -> (Map<String, Object>) item.get("part")).map(part -> (String) part.get("value")).ifPresent(appointment::setPatWardDesc);
+ }
+ });
+ });
+
+
+ // 灏咥ppointmentDO杞崲涓篈ppointmentSaveReqVO骞朵繚瀛�
+ AppointmentSaveReqVO saveReqVO = BeanUtils.toBean(appointment, AppointmentSaveReqVO.class);
+
+ // 鎸夌敵璇峰崟鍙锋鏌ユ槸鍚﹀凡瀛樺湪銆�
+ // 銆愭湰娆℃敼鍔� Q5銆戝師瀹炵幇鍛戒腑宸插瓨鍦ㄦ椂鐩存帴 return锛堜笉鏇存柊锛夛紝
+ // 涓� S0202ECG / S0405 涓ゆ潯鏇存柊娴佺殑"鎵句笉鍒板垯鍏滃簳鏂板"鏂瑰悜鐩稿弽锛岃涔変笉缁熶竴銆�
+ // 鐜版敼涓猴細鍛戒腑宸插瓨鍦ㄥ垯浠ユ湰娆℃姤鏂囧唴瀹规墽琛屾洿鏂帮紝閬垮厤 HIS 閲嶅鎺ㄩ�佹椂鏃ф暟鎹笉琚慨姝c��
+ AppointmentDO appointmentDO = appointmentMapper.getByApplyNo(saveReqVO.getApplyNo());
+ log.info("[handleAppointmentCreate][鏄惁宸插瓨鍦╙ applyNo={} existingId={}",
+ saveReqVO.getApplyNo(), appointmentDO == null ? null : appointmentDO.getId());
+ if (appointmentDO != null) {
+ // 淇濈暀鍘熻褰曚腑鏈鎶ユ枃鏈彁渚涚殑瀛楁锛岄伩鍏嶈绌哄�艰鐩�
+ mergeUnsetFields(appointment, appointmentDO);
+ saveReqVO = BeanUtils.toBean(appointment, AppointmentSaveReqVO.class);
+ saveReqVO.setId(appointmentDO.getId());
+ updateAppointment(saveReqVO);
+ return appointmentDO.getId();
+ }
+
+ return createAppointment(saveReqVO);
+ } catch (Exception e) {
+ log.error("[handleAppointmentCreate][澶勭悊棰勭害鍒涘缓澶辫触 dataMap({})]", dataMap, e);
+ throw exception(APPOINTMENT_CREATE_FAIL);
+ }
+ }
+
+ /**
+ * 鏇存柊鍓嶅悎骞讹細鏈鎶ユ枃鏈彁渚涳紙涓� null锛夌殑瀛楁锛屾部鐢ㄦ暟鎹簱涓殑鍘熷�笺��
+ * <p>
+ * 鐩殑锛歿@code S0201ECG} 鐨勬煇浜涘瓧娈靛湪閮ㄥ垎鍦烘櫙涓嬩細缂哄け锛堜緥濡備綋妫�鎮h�呮棤棰勭害鏃堕棿銆�
+ * 搴婂ご灞忔秷鎭棤绉戝淇℃伅锛夈�傝嫢鐩存帴浠ユ姤鏂囧唴瀹规暣浣撹鐩栵紝浼氭妸宸叉湁鏁版嵁娓呯┖銆�
+ * 杩欐槸"閮ㄥ垎鏇存柊"璇箟锛屼笌鏇存柊娴佺殑 {@code ifPresent} 閫愬瓧娈佃祴鍊间繚鎸佷竴鑷淬��
+ * <p>
+ * 娉ㄦ剰锛氬湪 {@link AppointmentDO} 灞傚悎骞讹紙鑰岄潪 VO 灞傦級锛屽洜涓�
+ * {@code AppointmentSaveReqVO} 涓� DO 鐨勫瓧娈电被鍨嬪苟涓嶄竴鑷�
+ * 锛圴O 鐨� {@code bookDate/patBirthday} 涓� {@code LocalDateTime}銆�
+ * {@code registerDate/doctorTime} 涓� {@code java.sql.Date}锛�
+ * DO 瀵瑰簲涓� {@code LocalDate} / {@code java.util.Date}锛夈��
+ *
+ * @param target 鏈鎶ユ枃瑙f瀽鍑虹殑瀵硅薄锛堜細琚氨鍦拌ˉ鍏級
+ * @param source 鏁版嵁搴撲腑宸叉湁鐨勮褰�
+ */
+ private void mergeUnsetFields(AppointmentDO target, AppointmentDO source) {
+ if (target.getApplyNo() == null) target.setApplyNo(source.getApplyNo());
+ if (target.getEpisodeId() == null) target.setEpisodeId(source.getEpisodeId());
+ if (target.getPatSrc() == null) target.setPatSrc(source.getPatSrc());
+ if (target.getPatId() == null) target.setPatId(source.getPatId());
+ if (target.getPatName() == null) target.setPatName(source.getPatName());
+ if (target.getPatGender() == null) target.setPatGender(source.getPatGender());
+ if (target.getPatBirthday() == null) target.setPatBirthday(source.getPatBirthday());
+ if (target.getPatMobile() == null) target.setPatMobile(source.getPatMobile());
+ if (target.getPatPhone() == null) target.setPatPhone(source.getPatPhone());
+ if (target.getPatIdentityId() == null) target.setPatIdentityId(source.getPatIdentityId());
+ if (target.getPatAddr() == null) target.setPatAddr(source.getPatAddr());
+ if (target.getPatDeptCode() == null) target.setPatDeptCode(source.getPatDeptCode());
+ if (target.getPatDeptDesc() == null) target.setPatDeptDesc(source.getPatDeptDesc());
+ if (target.getPatWardCode() == null) target.setPatWardCode(source.getPatWardCode());
+ if (target.getPatWardDesc() == null) target.setPatWardDesc(source.getPatWardDesc());
+ if (target.getPatBedNo() == null) target.setPatBedNo(source.getPatBedNo());
+ if (target.getBookDate() == null) target.setBookDate(source.getBookDate());
+ if (target.getBookTimeslot() == null) target.setBookTimeslot(source.getBookTimeslot());
+ if (target.getBookTime() == null) target.setBookTime(source.getBookTime());
+ if (target.getBookCheckType() == null) target.setBookCheckType(source.getBookCheckType());
+ if (target.getBookSrc() == null) target.setBookSrc(source.getBookSrc());
+ if (target.getPaid() == null) target.setPaid(source.getPaid());
+ if (target.getStatus() == null) target.setStatus(source.getStatus());
+ if (target.getRegisterDate() == null) target.setRegisterDate(source.getRegisterDate());
+ if (target.getTolerance() == null) target.setTolerance(source.getTolerance());
+ if (target.getHospitalNo() == null) target.setHospitalNo(source.getHospitalNo());
+ if (target.getMedicalCard() == null) target.setMedicalCard(source.getMedicalCard());
+ if (target.getOutpatientNo() == null) target.setOutpatientNo(source.getOutpatientNo());
+ if (target.getDoctor() == null) target.setDoctor(source.getDoctor());
+ if (target.getDoctorCode() == null) target.setDoctorCode(source.getDoctorCode());
+ if (target.getDoctorTime() == null) target.setDoctorTime(source.getDoctorTime());
+ // 鈥斺�� HIS 琛ュ厖瀛楁锛堥殢琛ㄦ柊澧炲垪涓�璧峰姞鍏ワ紝淇濇寔"閮ㄥ垎鏇存柊涓嶆竻绌�"璇箟锛夆�斺��
+ if (target.getJjbz() == null) target.setJjbz(source.getJjbz());
+ if (target.getMethodCode() == null) target.setMethodCode(source.getMethodCode());
+ if (target.getTargetSiteCode() == null) target.setTargetSiteCode(source.getTargetSiteCode());
+ if (target.getRoomName() == null) target.setRoomName(source.getRoomName());
+ if (target.getRemark() == null) target.setRemark(source.getRemark());
+ if (target.getBookSeqNum() == null) target.setBookSeqNum(source.getBookSeqNum());
+ }
+
+ @Override
+ public void handleAppointmentUpdate(Map<String, Object> dataMap) {
+ if (dataMap == null) {
+ throw exception(APPOINTMENT_UPDATE_FAIL);
+ }
+
+ try {
+ // 浠巇ataMap涓彁鍙栫敵璇峰崟鍙�
+ String applyNo = Optional.ofNullable(dataMap.get("controlActProcess")).map(controlActProcess -> (Map<String, Object>) controlActProcess).map(controlActProcess -> (Map<String, Object>) controlActProcess.get("subject")).map(subject -> (Map<String, Object>) subject.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("id")).map(id -> (Map<String, Object>) id.get("item")).map(item -> (String) item.get("extension")).orElseThrow(() -> exception(APPOINTMENT_CREATE_FAIL));
+
+ // 鏌ヨ鐜版湁棰勭害璁板綍
+ AppointmentDO existingAppointment = appointmentMapper.getByApplyNo(applyNo);
+
+ // 濡傛灉璁板綍涓嶅瓨鍦紝鍒欒皟鐢╤andleAppointmentCreate杩涜鏂板
+ if (existingAppointment == null) {
+ handleAppointmentCreate(dataMap);
+ return;
+ }
+
+ // 浠巇ataMap涓彁鍙栨暟鎹�
+ Map<String, Object> encounter = extractEncounter(dataMap);
+ if (encounter == null) {
+ throw exception(APPOINTMENT_CREATE_FAIL);
+ }
+
+ // 鏇存柊灏辫瘖娴佹按鍙�
+ Optional.ofNullable(encounter.get("id")).map(id -> (Map<String, Object>) id).map(id -> (List<?>) id.get("item")).filter(items -> items.size() > 1).map(items -> (Map<String, Object>) items.get(1)).map(item -> (String) item.get("extension")).ifPresent(existingAppointment::setEpisodeId);
+
+ // 璁剧疆搴婁綅鍙�
+ Optional.ofNullable(encounter.get("location")).map(location -> (Map<String, Object>) location).map(location -> (Map<String, Object>) location.get("serviceDeliveryLocation")).map(serviceDeliveryLocation -> (Map<String, Object>) serviceDeliveryLocation.get("location")).map(location -> (Map<String, Object>) location.get("id")).map(id -> (Map<String, Object>) id.get("item")).map(item -> (String) item.get("extension")).ifPresent(existingAppointment::setPatBedNo);
+
+
+ // 鏇存柊鎮h�呮潵婧愮被鍨�
+ Optional.ofNullable(encounter.get("code")).map(code -> (Map<String, Object>) code).map(code -> (String) code.get("code")).map(Integer::parseInt).ifPresent(existingAppointment::setPatSrc);
+
+ // 鏇存柊鎮h�呬俊鎭�
+ Optional.ofNullable(encounter.get("subject")).map(subject -> (Map<String, Object>) subject).map(subject -> (Map<String, Object>) subject.get("patient")).map(patient -> (Map<String, Object>) patient.get("patientPerson")).ifPresent(patientPerson -> {
+ // 鏇存柊鎮h�匢D
+ Optional.ofNullable(encounter.get("subject")).map(subject -> (Map<String, Object>) subject).map(subject -> (Map<String, Object>) subject.get("patient")).map(patient -> (Map<String, Object>) patient.get("id")).map(id -> (Map<String, Object>) id).map(id -> (List<?>) id.get("item")).filter(items -> items.size() > 1).map(items -> (Map<String, Object>) items.get(1)).map(item -> (String) item.get("extension")).ifPresent(existingAppointment::setPatId);
+
+ // 鏇存柊鎮h�呭鍚�
+ Optional.ofNullable(patientPerson.get("name")).map(name -> (Map<String, Object>) name).map(name -> (Map<String, Object>) name.get("item")).map(item -> (Map<String, Object>) item.get("part")).map(part -> (String) part.get("value")).ifPresent(existingAppointment::setPatName);
+
+ // 鏇存柊鎮h�呮墜鏈哄拰鐢佃瘽
+ Optional.ofNullable(patientPerson.get("telecom")).map(telecom -> (Map<String, Object>) telecom).map(telecom -> (Map<String, Object>) telecom.get("item")).map(item -> (String) item.get("value")).ifPresent(phone -> {
+ existingAppointment.setPatMobile(phone);
+ existingAppointment.setPatPhone(phone);
+ });
+
+ // 鏇存柊鎮h�呮�у埆
+ Optional.ofNullable(patientPerson.get("administrativeGenderCode")).map(genderCode -> (Map<String, Object>) genderCode).map(genderCode -> (String) genderCode.get("code")).map(Byte::parseByte).ifPresent(existingAppointment::setPatGender);
+
+ // 鏇存柊鎮h�呯敓鏃�
+ Optional.ofNullable(patientPerson.get("birthTime")).map(birthTime -> (Map<String, Object>) birthTime).map(birthTime -> (String) birthTime.get("value")).map(birthdayStr -> LocalDate.parse(birthdayStr, DateTimeFormatter.ofPattern("yyyyMMdd"))).ifPresent(existingAppointment::setPatBirthday);
+
+ // 鏇存柊鎮h�呭湴鍧�
+ Optional.ofNullable(patientPerson.get("addr")).map(addr -> (Map<String, Object>) addr).map(addr -> (Map<String, Object>) addr.get("item")).map(item -> (Map<String, Object>) item.get("part")).map(part -> (String) part.get("value")).ifPresent(existingAppointment::setPatAddr);
+
+ // 鏇存柊鎮h�呰韩浠借瘉鍙�
+ Optional.ofNullable(patientPerson.get("id")).map(id -> (Map<String, Object>) id).map(id -> (List<?>) id.get("item")).filter(items -> !items.isEmpty()).map(items -> (Map<String, Object>) items.get(0)).map(item -> (String) item.get("extension")).ifPresent(existingAppointment::setPatIdentityId);
+ });
+
+ // 鏇存柊绉戝鍜岀梾鍖轰俊鎭�
+ Optional.ofNullable(encounter.get("location")).map(location -> (Map<String, Object>) location).map(location -> (Map<String, Object>) location.get("serviceDeliveryLocation")).map(location -> (Map<String, Object>) location.get("serviceProviderOrganization")).ifPresent(org -> {
+ // 鏇存柊绉戝浠g爜鍜屽悕绉�
+ Optional.ofNullable(org.get("id")).map(id -> (Map<String, Object>) id).map(id -> (Map<String, Object>) id.get("item")).map(item -> (String) item.get("extension")).ifPresent(existingAppointment::setPatDeptCode);
+
+ Optional.ofNullable(org.get("name")).map(name -> (Map<String, Object>) name).map(name -> (Map<String, Object>) name.get("item")).map(item -> (Map<String, Object>) item.get("part")).map(part -> (String) part.get("value")).ifPresent(existingAppointment::setPatDeptDesc);
+
+ // 鏇存柊鐥呭尯浠g爜鍜屽悕绉�
+ Optional.ofNullable(org.get("asOrganizationPartOf")).map(wardOrg -> (Map<String, Object>) wardOrg).map(wardOrg -> (Map<String, Object>) wardOrg.get("wholeOrganization")).ifPresent(wardOrg -> {
+ Optional.ofNullable(wardOrg.get("id")).map(id -> (Map<String, Object>) id).map(id -> (Map<String, Object>) id.get("item")).map(item -> (String) item.get("extension")).ifPresent(existingAppointment::setPatWardCode);
+
+ Optional.ofNullable(wardOrg.get("name")).map(name -> (Map<String, Object>) name).map(name -> (Map<String, Object>) name.get("item")).map(item -> (Map<String, Object>) item.get("part")).map(part -> (String) part.get("value")).ifPresent(existingAppointment::setPatWardDesc);
+ });
+ });
+
+ // 鏇存柊鏀粯鐘舵��
+ Optional.ofNullable(dataMap.get("controlActProcess")).map(controlActProcess -> (Map<String, Object>) controlActProcess).map(controlActProcess -> (Map<String, Object>) controlActProcess.get("subject")).map(subject -> (Map<String, Object>) subject.get("observationRequest")).map(observationRequest -> (Map<String, Object>) observationRequest.get("zdy")).map(zdy -> {
+ Object payStatus = zdy.get("PayStatus");
+ if (payStatus != null) {
+ try {
+ return Integer.parseInt(payStatus.toString());
+ } catch (NumberFormatException e) {
+ log.warn("PayStatus杞崲澶辫触: {}", payStatus);
+ return null;
+ }
+ }
+ return null;
+ }).ifPresent(existingAppointment::setPaid);
+ // 璁剧疆妫�鏌ョ被鍨�
+ Integer checkTypeValue = resolveBookCheckTypeFromComponent2(dataMap);
+ if (checkTypeValue != null) {
+ existingAppointment.setBookCheckType(checkTypeValue);
+ } else {
+ log.warn("[handleAppointmentUpdate][鏈兘瑙f瀽妫�鏌ョ被鍨嬶紝淇濈暀鍘熷�糫 applyNo={}", applyNo);
+ }
+
+ // 灏咥ppointmentDO杞崲涓篈ppointmentSaveReqVO骞舵洿鏂�
+ AppointmentSaveReqVO updateReqVO = BeanUtils.toBean(existingAppointment, AppointmentSaveReqVO.class);
+ updateAppointment(updateReqVO);
+ } catch (Exception e) {
+ log.error("[handleAppointmentUpdate][鐢宠鍗曟洿鏂板け璐� dataMap({})]", dataMap, e);
+ throw exception(APPOINTMENT_UPDATE_FAIL);
+ }
+ }
+
+ /**
+ * 浠庢姤鏂� {@code component2.observationRequest.code.code} 瑙f瀽鏈湴妫�鏌ョ被鍨嬪�笺��
+ *
+ * <h3>淇鐨勭己闄�</h3>
+ * 鍘熷疄鐜颁负锛�
+ * <pre>
+ * if (checkType != null || checkType != "") // 鎭掍负 true锛屼笖閫昏緫搴斾负 &&
+ * setBookCheckType(Integer.valueOf(
+ * HisCheckCodeEnum.getByCode(checkType.substring(1)))); // 鏃犻暱搴︽牎楠�
+ * </pre>
+ * 瀛樺湪涓夊闂锛�
+ * <ol>
+ * <li>{@code ||} 浣垮垽鏂亽鐪燂紱</li>
+ * <li>{@code substring(1)} 鐩存帴鎴柇锛屾姤鏂囧�奸暱搴︿笉瓒虫椂鎶�
+ * {@code StringIndexOutOfBoundsException}锛堝疄娴嬫棩蹇椾腑鏈夌被浼煎紓甯革級锛�</li>
+ * <li>{@code HisCheckCodeEnum.getByCode()} 鍙兘杩斿洖 null锛�
+ * 闅忓悗 {@code Integer.valueOf(null)} 鎶� {@code NumberFormatException}
+ * 锛堝疄娴嬫棩蹇椾腑纭湁 {@code Cannot parse null string}锛夈��</li>
+ * </ol>
+ * 鐜版敼涓猴細HIS 浠g爜鍏煎甯�/涓嶅甫 {@code Y} 鍓嶇紑锛堝搴斿師 substring(1) 璇箟锛夛紝
+ * 涓斾粎鍦ㄨ兘鏄犲皠鍒版湰鍦� {@code check_type} 鍊兼椂鎵嶈繑鍥烇紝鍚﹀垯杩斿洖 null 鐢辫皟鐢ㄦ柟淇濈暀鍘熷�笺��
+ *
+ * @return 鏈湴妫�鏌ョ被鍨嬪�硷紙濡� 1000锛夛紱鏃犳硶瑙f瀽鏃惰繑鍥� null
+ */
+ private Integer resolveBookCheckTypeFromComponent2(Map<String, Object> dataMap) {
+ // 绫诲瀷瀹夊叏锛歰bservationRequest.code 鍙兘鏄� Map锛屼篃鍙兘鏄┖瀛楃涓�
+ String hisCode = digText(dataMap, "controlActProcess", "subject", "observationRequest",
+ "component2", "observationRequest", "code", "code");
+ if (StringUtils.isEmpty(hisCode)) {
+ return null;
+ }
+ String raw = hisCode.trim().replaceAll("\\s+", "");
+ // 鍏煎锛欻IS 鎶ユ枃鍊煎舰濡� "Y1202065"锛岃�屾灇涓� code 涓哄幓鎺夐瀛楃鍚庣殑 "1202065"锛�
+ // 鍚屾椂涔熷蹇嶆姤鏂囨湰韬笉甯﹀墠缂�
+ String[] candidates = raw.length() > 1
+ ? new String[]{raw, raw.substring(1)}
+ : new String[]{raw};
+ for (String candidate : candidates) {
+ String mapped = HisCheckCodeEnum.getByCode(candidate);
+ if (StringUtils.isNotEmpty(mapped)) {
+ return parseIntegerQuietly(mapped);
+ }
+ }
+ log.warn("[resolveBookCheckTypeFromComponent2][HIS 妫�鏌ヤ唬鐮佹棤娉曟槧灏勫埌鏈湴妫�鏌ョ被鍨媇 hisCode={}", hisCode);
+ return null;
+ }
+
+ /**
+ * 鐢宠鍗曠姸鎬佹洿鏂帮紙action: {@code S0405} / {@code S0405HIS} / {@code S040501HIS}锛夈��
+ *
+ * <h3>鈿狅笍 璇ユ湇鍔℃槸鍏ㄩ櫌閫氱敤鐨�</h3>
+ * 鎺ュ彛鏂囨。 6.3 瀹氫箟鍏� action 涓� {@code S0405|S0405HIS|S040501HIS}锛�**涓嶅尯鍒嗙瀹�**銆�
+ * 鍖婚櫌浼氭妸鎵�鏈夋鏌ョ瀹わ紙CT銆丮RI銆丏R銆佽秴澹般�侀瀵嗗害鈥︼級鐨勬鏌ョ姸鎬佷竴骞舵帹閫併��
+ * 瀹炴祴 2026-09-17锛氭湰鏈嶅姟鏀跺埌 1225 娆¤姹傦紝鍏朵腑浠� 3.5% 鐨勭敵璇峰崟鍙峰睘蹇冪數涓氬姟锛�
+ * 鍏朵綑涓烘斁灏�/瓒呭0绛夌瀹ょ殑鍗曪紙濡� {@code 2126091700001} 鑳搁儴CT骞虫壂 / 鎬ヨ瘖CT瀹わ級銆�
+ *
+ * <h3>澶勭悊绛栫暐</h3>
+ * <ol>
+ * <li>鎻愬彇鐢宠鍗曞彿涓庢鏌ョ姸鎬佺爜锛屽苟瀵圭姸鎬佺爜鍋�**褰掍竴鍖�**锛堝幓鍓嶅闆躲�佹牎楠屽悎娉曟�э級</li>
+ * <li>鏌ユ湰鍦伴绾﹁褰曪細
+ * <ul>
+ * <li><b>瀛樺湪</b> 鈫� 鏇存柊鐘舵�侊紱鐘舵�佷负 3锛堟鏌ョ櫥璁帮級鏃跺悓鏃跺啓鍏ョ櫥璁版椂闂�</li>
+ * <li><b>涓嶅瓨鍦� + 鏄績鐢靛崟</b> 鈫� 璁� WARN 骞�**鎻掑叆鏂拌褰�**锛圦4 瑕佹眰瀹归敊鏂板锛�</li>
+ * <li><b>涓嶅瓨鍦� + 闈炲績鐢靛崟</b> 鈫� 浠呰 DEBUG 鏃ュ織锛�**涓嶆彃鍏�**锛堥伩鍏嶇亴鍏ユ棤鍏虫暟鎹級</li>
+ * </ul>
+ * </li>
+ * </ol>
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void handleAppointmentStateUpdate(Map<String, Object> dataMap) {
+ if (dataMap == null) {
+ throw exception(APPOINTMENT_STATUS_UPDATE_FAIL);
+ }
+
+ // 1. 鎻愬彇鐢宠鍗曞彿锛堢被鍨嬪畨鍏ㄥ鑸級
+ String applyNo = digText(dataMap, "controlActProcess", "subject", "placerGroup",
+ "component2", "observationRequest", "id", "item", "extension");
+ if (StringUtils.isEmpty(applyNo)) {
+ log.warn("[handleAppointmentStateUpdate][鎶ユ枃缂哄皯鐢宠鍗曞彿锛屽拷鐣 dataMap={}", dataMap);
+ throw exception(HIS_APPLY_NO_MISSING);
+ }
+
+ // 2. 鎻愬彇骞跺綊涓�鍖栨鏌ョ姸鎬佺爜
+ // 绫诲瀷瀹夊叏锛歱rocessStep.code 鍦ㄩ儴鍒嗘姤鏂囦腑鏄� Map锛坈ode={code=7,...}锛夛紝
+ // 鍦ㄥ彟涓�浜涙姤鏂囦腑鍙兘鏄┖瀛楃涓诧紝鐩存帴鐢ㄩ摼寮忓己杞細鎶� ClassCastException
+ String rawStatus = digText(dataMap, "controlActProcess", "subject", "placerGroup",
+ "component2", "observationRequest", "component1", "processStep", "code", "code");
+ String status = HisCheckStatusEnum.normalize(rawStatus);
+ if (status == null) {
+ // 瀹炴祴鎶ユ枃涓鍊煎瓨鍦� "3" / "03" / "7" / "08" / "10" 绛変笉鍚屽啓娉曪紝
+ // 褰掍竴鍖栧悗浠嶆棤娉曡瘑鍒鏄庝笉鏄紪鐮佽〃鍐呯殑鐘舵�侊紙濡傜梾鐞嗕笓鐢� 21/22/23锛�
+ log.warn("[handleAppointmentStateUpdate][妫�鏌ョ姸鎬佺紪鐮侀潪娉曟垨涓嶅湪缂栫爜琛ㄥ唴锛屽拷鐣 applyNo={} rawStatus={}",
+ applyNo, rawStatus);
+ throw exception(HIS_STATUS_INVALID);
+ }
+
+ // 3. 鏈湴璁板綍鍖归厤
+ AppointmentDO existingAppointment = appointmentMapper.getByApplyNo(applyNo);
+ if (existingAppointment != null) {
+ existingAppointment.setStatus(status);
+ if (HisCheckStatusEnum.REGISTERED.getCode().toString().equals(status)) {
+ existingAppointment.setRegisterDate(new Date());
+ }
+ AppointmentSaveReqVO updateReqVO = BeanUtils.toBean(existingAppointment, AppointmentSaveReqVO.class);
+ updateAppointment(updateReqVO);
+ return;
+ }
+
+ // 4. 璁板綍涓嶅瓨鍦細鍏堝垽瀹氭槸鍚﹀績鐢典笟鍔″崟锛岄潪蹇冪數鍗曞彧璁版棩蹇椼�佷笉鎻掑叆
+ //
+ // S0405 鏄叏闄㈤�氱敤娴併�傚彲鐢ㄧ殑蹇冪數鍒ゅ畾渚濇嵁锛堟寜瀹炴祴鎶ユ枃锛夛細
+ // A. apply_no 鍚庣紑锛�1101/6401锛�
+ // B. component2.observationRequest.component1.processStep.code.ZDY
+ // 涓殑 jcxmcode / jcxmname锛堝疄娴� 1138/1225 鏉″甫璇ュ瓧娈碉紝
+ // 褰㈠ jcxmname=鑳搁儴CT骞虫壂,涓婅吂閮–T骞虫壂 / roomname=鎬ヨ瘖CT瀹わ級
+ // C. 鎵ц绉戝锛堥渶閰嶇疆鐧藉悕鍗曪級
+ Map<String, Object> zdyFromS0405 = extractZdyFromStateMessage(dataMap);
+ String s0405CheckCode = extractZdyValueFromMap(zdyFromS0405, "jcxmcode");
+ String s0405CheckName = extractZdyValueFromMap(zdyFromS0405, "jcxmname");
+ String hisDeptCode = extractDeptCodeFromComponent2(dataMap);
+ if (!hisEcgFilter.isEcgOrder("S0405", applyNo, s0405CheckCode, s0405CheckName, hisDeptCode)) {
+ // 鍏ㄩ櫌娴佷腑鐨勫叾浠栫瀹ゅ崟鎹紝闈欓粯璺宠繃锛圖EBUG 鏃ュ織鐢� filter 杈撳嚭锛�
+ return;
+ }
+
+ // 5. 鏄績鐢靛崟浣嗘湰鍦版棤璁板綍 鈫� 瀹归敊鏂板锛圦4 瑕佹眰锛�
+ log.warn("[handleAppointmentStateUpdate][蹇冪數涓氬姟鍗曚絾鏈湴鏃犺褰曪紝鎵ц瀹归敊鏂板] applyNo={} status={} dept={}",
+ applyNo, status, hisDeptCode);
+ insertAppointmentFromStateMessage(applyNo, status, dataMap);
+ }
+
+ /**
+ * 浠� S0405 鎶ユ枃涓瀯閫犲苟鎻掑叆涓�鏉¢绾﹁褰曘��
+ *
+ * <h3>鈿狅笍 宸茬煡鐨勬暟鎹己澶�</h3>
+ * {@code S0405} 鎶ユ枃**涓嶅寘鍚鏌ラ」鐩俊鎭�**锛堟棤 {@code component2.observationRequest.code}锛夛紝
+ * 鍥犳鏃犳硶纭畾 {@code book_check_type}锛堟鏌ョ被鍨嬶級銆傚疄娴嬬‘璁わ細鐢宠鍗曞彿鍚庣紑
+ * 涓庢鏌ョ被鍨�**鏃犲搴斿叧绯�**锛堝悓涓� {@code ...1101} 鍚庣紑鐨勮褰曞瓨鍦� 1000/100/1100 绛夊绉嶇被鍨嬶級锛�
+ * 鏁呬笉鍋氱寽娴嬶紝淇濇寔涓虹┖骞惰緭鍑� WARN锛屽緟鍚庣画 {@code S0202ECG}锛堢敵璇峰崟鏇存柊锛�
+ * 鎴栦汉宸ヨˉ褰曚慨姝c��
+ * <p>
+ * 鍚岀悊 {@code book_date}锛堥绾︽棩鏈燂級涔熶笉鍦ㄦ姤鏂囦腑锛屼繚鎸佷负绌� 鈥斺�� 杩欎笌鐜版湁鏁版嵁涓�鑷�
+ * 锛堝簱涓害 48% 璁板綍 {@code book_date} 涓虹┖锛岄绾︽棩鏈熺敱 S050401/S040501HIS 鍚庣画琛ュ叆锛夈��
+ */
+ private void insertAppointmentFromStateMessage(String applyNo, String status, Map<String, Object> dataMap) {
+ AppointmentDO appointment = new AppointmentDO();
+ appointment.setApplyNo(applyNo);
+ appointment.setStatus(status);
+ if (HisCheckStatusEnum.REGISTERED.getCode().toString().equals(status)) {
+ appointment.setRegisterDate(new Date());
+ }
+
+ // 鎮h�呬俊鎭紙S0405 鐨� patient.id.item 涓哄垪琛細鍩烮D/鎮h�匢D/闂ㄨ瘖鍙�/浣忛櫌鍙�/灏辫瘖娆℃暟/灏辫瘖娴佹按鍙凤級
+ // 鐢ㄧ被鍨嬪畨鍏ㄥ鑸紝閬垮厤鏌愪竴绾т笉鏄� Map 鏃舵姏 ClassCastException
+ Map<String, Object> encounter = dig(dataMap, "controlActProcess", "subject",
+ "placerGroup", "componentOf1", "encounter");
+ if (encounter != null) {
+ // 灏辫瘖娴佹按鍙凤細id.item[1]
+ List<?> encIdItems = asList(dig(encounter, "id"), "item");
+ if (encIdItems.size() > 1 && encIdItems.get(1) instanceof Map) {
+ appointment.setEpisodeId(str(((Map<String, Object>) encIdItems.get(1)).get("extension")));
+ }
+ // 鎮h�呬俊鎭�
+ Map<String, Object> patient = dig(encounter, "subject", "patient");
+ if (patient != null) {
+ List<?> patIdItems = asList(patient, "id", "item");
+ // 鎮h�匢D item[1]锛岄棬璇婂彿 item[2]锛屼綇闄㈠彿 item[3]
+ if (patIdItems.size() > 1 && patIdItems.get(1) instanceof Map) {
+ appointment.setPatId(str(((Map<String, Object>) patIdItems.get(1)).get("extension")));
+ }
+ if (patIdItems.size() > 2 && patIdItems.get(2) instanceof Map) {
+ appointment.setOutpatientNo(str(((Map<String, Object>) patIdItems.get(2)).get("extension")));
+ }
+ if (patIdItems.size() > 3 && patIdItems.get(3) instanceof Map) {
+ appointment.setHospitalNo(str(((Map<String, Object>) patIdItems.get(3)).get("extension")));
+ }
+ // 濮撳悕
+ String patName = digText(patient, "patientPerson", "name", "item", "part", "value");
+ if (StringUtils.isNotEmpty(patName)) {
+ appointment.setPatName(patName);
+ }
+ // 鎬у埆锛歱at_gender 涓� NOT NULL锛屽敖閲忓彇锛涘彇涓嶅埌鏃剁敱涓嬫柟鍏滃簳涓� 0
+ String gender = digText(patient, "patientPerson", "administrativeGenderCode", "code");
+ Byte genderByte = parseByteQuietly(gender);
+ if (genderByte != null) {
+ appointment.setPatGender(genderByte);
+ }
+ }
+ }
+
+ // 鎵ц绉戝锛堝啓鍏� pat_dept_code / pat_dept_desc锛�
+ Map<String, Object> org = dig(dataMap, "controlActProcess", "subject", "placerGroup",
+ "component2", "observationRequest", "location", "serviceDeliveryLocation",
+ "serviceProviderOrganization");
+ if (org != null) {
+ String deptCode = digText(org, "id", "item", "extension");
+ if (StringUtils.isNotEmpty(deptCode)) {
+ appointment.setPatDeptCode(deptCode);
+ }
+ String deptDesc = digText(org, "name", "item", "part", "value");
+ if (StringUtils.isNotEmpty(deptDesc)) {
+ appointment.setPatDeptDesc(deptDesc);
+ }
+ }
+
+ if (StringUtils.isEmpty(appointment.getPatName())) {
+ log.warn("[insertAppointmentFromStateMessage][瀹归敊鏂板鐨勮褰曠己灏戞偅鑰呭鍚峕 applyNo={}", applyNo);
+ }
+ log.warn("[insertAppointmentFromStateMessage][娉ㄦ剰锛歋0405 鎶ユ枃涓嶅惈妫�鏌ラ」鐩紝" +
+ "book_check_type 灏嗕负绌猴紝闇�鍚庣画 S0202ECG 鎴栦汉宸ヨˉ褰昡 applyNo={}", applyNo);
+ // pat_id / pat_name / pat_gender 鍦ㄦ暟鎹簱涓潎涓� NOT NULL锛岀己鍊兼椂鎻愬墠鎶ラ敊锛�
+ // 閬垮厤 SQL 寮傚父瀵艰嚧浜嬪姟鍥炴粴锛堝疄娴嬫姤閿欙細Field 'pat_gender' doesn't have a default value锛�
+ if (StringUtils.isEmpty(appointment.getPatId())) {
+ log.error("[insertAppointmentFromStateMessage][鎶ユ枃缂烘偅鑰呯紪鍙�(pat_id)锛屾棤娉曟柊澧瀅 applyNo={}", applyNo);
+ throw exception(PATIENT_NOT_EXISTS);
+ }
+ if (appointment.getPatGender() == null) {
+ log.warn("[insertAppointmentFromStateMessage][鎶ユ枃鏈彁渚涙偅鑰呮�у埆锛屾寜鏈煡(0)鍐欏叆] applyNo={}", applyNo);
+ appointment.setPatGender(UNKNOWN_GENDER);
+ }
+
+ AppointmentSaveReqVO saveReqVO = BeanUtils.toBean(appointment, AppointmentSaveReqVO.class);
+ createAppointment(saveReqVO);
+ }
+
+ /**
+ * 鍙� S0405 鎶ユ枃涓殑 {@code ZDY} 鑺傜偣銆�
+ * <p>
+ * 瀹炴祴璺緞锛歿@code controlActProcess.subject.placerGroup.component2.observationRequest
+ * .component1.processStep.code.ZDY}锛屽唴瀹瑰舰濡傦細
+ * <pre>
+ * ZDY={roomcode=111, roomname=鎬ヨ瘖CT瀹�, jcxmcode=1080,3016,3014,
+ * jcxmname=鑳搁儴CT骞虫壂,涓婅吂閮–T骞虫壂,涓嬭吂閮–T骞虫壂,
+ * pdh=000336, yysd=00:00-01:00, isjj=1}
+ * </pre>
+ * 娉ㄦ剰锛歿@code observationRequest.code} 鍦ㄦ姤鏂囦腑**鍙兘鏄┖瀛楃涓茶�岄潪 Map**锛�
+ * 鏁呭繀椤荤敤 {@link #dig(Object, String...)} 鍋氱被鍨嬪畨鍏ㄥ鑸��
+ */
+ private Map<String, Object> extractZdyFromStateMessage(Map<String, Object> dataMap) {
+ return dig(dataMap, "controlActProcess", "subject", "placerGroup", "component2",
+ "observationRequest", "component1", "processStep", "code", "ZDY");
+ }
+
+ /** 浠� Map 涓彇瀛楃涓插瓧娈碉紙鍙负绌猴級 */
+ private String extractZdyValueFromMap(Map<String, Object> map, String key) {
+ if (map == null) {
+ return null;
+ }
+ Object v = map.get(key);
+ return v == null ? null : v.toString();
+ }
+
+ /** 瀹夊叏杞瓧绗︿覆锛歯ull 杩斿洖 null锛屽叾浣� toString() */
+ private static String str(Object o) {
+ return o == null ? null : o.toString();
+ }
+
+ /** {@code appointment.remark} 鍒楀涓婇檺锛堣 08_fix_remark_length.sql锛屽綋鍓� varchar(2000)锛� */
+ private static final int REMARK_MAX_LEN = 2000;
+ /** {@code appointment.room_name} 鍒楀涓婇檺 */
+ private static final int ROOM_NAME_MAX_LEN = 200;
+
+ /**
+ * 鎸夊垪瀹芥埅鏂枃鏈紝闃叉 {@code Data too long for column} 瀵艰嚧**鏁翠釜浜嬪姟鍥炴粴**銆�
+ *
+ * <p><b>琛�娉暀璁�</b>锛�2026-09-28 鐢熶骇鐜璇ラ敊璇嚭鐜� 52 娆°�傚績鐢靛浘杩愬姩璇曢獙鐨�
+ * 娉ㄦ剰浜嬮」闀胯揪 474 瀛楃锛岃�� {@code remark} 鍒楀師涓� {@code varchar(255)}锛�
+ * 婧㈠嚭鍚庢姏 {@code MysqlDataTruncation}锛屼娇鏁存潯 UPDATE 鍥炴粴 鈥斺��
+ * 杩炲甫鍚屼竴浜嬪姟涓殑 {@code book_time}銆亄@code room_name} 涓�璧蜂涪澶憋紝
+ * 琛ㄧ幇涓�"棰勭害鏃堕棿娈垫病瀛樿繘鏁版嵁搴�"銆�
+ *
+ * @param value 鍘熷鏂囨湰
+ * @param maxLen 鐩爣鍒楀
+ * @return 鎴柇鍚庣殑鏂囨湰锛坣ull 鍘熸牱杩斿洖锛�
+ */
+ private static String truncate(String value, int maxLen) {
+ if (value == null) {
+ return null;
+ }
+ if (value.length() <= maxLen) {
+ return value;
+ }
+ log.warn("[truncate][鏂囨湰瓒呴暱宸叉埅鏂璢 鍘熼暱搴�={} 鎴柇鑷�={} 鍐呭鍓� 60 瀛�={}",
+ value.length(), maxLen,
+ value.substring(0, Math.min(60, value.length())));
+ return value.substring(0, maxLen);
+ }
+
+ /**
+ * 灞傜骇瀵艰埅鍚庡彇銆屽垪琛ㄣ�嶈妭鐐癸細{@code dig(root, path...)} 寰楀埌鐨勫�艰嫢鏄� List 鍒欒繑鍥烇紝
+ * 鍚﹀垯杩斿洖绌哄垪琛紙**涓嶆姏寮傚父**锛夈��
+ */
+ @SuppressWarnings("unchecked")
+ private static List<?> asList(Map<String, Object> root, String... path) {
+ Object cur = root;
+ for (String key : path) {
+ if (!(cur instanceof Map)) {
+ return Collections.emptyList();
+ }
+ cur = ((Map<String, Object>) cur).get(key);
+ }
+ return cur instanceof List ? (List<?>) cur : Collections.emptyList();
+ }
+
+ /**
+ * 绫诲瀷瀹夊叏鐨勫眰绾у鑸細閫愮骇鍙� Map 瀛愯妭鐐广��
+ *
+ * <p><b>涓轰粈涔堥渶瑕佸畠</b>锛欻IS 鎶ユ枃缁� Jackson 鍙嶅簭鍒楀寲鍚庯紝鍚屼竴瀛楁鐨勭被鍨�**骞朵笉绋冲畾**銆�
+ * 渚嬪 {@code observationRequest.code} 鍦ㄩ儴鍒嗘姤鏂囦腑鏄� {@code Map}锛坽@code code={code=7,...}}锛夛紝
+ * 鍦ㄥ彟涓�浜涙姤鏂囦腑鏄�**绌哄瓧绗︿覆**锛坽@code code=}锛夈�傝嫢鐢�
+ * {@code .map(m -> (Map<String,Object>) m.get("code"))} 杩欑閾惧紡寮哄埗杞崲锛�
+ * 閬囧埌瀛楃涓蹭細鎶� {@code ClassCastException}锛�**瀵艰嚧鏁存潯娑堟伅澶勭悊涓柇**銆�
+ *
+ * <p>瀹炴祴鐢熶骇鏃ュ織 2026-09-28 涓绫诲紓甯稿嚭鐜� **287 娆�**锛屾鏄敱姝ゅ啓娉曞紩璧�
+ * 锛坽@code AppointmentServiceImpl.lambda$extractCheckCodeFromComponent2}锛夈��
+ *
+ * @param root 璧峰鑺傜偣
+ * @param path 渚濇瑕佸彇鐨勯敭
+ * @return 鏈鑺傜偣锛涗换涓�鐜妭涓嶆槸 Map 鎴栫己澶辨椂杩斿洖 null锛�**涓嶆姏寮傚父**锛�
+ */
+ @SuppressWarnings("unchecked")
+ private static Map<String, Object> dig(Map<String, Object> root, String... path) {
+ Object cur = root;
+ for (String key : path) {
+ if (!(cur instanceof Map)) {
+ return null;
+ }
+ cur = ((Map<String, Object>) cur).get(key);
+ }
+ return cur instanceof Map ? (Map<String, Object>) cur : null;
+ }
+
+ /** HIS 鎶ユ枃涓�屽尰鍢卞彿/鍖诲槺ID銆嶇殑 id root锛堣銆婁氦浜掓湇鍔¢�氱敤鎺ュ彛鏂囨。銆�6.1 / 6.4 / 6.5锛� */
+ private static final String ORDER_NO_ROOT = "2.16.156.10011.1.28";
+
+ /**
+ * 鍦� HL7 鐨� {@code id} 鑺傜偣涓紝鎸� {@code root} 鍖归厤骞跺彇鍑� {@code extension}銆�
+ * <p>
+ * 鍏煎涓夌鐪熷疄褰㈡�侊紙鍧囧凡鍦ㄦ姤鏂�/鏂囨。涓嚭鐜帮級锛�
+ * <pre>
+ * id={item={root=..., extension=...}} // 鍗曚釜 Map
+ * id={item=[{root=..., extension=...}, {...}]} // List锛堝鏍囪瘑锛岄』鎸� root 鍖哄垎锛�
+ * {root=..., extension=...} // 鐩存帴灏辨槸鏍囪瘑鏈韩
+ * </pre>
+ * <p>
+ * <b>涓轰粈涔堜笉澶嶇敤 {@link #digText}</b>锛歿@code digText} 閬囧埌 List 鍙彇棣栧厓绱狅紝
+ * 鑰� {@code id.item} 涓烘暟缁勬椂鍙兘棣栧厓绱犳槸銆岀敵璇峰崟鍙�(root 1.24)銆嶈�岄潪銆屽尰鍢卞彿(root 1.28)銆嶏紝
+ * 浼氬彇閿欏�笺�傛晠杩欓噷鏄惧紡閬嶅巻骞舵寜 root 鍖归厤銆�
+ *
+ * @param idNode {@code id} 鑺傜偣锛圡ap 鎴� List锛屽彲涓� null锛�
+ * @param root 鐩爣 root 鍊�
+ * @return 鍖归厤椤圭殑 extension锛涙湭鍖归厤/涓虹┖鏃惰繑鍥� null
+ */
+ private static String findExtensionByRoot(Object idNode, String root) {
+ if (idNode == null) {
+ return null;
+ }
+ Object item = (idNode instanceof Map) ? ((Map<String, Object>) idNode).get("item") : idNode;
+ if (item == null) {
+ return null;
+ }
+ List<Object> candidates = new ArrayList<>();
+ if (item instanceof List) {
+ candidates.addAll((List<Object>) item);
+ } else {
+ candidates.add(item);
+ }
+ for (Object cand : candidates) {
+ if (!(cand instanceof Map)) {
+ continue;
+ }
+ Map<String, Object> m = (Map<String, Object>) cand;
+ Object r = m.get("root");
+ if (r != null && root.equals(r.toString().trim())) {
+ Object ext = m.get("extension");
+ if (ext != null && StringUtils.isNotEmpty(ext.toString().trim())) {
+ return ext.toString().trim();
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 浠� HIS 鎶ユ枃涓彇 {@code zdy} 鑷畾涔夊瓧娈靛尯鐨勩�屾槸鍚﹀簥杈广�嶆爣璁帮紙闇�姹�2锛夈��
+ *
+ * <h4>瀛楁鏉ユ簮</h4>
+ * {@code controlActProcess.subject.observationRequest.zdy.ISCB}锛�
+ * 鍙栧�� {@code 0=鍚� 1=鏄瘆銆�
+ *
+ * <p>璇ュ瓧娈�**鍦� HIS 瀹樻柟銆婁氦浜掓湇鍔¢�氱敤鎺ュ彛鏂囨。銆嬩腑鏈畾涔�** 鈥斺�� 鏂囨。閲� 25 涓�
+ * {@code zdy} 鍧楀叡 19 涓瓧娈碉紝瀹炴祴鐪熷疄鎶ユ枃鍗存湁 26 涓紝{@code ISCB} 灞炲叾涓�
+ * 7 涓湭鍏紑鎵╁睍瀛楁涔嬩竴锛坽@code ISCB/ISDN/BLLSH/SWCJBS/KDYSSJH/KLX/VTEGWBZ}锛夈��
+ * 瀹炴祴鏍锋湰涓� {@code ISCB} 鎭掍负 0銆�
+ *
+ * <h4>涓庛�屽簥杈规鏌ョ被鍨嬨�嶇殑鍖哄埆</h4>
+ * {@code check_type.value=1000} 鐨勫悕绉版槸"搴婅竟蹇冪數鍥�(甯歌+棰戣氨)"锛岄偅鏄�**涓�涓鏌ラ」鐩�**锛�
+ * 鏈爣璁拌〃杈剧殑鏄�**鍚屼竴椤圭洰銆佹偅鑰呴渶鍒板簥杈瑰仛**锛屼袱鑰呰涔変笉鍚岋紝涓嶅彲浜掔浉鏇夸唬銆�
+ *
+ * <p>鎶芥垚闈欐�佹柟娉曟槸涓轰簡鍙崟鍏冩祴璇曪紙瑙� {@code HisParseSafetyTest}锛夈��
+ *
+ * @param dataMap HIS 鎶ユ枃鏍硅妭鐐�
+ * @return {@code "0"}/{@code "1"}锛涘瓧娈电己澶辨垨涓虹┖鏃惰繑鍥� null
+ */
+ static String findBedsideFlag(Map<String, Object> dataMap) {
+ if (dataMap == null) {
+ return null;
+ }
+ Object cap = dataMap.get("controlActProcess");
+ if (!(cap instanceof Map)) {
+ return null;
+ }
+ Object subject = ((Map<String, Object>) cap).get("subject");
+ if (!(subject instanceof Map)) {
+ return null;
+ }
+ Object obs = ((Map<String, Object>) subject).get("observationRequest");
+ if (!(obs instanceof Map)) {
+ return null;
+ }
+ Object zdy = ((Map<String, Object>) obs).get("zdy");
+ if (!(zdy instanceof Map)) {
+ return null;
+ }
+ Object iscb = ((Map<String, Object>) zdy).get("ISCB");
+ if (iscb == null) {
+ return null;
+ }
+ String v = iscb.toString().trim();
+ return v.isEmpty() ? null : v;
+ }
+
+ /**
+ * 鍙栨湯绔妭鐐圭殑鏍囬噺鍊硷紙鐢ㄤ簬 {@code code} 鍙兘鏄� Map 涔熷彲鑳芥槸瀛楃涓茬殑鍦烘櫙锛夈��
+ *
+ * @return 鏍囬噺鏂囨湰锛涙湯绔负 Map 鏃跺彇鍏朵腑鐨� {@code value}/{@code code}锛涘彇涓嶅埌杩斿洖 null
+ */
+ private static String digText(Map<String, Object> root, String... path) {
+ Object cur = root;
+ for (int i = 0; i < path.length; i++) {
+ if (cur instanceof Map) {
+ cur = ((Map<String, Object>) cur).get(path[i]);
+ } else if (cur instanceof List) {
+ // 鍒楄〃褰㈡�侊紙濡� item=[{...}]锛夊彇绗竴涓厓绱犵户缁�
+ List<?> list = (List<?>) cur;
+ if (list.isEmpty() || !(list.get(0) instanceof Map)) {
+ return null;
+ }
+ cur = ((Map<String, Object>) list.get(0)).get(path[i]);
+ } else {
+ return null;
+ }
+ }
+ if (cur == null) {
+ return null;
+ }
+ if (cur instanceof Map) {
+ Map<String, Object> m = (Map<String, Object>) cur;
+ Object v = m.get("value");
+ if (v == null) {
+ v = m.get("code");
+ }
+ return v == null ? null : v.toString();
+ }
+ if (cur instanceof String) {
+ String s = (String) cur;
+ return s.trim().isEmpty() ? null : s;
+ }
+ return cur.toString();
+ }
+
+ /** 浠庢姤鏂囩殑 {@code component2.observationRequest.code.code} 鍙栨鏌ラ」鐩唬鐮侊紙鍙负绌猴級 */
+ private String extractCheckCodeFromComponent2(Map<String, Object> dataMap) {
+ // 绫诲瀷瀹夊叏锛歝ode 鍙兘鏄� Map锛屼篃鍙兘鏄┖瀛楃涓�
+ return digText(dataMap, "controlActProcess", "subject", "placerGroup", "component2",
+ "observationRequest", "code", "code");
+ }
+
+ /** 浠庢姤鏂囩殑 {@code component2.observationRequest.location...} 鍙栨墽琛岀瀹ょ紪鐮侊紙鍙负绌猴級 */
+ private String extractDeptCodeFromComponent2(Map<String, Object> dataMap) {
+ return digText(dataMap, "controlActProcess", "subject", "placerGroup", "component2",
+ "observationRequest", "location", "serviceDeliveryLocation",
+ "serviceProviderOrganization", "id", "item", "extension");
+ }
+
+ /**
+ * 浠� dataMap 涓彁鍙� encounter 鏁版嵁銆�
+ *
+ * <p>鎶ユ枃璺緞锛歿@code controlActProcess.subject.observationRequest.componentOf1.encounter}銆�
+ *
+ * <p><b>娉ㄦ剰</b>锛歿@code componentOf1} 浣嶄簬 {@code observationRequest} 涔嬩笅锛�
+ * 涓� {@code id}銆亄@code code}銆亄@code component2} 鍚岀骇锛�**涓嶆槸** {@code subject} 鐨勭洿鎺ュ瓙鑺傜偣銆�
+ * 鏋勯�犳祴璇曟姤鏂囨垨瑙f瀽鏃ュ織鏃跺鏄撴悶閿欏眰绾э紝姝ゅ閫愮骇鍒ょ┖浠ヤ究瀹氫綅銆�
+ */
+ @SuppressWarnings("unchecked")
+ private Map<String, Object> extractEncounter(Map<String, Object> dataMap) {
+ Map<String, Object> cap = (Map<String, Object>) dataMap.get("controlActProcess");
+ if (cap == null) {
+ return null;
+ }
+ Map<String, Object> subject = (Map<String, Object>) cap.get("subject");
+ if (subject == null) {
+ return null;
+ }
+ Map<String, Object> observationRequest = (Map<String, Object>) subject.get("observationRequest");
+ if (observationRequest == null) {
+ return null;
+ }
+ Object componentOf1 = observationRequest.get("componentOf1");
+ if (componentOf1 == null) {
+ return null;
+ }
+ return (Map<String, Object>) ((Map<String, Object>) componentOf1).get("encounter");
+ }
+
+ /**
+ * 妫�鏌ラ绾︾姸鎬佹柊澧�/鏇存柊
+ * 锛坅ction: {@code S050401}/{@code S050402} 鏂板銆亄@code S050501}/{@code S050502} 鏇存柊锛夈��
+ *
+ * <h3>鏈鏀瑰姩</h3>
+ * <ol>
+ * <li><b>鍒犻櫎姝讳唬鐮�</b>锛氬師瀹炵幇鍦ㄨ褰曚笉瀛樺湪鏃惰皟鐢� {@code handleAppointmentCreate(dataMap)}锛�
+ * 浣嗘湰鏈嶅姟鐨勬姤鏂囩粨鏋勬槸 {@code subject.actAppointment}锛岃�� create 鏈熸湜
+ * {@code subject.observationRequest} 鈥斺�� 涓よ�呭畬鍏ㄤ笉鍏煎锛寋@code extractEncounter}
+ * 蹇呯劧杩斿洖 null 骞舵姏寮傚父锛涘師绱ч殢鍏跺悗鐨� {@code log.warn("鏈壘鍒伴绾﹁褰�")}
+ * 鍥犳**姘歌繙涓嶄細鎵ц**銆傜幇鏀逛负鏄庣‘璁版棩蹇� + 瀹归敊鏂板銆�</li>
+ * <li><b>鐘舵�佸綊涓�鍖�</b>锛歿@code ZDY.statusCode} 鏄�**棰勭害鐘舵��**锛堝 1=宸查绾︼級锛�
+ * 涓� {@code S0405} 鐨�**妫�鏌ョ姸鎬佺紪鐮�**璇箟涓嶅悓锛屼絾鍚屽啓鍏� {@code status} 鍒椼��
+ * 杩欓噷缁熶竴璧� {@link HisCheckStatusEnum#normalize(String)} 鏍¢獙銆�</li>
+ * <li><b>瀹归敊鏂板</b>锛圦4 瑕佹眰锛夛細璁板綍涓嶅瓨鍦ㄦ椂璁� WARN 骞朵緷鎹湰鎶ユ枃鎻掑叆鏂拌褰曘��</li>
+ * <li><b>鍚敤鏈娇鐢ㄥ瓧娈�</b>锛圦7 瑕佹眰锛夛細{@code ZDY.remark}锛堟敞鎰忎簨椤癸級銆�
+ * {@code ZDY.area}锛堜綅缃級銆亄@code ZDY.roomcode}/{@code roomname}锛堟埧闂达級銆�
+ * {@code patient.id.item[4]}锛堥绾︽帓搴忓彿锛夈��</li>
+ * <li><b>绌哄�奸槻寰�</b>锛氬師瀹炵幇鐩存帴 {@code LocalDateTime.parse(bookTimeStr)}
+ * 涓� {@code Integer.parseInt(bookSrc)}锛屾姤鏂囩己瀛楁鏃朵細鎶涘紓甯稿鑷存暣鏉℃秷鎭け璐ャ��</li>
+ * </ol>
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void handleCheckAppointmentUpdate(Map<String, Object> dataMap) {
+ Map<String, Object> controlActProcess = (Map<String, Object>) dataMap.get("controlActProcess");
+ if (controlActProcess == null) {
+ throw exception(HIS_MESSAGE_PARSE_FAIL);
+ }
+ Map<String, Object> subject = (Map<String, Object>) controlActProcess.get("subject");
+ Map<String, Object> actAppointment = subject == null ? null
+ : (Map<String, Object>) subject.get("actAppointment");
+ if (actAppointment == null) {
+ throw exception(HIS_MESSAGE_PARSE_FAIL);
+ }
+
+ // 1. 鑾峰彇鐢宠缂栧彿銆�
+ // 娉ㄦ剰锛氭帴鍙f枃妗e畾涔夐绾﹀彿鍦� actAppointment.id.extension锛堝 3360270锛夛紝
+ // 鑰屽疄闄呮姤鏂囧悓鏃舵彁渚涗簡 referencedOrder[].actOrder.id.extension锛堝 2126091700001锛�
+ // 涓� S0201ECG 鍒涘缓鐨勭敵璇峰崟鍙蜂竴鑷达級銆傛湰鍦� appointment.apply_no 瀛樼殑鏄悗鑰咃紝
+ // 鍥犳**浼樺厛鍙� referencedOrder**锛屽彇涓嶅埌鍐嶅洖閫�鍒� actAppointment.id銆�
+ String applyNo = extractApplyNoFromCheckAppointment(actAppointment);
+ if (StringUtils.isEmpty(applyNo)) {
+ log.warn("[handleCheckAppointmentUpdate][鏈壘鍒扮敵璇风紪鍙凤紝蹇界暐] dataMap={}", dataMap);
+ throw exception(HIS_APPLY_NO_MISSING);
+ }
+
+ // 1.1 銆愬繀鍋氳繃婊ゃ�慡050401/S050501 鍚屾牱鏄�**鍏ㄩ櫌閫氱敤**鏈嶅姟锛屼細鎺ㄩ�佹斁灏�/瓒呭0绛�
+ // 闈炲績鐢电瀹ょ殑棰勭害鍗曪紙瀹炴祴 2026-09-17锛歋050401 109/256銆丼050501 4/19 涓洪潪蹇冪數锛�
+ // 妫�鏌ラ」鐩"鍙宠倶姝d晶浣�/2鍙锋満鎴�(DR)"銆�"褰╄秴鍙充笅鑲㈠姩鑴�/5鍙疯瘖瀹�"锛夈��
+ // 姝ゅ墠璇ュ鐞嗗櫒**娌℃湁浠讳綍杩囨护**锛屽鑷磋繖浜涘崟琚綋浣滃績鐢电敵璇峰崟閲囬泦鍏ュ簱銆�
+ // 闈炲績鐢靛崟鐩存帴璺宠繃锛堝彧璁版棩蹇椼�佷笉钀藉簱銆佷笉杩斿洖閿欒锛岄伩鍏� HIS 鍙嶅閲嶆帹锛夈��
+ Map<String, Object> zdyNode = (Map<String, Object>) actAppointment.get("ZDY");
+ String checkDeptCode = extractDeptCodeFromCheckAppointment(actAppointment);
+ if (!hisEcgFilter.isEcgOrderWithZdy("S050401/S050501", applyNo, checkDeptCode, zdyNode)) {
+ return;
+ }
+
+ // 2. 瑙f瀽棰勭害鏃堕棿锛堝彲鑳戒负绌猴紝鍘熷疄鐜颁細鐩存帴鎶涘紓甯革級
+ Map<String, Object> zdy = zdyNode;
+ Map<String, Object> effectiveTime = (Map<String, Object>) actAppointment.get("effectiveTime");
+ Map<String, Object> anyTime = effectiveTime == null ? null
+ : (Map<String, Object>) effectiveTime.get("any");
+ String bookTimeStr = anyTime == null ? null : (String) anyTime.get("value");
+ LocalDateTime bookTime = parseDateTime(bookTimeStr);
+ LocalDate bookDate = bookTime == null ? null : bookTime.toLocalDate();
+
+ // 3. 鏃堕棿娈碉紙ZDY.time锛屽舰濡� "2026-09-17 08:30-09:00"锛夛紝瑙f瀽澶辫触涓嶅奖鍝嶅叾浠栧瓧娈�
+ Integer bookTimeslot = parseBookTimeslot(zdy == null ? null : (String) zdy.get("time"));
+
+ // 4. 灏辫瘖绫诲埆 鈫� bookSrc锛堟枃妗o細actAppointment.code.code锛屼綇闄�/闂ㄨ瘖/鎬ヨ瘖浠g爜锛�
+ Map<String, Object> code = (Map<String, Object>) actAppointment.get("code");
+ String bookSrc = code == null ? null : (String) code.get("code");
+ Integer bookSrcValue = parseIntegerQuietly(bookSrc);
+
+ // 5. 棰勭害鐘舵�佸綊涓�鍖栵紙ZDY.statusCode锛�
+ String rawStatus = zdy == null || zdy.get("statusCode") == null
+ ? null : zdy.get("statusCode").toString();
+ String status = HisCheckStatusEnum.normalize(rawStatus);
+ if (status == null && rawStatus != null) {
+ log.warn("[handleCheckAppointmentUpdate][棰勭害鐘舵�佺紪鐮佷笉鍦ㄧ紪鐮佽〃鍐咃紝灏嗕笉鏇存柊鐘舵�乚 applyNo={} rawStatus={}",
+ applyNo, rawStatus);
+ }
+
+ // 6. 鍖归厤鏈湴璁板綍
+ AppointmentDO appointment = appointmentMapper.getByApplyNo(applyNo);
+ if (appointment == null) {
+ log.warn("[handleCheckAppointmentUpdate][鏈壘鍒伴绾﹁褰曪紝鎵ц瀹归敊鏂板] applyNo={} status={}",
+ applyNo, status);
+ insertAppointmentFromCheckAppointment(applyNo, actAppointment, bookDate, bookTime,
+ bookTimeslot, bookSrcValue, status);
+ return;
+ }
+
+ // 7. 鏇存柊宸叉湁璁板綍
+ if (bookDate != null) {
+ appointment.setBookDate(bookDate);
+ }
+ if (bookTime != null) {
+ appointment.setBookTime(bookTime);
+ }
+ if (bookTimeslot != null) {
+ appointment.setBookTimeslot(bookTimeslot);
+ }
+ if (bookSrcValue != null) {
+ appointment.setBookSrc(bookSrcValue);
+ }
+ if (status != null) {
+ appointment.setStatus(status);
+ }
+ // 鈥斺�� HIS 琛ュ厖瀛楁锛堥殢琛ㄦ柊澧炲垪涓�璧峰惎鐢級鈥斺��
+ // 娉ㄦ剰锛歳emark 鍙兘闀胯揪鏁扮櫨瀛楃锛堝瀹炴祴蹇冪數鍥捐繍鍔ㄨ瘯楠屾敞鎰忎簨椤� 474 瀛楋級锛�
+ // 蹇呴』鎸夊垪瀹芥埅鏂紝鍚﹀垯 Data too long 浼氬鑷存暣涓簨鍔″洖婊氾紙瑙� truncate 鏂规硶璇存槑锛�
+ if (zdy != null) {
+ Object remark = zdy.get("remark");
+ if (remark != null && StringUtils.isNotEmpty(remark.toString())) {
+ appointment.setRemark(truncate(remark.toString(), REMARK_MAX_LEN));
+ }
+ Object roomName = zdy.get("roomname");
+ if (roomName != null && StringUtils.isNotEmpty(roomName.toString())) {
+ appointment.setRoomName(truncate(roomName.toString(), ROOM_NAME_MAX_LEN));
+ }
+ }
+ // 棰勭害鎺掑簭鍙凤紙patient.id.item[4]锛�
+ Integer seqNum = extractBookSeqNum(actAppointment);
+ if (seqNum != null) {
+ appointment.setBookSeqNum(seqNum);
+ }
+ appointmentMapper.updateById(appointment);
+ }
+
+ /**
+ * 鍙栨鏌ラ绾︽姤鏂囦腑鐨勬墽琛�/鐢宠绉戝缂栫爜銆�
+ * <p>
+ * 鎶ユ枃璺緞锛歿@code actAppointment.subject.patient.providerOrganization.id.item.extension}
+ * 锛堝疄娴嬫牱渚� {@code ZY012}锛夈�備粎鐢ㄤ簬蹇冪數鍒ゅ畾鐨�"渚濇嵁 C"锛堥渶閰嶇疆鐧藉悕鍗曟墠鐢熸晥锛夈��
+ */
+ private String extractDeptCodeFromCheckAppointment(Map<String, Object> actAppointment) {
+ return digText(actAppointment, "subject", "patient", "providerOrganization", "id",
+ "item", "extension");
+ }
+
+ /**
+ * 棰勭害鎺掑簭鍙峰湪鎶ユ枃涓殑 root 鏍囪瘑銆�
+ * <p>
+ * 鎺ュ彛鏂囨。 6.4 鐨勭ず渚嬮噷鎶娿�岄绾︽帓搴忓彿銆嶆敞鍦� {@code item[4]} 浣嶇疆锛�
+ * 浣�**瀹為檯鎶ユ枃鐨� root 涓庝綅缃笉涓�鑷�**锛氱湡瀹炴姤鏂囷紙2026-09-17 鏃ュ織锛変负
+ * <pre>
+ * item[0] root=2.16.156.10011.2.5.1.5 鍩烮D
+ * item[1] root=2.16.156.10011.2.5.1.4 鎮h�匢D
+ * item[2] root=2.16.156.10011.1.10 闂紙鎬ワ級璇婂彿
+ * item[3] root=2.16.156.10011.1.12 浣忛櫌鍙�
+ * item[4] root=2.16.156.10011.2.5.1.8 灏辫瘖娆℃暟 鈫� 涓嶆槸鎺掑簭鍙�
+ * item[5] root=2.16.156.10011.2.5.1.9 灏辫瘖娴佹按鍙�
+ * item[6] root=2.16.156.10011.2.5.1.11 棰勭害鎺掑簭鍙� 鈫� 瀹為檯鍦ㄦ
+ * </pre>
+ * 鍥犳**鎸� root 鍖归厤**鑰岄潪鎸変綅缃彇鍊硷紝閬垮厤浣嶇疆婕傜Щ瀵艰嚧鍙栭敊瀛楁銆�
+ */
+ private static final String ROOT_BOOK_SEQ_NUM = "2.16.156.10011.2.5.1.11";
+
+ /**
+ * 鍙栥�岄绾︽帓搴忓彿銆嶃��
+ * <p>
+ * 鎶ユ枃璺緞锛歿@code actAppointment.subject.patient.id.item[]} 涓�
+ * {@code root=2.16.156.10011.2.5.1.11} 鐨勯偅涓�椤圭殑 {@code extension}銆�
+ *
+ * @return 鎺掑簭鍙凤紱鍙栦笉鍒版椂杩斿洖 null
+ */
+ @SuppressWarnings("unchecked")
+ private Integer extractBookSeqNum(Map<String, Object> actAppointment) {
+ List<?> items = asList(actAppointment, "subject", "patient", "id", "item");
+ for (Object it : items) {
+ if (!(it instanceof Map)) {
+ continue;
+ }
+ Map<String, Object> item = (Map<String, Object>) it;
+ Object root = item.get("root");
+ if (root != null && ROOT_BOOK_SEQ_NUM.equals(root.toString().trim())) {
+ Object ext = item.get("extension");
+ return ext == null ? null : parseIntegerQuietly(ext.toString());
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 鍙栨鏌ラ绾︽姤鏂囩殑鐢宠鍗曞彿銆�
+ * <p>
+ * 浼樺厛 {@code referencedOrder[0].actOrder.id.extension}锛堜笌 S0201ECG 鍒涘缓鐨勭敵璇峰崟鍙蜂竴鑷达紝
+ * 瀹炴祴 {@code 2126091700001}锛夛紱鍙栦笉鍒版椂鍥為��鍒� {@code actAppointment.id.extension}
+ * 锛堟帴鍙f枃妗e畾涔夌殑棰勭害鍙凤紝瀹炴祴 {@code 3360270}锛夈��
+ */
+ @SuppressWarnings("unchecked")
+ private String extractApplyNoFromCheckAppointment(Map<String, Object> actAppointment) {
+ Object referencedOrders = actAppointment.get("referencedOrder");
+ if (referencedOrders instanceof List) {
+ List<?> list = (List<?>) referencedOrders;
+ if (!list.isEmpty() && list.get(0) instanceof Map) {
+ Map<String, Object> first = (Map<String, Object>) list.get(0);
+ Map<String, Object> actOrder = (Map<String, Object>) first.get("actOrder");
+ if (actOrder != null) {
+ Map<String, Object> id = (Map<String, Object>) actOrder.get("id");
+ if (id != null && id.get("extension") != null) {
+ return id.get("extension").toString();
+ }
+ }
+ }
+ }
+ Map<String, Object> id = (Map<String, Object>) actAppointment.get("id");
+ if (id != null && id.get("extension") != null) {
+ return id.get("extension").toString();
+ }
+ return null;
+ }
+
+ /** 渚濇嵁妫�鏌ラ绾︽姤鏂囨彃鍏ユ柊璁板綍锛圦4 瀹归敊鏂板锛� */
+ @SuppressWarnings("unchecked")
+ private void insertAppointmentFromCheckAppointment(String applyNo, Map<String, Object> actAppointment,
+ LocalDate bookDate, LocalDateTime bookTime,
+ Integer bookTimeslot, Integer bookSrcValue, String status) {
+ AppointmentDO appointment = new AppointmentDO();
+ appointment.setApplyNo(applyNo);
+ appointment.setBookDate(bookDate);
+ appointment.setBookTime(bookTime);
+ appointment.setBookTimeslot(bookTimeslot);
+ appointment.setBookSrc(bookSrcValue);
+ appointment.setStatus(status);
+
+ Map<String, Object> zdy = (Map<String, Object>) actAppointment.get("ZDY");
+ // ZDY 涓殑 remark锛堟敞鎰忎簨椤癸級涓� roomname锛堟埧闂村悕绉帮級宸查殢琛ㄦ柊澧炲垪钀藉簱锛�
+ // area锛堜綅缃級涓� roomcode锛堟埧闂寸紪鐮侊級鐩墠浠嶆棤瀵瑰簲鍒楋紝鏆備笉淇濆瓨銆�
+ if (zdy != null) {
+ Object remark = zdy.get("remark");
+ if (remark != null && StringUtils.isNotEmpty(remark.toString())) {
+ appointment.setRemark(truncate(remark.toString(), REMARK_MAX_LEN));
+ }
+ Object roomName = zdy.get("roomname");
+ if (roomName != null && StringUtils.isNotEmpty(roomName.toString())) {
+ appointment.setRoomName(truncate(roomName.toString(), ROOM_NAME_MAX_LEN));
+ }
+ }
+ // 棰勭害鎺掑簭鍙凤紙patient.id.item[4]锛�
+ Integer bookSeqNum = extractBookSeqNum(actAppointment);
+ if (bookSeqNum != null) {
+ appointment.setBookSeqNum(bookSeqNum);
+ }
+
+ // 鎮h�呬俊鎭�
+ Map<String, Object> subjectNode = (Map<String, Object>) actAppointment.get("subject");
+ if (subjectNode != null) {
+ Map<String, Object> patient = (Map<String, Object>) subjectNode.get("patient");
+ if (patient != null) {
+ List<?> patIdItems = Optional.ofNullable(patient.get("id"))
+ .map(id -> (Map<String, Object>) id).map(id -> id.get("item"))
+ .filter(it -> it instanceof List).map(it -> (List<?>) it)
+ .orElse(Collections.emptyList());
+ if (patIdItems.size() > 1) {
+ appointment.setPatId((String) ((Map<String, Object>) patIdItems.get(1)).get("extension"));
+ }
+ if (patIdItems.size() > 2) {
+ appointment.setOutpatientNo((String) ((Map<String, Object>) patIdItems.get(2)).get("extension"));
+ }
+ if (patIdItems.size() > 3) {
+ appointment.setHospitalNo((String) ((Map<String, Object>) patIdItems.get(3)).get("extension"));
+ }
+ // 棰勭害鎺掑簭鍙峰凡鍦ㄤ笂鏂归�氳繃 extractBookSeqNum 缁熶竴璧嬪�硷紝姝ゅ涓嶅啀閲嶅澶勭悊
+ // 鎮h�呭鍚�
+ Optional.ofNullable(patient.get("patientPerson"))
+ .map(p -> (Map<String, Object>) p)
+ .map(p -> (Map<String, Object>) p.get("name"))
+ .map(n -> (Map<String, Object>) n.get("item"))
+ .map(i -> (Map<String, Object>) i.get("part"))
+ .map(part -> (String) part.get("value"))
+ .ifPresent(appointment::setPatName);
+ // 鐥呬汉绉戝锛坧roviderOrganization锛夆�斺�� Q7 鍚敤
+ Optional.ofNullable(patient.get("providerOrganization"))
+ .map(org -> (Map<String, Object>) org)
+ .ifPresent(org -> {
+ Optional.ofNullable(org.get("id"))
+ .map(id -> (Map<String, Object>) id)
+ .map(id -> (Map<String, Object>) id.get("item"))
+ .map(item -> (Map<String, Object>) item)
+ .map(item -> (String) item.get("extension"))
+ .ifPresent(appointment::setPatDeptCode);
+ Optional.ofNullable(org.get("name"))
+ .map(n -> (Map<String, Object>) n)
+ .map(n -> (Map<String, Object>) n.get("item"))
+ .map(i -> (Map<String, Object>) i.get("part"))
+ .map(part -> (String) part.get("value"))
+ .ifPresent(appointment::setPatDeptDesc);
+ });
+ }
+ }
+
+ if (StringUtils.isEmpty(appointment.getPatName())) {
+ log.warn("[insertAppointmentFromCheckAppointment][瀹归敊鏂板鐨勮褰曠己灏戞偅鑰呭鍚峕 applyNo={}", applyNo);
+ }
+ // appointment.pat_id / pat_name 鍦ㄦ暟鎹簱涓负 NOT NULL锛�
+ // 缂哄�兼椂鑻ョ洿鎺� insert 浼氭姏 SQL 寮傚父骞跺鑷存暣涓簨鍔″洖婊氥��
+ // 杩欓噷鎻愬墠缁欏嚭鏄庣‘閿欒锛屼究浜� HIS 渚у畾浣嶆姤鏂囬棶棰樸��
+ if (StringUtils.isEmpty(appointment.getPatId())) {
+ log.error("[insertAppointmentFromCheckAppointment][鎶ユ枃缂烘偅鑰呯紪鍙�(pat_id)锛屾棤娉曟柊澧瀅 applyNo={}", applyNo);
+ throw exception(PATIENT_NOT_EXISTS);
+ }
+ if (appointment.getPatGender() == null) {
+ log.warn("[insertAppointmentFromCheckAppointment][鎶ユ枃鏈彁渚涙偅鑰呮�у埆锛屾寜鏈煡(0)鍐欏叆] applyNo={}", applyNo);
+ appointment.setPatGender(UNKNOWN_GENDER);
+ }
+ AppointmentSaveReqVO saveReqVO = BeanUtils.toBean(appointment, AppointmentSaveReqVO.class);
+ createAppointment(saveReqVO);
+ }
+
+ /** 瑙f瀽 {@code yyyyMMddHHmmss} 鏃堕棿锛屽け璐ユ垨涓虹┖杩斿洖 null锛堜笉鎶涘紓甯革級 */
+ private LocalDateTime parseDateTime(String value) {
+ if (StringUtils.isEmpty(value)) {
+ return null;
+ }
+ try {
+ return LocalDateTime.parse(value.trim(), DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
+ } catch (Exception e) {
+ log.warn("[parseDateTime][鏃堕棿鏍煎紡闈炴硶锛屽拷鐣 value={}", value);
+ return null;
+ }
+ }
+
+ /** 瑙f瀽 ZDY.time锛堝舰濡� "2026-09-17 08:30-09:00"锛変负 hhmmhhmm 鏁存暟锛屽け璐ヨ繑鍥� null */
+ private Integer parseBookTimeslot(String timeRange) {
+ if (StringUtils.isEmpty(timeRange)) {
+ return null;
+ }
+ try {
+ String[] parts = timeRange.trim().split("\\s+");
+ if (parts.length < 2) {
+ return null;
+ }
+ String[] times = parts[1].split("-");
+ if (times.length < 2) {
+ return null;
+ }
+ String startTime = times[0].trim().replace(":", "");
+ String endTime = times[1].trim().replace(":", "");
+ return Integer.parseInt(startTime) * 10000 + Integer.parseInt(endTime);
+ } catch (Exception e) {
+ log.warn("[parseBookTimeslot][鏃堕棿娈佃В鏋愬け璐ワ紝蹇界暐] timeRange={}", timeRange);
+ return null;
+ }
+ }
+
+ /** 瀹芥澗鏁存暟瑙f瀽锛氶潪鏁板瓧鎴栫┖杩斿洖 null锛堥伩鍏� Integer.parseInt(null) 鎶涘紓甯革級 */
+ private Integer parseIntegerQuietly(String value) {
+ if (StringUtils.isEmpty(value) || !value.trim().matches("-?\\d+")) {
+ return null;
+ }
+ try {
+ return Integer.parseInt(value.trim());
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ }
+
+ /** 瀹芥澗 Byte 瑙f瀽锛氶潪鏁板瓧鎴栫┖杩斿洖 null锛堢敤浜庢偅鑰呮�у埆绛� tinyint 瀛楁锛� */
+ private Byte parseByteQuietly(String value) {
+ if (StringUtils.isEmpty(value) || !value.trim().matches("-?\\d+")) {
+ return null;
+ }
+ try {
+ return Byte.parseByte(value.trim());
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public void handleAppointmentStatusUpdate(Map<String, Object> dataMap) {
+ if (dataMap == null) {
+ throw exception(APPOINTMENT_STATUS_REGISTER_UPDATE_FAIL);
+ }
+ //鑾峰彇applyNo
+ Map<String, Object> controlActProcess = (Map<String, Object>) dataMap.get("controlActProcess");
+ Map<String, Object> subject = (Map<String, Object>) controlActProcess.get("subject");
+ Map<String, Object> placerGroup = (Map<String, Object>) subject.get("placerGroup");
+ Map<String, Object> component2 = (Map<String, Object>) placerGroup.get("component2");
+ Map<String, Object> observationRequest = (Map<String, Object>) component2.get("observationRequest");
+ Map<String, Object> id = (Map<String, Object>) observationRequest.get("id");
+ Map<String, Object> item = (Map<String, Object>) id.get("item");
+ String applyNo = (String) item.get("extension");
+
+ //鑾峰彇status
+ Map<String, Object> component1 = (Map<String, Object>) observationRequest.get("component1");
+ Map<String, Object> processStep = (Map<String, Object>) component1.get("processStep");
+ Map<String, Object> codeMap = (Map<String, Object>) processStep.get("code");
+ String status = String.valueOf(codeMap.get("code"));
+ Date date = null;
+ if (status.equals("3")) {
+ //璁板綍鐧昏鏃堕棿
+ date = new Date();
+ }
+ // 銆愯瘖鏂棩蹇椼�戠櫥璁版椂闂村啓鍏ュ墠鍚庡甫绫诲瀷淇℃伅锛岀敤浜庡揩閫熷畾浣嶃��00:00:00 鎴柇銆嶇被闂銆�
+ //
+ // 鑳屾櫙锛�2026-09-27 璧� appointment.register_date 鍑虹幇澶ч噺 yyyy-MM-dd 00:00:00锛�
+ // 缁忓疄楠岀‘璁ゆ垚鍥犳槸銆屽啓鍏ュ�兼槸 DATE 璇箟鐨勫�笺�嶈�岄潪椹卞姩闂锛�
+ // 路 java.util.Date + DATETIME 鍒� 鈫� 淇濈暀鏃跺垎绉�
+ // 路 java.sql.Date / DATE 鍒� 鈫� 蹇呯劧鍙樻垚 00:00:00
+ // 鏈棩蹇楁墦鍗� date 鐨勫疄闄呯被鍚嶄笌鍊硷紝鑻ユ棩蹇楅噷鍑虹幇 java.sql.Date 鎴栭潪 3 鐘舵�佸嵈琚啓锛�
+ // 鍗冲彲鐩存帴瀹氫綅鍐欏叆鏂广��
+ if (date != null) {
+ log.info("[handleAppointmentStatusUpdate][鐧昏鏃堕棿鍐欏叆] applyNo={} status={} "
+ + "鏃ユ湡瀵硅薄绫诲瀷={} 鍊�={}锛堟椂闂撮儴鍒嗗簲涓哄綋鍓嶆椂鍒伙紝鑻ヤ负 00:00:00 璇存槑琚埅鏂級",
+ applyNo, status, date.getClass().getName(),
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date));
+ }
+ //鐘舵�佹洿鏂�
+ Integer i = appointmentMapper.updateStatusByApplyNo(applyNo, status, date);
+ log.info("鐢宠鍗曠櫥璁癮pplyNo:{},鐘舵�乻tatus:{},鏇存柊缁撴灉锛歿}", applyNo, status, i);
+
+ }
+
+ public AppointmentDO getByApplyNo(String applyNo) {
+ return appointmentMapper.getByApplyNo(applyNo);
+ }
+}
+
--
Gitblit v1.9.3