소스 검색

Merge branch 'master' of http://121.41.40.202:3000/zhuwei/bladex

huangtf 1 년 전
부모
커밋
05491ea82e

+ 11 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/dto/FormData.java

@@ -254,5 +254,16 @@ public class FormData {
         }
     }
 
+    public boolean hasChange(){
+        if(this.values.size()!=this.initial.size()){
+            return true;
+        }else if(this.values.size()>0){
+            String sa= this.values.stream().map(ElementData::stringValue).collect(Collectors.joining());
+            String sc=this.initial.stream().map(ElementData::stringValue).collect(Collectors.joining());
+            return sa.equals(sc);
+        }
+        return false;
+    }
+
 
 }

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

@@ -563,6 +563,7 @@ public class CustomFunction {
         return "";
     }
 
+
     /**
      * @return java.lang.Object
      * @Description 主要工序质量等级
@@ -1216,8 +1217,8 @@ public class CustomFunction {
                         pass.addAndGet(StringUtils.handleObj2Integer(obs[1]));
                     }
                 }else{
-                    data.stream().map(d -> Arrays.stream(designArr).filter(StringUtils::isNotEmpty).map(e -> CustomFunction.dXd(e, d,1,3)).reduce(Double.MAX_VALUE, (p, n) -> offRangeSum(p) < offRangeSum(n) ? p : n)).collect(Collectors.toCollection((Supplier<ArrayList<Object>>) ArrayList::new));
                     List<Object> designList=Arrays.asList(designArr);
+                    /*依次计算偏差挑选最佳设计值,并根据设计值分组,然后在计算是否合格*/
                     Function<Object,Object> fc=d-> designList.stream().reduce(Double.MAX_VALUE, (p, n) -> offRangeSum(CustomFunction.dXd(p, d,1,3)) < offRangeSum(CustomFunction.dXd(n, d,1,3)) ? p : n);
                     Map<Integer,List<Object>> group=data.stream().filter(StringUtils::isNotEmpty).collect(Collectors.groupingBy(x->designList.indexOf(fc.apply(x))));
                     Object finalXN = xN;
@@ -1506,7 +1507,6 @@ public class CustomFunction {
     public static Object tree(List<String> treeNodes, String param) {
         if (CollectionUtil.isNotEmpty(treeNodes) && Func.isNotBlank(param)&&RegexUtil.match(ParamElements.LEVEL_REG, param.trim())) {
             List<String> nodes = new ArrayList<>(treeNodes);
-            //Collections.reverse(nodes);
             List<String> result = new ArrayList<>();
             param = param.trim().replaceAll("(?i:c)", "");
             List<String> list = Arrays.asList(param.split("[^.\\d]"));

+ 19 - 6
blade-service/blade-manager/src/main/java/com/mixsmart/utils/FormulaUtils.java

@@ -446,16 +446,22 @@ public class FormulaUtils {
     }
 
     public static Map<String, String> getElementCell(String uri){
-        return getElementCell(uri,null);
+        return getElementCell(uri,null,null);
     }
     public static Map<String, String> getElementCell(String uri,String key) {
+           return getElementCell(uri,key,null);
+    }
+    public static Map<String, String> getElementCell(String uri,String key,Document document) {
         try {
-            InputStream inputStreamByUrl = FileUtils.getInputStreamByUrl(uri);
+
             String filter=" [keyname]";
             if(Func.isNotBlank(key)){
                 filter="[keyname^="+key+"__]";
             }
-            Document document=Jsoup.parse(IoUtil.readToString(inputStreamByUrl));
+            if(document==null){
+                InputStream inputStreamByUrl = FileUtils.getInputStreamByUrl(uri);
+                document=Jsoup.parse(IoUtil.readToString(inputStreamByUrl));
+            }
             Map<String,String> result= document
                     .select("table").first()
                     .select(filter).stream()
@@ -775,7 +781,6 @@ public static List<FormData>  registerFd(List<String> curTableNames, List<FormDa
     /**
      * @Description  调训符合条件的元素
      * @Param [initiator 初始集合, other 待选集合, curFormDatas 结果集, function:挑选方法]
-     * @return void
      * @Author yangyj
      * @Date 2023.10.12 14:53
      **/
@@ -797,13 +802,21 @@ public static void pick(List<FormData> initiator,List<FormData> other,List<FormD
 }
 
 
-/**最小加载页面*/
+/**最小加载页面,只要包含当前提交元素的页面都需要加载*/
 public static Map<String,List<Long>> relatedPages(List<FormData> curFormDatas ,List<NodeTable> tableAll){
    Set<String> initTableNames= curFormDatas.stream().map(FormData::getTableName).collect(Collectors.toSet());
    return tableAll.stream().filter(e->initTableNames.contains(e.getInitTableName())).collect(Collectors.groupingBy(NodeTable::getInitTableName,Collectors.mapping(NodeTable::getPKeyId,Collectors.toList())));
 }
 
-
+/*比较两组单元格内容是否一样*/
+  public static boolean compareElementDataList(List<ElementData> before ,List<ElementData> cur){
+       if(Func.isNotEmpty(before)&&Func.isNotEmpty(cur)&&before.size()==cur.size()){
+           String sa= before.stream().map(ElementData::stringValue).collect(Collectors.joining());
+           String sc= cur.stream().map(ElementData::stringValue).collect(Collectors.joining());
+           return sa.equals(sc);
+       }
+       return false;
+  }
 
 
 

+ 1 - 1
blade-service/blade-manager/src/main/java/org/springblade/manager/bean/TableInfo.java

@@ -8,7 +8,7 @@ import java.util.List;
 /**
  * @author yangyj
  * @Date 2022/8/22 17:12
- * @description TODO
+ * @description 表单页对象
  */
 @Data
 public class TableInfo {

+ 1 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/formula/impl/FormulaTurnPoint.java

@@ -172,6 +172,7 @@ public class FormulaTurnPoint implements FormulaStrategy {
             List<NodeTable> list = tec.getTableByName(cur.getTableName());
             if(list.size()>pageSize){
                 List<NodeTable> removeList = list.stream().skip(pageSize).collect(Collectors.toList());
+                //TODO 删除因为转点数量变化而导致的空白页
             }
             ai.set(0);
             dataSourceMap.forEach((k, v) -> {

+ 59 - 164
blade-service/blade-manager/src/main/java/org/springblade/manager/formula/impl/TableElementConverter.java

@@ -60,12 +60,16 @@ public class TableElementConverter implements ITableElementConverter {
 
     /**当前工序所有元素信息*/
     public Map<String, FormData> formDataNodeMap = new HashMap<>();
+    /**根据表名分类存放当前工序所有元素*/
+    public Map<String,List<FormData>> tableNameFormDataMap=new HashMap<>();
     /**
      * {tableName:{key:val}}
      */
     Map<String, Map<String, String>> coordinateMap = new HashMap<>();
     /**业务表所包含的所有页面,根据表名查询*/
     Map<String,List<Long>> tableNamePkeyIdMap;
+    /**pkeyId对应的表名称*/
+    Map<Long,String> pkeyIdTableNameMap;
     /**表单对应的Excel对象*/
     public Map<String, Workbook> wkbMap = new HashMap<>();
     /**
@@ -99,8 +103,8 @@ public class TableElementConverter implements ITableElementConverter {
     public List<FormData> summary = new ArrayList<>();
 
     /**根据表名获取对应表页对象*/
-    public List<NodeTable> getTableByName(String initTableName){
-       List<NodeTable> list = new ArrayList<>();
+    public LinkedList<NodeTable> getTableByName(String initTableName){
+        LinkedList<NodeTable> list = new LinkedList<>();
        for(NodeTable nt: this.tableAll){
            if(nt.getInitTableName().equals(initTableName)){
                list.add(nt);
@@ -116,6 +120,7 @@ public class TableElementConverter implements ITableElementConverter {
             fd.setIsCurrentNodeElement(true);
             formDataNodeMap.put(fd.getCode(),fd);
         }
+        this.tableNameFormDataMap=processFds.stream().collect(Collectors.groupingBy(FormData::getTableName));
         this.tableInfoList=tableInfoList;
         this.formDataList=curFormDatas;
         for(FormData fd:curFormDatas){
@@ -129,6 +134,7 @@ public class TableElementConverter implements ITableElementConverter {
         this.wbsTreeId = wtc.getId();
         this.currentNode = wtc;
         this.tableAll = tableAll;
+        this.pkeyIdTableNameMap=tableAll.stream().collect(Collectors.toMap(NodeTable::getPKeyId,NodeTable::getInitTableName));
     }
     /*优化测试新增属性end*/
 
@@ -224,11 +230,31 @@ public class TableElementConverter implements ITableElementConverter {
         }
     }
     public void before2(){
+           /*表单数据集合{table{pkeyId{k:v...}}}*/
+           Map<String,Map<String,Object>> formMap= new HashMap<>(30);
+            for(TableInfo info:this.tableInfoList){
+                Long pkeyId=Long.parseLong(info.getPkeyId());
+                String tbn=this.pkeyIdTableNameMap.get(pkeyId);
+                List<Long> plist=this.tableNamePkeyIdMap.get(tbn);
+                int index=plist.indexOf(pkeyId);
+                LinkedHashMap<String, String> pageData = info.getDataMap();
+                Map<String,Object> tmpMap =formMap.computeIfAbsent(tbn,k->new HashMap<>(100));
+                pageData.forEach((k,v)->{
+                    if (StringUtils.isNotEmpty(v)) {
+                        String[] values = v.split("☆");
+                        for (String s : values) {
+                            String[] t = s.split("_\\^_");
+                            String[] c = t[1].split("_");
+                            tmpMap.put(StringUtils.join( index,Func.toInt(c[1]), Func.toInt(c[0]), StringPool.AT), t[0].trim());
+                        }
+                    }
+                });
+            }
            for(FormData fd:this.formDataList){
-               /*根据单元格信息、表单页对象、单元格原始数据 初始化袁术数据*/
+               /*根据单元格信息、表单页对象、单元格原始数据 初始化元素数据*/
                try {
                    fd.setIsCurrentNodeElement(Boolean.TRUE);
-                   String coords =this.coordinateMap.getOrDefault(fd.getTableName(), new HashMap<>()).get(fd.getKey());
+                   String coords =this.coordinateMap.getOrDefault(fd.getTableName(), new HashMap<>(20)).get(fd.getKey());
                    if(Func.isNotBlank(coords)){
                        fd.flushCoords(coords);
                    }else{
@@ -239,10 +265,21 @@ public class TableElementConverter implements ITableElementConverter {
                    List<Coords> coordsList= fd.getCoordsList();
                    List<ElementData> eds =fd.getValues();
                    Map<String,Object> map = fd.getCellDataVoList().stream().collect(Collectors.toMap(e-> StringUtils.join( pkeyIds.indexOf(e.getPageId()), e.getX(), e.getY(), StringPool.AT), CellDataVo::getValue));
-                   for(int i=0;i<pkeyIds.size();i++){
-                       for(Coords c:coordsList){
-                           String k=StringUtils.join( i, c.getX(), c.getY(), StringPool.AT);
-                           eds.add(new ElementData(i,0,map.get(k),c.getX(),c.getY()));
+                   if(fd.getIsCurrentSubmitElement()){
+                      Map<String,Object> formTableMap =formMap.get(fd.getTableName());
+                       for(int i=0;i<pkeyIds.size();i++){
+                           for(Coords c:coordsList){
+                               String k=StringUtils.join( i, c.getX(), c.getY(), StringPool.AT);
+                               /*优先写人表单数据*/
+                               eds.add(new ElementData(i,0,formTableMap.getOrDefault(k,map.get(k)),c.getX(),c.getY()));
+                           }
+                       }
+                   }else{
+                       for(int i=0;i<pkeyIds.size();i++){
+                           for(Coords c:coordsList){
+                               String k=StringUtils.join( i, c.getX(), c.getY(), StringPool.AT);
+                               eds.add(new ElementData(i,0,map.get(k),c.getX(),c.getY()));
+                           }
                        }
                    }
                    /*数据初始化加载*/
@@ -294,165 +331,23 @@ public class TableElementConverter implements ITableElementConverter {
 
     }
     public void after2(){
-        List<FormData> updateList = this.formDataMap.values().stream().filter(e -> e.getUpdate() == 1 && e.isCurrentNodeElement).collect(Collectors.toList());
-        if(!updateList.isEmpty()){
-             List<Long> pkeyIds= this.tableNamePkeyIdMap.values().stream().flatMap(Collection::stream).collect(Collectors.toList());
-             Map<String,List<FormData>> group = updateList.stream().collect(Collectors.groupingBy(FormData::getTableName,Collectors.toList()));
-             Map<String,TableInfo> tableInfoMap= this.tableInfoList.stream().collect(Collectors.toMap(TableInfo::getPkeyId,t->t));
-            TableInfo one = this.tableInfoList.get(0);
-             for(Long pi:pkeyIds){
-                 if(!tableInfoMap.containsKey(pi.toString())){
-                     TableInfo info=new TableInfo();
-                     BeanUtils.copyProperties(one,info);
-                     info.setPkeyId(pi.toString());
-                     info.setDataMap(new LinkedHashMap<>());
-                     tableInfoMap.put(pi.toString(),info);
-                 }
-             }
-             group.forEach((k,v)->{
-                   /*k:表名,v:表单页集合*/
-                 for(FormData fd:v){
-                     /*LinkedHashMap<Integer, List<ElementData>> pages = fd.getValues().stream().collect(Collectors.groupingBy(ElementData::getIndex, LinkedHashMap::new, Collectors.toList()));*/
-                     List<List<ElementData>> pages= BaseUtils.splitList( fd.getValues(),fd.getCoordsList().size());
-                     List<Long> ids = this.tableNamePkeyIdMap.get(k);
-                     for(int i=0;i<ids.size();i++){
-                         Long id=ids.get(i);
-                         TableInfo info = tableInfoMap.get(id.toString());
-                         List<ElementData> p = pages.get(i);
-                         info.setToBeUpdated(true);
-                         info.getDataMap().put(fd.getKey(), recovery(p));
-                     }
-                 }
-
-             });
-        }else {
-            log.put(FormulaLog.OTHER,"公式未插入或者修改任何数据");
-        }
+           /*判断需要更新的元素*/
+          List<FormData> updateList =  this.formDataMap.values().stream().filter(e->e.getIsCurrentSubmitElement()&&e.getUpdate()==1&&e.hasChange()).collect(Collectors.toList());
+          List<TableInfo> tableInfoList = this.tableInfoList;
+          Set<String> tableNameSet= updateList.stream().map(FormData::getTableName).collect(Collectors.toSet());
+          List<Long> pkeyIds = new ArrayList<>();
+          for(String tk:tableNameSet){
+              List<Long> tmp = this.tableNamePkeyIdMap.get(tk);
+              if(tmp!=null){
+                  pkeyIds.addAll(tmp);
+              }
+          }
+        /*判断需要更新的tableInfo*/
+         tableInfoList.removeIf(t->!pkeyIds.contains(Long.parseLong(t.getPkeyId())));
+        /*筛查需要更新的元素数据*/
     }
-    /**
-     * 备份
-     */
-/*
-    public void afterBak() {
-        */
-/*可以优化对每一张表进行元素分类,同一张元素*//*
-
-        */
-/*根据数据库表分组*//*
-
-        LinkedHashMap<String, List<KeyMapper>> tabs = keyMappers.stream().collect(Collectors.groupingBy(KeyMapper::getCode, LinkedHashMap::new, Collectors.toList()));
-        Map<String, List<TableInfo>> tableMap = new HashMap<>(tabs.size() * 2);
-        for (FormData fd : this.formDataList) {
-            if (fd.getUpdate().equals(0)) {
-                continue;
-            }
-            */
-/*暂时不处理没有公式配置的数据*//*
-
-            */
-/*元素所有的数据内容*//*
 
-            List<ElementData> values = fd.getValues();
-            List<TableInfo> tables;
-            LinkedHashMap<Integer, LinkedHashMap<Integer, List<ElementData>>> groups = values.stream().collect(Collectors.groupingBy(ElementData::getGroupId, LinkedHashMap<Integer, LinkedHashMap<Integer, List<ElementData>>>::new, Collectors.groupingBy(ElementData::getIndex, LinkedHashMap<Integer, List<ElementData>>::new, Collectors.toList())));
-            */
-/*每个元素数据有N组组成,每组由N页组成*//*
 
-            if (tableMap.containsKey(fd.getTableName())) {
-                tables = tableMap.get(fd.getTableName());
-            } else {
-                List<Long> tableIds = keyMappers.stream().filter(e -> StringUtils.isEquals(e.getCode(), fd.getCode())).map(KeyMapper::getPkId).collect(Collectors.toList());
-                tables = this.tableInfoList.stream().filter(e -> tableIds.contains(Long.parseLong(e.getPkeyId()))).collect(Collectors.toList());
-                tableMap.put(fd.getTableName(), tables);
-            }
-            groups.forEach((groupId, group) -> {
-                group.forEach((index, page) -> {
-                    if (Func.isNotEmpty(page)) {
-                        TableInfo info = tables.get(index);
-                        */
-/*每一页对应一个info*//*
-
-                        info.getDataMap().put(fd.getKey(), recovery(page, fd));
-                    }
-                });
-            });
-
-        }
-
-    }
-*/
-
-    /**
-     * 格式化回写内容
-     */
-/*    public String recovery(List<ElementData> dataList, String position, String z) {
-        List<Coords> coordsList = CoordsBuilder.getInstance().build(position);
-        StringBuilder sb = new StringBuilder();
-        List<Integer[]> total = new ArrayList<>();
-        int n = 0;
-        for (Coords coords : coordsList) {
-            int outer, outer2, inner, inner2;
-            if (coords.getHorizontal()) {
-                outer = coords.getY();
-                outer2 = coords.getY2();
-                inner = coords.getX();
-                inner2 = coords.getX2();
-            } else {
-                outer = coords.getX();
-                outer2 = coords.getX2();
-                inner = coords.getY();
-                inner2 = coords.getY2();
-            }
-            List<Integer[]> indexs = new ArrayList<>();
-            for (int i = outer; i < outer2; i++) {
-                for (int j = inner; j < inner2; j++) {
-                    if (coords.getHorizontal()) {
-                        *//*[x,y]*//*
-                        indexs.add(new Integer[]{j, i});
-                    } else {
-                        indexs.add(new Integer[]{i, j});
-                    }
-                }
-            }
-            if (coords.hasMerge()) {
-                indexs = indexs.stream().filter(e -> !coords.getEx().contains(e[0]) && !coords.getEy().contains(e[1])).collect(Collectors.toList());
-            }
-            total.addAll(indexs);
-        }
-        for (int i = 0; i < dataList.size(); i++) {
-            if (i >= total.size()) {
-                break;
-            }
-            ElementData d = dataList.get(i);
-            Integer[] a = total.get(i);
-            *//*a:[x,y]*//*
-            sb.append(a[1]).append(StringPool.UNDERSCORE).append(a[0]).append(StringPool.UNDERSCORE).append(d.stringValue());
-        }
-        return sb.toString();
-    }*/
-
-
-   /* public String recovery(List<ElementData> dataList, FormData fd) {
-        String coords = this.coordinateMap.get(fd.getTableName()).get(fd.getKey());
-        StringBuilder sb = new StringBuilder();
-        if (Func.isNotEmpty(coords)) {
-            List<Coords> list = Stream.of(coords).flatMap(e -> Arrays.stream(e.split(";"))).map(e -> {
-                String[] xy = e.split("_");
-                return new Coords(xy[1], xy[0]);
-            }).collect(Collectors.toList());
-            for (int i = 0; i < dataList.size(); i++) {
-                ElementData ed = dataList.get(i);
-                if (list.size() > i && Func.isNotEmpty(ed.getValue())) {
-                    Coords c = list.get(i);
-                    sb.append(ed.stringValue()).append("_^_").append(c.getY()).append("_").append(c.getX()).append("☆");
-                }
-            }
-            if (sb.length() > 5) {
-                sb.deleteCharAt(sb.length() - 1);
-            }
-        }
-        return sb.toString();
-    }*/
 
     public String recovery(List<ElementData> dataList) {
         if (Func.isNotEmpty(dataList)) {

+ 6 - 1
blade-service/blade-manager/src/main/java/org/springblade/manager/service/IFormulaService.java

@@ -1,9 +1,11 @@
 package org.springblade.manager.service;
 
+import org.jsoup.nodes.Document;
 import org.springblade.core.mp.base.BaseService;
 import org.springblade.manager.dto.FormData;
 import org.springblade.manager.entity.Formula;
 import org.springblade.manager.entity.WbsInfo;
+import org.springblade.manager.entity.WbsTreeContract;
 import org.springblade.manager.entity.WbsTreePrivate;
 import org.springblade.manager.enums.ExecuteType;
 import org.springblade.manager.formula.KeyMapper;
@@ -101,9 +103,12 @@ public interface IFormulaService extends BaseService<Formula> {
     WbsTreePrivate getOriginWtp(Long pkeyId);
 
     <T> T getSqlOne(@NotNull  String sql,@NotNull Class<T> clazz , Object ...args);
-    <T> List<T> getSqlList(@NotNull String sql, @NotNull Class<T> clazz,Object... args);
 
+    <T> List<T> getSqlList(@NotNull String sql, @NotNull Class<T> clazz,Object... args);
+    /**加载元素数据*/
     void loadElementData(List<FormData> curFormDatas,Map<String,List<Long>>  tableNamePkeyIdMap);
+    /**表单数据加载的时候执行节点参数*/
+    void paramFormula(WbsTreeContract wbsTreeContract, Map<String, Object> result, Document document);
 
 
 }

+ 13 - 4
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ExcelTabServiceImpl.java

@@ -402,7 +402,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
             Long nodeId = tableInfo.getLong("nodeId");
             List<TableInfo> tableInfoList = this.getTableInfoList(dataArray);
             List<NodeTable> tableAll = createNodeTables(nodeId, tableInfoList.get(0).getContractId(), tableInfoList.get(0).getProjectId(), type);
-            String tableNames = tableAll.stream().map(NodeTable::getInitTableName).distinct().collect(Collectors.joining("','", "'", "'"));
+            String tableNames = tableAll.stream().map(NodeTable::getInitTableName).distinct().collect(Collectors.joining("','"));
             /*当前工序包含的所有元素信息,还未包含数据*/
             List<FormData> processFds = this.formulaService.createFormDataByTableName(tableNames);
             List<Long> pkeyIds = tableInfoList.stream().map(TableInfo::getPkeyId).map(Long::parseLong).collect(Collectors.toList());
@@ -1229,7 +1229,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
 
     @Override
     public R getBussDataInfo(Long pkeyId, int type) {
-
+        Document document=null;
         Map<String, Object> reData = new HashMap<>();
 
         WbsTreeContract wbsTreeContract = wbsTreeContractService.getBaseMapper().selectOne(Wrappers.<WbsTreeContract>query().lambda()
@@ -1259,6 +1259,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
 
             String htmlString = IoUtil.readToString(inputStreamByUrl);
             Document doc = Jsoup.parse(htmlString);
+            document=doc;
 
             // 解析
             // 模糊匹配
@@ -1474,6 +1475,8 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
             reData.put("pkeyId", reData.get("p_key_id"));
         }
         reData.put("tabGroupId", wbsTreeContract.getTabGroupId());
+        /*表单公式*/
+        this.formulaService.paramFormula(wbsTreeContract,reData,document);
         return R.data(reData);
     }
 
@@ -1593,9 +1596,15 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
             Element table = doc.select("table").first();
             //计算填报率
             Long keySize = table.getElementsByAttribute("v-model").stream().count();
+            Long sigSize = table.getElementsByAttribute(":readonly").stream().count();
             if (fillNumbers != 0 && keySize != 0){
-                Double v = fillNumbers.doubleValue() / keySize.doubleValue() * 100;
-                realFillRate = v.intValue();
+                if (keySize == sigSize){
+                    realFillRate = 100;
+                }else {
+                    keySize = keySize - sigSize;
+                    Double v = fillNumbers.doubleValue() / keySize.doubleValue() * 100;
+                    realFillRate = v.intValue();
+                }
             }
             Elements trs = table.select("tr");
             if (ObjectUtil.isNotEmpty(DataInfo)) {

+ 337 - 139
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/FormulaServiceImpl.java

@@ -3,6 +3,7 @@ package org.springblade.manager.service.impl;
 
 import cn.hutool.core.date.DatePattern;
 import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.StopWatch;
 import cn.hutool.core.util.HashUtil;
 import cn.hutool.log.StaticLog;
 import com.alibaba.fastjson.JSON;
@@ -12,6 +13,7 @@ import com.jfireel.expression.Expression;
 import com.mixsmart.utils.*;
 import lombok.RequiredArgsConstructor;
 import org.apache.poi.ss.usermodel.*;
+import org.jsoup.nodes.Document;
 import org.springblade.common.utils.BaseUtils;
 import org.springblade.common.utils.CommonUtil;
 import org.springblade.common.utils.SnowFlakeUtil;
@@ -33,7 +35,6 @@ import org.springblade.manager.vo.AppWbsTreeContractVO;
 import org.springblade.manager.vo.CurrentNode;
 import org.springframework.context.annotation.Scope;
 import org.springframework.context.annotation.ScopedProxyMode;
-import org.springframework.http.converter.json.MappingJacksonValue;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.stereotype.Service;
 import org.springframework.web.context.WebApplicationContext;
@@ -77,12 +78,12 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
     public static final Pattern AP=Pattern.compile("(E|WP)\\[([^]']+)]");
     public static final String IF_REG= "(?<=T\\(com.mixsmart.utils.CustomFunction\\).ifelse\\()[^,]+(?=,)";
     public static final String FC_REG="T\\(com.mixsmart.utils.CustomFunction\\)\\.";
-    public static final Pattern IF = Pattern.compile(IF_REG);
+    /*public static final Pattern IF = Pattern.compile(IF_REG);*/
     public static final String ELE_CODE_REG= "(?<=E\\[)[^]]+(?=])";
     public static final Pattern P = Pattern.compile(ELE_CODE_REG);
-    public static final Pattern P2= Pattern.compile("(?<=E\\[)[^];]+:[^];]+:[^];]+(?=])");
+    /*public static final Pattern P2= Pattern.compile("(?<=E\\[)[^];]+:[^];]+:[^];]+(?=])");*/
     public final static String CTI="ContractInfo";
-    public final static String PJI="ProjectInfo";
+    /*public final static String PJI="ProjectInfo";*/
     /**元素标识*/
     public final static String E="E";
     /**公式参数*/
@@ -91,7 +92,8 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
     /**是否使用新流程*/
     public final static  boolean isNew=false;
 
-
+    /**是否使用表单公式*/
+    public final static  boolean isForm=true;
 
 
 
@@ -754,17 +756,23 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
         try {
             Map<Boolean, List<FormData>> map = tec.formDataList.stream().collect(Collectors.partitioningBy(e -> Func.isNotEmpty(e.getFormula()) && e.getFormula().getFormula().contains("E[")));
             tec.formDataList.clear();
-            /*没有依赖的*/
-            List<FormData> simple = map.get(false);
-            if (CollectionUtil.isNotEmpty(simple)) {
-                tec.formDataList.addAll(simple);
-            }
             /*有依赖的*/
             List<FormData> rely = map.get(true);
             if (CollectionUtil.isNotEmpty(rely)) {
                 sort(rely, ((rely.size() + 1) / 2) * rely.size());
                 tec.formDataList.addAll(rely);
             }
+            /*没有依赖的*/
+            List<FormData> simple = map.get(false);
+            if (CollectionUtil.isNotEmpty(simple)) {
+                for(FormData fd:simple){
+                    if(fd.getCoordsList().size()==1&&fd.executable()&&fd.getFormula().getFormula().contains(WP)&&!fd.empty()){
+                        fd.setFinished(true);
+                        fd.setUpdate(1);
+                    }
+                }
+                tec.formDataList.addAll(simple);
+            }
             /*初始化排序值,每个点间隔1000,方便插入*/
             AtomicInteger sort = new AtomicInteger();
             tec.formDataList.forEach(e -> e.setSort(sort.getAndAdd(1000)));
@@ -887,10 +895,15 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
         /*通用计算*/
         generalCalc();
         if(ExecuteType.INSPECTION.equals(tec.getExecuteType())) {
-            /*汇总信息处理*/
-             summaryCalc();
-            /*附表的处理*/
-            forSubTb();
+            if(isNew){
+                //TODO
+            }else{
+                /*汇总信息处理*/
+                summaryCalc();
+                /*附表的处理*/
+                forSubTb();
+            }
+
         }
         return this;
     }
@@ -1079,85 +1092,11 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                 List<NodeTable> subTabList = this.tec.getTableAll().stream().filter(e -> e.getNodeName().contains("附表")).collect(Collectors.toList());
                 if (subTabList.size() == 0) {
                     linkSub(subTabList);
-                  /*  boolean pd=tec.getTableAll().stream().anyMatch(e->e.getTableType().equals(5));
-                    WbsTreePrivate sub = wbsTreePrivateService.getOne(Wrappers.<WbsTreePrivate>lambdaQuery().and(e->e.eq(WbsTreePrivate::getNodeName, pd?"质量检验评定表(附表)":"质量检验表(附表)").or().eq(WbsTreePrivate::getFullName, pd?"质量检验评定表(附表)":"质量检验表(附表)")).eq(WbsTreePrivate::getProjectId, tec.getProjectId()).eq(WbsTreePrivate::getIsLinkTable,2));
-                    if (sub == null) {
-                        this.tec.getLog().put(FormulaLog.SUB_TAB,"该项目没有挂有附表信息");
-                    } else {
-                        this.wbsTreePrivateService.addWbsTreeContractInfo(this.tec.getCurrentNode().getPkId().toString(), sub.getPKeyId().toString(), tec.getContractId());
-                        NodeTable one = this.tec.getTableAll().get(0);
-                        WbsTreeContract wtc = this.wbsTreeContractService.getOne(Wrappers.<WbsTreeContract>lambdaQuery().eq(WbsTreeContract::getParentId, one.getParentId()).eq(WbsTreeContract::getContractId,tec.getContractId()).eq(WbsTreeContract::getWbsId, one.getWbsId()).and(e->e.eq(WbsTreeContract::getNodeName, pd?"质量检验评定表(附表)":"质量检验表(附表)").or().eq(WbsTreeContract::getFullName, pd?"质量检验评定表(附表)":"质量检验表(附表)")));
-                        if (wtc != null) {
-                            *//*附表的顺序在检验单或者评定表之后,默认最后*//*
-                            int sort=this.tec.getTableAll().stream().filter(e ->e.getTableType().equals(1) || e.getTableType().equals(5)).map(NodeTable::getSort).max(Integer::compareTo).orElse(1000);
-                            this.wbsTreeContractService.update(Wrappers.<WbsTreeContract>lambdaUpdate()
-                                    .set(WbsTreeContract::getSort,sort).set(WbsTreeContract::getContractType,-1).set(WbsTreeContract::getAncestors,one.getAncestors())
-                                    .set(WbsTreeContract::getIsCopeTab,2)
-                                    .eq(WbsTreeContract::getPKeyId,wtc.getPKeyId()));
-                            *//*只需要挂载一张*//*
-                            NodeTable obj = BeanUtil.copy(wtc, NodeTable.class);
-                            tec.getTableAll().add(obj);
-                            subTabList.add(obj);
-                        }
-                    }*/
                 }
                 NodeTable first = subTabList.get(0);
                 if (tec.getTableInfoList().stream().noneMatch(e -> StringUtils.isEquals(e.getPkeyId(), first.getPKeyId()))) {
                     /*找不到附表表单数据,则从数据库加载*/
                     loadSubData(subTabList,first);
-                   /* JSONArray dataArray = new JSONArray();
-                    for (NodeTable data : subTabList) {
-                        *//*自动挂载附表情况下,装配TableInfo数据*//*
-                        R bussDataInfo = this.excelTabService.getBussDataInfo(data.getPKeyId(), 1);
-                        @SuppressWarnings("unchecked")
-                        Map<String, Object>  data1 = (Map<String, Object>) bussDataInfo.getData();
-                        data1.put("pkeyId",data.getPKeyId());
-                        dataArray.add(data1);
-                    }
-                    List<TableInfo> subTableInfo = this.excelTabService.getTableInfoList(dataArray);
-                    TableInfo example = tec.getTableInfoList().get(0);
-                    subTableInfo.forEach(e -> {
-                        e.setToBeUpdated(true);
-                        e.setBusinessId(null);
-                        e.setContractId(example.getContractId());
-                        e.setClassify(example.getClassify());
-                        e.setProjectId(example.getProjectId());
-                        e.setGroupId(example.getGroupId());
-                    });
-                    tec.getTableInfoList().addAll(subTableInfo);
-                    *//*获取附表元素定位集*//*
-                    *//*tec.getCoordinateMap().put(subTabList.get(0).getInitTableName(), FormulaUtils.getElementCell(first.getHtmlUrl()));*//*
-                    tec.getCoordinateMap().computeIfAbsent(subTabList.get(0).getInitTableName(),k->FormulaUtils.getElementCell(first.getHtmlUrl()));
-                    *//*附表元素关键信息*//*
-                    List<Map<String, Object>> elementMaps = this.jdbcTemplate.queryForList("select b.e_name ename , CONCAT(a.tab_en_name,':',b.e_key) code , b.e_key ekey ,b.id fieldId,a.tab_en_name tableName from m_table_info a join m_wbs_form_element b on a.id = b.f_id where a.tab_en_name='" + first.getInitTableName() + "' and b.is_deleted=0 ");
-                    if (Func.isNotEmpty(elementMaps)) {
-                        elementMaps.forEach(e->{
-                            *//*装配元素*//*
-                            String values=subTableInfo.stream().map(TableInfo::getDataMap).map(m->m.get(StringUtils.handleNull(e.get("ekey")))).filter(StringUtils::isNotEmpty).collect(Collectors.joining(";;"));
-                            FormData tmp=  createFormDataFast(StringUtils.handleNull(e.get("ename")),StringUtils.handleNull(e.get("code")),values);
-                            if(tmp!=null){
-                                String idStr =StringUtils.handleNull(e.get("fieldId"));
-                                if(Func.isNotEmpty(idStr)) {
-                                    tmp.setId(Func.toLong(idStr));
-                                }
-                                tmp.setIsCurrentNodeElement(true);
-                                tec.formDataMap.put(tmp.getCode(),tmp);
-                                tec.formDataList.add(tmp);
-                            }
-                        });
-                        *//*生成元素映射关系*//*
-                        subTabList.forEach(s->{
-                            elementMaps.forEach(e->{
-                                KeyMapper km = new KeyMapper();
-                                km.setPkId(s.getPKeyId());
-                                km.setField(StringUtils.handleNull(e.get("ekey")));
-                                km.setFieldId(Func.toLong(e.get("fieldId")));
-                                km.setTableName(StringUtils.handleNull(e.get("tableName")));
-                                this.tec.getKeyMappers().add(km);
-                            });
-                        });
-
-                    }*/
                 }
                 /*获取封装好的附表元素*/
                 List<FormData> subTableFds=tec.formDataMap.values().stream().filter(e->StringUtils.isEquals(first.getInitTableName(),e.getTableName())).collect(Collectors.toList());
@@ -1186,21 +1125,6 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                 }
                 /*把主表的表头表尾信息拷贝*/
                 headerFooterSub(subTableFds);
-               /* String mainTableName = tec.getTableAll().stream().filter(e -> e.getTableType().equals(1) || e.getTableType().equals(5)).map(NodeTable::getInitTableName).findFirst().orElse("");
-                if(Func.isNotBlank(mainTableName)){
-                    List<FormData> sourceFds=tec.getFormDataMap().values().stream().filter(s->!s.empty()).filter(s->StringUtils.isEquals(s.getTableName(),mainTableName)).collect(Collectors.toList());
-                    Map<String,Object> copyMap= new HashMap<>();
-                    if(sourceFds.size()>0){
-                        sourceFds.forEach(d->{
-                            copyMap.put(d.getSimplifyName(),d.getValues().stream().map(ElementData::getValue).filter(StringUtils::isNotEmpty).findAny().orElse(""));
-                        });
-                    }
-                    subTableFds.stream().filter(s-> !SubTable.KEYS.contains(s.getEName().trim())).filter(s->copyMap.containsKey(s.getSimplifyName())).forEach(t->{
-                         Object val = copyMap.get(t.getSimplifyName());
-                         t.getValues().forEach(e->e.setValue(val));
-                         t.setUpdate(1);
-                    });
-                }*/
             }
 
         } catch (Exception e) {
@@ -1314,12 +1238,12 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
     public void summaryCalc(){
         try{
             if(tec.summary.size()>0){
-                /**/
+                /*获取有实测值的检查项目*/
                 List<String> result=tec.checkItems.stream().filter(fdTmp->fdTmp.getValues().stream().map(ElementData::getValue).anyMatch(e->StringUtils.isNotEmpty(e)&&StringUtils.isNotEquals("/",e))).map(FormData::getEName).map(FormulaUtils::checkItemName).distinct().collect(Collectors.toList());
                 Optional<FormData> opk= tec.summary.stream().filter(FormData::executable).filter(f->StringUtils.isEquals(f.getFormula().getNumber(),CHECK_ITEMS)).findAny();
                 List<String> history=null;
                 if(opk.isPresent()&&!opk.get().empty()){
-                    /*假如已经存内容,则需要筛选出手填部分*/
+                    /*假如已经存内容,则需要筛选出手填部分*/
                     history=  Arrays.asList(opk.get().getValues().get(0).stringValue().replaceAll("[\\s\\n]+","").split("[,、,]"));
                 }
                 if(history!=null&&history.size()>0){
@@ -1327,7 +1251,9 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                     List<String> customize=history.stream().filter(s->!itemAll.contains(s)).collect(Collectors.toList());
                     result.addAll(customize);
                 }
+                /*检查内容*/
                 tec.constantMap.put(CHECK_ITEMS,result);
+                /*计算检查日期*/
                 tec.constantMap.put("CKD",tec.checkDate.stream().flatMap(k->k.getValues().stream()).map(ElementData::stringValue)
                         .filter(StringUtils::isNotEmpty)
                         .map(FormulaUtils::range2end)
@@ -1341,7 +1267,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                     Object data = Expression.parse(e.getFormula().getFormula()).calculate(tec.constantMap);
                     if(data!=null){
                         e.getFormula().setOutm(1);
-                        FormulaUtils.write(e,data,false);
+                        FormulaUtils.write(e,data);
                         e.setUpdate(1);
                     }
                 });
@@ -1537,15 +1463,61 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
            }
        });
    }
+   public void copy2(FormData fd){
+       /*挑选最长的元素来决定需要增加的页数*/
+        if(fd.getAddPages()>20){
+            /*最大页数20*/
+            return;
+        }
+        int pageAdd=fd.getAddPages();
+        /*增加表单页,删除实测值*/
+       LinkedList<NodeTable> nodeTableList=tec.getTableByName(fd.getTableName());
+       NodeTable source = nodeTableList.getLast();
+       WbsTreeContract  origin =  this.wbsTreeContractService.getOne(Wrappers.<WbsTreeContract>lambdaQuery().eq(WbsTreeContract::getPKeyId,source.getPKeyId()));
+       if(origin!=null){
+           for(int i=0;i<pageAdd;i++){
+               /*复制表*/
+               WbsTreeContract target = new WbsTreeContract();
+               BeanUtil.copy(origin,target);
+               target.setPKeyId(SnowFlakeUtil.getId());
+               target.setCreateTime(new Date());
+               String nodeName = origin.getNodeName();
+               if (nodeName.contains("__")) {
+                   String[] oldName = nodeName.split("__");
+                   nodeName = oldName[0] + "__" + (Integer.parseInt(oldName[1]) + 1);
+               } else {
+                   nodeName = nodeName + "__" + 1;
+               }
+               target.setNodeName(nodeName);
+               target.setIsCopeTab(2);
+               target.setIsTabPdf(1); // pdf 不能预览
+               target.setIsBussShow(1); // 是否隐藏表
+               target.setTabFileType(1);//没有上传附件
+               target.setPdfUrl("");
+               this.wbsTreeContractService.save(target);
+               Long pkeyId=origin.getPKeyId();
+               tec.getTableInfoList().stream().filter(o->StringUtils.isEquals(o.getPkeyId(),pkeyId)).findFirst().ifPresent(tb->{
+                   /*表单数据复制*/
+                   TableInfo tableInfo = new TableInfo();
+                   BeanUtil.copy(tb,tableInfo);
+                   tableInfo.setPkeyId(target.getPKeyId().toString());
+                   tableInfo.setDataMap(new LinkedHashMap<>(tb.getDataMap()));
+                   /*删除所有实测项目*/
+                   List<FormData> fdsOfTable=tec.getTableNameFormDataMap().get(source.getInitTableName());
+                   Set<String> removeKeySet=fdsOfTable.stream().filter(f->!f.empty()&&f.getCoordsList().size()>1).map(FormData::getKey).collect(Collectors.toSet());
+                   for(String rk:removeKeySet){
+                       tableInfo.getDataMap().remove(rk);
+                   }
+                   tableInfo.getDataMap().put("p_key_id",tableInfo.getPkeyId());
+                   tec.getTableInfoList().add(tec.getTableInfoList().indexOf(tb)+1,tableInfo);
+               });
+               origin=target;
+           }
+       }
+       /*复制最后一页只有一个单元格的存在内容的元素*/
+    }
 
 
-/*public  List<ElementData> setScale(Integer scale,List<ElementData> data){
-    if(scale==null){
-        scale=StringUtils.getScale(data.stream().map(ElementData::getValue).filter(StringUtils::isDouble).collect(Collectors.toList()));
-    }
-    Integer finalScale = scale;
-    return data.stream().peek(e->{if(StringUtils.isDouble(e.getValue())){e.setValue(StringUtils.number2StringZero(e.getValue(),finalScale));}}).collect(Collectors.toList());
-}*/
 
     @Override
     public void format() {
@@ -1560,9 +1532,25 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
             }
         }
         /*检查超页情况*/
-        tec.formDataMap.values().stream().filter(e->e.getIsCurrentNodeElement()&&e.getUpdate()==1&&e.getAddPages()>0).sorted(Comparator.comparing(FormData::getAddPages).reversed())
-                        .collect(Collectors.groupingBy(FormData::getTableName,LinkedHashMap::new,Collectors.toList())).values()
-                        .forEach(l->copy(l.get(0)));
+        if(isNew){
+            tec.formDataMap.values().stream().filter(e->e.getIsCurrentSubmitElement()&&e.getUpdate()==1&&e.getAddPages()>0).sorted(Comparator.comparing(FormData::getAddPages).reversed())
+                    .collect(Collectors.groupingBy(FormData::getTableName,LinkedHashMap::new,Collectors.toList())).values()
+                    .forEach(l->copy2(l.get(0)));
+            /*表头表尾数据处理*/
+            tec.formDataMap.values().stream().filter(e->!e.empty()&&e.getIsCurrentSubmitElement()&&e.getUpdate()==1&&e.getCoordsList().size()==1).forEach(e->{
+                 ElementData ed = e.getValues().get(0);
+                 e.getValues().forEach(x->x.setValue(ed.getValue()));
+            });
+
+        }else{
+            tec.formDataMap.values().stream().filter(e->e.getIsCurrentNodeElement()&&e.getUpdate()==1&&e.getAddPages()>0).sorted(Comparator.comparing(FormData::getAddPages).reversed())
+                    .collect(Collectors.groupingBy(FormData::getTableName,LinkedHashMap::new,Collectors.toList())).values()
+                    .forEach(l->copy(l.get(0)));
+        }
+
+
+
+
     }
 
     @Override
@@ -1604,7 +1592,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                 }
             }
         }else if(executeType.equals(ExecuteType.TESTING)){
-
+             //TODO
         }
     }
 
@@ -1987,32 +1975,19 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                  }
                  if(f.contains("quantity")){
                      /*聚合*/
-                     Matcher m = RegexUtils.matcher(FC_REG+"(quantity)\\(([^)]+)\\)",f);
+              /*       Matcher m = RegexUtils.matcher(FC_REG+"(quantity)\\(([^)]+)\\)",f);
                      while (m.find()) {
                          Object data=null;
                          List<String> codeList = FormulaUtils.getCodeList(m.group(2));
-//                         Map<String,List<Map<String,Object>>> textInfoMap= (Map<String, List<Map<String, Object>>>) tec.constantMap.getOrDefault(TEXT_INFO_MAP,new HashMap<>());
-//                         List<Map<String,Object>> tableColKeyVal= textInfoMap.get(codeList.get(0));
-                         /*表名+合同段+父节点*/
-                         String findStr="OP['"+fd.getTableName()+"']['"+fd.getKey()+"']['RG']";
-                          String rangeStr=StringUtils.handleNull(Expression.parse(findStr).calculate(tec.constantMap));
-                         //System.out.println("随机值参数:"+rangeStr);
-                         if(false){
-                          /*   Optional<RangeInfo> op=tableColKeyVal.stream().map(map-> BeanUtil.toBean(JSON.parseObject(map.get("val").toString()),RangeInfo.class)).findFirst();
-                             if(op.isPresent()){
-                                 RangeInfo d = op.get();
-                                 d.build();
-                                 data=  d.getPassList().stream().mapToInt(Func::toInt).sum();
-                             }*/
-                         }else{
+                       {
                              FormData dataFd=tec.formDataMap.get(codeList.get(0));
                              String designStr=codeList.get(1);
                              FormData designFd=tec.formDataMap.get(designStr);
                              String devStr=StringUtils.isNotEmpty(formula.getDev())?formula.getDev():fd.getEAllowDeviation();
                              if(StringUtils.isEmpty(devStr)){
-                                 /*数据库找不到的情况就读取Excel*/
+                                 *//*数据库找不到的情况就读取Excel*//*
                                  if(tec.wkbMap.isEmpty()){
-                                     /*初始化*/
+                                     *//*初始化*//*
                                     List<String> tableNames4Excel=  tec.getFormDataList().stream().filter(FormData::executable).filter(e->e.info().contains("quantity")).map(FormData::getTableName).distinct().collect(Collectors.toList());
                                     if(!tableNames4Excel.isEmpty()){
                                         List<String> ids =tec.getTableAll().stream().filter(e->tableNames4Excel.contains(e.getInitTableName())).map(NodeTable::getPKeyId).map(String::valueOf).collect(Collectors.toList());
@@ -2078,7 +2053,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                                }
                                devStr= Arrays.stream(devStr.replaceAll("^\\[|\\]$","").split(",")).map(s->map.getOrDefault(s,s)).map(StringUtils::handleNull).collect(Collectors.joining(","));
                              }
-                             /*设计值可以是数值类型,或空(等效0)*/
+                             *//*设计值可以是数值类型,或空(等效0)*//*
                              if(dataFd!=null){
                                     List<Object> values= dataFd.getRawValue();
                                     boolean nonNumeric=values.stream().filter(StringUtils::isNotEmpty).anyMatch(e->!StringUtils.isNumber(e));
@@ -2086,7 +2061,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                                    data=values.stream().filter(StringUtils::isNotEmpty).count();
                                  }else if(designFd!=null){
                                      if(dataFd.getValues().stream().map(ElementData::getValue).anyMatch(StringUtils::isNotEmpty)&&(designFd.getValues().size()>1||designFd.getValues().stream().map(ElementData::getValue).anyMatch(StringUtils::isEmpty))){
-                                         /*多少个设计值暂时默认全部合格,满足绝大部分结果*/
+                                         *//*多少个设计值暂时默认全部合格,满足绝大部分结果*//*
                                          data=dataFd.getValues().stream().map(ElementData::getValue).filter(StringUtils::isNotEmpty).count();
                                      }else{
                                          List<Object>  result =  CustomFunction.b445check(dataFd.getValues().stream().map(ElementData::getValue).collect(Collectors.toList()),designFd.getValues().stream().map(ElementData::getValue).collect(Collectors.toList()),devStr,1 );
@@ -2101,7 +2076,8 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                          f = f.replace(m.group(),putDataWithKey(BaseUtils.isNumber(data)?Double.parseDouble(data.toString()):data));
                      }
                      fd.getFormula().setFormula(f);
-                     formula.setScale(1);
+                     formula.setScale(1);*/
+                     quantity(formula,fd,f);
                  }
                  formula.setFormula(f);
              }catch (Exception e){
@@ -2110,6 +2086,112 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
              }
     }
 
+    /*合格率预处理*/
+    public void quantity( Formula formula,FormData fd,String f){
+        /*聚合*/
+        Matcher m = RegexUtils.matcher(FC_REG+"(quantity)\\(([^)]+)\\)",f);
+        while (m.find()) {
+            Object data=null;
+            List<String> codeList = FormulaUtils.getCodeList(m.group(2));
+            {
+                FormData dataFd=tec.formDataMap.get(codeList.get(0));
+                String designStr=codeList.get(1);
+                FormData designFd=tec.formDataMap.get(designStr);
+                String devStr=StringUtils.isNotEmpty(formula.getDev())?formula.getDev():fd.getEAllowDeviation();
+                if(StringUtils.isEmpty(devStr)){
+                    /*数据库找不到的情况就读取Excel*/
+                    if(tec.wkbMap.isEmpty()){
+                        /*初始化*/
+                        List<String> tableNames4Excel=  tec.getFormDataList().stream().filter(FormData::executable).filter(e->e.info().contains("quantity")).map(FormData::getTableName).distinct().collect(Collectors.toList());
+                        if(!tableNames4Excel.isEmpty()){
+                            List<String> ids =tec.getTableAll().stream().filter(e->tableNames4Excel.contains(e.getInitTableName())).map(NodeTable::getPKeyId).map(String::valueOf).collect(Collectors.toList());
+                            List<Map<String,Object>> listMaps=  this.jdbcTemplate.queryForList("select a.p_key_id pkeyId,a.init_table_name tableName,b.file_url url from m_wbs_tree_contract a join m_excel_tab b on a.excel_id=b.id where a.p_key_id in("+String.join(",",ids)+")");
+                            listMaps.forEach(mp->{
+                                try {
+                                    Workbook wb = WorkbookFactory.create(Objects.requireNonNull(CommonUtil.getOSSInputStream(StringUtils.handleNull(mp.get("url")))));
+                                    tec.wkbMap.put(mp.get("pkeyId").toString(),wb);
+                                } catch (Exception e) {
+                                    e.printStackTrace();
+                                }
+                            });
+                        }
+                    }
+                    Optional<NodeTable> nodeTableOp =tec.getTableAll().stream().filter(e->e.getInitTableName().equals(fd.getTableName())).findFirst();
+                    if(nodeTableOp.isPresent()){
+                        Workbook wb = tec.wkbMap.get(nodeTableOp.get().getPKeyId().toString());
+                        if(wb!=null){
+                            Cell deCell=null;
+                            Sheet sheet = wb.getSheetAt(0);
+                            outerLoop: for(int y=3;y<35;y++){
+                                for(int x=0;x<35;x++){
+                                    Row row = sheet.getRow(y);
+                                    Cell cell=  row.getCell(x);
+                                    String sv=StringUtils.handleNull(FormulaUtils.getValue(cell)).replaceAll("[^\u4e00-\u9fa5]+","");
+                                    if(sv.contains("规定")&&sv.contains("偏差")){
+                                        deCell=cell;
+                                        break outerLoop;
+                                    }
+                                }
+                            }
+                            if(deCell!=null) {
+                                int min = 0;
+                                Optional<Integer> op = fd.getCoordsList().stream().map(Coords::getY).distinct().min(Comparator.comparingInt(e -> e));
+                                if (op.isPresent()) {
+                                    min = op.get();
+                                }
+                                Row row = sheet.getRow(min);
+                                Cell cell = row.getCell(deCell.getColumnIndex());
+                                devStr = FormulaUtils.getValue(cell).toString();
+                            }
+                        }
+                    }
+                }
+                if(CustomFunction.containsZH(devStr)||StringUtils.isEmpty(devStr)||StringUtils.handleNull(devStr).contains("/")){
+                    devStr="±100000";
+                }
+                if(devStr.contains("E[")){
+                    List<String> codes= getCodeByEl(devStr);
+                    Map<String,Object> map = new HashMap<>();
+                    boolean isNull=false;
+                    for (String c:codes){
+                        FormData ffd= tec.getFormDataMap().get(c);
+                        if(ffd.empty()){
+                            isNull=true;
+                            break;
+                        } else{
+                            map.put("E["+c+"]",ffd.getRawValue().stream().filter(StringUtils::isNotEmpty).findFirst().orElse(null)) ;
+                        }
+                    }
+                    if(isNull){
+                        devStr="±100000";
+                    }
+                    devStr= Arrays.stream(devStr.replaceAll("^\\[|\\]$","").split(",")).map(s->map.getOrDefault(s,s)).map(StringUtils::handleNull).collect(Collectors.joining(","));
+                }
+                /*设计值可以是数值类型,或空(等效0)*/
+                if(dataFd!=null){
+                    List<Object> values= dataFd.getRawValue();
+                    boolean nonNumeric=values.stream().filter(StringUtils::isNotEmpty).anyMatch(e->!StringUtils.isNumber(e));
+                    if(nonNumeric){
+                        data=values.stream().filter(StringUtils::isNotEmpty).count();
+                    }else if(designFd!=null){
+                        if(dataFd.getValues().stream().map(ElementData::getValue).anyMatch(StringUtils::isNotEmpty)&&(designFd.getValues().size()>1||designFd.getValues().stream().map(ElementData::getValue).anyMatch(StringUtils::isEmpty))){
+                            /*多少个设计值暂时默认全部合格,满足绝大部分结果*/
+                            data=dataFd.getValues().stream().map(ElementData::getValue).filter(StringUtils::isNotEmpty).count();
+                        }else{
+                            List<Object>  result =  CustomFunction.b445check(dataFd.getValues().stream().map(ElementData::getValue).collect(Collectors.toList()),designFd.getValues().stream().map(ElementData::getValue).collect(Collectors.toList()),devStr,1 );
+                            data=result.get(1);
+                        }
+                    }else if(BaseUtils.isNumber(designStr)) {
+                        List<Object> result = CustomFunction.b445check(dataFd.getValues().stream().map(ElementData::getValue).collect(Collectors.toList()), 0, devStr, 1);
+                        data = result.get(1);
+                    }
+                }
+            }
+            f = f.replace(m.group(),putDataWithKey(BaseUtils.isNumber(data)?Double.parseDouble(data.toString()):data));
+        }
+        fd.getFormula().setFormula(f);
+        formula.setScale(1);
+    }
 
 
    public Map<String,Object> createCurrentMap(String el){
@@ -2219,7 +2301,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
     public Map<String, FormData> createFormDataByCode(String codes) {
         if(Func.isNotBlank(codes)) {
             List<String> codeList = Arrays.asList(codes.split(StringPool.COMMA));
-             String tableNames =  codeList.stream().map(e->e.split(StringPool.COLON)[0]).collect(Collectors.joining(","));
+             String tableNames =  codeList.stream().map(e->e.split(StringPool.COLON)[0]).collect(Collectors.joining("','"));
              /*select d.id,c.tab_ch_name tableChName,d.e_type eType,d.e_name eName,d.e_length eLength,d.e_allow_deviation eAllowDeviation,CONCAT(c.tab_en_name,':',d.e_key) code */
             List<FormData>  fds =createFormDataByTableName(tableNames);
             if(fds!=null){
@@ -2235,7 +2317,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
         return this.getSqlList("select b.id, CONCAT(a.tab_en_name,':',b.e_key) code,a.tab_ch_name tableChName,b.e_name eName ,b.e_allow_deviation eAllowDeviation ,b.e_length eLength,c.dict_value eType " +
                         "from m_table_info a JOIN m_wbs_form_element b on a.id=b.f_id and b.is_deleted=0  " +
                         "LEFT JOIN (select dict_key, dict_value from blade_dict where code ='data_type' and parent_id > 0 and is_sealed = 0 and is_deleted = 0 )c on b.e_type=c.dict_key" +
-                        " where  a.tab_en_name in( "+ tableNames+")"
+                        " where  a.tab_en_name in('"+ tableNames+"')"
                 ,  FormData.class);
     }
 
@@ -2254,10 +2336,126 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                     }
                  }
              });
+    }
 
+    @Override
+    public void paramFormula(WbsTreeContract wtc, Map<String, Object> dataMap,  Document doc) {
+        try {
+            if(!isForm){
+                return;
+            }
+            StopWatch stopWatch = new StopWatch();
+            stopWatch.start("表单公式");
+            /*获取当前表所有元素*/
+            List<FormData> fds=createFormDataByTableName(wtc.getInitTableName());
+            /*过滤掉已经存在内容的元素*/
+            Set<String> filterSet= dataMap.keySet().stream().map(s->s.split("__")[0]).collect(Collectors.toSet());
+            fds.removeIf(f->filterSet.contains(f.getKey()));
+            /*获取元素定位信息,过滤掉绑定单元格数量不为1的元素*/
+            Map<String,String> map = FormulaUtils.getElementCell(wtc.getHtmlUrl(),null,doc);
+            for(FormData fd:fds){
+                String coords= map.get(fd.getKey());
+                if(Func.isNotBlank(coords)){
+                    fd.flushCoords(coords);
+                }
+            }
+            fds.removeIf(f->f.getCoordsList().size()!=1);
+            /*工序节点*/
+            WbsTreeContract node = this.wbsTreeContractService.getOne(Wrappers.<WbsTreeContract>lambdaQuery().eq(WbsTreeContract::getId, wtc.getParentId()).eq(WbsTreeContract::getContractId,wtc.getContractId()));
+            /*项目节点*/
+            WbsTreePrivate wtp = this.wtpId(node.getPKeyId());
+            /*WBS*/
+            WbsTreePrivate publicWtp = this.getOriginWtp(wtp.getPKeyId());
+
+            Map<String,Object> result = new HashMap<>(100);
+            List<WbsParam> total = new ArrayList<>();
+            List<WbsParam> wpsPublic = this.wpService.list(Wrappers.<WbsParam>lambdaQuery().eq(WbsParam::getNodeId,publicWtp.getId()).eq(WbsParam::getType,1));
+            if(Func.isNotEmpty(wpsPublic)){
+                total.addAll(wpsPublic);
+            }
+            List<WbsParam> wpsPrivate = this.wpService.list(Wrappers.<WbsParam>lambdaQuery().eq(WbsParam::getNodeId,wtp.getPKeyId()).eq(WbsParam::getType,1));
+            if(Func.isNotEmpty(wpsPrivate)){
+                total.addAll(wpsPrivate);
+            }
+            if(CollectionUtil.isNotEmpty(total)){
+                /*同名参数私有覆盖公用*/
+                for(WbsParam p:total){
+                    result.put(p.getK(),p.getV());
+                }
+            }
+          Map<Long,String> paramIdKeyMap=  total.stream().collect(Collectors.toMap(WbsParam::getId,WbsParam::getK));
+            /*元素动态绑定*/
+            Map<String,Formula> formulaIdMap = this.wpService.formulaKeyMap(total.stream().map(WbsParam::getK).collect(Collectors.toList()));
+            /*获取已配置节点公式*/
+            if(Func.isNotEmpty(total)){
+                List<ElementFormulaMapping> mappingList =  this.elementFormulaMappingService.list(Wrappers.<ElementFormulaMapping>lambdaQuery().in(ElementFormulaMapping::getParamId,total.stream().map(WbsParam::getId).collect(Collectors.toList())));
+                if(Func.isNotEmpty(mappingList)){
+                    fds.forEach(e->{
+                        mappingList.stream().filter(m->StringUtils.isEquals(m.getElementId(),e.getId())).findAny().ifPresent(d->{
+                            String key = paramIdKeyMap.get(d.getParamId());
+                            Formula formula=formulaIdMap.computeIfAbsent(key,k->this.getById(d.getFormulaId()));
+                            if(formula!=null){
+                                e.setFormulaId(formula.getId());
+                                e.setFormula(formula);
+                            }
+                        });
+                    });
+                }
+            }
+            /*检查是否可以自动绑定参数公式*/
+            List<FormData> notFormulaFds=fds.stream().filter(f->f.getFormulaId()==null).collect(Collectors.toList());
+            if(notFormulaFds.size()>0){
+                notFormulaFds.forEach(e->{
+                    /*暂时用参数名称是否包含元素名称作为匹配规则*/
+                    total.stream().filter(p->e.getEName().contains(p.getName().replaceAll("【[\\u4E00-\\u9FFF]+】|\\s+",""))).findAny().ifPresent(d->{
+                        Formula tf= formulaIdMap.get(d.getK());
+                        if(tf!=null&&e.getId()!=null) {
+                            e.setFormula(tf);
+                            ElementFormulaMapping efm = new ElementFormulaMapping();
+                            efm.setScope(FormulaBean.PARAM);
+                            efm.setParamId(d.getId());
+                            efm.setElementId(e.getId());
+                            efm.setFormulaId(tf.getId());
+                            this.elementFormulaMappingService.save(efm);
+                        }
+                    });
+                });
+            }
+            /*执行结果放回数据集合*/
+            Map<String,Object> currentMap = new HashMap<>(30);
+            /*获取祖先联链*/
+            List<WbsTreeContract> nodes =this.wpService.tracing(node.getPKeyId());
+            currentMap.put(CHAIN,nodes.stream().map(e->StringUtils.isNotEmpty(e.getFullName())?e.getFullName():e.getNodeName()).collect(Collectors.toList()));
+            /*节点参数*/
+            currentMap.put(WP,result);
+            fds.forEach(fd->{
+                if(fd.executable()){
+                    String tmp =fd.getFormula().getFormula().replaceAll("[\\s]+","");
+                    tmp = tmp.replace(FC, CustomFunction.CLASS_CALL);
+                    if(tmp.contains("WP[")){
+                        Matcher am = AP.matcher(tmp);
+                        while (am.find()){
+                            tmp = tmp.replace(am.group(),am.group(1)+"['"+am.group(2)+"']");
+                        }
+                    }
+                    Object data =Expression.parse(tmp).calculate(currentMap);
+                    if(StringUtils.isNotEmpty(data)){
+                        Coords coords=fd.getCoordsList().get(0);
+                        /*计算结果放回结果集 */
+                        dataMap.put(fd.getKey()+"__"+coords.getY()+"_"+coords.getX(),data);
+                    }
+                }
+            });
+            stopWatch.stop();
+            long totalTime = stopWatch.getTotalTimeMillis();
+            StaticLog.info("表单公式执行用时:{}", totalTime);
+        }catch (Exception e){
+            e.printStackTrace();
+        }
     }
 
 
+
 }