浏览代码

回退后管优化查询速度

cr 2 天之前
父节点
当前提交
c4e7981ce7

+ 166 - 173
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/WbsTreePrivateController.java

@@ -317,208 +317,201 @@ public class WbsTreePrivateController extends BladeController {
         return R.fail("操作失败");
     }
 
+//
+    /**
+     * 查询当前节点下所有表单(根据节点ID查询当前表单)
+     */
     @GetMapping("/get-node-tables")
     @ApiOperationSupport(order = 3)
     @ApiOperation(value = "查询当前节点下所有元素表", notes = "传入父节点id、wbsId、projectId")
-    public R<List<WbsNodeTableVO>> findNodeTableByCondition(
-            @RequestParam("parentId") String parentId,
-            @RequestParam("wbsId") String wbsId,
-            @RequestParam("projectId") String projectId) {
+    public R<List<WbsNodeTableVO>> findNodeTableByCondition(@RequestParam("parentId") String parentId,
+                                                            @RequestParam("wbsId") String wbsId,
+                                                            @RequestParam("projectId") String projectId) {
         List<WbsNodeTableVO> rs = wbsTreePrivateService.selectByNodeTable(parentId, wbsId, projectId);
-        // 仅处理isLinkTable标记(SQL无法处理的逻辑)
-        if (CollectionUtil.isNotEmpty(rs)) {
-            rs.forEach(r -> {
+        if (rs.size() > 0) {
+            /*表单对应的initTableIdMaps*/
+            Set<String> ids = rs.stream().map(WbsNodeTableVO::getId).collect(Collectors.toSet());
+            Map<Long, Long> initTableIdMaps = wbsTreeService.getBaseMapper().selectList(Wrappers.<WbsTree>lambdaQuery()
+                            .select(WbsTree::getInitTableId, WbsTree::getId)
+                            .in(WbsTree::getId, ids))
+                    .stream()
+                    .filter(wbsTree -> wbsTree.getId() != null && wbsTree.getInitTableId() != null)
+                    .collect(Collectors.toMap(WbsTree::getId, WbsTree::getInitTableId));
+
+            /*元素FidSet,统计数量*/
+            Set<Long> formElementFids = new HashSet<>();
+
+            /*initTabId赋值*/
+            for (WbsNodeTableVO r : rs) {
                 if (StringUtil.isBlank(r.getHtmlUrl())) {
                     r.setIsLinkTable(1);
                 }
-            });
-            return R.data(rs);
-        }
-        return R.fail(404, "未查询到数据"); // 200是成功码,失败用404更规范
-    }
+                if (StringUtil.isBlank(r.getInitTableId())) {
 
-    @GetMapping("/get-group-node-tables")
-    @ApiOperationSupport(order = 3)
-    @ApiOperation(value = "查询当前节点下所有元素表并分类", notes = "传入父节点id、wbsId、projectId")
-    public R<List<WbsTreePrivateTableVO>> findAndGroupNodeTableByCondition(
-            @RequestParam("parentId") String parentId,
-            @RequestParam("wbsId") String wbsId,
-            @RequestParam("projectId") String projectId) {
-        // 2. 获取基础数据(已优化SQL,无冗余)
-        R<List<WbsNodeTableVO>> r = findNodeTableByCondition(parentId, wbsId, projectId);
-        List<WbsNodeTableVO> data = r.getData();
-        if (CollectionUtil.isEmpty(data)) {
-            return R.fail(404, "未查询到数据");
-        }
+                    /*提出去,不for循环查询
+                    WbsTree wbsTree = wbsTreeService.getById(r.getId());*/
 
-        // 3. 批量处理HTML解析(核心优化:批量查询→并行处理)
-        processHtmlElementsBatch(data);
+                    Long initTabId = initTableIdMaps.getOrDefault(Long.parseLong(r.getId()), null);
 
-        // 4. 简化分组逻辑(减少重复计算)
-        List<WbsTreePrivateTableVO> list = groupNodeTables(data);
+                    if (initTabId != null) {
+                        r.setInitTableId(String.valueOf(initTabId));
 
-        return R.data(list);
-    }
+                        formElementFids.add(initTabId);
 
-    /**
-     * 批量处理HTML元素校验(解决N+1查询+串行解析)
-     */
-    private void processHtmlElementsBatch(List<WbsNodeTableVO> data) {
-        // 步骤1:批量收集需要查询的initTableId和pKeyId(避免循环内查询)
-        Map<String, WbsNodeTableVO> initTableId2Vo = new HashMap<>();
-        Set<String> pKeyIds = new HashSet<>();
-        for (WbsNodeTableVO f : data) {
-            String htmlUrl = f.getHtmlUrl();
-            String initTableId = f.getInitTableId();
-            if (StringUtil.isNotBlank(htmlUrl) && StringUtils.isNotEmpty(initTableId)) {
-                initTableId2Vo.put(initTableId, f);
-                pKeyIds.add(f.getPKeyId()+"");
-            }
-        }
-        if (initTableId2Vo.isEmpty()) {
-            return;
-        }
+                        /*提出去,不for循环查询
+                        r.setElementTotal(Math.toIntExact(wbsFormElementService.count(
+                                new LambdaQueryWrapper<WbsFormElement>().eq(WbsFormElement::getFId, r.getInitTableId()))));*/
 
-        // 步骤2:批量查询wbsFormElement(替代循环内N+1查询)
-        List<WbsFormElement> wbsFormElements = wbsFormElementService.getBaseMapper().selectList(
-                Wrappers.<WbsFormElement>lambdaQuery()
-                        .in(WbsFormElement::getFId, initTableId2Vo.keySet())
-                        .eq(WbsFormElement::getIsDeleted, 0)
-        );
-        // 构建initTableId→eKey集合的映射
-        Map<String, Set<String>> initTableId2Keys = wbsFormElements.stream()
-                .collect(Collectors.groupingBy(
-                        WbsFormElement::getFId,
-                        Collectors.mapping(WbsFormElement::getEKey, Collectors.toSet())
-                ));
-
-        // 步骤3:批量获取HTML内容(建议对excelHtml结果加本地缓存,比如Caffeine)
-        Map<String, String> pKeyId2Html = new HashMap<>();
-        if (CollectionUtil.isNotEmpty(pKeyIds)) {
-            // 并行获取HTML(如果getExcelHtml是远程调用/耗时操作,并行可提升效率)
-            pKeyIds.parallelStream().forEach(pKeyId -> {
-                try {
-                    R excelHtml = excelTabController.getExcelHtml(Long.parseLong(pKeyId));
-                    if (excelHtml.isSuccess() && excelHtml.getData() != null) {
-                        pKeyId2Html.put(pKeyId, excelHtml.getData().toString());
+                    } else {
+                        r.setInitTableId("");
                     }
-                } catch (Exception e) {
-                    System.out.println("获取HTML失败,pKeyId="+pKeyId); // 增加日志,避免空catch
                 }
-            });
-        }
-
-        // 步骤4:并行解析HTML(CPU密集型操作,并行提升效率)
-        data.parallelStream().forEach(f -> {
-            String htmlUrl = f.getHtmlUrl();
-            String initTableId = f.getInitTableId();
-            if (StringUtil.isBlank(htmlUrl) || StringUtils.isEmpty(initTableId)) {
-                return;
             }
-            // 获取缓存的HTML内容
-            String htmlString = pKeyId2Html.get(f.getPKeyId());
-            if (StringUtil.isEmpty(htmlString)) {
-                return;
-            }
-            // 获取预查询的eKey集合
-            Set<String> keys = initTableId2Keys.getOrDefault(initTableId, Collections.emptySet());
 
-            // Jsoup解析(简化标签选择+批量判断)
-            Document doc = Jsoup.parse(htmlString);
-            String[] tagNames = {"el-input", "el-date-picker", "el-time-picker", "hc-form-select-search",
-                    "hc-table-form-upload", "hc-form-checkbox-group", "el-radio-group", "el-select"};
-            Elements inputs = new Elements();
-            for (String tagName : tagNames) {
-                inputs.addAll(doc.select(tagName));
-            }
+            if (formElementFids.size() > 0) {
+                /*查询所有相关的元素记录*/
+                List<WbsFormElement> wbsFormElements = wbsFormElementService.getBaseMapper().selectList(Wrappers.<WbsFormElement>lambdaQuery()
+                        .select(WbsFormElement::getFId)
+                        .in(WbsFormElement::getFId, formElementFids));
 
-            // 标记是否有错误(只要有一个标签不合法,就标记为1)
-            boolean hasError = inputs.stream().anyMatch(input -> {
-                String id = input.attr("id");
-                if (StringUtils.isEmpty(id)) {
-                    return true;
-                }
-                // 预编译分割逻辑,减少重复split(核心优化)
-                String[] idParts = id.split("__", 2); // 只分割一次
-                if (idParts.length != 2) {
-                    return true;
-                }
-                String keyPart = idParts[0];
-                String coordPart = idParts[1];
-                // 1. 检查keyPart格式:key_+数字
-                if (!keyPart.startsWith("key_") || !StringUtils.isNumber(keyPart.replace("key_", ""))) {
-                    return true;
-                }
-                // 2. 检查coordPart格式:数字_数字
-                String[] coordParts = coordPart.split("_", 2);
-                if (coordParts.length != 2 || !StringUtils.isNumber(coordParts[0]) || !StringUtils.isNumber(coordParts[1])) {
-                    return true;
-                }
-                // 3. 检查key是否存在
-                return !keys.contains(keyPart);
-            });
+                /*elementCountMap分组*/
+                Map<String, Integer> elementCountMap = wbsFormElements.stream()
+                        .collect(Collectors.groupingBy(WbsFormElement::getFId, Collectors.collectingAndThen(Collectors.counting(), Long::intValue)));
 
-            if (hasError) {
-                f.setHtmlElementError(1);
+                /*元素数量赋值*/
+                for (WbsNodeTableVO r : rs) {
+                    if (StringUtil.isNotBlank(r.getInitTableId())) {
+                        r.setElementTotal(elementCountMap.getOrDefault(r.getInitTableId(), 0));
+                    }
+                }
             }
-        });
+
+            return R.data(rs);
+        }
+        return R.fail(200, "未查询到数据");
     }
 
     /**
-     * 简化分组逻辑(减少重复判断
+     * 查询当前节点下所有表单(根据节点ID查询当前表单)
      */
-    private List<WbsTreePrivateTableVO> groupNodeTables(List<WbsNodeTableVO> data) {
+    @GetMapping("/get-group-node-tables")
+    @ApiOperationSupport(order = 3)
+    @ApiOperation(value = "查询当前节点下所有元素表并分类", notes = "传入父节点id、wbsId、projectId")
+    public R<List<WbsTreePrivateTableVO>> findAndGroupNodeTableByCondition(@RequestParam("parentId") String parentId,
+                                                                           @RequestParam("wbsId") String wbsId,
+                                                                           @RequestParam("projectId") String projectId) {
+        R<List<WbsNodeTableVO>> r = findNodeTableByCondition(parentId, wbsId, projectId);
+        List<WbsNodeTableVO> data = r.getData();
         List<WbsTreePrivateTableVO> list = new ArrayList<>();
-        Integer wbsType = data.get(0).getWbsType();
-        if (wbsType == null) {
-            list.add(new WbsTreePrivateTableVO("", data));
-            return list;
-        }
-
-        // 预定义分组规则(避免嵌套if)
-        Function<WbsNodeTableVO, Integer> groupFunction;
-        String[] titles;
-        if (wbsType == 1) {
-            // 施工方/监理方/其他分组
-            groupFunction = vo -> {
-                String tableOwner = vo.getTableOwner();
-                if (StringUtil.isNumeric(tableOwner)) {
-                    int i = Integer.parseInt(tableOwner);
-                    if (i >= 1 && i <= 3) return 1;
-                    if (i >= 4 && i <= 6) return 2;
-                }
-                return 3;
-            };
-            titles = new String[]{"施工方", "监理方", "其他"};
-        } else if (wbsType == 2) {
-            // 报告表/记录表/其他分组
-            groupFunction = vo -> {
-                String tableType = vo.getTableType();
-                if (StringUtil.isNumeric(tableType)) {
-                    int i = Integer.parseInt(tableType);
-                    if (i == 1) return 2;
-                    if (i == 2) return 1;
+        if (data != null && !data.isEmpty()) {
+            //解析html
+            data.forEach(f -> {
+                String htmlUrl = f.getHtmlUrl();
+                String initTableId = f.getInitTableId();
+                if(StringUtil.isNotBlank(htmlUrl) && StringUtils.isNotEmpty(initTableId)){
+                    //获取元素表数据
+                    List<WbsFormElement> wbsFormElements = wbsFormElementService.getBaseMapper().selectList(Wrappers.<WbsFormElement>lambdaQuery()
+                            .eq(WbsFormElement::getFId, initTableId)
+                            .eq(WbsFormElement::getIsDeleted, 0)
+                    );
+
+                    List<String> keys = wbsFormElements.stream().map(WbsFormElement::getEKey).collect(Collectors.toList());
+
+
+                    // 读取html页面信息
+                    String htmlString = "";
+                    //解析html
+                    try {
+                        R excelHtml = excelTabController.getExcelHtml(f.getPKeyId());
+                        htmlString = excelHtml.getData().toString();
+                    } catch (Exception e) {
+                    }
+                    if(StringUtil.isEmpty(htmlString)){
+                        return;
+                    }
+                    // 样式集合
+                    Document doc = Jsoup.parse(htmlString);
+                    //获取所有input标签
+                    //获取所有input标签
+                    String[] tagNames = {"el-input", "el-date-picker", "el-time-picker", "hc-form-select-search",
+                            "hc-table-form-upload", "hc-form-checkbox-group", "el-radio-group", "el-select"};
+                    Elements inputs = new Elements();
+                    for (String tagName : tagNames) {
+                        inputs.addAll(doc.select(tagName));
+                    }
+                    //判断标签是否存在id属性
+                    inputs.forEach(input -> {
+                        String id = input.attr("id");
+                        if(StringUtils.isEmpty(id)){
+                            f.setHtmlElementError(1);
+                            input.attr("htmlElementError", "1");
+                        } else {
+                            /**
+                             * 判断当前元素是否符合格式
+                             * 1、是否存在key_
+                             * 2、是否存在__
+                             * 3、key_后面是否为数字
+                             * 4、__后面是否为坐标
+                             * 5、key是否在元素库中存在
+                             */
+                            if(!id.contains("key_")
+                                    || !id.contains("__")
+                                    || !StringUtils.isNumber(id.split("__")[0].replace("key_",""))
+                                    || !id.split("__")[1].contains("_")
+                                    || !StringUtils.isNumber(id.split("__")[1].split("_")[0])
+                                    || !StringUtils.isNumber(id.split("__")[1].split("_")[1])
+                                    || !keys.contains(id.split("__")[0])
+                            ){
+                                f.setHtmlElementError(1);
+                                input.attr("htmlElementError", "1");
+                            }
+                        }
+                    });
                 }
-                return 3;
-            };
-            titles = new String[]{"报告表", "记录表", "其他"};
-        } else {
-            list.add(new WbsTreePrivateTableVO("", data));
-            return list;
-        }
-
-        // 分组(流式API简化)
-        Map<Integer, List<WbsNodeTableVO>> groupMap = data.stream()
-                .collect(Collectors.groupingBy(groupFunction));
+            });
 
-        // 构建返回列表
-        for (int i = 1; i <= 3; i++) {
-            List<WbsNodeTableVO> voList = groupMap.get(i);
-            if (CollectionUtil.isNotEmpty(voList)) {
-                list.add(new WbsTreePrivateTableVO(titles[i - 1], voList));
+            Integer wbsType = data.get(0).getWbsType();
+            Map<Integer, List<WbsNodeTableVO>> groupMap;
+            if (wbsType != null && wbsType == 1) {
+                groupMap = data.stream().collect(Collectors.groupingBy(vo -> {
+                    String tableOwner = vo.getTableOwner();
+                    if (StringUtil.isNumeric(tableOwner)) {
+                        int i = Integer.parseInt(tableOwner);
+                        if (i > 0 && i <= 3) {
+                            return 1;
+                        } else if (i > 3 && i <= 6) {
+                            return 2;
+                        }
+                    }
+                    return 3;
+                }));
+            } else if (wbsType != null && wbsType == 2) {
+                groupMap = data.stream().collect(Collectors.groupingBy(vo -> {
+                    String tableType = vo.getTableType();
+                    if (StringUtil.isNumeric(tableType)) {
+                        int i = Integer.parseInt(tableType);
+                        if (i == 1 ) {
+                            return 2;
+                        } else if (i == 2 ) {
+                            return 1;
+                        }
+                    }
+                    return 3;
+                }));
+            } else {
+                list.add(new WbsTreePrivateTableVO("", data));
+                return R.data(list);
+            }
+            String[][] titles = {{"施工方", "监理方", "其他"}, {"报告表", "记录表", "其他"}};
+            for (int i = 1; i <= 3; i++) {
+                List<WbsNodeTableVO> wbsNodeTableVOS = groupMap.get(i);
+                if (wbsNodeTableVOS != null && !wbsNodeTableVOS.isEmpty()) {
+                    list.add(new WbsTreePrivateTableVO(titles[wbsType - 1][i - 1], wbsNodeTableVOS));
+                }
             }
+            return R.data(list);
         }
-        return list;
+        return R.fail(200, "未查询到数据");
     }
 
     /**

+ 1 - 1
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreePrivateMapper.java

@@ -35,7 +35,7 @@ public interface WbsTreePrivateMapper extends EasyBaseMapper<WbsTreePrivate> {
 
     List<WbsTree> selectIsTable(Long tableId, String projectId);
 
-    List<WbsNodeTableVO> selectByNodeTable(@Param("parentId")String id, @Param("wbsId")String wbsId, @Param("projectId")String projectId);
+    List<WbsNodeTableVO> selectByNodeTable(String id, String wbsId, String projectId);
 
     void updateDeletedByCondition(String id, String wbsId, String projectId);
     void removeTableByPKeyIdCondition(String pKeyId, String wbsId, String projectId);

+ 32 - 39
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreePrivateMapper.xml

@@ -512,50 +512,43 @@
           AND project_id = #{projectId}
     </select>
     <select id="selectByNodeTable" resultType="org.springblade.manager.vo.WbsNodeTableVO">
-        SELECT
-            wt.p_key_id AS "pKeyId",
-            wt.id AS id,
-            wt.wbs_type AS wbsType,
-            wt.node_name AS tableName,
-            wt.is_buss_show AS isBussShow,
-            IFNULL(IF(LENGTH(TRIM(wt.full_name)) > 0, wt.full_name, wt.node_name), wt.node_name) AS fullName,
-            CASE
-                WHEN wt.table_type IN (1, 9) THEN 1
-                WHEN wt.table_type IN (2, 10) THEN 2
-                ELSE wt.table_type
-                END AS tableType,
-            wt.`status` AS isCreateTable,
-            wt.table_owner AS tableOwner,
-            wt.is_link_table,
-            wt.init_table_name,
-            -- 关联m_wbs_tree获取init_table_id,避免Java层二次查询
-            COALESCE(wt.init_table_id, wt2.init_table_id) AS initTableId,
-            wt.excel_id AS excelId,
-            wt.sort,
-            wt.status,
-            wt.node_type AS nodeType,
-            wt.wbs_type AS wbsType,
-            wt.default_conceal AS defaultConceal,
-            wt.fill_rate AS "fillRate",
-            wt.html_url AS htmlUrl,
-            -- 预统计元素数量,避免Java层重复查询
-            COALESCE(we.element_count, 0) AS elementTotal
+        SELECT wt.p_key_id                                                                          AS "pKeyId",
+               wt.id                                                                                AS id,
+               wt.wbs_type                                                                          AS wbsType,
+               wt.node_name                                                                         AS tableName,
+               wt.is_buss_show                                                                      AS isBussShow,
+               IFNULL(if(length(trim(wt.full_name)) > 0, wt.full_name, wt.node_name), wt.node_name) AS fullName,
+               case
+                   when wt.table_type in (1, 9) then 1
+                   when wt.table_type in (2, 10) then 2
+                   else wt.table_type
+                   end                                                                              as tableType,
+               wt.`status`                                                                          AS isCreateTable,
+               wt.table_owner                                                                       AS tableOwner,
+               wt.is_link_table,
+               wt.init_table_name,
+               wt.init_table_id                                                                     as initTableId,
+               wt.excel_id                                                                          AS excelId,
+               wt.sort,
+               wt.status,
+               wt.node_type                                                                         AS nodeType,
+               wt.wbs_type                                                                          AS wbsType,
+               wt.default_conceal                                                                   AS defaultConceal,
+               wt.fill_rate                                                                         AS "fillRate",
+               wt.html_url                                                                          AS htmlUrl,
+               (SELECT count(1)
+                FROM m_wbs_form_element
+                WHERE f_id = wt.init_table_id
+                  and is_deleted = 0)                                                               AS "elementTotal"
+                , (SELECT tab_ch_name from m_table_info where tab_en_name = wt.init_table_name)     As elementTableName
         FROM m_wbs_tree_private AS wt
-                 -- 左关联m_wbs_tree获取init_table_id(原Java层initTableIdMaps逻辑)
-                 LEFT JOIN m_wbs_tree AS wt2 ON wt.id = wt2.id AND wt2.is_deleted = 0
-            -- 预统计每个init_table_id的元素数量,消除行级子查询
-                 LEFT JOIN (
-            SELECT f_id, COUNT(1) AS element_count
-            FROM m_wbs_form_element
-            WHERE is_deleted = 0
-            GROUP BY f_id
-        ) AS we ON wt.init_table_id = we.f_id
         WHERE wt.type = 2
           AND wt.is_deleted = 0
-          AND wt.parent_id = #{parentId}  -- 原参数写错了!是parentId不是id
+          AND wt.parent_id = #{id}
           AND wt.wbs_id = #{wbsId}
           AND wt.project_id = #{projectId}
-          AND wt.trial_tab_contract_id IS NULL
+          AND wt.trial_tab_contract_id is null
+        -- AND (wt.wbs_type != 2 OR wt.table_type IN (1,2,9,10))
         ORDER BY wt.sort, fullName
     </select>
     <select id="getByCondition" resultType="org.springblade.manager.entity.WbsTreePrivate">