package com.ruoyi.quality.util; import com.ruoyi.quality.pojo.QualityInspectParam; import org.apache.commons.lang3.StringUtils; import java.math.BigDecimal; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * 检验值与标准/内控范围校验。 * 支持区间、正负偏差、大小比较和精确数值,例如:1.95~2.05、2.00±0.10、≤0.02、≥100。 */ public final class QualityInspectionValueValidator { private static final String NUMBER = "(-?\\d+(?:\\.\\d+)?)"; private static final Pattern RANGE = Pattern.compile("^" + NUMBER + "(?:~|~|至|—|-)" + NUMBER + "$"); private static final Pattern PLUS_MINUS = Pattern.compile("^" + NUMBER + "(?:±|\\+/-)" + NUMBER + "$"); private static final Pattern TOLERANCE_ONLY = Pattern.compile("^(?:±|\\+/-)" + NUMBER + "$"); private static final Pattern COMPARE = Pattern.compile("^(<=|>=|<|>|≤|≥)" + NUMBER + "$"); private static final Pattern EXACT = Pattern.compile("^" + NUMBER + "$"); private static final Pattern OBVIOUS_ABNORMAL_TEXT = Pattern.compile(".*(异常|不合格|失败|不通过|超标|缺陷).*", Pattern.CASE_INSENSITIVE); private QualityInspectionValueValidator() { } public static String validateQualified(List parameters) { if (parameters == null) { return null; } for (QualityInspectParam parameter : parameters) { String message = validateParameter(parameter); if (message != null) { return message; } } return null; } private static String validateParameter(QualityInspectParam parameter) { if (parameter == null || StringUtils.isBlank(parameter.getTestValue())) { return null; } String testText = normalize(parameter.getTestValue()); if (OBVIOUS_ABNORMAL_TEXT.matcher(testText).matches()) { return error(parameter, effectiveRule(parameter)); } BigDecimal testValue = decimal(testText); String rule = firstNumericRule(parameter.getControlValue(), parameter.getStandardValue()); if (rule == null) { return null; } if (testValue == null || !matches(testValue, rule)) { return error(parameter, rule); } return null; } private static String firstNumericRule(String controlValue, String standardValue) { String control = normalize(controlValue); if (isSupportedRule(control)) { return control; } String standard = normalize(standardValue); return isSupportedRule(standard) ? standard : null; } private static boolean isSupportedRule(String rule) { return rule != null && (RANGE.matcher(rule).matches() || PLUS_MINUS.matcher(rule).matches() || TOLERANCE_ONLY.matcher(rule).matches() || COMPARE.matcher(rule).matches() || EXACT.matcher(rule).matches()); } private static boolean matches(BigDecimal value, String rule) { Matcher matcher = RANGE.matcher(rule); if (matcher.matches()) { BigDecimal first = new BigDecimal(matcher.group(1)); BigDecimal second = new BigDecimal(matcher.group(2)); BigDecimal min = first.min(second); BigDecimal max = first.max(second); return value.compareTo(min) >= 0 && value.compareTo(max) <= 0; } matcher = PLUS_MINUS.matcher(rule); if (matcher.matches()) { BigDecimal center = new BigDecimal(matcher.group(1)); BigDecimal tolerance = new BigDecimal(matcher.group(2)).abs(); return value.compareTo(center.subtract(tolerance)) >= 0 && value.compareTo(center.add(tolerance)) <= 0; } Matcher toleranceOnly = TOLERANCE_ONLY.matcher(rule); if (toleranceOnly.matches()) { BigDecimal tolerance = new BigDecimal(toleranceOnly.group(1)).abs(); return value.abs().compareTo(tolerance) <= 0; } matcher = COMPARE.matcher(rule); if (matcher.matches()) { int compared = value.compareTo(new BigDecimal(matcher.group(2))); String operator = matcher.group(1); if ("<".equals(operator)) return compared < 0; if (">".equals(operator)) return compared > 0; if ("<=".equals(operator) || "≤".equals(operator)) return compared <= 0; return compared >= 0; } matcher = EXACT.matcher(rule); return matcher.matches() && value.compareTo(new BigDecimal(matcher.group(1))) == 0; } private static BigDecimal decimal(String value) { try { return StringUtils.isBlank(value) ? null : new BigDecimal(value); } catch (NumberFormatException ignored) { return null; } } private static String normalize(String value) { return StringUtils.isBlank(value) ? null : value.trim().replaceAll("\\s+", "").replace(",", ""); } private static String effectiveRule(QualityInspectParam parameter) { return StringUtils.isNotBlank(parameter.getControlValue()) ? parameter.getControlValue() : parameter.getStandardValue(); } private static String error(QualityInspectParam parameter, String rule) { String item = StringUtils.defaultIfBlank(parameter.getParameterItem(), "未命名指标"); String standard = StringUtils.defaultIfBlank(rule, "已配置标准"); return "检验项目“" + item + "”的检验值“" + parameter.getTestValue() + "”不符合标准(" + standard + "),不能按合格保存"; } }