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<QualityInspectParam> 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 + "),不能按合格保存";
|
}
|
}
|