|
@@ -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
|