Jelajahi Sumber

Merge branch 'refs/heads/feature-lihb-20251030-formula' into dev

LHB 1 hari lalu
induk
melakukan
4ecc86902f

+ 1 - 1
blade-service/blade-manager/src/main/java/com/jfireel/expression/node/impl/EqualNode.java

@@ -28,7 +28,7 @@ public class EqualNode extends OperatorResultNode {
             if (leftValue instanceof Number && rightValue instanceof Number) {
                 return EqUtil.calculate((Number) leftValue, (Number) rightValue);
             } else if (leftValue instanceof List || rightValue instanceof List) {
-                Object[] leftAndRight = ValueUtil.obtain(leftOperand.calculate(variables), rightOperand.calculate(variables));
+                Object[] leftAndRight = ValueUtil.obtain(leftOperand.calculate(variables), rightOperand.calculate(variables), true);
 
                 //如果是数字类型 第一个是float  第二个是整数所以不能使用equals
                 if (leftAndRight[0] instanceof Number && leftAndRight[1] instanceof Number) {

+ 1 - 1
blade-service/blade-manager/src/main/java/com/jfireel/expression/node/impl/GtEqNode.java

@@ -28,7 +28,7 @@ public class GtEqNode extends OperatorResultNode {
             return calculate;
         }
         Object calculate1 = rightOperand.calculate(variables);
-        Object[] leftAndRight = ValueUtil.obtain(calculate, calculate1);
+        Object[] leftAndRight = ValueUtil.obtain(calculate, calculate1, true);
         return leftAndRight == null ? null : !((Boolean) LtUtil.calculate((Number) leftAndRight[0], (Number) leftAndRight[1]));
     }
 }

+ 1 - 1
blade-service/blade-manager/src/main/java/com/jfireel/expression/node/impl/GtNode.java

@@ -26,7 +26,7 @@ public class GtNode extends OperatorResultNode {
             return calculate;
         }
         Object calculate1 = rightOperand.calculate(variables);
-        Object[] leftAndRight = ValueUtil.obtain(calculate, calculate1);
+        Object[] leftAndRight = ValueUtil.obtain(calculate, calculate1, true);
         return leftAndRight == null ? null : GtUtil.calculate((Number) leftAndRight[0], (Number) leftAndRight[1]);
     }
 

+ 1 - 1
blade-service/blade-manager/src/main/java/com/jfireel/expression/node/impl/LtEqNode.java

@@ -26,7 +26,7 @@ public class LtEqNode extends OperatorResultNode {
             return calculate;
         }
         Object calculate1 = rightOperand.calculate(variables);
-        Object[] leftAndRight = ValueUtil.obtain(calculate, calculate1);
+        Object[] leftAndRight = ValueUtil.obtain(calculate, calculate1, true);
         return leftAndRight == null ? null : !((Boolean) GtUtil.calculate((Number) leftAndRight[0], (Number) leftAndRight[1]));
     }
 

+ 1 - 1
blade-service/blade-manager/src/main/java/com/jfireel/expression/node/impl/LtNode.java

@@ -27,7 +27,7 @@ public class LtNode extends OperatorResultNode {
             return calculate;
         }
         Object calculate1 = rightOperand.calculate(variables);
-        Object[] leftAndRight = ValueUtil.obtain(calculate, calculate1);
+        Object[] leftAndRight = ValueUtil.obtain(calculate, calculate1, true);
         return leftAndRight == null ? null : LtUtil.calculate((Number) leftAndRight[0], (Number) leftAndRight[1]);
     }
 

+ 1 - 1
blade-service/blade-manager/src/main/java/com/jfireel/expression/node/impl/NotEqualNode.java

@@ -28,7 +28,7 @@ public class NotEqualNode extends OperatorResultNode {
             if (leftValue instanceof Number && rightValue instanceof Number) {
                 return EqUtil.calculate((Number) leftValue, (Number) rightValue) == false;
             } else if (leftValue instanceof List || rightValue instanceof List) {
-                Object[] leftAndRight = ValueUtil.obtain(leftOperand.calculate(variables), rightOperand.calculate(variables));
+                Object[] leftAndRight = ValueUtil.obtain(leftOperand.calculate(variables), rightOperand.calculate(variables), true);
 
                 //如果是数字类型 第一个是float  第二个是整数所以不能使用equals
                 if (leftAndRight[0] instanceof Number && leftAndRight[1] instanceof Number) {

+ 60 - 0
blade-service/blade-manager/src/main/java/com/jfireel/expression/util/ValueUtil.java

@@ -36,10 +36,70 @@ public class ValueUtil {
         return null;
     }
 
+    /**
+     * 判断条件 处理字母+数字的数据 去掉字母
+     * @param left
+     * @param right
+     * @param letterNumber
+     * @return
+     */
+    public static Object[] obtain(Object left, Object right, boolean letterNumber) {
+        if (StringUtils.isNotEmpty(left, right)) {
+            if (left instanceof List) {
+                List<Object> tmp = CustomFunction.obj2ListNe(left);
+                if (tmp.size() == 0) {
+                    return null;
+                }
+                if(tmp.size() == 1){
+                    if(StringUtils.isNumber(tmp.get(0).toString())){
+                        left = Double.valueOf(tmp.get(0).toString());
+                    }else{
+                        left = tmp.get(0);
+                    }
+
+                }else{
+                    left = sum(tmp);
+                }
+            }
+            if (right instanceof List) {
+                List<Object> tmp = CustomFunction.obj2ListNe(right);
+                if (tmp.size() == 0) {
+                    return null;
+                }
+                if(tmp.size() == 1){
+                    if(StringUtils.isNumber(tmp.get(0).toString())){
+                        right = Double.valueOf(tmp.get(0).toString());
+                    }else{
+                        right = tmp.get(0);
+                    }
+                }else{
+                    right = sum(tmp);
+                }
+
+            }
+            if (StringUtils.isNotEmpty(left) && StringUtils.isNotEmpty(right)) {
+                if (letterNumber) {
+                    left = isLetterNumber(left);
+                    right = isLetterNumber(right);
+                }
+                return new Object[]{left, right};
+            }
+        }
+        return null;
+    }
     public static Object sum(List<Object> list) {
         if (ListUtils.isNotEmpty(list)) {
             return (float) list.stream().filter(StringUtils::isNumber).map(StringUtils::handleNull).mapToDouble(Double::parseDouble).sum();
         }
         return 0;
     }
+
+    public static Object isLetterNumber(Object str){
+        // 检查是否是字母数字组合(必须同时包含字母和数字,且只包含字母数字)
+        if (str != null && str.toString().matches("^(?=.*[a-zA-Z])(?=.*\\d)[a-zA-Z\\d]+$")) {
+            // 提取所有数字
+            return Double.valueOf(str.toString().replaceAll("[^0-9]", ""));
+        }
+        return str;
+    }
 }

+ 197 - 1
blade-service/blade-manager/src/main/java/com/mixsmart/utils/CustomFunction.java

@@ -11,11 +11,14 @@ import com.jfireel.expression.node.impl.VariableNode;
 import com.jfireel.expression.token.Token;
 import org.apache.commons.collections4.MapUtils;
 import org.springblade.common.utils.BaseUtils;
+import org.springblade.core.log.exception.ServiceException;
 import org.springblade.core.redis.cache.BladeRedis;
 import org.springblade.core.tool.utils.*;
+import org.springblade.manager.bean.SpringContextHolder;
 import org.springblade.manager.dto.ParamElements;
 import org.springblade.manager.entity.WbsTreeContract;
 import org.springblade.manager.utils.RandomNumberHolder;
+import org.springframework.jdbc.core.JdbcTemplate;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
@@ -23,6 +26,7 @@ import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.time.ZoneOffset;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
@@ -1187,7 +1191,7 @@ public class CustomFunction {
         }else{
             localDateTime= LocalDateTime.now();
         }
-      return localDateTime.atZone(java.time.ZoneOffset.UTC)
+      return localDateTime.atZone(ZoneOffset.UTC)
               .toInstant()
               .toEpochMilli();
     }
@@ -1996,6 +2000,19 @@ public class CustomFunction {
         }
         return result;
     }
+    public static List<Object> obj3List(Object obj) {
+        List<Object> result = new ArrayList<>();
+        if (obj != null) {
+            List<Object> datas = new ArrayList<>();
+            if (obj instanceof List) {
+                datas = (List<Object>) obj;
+            } else {
+                datas.add(obj);
+            }
+            return datas;
+        }
+        return result;
+    }
 
     /**
      * @return java.lang.Object
@@ -2235,6 +2252,10 @@ public class CustomFunction {
         List<Object> list = obj2List(obj);
         return list.parallelStream().filter(StringUtils::isNotEmpty).collect(Collectors.toList());
     }
+    public static List<Object> obj3ListNe(Object obj) {
+        List<Object> list = obj3List(obj);
+        return list.parallelStream().filter(StringUtils::isNotEmpty).collect(Collectors.toList());
+    }
 
     /*obj2ListNe别名*/
     public static List<Object> objToListNe(Object obj) {
@@ -3062,7 +3083,182 @@ public class CustomFunction {
         toDay(list).forEach(System.out::println);
     }*/
 
+    /**
+     * 特征值计算
+     */
+    public static Object eigenvalue(Object data){
 
+        //默认只有10组数据
+        if (data != null ) {
+            List<Object> datas = obj2ListNe(data);
+            datas = datas.size() > 10 ? datas.subList(0, datas.size()/2) : datas;
+            int total = datas.size();
+            //换算系数
+            double conversionFactor;
+            //获取换算系数
+            if(total >= 10 && total <= 15){
+                conversionFactor = 1.695;
+            }else if(total >= 16 && total <= 24){
+                conversionFactor = 1.645;
+            }else if(total>=25){
+                conversionFactor = 1.595;
+            }else{
+                throw new ServiceException("数据组数小于10");
+            }
+            List<String> _datas = datas.stream().map(StringUtils::handleNull).collect(Collectors.toList());
+            //获取平均值
+            double avgVal = _datas.stream().mapToDouble(Double::parseDouble).average().orElse(0D);
+            //获取标准差
+            double sqrt = Math.sqrt(_datas.stream().mapToDouble(Double::parseDouble).map(e -> Math.pow(e - avgVal, 2)).sum() / (total-1));
+            return avgVal - (conversionFactor * sqrt);
+        }
+        return null;
+    }
 
+    /**
+     * 混凝土强度 “换算值”计算
+     * @param data 混凝土强度实测值
+     * @param angle 角度
+     * @param pouringSurface 浇筑面
+     * @param type 测区计算方式 1-单独测区深度,2-测区平均值
+     * @param surveyDepth 测区深度
+     * @param Pumping 是否泵送 1-是,2-否
+     */
+    public static Object concreteStrength(Object data, Object angle, Object pouringSurface, Object type, Object surveyDepth, Object Pumping){
+        List<Object> datas = obj2ListNe(data);
+        List<Object> data1 = obj2ListNe(angle);
+        List<Object> data2 = obj2ListNe(pouringSurface);
+        List<Object> data4 = obj2ListNe(Pumping);
+
+        //数据库查询对象
+        JdbcTemplate jdbcTemplateStatic = SpringContextHolder.getBean(JdbcTemplate.class);
+
+        if (CollectionUtil.isNotEmpty(datas) && CollectionUtil.isNotEmpty(data1) && CollectionUtil.isNotEmpty(data2) && surveyDepth != null && CollectionUtil.isNotEmpty(data4)) {
+            angle = data1.get(0);
+            pouringSurface = data2.get(0);
+            Pumping = data4.get(0);
+
+            List<Double> list = datas.stream().filter(StringUtils::isNumber).map(m -> Double.valueOf(m.toString())).collect(Collectors.toList());
+            list = removeThreeMinAndMaxEfficient(list);
+            //计算平均值
+            double asDouble = list.stream().filter(StringUtils::isNumber).map(StringUtils::handleNull).mapToDouble(Double::parseDouble).average().orElse(0.0);
+            if (StringUtils.isNotEmpty(angle) && StringUtils.isNotEmpty(pouringSurface)) {
+                //角度  根据平均值从数据库中查询对应的映射值
+                List<Map<String, Object>> angleList = jdbcTemplateStatic.queryForList("select data_value from coordinate_angle where r_value = " + asDouble + " and h_value = " + angle);
+                if (CollectionUtil.isNotEmpty(angleList)) {
+                    Map<String, Object> stringObjectMap = angleList.get(0);
+                    asDouble += Double.parseDouble(stringObjectMap.get("data_value").toString());
+                }
+                //角度  根据平均值从数据库中查询对应的映射值
+                List<Map<String, Object>> pouringSurfaceList = jdbcTemplateStatic.queryForList("select data_value from coordinate_pouring_urface where r_value = " + asDouble + " and h_value = '" + pouringSurface + "'");
+                if (CollectionUtil.isNotEmpty(pouringSurfaceList)) {
+                    Map<String, Object> stringObjectMap = pouringSurfaceList.get(0);
+                    asDouble += Double.parseDouble(stringObjectMap.get("data_value").toString());
+                }
+
+                //最终值 R H
+                double r = asDouble;
+                double h = 0;
+
+                //测区深度 第一种只取第一条数据
+                if(type == null || "1".equals(type.toString())){
+                    String surveyDepthStr;
+                    if(surveyDepth instanceof List){
+                        List<Object> surveyDepthList = obj3ListNe(surveyDepth);
+                        surveyDepthStr = surveyDepthList.get(0).toString();
+                    }else{
+                        surveyDepthStr = surveyDepth.toString();
+                    }
+                    //分割字符串
+                    String[] split = surveyDepthStr.split(surveyDepthStr.contains(",") ? "," : "、");
+                    //计算平均值
+                    h = Arrays.stream(split).filter(StringUtils::isNumber).map(StringUtils::handleNull).mapToDouble(Double::parseDouble).average().orElse(0.0);
+                    //进行0.5修正
+                    h = roundHalfEven(new BigDecimal(h).setScale(1, RoundingMode.HALF_UP).doubleValue(),1);
+                }else{
+                    List<Object> surveyDepthList = obj3ListNe(surveyDepth);
+                    List<Double> doubleArrList = new ArrayList<>();
+                    surveyDepthList.forEach(f -> {
+                        String string = f.toString();
+                        //分割字符串
+                        String[] split = string.split(string.contains(",") ? "," : "、");
+                        //计算平均值
+                        double avg = Arrays.stream(split).filter(StringUtils::isNumber).map(StringUtils::handleNull).mapToDouble(Double::parseDouble).average().orElse(0.0);
+                        doubleArrList.add(roundHalfEven(new BigDecimal(avg).setScale(1, RoundingMode.HALF_UP).doubleValue(),1));
+                    });
+                    //结果再计算平均值
+                    h = doubleArrList.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
+                    //在进行修正
+                    h = roundHalfEven(new BigDecimal(h).setScale(1, RoundingMode.HALF_UP).doubleValue(),1);
+                }
+
+                //是否泵送
+                if ("是".equals(Pumping) || "1".equals(Pumping)) {
+                    //计算公式:f = 0.034488 * (R^1.9400) * 10^(-0.0173 * dm)
+                    double v = 0.034488 * Math.pow(r, 1.9400) * Math.pow(10, -0.0173 * h);
+                    return new BigDecimal(v).setScale(1, RoundingMode.HALF_UP);
+                } else {
+                    //从数据库中获取数据
+                    List<Map<String, Object>> list1 = jdbcTemplateStatic.queryForList("select data_value from coordinate_data where r_value = " + r + " and h_value = " + h);
+                    if (CollectionUtil.isNotEmpty(list1)) {
+                        Map<String, Object> stringObjectMap = list1.get(0);
+                        return new BigDecimal(stringObjectMap.get("data_value").toString()).setScale(1, RoundingMode.HALF_UP);
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    // 更高效的实现方式(一次性操作)
+    public static List<Double> removeThreeMinAndMaxEfficient(List<Double> list) {
+        if (list.size() <= 6) {
+            return new ArrayList<>();
+        }
+
+        // 创建列表的副本
+        List<Double> sortedList = new ArrayList<>(list);
 
+        // 排序列表
+        Collections.sort(sortedList);
+
+        // 直接获取中间部分的元素(跳过前3个和后3个)
+        return sortedList.subList(3, sortedList.size() - 3);
+    }
+
+    /**
+     * 使用银行家舍入法进行0.5修正
+     * @param number 要修正的数字
+     * @param scale 保留的小数位数
+     * @return 修正后的结果
+     */
+    public static double roundHalfEven(double number, int scale) {
+        BigDecimal bd = BigDecimal.valueOf(number);
+
+        // 获取小数部分
+        BigDecimal integerPart = new BigDecimal(bd.toBigInteger().toString());
+        BigDecimal decimalPart = bd.subtract(integerPart);
+
+        // 如果小数部分为0,直接返回
+        if (decimalPart.compareTo(BigDecimal.ZERO) == 0) {
+            return number;
+        }
+
+        // 将小数部分乘以10,获取第一位小数
+        BigDecimal firstDecimal = decimalPart.multiply(BigDecimal.TEN)
+                .setScale(0, RoundingMode.DOWN);
+
+        int firstDigit = firstDecimal.intValue();
+
+        if (firstDigit < 5) {
+            // 小数位数小于5,改成5
+            return integerPart.add(new BigDecimal("0.5")).doubleValue();
+        } else if (firstDigit > 5) {
+            // 小数位数大于5,四舍五入到整数
+            return bd.setScale(0, RoundingMode.HALF_UP).doubleValue();
+        } else {
+            // 等于5,不变
+            return number;
+        }
+    }
 }

+ 25 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/bean/SpringContextHolder.java

@@ -0,0 +1,25 @@
+package org.springblade.manager.bean;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SpringContextHolder implements ApplicationContextAware {
+
+    private static ApplicationContext applicationContext;
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        SpringContextHolder.applicationContext = applicationContext;
+    }
+
+    public static <T> T getBean(Class<T> clazz) {
+        return applicationContext.getBean(clazz);
+    }
+
+    public static Object getBean(String name) {
+        return applicationContext.getBean(name);
+    }
+}

+ 131 - 1
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/FormulaServiceImpl.java

@@ -5626,6 +5626,109 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                     }
                 }
             }
+            //合格点数公式
+            if(f.contains(".passingPoints")){
+                //Fc.passingPoints(参数1,参数2,=,参数3,返回类型(1数量,2内容),判定规则同行/同列)
+                Matcher m = RegexUtils.matcher(FC_REG + "(passingPoints)\\(([^)]+)\\)", f);
+                while (m.find()) {
+                    String el = m.group();
+                    String[] args = m.group(2).split(",");
+                    if(args.length == 6){
+                        //前进方向一侧
+                        List<FormData> fronts = getFormDataByCode(args[0], tec);
+                        //相反方向一侧
+                        List<FormData> afters = getFormDataByCode(args[1], tec);
+                        //统计规则,x 同列,y,同行
+                        String arg = args[5];
+                        List<Object> data = new ArrayList<>();
+                        Map<Integer, List<ElementData>> collect1;
+                        Map<Integer, List<ElementData>> collect2;
+                        if(CollectionUtil.isNotEmpty(fronts)){
+                            List<ElementData> values = fronts.get(0).getValues();
+                            //同行还是同列
+                            if("x".equals(arg)){
+                                collect1 = values.stream().collect(Collectors.groupingBy(ElementData::getX));
+                            }else{
+                                collect1 = values.stream().collect(Collectors.groupingBy(ElementData::getY));
+                            }
+
+                        } else {
+                            collect1 = null;
+                        }
+                        if(CollectionUtil.isNotEmpty(afters)){
+                            List<ElementData> values = afters.get(0).getValues();
+                            if("x".equals(arg)){
+                                collect2 = values.stream().collect(Collectors.groupingBy(ElementData::getX));
+                            }else{
+                                collect2 = values.stream().collect(Collectors.groupingBy(ElementData::getY));
+                            }
+                        } else {
+                            collect2 = null;
+                        }
+                        //默认统计数量
+                        boolean type;
+                        //统计数量
+                        if("2".equals(args[4])){
+                            type = false;
+                        } else {
+                            type = true;
+                        }
+                        fd.getValues().forEach(v -> {
+                            long count = 0;
+                            List<Object> list = new ArrayList<>();
+
+                            //两个数据源都为空
+                            boolean isOneFalse = true;
+                            boolean isTwoFalse = true;
+                            if (collect1 != null) {
+                                //根据坐标获取数据
+                                List<ElementData> elementData = collect1.get("x".equals(arg) ? v.getX() : v.getY());
+                                if(CollectionUtil.isNotEmpty(elementData)){
+
+                                    List<ElementData> collect = elementData.stream().filter(e -> StringUtils.isNotEmpty(e.getValue())).collect(Collectors.toList());
+                                    //如果全部参数不为空,统计值
+                                    if(CollectionUtil.isNotEmpty(collect)){
+                                        if(type){
+                                            count += collect.stream().filter(e -> evaluateCondition(e.getValue().toString(), args[2], args[3])).count();
+                                        }else{
+                                            list.addAll(collect.stream().map(ElementData::getValue).filter(value -> evaluateCondition(value.toString(), args[2], args[3])).collect(Collectors.toList()));
+                                        }
+
+                                        isOneFalse = false;
+                                    }
+                                }
+                            }
+                            if (collect2 != null) {
+                                List<ElementData> elementData = collect2.get("x".equals(arg) ? v.getX() : v.getY());
+                                if(CollectionUtil.isNotEmpty(elementData)){
+                                    List<ElementData> collect = elementData.stream().filter(e -> StringUtils.isNotEmpty(e.getValue())).collect(Collectors.toList());
+                                    if(CollectionUtil.isNotEmpty(collect)){
+                                        if(type){
+                                            count += collect.stream().filter(e -> evaluateCondition(e.getValue().toString(), args[2], args[3])).count();
+                                        }else{
+                                            list.addAll(collect.stream().map(ElementData::getValue).filter(value -> evaluateCondition(value.toString(), args[2], args[3])).collect(Collectors.toList()));
+                                        }
+                                        isTwoFalse = false;
+                                    }
+
+                                }
+                            }
+                            //如果两个组数据都是空的 那么值也设置为空
+                            if(isOneFalse && isTwoFalse){
+                                data.add("");
+                            }else{
+                                if(type){
+                                    data.add(count);
+                                }else{
+                                    data.add(StringUtil.join(list, "、"));
+                                }
+                            }
+                        });
+                        f = f.replace(el, putDataWithKey(data, tec));
+                    }
+
+                }
+            }
             formula.setFormula(f);
             if (f.contains("quantity")) {
                 quantity(formula, fd, f, tec);
@@ -7401,5 +7504,32 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
         }
         return wbsTreeContract;
     }
-    
+
+    public boolean evaluateCondition(String value1, String operator, String value2) {
+        try {
+            // 尝试将字符串转换为数字(支持整数和浮点数)
+            double num1 = Double.parseDouble(value1);
+            double num2 = Double.parseDouble(value2);
+
+            switch (operator) {
+                case "=":
+                case "==":
+                    return num1 == num2;
+                case ">":
+                    return num1 > num2;
+                case "<":
+                    return num1 < num2;
+                case ">=":
+                    return num1 >= num2;
+                case "<=":
+                    return num1 <= num2;
+                case "!=":
+                    return num1 != num2;
+                default:
+                    throw new IllegalArgumentException("无效的运算符: " + operator);
+            }
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException("数值格式错误: " + value1 + " 或 " + value2);
+        }
+    }
 }