liu
6 天以前 f8ccc5ab312ab7c5d6c7eb7fac4e37924f513869
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
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 + "),不能按合格保存";
    }
}