yxh
7 天以前 68ff33beff11310e830b0615b5a81f83fad0f683
jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/enums/HisCheckNameEnum.java
@@ -4,7 +4,20 @@
import lombok.Getter;
/**
 * His的Check_type类型枚举
 * His的Check_type类型枚举(按 HIS 传来的**检查项目名称**映射本地 check_type)
 *
 * <p>注意:同一个检查在 HIS 侧可能有多个叫法,本枚举用「一个值挂多个名称」的方式兼容。
 * 实测 2026-10-04/05:运动试验这一项 HIS 侧改名过——
 * 「平板运动心电」(旧)→「平板运动试验」(现),而本地 check_type 一直是 400。
 * 名称映射不到时,{@code handleAppointmentCreate} 会退回按 HIS 检查代码映射
 * ({@link HisCheckCodeEnum}),两条路任一条通即可,避免再出现 book_check_type 为空。</p>
 *
 * <p>实测 2026-10-07 又发现血压类同样的问题:HIS 发的是「24小时动态血压监测」,
 * 而枚举里当时只有「动态血压」,精确匹配失败(日志:
 * {@code [handleAppointmentCreate][体检患者检查项目名称无法映射] checkName=24小时动态血压监测})。
 * 现已补齐别名;同时 {@link #getByName(String)} 增加一层**规范化兜底匹配**,
 * 用于吸收 HIS 侧「有无「24小时」前缀」「全/半角括号」「多余空格」这类无意义差异,
 * 避免每换一种叫法就要改一次代码。</p>
 */
@Getter
@AllArgsConstructor
@@ -12,8 +25,23 @@
    Y691133607("常规心电图", "100"),
    Y201605("24小时动态心电图", "200"),
    Y201606("24小时动态心电监测", "200"),
    // 同一检查(本地 check_type=200 动态心电)的其它叫法。
    // 实测报文里该项的 code 存在两种形态:Y201605(带Y前缀)与 201605(不带),
    // 而 HisCheckCodeEnum 只登记了 201605,故带 Y 的那种必须靠名称映射兜住。
    Y201605_ALIAS1("动态心电图", "200"),
    Y201605_ALIAS2("24小时动态心电", "200"),
    Y201605_ALIAS3("动态心电监测", "200"),
    Y200327("动态血压", "300"),
    // 同一检查(本地 check_type=300 动态血压)的其它叫法。
    // 实测 2026-10-07:HIS 实际下发的是「24小时动态血压监测」(jcxmcode=Y200327),
    // 当时枚举只有「动态血压」→ 名称匹配失败,且代码兜底也对不上(代码是 Y200327,表里记的是 200327)。
    Y200327_ALIAS1("24小时动态血压监测", "300"),
    Y200327_ALIAS2("24小时动态血压", "300"),
    Y200327_ALIAS3("动态血压监测", "300"),
    Y201652("平板运动心电", "400"),
    // 同一检查(本地 check_type=400)的其它叫法:枚举常量名不能重复,故加后缀
    Y201652_ALIAS1("平板运动试验", "400"),
    Y201652_ALIAS2("心电图运动试验", "400"),
    Y502490914("动脉硬化检测", "500"),
    Y419562119("食道电生理", "600"),
    Y201604("心电图药物负荷试验", "700"),
@@ -32,20 +60,66 @@
    private final String value;
    /**
     * 根据类型获取枚举
     * 根据名称获取本地检查类型:先精确匹配,再规范化兜底匹配。
     *
     * @param type 类型
     * @return 枚举
     * @param name HIS 传来的检查项目名称
     * @return 本地 check_type 字符串;都匹配不到返回 null
     */
    public static String getByName(String name) {
        if (name == null) {
            return null;
        }
        // ① 精确匹配(保持原有行为)
        for (HisCheckNameEnum value : values()) {
            if (value.getName().equals(name)) {
                return value.getValue();
            }
        }
        // ② 规范化后再匹配:吸收「24小时」前缀、全/半角括号、空格、大小写等无意义差异,
        //    避免 HIS 每换一种叫法就漏映射(例如「24小时动态血压监测」vs「动态血压监测」)
        String normalized = normalizeName(name);
        if (normalized.isEmpty()) {
            return null;
        }
        for (HisCheckNameEnum value : values()) {
            String enumNormalized = normalizeName(value.getName());
            if (enumNormalized.equals(normalized)) {
                return value.getValue();
            }
            // ③ 去掉「24小时」后再比一次:HIS 侧有无该前缀都可能出现
            if (strip24Hour(enumNormalized).equals(strip24Hour(normalized)) && !strip24Hour(normalized).isEmpty()) {
                return value.getValue();
            }
        }
        return null;
    }
    /** 规范化项目名称:去空白、统一大小写、全角括号→半角、去掉「24小时」前缀 */
    private static String normalizeName(String name) {
        if (name == null) {
            return "";
        }
        return name.trim()
                .replace(" ", "")
                .replace("\u3000", "")
                .replace("(", "(")
                .replace(")", ")")
                .replace("24", "24")
                .toLowerCase();
    }
    /** 去掉「24小时」/「24h」前缀,用于比较同义名称 */
    private static String strip24Hour(String normalizedName) {
        String v = normalizedName;
        if (v.startsWith("24小时")) {
            v = v.substring("24小时".length());
        }
        if (v.startsWith("24h")) {
            v = v.substring("24h".length());
        }
        return v;
    }
    /**
     * 根据类型获取枚举
     *