package cn.lihu.jh.module.ecg.controller.admin.external;
|
|
import cn.lihu.jh.framework.common.pojo.CommonResult;
|
import cn.lihu.jh.module.ecg.enums.ActionTypeEnum;
|
import cn.lihu.jh.module.ecg.service.appointment.AppointmentService;
|
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.validation.annotation.Validated;
|
import org.springframework.web.bind.annotation.*;
|
|
import javax.annotation.Resource;
|
import javax.annotation.security.PermitAll;
|
import javax.validation.constraints.NotEmpty;
|
import javax.validation.constraints.NotNull;
|
import java.util.Map;
|
|
import static cn.lihu.jh.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.lihu.jh.framework.common.pojo.CommonResult.success;
|
import static cn.lihu.jh.module.ecg.enums.ErrorCodeConstants.*;
|
|
/**
|
* 供第三方(HIS / 集成平台)调用的通用接口。
|
*
|
* <h3>路由方式</h3>
|
* 通过请求头 {@code action} 区分服务,取值见 {@link ActionTypeEnum}。
|
*
|
* <h3>本次改动要点</h3>
|
* <ol>
|
* <li><b>补注册 ECG 专属 action</b>:接口文档 6.4/6.5 定义
|
* {@code S050402}(ECG 检查预约状态新增)、{@code S050502}(ECG 检查预约状态更新),
|
* 与 pacs 的 {@code S050401}/{@code S050501} 并列。实测日志中这两个编号
|
* 尚未出现(0 次),此处**主动兼容**,避免院方切换编号时消息被拒。</li>
|
* <li><b>兼容无后缀写法</b>:文档定义 {@code S0201}/{@code S0202},
|
* 而实测报文为 {@code S0201ECG}/{@code S0202ECG},两者均接收。</li>
|
* <li><b>细化错误码</b>:原实现把所有异常统一压成
|
* {@code APPOINTMENT_CREATE_FAIL}("申请单创建失败"),
|
* 导致排障困难(本次问题排查成本即来自此)。现按
|
* 「未知 action / 报文解析失败 / 记录不存在 / 其他」区分返回。</li>
|
* </ol>
|
*
|
* <h3>关于 S0405</h3>
|
* {@code S0405}(申请单状态更新)是**全院通用**服务,医院会把所有检查科室
|
* (CT/MRI/DR/超声…)的状态一并推送。业务层已按心电范围过滤,
|
* 非心电单只记日志、不处理(详见 {@code HisEcgFilter})。
|
*
|
* @author 心电排队装机系统
|
*/
|
@Tag(name = "供第三方调用接口")
|
@RestController
|
@RequestMapping("/ecg/external")
|
@Validated
|
@Slf4j
|
public class ExternalController {
|
|
/** 请求头中的 action 键名 */
|
private static final String HEADER_ACTION = "action";
|
|
@Resource
|
private AppointmentService appointmentService;
|
|
/**
|
* 通用接口。
|
*
|
* <p>支持的 action 见 {@link ActionTypeEnum},包括:
|
* 申请单新增/更新、申请单状态更新、检查预约状态新增/更新。
|
*
|
* @param dataMap 请求数据(HL7 V3 转换后的 Map)
|
* @param headers 请求头,必须包含 {@code action}
|
* @return 处理结果
|
*/
|
@PermitAll
|
@Operation(summary = "通用接口")
|
@PostMapping("/generalInterface")
|
public CommonResult<Boolean> generalInterface(
|
@RequestBody @NotNull(message = "请求数据不能为空") Map<String, Object> dataMap,
|
@RequestHeader @NotEmpty(message = "请求头不能为空") Map<String, String> headers) {
|
|
String rawAction = headers.get(HEADER_ACTION);
|
ActionTypeEnum action = ActionTypeEnum.getByType(rawAction);
|
if (action == null) {
|
// 不再吞成"申请单创建失败",明确告知 action 不受支持
|
log.warn("[generalInterface][不支持的 action({}),请核对接口文档 6.x 交易编号]", rawAction);
|
throw exception(HIS_ACTION_NOT_SUPPORTED);
|
}
|
|
log.info("[generalInterface][开始处理请求 action({}) dataMap({})]", rawAction, dataMap);
|
|
try {
|
dispatch(action, dataMap);
|
return success(true);
|
} catch (cn.lihu.jh.framework.common.exception.ServiceException e) {
|
// 业务异常:保留原始错误码与信息,便于 HIS 侧定位
|
log.error("[generalInterface][业务处理失败 action({}) code({}) msg({})]",
|
rawAction, e.getCode(), e.getMessage());
|
throw e;
|
} catch (Exception e) {
|
// 未预期异常:报文解析失败、字段缺失导致的 NPE/类型转换异常等
|
log.error("[generalInterface][报文处理异常 action({}) dataMap({})]", rawAction, dataMap, e);
|
throw exception(HIS_MESSAGE_PARSE_FAIL);
|
}
|
}
|
|
/**
|
* 按 action 分派到对应处理器。
|
* <p>
|
* 使用 {@link ActionTypeEnum} 的分组方法而非 Map 映射,是为了让
|
* 「同一服务的多种编号」(pacs / ECG、有后缀 / 无后缀)走同一处理器,
|
* 避免新增编号时漏配。
|
*/
|
private void dispatch(ActionTypeEnum action, Map<String, Object> dataMap) {
|
if (action.isApplyCreate()) {
|
appointmentService.handleAppointmentCreate(dataMap);
|
} else if (action.isApplyUpdate()) {
|
appointmentService.handleAppointmentUpdate(dataMap);
|
} else if (action.isApplyStatusUpdate()) {
|
appointmentService.handleAppointmentStateUpdate(dataMap);
|
} else if (action.isAppointmentStatusCreate()
|
|| action.isAppointmentStatusUpdate()) {
|
// 检查预约状态:新增(S050401/S050402) 与 更新(S050501/S050502)
|
// 报文结构相同,走同一处理器
|
appointmentService.handleCheckAppointmentUpdate(dataMap);
|
} else {
|
// 枚举新增但未接入分派逻辑时的兜底,避免静默忽略
|
throw exception(HIS_ACTION_NOT_SUPPORTED);
|
}
|
}
|
}
|