Jelajahi Sumber

Merge branch 'test' into test-merge

lvy 2 bulan lalu
induk
melakukan
fbc043af16

+ 14 - 3
blade-service/blade-business/src/main/java/org/springblade/business/controller/TaskController.java

@@ -329,11 +329,16 @@ public class TaskController extends BladeController {
             }
 
             //校验当前项目是否为垂直审批
-            List<Task> taskList = taskService.getBaseMapper().selectList(Wrappers.<Task>lambdaQuery().select(Task::getId,Task::getProjectId, Task::getTaskName, Task::getProcessInstanceId, Task::getContractId, Task::getFormDataId).in(Task::getId, Arrays.asList(taskIdArray)));
+            List<String> taskIdList = new ArrayList<>();
+            List<Task> taskList = taskService.getBaseMapper().selectList(Wrappers.<Task>lambdaQuery().select(Task::getId,Task::getProjectId, Task::getTaskName, Task::getProcessInstanceId, Task::getContractId, Task::getFormDataId, Task::getStatus).in(Task::getId, Arrays.asList(taskIdArray)));
             for (Task task : taskList) {
                 if (ObjectUtil.isEmpty(task.getProjectId())) {
                     throw new ServiceException("未获取到任务【" + task.getTaskName() + "】对应的项目信息");
                 }
+                if (task.getStatus() != null && task.getStatus() == 3) {
+                    taskIdList.add(task.getId() + "");
+                    continue;
+                }
                 ProjectInfo projectInfo = jdbcTemplate.query("select approval_type from m_project_info where id = " + task.getProjectId(), new BeanPropertyRowMapper<>(ProjectInfo.class)).stream().findAny().orElse(null);
                 //如果是垂直审批,那么检查当前用户是否符合当前顺序
                 if (projectInfo != null && projectInfo.getApprovalType() != null && new Integer(1).equals(projectInfo.getApprovalType())) {
@@ -369,6 +374,9 @@ public class TaskController extends BladeController {
             List<TaskApprovalVO> taskApprovalVOS = new ArrayList<>();
 
             for (int i = 0, l = taskIdArray.length; i < l; i++) {
+                if (taskIdList.contains(taskIdArray[i])) {
+                    continue;
+                }
                 TaskApprovalVO approvalVO = new TaskApprovalVO();
                 approvalVO.setTaskId(taskIdArray[i]);
                 approvalVO.setParallelProcessInstanceId(parallelProcessInstanceIdArray[i]);
@@ -384,7 +392,7 @@ public class TaskController extends BladeController {
             this.taskService.batchCompleteApprovalTask(taskApprovalVOS);
             Map<String, TaskApprovalVO> taskApprovalVOMap = taskApprovalVOS.stream().collect(Collectors.toMap(TaskApprovalVO::getTaskId, taskApprovalVO -> taskApprovalVO, (o1, o2) -> o1));
             for (Task task : taskList) {
-                if (batchTaskVO.getFlag().equals("NO")) {
+                if (batchTaskVO.getFlag().equals("NO") && task.getStatus() != null && task.getStatus() != 3) {
                     JSONObject json = new JSONObject();
                     json.put("operationObjIds", Func.toStrList(task.getFormDataId()));
                     json.put("operationObjName", "批量废除");
@@ -1233,9 +1241,12 @@ public class TaskController extends BladeController {
         //生成等待批次,任务完成后删除
         List<TaskApprovalVO> taskApprovalVOS = new ArrayList<>();
         taskApprovalVOS.add(taskApprovalVO);
+        Task task = taskService.getOne(Wrappers.<Task>lambdaQuery().eq(Task::getId, taskApprovalVO.getTaskId()));
+        if (task.getStatus() != null && task.getStatus() == 3) {
+            return R.fail("任务已被撤回或者驳回");
+        }
         this.taskService.batchCompleteApprovalTask(taskApprovalVOS);
         if (!taskApprovalVO.isPass()) {
-            Task task = taskService.getBaseMapper().selectOne(Wrappers.<Task>lambdaQuery().select(Task::getProjectId, Task::getContractId, Task::getFormDataId).eq(Task::getId, taskApprovalVO.getTaskId()));
             JSONObject json = new JSONObject();
             json.put("operationObjIds", Func.toStrList(task.getFormDataId()));
             json.put("operationObjName", "批量废除");

+ 8 - 1
blade-service/blade-e-visa/src/main/java/org/springblade/evisa/service/impl/EVDataServiceImpl.java

@@ -335,7 +335,7 @@ public class EVDataServiceImpl implements EVDataService {
                     if (taskApp.getSigType() == 2) {
                         this.jdbcTemplate.execute("update u_entrust_info set sample_status=2,status=" + (taskApp.getSigType() + 1) + ",entrust_e_pdf='" + taskApp.getLastFilePdfUrl() + "' where id=(SELECT wbs_id from u_information_query where id='" + taskApp.getFormDataId() + "')");
                     }
-                    updateSql = "update u_information_query set e_visa_pdf_url='" + taskApp.getLastFilePdfUrl() + "',status=" + taskApp.getSigType() + " where id='" + taskApp.getFormDataId() + "'";
+                    updateSql = "update u_information_query set e_visa_pdf_url='" + taskApp.getLastFilePdfUrl() + "',status=" + taskApp.getSigType() + ",business_time='" + taskApp.getPdfDate() + "' where id='" + taskApp.getFormDataId() + "'";
                 }
                 this.jdbcTemplate.execute(updateSql);
                 System.out.println("u_information_query修改语句:"+updateSql);
@@ -378,6 +378,13 @@ public class EVDataServiceImpl implements EVDataService {
                 String eVisaPdfUrl = map.get("e_visa_pdf_url") + ""; //签字的PDF路径
                 String pdfUrl = map.get("pdf_url") + ""; //合并后的PDF路径
                 String type = map.get("type") + ""; //资料类型,1资料填报,2试验,3首件
+                Object status = map.get("status");
+                if (status != null && status.toString().equals("3")) {
+                     this.jdbcTemplate.execute("delete from u_task_batch where id in(" + taskApp.getId()+")");
+                     RedisTemplate.delete("sign-" + taskApp.getFormDataId());
+                     taskApp.setSigState(2);
+                     return;
+                }
                 taskApp.setPdfDataType(type);
                 if (StringUtils.isNotEmpty(pdfTrialUrlPosition) || StringUtils.isNotEmpty(pdfTrialUrl) || StringUtils.isNotEmpty(eVisaPdfUrl) || StringUtils.isNotEmpty(pdfUrl)) {
                     if ("1".equals(type)) {

+ 34 - 8
blade-service/blade-e-visa/src/main/java/org/springblade/evisa/utils/PDFUtils.java

@@ -1,16 +1,17 @@
 package org.springblade.evisa.utils;
 
 import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDPage;
 import org.apache.pdfbox.text.PDFTextStripper;
 import org.springblade.business.vo.TaskSignInfoVO;
 import org.springblade.common.utils.CommonUtil;
 import org.springblade.core.tool.utils.Func;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStream;
+import java.io.*;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
+import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
@@ -23,7 +24,9 @@ public class PDFUtils {
             PDFTextStripper stripper = new PDFTextStripper();
             String text = stripper.getText(document);
             String[] lines = text.split("[ \\n]+");
-            String regex = "^\\d{4}年\\d{2}月\\d{2}日$";
+            String lastDate = getPdfFirstPageLastDate(document);
+            taskApp.setPdfDate(lastDate);
+            Pattern pattern = Pattern.compile("(\\d{4}[年-]\\d{2}[月-]\\d{2}日?)");
 
             for(int k=0;k<lines.length;k++){
                 String textStr = lines[k];
@@ -41,10 +44,11 @@ public class PDFUtils {
                     if (txt.length() >= 15 && Func.isNumeric(txt)||(Func.isNumeric(txt)&&txt.length()==8&&txt.startsWith("123"))) {
                         eVisaConfigList.add(txt);
                     }
-
-                    Pattern pattern = Pattern.compile(regex);
-                    if(pattern.matcher(txt).matches()){
-                        taskApp.setPdfDate(txt);
+                    if (taskApp.getPdfDate() == null || taskApp.getPdfDate().isEmpty()) {
+                        Matcher matcher = pattern.matcher(txt);
+                        if(matcher.matches()){
+                            taskApp.setPdfDate(matcher.group(1));
+                        }
                     }
                 }
 
@@ -123,4 +127,26 @@ public class PDFUtils {
         }
     }
 
+    public static String getPdfFirstPageLastDate(PDDocument document) throws IOException {
+        PDFTextStripper stripper = new PDFTextStripper();
+        stripper.setStartPage(1);
+        stripper.setEndPage(1);
+        String text = stripper.getText(document);
+        Pattern pattern = Pattern.compile("(\\d{4}[-年.]\r?\n?\\d{2}[-月.]\r?\n?\\d{2}日?)");
+        Matcher matcher = pattern.matcher(text);
+        List<String> dates = new ArrayList<>();
+        while (matcher.find()) {
+            dates.add(matcher.group(1));
+        }
+        if (!dates.isEmpty()) {
+            Optional<String> max = dates.stream().map(item -> {
+                String replace = item.replace("年", "-").replace("月", "-").replace("日", "").replaceAll("\\.", "-");
+                return replace.replaceAll("[\r\n]",  "");
+            }).max(String::compareTo);
+            return max.get();
+        } else {
+            return "";
+        }
+    }
+
 }

+ 16 - 16
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/SignConfigServiceImpl.java

@@ -324,8 +324,7 @@ public class SignConfigServiceImpl extends BaseServiceImpl<SignConfigMapper, Sig
             if (signConfigVOS == null || signConfigVOS.isEmpty()) {
                 return;
             }
-            List<Long> roleIds = new ArrayList<>();
-            List<String> roleNames = new ArrayList<>();
+            Map<Long, String> roleIdNameMap = new HashMap<>();
             signConfigVOS.forEach(signConfigVO -> {
                 List<SignConfigRelation> relations = signConfigVO.getRelations();
                 if (relations != null && !relations.isEmpty()) {
@@ -345,24 +344,25 @@ public class SignConfigServiceImpl extends BaseServiceImpl<SignConfigMapper, Sig
                     List<SignConfigRelation> roles = collect.get(1);
                     if (roles != null && !roles.isEmpty()) {
                         roles.forEach(role -> {
-                            roleIds.add(role.getRelationId());
-                            roleNames.add(role.getRelationName());
+                            roleIdNameMap.put(role.getRelationId(), role.getRelationName());
                         });
                     }
                 }
             });
-            if (!roleIds.isEmpty()) {
-                TextdictInfoVO textdictInfoVO = new TextdictInfoVO();
-                if (vo != null) {
-                    BeanUtil.copy(vo, textdictInfoVO);
-                }
-                textdictInfoVO.setId(null);
-                textdictInfoVO.setColKey(value);
-                textdictInfoVO.setColName(colName);
-                textdictInfoVO.setIsSystem(1);
-                textdictInfoVO.setSigRoleId(StringUtil.join(roleIds, ","));
-                textdictInfoVO.setSigRoleName(StringUtil.join(roleNames, ","));
-                textdictInfoVOS.add(textdictInfoVO);
+            if (!roleIdNameMap.isEmpty()) {
+                roleIdNameMap.forEach((roleId, roleName) -> {
+                    TextdictInfoVO textdictInfoVO = new TextdictInfoVO();
+                    if (vo != null) {
+                        BeanUtil.copy(vo, textdictInfoVO);
+                    }
+                    textdictInfoVO.setId(null);
+                    textdictInfoVO.setColKey(value);
+                    textdictInfoVO.setColName(colName);
+                    textdictInfoVO.setIsSystem(1);
+                    textdictInfoVO.setSigRoleId(roleId + "");
+                    textdictInfoVO.setSigRoleName(roleName);
+                    textdictInfoVOS.add(textdictInfoVO);
+                });
             }
         });
         return textdictInfoVOS;

+ 4 - 8
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/TextdictInfoServiceImpl.java

@@ -108,15 +108,11 @@ public class TextdictInfoServiceImpl extends ServiceImpl<TextdictInfoMapper, Tex
                         if (textdict == null || textdict.isEmpty()) {
                             textdict = textdictList;
                         } else {
-                            Map<String, TextdictInfoVO> map = textdict.stream().collect(Collectors.toMap(TextdictInfoVO::getColKey, TextdictInfoVO -> TextdictInfoVO, (v1, v2) -> v1));
+                            Map<String, Map<String, TextdictInfoVO>> map = textdict.stream().collect(Collectors.groupingBy(TextdictInfoVO::getColKey, Collectors.toMap(TextdictInfoVO::getSigRoleId, v -> v, (v1, v2) -> v1)));
                             List<TextdictInfoVO> collect = textdictList.stream().filter(textdictInfoVO -> {
-                                TextdictInfoVO vo = map.get(textdictInfoVO.getColKey());
-                                if (vo != null && vo.getSigRoleId() != null && !vo.getSigRoleId().isEmpty()) {
-                                    List<String> projectRoleIds = Arrays.asList(vo.getSigRoleId().split(","));
-                                    List<String> systemRoleIds = new ArrayList<>(Arrays.asList(textdictInfoVO.getSigRoleId().split(",")));
-                                    // 如果 projectRoleIds 包含所有  systemRoleIds,则返回 false
-                                    systemRoleIds.removeAll(projectRoleIds);
-                                    return !systemRoleIds.isEmpty();
+                                Map<String, TextdictInfoVO> voMap = map.get(textdictInfoVO.getColKey());
+                                if (voMap != null && !voMap.isEmpty() ) {
+                                    return voMap.get(textdictInfoVO.getSigRoleId()) == null;
                                 }
                                 return true;
                             }).collect(Collectors.toList());

+ 3 - 21
blade-service/blade-manager/src/main/java/org/springblade/manager/utils/PdfAddContextUtils.java

@@ -13,11 +13,11 @@ import com.itextpdf.text.pdf.parser.PdfReaderContentParser;
 import com.itextpdf.text.pdf.parser.RenderListener;
 import com.itextpdf.text.pdf.parser.TextRenderInfo;
 import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellType;
 import org.apache.poi.ss.usermodel.Row;
 import  org.apache.poi.ss.usermodel.Sheet;
 
-import java.io.File;
-import java.io.FileInputStream;
+
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -27,23 +27,6 @@ public class PdfAddContextUtils {
 
     public static void addContextByTitle(String src, String dest, String title, String context,  int fontSize) throws IOException, DocumentException {
 
-        File pdfFile = new File(src);
-        byte[] pdfData = new byte[(int) pdfFile.length()];
-        FileInputStream inputStream = null;
-        try {
-            inputStream = new FileInputStream(pdfFile);
-            inputStream.read(pdfData);
-        } catch (IOException e) {
-            throw e;
-        } finally {
-            if (inputStream != null) {
-                try {
-                    inputStream.close();
-                } catch (IOException e) {
-                    inputStream.close();
-                }
-            }
-        }
         // 读取PDF文件
         PdfReader reader = new PdfReader(src);
         PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
@@ -66,14 +49,13 @@ public class PdfAddContextUtils {
     public static String getExcelFullTitle(org.apache.poi.ss.usermodel.Workbook workbook, String title) {
         Sheet sheet = workbook.getSheetAt(0);
         sheet.setForceFormulaRecalculation(true);
-        int rowNum = sheet.getLastRowNum();
         for (int i = 0; i < 6; i++) {
             Row row = sheet.getRow(i);
             if (row != null) {
                 short cellNum = row.getLastCellNum();
                 for (int j = 0; j < cellNum; j++) {
                     Cell cell = row.getCell(j);
-                    if (cell != null) {
+                    if (cell != null && cell.getCellTypeEnum() == CellType.STRING) {
                         String cellValue = cell.getStringCellValue();
                         if (cellValue != null && !cellValue.isEmpty()) {
                             if (containsAllCharactersInOrder(cellValue, title)) {

+ 268 - 6
blade-service/blade-repair/src/main/java/org/springblade/repair/controller/CheckAndRepairController.java

@@ -6,14 +6,19 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.AllArgsConstructor;
 import org.apache.commons.lang.SystemUtils;
+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.common.utils.SnowFlakeUtil;
 import org.springblade.core.oss.model.BladeFile;
+import org.springblade.core.tool.utils.FileUtil;
+import org.springblade.core.tool.utils.IoUtil;
 import org.springblade.core.tool.utils.ObjectUtil;
-import org.springblade.manager.entity.ExcelTab;
-import org.springblade.manager.entity.WbsTreeContract;
-import org.springblade.manager.entity.WbsTreePrivate;
+import org.springblade.core.tool.utils.StringUtil;
+import org.springblade.manager.entity.*;
 import org.springblade.repair.util.ExcelInfoUtils;
 import org.springblade.repair.util.FileUtils;
 import org.springblade.resource.feign.NewIOSSClient;
@@ -21,19 +26,19 @@ import org.springblade.system.cache.ParamCache;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.transaction.support.TransactionTemplate;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 import org.springblade.manager.feign.ExcelTabClient;
 
+import javax.validation.constraints.NotNull;
 import java.io.*;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.file.StandardCopyOption;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 import java.util.stream.Collectors;
 
 
@@ -418,4 +423,261 @@ public class CheckAndRepairController {
         }
         System.out.println("检查完毕,更新了"+i+"条记录");
     }
+
+
+    private final TransactionTemplate transactionTemplate;
+    @RequestMapping("/checkAndRepairExcelHtmlDefaultValue")
+    @ApiOperation("定时检测修复ExcelHtml")
+    @Scheduled(cron = "00 00 01 * * ?")
+    public void checkAndRepairExcelHtmlDefaultValue() {
+//        String projectSql = "SELECT * from m_project_info WHERE is_deleted = 0 and id != 1904814720589430785";
+        String projectSql = "SELECT * from m_project_info WHERE is_deleted = 0 and id = 1630011899725201410";
+        List<ProjectInfo> projectInfos = jdbcTemplate.query(projectSql, new BeanPropertyRowMapper<>(ProjectInfo.class));
+        projectInfos.forEach(projectInfo -> {
+            String sql = "SELECT html_url from m_wbs_tree_private WHERE html_url is not null and html_url != '' and is_deleted = 0 and project_id = ? group by html_url LIMIT ? offset ?;";
+            long pageSize = 2000L;
+            long offset = 0L;
+            boolean flag = true;
+            while (flag) {
+                List<String> htmlUrls = jdbcTemplate.queryForList(sql, String.class,projectInfo.getId(), pageSize, offset);
+                if (!htmlUrls.isEmpty()) {
+                    for (String htmlUrl : htmlUrls) {
+                        try  {
+                            List<TextdictInfo> textDictInfoDefaultByHtml = new ArrayList<>();
+                            List<TextdictInfo> textDictInfoTipsByHtml = new ArrayList<>();
+                            // 获取html中的 默认值信息和提示信息
+                            getTextDictInfos(htmlUrl, textDictInfoTipsByHtml, textDictInfoDefaultByHtml);
+                            List<WbsTreePrivate> wbsTreePrivates = jdbcTemplate.query("SELECT * from m_wbs_tree_private WHERE is_deleted = 0 and project_id = ? and html_url = ?", new BeanPropertyRowMapper<>(WbsTreePrivate.class),
+                                    projectInfo.getId(), htmlUrl);
+                            // 获取表元素信息
+                            Map<String, Map<String, String>> tableElementInfo = getTableElementInfo(wbsTreePrivates);
+                            for (WbsTreePrivate wbsTreePrivate : wbsTreePrivates) {
+                                List<TextdictInfo> textDictInfoList = jdbcTemplate.query("SELECT * from m_textdict_info WHERE type in (4,5) and is_deleted = 0 and tab_id = " + wbsTreePrivate.getPKeyId() + " and project_id = " + wbsTreePrivate.getProjectId(),
+                                        new BeanPropertyRowMapper<>(TextdictInfo.class));
+                                Map<String, String> map = tableElementInfo.get(wbsTreePrivate.getInitTableName());
+                                Map<String, TextdictInfo> insertTextDictInfoMaps = new HashMap<>();
+                                List<TextdictInfo> updateHtmlTextDictInfos = new ArrayList<>();
+                                if (textDictInfoList.isEmpty()) {
+                                    createTextDictInfos(wbsTreePrivate, textDictInfoTipsByHtml, map, insertTextDictInfoMaps, 5, "提示信息");
+                                    createTextDictInfos(wbsTreePrivate, textDictInfoDefaultByHtml, map, insertTextDictInfoMaps, 4, "默认值");
+                                } else {
+                                    // 去重并保留id最大的
+                                    Map<String, TextdictInfo> tempMap = new HashMap<>();
+                                    textDictInfoList.forEach(info -> {
+                                        if (info.getColKey() == null || info.getColKey().isEmpty()) {
+                                            return;
+                                        }
+                                        TextdictInfo temp = tempMap.get(info.getColKey() + "_" + info.getType());
+                                        if (temp == null || info.getId() > temp.getId()) {
+                                            tempMap.put(info.getColKey() + "_" + info.getType(), info);
+                                        }
+                                    });
+                                    // 与html中的进行对比, 保留数据库中的值
+                                    textDictInfoDefaultByHtml.forEach(info -> {
+                                        TextdictInfo temp = tempMap.get(info.getColKey() + "_" + info.getType());
+                                        if (temp != null) {
+                                            if (!temp.getSigRoleName().equals(info.getSigRoleName())) {
+                                                // 更新html中的值
+                                                temp.setColName(info.getColName());
+                                                info.setSigRoleName(temp.getSigRoleName());
+                                                updateHtmlTextDictInfos.add(temp);
+                                            }
+                                            tempMap.remove(info.getColKey() + "_" + info.getType());
+                                        }
+                                        TextdictInfo textdictInfo = createTextDictInfo(wbsTreePrivate, map, 4, "默认值", info);
+                                        insertTextDictInfoMaps.put(textdictInfo.getColKey() + "_" + textdictInfo.getType(), textdictInfo);
+                                    });
+                                    textDictInfoTipsByHtml.forEach(info -> {
+                                        TextdictInfo temp = tempMap.get(info.getColKey() + "_" + info.getType());
+                                        if (temp != null) {
+                                            if (!temp.getSigRoleName().equals(info.getSigRoleName())) {
+                                                // 更新html中的值
+                                                temp.setColName(info.getColName());
+                                                info.setSigRoleName(temp.getSigRoleName());
+                                                updateHtmlTextDictInfos.add(temp);
+                                            }
+                                            tempMap.remove(info.getColKey() + "_" + info.getType());
+                                        }
+                                        TextdictInfo textdictInfo = createTextDictInfo(wbsTreePrivate, map, 5, "提示信息", info);
+                                        insertTextDictInfoMaps.put(textdictInfo.getColKey() + "_" + textdictInfo.getType(), textdictInfo);
+                                    });
+                                    if (!tempMap.isEmpty()) {
+                                        tempMap.forEach((key, value) -> {
+                                            if (value.getType() == 4) {
+                                                TextdictInfo textdictInfo = createTextDictInfo(wbsTreePrivate, map, 4, "默认值", value);
+                                                insertTextDictInfoMaps.put(textdictInfo.getColKey() + "_" + textdictInfo.getType(), textdictInfo);
+                                            } else if (value.getType() == 5) {
+                                                TextdictInfo textdictInfo = createTextDictInfo(wbsTreePrivate, map, 5, "提示信息", value);
+                                                insertTextDictInfoMaps.put(textdictInfo.getColKey() + "_" + textdictInfo.getType(), textdictInfo);
+                                            }
+                                            updateHtmlTextDictInfos.add(value);
+                                        });
+                                    }
+                                }
+                                String replace;
+                                if (!updateHtmlTextDictInfos.isEmpty()) {
+                                    InputStream fileInputStream = FileUtils.getInputStreamByUrl(wbsTreePrivate.getHtmlUrl());
+                                    String htmlString = IoUtil.readToString(fileInputStream);
+                                    Document doc = Jsoup.parse(htmlString);
+                                    updateHtmlTextDictInfos.forEach(textdictInfo -> {
+                                        Element element = doc.getElementById(textdictInfo.getColKey());
+                                        if (element != null) {
+                                            element.attr("placeholder", textdictInfo.getColName());
+                                            if (textdictInfo.getType() == 4) {
+                                                element.attr("defText", textdictInfo.getSigRoleName());
+                                            } else if (textdictInfo.getType() == 5) {
+                                                Element parent = element.parent();
+                                                // 判断 parent 是否是el-tooltip
+                                                if (parent.tagName().equals("el-tooltip")) {
+                                                    parent.attr("content", textdictInfo.getSigRoleName());
+                                                } else {
+                                                    String lastHtml = " <el-tooltip content='" + textdictInfo.getSigRoleName() + "' placement='top' effect='customized'>" + parent.html() + "</el-tooltip>";
+                                                    parent.empty().append(lastHtml);
+                                                }
+                                            }
+                                        }
+                                    });
+                                    String url = wbsTreePrivate.getHtmlUrl();
+                                    File writeFile = new File(url);
+                                    FileUtil.writeToFile(writeFile, doc.html(), Boolean.parseBoolean("UTF-8"));
+                                    String str1 = url.replace("Desktop//privateUrl", "Desktop/privateUrl");
+                                    replace = str1.replace("\\", "\\\\");
+                                } else {
+                                    replace = null;
+                                }
+                                transactionTemplate.execute( status -> {
+                                    if (!insertTextDictInfoMaps.isEmpty()) {
+                                        // 使用jdbcTemplate批量插入
+                                        jdbcTemplate.batchUpdate("insert into m_textdict_info_copy3 (id,name,type,tab_id,col_key,col_name,sig_role_id,sig_role_name,pyzbx,pyzby,excel_id,project_id,is_deleted,time_col_key,time_name,time_state) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
+                                                insertTextDictInfoMaps.values(),
+                                                insertTextDictInfoMaps.values().size(), (ps, textdictInfo) -> {
+                                                    ps.setLong(1, textdictInfo.getId());
+                                                    ps.setString(2, textdictInfo.getName());
+                                                    ps.setInt(3, textdictInfo.getType());
+                                                    ps.setString(4, textdictInfo.getTabId());
+                                                    ps.setString(5, textdictInfo.getColKey());
+                                                    ps.setString(6, textdictInfo.getColName());
+                                                    ps.setString(7, textdictInfo.getSigRoleId());
+                                                    ps.setString(8, textdictInfo.getSigRoleName());
+                                                    ps.setDouble(9, 0);
+                                                    ps.setDouble(10, 0);
+                                                    ps.setString(11, textdictInfo.getExcelId());
+                                                    ps.setString(12, textdictInfo.getProjectId());
+                                                    ps.setInt(13, 0);
+                                                    ps.setString(14, textdictInfo.getTimeColKey());
+                                                    ps.setString(15, textdictInfo.getTimeName());
+                                                    ps.setInt(16, 0);
+                                                }
+                                        );
+                                    }
+                                    if (replace != null) {
+                                        String updateSqlP = "update m_wbs_tree_private_copy6 set html_url = '" + replace + "' where p_key_id = " + wbsTreePrivate.getPKeyId() + " and project_id = " + wbsTreePrivate.getProjectId();
+                                        jdbcTemplate.execute(updateSqlP);
+                                    }
+                                    if (!textDictInfoList.isEmpty()) {
+                                        List<Long> ids = textDictInfoList.stream().map(TextdictInfo::getId).collect(Collectors.toList());
+                                        jdbcTemplate.execute("update  m_textdict_info_copy3 set is_deleted = 2 where  id in (" + StringUtil.join(ids, ",") + ")");
+                                    }
+                                    return true;
+                                });
+                            }
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                        }
+                    }
+                } else {
+                    flag = false;
+                }
+                offset  += pageSize;
+            }
+        });
+    }
+    private static void createTextDictInfos(WbsTreePrivate wbsTreePrivate, List<TextdictInfo> textDictInfos, Map<String, String> map, Map<String, TextdictInfo> insertTextDictInfoMaps, int type, String name) {
+        if (!textDictInfos.isEmpty()) {
+            for (TextdictInfo textdictInfo : textDictInfos) {
+                TextdictInfo saveTextdictInfo = createTextDictInfo(wbsTreePrivate, map, type, name, textdictInfo);
+                insertTextDictInfoMaps.put(saveTextdictInfo.getColKey() + "_" + saveTextdictInfo.getType(), saveTextdictInfo);
+            }
+        }
+    }
+    @NotNull
+    private static TextdictInfo createTextDictInfo(WbsTreePrivate wbsTreePrivate, Map<String, String> map, int type, String name, TextdictInfo textdictInfo) {
+        TextdictInfo saveTextdictInfo = new TextdictInfo();
+        saveTextdictInfo.setColKey(textdictInfo.getColKey());
+        saveTextdictInfo.setColName(textdictInfo.getColName());
+        saveTextdictInfo.setSigRoleName(textdictInfo.getSigRoleName());
+        saveTextdictInfo.setId(SnowFlakeUtil.getId());
+        saveTextdictInfo.setTabId(wbsTreePrivate.getPKeyId() + "");
+        saveTextdictInfo.setType(type);
+        saveTextdictInfo.setName(name);
+        saveTextdictInfo.setExcelId(wbsTreePrivate.getExcelId() + "");
+        saveTextdictInfo.setProjectId(wbsTreePrivate.getProjectId());
+        if (map != null) {
+            String s = map.get(saveTextdictInfo.getColKey().split("__")[0]);
+            if (s != null && !s.trim().isEmpty()) {
+                saveTextdictInfo.setColName(s);
+            }
+        }
+        return saveTextdictInfo;
+    }
+    private Map<String, Map<String, String>> getTableElementInfo(List<WbsTreePrivate> wbsTreePrivates) {
+        String inSql = wbsTreePrivates.stream().map(e -> "'" + e.getInitTableName() + "'").distinct().collect(Collectors.joining(","));
+        List<TableInfo> tableInfos = jdbcTemplate.query("SELECT id, tab_en_name from m_table_info  where tab_en_name in (" + inSql + ")", new BeanPropertyRowMapper<>(TableInfo.class));
+        if (tableInfos.isEmpty()) {
+            return new HashMap<>();
+        }
+        Map<String, String> map = tableInfos.stream().collect(Collectors.toMap(tableInfo -> tableInfo.getId() + "", TableInfo::getTabEnName));
+        List<WbsFormElement> wbsFormElementList = jdbcTemplate.query("SELECT f_id,e_key,e_name from m_wbs_form_element WHERE f_id in (" + StringUtil.join(map.keySet(), ",") + ")", new BeanPropertyRowMapper<>(WbsFormElement.class));
+        // 将 initTableNames 与 wbsFormElementList 关联
+        return wbsFormElementList.stream().peek(item -> item.setFId(map.get(item.getFId())))
+                .collect(Collectors.groupingBy(WbsFormElement::getFId, Collectors.toMap(WbsFormElement::getEKey, WbsFormElement::getEName, (v1, v2) -> v1)));
+    }
+    private static void getTextDictInfos(String htmlUrl, List<TextdictInfo> textDictInfoTips, List<TextdictInfo> textDictInfoDefault) throws Exception {
+        InputStream fileInputStream = FileUtils.getInputStreamByUrl(htmlUrl);
+        String htmlString = IoUtil.readToString(fileInputStream);
+        Document doc = Jsoup.parse(htmlString);
+        Element table = doc.select("table").first();
+        Elements trs = table.select("tr");
+        trs.forEach(tr -> {
+            Elements td = tr.select("td");
+            for (Element element : td) {
+                Elements tooltips = element.select("el-tooltip");
+                getTextDictInfo(tooltips, "content", textDictInfoTips);
+                Elements inputs = element.select("el-input");
+                getTextDictInfo(inputs, "deftext", textDictInfoDefault);
+            }
+        });
+    }
+    private static void getTextDictInfo(Elements elements, String attrName, List<TextdictInfo> textDictInfos) {
+        if (!elements.isEmpty()) {
+            elements.forEach(element -> {
+                String content = element.attr(attrName);
+                if (content != null && !content.trim().isEmpty()) {
+                    String keyname = element.children().attr("keyname");
+                    String placeholder = element.children().attr("placeholder");
+                    if (keyname == null || !keyname.trim().isEmpty()) {
+                        String html = element.html();
+                        keyname = getHtmlAttrValue(html, "keyname");
+                        placeholder = getHtmlAttrValue(html, "placeholder");
+                    }
+                    if (keyname != null) {
+                        TextdictInfo info = new TextdictInfo();
+                        info.setColKey(keyname);
+                        info.setColName(placeholder);
+                        info.setSigRoleName(content);
+                        textDictInfos.add(info);
+                    }
+                }
+            });
+        }
+    }
+    private static String getHtmlAttrValue(String html, String attr) {
+        int index = html.indexOf(attr);
+        if (index > 0) {
+            int start = attr.length() + index + 1;
+            char c = html.charAt(start);
+            return html.substring(start + 1, html.indexOf(c, start + 1));
+        }
+        return null;
+    }
 }

+ 48 - 3
blade-service/blade-user/src/main/java/org/springblade/system/user/service/impl/UserServiceImpl.java

@@ -792,7 +792,7 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implement
                         long startTime = System.currentTimeMillis();
 //                        List<NodeVO> nodeVOList = distinctNodesAll.stream().map(this::convertToNodeVO).collect(Collectors.toList());
 //                        Map<Long, NodeVO> nodeVOMap = nodeVOList.stream().collect(Collectors.toMap(NodeVO::getId, vo -> vo, (existing, replacement) -> existing));
-                        List<NodeVO> treeNodeVOList = this.buildNodeTreeByStream(distinctNodesAll, lowestNodesMap);
+                        List<NodeVO> treeNodeVOList = this.buildNodeTreeByStream1(distinctNodesAll, lowestNodesMap);
 //                        NodeVO.calculateStatusToDFS(treeNodeVOList, nodeVOMap);
                         Map<Long, Integer> nodeColorStatusMap = new HashMap<>();
                         NodeVO.calculateStatusToDFS1(treeNodeVOList, nodeColorStatusMap);
@@ -935,7 +935,7 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implement
 
 //                                List<NodeVO> nodeVOList = distinctNodesAll.stream().map(this::convertToNodeVO).collect(Collectors.toList());
 //                                Map<Long, NodeVO> nodeVOMap = nodeVOList.stream().collect(Collectors.toMap(NodeVO::getId, vo -> vo, (existing, replacement) -> existing));
-                                List<NodeVO> treeNodeVOList = this.buildNodeTreeByStream(distinctNodesAll, lowestNodesMap);
+                                List<NodeVO> treeNodeVOList = this.buildNodeTreeByStream1(distinctNodesAll, lowestNodesMap);
 //                                NodeVO.calculateStatusToDFS(treeNodeVOList, nodeVOMap);
 //                                List<NodeVO> nodeVOS = this.flattenTree(treeNodeVOList);
 //                                Map<Long, Integer> nodeColorStatusMap = nodeVOS.stream().collect(Collectors.toMap(NodeVO::getPKeyId, NodeVO::getStatus, (existing, replacement) -> existing));
@@ -1512,7 +1512,7 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implement
                 })
                 .collect(Collectors.toList());
         List<Long> collect = collectedNodes.stream()
-                .map(WbsTreeContractLazyVO::getParentId).filter(Objects::nonNull).distinct()
+                .map(WbsTreeContractLazyVO::getParentId).filter(Objects::nonNull)
                 .collect(Collectors.toList());
         if (!collect.isEmpty()) {
             result.addAll(collectedNodes);
@@ -1575,6 +1575,51 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implement
         return result;
     }
 
+    /**
+     * 构造树形结构数据 (解决节点颜色问题)
+     *
+     * @param distinctNodesAll 去重后所有节点数据
+     * @return
+     */
+    public List<NodeVO> buildNodeTreeByStream1(List<WbsTreeContractLazyVO> distinctNodesAll,
+                                              Map<Long, WbsTreeContractLazyVO> lowestNodesMap) {
+        List<WbsTreeContractLazyVO> list = distinctNodesAll.stream().filter(f->f.getParentId()!=null).filter(f -> f.getParentId().equals(0L)).collect(Collectors.toList());
+        Map<Long, List<WbsTreeContractLazyVO>> map = distinctNodesAll.stream().filter(f->f.getParentId()!=null).collect(Collectors.groupingBy(WbsTreeContractLazyVO::getParentId));
+        Map<Long, NodeVO> nodeVOMap = new HashMap<>();
+        return recursionFnNodeTree(list, map, lowestNodesMap,nodeVOMap);
+    }
+
+    public List<NodeVO> recursionFnNodeTree
+            (List<WbsTreeContractLazyVO> list, Map<Long, List<WbsTreeContractLazyVO>> map,
+             Map<Long, WbsTreeContractLazyVO> lowestNodesMap, Map<Long, NodeVO> nodeVOMap) {
+        List<NodeVO> result = new ArrayList<>();
+        for (WbsTreeContractLazyVO vo : list) {
+            if (vo.getHasChildren().equals(0)) {
+                WbsTreeContractLazyVO lowestNodeVO = lowestNodesMap.getOrDefault(vo.getPKeyId(), null);
+                if (lowestNodeVO != null && lowestNodeVO.getColorStatus() != null) {
+                    //最底层颜色初始化
+                    vo.setColorStatus(lowestNodeVO.getColorStatus());
+                }
+            } else {
+                //非最底层节点,颜色默认=1黑色
+                vo.setColorStatus(1);
+            }
+            //转换为NodeVO
+            NodeVO nodeVO = convertToNodeVO(vo);
+            nodeVOMap.put(nodeVO.getPKeyId(), nodeVO);
+            List<WbsTreeContractLazyVO> childrenList = map.get(vo.getId());
+            if (childrenList != null && !childrenList.isEmpty()) {
+                List<WbsTreeContractLazyVO> collect = childrenList.stream().filter(child -> !nodeVOMap.containsKey(child.getPKeyId()))
+                        .collect(Collectors.toList());
+                if (!collect.isEmpty()) {
+                    nodeVO.setChildren(recursionFnNodeTree(collect, map, lowestNodesMap, nodeVOMap));
+                }
+            }
+            result.add(nodeVO);
+        }
+        return result;
+    }
+
     /**
      * 树形层级结构转为普通List
      *