فهرست منبع

Merge branch 'lihb' of http://219.151.181.73:3000/zhuwei/bladex into dev-test-merge

lvy 3 هفته پیش
والد
کامیت
5462c76cf8

+ 156 - 30
blade-service/blade-business/src/main/java/org/springblade/business/controller/InformationWriteQueryController.java

@@ -1967,13 +1967,20 @@ public R<Boolean> copyContractTreeNode(@RequestBody CopyContractTreeNodeVO vo) {
             }
 
             //TODO 20250414-lhb-新增 添加祖级字段 ancestorsPId
-            List<WbsTreeContract> contractWbsTreeByContractId = wbsTreeContractClient.getContractWbsTreeByContractId(Long.valueOf(needCopyNode.getContractId()));
-            contractWbsTreeByContractId.addAll(saveList);
-            Map<Long, WbsTreeContract> collect = contractWbsTreeByContractId.stream().collect(Collectors.toMap(WbsTreeContract::getPKeyId, Function.identity()));
-            saveList.forEach(node -> {
-                String correctAncestors = createAncestorsPId(node,collect);;
-                node.setAncestorsPId(correctAncestors);
-            });
+            //因为复制选中节点,所以要查询出选中节点的父节点信息 来组装祖级节点
+            if(needCopyNode != null){
+                Long parentPKeyId = null;
+                String ancestorsPId = null;
+                if(needCopyNode.getPId() == 0L){
+                    ancestorsPId = "0";
+                    parentPKeyId = 0L;
+                }else{
+                    WbsTreeContract parentNode = this.wbsTreeContractClient.getContractNodeByPrimaryKeyId(String.valueOf(needCopyNode.getPId()));
+                    ancestorsPId = parentNode.getAncestorsPId();
+                    parentPKeyId = parentNode.getPKeyId();
+                }
+                attachNodesToTarget(saveList,parentPKeyId,ancestorsPId);
+            }
         }
         needCopyNode.setNodeName(vo.getNeedCopyNodeName());
 
@@ -2141,6 +2148,26 @@ public R<Boolean> copyContractTreeNode(@RequestBody CopyContractTreeNodeVO vo) {
                                     this.addCopyTabData(needCopyNode, toCopyNode, tabOwner, resultTablesData, addTabList, vo.getIsCopyData(), addNewFileTabs);
                                 }
                             }
+
+
+                            /*重构祖级id*/
+                            List<WbsTreeContract> resultAll = new ArrayList<>();
+                            resultAll.addAll(addNodeList);
+                            resultAll.addAll(addTabList);
+                            //因为复制选中节点,所以要查询出选中节点的父节点信息 来组装祖级节点
+                            if(needCopyNode != null && CollectionUtil.isNotEmpty(resultAll)){
+                                Long parentPKeyId = null;
+                                String ancestorsPId = null;
+                                if(needCopyNode.getPId() == 0L){
+                                    ancestorsPId = "0";
+                                    parentPKeyId = 0L;
+                                }else{
+                                    WbsTreeContract parentNode = this.wbsTreeContractClient.getContractNodeByPrimaryKeyId(String.valueOf(toCopyVO.getPrimaryKeyId()));
+                                    ancestorsPId = parentNode.getAncestorsPId();
+                                    parentPKeyId = parentNode.getPKeyId();
+                                }
+                                attachNodesToTarget(resultAll,parentPKeyId,ancestorsPId);
+                            }
                         }
                     }
                 }
@@ -2150,14 +2177,6 @@ public R<Boolean> copyContractTreeNode(@RequestBody CopyContractTreeNodeVO vo) {
                 resultAll.addAll(addNodeList);
                 resultAll.addAll(addTabList);
 
-                //TODO 20250414-lhb-新增
-                List<WbsTreeContract> contractWbsTreeByContractId = wbsTreeContractClient.getContractWbsTreeByContractId(Long.valueOf(contractId));
-                contractWbsTreeByContractId.addAll(resultAll);
-                Map<Long, WbsTreeContract> collect = contractWbsTreeByContractId.stream().collect(Collectors.toMap(WbsTreeContract::getPKeyId, Function.identity()));
-                resultAll.forEach(node -> {
-                    String correctAncestors = createAncestorsPId(node,collect);;
-                    node.setAncestorsPId(correctAncestors);
-                });
 
                 List<WbsTreeContract> allData = this.reBuildAncestors(resultAll);
                 List<WbsTreeContract> nodes = allData.stream().filter(f -> f.getType().equals(1)).collect(Collectors.toList());
@@ -3966,24 +3985,20 @@ public R<Boolean> saveContractTreeNode(@RequestBody AddContractTreeNodeVO vo) {
             saveList.addAll(customResult);
         }
         //找到最顶级节点设置parentId
-        WbsTreeContract topLevelNode = findTopLevelNode(saveList);
-        if (ObjectUtils.isNotEmpty(topLevelNode)) {
+        List<WbsTreeContract> topLevelNode = findTopLevelNode(saveList);
+        if (CollectionUtil.isNotEmpty(topLevelNode)) {
             for (WbsTreeContract wbsTreeContract : saveList) {
-                if (topLevelNode.getPKeyId().equals(wbsTreeContract.getPKeyId())) {
-                    wbsTreeContract.setParentId(treeContract.getId());
-                    //TODO 20250414-lhb-新增
-                    wbsTreeContract.setPId(treeContract.getPKeyId());
+                for (WbsTreeContract contract : topLevelNode) {
+                    if (contract.getPKeyId().equals(wbsTreeContract.getPKeyId())) {
+                        wbsTreeContract.setParentId(treeContract.getId());
+                        //TODO 20250414-lhb-新增
+                        wbsTreeContract.setPId(treeContract.getPKeyId());
+                    }
                 }
             }
         }
         //TODO 20250414-lhb-新增 添加ancestorsPId字段
-        List<WbsTreeContract> contractWbsTreeByContractId = wbsTreeContractClient.getContractWbsTreeByContractId(Long.valueOf(treeContract.getContractId()));
-        contractWbsTreeByContractId.addAll(saveList);
-        Map<Long, WbsTreeContract> collect = contractWbsTreeByContractId.stream().collect(Collectors.toMap(WbsTreeContract::getPKeyId, Function.identity()));
-        saveList.forEach(node -> {
-            String correctAncestors = createAncestorsPId(node,collect);;
-            node.setAncestorsPId(correctAncestors);
-        });
+        attachNodesToTarget(saveList,treeContract.getPKeyId(),treeContract.getAncestorsPId());
 
         R<Boolean> booleanR = this.saveOrCopyNodeTree(saveList, saveLedger, 2, treeContract);
 
@@ -4009,16 +4024,20 @@ public R<String> getDICengNodeName(@RequestParam Long pKeyId,@RequestParam Long
     return R.data("");
 }
 
-public static WbsTreeContract findTopLevelNode(List<WbsTreeContract> saveList) {
+public static List<WbsTreeContract> findTopLevelNode(List<WbsTreeContract> saveList) {
     Set<Long> nodeIds = new HashSet<>();
     for (WbsTreeContract node : saveList) {
         nodeIds.add(node.getId());
     }
+    List<WbsTreeContract> parentNodes = new ArrayList<>();
     for (WbsTreeContract node : saveList) {
         if (!nodeIds.contains(node.getParentId())) {
-            return node;
+            parentNodes.add(node);
         }
     }
+    if(CollectionUtil.isNotEmpty(parentNodes)){
+        return parentNodes;
+    }
     return null;
 }
 
@@ -4893,4 +4912,111 @@ public R<Object> customAddContractNode(@RequestBody CustomAddContractNodeDTO dto
         }
     }
 
+    public void attachNodesToTarget(List<WbsTreeContract> newNodes, Long targetId, String targetAncestors) {
+        // 1. 找到新数据中的顶层节点(新树的根节点)
+        List<WbsTreeContract> newRoot = findRootNode(newNodes);
+
+        // 2. 将新树的根节点绑定到目标节点
+        newRoot.forEach(f -> {
+            f.setPId(targetId);
+            f.setAncestorsPId(calculateAncestors(targetAncestors, targetId));
+
+
+            // 3. 构建映射关系
+            Map<Long, WbsTreeContract> nodeMap = new HashMap<>();
+            Map<Long, List<WbsTreeContract>> childrenMap = new HashMap<>();
+
+            for (WbsTreeContract node : newNodes) {
+                nodeMap.put(node.getPKeyId(), node);
+                childrenMap.computeIfAbsent(node.getPId(), k -> new ArrayList<>()).add(node);
+            }
+
+            // 4. 安全层序遍历(带循环检测)
+            List<WbsTreeContract> list = childrenMap.get(f.getPKeyId());
+            if(CollectionUtil.isNotEmpty(list)){
+                //如果是多个根节点
+                safeBfsTraversal(f, childrenMap, newRoot.size() > 1 ? list.size() : newNodes.size());
+            }
+        });
+
+
+
+    }
+
+    private void safeBfsTraversal(WbsTreeContract root,
+                                  Map<Long, List<WbsTreeContract>> childrenMap,
+                                  int totalNodes) {
+        Queue<WbsTreeContract> queue = new LinkedList<>();
+        Set<Long> visited = new HashSet<>();  // 已访问节点集合
+        queue.add(root);
+        visited.add(root.getPKeyId());
+
+        int processedCount = 0;  // 已处理节点计数器
+        final int MAX_DEPTH = 100;  // 最大深度保护
+
+        while (!queue.isEmpty()) {
+            WbsTreeContract parent = queue.poll();
+            processedCount++;
+
+            // 安全检测1:防止循环引用导致无限循环
+            if (processedCount > totalNodes * 2) {
+                throw new IllegalStateException("处理节点数超过预期,可能存在循环引用。已处理: "
+                        + processedCount + ",总节点: " + totalNodes);
+            }
+
+            // 安全检测2:防止路径过长
+            if (parent.getAncestorsPId().split(",").length > MAX_DEPTH) {
+                throw new IllegalStateException("祖级路径超过最大深度限制: " + MAX_DEPTH);
+            }
+
+            List<WbsTreeContract> children = childrenMap.get(parent.getPKeyId());
+            if (children == null) continue;
+
+            for (WbsTreeContract child : children) {
+                // 安全检测3:检查循环引用
+                if (visited.contains(child.getPKeyId())) {
+                    throw new IllegalStateException("检测到循环引用: 节点" + child.getPKeyId()
+                            + " -> 节点" + parent.getPKeyId());
+                }
+
+                // 更新祖级路径 = 父路径 + 父ID
+                child.setAncestorsPId(calculateAncestors(parent.getAncestorsPId(), parent.getPKeyId()));
+
+                queue.add(child);
+                visited.add(child.getPKeyId());
+            }
+        }
+
+        // 验证是否处理了所有节点
+        if (processedCount < totalNodes) {
+            throw new IllegalStateException("存在未处理的节点,可能是不连通的子树。已处理: "
+                    + processedCount + ",总节点: " + totalNodes);
+        }
+    }
+
+    private String calculateAncestors(String parentAncestors, Long parentId) {
+        if (parentAncestors == null || parentAncestors.isEmpty()) {
+            return parentId.toString();
+        }
+        return parentAncestors + "," + parentId;
+    }
+
+    private List<WbsTreeContract> findRootNode(List<WbsTreeContract> nodes) {
+        Set<Long> nodeIds = new HashSet<>();
+        for (WbsTreeContract node : nodes) {
+            nodeIds.add(node.getPKeyId());
+        }
+        List<WbsTreeContract> parentNodes = new ArrayList<>();
+        for (WbsTreeContract node : nodes) {
+            Long parentId = node.getPId();
+            // 父节点为空 或 父节点不在当前新数据列表中 → 视为根节点
+            if (parentId == null || !nodeIds.contains(parentId)) {
+                parentNodes.add(node);
+            }
+        }
+        if (CollectionUtil.isNotEmpty(parentNodes)) {
+            return parentNodes;
+        }
+        throw new IllegalArgumentException("新数据中未找到根节点");
+    }
 }

+ 14 - 10
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ExcelTabController.java

@@ -600,7 +600,7 @@ public class ExcelTabController extends BladeController {
 
                     for (WbsFormElement elementInfo : elementList) {
                         String ysName = elementInfo.getEName();
-                        if (titleName.equals(ysName)) {
+                         if (titleName.equals(ysName)) {
                             lastName = elementInfo.getEName();
                             attrInfo = elementInfo.getEKey() + "__" + i + "_" + j;
                             filedType = WbsElementUtil.getInitTableFiledType(elementInfo.getEType());
@@ -610,7 +610,8 @@ public class ExcelTabController extends BladeController {
                             is_true = true;
                             break;
                         } else {
-                            if (MathUtil.sim(titleName, ysName) > maxScore) {
+                             List<String> list = Arrays.asList(titleName.split("_"));
+                             if (list.contains(ysName)) {
                                 attrInfo = elementInfo.getEKey() + "__" + i + "_" + j;
 
                                 filedType = WbsElementUtil.getInitTableFiledType(elementInfo.getEType());
@@ -620,6 +621,7 @@ public class ExcelTabController extends BladeController {
                                 lastName = ysName;
                                 maxScore = MathUtil.sim(titleName, ysName);
                                 is_true = true;
+                                break;
                             }
                         }
                     }
@@ -1265,10 +1267,10 @@ public class ExcelTabController extends BladeController {
                                         if (x1 - xx2 <= 1 && y1 == yy2) {
                                             inputText = name;
                                         } else {
-                                            inputText += name + "_";
+                                            inputText += name + "_" +name;
                                         }
                                     } else {
-                                        inputText += name + "_";
+                                        inputText += "_" +name;
                                     }
                                 } else {
                                     if (x1 - xx2 <= 1 && y1 == yy2) {
@@ -1287,14 +1289,14 @@ public class ExcelTabController extends BladeController {
                                 int yy1 = Integer.parseInt(top.get(k).get("y1"));
                                 int yy2 = Integer.parseInt(top.get(k).get("y2"));
                                 if (!StringUtil.isNumeric(name) && name.length() <= 20) {
-                                    inputText += name + "_";
+                                    inputText += "_" + name;
                                 }
                             }
                         }
-
-                        if (inputText != null && inputText != "" && inputText.indexOf("_") >= 0) {
-                            inputText = inputText.substring(0, inputText.lastIndexOf("_"));
-                        }
+                        //这段代码含义未知
+//                        if (inputText != null && inputText != "" && inputText.indexOf("_") >= 0) {
+//                            inputText = inputText.substring(0, inputText.lastIndexOf("_"));
+//                        }
 
                         // 质检表特殊处理匹配
 
@@ -2023,7 +2025,6 @@ public class ExcelTabController extends BladeController {
             throw new RuntimeException(e);
         }
 
-
         //公式填充
         executionTime.info("----公式填充执行----");
         this.excelTabService.formulaFillData(tableInfoList, Long.parseLong(nodeId), ExecuteType.INSPECTION);
@@ -2033,6 +2034,9 @@ public class ExcelTabController extends BladeController {
             R.success("数据未发生变化");
         }
         executionTime.info("----公式填充执行完毕----");
+
+        //把CL08 和CL10 的监理表添加进去
+
         //保存数据到数据库
         R<Object> result = this.excelTabService.saveOrUpdateInfo(tableInfoList,singnType);
         RandomNumberHolder.RandomTemplateTypeclear();

+ 17 - 2
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/TextdictInfoController.java

@@ -113,7 +113,9 @@ public class TextdictInfoController extends BladeController {
     @ApiOperationSupport(order = 3)
     @ApiOperation(value = "分页", notes = "传入textdictInfo")
     public R<IPage<TextdictInfoVO>> page(TextdictInfoVO textdictInfo, Query query) {
-
+        if(textdictInfo.getType() == 4){
+            return R.data(textdictInfoService.analysisHtmlDefault(textdictInfo.getTabId()));
+        }
         IPage<TextdictInfoVO> pages = textdictInfoService.selectTextdictInfoPage(Condition.getPage(query), textdictInfo);
         return R.data(pages);
     }
@@ -155,7 +157,15 @@ public class TextdictInfoController extends BladeController {
     @PostMapping("/remove")
     @ApiOperationSupport(order = 7)
     @ApiOperation(value = "逻辑删除", notes = "传入ids")
-    public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids,@ApiParam(value = "wbs p_key_id", required = true) @RequestParam String tabId) throws FileNotFoundException {
+    public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids,
+                    @ApiParam(value = "wbs p_key_id", required = true) @RequestParam String tabId,
+                    String colKey,
+                    Integer type) throws FileNotFoundException {
+        if(type != null && type == 4){
+            textdictInfoService.removeHtmlDefault(tabId,colKey);
+            return R.success("删除成功");
+        }
+
         //获取节点信息
 
         WbsTreePrivate wbsTreePrivate = wbsTreePrivateMapper.getByPKeyId(Long.parseLong(tabId));
@@ -562,6 +572,11 @@ public class TextdictInfoController extends BladeController {
     @ApiOperationSupport(order = 7)
     @ApiOperation(value = "保存默认值", notes = "保存默认值")
     public R<String> saveDefaulVal(@Valid @RequestBody TextdictBy345VO textdictInfo) throws Exception {
+        if(textdictInfo.getType() == 4){
+            textdictInfoService.saveHtmlDefault(textdictInfo);
+            return R.success("操作成功");
+        }
+
 
         //当前清表信息
         WbsTreePrivate wbsTreePrivate = wbsTreePrivateMapper.getByPKeyId(textdictInfo.getTableId());

+ 7 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsFormElementMapper.java

@@ -77,4 +77,11 @@ public interface WbsFormElementMapper extends BaseMapper<WbsFormElement> {
      * @return
      */
     Integer selectFiledDataMaxLength(@Param("tableName") String initTableName,@Param("key") String eKey);
+
+    /**
+     * 统计当前表所有字段长度
+     * @param initTableName
+     * @return
+     */
+    int selectSumColumnLength(@Param("database") String database,@Param("tableName") String initTableName);
 }

+ 12 - 2
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsFormElementMapper.xml

@@ -167,10 +167,20 @@
         SELECT data_type FROM information_schema.columns WHERE table_name=#{initTableName} AND column_name = #{eKey}
     </select>
     <select id="selectFiledLength" resultType="java.util.Map">
-        select column_name `key`,character_octet_length length from INFORMATION_SCHEMA.COLUMNS  where table_name = #{initTableName}
+        select column_name `key`,character_maximum_length length from INFORMATION_SCHEMA.COLUMNS  where table_name = #{initTableName}
     </select>
     <select id="selectFiledDataMaxLength" resultType="java.lang.Integer">
-        select MAX(LENGTH(${key})) from ${tableName}
+        select IFNULL(MAX(CHAR_LENGTH(${key})),0) from ${tableName}
+    </select>
+    <select id="selectSumColumnLength" resultType="java.lang.Integer">
+        SELECT
+            SUM( CHARACTER_MAXIMUM_LENGTH )
+        FROM
+            information_schema.COLUMNS
+        WHERE
+            TABLE_SCHEMA = #{database}
+            AND TABLE_NAME = #{tableName}
+            AND DATA_TYPE = 'varchar'
     </select>
 
 </mapper>

+ 7 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/service/ITextdictInfoService.java

@@ -20,6 +20,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import org.springblade.core.tool.api.R;
 import org.springblade.manager.dto.RangeInfo;
 import org.springblade.manager.entity.TextdictInfo;
+import org.springblade.manager.vo.TextdictBy345VO;
 import org.springblade.manager.vo.TextdictDataInfoVO;
 import org.springblade.manager.vo.TextdictInfoVO;
 import org.springblade.core.mp.base.BaseService;
@@ -47,4 +48,10 @@ public interface ITextdictInfoService extends IService<TextdictInfo> {
     void deleDataInfoById(String id);
 
     TextdictInfo selectTextdictInfoOne(String id,String sigRoleId,String projectId);
+
+    IPage<TextdictInfoVO> analysisHtmlDefault(String tabId);
+
+    void removeHtmlDefault(String tabId, String colKey);
+
+    void saveHtmlDefault(TextdictBy345VO textdictInfo);
 }

+ 129 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/TextdictInfoServiceImpl.java

@@ -17,13 +17,18 @@
 package org.springblade.manager.service.impl;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import org.jsoup.Jsoup;
 import org.jsoup.nodes.Document;
 import org.jsoup.nodes.Element;
 import org.jsoup.select.Elements;
+import org.springblade.common.constant.CommonConstant;
+import org.springblade.common.utils.CommonUtil;
+import org.springblade.core.tool.utils.FileUtil;
 import org.springblade.core.tool.utils.Func;
 import org.springblade.core.tool.utils.IoUtil;
+import org.springblade.core.tool.utils.ResourceUtil;
 import org.springblade.manager.entity.TextdictInfo;
 import org.springblade.manager.entity.WbsTreePrivate;
 import org.springblade.manager.mapper.TextdictInfoMapper;
@@ -31,12 +36,17 @@ import org.springblade.manager.mapper.WbsTreePrivateMapper;
 import org.springblade.manager.service.ISignConfigService;
 import org.springblade.manager.service.ITextdictInfoService;
 import org.springblade.manager.utils.FileUtils;
+import org.springblade.manager.vo.TextdictBy345VO;
 import org.springblade.manager.vo.TextdictInfoVO;
+import org.springblade.system.cache.ParamCache;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.InputStream;
 import java.util.*;
 import java.util.stream.Collectors;
@@ -178,4 +188,123 @@ public class TextdictInfoServiceImpl extends ServiceImpl<TextdictInfoMapper, Tex
         return true;
     }
 
+    @Override
+    public void saveHtmlDefault(TextdictBy345VO textdictInfo) {
+        String file_path = ParamCache.getValue(CommonConstant.SYS_LOCAL_URL);
+        String sys_file_net_url = ParamCache.getValue(CommonConstant.SYS_FILE_NET_URL);
+        WbsTreePrivate wbsTreePrivate = wbsTreePrivateMapper.getByPKeyId(textdictInfo.getTableId());
+        try {
+            File file1 = ResourceUtil.getFile(wbsTreePrivate.getHtmlUrl());
+            InputStream fileInputStream;
+            if (file1.exists()) {
+                fileInputStream = new FileInputStream(file1);
+            } else {
+                String path = sys_file_net_url + wbsTreePrivate.getHtmlUrl().replaceAll("//", "/").replaceAll(file_path, "");
+                fileInputStream = CommonUtil.getOSSInputStream(path);
+            }
+            String htmlString = IoUtil.readToString(fileInputStream);
+            //样式集合
+            Document doc = Jsoup.parse(htmlString);
+            //解析
+            Element table = doc.select("table").first();
+
+            Elements trs = table.select("tr");
+            Element element = trs.get(textdictInfo.getTrIndex()).select("td").get(textdictInfo.getTdIndex());
+
+            if (element.html().indexOf("el-input") >= 0 ) {
+                element.children().removeAttr("defText");
+                element.children().attr("defText", textdictInfo.getTextId());
+            } else {
+                element.children().removeAttr("defText");
+                element.attr("defText", textdictInfo.getTextId());
+            }
+            File writeFile = new File(wbsTreePrivate.getHtmlUrl());
+            FileUtil.writeToFile(writeFile, doc.html(), Boolean.parseBoolean("UTF-8"));
+
+        } catch (FileNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+
+
+
+    }
+
+    @Override
+    public IPage<TextdictInfoVO> analysisHtmlDefault(String tabId) {
+        String file_path = ParamCache.getValue(CommonConstant.SYS_LOCAL_URL);
+        String sys_file_net_url = ParamCache.getValue(CommonConstant.SYS_FILE_NET_URL);
+
+        WbsTreePrivate wbsTreePrivate = wbsTreePrivateMapper.getByPKeyId(Long.parseLong(tabId));
+        IPage<TextdictInfoVO> textdictInfoPage = new Page<TextdictInfoVO>();
+        try {
+            File file1 = ResourceUtil.getFile(wbsTreePrivate.getHtmlUrl());
+            InputStream fileInputStream;
+            if (file1.exists()) {
+                fileInputStream = new FileInputStream(file1);
+            } else {
+                String path = sys_file_net_url + wbsTreePrivate.getHtmlUrl().replaceAll("//", "/").replaceAll(file_path, "");
+                fileInputStream = CommonUtil.getOSSInputStream(path);
+            }
+            String htmlString = IoUtil.readToString(fileInputStream);
+            //样式集合
+            Document doc = Jsoup.parse(htmlString);
+            //解析
+            Element table = doc.select("table").first();
+            Elements elements = table.select("[defText]");
+
+            ArrayList<TextdictInfoVO> textdictInfos = new ArrayList<>();
+            for (Element element : elements) {
+                TextdictInfoVO textdictInfo = new TextdictInfoVO();
+                String keyname = element.attr("keyname");
+                String placeholder = element.attr("placeholder");
+                String defText = element.attr("defText");
+                textdictInfo.setColKey(keyname);
+                textdictInfo.setColName(placeholder);
+                textdictInfo.setSigRoleName(defText);
+                textdictInfo.setType(4);
+                textdictInfo.setId(-1L);
+                textdictInfos.add(textdictInfo);
+            }
+            textdictInfoPage.setRecords(textdictInfos);
+            return textdictInfoPage;
+        } catch (FileNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public void removeHtmlDefault(String tabId, String colKey) {
+        String file_path = ParamCache.getValue(CommonConstant.SYS_LOCAL_URL);
+        String sys_file_net_url = ParamCache.getValue(CommonConstant.SYS_FILE_NET_URL);
+
+        WbsTreePrivate wbsTreePrivate = wbsTreePrivateMapper.getByPKeyId(Long.parseLong(tabId));
+        try {
+            File file1 = ResourceUtil.getFile(wbsTreePrivate.getHtmlUrl());
+            InputStream fileInputStream;
+            if (file1.exists()) {
+                fileInputStream = new FileInputStream(file1);
+            } else {
+                String path = sys_file_net_url + wbsTreePrivate.getHtmlUrl().replaceAll("//", "/").replaceAll(file_path, "");
+                fileInputStream = CommonUtil.getOSSInputStream(path);
+            }
+            String htmlString = IoUtil.readToString(fileInputStream);
+            //样式集合
+            Document doc = Jsoup.parse(htmlString);
+            //解析
+            Element table = doc.select("table").first();
+            Elements elements = table.select("[defText]");
+            for (Element element : elements) {
+                String keyname = element.attr("keyname");
+                if(Objects.equals(colKey,keyname)){
+                    element.removeAttr("defText");
+                }
+            }
+
+            //重写html
+            File writeFile = new File(wbsTreePrivate.getHtmlUrl());
+            FileUtil.writeToFile(writeFile, doc.html(), Boolean.parseBoolean("UTF-8"));
+        } catch (FileNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+    }
 }

+ 123 - 56
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsFormElementServiceImpl.java

@@ -62,6 +62,8 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
     public static final Integer DEFAULT_ELEMENT_LENGTH_DATE = 100;
     //实体表字段默认长度
     private static final String ELEMENT_LENGTH_ENTITY = "200";
+    //数据库动态表总字段最大长度
+    private static final Integer MYSQL_MAX_COLUMN_LENGTH = 16328;
 
     @Override
     public IPage<WbsFormElementVO> selectWbsFormElementPage(IPage<WbsFormElementVO> page, WbsFormElementVO wbsFormElement) {
@@ -140,24 +142,32 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public WbsFormElement saveAndSyn(WbsFormElement wbsFormElement, String tableName) {
-        try {
 
-            String isExitSql = "select * from information_schema.TABLES where TABLE_NAME='" + tableName + "'";
-            List<Map<String, Object>> tabList = jdbcTemplate.queryForList(isExitSql);
-            if (tabList.size() <= 0) {
-                throw new ServiceException("未获取到对应的实体表名称initTableName");
-            }
+        String isExitSql = "select * from information_schema.TABLES where TABLE_NAME='" + tableName + "'";
+        List<Map<String, Object>> tabList = jdbcTemplate.queryForList(isExitSql);
+        if (tabList.size() <= 0) {
+            throw new ServiceException("未获取到对应的实体表名称initTableName");
+        }
 
 
-            //获取实体表主库信息
-            TableInfo tableInfo = tableInfoMapper.selectById(wbsFormElement.getFId());
-            if (tableInfo == null) {
-                throw new ServiceException("没有找到主库信息,确认fid是否正确");
-            } else {
-                tableName = tableInfo.getTabEnName();
-            }
+        //获取实体表主库信息
+        TableInfo tableInfo = tableInfoMapper.selectById(wbsFormElement.getFId());
+        if (tableInfo == null) {
+            throw new ServiceException("没有找到主库信息,确认fid是否正确");
+        } else {
+            tableName = tableInfo.getTabEnName();
+        }
 
+
+        //当前表总字段长度
+        int sumLength = baseMapper.selectSumColumnLength(jdbcTemplate.queryForObject("SELECT DATABASE()", String.class), tableName);
+        if (sumLength + wbsFormElement.getELength() > MYSQL_MAX_COLUMN_LENGTH) {
+            updateTableFieldLength(tableName);
+            throw new ServiceException("无法添加字段,可用长度:" + (MYSQL_MAX_COLUMN_LENGTH - sumLength) + ",已自动调整其他字段长度,请重新添加");
+        }
+        try {
             // 删除 元素和实体表不匹配的字段
             //baseMapper.deleteElementByfId2();
 
@@ -193,6 +203,7 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
                     throw new ServiceException("请输入正确的长度,范围为10-1000");
                 } else {
                     //新增
+                    wbsFormElement.setELength(DEFAULT_ELEMENT_LENGTH_VARCHAR);
                     baseMapper.insert(wbsFormElement);
 
                     //同步
@@ -209,6 +220,7 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
                     throw new ServiceException("请输入正确的长度,范围为10-255");
                 } else {
                     //新增
+                    wbsFormElement.setELength(DEFAULT_ELEMENT_LENGTH_VARCHAR);
                     baseMapper.insert(wbsFormElement);
 
                     //同步
@@ -240,6 +252,7 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
                     throw new ServiceException("请输入正确的长度,范围为0-100");
                 } else {
                     //新增
+                    wbsFormElement.setELength(DEFAULT_ELEMENT_LENGTH_VARCHAR);
                     baseMapper.insert(wbsFormElement);
 
                     //同步
@@ -305,19 +318,20 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
         wbsFormElementList.forEach(obj -> obj.setStatus(1));
         boolean b = this.updateBatchById(wbsFormElementList);
 
-        //字段级字段长度缓存
-        Map<String, Integer> lengthMap = new HashMap<>();
 
-        //查询当前表的所有字段级字段长度
-        List<Map<String, Object>> filedLengths = baseMapper.selectFiledLength(initTableName);
-        for (Map<String, Object> filedLength : filedLengths) {
-            BigInteger length = (BigInteger) filedLength.get("length");
-            if (length == null) {
-                continue;
-            }
-            lengthMap.put(filedLength.get("key").toString(), length.intValue());
+        //当前设置的字段总长度
+        Integer nowTotalLength = 0;
+        for (WbsFormElement wbsFormElement : wbsFormElementList) {
+            nowTotalLength += wbsFormElement.getELength();
+        }
+        //当前表总字段长度
+        int sumLength = baseMapper.selectSumColumnLength(jdbcTemplate.queryForObject("SELECT DATABASE()", String.class), initTableName);
+        if (nowTotalLength > MYSQL_MAX_COLUMN_LENGTH) {
+            //修改元素字段长度
+            throw new ServiceException("无法添加字段,可用长度:" + (MYSQL_MAX_COLUMN_LENGTH - sumLength));
         }
 
+
         //修改实体表信息
         if (b) {
             String fId = "";
@@ -361,40 +375,9 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
                 int row1 = wbsTreeMapper.isThereAField(initTableName, eKey);
                 if (row1 > 0) {
                     try {
-                        //1、查询当前表当前字段
-
-                        //字段配置的长度
-                        Integer filedLength = lengthMap.get(eKey);
-                        if(filedLength == null){
-                            throw new RuntimeException("字段不存在");
-                        }
-                        //获取当前字段数据的最长数据长度
-                        Integer maxLength = baseMapper.selectFiledDataMaxLength(initTableName, eKey);
-                        //初始长度
-                        int initLength = 250;
-                        //当前字段数据长度为null
-                        if (maxLength == null) {
-                            //设置初始长度
-                            baseMapper.updateFiledType(initTableName, eKey, "varchar", initLength);
-                            wbsFormElement.setELength(initLength);
-                            baseMapper.updateById(wbsFormElement);
-                        } else {
-                            //动态扩容 每次根据最大数据长度扩容100
-                            int newLength = maxLength + 100;
-                            //如果字段的长度与扩容后的值一致则不去修改字段
-                            if (filedLength == newLength) {
-                                continue;
-                            }
-                            //如果数据的最大长度 +100 都大于字段配置的长度  则重新设置字段的长度
-                            if (filedLength >= newLength) {
-                                baseMapper.updateFiledType(initTableName, eKey, "varchar", newLength);
-                                wbsFormElement.setELength(newLength);
-                                baseMapper.updateById(wbsFormElement);
-                                continue;
-                            }
-                            baseMapper.updateFiledType(initTableName, eKey, "varchar", eLength);
-                        }
+                        baseMapper.updateFiledType(initTableName, eKey, "varchar", eLength);
                     } catch (Exception e) {
+                        e.printStackTrace();
                         this.updateBatchById(beforeUpdateWbsFormElements);
                         throw new RuntimeException("字段长度范围超出总最大限制,请尝试缩小当前字段长度或其他字段长度");
                     }
@@ -965,4 +948,88 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
         }
     }
 
+
+    /**
+     * 修改当前表所有字段的长度 (只用于字段缩减)
+     * 1、字段数量超过80 表数据超过500条 把数据长度为0的旧字段长度改为50
+     * 超过:新字段的默认长度改为150,并且
+     */
+    public void updateTableFieldLength(String tableName) {
+        TableInfo tableInfo = tableInfoMapper.selectOne(Wrappers.<TableInfo>lambdaQuery()
+                .eq(TableInfo::getTabEnName, tableName)
+                .last("limit 1"));
+
+        List<WbsFormElement> wbsFormElements = baseMapper.selectList(Wrappers.<WbsFormElement>lambdaQuery()
+                .eq(WbsFormElement::getFId, tableInfo.getId()));
+        //元素是否存在
+        if (CollectionUtil.isEmpty(wbsFormElements)) {
+            return;
+        }
+        //字段级字段长度缓存
+        Map<String, Integer> lengthMap = new HashMap<>();
+        //查询当前表的所有字段级字段长度
+        List<Map<String, Object>> filedLengths = baseMapper.selectFiledLength(tableName);
+        //表是否存在
+        if (CollectionUtil.isEmpty(filedLengths)) {
+            return;
+        }
+        for (Map<String, Object> filedLength : filedLengths) {
+            BigInteger length = (BigInteger) filedLength.get("length");
+            if (length == null) {
+                continue;
+            }
+            //记录字段与字段长度
+            lengthMap.put(filedLength.get("key").toString(), length.intValue());
+        }
+
+        //这张表是否拥有数据超过500条
+        Integer count = jdbcTemplate.queryForObject("select count(0) from " + tableName, Integer.class);
+
+
+        for (WbsFormElement wbsFormElement : wbsFormElements) {
+
+            String eKey = wbsFormElement.getEKey();
+            //字段不存在
+            if (lengthMap.get(eKey) == null) {
+                continue;
+            }
+            Integer dataLength = baseMapper.selectFiledDataMaxLength(tableName, eKey);
+
+            if (wbsFormElements.size() > 80 && count > 500) {
+                //数据长度
+                dataLength = dataLength == 0 ? 50 : lengthMap.get(eKey) + 100;
+                //如果当前需要设置的长度大于当前字段长度,则跳过
+                if (dataLength > wbsFormElement.getELength()) {
+                    continue;
+                }
+            } else if (wbsFormElements.size() > 80 && count < 500) {
+                //数据长度
+                dataLength = dataLength == 0 ? 100 : lengthMap.get(eKey) + 100;
+                //如果当前需要设置的长度大于当前字段长度,则跳过
+                if (dataLength > wbsFormElement.getELength()) {
+                    continue;
+                }
+            } else if (wbsFormElements.size() < 80 && count > 500) {
+                //数据长度
+                dataLength = dataLength == 0 ? 200 : lengthMap.get(eKey) + 100;
+                //如果当前需要设置的长度大于当前字段长度,则跳过
+                if (dataLength > wbsFormElement.getELength()) {
+                    continue;
+                }
+            } else {
+                //数据长度
+                dataLength = dataLength == 0 ? 200 : lengthMap.get(eKey) + 100;
+                //如果当前需要设置的长度大于当前字段长度,则跳过
+                if (dataLength > wbsFormElement.getELength()) {
+                    continue;
+                }
+                if (dataLength < 200) {
+                    dataLength = 200;
+                }
+            }
+            baseMapper.updateFiledType(tableName, eKey, "varchar", dataLength);
+            wbsFormElement.setELength(dataLength);
+            baseMapper.updateById(wbsFormElement);
+        }
+    }
 }

+ 322 - 2
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreeContractServiceImpl.java

@@ -20,6 +20,7 @@ import org.apache.ibatis.session.SqlSessionFactory;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Table;
 import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.jsoup.Jsoup;
@@ -82,6 +83,8 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.math.MathContext;
+import java.math.RoundingMode;
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Function;
@@ -110,6 +113,8 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
     private final InformationQueryClient informationQueryClient;
     private final ContractClient contractClient;
     private final ITableFileService tableFileService;
+    private final TableInfoMapper  tableInfoMapper;
+    private final WbsFormElementMapper wbsFormElementMapper;
 
 
     @Autowired
@@ -1657,17 +1662,87 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
                     sgTabMaps.put(s + "---" + wbsTreeContract.getPKeyId(), wbsTreeContract.getInitTableName());
                 }
             }
+            //获取 CL08水准测量记录表(监理)的 实际标高、高程偏差 对应字段 m_20220928134702_1574999102784012288
+            String leveling = "CL08水准测量记录表(监理)";
+            String levelingTableName = "m_20220928134702_1574999102784012288";
+
+            String designedElevation = "设计标高";
+            //负值+0/1 正值-0/1
+            String heightDeviation = "高程偏差";
+            //设置标高 + (高度偏差 / 100)
+            String actualElevation = "实际标高";
+
+            //m_20220928134725_1574999197613031424
+            String planePosition = "CL10平面位置检测记录表(监理)";
+            String planePositionTableName = "m_20220928134725_1574999197613031424";
+
+            //负值+0/1 正值-0/1
+            String difference = "差值";
+            //差值X + 差值Y 的开平方
+            String deviation = "偏位";
+            //指定表单和指定字段
+            Map<String, Map<String, String>> dataMaps = new HashMap<>();
+
             for (WbsTreeContract wbsTreeContract : jlTabSort) {
                 //监理表
                 String s = extractAlphameric(wbsTreeContract.getNodeName());
                 if (StringUtils.isNotEmpty(s)) {
                     jlTabMaps.put(s + "---" + wbsTreeContract.getPKeyId(), wbsTreeContract.getInitTableName());
                 }
+
+
+                /**
+                 * 如果是
+                 *  CL08水准测量记录表(监理)
+                 *      1、“实际标高”不获取数据,改为计算得来,计算规则为:实际标高 = 设计标高 + (高程偏差 / 100)。其中高程偏差需带符号进行计算,特别是负号;
+                 *      2、获取的【高程偏差】需要做随机加减(规则为:如果是负数则+0/1,如果是正数则-0/1)
+                 *  CL10平面位置检测记录表(监理)
+                 *      1、“差值”的两列和“偏位”数据不获取
+                 *      2、获取的【差值】两列 需要做随机加减(规则为:如果是负数则+0/1,如果是正数则-0/1)
+                 *      3、“偏差”不获取数据,改为计算得来,计算规则为:(差值x的平方 + 差值y的平方)的和开平方,四舍五入保留整数。
+                 */
+                HashMap<String, String> map = new HashMap<>();
+
+                //判断当前表单是否是CL08、CL10
+                if (levelingTableName.equals(wbsTreeContract.getInitTableName()) || planePositionTableName.equals(wbsTreeContract.getInitTableName())) {
+                    TableInfo tableInfo = tableInfoMapper.selectOne(Wrappers.<TableInfo>lambdaQuery()
+                            .eq(TableInfo::getTabEnName, wbsTreeContract.getInitTableName()));
+                    List<WbsFormElement> wbsFormElements = wbsFormElementMapper.selectList(Wrappers.<WbsFormElement>lambdaQuery()
+                            .eq(WbsFormElement::getFId, tableInfo.getId()));
+                    for (WbsFormElement wbsFormElement : wbsFormElements) {
+                        String eName = wbsFormElement.getEName();
+                        if(eName.contains(designedElevation)){
+                            //设置标高
+                            map.put(designedElevation, wbsFormElement.getEKey());
+                        }else if(eName.contains(heightDeviation)){
+                            //高度偏差
+                            map.put(heightDeviation, wbsFormElement.getEKey());
+                        }else if(eName.contains(actualElevation)){
+                            //实际标高
+                            map.put(actualElevation, wbsFormElement.getEKey());
+                        }else if(eName.contains(difference)){
+                            //差值
+                            if(eName.contains("X")){
+                                map.put(difference + "X", wbsFormElement.getEKey());
+                            }else if (eName.contains("Y")){
+                                map.put(difference + "Y", wbsFormElement.getEKey());
+                            }
+                        }else if(eName.contains(deviation)){
+                            //偏差
+                            map.put(deviation, wbsFormElement.getEKey());
+                        }
+                    }
+
+                    //存储
+                    dataMaps.put(wbsTreeContract.getInitTableName(),map);
+                }
             }
 
             //构造表数据
             List<InsertDataVO> resultData = new LinkedList<>();
-            this.syncTabDataImpl(sgTabMaps, jlTabMaps, resultData);
+            //坐标
+            Map<String,Set<String>> coordinateMap = new HashMap<>();
+            this.syncTabDataImpl(sgTabMaps, jlTabMaps, resultData,coordinateMap);
 
             //入库处理
             if (resultData.size() > 0) {
@@ -1753,6 +1828,209 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
                                 filedNames.add(vo.getName());
                             }*/
                         }
+
+                        Map<String, String> stringStringMap = dataMaps.get(initTabName);
+
+                        //CL08水准测量记录表(监理)
+                        if(levelingTableName.equals(initTabName)){
+                            //设计标高
+                            String designedElevationNew = stringStringMap.get(designedElevation);
+                            HashMap<Integer, BigDecimal> designedElevationNewMap = new HashMap<>();
+                            //偏差
+                            String heightDeviationNew = stringStringMap.get(heightDeviation);
+                            HashMap<Integer, BigDecimal> heightDeviationNewMap = new HashMap<>();
+                            //实际标高
+                            String actualElevationNew = stringStringMap.get(actualElevation);
+
+                            //记录数量
+                            Integer rowMin = null;
+                            Integer rowMax = null;
+
+                            for (int i = 0; i < keys.size(); i++) {
+                                if(!Objects.equals(keys.get(i),designedElevationNew) && !Objects.equals(keys.get(i),heightDeviationNew)){
+                                    continue;
+                                }
+
+
+                                String value = values.get(i);
+                                //拆分数据
+                                String[] split1 = value.split("☆");
+
+                                List<String> heightDeviationList = new ArrayList<>();
+                                for (String s : split1) {
+                                    String[] split2 = s.split("_\\^_");
+                                    int rowNum = Integer.parseInt(split2[1].split("_")[0]);
+                                    //获取最大行数
+                                    if(rowMax == null){
+                                        rowMax = rowNum;
+                                    }else if(rowMax < rowNum){
+                                        rowMax = rowNum;
+                                    }
+                                    //获取最小行数
+                                    if(rowMin == null){
+                                        rowMin = rowNum;
+                                    }else if(rowMin > rowNum){
+                                        rowMin = rowNum;
+                                    }
+
+                                    if (keys.get(i).equals(designedElevationNew)) {
+                                        //设计标高
+                                        designedElevationNewMap.put(rowNum, new BigDecimal(split2[0]));
+                                    } else if (keys.get(i).equals(heightDeviationNew)){
+                                        if(StringUtils.isNotEmpty(split2[0])){
+                                            double v = Double.parseDouble(split2[0]);
+                                            //随机+ - 0/1
+                                            Random random = new Random();
+                                            int adjustment = random.nextInt(2);
+                                            if(v > 0){
+                                                v = v - adjustment;
+                                            }else{
+                                                v = v + adjustment;
+                                            }
+
+                                            //高度偏差
+                                            heightDeviationNewMap.put(rowNum, BigDecimal.valueOf(v));
+
+                                            heightDeviationList.add(new BigDecimal(v).setScale(0,RoundingMode.HALF_UP).intValue() + "_^_"+ split2[1]);
+                                        }
+                                    }
+                                }
+                                //设置偏高的值
+                                if(CollectionUtil.isNotEmpty(heightDeviationList)){
+                                    values.set(i, String.join("☆",heightDeviationList));
+                                }
+                            }
+                            if(rowMin==null){
+                                continue;
+                            }
+                            List<String> list = new ArrayList<>();
+
+                            //获取当前key对应的坐标
+                            Set<String> strings = coordinateMap.get(initTabName);
+                            String index = null;
+                            for (String string : strings) {
+                                String[] split = string.split("__");
+                                if(Objects.equals(split[0],actualElevationNew)){
+                                    index = split[1];
+                                }
+                            }
+                            //按照最小行数来计算
+                            for (int i = rowMin; i <= rowMax; i++) {
+                                BigDecimal designed = designedElevationNewMap.get(i);
+                                BigDecimal height = heightDeviationNewMap.get(i);
+
+                                if(designed == null || height == null){
+                                    continue;
+                                }
+                                BigDecimal v = designed.add(height.divide(new BigDecimal(1000)));
+                                //第5列,索引为4
+                                list.add(v.doubleValue() + "_^_"+ i + "_" + index);
+                            }
+                            //未获取到当前key的坐标就不设置值
+                            if(index == null){
+                                continue;
+                            }
+                            //设置实际标高的值
+                            values.set(keys.indexOf(actualElevationNew), String.join("☆",list));
+                        }else if(planePositionTableName.equals(initTabName)){
+                            //CL10平面位置检测记录表(监理)
+                            //差值
+                            String differenceNewX = stringStringMap.get(difference + "X");
+                            HashMap<Integer, BigDecimal> differenceNewXMap = new HashMap<>();
+
+                            String differenceNewY = stringStringMap.get(difference + "Y");
+                            HashMap<Integer, BigDecimal> differenceNewYMap = new HashMap<>();
+
+
+                            String deviationNew = stringStringMap.get(deviation);
+                            //记录数量
+                            Integer rowMin = null;
+                            Integer rowMax = null;
+                            for (int i = 0; i < keys.size(); i++) {
+                                if(!Objects.equals(keys.get(i),differenceNewX) && !Objects.equals(keys.get(i),differenceNewY)){
+                                    continue;
+                                }
+
+                                String value = values.get(i);
+                                //拆分数据
+                                String[] split1 = value.split("☆");
+
+                                List<String> list = new ArrayList<>();
+
+                                for (String s : split1) {
+                                    String[] split2 = s.split("_\\^_");
+                                    int rowNum = Integer.parseInt(split2[1].split("_")[0]);
+                                    //获取最大行数
+                                    if(rowMax == null){
+                                        rowMax = rowNum;
+                                    }else if(rowMax < rowNum){
+                                        rowMax = rowNum;
+                                    }
+                                    //获取最小行数
+                                    if(rowMin == null){
+                                        rowMin = rowNum;
+                                    }else if(rowMin > rowNum){
+                                        rowMin = rowNum;
+                                    }
+                                    if(StringUtils.isNotEmpty(split2[0])){
+                                        Integer v = Integer.parseInt(split2[0]);
+                                        //随机+ - 0/1
+                                        Random random = new Random();
+                                        int adjustment = random.nextInt(2);
+                                        if(v > 0){
+                                            v = v - adjustment;
+                                        }else{
+                                            v = v + adjustment;
+                                        }
+                                        if (keys.get(i).equals(differenceNewX)) {
+                                            //偏差X
+                                            differenceNewXMap.put(rowNum, new BigDecimal(split2[0]));
+                                        } else if (keys.get(i).equals(differenceNewY)){
+                                            //偏差Y
+                                            differenceNewYMap.put(rowNum, BigDecimal.valueOf(v));
+                                        }
+                                        list.add(v + "_^_"+ split2[1]);
+                                    }
+                                }
+                                values.set(i, String.join("☆",list));
+                            }
+                            if(rowMin==null){
+                                continue;
+                            }
+                            List<String> list = new ArrayList<>();
+                            //获取当前key对应的坐标
+                            Set<String> strings = coordinateMap.get(initTabName);
+                            String index = null;
+                            for (String string : strings) {
+                                String[] split = string.split("__");
+                                if(Objects.equals(split[0],deviationNew)){
+                                    index = split[1];
+                                }
+                            }
+                            //按照最小行数来计算
+                            for (int i = rowMin; i <= rowMax; i++) {
+                                BigDecimal x = differenceNewXMap.get(i);
+                                BigDecimal y = differenceNewYMap.get(i);
+
+                                if(x == null || y == null){
+                                    continue;
+                                }
+                                BigDecimal sqrt = sqrt(x.multiply(x).add(y.multiply(y)), 0);
+
+                                //第9列,索引为8
+                                list.add(sqrt.intValue() + "_^_"+ i + "_" + index);
+                            }
+                            //未获取到当前key的坐标就不设置值
+                            if(index == null){
+                                continue;
+                            }
+                            //设置实际标高的值
+                            values.set(keys.indexOf(deviationNew), String.join("☆",list));
+                        }
+
+
+
+
                         if (keys.size() > 0 && values.size() > 0 && keys.size() == values.size()) {
                             //alter SQL(扩容字段长度)
                             StringBuilder exStrBuilder = new StringBuilder();
@@ -1857,6 +2135,32 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
         }
     }
 
+    // 牛顿迭代法实现开平方
+    public  BigDecimal sqrt(BigDecimal value, int precision) {
+        // 检查负数输入
+        if (value.compareTo(BigDecimal.ZERO) < 0) {
+            throw new ArithmeticException("不能对负数开平方");
+        }
+
+        // 精度设置(保留小数位 + 额外2位保证精度)
+        MathContext mc = new MathContext(precision + 2, RoundingMode.HALF_EVEN);
+
+        // 初始值 = value / 2
+        BigDecimal guess = value.divide(BigDecimal.valueOf(2), mc);
+        BigDecimal lastGuess;
+
+        // 牛顿迭代公式:xₙ₊₁ = (xₙ + value/xₙ)/2
+        do {
+            lastGuess = guess;
+            guess = value.divide(guess, mc).add(guess)
+                    .divide(BigDecimal.valueOf(2), mc);
+        } while (guess.subtract(lastGuess).abs().compareTo(
+                BigDecimal.valueOf(1, precision + 1)) > 0); // 精度控制
+
+        // 返回最终结果(精确到指定小数位)
+        return guess.setScale(precision, RoundingMode.HALF_UP);
+    }
+
     /**
      * 构造数据
      *
@@ -1866,7 +2170,7 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
      * @throws Exception
      */
     private void syncTabDataImpl
-    (Map<String, String> sgData, Map<String, String> jlData, List<InsertDataVO> resultData) throws
+    (Map<String, String> sgData, Map<String, String> jlData, List<InsertDataVO> resultData, Map<String,Set<String>> coordinateMap) throws
             Exception {
         for (Map.Entry<String, String> sgTab : sgData.entrySet()) { //质检表
             String[] split = sgTab.getKey().split("---");
@@ -1885,6 +2189,22 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
                 //表的代码名称相同,就复制数据,例如:G10=G10
                 if (nodeNameRe.equals(nodeNameReJL)) {
                     String htmlStringJL = this.getHtmlString(pKeyIdJL);
+
+                    //解析html坐标,生成key与keyName的映射关系
+                    if (StringUtils.isNotEmpty(htmlStringJL)) {
+                        Document doc = Jsoup.parse(htmlStringJL);
+                        Elements select = doc.select("[id]");
+                        HashSet<String> strings = new HashSet<>();
+                        for (Element element : select) {
+                            String id = element.id();
+                            String[] split1 = id.split("__");
+                            String s = split1[1].split("_")[1];
+
+                            strings.add(split1[0] + "__" + s);
+                        }
+                        coordinateMap.put(initTabNameJL, strings);
+                    }
+
                     //获取质检实体表对应数据
                     List<Map<String, Object>> mapsList = jdbcTemplate.queryForList("select * from " + initTabName + " where p_key_id = " + pKeyId);
                     if (mapsList.size() > 0) {