traffic-audit-server/src/main/java/com/trafficaudit/auditengine/service/AuditEngineService.java
@@ -1645,26 +1645,34 @@
        return null;
    }
    /** 货运类型环比:本月新增(上月为0、本月>0)需核实,少的不管 */
    /** 货运类型环比(RULE_004):上月无→本月新增 或 上月有→本月无,均提醒核实 */
    private AuditResult checkMom(AuditRule rule, H2032EnterpriseMonthly report,
                                 Map<String, H2032EnterpriseMonthly> lastMonthMap) {
        H2032EnterpriseMonthly lastMonth = lastMonthMap.get(key(report.getEnterpriseCode()));
        if (lastMonth == null) return null;
        List<String> hits = new ArrayList<>();
        List<String> addHits = new ArrayList<>();
        List<String> delHits = new ArrayList<>();
        for (String field : rule.getCheckField().split(",")) {
            double current = getH2032FieldValue(report, field);
            double last = getH2032FieldValue(lastMonth, field);
            if (current > 0 && last == 0) {
                hits.add(h2032FieldLabel(field) + "=" + fmt(current));
                addHits.add(h2032FieldLabel(field) + "=" + fmt(current));
            } else if (last > 0 && current == 0) {
                delHits.add(h2032FieldLabel(field) + "(上月=" + fmt(last) + ",本月无)");
            }
        }
        if (!hits.isEmpty()) {
            return buildResult(rule, report, "本月新增: " + String.join("、", hits),
                "上月该类型为0", "本月新增货运类型(上月无)");
        if (!addHits.isEmpty() || !delHits.isEmpty()) {
            StringBuilder msg = new StringBuilder();
            if (!addHits.isEmpty()) msg.append("本月新增: ").append(String.join("、", addHits));
            if (!delHits.isEmpty()) {
                if (msg.length() > 0) msg.append(";");
                msg.append("本月消失: ").append(String.join("、", delHits));
            }
            return buildResult(rule, report, msg.toString(),
                "上月无→本月新增 或 上月有→本月无", "货运类型环比新增/消失需核实");
        }
        return null;
    }
    /** 有货运量但对应车辆为0 需核实(如 有集装箱货运量无集装箱车辆) */
    private AuditResult checkNull(AuditRule rule, H2032EnterpriseMonthly report) {
        String[] fields = rule.getCheckField().split(",");
@@ -1679,15 +1687,29 @@
        return null;
    }
    /** 数值范围检查(如 整车吨位 4≤且≤40) */
    /** 数值范围检查;整车吨位按“平均吨位=整车吨位/整车数”口径判定 4~40 */
    private AuditResult checkOutRange(AuditRule rule, H2032EnterpriseMonthly report) {
        String[] bounds = rule.getThreshold().split(",");
        if (bounds.length < 2) return null;
        double value = getH2032FieldValue(report, rule.getCheckField());
        String field = rule.getCheckField();
        String label = h2032FieldLabel(field);
        double value;
        if ("tonsWhole".equals(field)) {
            double vehicles = report.getVehicleWhole() == null ? 0.0 : report.getVehicleWhole().doubleValue();
            double tons = nvl(report.getTonsWhole());
            if (vehicles > 0) {
                value = tons / vehicles;
                label = "整车平均吨位(整车吨位/整车数)";
            } else {
                value = tons; // 无整车数但有吨位时仍按原吨位判定
            }
        } else {
            value = getH2032FieldValue(report, field);
        }
        double low = Double.parseDouble(bounds[0].trim());
        double high = Double.parseDouble(bounds[1].trim());
        if (value > 0 && (value < low || value > high)) {
            return buildResult(rule, report, h2032FieldLabel(rule.getCheckField()) + "=" + fmt(value),
            return buildResult(rule, report, label + "=" + fmt(value),
                "范围 " + fmt(low) + "~" + fmt(high), "超出范围");
        }
        return null;
@@ -1805,18 +1827,20 @@
    }
    private String fmt(double v) {
        if (v == Math.floor(v) && !Double.isInfinite(v)) {
        if (v == Math.floor(v) && !Double.isInfinite(v) && Math.abs(v) < 1e15) {
            return String.valueOf((long) v);
        }
        return String.valueOf(Math.round(v * 100.0) / 100.0);
        return java.math.BigDecimal.valueOf(v).setScale(2, java.math.RoundingMode.HALF_UP)
            .stripTrailingZeros().toPlainString();
    }
    /** 占比/小数值:保留 4 位小数 */
    private String fmt4(double v) {
        if (v == Math.floor(v) && !Double.isInfinite(v)) {
        if (v == Math.floor(v) && !Double.isInfinite(v) && Math.abs(v) < 1e15) {
            return String.valueOf((long) v);
        }
        return String.valueOf(Math.round(v * 10000.0) / 10000.0);
        return java.math.BigDecimal.valueOf(v).setScale(4, java.math.RoundingMode.HALF_UP)
            .stripTrailingZeros().toPlainString();
    }
    // ========== H2031 旅客审核 ==========