ソースを参照

Merge branch 'refs/heads/feature-import-lihb-20250910' into dev

LHB 6 日 前
コミット
81ea8afdcf

+ 1 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ExcelTabController.java

@@ -1738,6 +1738,7 @@ public class ExcelTabController extends BladeController {
             nodeName = nodeName + "__" + 1;
         }
         wbsTreeContract.setNodeName(nodeName);
+        wbsTreeContract.setSort(wbsTreeContractList2.get(wbsTreeContractList2.size() - 1).getSort() + 1);
         wbsTreeContract.setIsCopeTab(2);
         wbsTreeContract.setIsTabPdf(1); // pdf 不能预览
         wbsTreeContract.setIsBussShow(1); // 是否隐藏表

+ 313 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/WbsTreeContractController.java

@@ -1,5 +1,6 @@
 package org.springblade.manager.controller;
 
+import com.alibaba.fastjson.JSONObject;
 import com.aspose.cells.LoadFormat;
 import com.aspose.cells.LoadOptions;
 import com.aspose.cells.SaveFormat;
@@ -11,6 +12,7 @@ import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
 import com.google.common.collect.Lists;
 import com.spire.xls.FileFormat;
 import com.spire.xls.Worksheet;
+import com.spire.xls.collections.WorksheetsCollection;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiImplicitParams;
@@ -35,6 +37,7 @@ import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.core.boot.ctrl.BladeController;
 import org.springblade.core.log.exception.ServiceException;
 import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.CollectionUtil;
 import org.springblade.core.tool.utils.IoUtil;
 import org.springblade.core.tool.utils.ObjectUtil;
 import org.springblade.core.tool.utils.ResourceUtil;
@@ -55,6 +58,7 @@ import org.springblade.manager.vo.*;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.io.ByteArrayResource;
 import org.springframework.core.io.Resource;
+import org.springframework.dao.DataAccessException;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
@@ -640,6 +644,315 @@ public class WbsTreeContractController extends BladeController {
         return R.data(null, "没有获取到excel中的数据");
     }
 
+
+    /**
+     * 客户端-导入excel数据到对应元素表中(批量)
+     *
+     * @author liuyc
+     * @date 2023年8月29日
+     */
+    @PostMapping("/import-excel-list")
+    @ApiOperationSupport(order = 14)
+    @ApiOperation(value = "客户端-导入excel数据到对应元素表中(批量)", notes = "传入表的pKeyId、excel文件file")
+    public R<Map<String, Object>> importExcelList(@RequestParam Long pKeyId,
+                                                  @RequestPart MultipartFile file) {
+        WbsTreeContract byId = wbsTreeContractServiceImpl.getById(pKeyId);
+        List<String> integers = new ArrayList<>();
+        integers.add("4");
+        integers.add("5");
+        integers.add("6");
+
+        Integer classify = 1;
+        if (byId.getTableOwner() != null && integers.contains(byId.getTableOwner())) {
+            classify = 2;
+        }
+        //查询与当前表及所有复制表
+        List<WbsTreeContract> list = wbsTreeContractServiceImpl.list(Wrappers.<WbsTreeContract>lambdaQuery()
+                .eq(WbsTreeContract::getPId, byId.getPId())
+                .eq(WbsTreeContract::getInitTableName, byId.getInitTableName())
+                .in(WbsTreeContract::getTableOwner, byId.getTableOwner())
+                .orderByAsc(WbsTreeContract::getSort)
+                .orderByAsc(WbsTreeContract::getFullName)
+                .orderByAsc(WbsTreeContract::getCreateTime)
+        );
+        // 查找目标ID的索引
+        int targetIndex = -1;
+
+        //只记录当前这个表及它排序下的表
+        for (int i = 0; i < list.size(); i++) {
+            if (Objects.equals(pKeyId, list.get(i).getPKeyId())) {
+                targetIndex = i;
+                break;
+            }
+        }
+        if (targetIndex != -1) {
+            list = list.subList(targetIndex, list.size());
+        }
+
+        ArrayList<Map<String, Object>> maps = new ArrayList<>();
+
+
+        //日期格式正则
+        String doubleSlashRegex_XG = ".*\\/[^\\/]*\\/.*"; //匹配包含两个斜杠且不相邻的字符串
+        String dateFormatRegex_yyyyMdd = "\\d{4}/\\d{1,2}/\\d{1,2}"; //yyyy/M/dd格式
+        String dateFormatRegex_yyyyMMdd = "\\d{4}/\\d{2}/\\d{2}";   //yyyy/MM/dd格式
+        String dateFormatRegex_chinese = "(\\d{4}年\\d{1,2}月\\d{1,2}日|\\d{4}年\\d{2}月\\d{2}日)"; //“2023年1月1日、2023年01月01日”这两种格式
+        SimpleDateFormat inputDateFormat = new SimpleDateFormat("yyyy/M/dd");
+        SimpleDateFormat outputDateFormat = new SimpleDateFormat("yyyy年MM月dd日");
+
+
+        //创建一个临时html路径
+        Long id = SnowFlakeUtil.getId();
+        String importExcelFilePath = FileUtils.getSysLocalFileUrl();
+        String importExcelTOHtmlPath = importExcelFilePath + "/pdf//" + id + ".html";
+
+        //解析匹配数据(rul_1为临时文件地址,接口执行后删除,用流读取会导致htmlString_2乱码,只能存储本地后再解析)
+        String url_1 = "";
+        //文件转workbook
+        com.spire.xls.Workbook workbook = null;
+
+        try {
+            workbook = new com.spire.xls.Workbook();
+            workbook.loadFromHtml(file.getInputStream());
+            WorksheetsCollection worksheets = workbook.getWorksheets();
+            workbook.saveToFile(importExcelTOHtmlPath, FileFormat.HTML);
+            int size = worksheets.size();
+
+            //获取第一张表的行和列,然后其他表与第一张表的行、列不匹配,就说明表格错误
+            Worksheet worksheet = worksheets.get(0);
+            int lastRow = worksheet.getLastRow();
+            int lastColumn = worksheet.getLastColumn();
+            //排除空表
+            for (int x = 0; x < size; x++) {
+                Worksheet sheet = worksheets.get(x);
+                if(lastRow != sheet.getLastRow() && lastColumn != sheet.getLastColumn()){
+                    worksheets.remove(x);
+                    size = worksheets.size();
+                }
+            }
+            //如果sheet比数据库中表多 则需要添加复制表
+            if (size > list.size()) {
+                //却几张复制几张 并且复制出来的排序要再最后
+                for (int i = 0; i < size - list.size(); i++) {
+                    excelTabController.copeBussTab(pKeyId);
+                }
+
+                list = wbsTreeContractServiceImpl.list(Wrappers.<WbsTreeContract>lambdaQuery()
+                        .eq(WbsTreeContract::getPId, byId.getPId())
+                        .eq(WbsTreeContract::getInitTableName, byId.getInitTableName())
+                        .in(WbsTreeContract::getTableOwner, byId.getTableOwner())
+                        .orderByAsc(WbsTreeContract::getSort)
+                        .orderByAsc(WbsTreeContract::getFullName)
+                        .orderByAsc(WbsTreeContract::getCreateTime)
+                );
+
+                //只记录当前这个表及它排序下的表
+                for (int i = 0; i < list.size(); i++) {
+                    if (Objects.equals(pKeyId, list.get(i).getPKeyId())) {
+                        targetIndex = i;
+                        break;
+                    }
+                }
+                if (targetIndex != -1) {
+                    list = list.subList(targetIndex, list.size());
+                }
+            }
+            if (size > list.size()) {
+                return R.fail("添加复制表失败");
+            }
+
+
+            //获取转换成功后的html路径
+            url_1 = importExcelTOHtmlPath.split("pdf//")[0];
+
+            for (int x = 0; x < size; x++) {
+                //结果集
+                Map<String, String> stringStringMap = new HashMap<>();
+
+
+                WbsTreeContract wbsTreeContract = list.get(x);
+
+                //获取当前表htmlString
+                String htmlString_1 = wbsTreeContractServiceImpl.getHtmlString(String.valueOf(wbsTreeContract.getPKeyId()));
+
+                Worksheet sheet = worksheets.get(x);
+                String excelToHtmlFileUrl = url_1 + "/pdf/" + id + "_files/" + sheet.getName() + ".html";
+                String htmlString_2 = IoUtil.readToString(new FileInputStream(ResourceUtil.getFile(excelToHtmlFileUrl)));
+                //循环遍历解析两张html的tr、td
+                Document doc_1 = Jsoup.parse(htmlString_1); //合同段表的html
+                Document doc_2 = Jsoup.parse(htmlString_2); //导入excel转换的html
+                Elements trElements1 = doc_1.select("table tbody tr");
+                Elements trElements2 = doc_2.select("table tbody tr");
+                for (int i = 0; i < trElements1.size(); i++) {
+                    Element tr1 = trElements1.get(i);
+                    Element tr2 = trElements2.get(i);
+                    //排除电签单元格
+                    Elements tdElements1 = tr1.select("td:not([dqid])");
+                    Elements tdElements2 = tr2.select("td");
+                    for (int j = 0; j < tdElements1.size(); j++) {
+                        Element td1 = tdElements1.get(j);
+                        Element td2 = tdElements2.get(j);
+                        String keyName = getKeyNameFromChildElement(td1);
+                        if (StringUtils.isNotEmpty(keyName)) {
+                            String[] split = keyName.split("__");
+
+                            String divValue = td2.text(); //获取文本值
+                            if (StringUtils.isNotEmpty(divValue)) {
+                                if (parseDateRange(divValue).size() == 2) {
+                                    //判断范围日期
+                                    List<String> dateArr = parseDateRange(divValue);
+                                    String value = stringStringMap.get(split[0]);
+
+                                    String dataValue = "[" + dateArr.get(0) + "," + dateArr.get(1) + "]" + "_^_" + split[1];
+                                    if (value != null) {
+                                        value = value + "☆" + dataValue;
+                                    } else {
+                                        value = dataValue;
+                                    }
+                                    // key_1  1_^_1_1
+                                    stringStringMap.put(split[0], value);
+                                    continue;
+                                }
+                                //判断是否存在两个斜杠,且不在一起,那么视为日期格式
+                                Pattern pattern_XG = Pattern.compile(doubleSlashRegex_XG);
+                                Matcher matcher_XG = pattern_XG.matcher(divValue);
+                                if (matcher_XG.matches()) {
+                                    //判断日期格式yyyy/M/dd、yyyy/MM/dd
+                                    Pattern pattern_yyyyMdd = Pattern.compile(dateFormatRegex_yyyyMdd);
+                                    Pattern pattern_yyyyMMdd = Pattern.compile(dateFormatRegex_yyyyMMdd);
+                                    Matcher matcher_yyyyMdd = pattern_yyyyMdd.matcher(divValue);
+                                    Matcher matcher_yyyyMMdd = pattern_yyyyMMdd.matcher(divValue);
+                                    if (matcher_yyyyMdd.matches()) {
+                                        Date date = inputDateFormat.parse(divValue);
+                                        divValue = outputDateFormat.format(date);
+                                    } else if (matcher_yyyyMMdd.matches()) {
+                                        Date date = inputDateFormat.parse(divValue);
+                                        divValue = outputDateFormat.format(date);
+                                    }
+
+                                } else if (divValue.contains("年") && divValue.contains("月") && divValue.contains("日")) {
+                                    //判断如:“2023年1月1日、2023年01月01日”这两种格式
+                                    Pattern pattern_chinese = Pattern.compile(dateFormatRegex_chinese);
+                                    Matcher matcher_chinese = pattern_chinese.matcher(divValue);
+                                    if (matcher_chinese.matches()) {
+                                        Date date = outputDateFormat.parse(divValue);
+                                        divValue = outputDateFormat.format(date);
+                                    }
+                                }
+                                String value = stringStringMap.get(split[0]);
+
+                                String dataValue = divValue + "_^_" + split[1];
+                                if (value != null) {
+                                    value = value + "☆" + dataValue;
+                                } else {
+                                    value = dataValue;
+                                }
+                                stringStringMap.put(split[0], value);
+                            }
+                        }
+                    }
+                }
+
+                //先查询 如果有 则修改数据
+
+                String selectSql = "select * from " + byId.getInitTableName() + " where p_key_id = " + wbsTreeContract.getPKeyId();
+
+                Map<String, Object> initId = null;
+                try {
+                    List<Map<String, Object>> hashMaps = jdbcTemplate.queryForList(selectSql);
+                    if(CollectionUtil.isNotEmpty(hashMaps)){
+                        initId = hashMaps.get(0);
+                    }
+                } catch (DataAccessException e) {
+                    initId = null;
+                }
+                String sql = null;
+                if (initId != null) {
+                    sql = "update " + byId.getInitTableName() + " set ";
+                    //导入的数据
+                    Set<Map.Entry<String, String>> entries = stringStringMap.entrySet();
+                    StringBuilder sb = new StringBuilder();
+                    Map<String, Object> finalInitId = initId;
+                    entries.forEach(f -> {
+                        //原先是否存在值 是否为☆拼接的多数据
+                        String oldValue = (String) finalInitId.get(f.getKey());
+                        if (StringUtils.isNotEmpty(oldValue)) {
+                            //当前keu坐标与数据的对应关系
+                            HashMap<String, String> newCoordinate = new HashMap<>();
+                            //旧数据中需要保留的数据
+                            List<String> oldRetainData = new ArrayList<>();
+                            //导入的数据
+                            String[] newSp = f.getValue().split("☆");
+                            for (String s : newSp) {
+                                //单个单元格的数据
+                                String[] split1 = s.split("_\\^_");
+                                newCoordinate.put(split1[1], split1[0]);
+                            }
+                            //旧数据
+                            String[] oldSp = oldValue.split("☆");
+                            for (String s : oldSp) {
+                                //单个单元格的数据
+                                String[] split1 = s.split("_\\^_");
+                                //根据旧数据的坐标去新数据中查询
+                                String s1 = newCoordinate.get(split1[1]);
+                                //如果没有查询到就需要当前坐标数据
+                                if (s1 == null) {
+                                    oldRetainData.add(s);
+                                }
+                            }
+                            if (CollectionUtil.isNotEmpty(oldRetainData)) {
+                                f.setValue(f.getValue() + "☆" + StringUtils.join(oldRetainData, "☆"));
+                            }
+                        }
+                        if (StringUtils.isNotEmpty(sb.toString())) {
+                            sb.append(",");
+                        }
+                        sb.append(f.getKey()).append("=").append("'").append(f.getValue()).append("'");
+                    });
+                    sql = sql + sb + "where id = " + initId.get("id");
+                } else {
+                    Set<String> strings = stringStringMap.keySet();
+                    Collection<String> values = stringStringMap.values();
+                    //转换成sql能够使用的字符串
+                    ArrayList<String> strings1 = new ArrayList<>();
+                    values.forEach(f -> {
+                        f = "'" + f + "'";
+                        strings1.add(f);
+                    });
+                    long newPkId = SnowFlakeUtil.getId();
+                    sql = "insert into " + byId.getInitTableName() + " (id,p_key_id," + StringUtils.join(strings, ",") + ") VALUES (" + newPkId + ", " + wbsTreeContract.getPKeyId() + ", " + StringUtils.join(strings1, ",") + ")";
+                }
+
+
+                jdbcTemplate.execute(sql);
+            }
+
+
+            //删除临时文件信息
+            if (deleteFolder(Paths.get(importExcelTOHtmlPath))) {
+                logger.info("执行方法【importExcel】结束,删除临时文件成功!");
+            } else {
+                logger.info("执行方法【importExcel】结束,删除临时文件失败!");
+            }
+            if (StringUtils.isNotEmpty(url_1)) {
+                //删除临时文件夹
+                if (deleteFolderAndContents(Paths.get(url_1 + "/pdf/" + id + "_files"))) {
+                    logger.info("执行方法【importExcel】结束,删除临时文件夹成功!");
+                } else {
+                    logger.info("执行方法【importExcel】结束,删除临时文件夹失败!");
+                }
+            }
+            return R.success("ok");
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        } finally {
+            if (workbook != null) {
+                workbook.dispose();
+            }
+        }
+
+    }
+
     /**
      * 判断日期范围格式数据,以下12种格式
      * 2023-01-01-2023-01-30 或 2023-01-01~2023-01-30