|
@@ -0,0 +1,364 @@
|
|
|
+package org.springblade.manager.formula;
|
|
|
+
|
|
|
+import cn.hutool.log.StaticLog;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
+import com.mixsmart.utils.CustomFunction;
|
|
|
+import com.mixsmart.utils.FormulaUtils;
|
|
|
+import com.mixsmart.utils.StringUtils;
|
|
|
+import lombok.Data;
|
|
|
+import org.springblade.core.tool.utils.Func;
|
|
|
+import org.springblade.core.tool.utils.StringPool;
|
|
|
+import org.springblade.manager.dto.*;
|
|
|
+import org.springblade.manager.entity.Formula;
|
|
|
+import org.springblade.manager.entity.WbsTreeContract;
|
|
|
+import org.springblade.manager.enums.ExecuteType;
|
|
|
+import org.springblade.manager.formula.impl.TableElementConverter;
|
|
|
+import org.springblade.manager.service.*;
|
|
|
+import org.springblade.manager.service.impl.FormulaServiceImpl;
|
|
|
+import org.springblade.manager.vo.AppWbsTreeContractVO;
|
|
|
+import org.springblade.manager.vo.CurrentNode;
|
|
|
+
|
|
|
+import java.util.*;
|
|
|
+import java.util.regex.Pattern;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+import java.util.stream.Stream;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @author yangyj
|
|
|
+ * @Date 2023/11/30 16:18
|
|
|
+ * @description 公式执行器
|
|
|
+ */
|
|
|
+@Data
|
|
|
+public class FormulaExecutor {
|
|
|
+ private final FormulaServiceImpl service;
|
|
|
+ private final TableElementConverter tec;
|
|
|
+ public final static String WP="WP";
|
|
|
+ public final static String CHAIN="trees";
|
|
|
+ public final static String FC="FC.";
|
|
|
+ public final static String TABLE_LIST="TBL";
|
|
|
+ public final static String CHECK_ITEMS="CKI";
|
|
|
+ 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 String ELE_CODE_REG= "(?<=E\\[)[^]]+(?=])";
|
|
|
+ public static final Pattern P = Pattern.compile(ELE_CODE_REG);
|
|
|
+ public final static String CTI="ContractInfo";
|
|
|
+
|
|
|
+ public FormulaExecutor(FormulaServiceImpl service, TableElementConverter tec) {
|
|
|
+ this.service = service;
|
|
|
+ this.tec = tec;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public void execute(){
|
|
|
+ List<FormulaHandleChain> chainList = new LinkedList<>();
|
|
|
+ chainList.add(new Init());
|
|
|
+ chainList.add(new Sort());
|
|
|
+ chainList.add(new Pre());
|
|
|
+ chainList.add(new Special());
|
|
|
+ chainList.add(new Calculate());
|
|
|
+ chainList.add(new Format());
|
|
|
+ chainList.forEach(FormulaHandleChain::handle);
|
|
|
+ }
|
|
|
+
|
|
|
+ public class Init implements FormulaHandleChain{
|
|
|
+ @Override
|
|
|
+ public void handle() {
|
|
|
+ /*基础数据*/
|
|
|
+ baseData();
|
|
|
+ if(ExecuteType.INSPECTION.equals(tec.getExecuteType())) {
|
|
|
+ /*依赖加载*/
|
|
|
+ checkingMissingList();
|
|
|
+ /*公式参数*/
|
|
|
+ //option();
|
|
|
+ /*评定表*/
|
|
|
+ //assessmentForm();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**补充缺失的元素依赖*/
|
|
|
+ public void checkingMissingList(){
|
|
|
+ List<String> missingList = new ArrayList<>();
|
|
|
+ if(tec.isNew){
|
|
|
+ tec.formDataList.forEach(fd->{
|
|
|
+ if (fd.executable()) {
|
|
|
+ service.relyParse(fd.getFormula());
|
|
|
+ Formula f = fd.getFormula();
|
|
|
+ List<String> relyList = f.getRelyList();
|
|
|
+ if (Func.isNotEmpty(relyList)) {
|
|
|
+ relyList.forEach(r -> {
|
|
|
+ if (!tec.formDataMap.containsKey(r)) {
|
|
|
+ missingList.add(r);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ missingFill2(missingList);
|
|
|
+ }else {
|
|
|
+ tec.formDataList.forEach(fd -> {
|
|
|
+ if (fd.executable()) {
|
|
|
+ service.relyParse(fd.getFormula());
|
|
|
+ Formula f = fd.getFormula();
|
|
|
+ List<String> relyList = f.getRelyList();
|
|
|
+ if (Func.isNotEmpty(relyList)) {
|
|
|
+ relyList.forEach(r -> {
|
|
|
+ if (tec.formDataMap.values().stream().map(FormData::getCode).noneMatch(k -> StringUtils.isEquals(k, r))) {
|
|
|
+ missingList.add(r);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ missingFill(missingList);
|
|
|
+ }
|
|
|
+ if(Func.isNotEmpty(missingList)){
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
+ missingList.stream().collect(Collectors.groupingBy(s->s.split(StringPool.COLON)[0])).forEach((k, v)->{
|
|
|
+ sb.append(k).append("(").append(v.stream().map(c->c.split(StringPool.COLON)[1]).collect(Collectors.joining(","))).append(")");
|
|
|
+ });
|
|
|
+ tec.getLog().put(FormulaLog.CROSS,sb.toString());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ public void missingFill(List<String> missingList){
|
|
|
+ try {
|
|
|
+ /*数据池里面没有任何元素匹配和当前依赖匹配*/
|
|
|
+ if (Func.isNotEmpty(missingList)) {
|
|
|
+ StaticLog.info("需要挂载的元素{}", String.join(";", missingList));
|
|
|
+ Map<String, Object> elementInfoMap = service.getElementInfoByCodes(String.join(",", missingList));
|
|
|
+ /*1从当前节点其它表格中查找匹配的元素*/
|
|
|
+ List<String> removeList = new ArrayList<>();
|
|
|
+ if (Func.isNotEmpty(missingList)) {
|
|
|
+ /*2从当前节点的兄弟节点中查找匹配的元素*/
|
|
|
+ CurrentNode currentNode = tec.getCurrentNode();
|
|
|
+ /*List<Map<String,Object>> tableNamePkIdsMaps= this.jdbcTemplate.queryForList("select c.init_table_name tableName,c.p_key_id pkId,c.html_url url from (select b.id from m_wbs_tree_contract a join m_wbs_tree_contract b on (a.contract_id=b.contract_id and b.ancestors like CONCAT(a.ancestors,'%')) where a.p_key_id="+currentNode.getPkId()+" and b.is_deleted=0 and b.node_type=6 ORDER BY b.sort) k join m_wbs_tree_contract c on c.parent_id = k.id where c.contract_id="+tec.getContractId()+" and c.is_deleted=0 ");*/
|
|
|
+ WbsTreeContract parent = service.wbsTreeContractService().getOne(Wrappers.<WbsTreeContract>lambdaQuery().eq(WbsTreeContract::getPKeyId, currentNode.getParentPkeyId()));
|
|
|
+ if (parent == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ List<Map<String, Object>> tableNamePkIdsMaps = tec.jdbcTemplate.queryForList(
|
|
|
+ "select c.init_table_name tableName,c.p_key_id pkId,c.html_url url from" +
|
|
|
+ " (select id from m_wbs_tree_contract where contract_id=" + currentNode.getContractId() + " and is_deleted=0 and node_type=6 and tree_code like '" + parent.getTreeCode() + "%' ORDER BY sort) k" +
|
|
|
+ " join m_wbs_tree_contract c on c.parent_id = k.id " +
|
|
|
+ "where c.contract_id=" + currentNode.getContractId() + " and c.is_deleted=0 "
|
|
|
+ );
|
|
|
+ if (Func.isNotEmpty(tableNamePkIdsMaps)) {
|
|
|
+ // removeList.clear();
|
|
|
+ missingList.forEach(miss -> {
|
|
|
+ @SuppressWarnings("unckecked")
|
|
|
+ Map<String, Object> elementInfo = (Map<String, Object>) elementInfoMap.get(miss);
|
|
|
+ String tn = miss.substring(0, miss.indexOf(StringPool.COLON));
|
|
|
+ String key = miss.substring(miss.indexOf(StringPool.COLON) + 1);
|
|
|
+ String targetIds = tableNamePkIdsMaps.stream().filter(m -> StringUtils.isEquals(m.get("tableName"), tn)).map(m -> m.get("pkId")).map(StringUtils::handleNull).collect(Collectors.joining(","));
|
|
|
+ if (Func.isNotEmpty(targetIds)) {
|
|
|
+ if (!tec.getCoordinateMap().containsKey(tn)) {
|
|
|
+ tableNamePkIdsMaps.stream().filter(m -> StringUtils.isEquals(m.get("tableName"), tn)).findAny().ifPresent(m -> {
|
|
|
+ tec.getCoordinateMap().put(tn, FormulaUtils.getElementCell(StringUtils.handleNull(m.get("url"))));
|
|
|
+ });
|
|
|
+ }
|
|
|
+ List<Map<String, Object>> tableDatas = tec.jdbcTemplate.queryForList("select * from " + tn + " where p_key_id in (" + targetIds + ")");
|
|
|
+ String tmp = elementInfo == null ? "" : StringUtils.handleNull(elementInfo.get("ename"));
|
|
|
+ fill(tableDatas, removeList, tn, key, tmp);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (Func.isNotEmpty(removeList)) {
|
|
|
+ /*移除已经找到的元素数据*/
|
|
|
+ missingList.removeIf(removeList::contains);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }catch (Exception e){
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ public void fill(List<Map<String,Object>> tableDatas,List<String> removeList,String tn,String key,String name){
|
|
|
+ if(Func.isNotEmpty(tableDatas)){
|
|
|
+ Map<String,Object> map = new HashMap<>();
|
|
|
+ tableDatas.forEach(m->{
|
|
|
+ for(Map.Entry<String,Object> entry:m.entrySet()){
|
|
|
+ if(entry.getValue()!=null){
|
|
|
+ map.merge(entry.getKey(), entry.getValue(), (v1, v2) -> v1 + ";;" + v2);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ tec.tableDataMaps.put(tn,map);
|
|
|
+ String values= StringUtils.handleNull(map.get(key));
|
|
|
+ String r= tn+StringPool.COLON+key;
|
|
|
+ FormData tmp=createFormDataFast(name,r,values);
|
|
|
+ if(tmp!=null){
|
|
|
+ tec.formDataMap.put(r,tmp);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ public FormData createFormDataFast(String name,String code,String values){
|
|
|
+ if(StringUtils.isNotEmpty(code,name)){
|
|
|
+ String[] arr=code.split(":");
|
|
|
+ String coords = tec.getCoordinateMap().get(arr[0]).get(arr[1]);
|
|
|
+ if(StringUtils.isNotEmpty(coords)) {
|
|
|
+ /*定位信息存在才合法*/
|
|
|
+ List<Coords> coordsList = Stream.of(coords).flatMap(s -> Arrays.stream(s.split(";"))).map(s -> {
|
|
|
+ String[] xy = s.split("_");
|
|
|
+ return new Coords(xy[1], xy[0]);
|
|
|
+ }).collect(Collectors.toList());
|
|
|
+ List<ElementData> eds = new ArrayList<>();
|
|
|
+ if (StringUtils.isNotEmpty(values)) {
|
|
|
+ String[] pages = values.split(";;");
|
|
|
+ for (int index = 0; index < pages.length; index++) {
|
|
|
+ String pg = pages[index];
|
|
|
+ if (Func.isNotBlank(pg)) {
|
|
|
+ String[] val = pg.split("☆");
|
|
|
+ Map<String, Object> tmpMap = new LinkedHashMap<>();
|
|
|
+ for (String s : val) {
|
|
|
+ String[] t = s.split("_\\^_");
|
|
|
+ String[] c = t[1].split("_");
|
|
|
+ tmpMap.put(StringUtils.join(code, 0, index, Func.toInt(c[1]), Func.toInt(c[0]), StringPool.AT), t[0]);
|
|
|
+ }
|
|
|
+ for (Coords c : coordsList) {
|
|
|
+ Object data = null;
|
|
|
+ String key = StringUtils.join(code, 0, index, c.getX(), c.getY(), StringPool.AT);
|
|
|
+ if (tmpMap.containsKey(key)) {
|
|
|
+ data = tmpMap.get(key);
|
|
|
+ }
|
|
|
+ eds.add(new ElementData(index, 0, data, c.getX(), c.getY()));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ } else {
|
|
|
+ eds = coordsList.stream().map(c -> new ElementData(0, 0, null, c.getX(), c.getY())).collect(Collectors.toList());
|
|
|
+ }
|
|
|
+ FormData one = new FormData(code, eds, null, coords);
|
|
|
+ one.setEName(name);
|
|
|
+ /*备份原始数据,用于更新比较*/
|
|
|
+ one.init();
|
|
|
+ return one;
|
|
|
+ }
|
|
|
+ tec.getLog().put(FormulaLog.POSITION,code+"("+name+")");
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ public void missingFill2(List<String> missingList){
|
|
|
+ /*数据池里面没有任何元素匹配和当前依赖匹配*/
|
|
|
+ if(Func.isNotEmpty(missingList)){
|
|
|
+ StaticLog.info("需要挂载的元素{}", String.join(";", missingList));
|
|
|
+ Map<String,FormData> fdsMap = service.createFormDataByCode(String.join(",",missingList));
|
|
|
+ /*1从当前节点其它表格中查找匹配的元素*/
|
|
|
+ List<String> removeList=new ArrayList<>();
|
|
|
+ /*2从当前节点的兄弟节点中查找匹配的元素*/
|
|
|
+ CurrentNode currentNode = tec.getCurrentNode();
|
|
|
+ String sql= "select c.init_table_name tableName,c.p_key_id pkeyId,c.html_url url from (select b.id from m_wbs_tree_contract a join m_wbs_tree_contract b on (a.contract_id=b.contract_id and b.ancestors like CONCAT(a.ancestors,'%')) where a.p_key_id="+currentNode.getPkId()+" and b.is_deleted=0 and b.node_type=6 ORDER BY b.sort) k join m_wbs_tree_contract c on c.parent_id = k.id where c.contract_id="+tec.getContractId()+" and c.is_deleted=0 ";
|
|
|
+ List<TableFormMapper> tableNamePkIdsList = service.getSqlList(sql,TableFormMapper.class);
|
|
|
+ if(Func.isNotEmpty(tableNamePkIdsList)) {
|
|
|
+ List<Long> pkeyIds=tec.getTableAll().stream().map(NodeTable::getPKeyId).collect(Collectors.toList());
|
|
|
+ Map<String,List<Long>>tableNamePkIdsMaps=tableNamePkIdsList.stream().filter(m->!pkeyIds.contains(m.getPkeyId())).collect(Collectors.groupingBy(TableFormMapper::getTableName,Collectors.mapping(TableFormMapper::getPkeyId,Collectors.toList())));
|
|
|
+ Map<String,String> tableNameUrlMaps=tableNamePkIdsList.stream().collect(Collectors.toMap(TableFormMapper::getTableName,TableFormMapper::getUrl,(p,n)->p));
|
|
|
+ List<FormData> fds=new ArrayList<>(fdsMap.values());
|
|
|
+ Map<String,List<FormData>> group = fds.stream().collect(Collectors.groupingBy(FormData::getTableName,Collectors.toList()));
|
|
|
+ group.forEach((k,v)->{
|
|
|
+ String ids =tableNamePkIdsMaps.get(k).stream().map(Objects::toString).collect(Collectors.joining(","));
|
|
|
+ String sqlTableDataInfo="select id,p_key_id pageId,tab_key tabKey ,key_val value from table_data_info where p_key_id in("+ids+")";
|
|
|
+ List<CellDataVo> list= service.getSqlList(sqlTableDataInfo,CellDataVo.class);
|
|
|
+ if(list!=null){
|
|
|
+ Set<String> set= v.stream().map(FormData::getTableName).collect(Collectors.toSet());
|
|
|
+ Map<String, List<CellDataVo>> targetGroup=list.stream().filter(e->set.contains(e.getKey())).collect(Collectors.groupingBy(CellDataVo::getKey,Collectors.toList()));
|
|
|
+ for(FormData fd:v){
|
|
|
+ fd.setCellDataVoList(targetGroup.get(fd.getKey()));
|
|
|
+ if(fd.getCellDataVoList()!=null) {
|
|
|
+ List<Long> pageIds = tableNamePkIdsMaps.get(fd.getTableName());
|
|
|
+ String coords =tec.getCoordinateMap().computeIfAbsent(fd.getTableName(), x -> FormulaUtils.getElementCell(tableNameUrlMaps.get(x))).get(fd.getKey());
|
|
|
+ if(Func.isNotBlank(coords)){
|
|
|
+ fd.flushCoords(coords);
|
|
|
+ }else{
|
|
|
+ tec.getLog().put(FormulaLog.POSITION,fd.getCode()+"("+fd.getEName()+")");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ List<Coords> coordsList = fd.getCoordsList();
|
|
|
+ List<ElementData> eds = fd.getValues();
|
|
|
+ Map<String, Object> map = fd.getCellDataVoList().stream().collect(Collectors.toMap(e -> StringUtils.join(pageIds.indexOf(e.getPageId()), e.getX(), e.getY(), StringPool.AT), CellDataVo::getValue));
|
|
|
+ for (int i = 0; i < pageIds.size(); i++) {
|
|
|
+ for (Coords c : coordsList) {
|
|
|
+ String key = StringUtils.join(i, c.getX(), c.getY(), StringPool.AT);
|
|
|
+ eds.add(new ElementData(i, 0, map.get(key), c.getX(), c.getY()));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /*数据初始化加载*/
|
|
|
+ fd.setInitReady(true);
|
|
|
+ /*备份原始数据,用于更新比较*/
|
|
|
+ fd.init();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ if(Func.isNotEmpty(removeList)){
|
|
|
+ /*移除已经找到的元素数据*/
|
|
|
+ missingList.removeIf(removeList::contains);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ public void keyWord(Map<String,Object> constantMap){
|
|
|
+ CustomFunction.KEYWORD_SET.forEach(e->{
|
|
|
+ constantMap.put(e,e);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ public void baseData(){
|
|
|
+ /*List<FormData> list =this.tec.getFds();*/
|
|
|
+ CurrentNode one=tec.getCurrentNode();
|
|
|
+ /*tec.formDataList=list;*/
|
|
|
+ /*预设关键字*/
|
|
|
+ keyWord(tec.constantMap);
|
|
|
+ /*wbs节点链*/
|
|
|
+ if(ExecuteType.INSPECTION.equals(tec.getExecuteType())) {
|
|
|
+ List<WbsTreeContract> nodes = service.wpService().tracing(one.getPkId());
|
|
|
+ tec.constantMap.put(CHAIN,nodes.stream().map(e-> StringUtils.isNotEmpty(e.getFullName())?e.getFullName():e.getNodeName()).collect(Collectors.toList()));
|
|
|
+ /*节点参数*/
|
|
|
+ tec.constantMap.put(WP,service.getWpMap(one));
|
|
|
+ /*监表质量附件,过滤掉隐藏表格*/
|
|
|
+ tec.constantMap.put("tableNames",tec.getTableAll().stream().filter(e->StringUtils.isEquals(e.getIsBussShow(),1)&&StringUtils.isNotEquals(e.getTableType(),4)).map(NodeTable::getNodeName).collect(Collectors.toList()));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public class Sort implements FormulaHandleChain{
|
|
|
+ @Override
|
|
|
+ public void handle() {
|
|
|
+ tec.getFormDataList().sort(Comparator.comparingInt(FormData::getStep));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public class Pre implements FormulaHandleChain{
|
|
|
+ @Override
|
|
|
+ public void handle() {
|
|
|
+ for(FormData fd:tec.getFormDataList()){
|
|
|
+ System.out.println(fd.getEName());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ public class Special implements FormulaHandleChain{
|
|
|
+ @Override
|
|
|
+ public void handle() {
|
|
|
+ for(FormData fd:tec.getFormDataList()){
|
|
|
+ System.out.println(fd.getEName());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ public class Calculate implements FormulaHandleChain{
|
|
|
+ @Override
|
|
|
+ public void handle() {
|
|
|
+ for(FormData fd:tec.getFormDataList()){
|
|
|
+ System.out.println(fd.getEName());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ public class Format implements FormulaHandleChain{
|
|
|
+ @Override
|
|
|
+ public void handle() {
|
|
|
+ for(FormData fd:tec.getFormDataList()){
|
|
|
+ System.out.println(fd.getEName());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|