|
|
@@ -0,0 +1,714 @@
|
|
|
+package org.springblade.manager.controller;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
|
|
+import io.swagger.annotations.*;
|
|
|
+import lombok.AllArgsConstructor;
|
|
|
+import org.apache.commons.io.IOUtils;
|
|
|
+import org.apache.commons.lang.StringUtils;
|
|
|
+import org.jetbrains.annotations.NotNull;
|
|
|
+import org.jsoup.Jsoup;
|
|
|
+import org.jsoup.nodes.Document;
|
|
|
+import org.jsoup.nodes.Element;
|
|
|
+import org.jsoup.select.Elements;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+import org.springblade.business.entity.InformationQuery;
|
|
|
+import org.springblade.common.constant.CommonConstant;
|
|
|
+import org.springblade.common.utils.SnowFlakeUtil;
|
|
|
+import org.springblade.core.boot.ctrl.BladeController;
|
|
|
+import org.springblade.core.log.exception.ServiceException;
|
|
|
+import org.springblade.core.mp.support.Condition;
|
|
|
+import org.springblade.core.mp.support.Query;
|
|
|
+import org.springblade.core.secure.utils.AuthUtil;
|
|
|
+import org.springblade.core.tool.api.R;
|
|
|
+import org.springblade.core.tool.utils.IoUtil;
|
|
|
+import org.springblade.core.tool.utils.ResourceUtil;
|
|
|
+import org.springblade.core.tool.utils.StringUtil;
|
|
|
+import org.springblade.manager.dto.ServiceUserDto;
|
|
|
+import org.springblade.manager.entity.*;
|
|
|
+import org.springblade.manager.feign.ExcelTabClient;
|
|
|
+import org.springblade.manager.feign.ExcelTabClientImpl;
|
|
|
+import org.springblade.manager.service.IExcelTabService;
|
|
|
+import org.springblade.manager.service.IWbsTreeContractService;
|
|
|
+import org.springblade.manager.service.InformationImportRecordService;
|
|
|
+import org.springblade.manager.service.impl.WbsTreeContractServiceImpl;
|
|
|
+import org.springblade.manager.util.DataStructureFormatUtils;
|
|
|
+import org.springblade.manager.utils.DuplicateSheetRecognizer;
|
|
|
+import org.springblade.manager.utils.FileUtils;
|
|
|
+import org.springblade.manager.vo.InformationImportRecordVO;
|
|
|
+import org.springblade.system.cache.ParamCache;
|
|
|
+import org.springblade.system.user.feign.IUserClient;
|
|
|
+import org.springframework.beans.BeanUtils;
|
|
|
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
|
|
|
+import org.springframework.jdbc.core.JdbcTemplate;
|
|
|
+import org.springframework.scheduling.annotation.Async;
|
|
|
+import org.springframework.scheduling.annotation.Scheduled;
|
|
|
+import org.springframework.web.bind.annotation.*;
|
|
|
+import org.springframework.web.multipart.MultipartFile;
|
|
|
+
|
|
|
+import java.io.File;
|
|
|
+import java.io.FileInputStream;
|
|
|
+import java.io.FileNotFoundException;
|
|
|
+import java.io.InputStream;
|
|
|
+import java.nio.file.Files;
|
|
|
+import java.nio.file.Path;
|
|
|
+import java.nio.file.Paths;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.util.*;
|
|
|
+import java.util.regex.Matcher;
|
|
|
+import java.util.regex.Pattern;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+import static java.util.stream.Collectors.toMap;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 资料导入及记录查询控制器
|
|
|
+ */
|
|
|
+@RestController
|
|
|
+@AllArgsConstructor
|
|
|
+@RequestMapping("/informationImportRecord")
|
|
|
+@Api(tags = "资料导入及记录查询接口")
|
|
|
+public class InformationImportRecordController extends BladeController {
|
|
|
+
|
|
|
+ private final IExcelTabService excelTabService;
|
|
|
+
|
|
|
+ private final IWbsTreeContractService wbsTreeContractService;
|
|
|
+ private final WbsTreeContractServiceImpl wbsTreeContractServiceImpl;
|
|
|
+ private final ExcelTabClient excelTabClient;
|
|
|
+ private final InformationImportRecordService informationImportRecordService;
|
|
|
+ private final IUserClient userClient;
|
|
|
+ private final JdbcTemplate jdbcTemplate;
|
|
|
+
|
|
|
+ private static final Logger logger = LoggerFactory.getLogger(InformationImportRecordController.class);
|
|
|
+ private static final java.util.concurrent.atomic.AtomicBoolean RUNNING = new java.util.concurrent.atomic.AtomicBoolean(false);
|
|
|
+ private static final java.util.concurrent.ExecutorService IMPORT_EXECUTOR = new java.util.concurrent.ThreadPoolExecutor(
|
|
|
+ Math.max(2, Runtime.getRuntime().availableProcessors()),
|
|
|
+ Math.max(4, Runtime.getRuntime().availableProcessors() * 2),
|
|
|
+ 60L,
|
|
|
+ java.util.concurrent.TimeUnit.SECONDS,
|
|
|
+ new java.util.concurrent.LinkedBlockingQueue<>(200),
|
|
|
+ new java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy()
|
|
|
+ );
|
|
|
+
|
|
|
+
|
|
|
+ @GetMapping("/page")
|
|
|
+ @ApiOperationSupport(order = 1)
|
|
|
+ @ApiOperation(value = "获取资料导入记录")
|
|
|
+ public R<IPage<InformationImportRecord>> page(InformationImportRecordVO record, Query query) {
|
|
|
+ LambdaQueryWrapper<InformationImportRecord> wrapper = Wrappers.lambdaQuery();
|
|
|
+ wrapper.eq(InformationImportRecord::getContractId, record.getContractId());
|
|
|
+ if (StringUtil.hasText(record.getFileName())) {
|
|
|
+ wrapper.like(InformationImportRecord::getFileName, record.getFileName());
|
|
|
+ }
|
|
|
+ if (record.getStatus() != null && (record.getStatus() >= 0 && record.getStatus() <= 3)) {
|
|
|
+ wrapper.eq(InformationImportRecord::getStatus, record.getStatus());
|
|
|
+ }
|
|
|
+ if (record.getUserId() != null && record.getUserId() > 0) {
|
|
|
+ wrapper.eq(InformationImportRecord::getCreateUser, record.getUserId());
|
|
|
+ }
|
|
|
+ if (record.getClassify() != null && (record.getClassify() == 1 || record.getClassify() == 2)) {
|
|
|
+ wrapper.eq(InformationImportRecord::getClassify, record.getClassify());
|
|
|
+ }
|
|
|
+ if (record.getStartTime() != null && record.getEndTime() != null) {
|
|
|
+ if (record.getStartTime().trim().matches("^\\d{4}-\\d{2}-\\d{2}$") && record.getEndTime().trim().matches("^\\d{4}-\\d{2}-\\d{2}$")) {
|
|
|
+ wrapper.between(InformationImportRecord::getCreateTime, record.getStartTime() + " 00:00:00", record.getEndTime() + " 23:59:59");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ wrapper.orderByDesc(InformationImportRecord::getCreateTime);
|
|
|
+ IPage<InformationImportRecord> page = informationImportRecordService.page(Condition.getPage(query), wrapper);
|
|
|
+ List<InformationImportRecord> records = page.getRecords();
|
|
|
+ if (records != null && !records.isEmpty()) {
|
|
|
+ String userIds = records.stream().filter(item -> item.getCreateUser() != null && item.getCreateUser() > 0).map(item -> item.getCreateUser() + "").collect(Collectors.joining(","));
|
|
|
+ List<ServiceUserDto> userList = jdbcTemplate.query("select id as userId, name as userName from blade_user where id in (" + userIds + ")", new BeanPropertyRowMapper<>(ServiceUserDto.class));
|
|
|
+ Map<String, String> map = userList.stream().collect(Collectors.toMap(ServiceUserDto::getUserId, ServiceUserDto::getUserName, (k1, k2) -> k1));
|
|
|
+ records.forEach(item -> {
|
|
|
+ String username = map.get(item.getCreateUser() + "");
|
|
|
+ item.setCreateUserName(username);
|
|
|
+ item.setRemark(item.getRemark() == null ? "" : item.getRemark().split("::")[0]);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return R.data(page);
|
|
|
+ }
|
|
|
+
|
|
|
+ @GetMapping("/users")
|
|
|
+ @ApiOperationSupport(order = 1)
|
|
|
+ @ApiOperation(value = "获取资料导入操作人列表", notes = "传入合同段id,返回 id, name")
|
|
|
+ public R<List<ServiceUserDto>> page(@RequestParam Long contractId) {
|
|
|
+ List<ServiceUserDto> query = jdbcTemplate.query("select distinct b.id as userId, b.name as userName from u_information_import_record a left join blade_user b on a.create_user = b.id where contract_id = " + contractId,
|
|
|
+ new BeanPropertyRowMapper<>(ServiceUserDto.class));
|
|
|
+ return R.data(query);
|
|
|
+ }
|
|
|
+
|
|
|
+ @PostMapping("/import")
|
|
|
+ @ApiOperationSupport(order = 2)
|
|
|
+ @ApiOperation(value = "客户端-导入多sheet excel到对应节点下的表单", notes = "传入节点ID、分类和多sheet excel文件")
|
|
|
+ public R<Object> importNodeExcel(@RequestPart List<MultipartFile> files, @RequestParam Long nodeId, @RequestParam Integer classify) throws Exception {
|
|
|
+ if (files.isEmpty()) {
|
|
|
+ return R.fail("请选择文件");
|
|
|
+ }
|
|
|
+ if (nodeId == null) {
|
|
|
+ return R.fail("请选择节点");
|
|
|
+ }
|
|
|
+ List<WbsTreeContract> query = jdbcTemplate.query("select * from m_wbs_tree_contract where is_deleted = 0 and p_key_id = " + nodeId, new BeanPropertyRowMapper<>(WbsTreeContract.class));
|
|
|
+ if (query.isEmpty()) {
|
|
|
+ return R.fail("请选择节点");
|
|
|
+ }
|
|
|
+ WbsTreeContract wbsTreeContract = query.get(0);
|
|
|
+ long contractId;
|
|
|
+ try {
|
|
|
+ contractId = Long.parseLong(wbsTreeContract.getContractId());
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ return R.fail("未找到对应的合同段id");
|
|
|
+ }
|
|
|
+ if (classify == null || classify < 0 || classify > 2) {
|
|
|
+ return R.fail("请选择所属方");
|
|
|
+ }
|
|
|
+ String localPath = ParamCache.getValue(CommonConstant.SYS_LOCAL_URL);
|
|
|
+ String base = localPath + File.separator + "import" + File.separator;
|
|
|
+ {
|
|
|
+ // 如果文件夹不存在则创建
|
|
|
+ File file1 = new File(base);
|
|
|
+ if (!file1.exists()) {
|
|
|
+ boolean mkdirs = file1.mkdirs();
|
|
|
+ if (!mkdirs) {
|
|
|
+ return R.fail("创建文件夹失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ LocalDateTime now = LocalDateTime.now();
|
|
|
+ List<InformationImportRecord> records = new ArrayList<>();
|
|
|
+ for (MultipartFile file : files) {
|
|
|
+ // 将file保存到本地
|
|
|
+ Long id = SnowFlakeUtil.getId();
|
|
|
+ String filename = file.getOriginalFilename();
|
|
|
+ if (filename == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ InputStream is = file.getInputStream();
|
|
|
+ // 避免重名以及文件名过长的问题
|
|
|
+ String path = base + id + filename.substring(filename.lastIndexOf("."));
|
|
|
+
|
|
|
+ Files.write(Paths.get(path), IOUtils.toByteArray(is));
|
|
|
+
|
|
|
+ // 创建记录
|
|
|
+ InformationImportRecord record = new InformationImportRecord();
|
|
|
+ record.setId(id);
|
|
|
+ record.setNodeId(nodeId);
|
|
|
+ record.setContractId(contractId);
|
|
|
+ record.setClassify(classify);
|
|
|
+ record.setFileName(filename.substring(0, filename.lastIndexOf(".")));
|
|
|
+ record.setFilePath(path);
|
|
|
+ record.setCreateTime(now);
|
|
|
+ record.setCreateUser(AuthUtil.getUserId());
|
|
|
+ records.add(record);
|
|
|
+ }
|
|
|
+ informationImportRecordService.saveBatch(records);
|
|
|
+ importInformationData();
|
|
|
+ return R.data(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 初始化: 匹配节点,创建子节点
|
|
|
+ * @param id 记录ID
|
|
|
+ * @param node 节点
|
|
|
+ */
|
|
|
+ public void init(@NotNull Long id, @NotNull WbsTreeContract node) {
|
|
|
+ InformationImportRecord record = informationImportRecordService.getById(id);
|
|
|
+ if (record == null || record.getStatus() != 0) {
|
|
|
+ logger.info("记录[{}]已经初始化,已跳过", id);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ String name = record.getFileName();
|
|
|
+ String[] split = name.split("》");
|
|
|
+ String lastName = split[split.length - 1];
|
|
|
+ String newName = "";
|
|
|
+ String[] split1 = lastName.split("【");
|
|
|
+ if (split1.length > 1) {
|
|
|
+ lastName = split1[0];
|
|
|
+ newName = split1[1].replace("】", "");
|
|
|
+ }
|
|
|
+ WbsTreeContract target = null;
|
|
|
+ if (split.length > 1) {
|
|
|
+ // 获取节点下的所有子节点
|
|
|
+ Long pId = node.getPKeyId();
|
|
|
+ int i = 0;
|
|
|
+ for (; i < split.length - 1; i++) {
|
|
|
+ List<WbsTreeContract> query = jdbcTemplate.query("select * from m_wbs_tree_contract where is_deleted = 0 and p_id = " + pId + " and full_name = '" + split[i] + "'",
|
|
|
+ new BeanPropertyRowMapper<>(WbsTreeContract.class));
|
|
|
+ if (query.isEmpty() || query.get(0) == null) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ target = query.get(0);
|
|
|
+ pId = target.getPKeyId();
|
|
|
+ if (pId == null ) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (target == null || i < split.length - 2) {
|
|
|
+ informationImportRecordService.updateProcess(record.getId(), null, 3, "节点未找到-客户端::" + split[i], record.getUpdateTime());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ target = node;
|
|
|
+ }
|
|
|
+
|
|
|
+ {
|
|
|
+ // todo 判断target节点下是否有该节点,如果有是否有资料,没有的 监理和施工
|
|
|
+ List<WbsTreeContract> query = jdbcTemplate.query("select * from m_wbs_tree_contract where is_deleted = 0 and p_id = " + target.getPKeyId() + " and full_name = '" + (StringUtil.hasText(newName) ? newName : lastName) + "'",
|
|
|
+ new BeanPropertyRowMapper<>(WbsTreeContract.class));
|
|
|
+ if (!query.isEmpty()) {
|
|
|
+ for (WbsTreeContract wbsTreeContract : query) {
|
|
|
+ List<InformationQuery> informationQueries = jdbcTemplate.query("select * from u_information_query where is_deleted = 0 and contract_id = " + record.getContractId() + " and wbs_id = " + wbsTreeContract.getPKeyId()
|
|
|
+ + " and classify = " + record.getClassify(), new BeanPropertyRowMapper<>(InformationQuery.class));
|
|
|
+ if (informationQueries.isEmpty()) {
|
|
|
+ record.setTargetId(wbsTreeContract.getPKeyId());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (record.getTargetId() != null && record.getTargetId() > 0) {
|
|
|
+ informationImportRecordService.updateProcess(record.getId(), 20, 1, null, record.getUpdateTime());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (target.getIsTypePrivatePid() == null) {
|
|
|
+ informationImportRecordService.updateProcess(record.getId(), null, 3, "节点未找到-后管::" + target.getFullName(), record.getUpdateTime());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ List<WbsTreePrivate> query = jdbcTemplate.query("select * from m_wbs_tree_private where is_deleted = 0 and p_id = " + target.getIsTypePrivatePid() + " and node_name = '" + lastName + "' limit 1",
|
|
|
+ new BeanPropertyRowMapper<>(WbsTreePrivate.class));
|
|
|
+ if (query.isEmpty()) {
|
|
|
+ informationImportRecordService.updateProcess(record.getId(), null, 3, "节点未找到-后管::" + target.getFullName(), record.getUpdateTime());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ informationImportRecordService.updateProcess(record.getId(), 7, 1, null, record.getUpdateTime());
|
|
|
+ WbsTreePrivate wbsTreePrivate = query.get(0);
|
|
|
+ List<WbsTreePrivate> tables = jdbcTemplate.query("select * from m_wbs_tree_private where is_deleted = 0 and p_id = " + wbsTreePrivate.getPKeyId(), new BeanPropertyRowMapper<>(WbsTreePrivate.class));
|
|
|
+
|
|
|
+ // 在target节点下创建子节点及表单
|
|
|
+ Long parentPKeyId = SnowFlakeUtil.getId();
|
|
|
+ Long parentId = SnowFlakeUtil.getId();
|
|
|
+ String ancestors = target.getAncestors() == null ? target.getId() + "" : target.getAncestors() + "," + target.getId();
|
|
|
+ String ancestorsPId = target.getAncestorsPId() == null ? target.getPKeyId() + "" : target.getAncestorsPId() + "," + target.getPKeyId();
|
|
|
+
|
|
|
+ List<WbsTreeContract> saveList = new ArrayList<>();
|
|
|
+ {
|
|
|
+ WbsTreeContract newData = new WbsTreeContract();
|
|
|
+ BeanUtils.copyProperties(wbsTreePrivate, newData);
|
|
|
+
|
|
|
+ //重塑pKeyId、id和parentId
|
|
|
+ newData.setPKeyId(parentPKeyId);
|
|
|
+ newData.setId(parentId);
|
|
|
+ newData.setParentId(target.getId());
|
|
|
+ newData.setPId(target.getPKeyId());
|
|
|
+ newData.setAncestors(ancestors);
|
|
|
+ newData.setAncestorsPId(ancestorsPId);
|
|
|
+
|
|
|
+ //设置合同段等信息
|
|
|
+ newData.setWbsType(target.getWbsType());
|
|
|
+ newData.setContractId(target.getContractId());
|
|
|
+ newData.setContractIdRelation(target.getContractIdRelation());
|
|
|
+ newData.setContractType(target.getContractType());
|
|
|
+ newData.setCreateTime(new Date());
|
|
|
+ newData.setIsTypePrivatePid(wbsTreePrivate.getPKeyId());
|
|
|
+ if (wbsTreePrivate.getType() != null && new Integer("2").equals(wbsTreePrivate.getType())) {
|
|
|
+ newData.setIsBussShow(1);
|
|
|
+ }
|
|
|
+ //获取当前所有复制的节点的最大sort
|
|
|
+ newData.setSort(ObjectUtils.isNotEmpty(wbsTreePrivate.getSort()) ? wbsTreePrivate.getSort() : 0);
|
|
|
+
|
|
|
+ //记录旧ID
|
|
|
+ newData.setOldId(wbsTreePrivate.getId().toString());
|
|
|
+
|
|
|
+ newData.setFullName(StringUtil.hasText(newName) ? newName : lastName);
|
|
|
+
|
|
|
+ saveList.add(newData);
|
|
|
+ }
|
|
|
+
|
|
|
+ //处理数据
|
|
|
+ for (WbsTreePrivate half : tables) {
|
|
|
+ //处理合同段数据
|
|
|
+ WbsTreeContract newData = new WbsTreeContract();
|
|
|
+ BeanUtils.copyProperties(half, newData);
|
|
|
+
|
|
|
+ //重塑pKeyId、id和parentId
|
|
|
+ newData.setPKeyId(SnowFlakeUtil.getId());
|
|
|
+ newData.setId(SnowFlakeUtil.getId());
|
|
|
+ newData.setParentId(parentId);
|
|
|
+ newData.setPId(parentPKeyId);
|
|
|
+ newData.setAncestors(ancestors + "," + parentId);
|
|
|
+ newData.setAncestorsPId(ancestorsPId + "," + parentPKeyId);
|
|
|
+
|
|
|
+ //记录旧ID
|
|
|
+ newData.setOldId(half.getId().toString());
|
|
|
+ //设置合同段等信息
|
|
|
+ newData.setWbsType(target.getWbsType());
|
|
|
+ newData.setContractId(target.getContractId());
|
|
|
+ newData.setContractIdRelation(target.getContractIdRelation());
|
|
|
+ newData.setContractType(target.getContractType());
|
|
|
+ newData.setCreateTime(new Date());
|
|
|
+ newData.setIsTypePrivatePid(half.getPKeyId());
|
|
|
+ if (half.getType() != null && new Integer("2").equals(half.getType())) {
|
|
|
+ if (half.getDefaultConceal() != null && half.getDefaultConceal() == 1) {
|
|
|
+ // 后续如果此表格中有数据再修改成 1
|
|
|
+ newData.setIsBussShow(2);
|
|
|
+ } else {
|
|
|
+ //2023年8月1日14:41:03更改需求,isBussShow默认=1
|
|
|
+ newData.setIsBussShow(1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //获取当前所有复制的节点的最大sort
|
|
|
+ newData.setSort(ObjectUtils.isNotEmpty(half.getSort()) ? half.getSort() : 0);
|
|
|
+
|
|
|
+ //设置名称, 后续根据sheet 名称进行设置
|
|
|
+ newData.setFullName(half.getFullName());
|
|
|
+
|
|
|
+ //设置到保存集合中
|
|
|
+ saveList.add(newData);
|
|
|
+ }
|
|
|
+ wbsTreeContractService.saveBatch(saveList);
|
|
|
+ informationImportRecordService.update(Wrappers.<InformationImportRecord>lambdaUpdate().eq(InformationImportRecord::getId, record.getId())
|
|
|
+ .set(InformationImportRecord::getTargetId, parentPKeyId).set(InformationImportRecord::getProcess, 20));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void importData(@NotNull Long id) {
|
|
|
+ InformationImportRecord record = informationImportRecordService.getById(id);
|
|
|
+ if (record == null || record.getStatus() != 1) {
|
|
|
+ logger.info("记录[{}]已经不存在或者状态错误,已跳过", id);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (record.getTargetId() == null) {
|
|
|
+ informationImportRecordService.updateProcess(record.getId(), null, 3, record.getRemark() + "::找不到目标节点", record.getUpdateTime());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ Path path1 = Paths.get(record.getFilePath());
|
|
|
+ if (!Files.exists(path1)) {
|
|
|
+ logger.info("文件[{}]不存在,已跳过", record.getFilePath());
|
|
|
+ informationImportRecordService.updateProcess(record.getId(), null, 3, "文件不存在", record.getUpdateTime());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try (InputStream is = Files.newInputStream(path1)) {
|
|
|
+ importNodeExcel(is, record);
|
|
|
+ informationImportRecordService.updateProcess(record.getId(), 65, null, null, record.getUpdateTime());
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("文件[{}]读取异常,已跳过", record.getFilePath(), e);
|
|
|
+ informationImportRecordService.updateProcess(record.getId(), null, 3, "文件读取异常", record.getUpdateTime());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void saveAgain(Long id, String projectId) {
|
|
|
+ InformationImportRecord record = informationImportRecordService.getById(id);
|
|
|
+ if (record == null || record.getStatus() != 1) {
|
|
|
+ logger.info("记录[{}]已经不存在或者状态错误,已跳过", id);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (record.getTargetId() == null) {
|
|
|
+ informationImportRecordService.updateProcess(record.getId(), null, 3, record.getRemark() + "::找不到目标节点", record.getUpdateTime());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ excelTabClient.synPDFInfo(record.getContractId() + "", record.getTargetId() + "", record.getClassify() + "", projectId, userClient.getTokenByUser("admin"));
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("生成pdf失败", e);
|
|
|
+ informationImportRecordService.updateProcess(record.getId(), null, 3, record.getRemark() + "::生成pdf失败", record.getUpdateTime());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 检查是否成功
|
|
|
+ List<InformationQuery> query = jdbcTemplate.query("select * from u_information_query where contract_id = " + record.getContractId() + " and wbs_id = " + record.getTargetId() + " and classify = " + record.getClassify(),
|
|
|
+ new BeanPropertyRowMapper<>(InformationQuery.class));
|
|
|
+ if (!query.isEmpty()) {
|
|
|
+ informationImportRecordService.updateProcess(record.getId(), 100, 2, null, record.getUpdateTime());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void importNodeExcel(InputStream is, InformationImportRecord record) throws Exception {
|
|
|
+
|
|
|
+ // 1. 获取节点下所有表单,并建立 sheet名 -> WbsTreeContract 的映射(处理特殊字符)
|
|
|
+ Object[] params;
|
|
|
+ if (record.getClassify() == 1) {
|
|
|
+ params = new Object[]{record.getTargetId(), 1, 2, 3};
|
|
|
+ } else {
|
|
|
+ params = new Object[]{record.getTargetId(), 4, 5, 6};
|
|
|
+ }
|
|
|
+ List<WbsTreeContract> wbsTreeContracts = jdbcTemplate.query(
|
|
|
+ "select * from m_wbs_tree_contract where p_id = ? and is_deleted = 0 and status!=0 and type = 2 and table_owner in (?,?,?) order by sort",
|
|
|
+ new BeanPropertyRowMapper<>(WbsTreeContract.class),
|
|
|
+ params);
|
|
|
+
|
|
|
+ if (wbsTreeContracts.isEmpty()) {
|
|
|
+ informationImportRecordService.updateProcess(record.getId(), null, 3, record.getRemark() + "::没有找到对应的表单数据", record.getUpdateTime());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 2. 加载上传的多sheet Excel文件
|
|
|
+ com.spire.xls.Workbook mainWorkbook = new com.spire.xls.Workbook();
|
|
|
+ try {
|
|
|
+ mainWorkbook.loadFromStream(is);
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("加载Excel文件失败", e);
|
|
|
+ informationImportRecordService.updateProcess(record.getId(), null, 3, record.getRemark() + "::Excel文件解析失败", record.getUpdateTime());
|
|
|
+ return ;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 遍历所有sheet,逐个处理
|
|
|
+ int sheetCount = mainWorkbook.getWorksheets().getCount();
|
|
|
+ // 处理表单名称(与下载时的sheet名处理逻辑一致,确保匹配)
|
|
|
+ Map<String, WbsTreeContract> nodeNameToContractMap = new HashMap<>();
|
|
|
+ for (WbsTreeContract contract : wbsTreeContracts) {
|
|
|
+ String processedNodeName = contract.getNodeName().replaceAll("[\\\\/:*?\"<>|]", "_").trim();
|
|
|
+ nodeNameToContractMap.put(processedNodeName, contract);
|
|
|
+ }
|
|
|
+ if(wbsTreeContracts.size()<sheetCount){
|
|
|
+ for (int i = 0; i < sheetCount; i++) {
|
|
|
+ com.spire.xls.Worksheet sheet = mainWorkbook.getWorksheets().get(i);
|
|
|
+ String sheetName = sheet.getName();
|
|
|
+ String processedSheetName = sheetName.replaceAll("[\\\\/:*?\"<>|]", "_").trim(); // 处理sheet名特殊字符
|
|
|
+ // 1. 识别当前sheet是否为复制表
|
|
|
+ DuplicateSheetRecognizer.DuplicateSheetResult result =
|
|
|
+ DuplicateSheetRecognizer.recognize(processedSheetName);
|
|
|
+ if (result.isDuplicate()) {
|
|
|
+ String originalName = result.getOriginalName();
|
|
|
+ if(nodeNameToContractMap.containsKey(originalName)){
|
|
|
+ WbsTreeContract contract = nodeNameToContractMap.get(originalName);
|
|
|
+ R r = excelTabClient.copeBussTab(contract.getPKeyId(), userClient.getTokenByUser("admin"));
|
|
|
+ if(r.isSuccess()){
|
|
|
+ WbsTreeContract data = (WbsTreeContract) r.getData();
|
|
|
+ nodeNameToContractMap.put(data.getNodeName(), data);
|
|
|
+ sheet.setName(data.getNodeName());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for (int i = 0; i < sheetCount; i++) {
|
|
|
+ com.spire.xls.Worksheet sheet = mainWorkbook.getWorksheets().get(i);
|
|
|
+ String sheetName = sheet.getName();
|
|
|
+ String processedSheetName = sheetName.replaceAll("[\\\\/:*?\"<>|]", "_").trim(); // 处理sheet名特殊字符
|
|
|
+
|
|
|
+ // 匹配对应的表单
|
|
|
+ WbsTreeContract matchedContract = nodeNameToContractMap.get(processedSheetName);
|
|
|
+ if (matchedContract == null) {
|
|
|
+ logger.warn("sheet名[{}]未匹配到任何表单,已跳过", sheetName);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取当前表单的pkeyId
|
|
|
+ String pkeyId = matchedContract.getPKeyId() + "";
|
|
|
+ logger.info("开始处理sheet[{}],对应表单pkeyId[{}]", sheetName, pkeyId);
|
|
|
+
|
|
|
+ // 4. 将当前sheet保存为临时Excel文件(模拟单个文件上传)
|
|
|
+ File tempFile = null;
|
|
|
+ InputStream tempInputStream = null;
|
|
|
+ try {
|
|
|
+ // 创建临时文件
|
|
|
+ tempFile = File.createTempFile("sheet_", ".xlsx");
|
|
|
+ // 创建仅包含当前sheet的新工作簿
|
|
|
+ com.spire.xls.Workbook singleSheetWorkbook = new com.spire.xls.Workbook();
|
|
|
+ singleSheetWorkbook.getWorksheets().clear();
|
|
|
+ singleSheetWorkbook.getWorksheets().addCopy(sheet); // 复制当前sheet到新工作簿
|
|
|
+ singleSheetWorkbook.saveToFile(tempFile.getAbsolutePath(), com.spire.xls.FileFormat.Version2016);
|
|
|
+ singleSheetWorkbook.dispose();
|
|
|
+
|
|
|
+ // 读取临时文件作为输入流,调用单表单导入逻辑
|
|
|
+ tempInputStream = new FileInputStream(tempFile);
|
|
|
+ Map<String, Object> sheetResult = processSingleSheetImport(pkeyId, tempInputStream);
|
|
|
+ if(sheetResult.isEmpty()){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ Map<String, String> dataMap = WbsTreeContractController.getDataMap(sheetResult);
|
|
|
+ for (Map.Entry<String, String> entry : dataMap.entrySet()) {
|
|
|
+ String value = entry.getValue();
|
|
|
+ if (value != null) {
|
|
|
+ value = value.replace("'", "''");
|
|
|
+ entry.setValue(value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ String delSql = "delete from " + matchedContract.getInitTableName() + " where p_key_id=" + matchedContract.getPKeyId();
|
|
|
+ dataMap.put("p_key_id", matchedContract.getPKeyId()+"");
|
|
|
+ String sqlInfo = excelTabService.buildMTableInsertSql(matchedContract.getInitTableName(), dataMap, SnowFlakeUtil.getId(), null, null).toString();
|
|
|
+ jdbcTemplate.execute(delSql);
|
|
|
+ jdbcTemplate.execute(sqlInfo);
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ throw new ServiceException("处理sheet[" + sheetName + "]失败:" + e.getMessage());
|
|
|
+ } finally {
|
|
|
+ // 关闭流并删除临时文件
|
|
|
+ if (tempInputStream != null) {
|
|
|
+ tempInputStream.close();
|
|
|
+ }
|
|
|
+ if (tempFile != null && !tempFile.delete()) {
|
|
|
+ logger.warn("临时文件[{}]删除失败", tempFile.getAbsolutePath());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ mainWorkbook.dispose();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 复用importExcel的核心逻辑,处理单个sheet的导入
|
|
|
+ * 抽取自原importExcel方法,参数改为pkeyId和输入流
|
|
|
+ */
|
|
|
+ private Map<String, Object> processSingleSheetImport(String pkeyId, InputStream inputStream) throws Exception {
|
|
|
+ // 获取当前表htmlString(模板)
|
|
|
+ String htmlString_1 = wbsTreeContractServiceImpl.getHtmlString(pkeyId);
|
|
|
+ if (StringUtils.isEmpty(htmlString_1)) {
|
|
|
+ throw new ServiceException("获取表单[" + pkeyId + "]的html模板失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 结果集
|
|
|
+ Map<String, Object> resultMap = new HashMap<>();
|
|
|
+
|
|
|
+ // 日期格式正则(复用原逻辑)
|
|
|
+ String doubleSlashRegex_XG = ".*\\/[^\\/]*\\/.*";
|
|
|
+ String dateFormatRegex_yyyyMdd = "\\d{4}/\\d{1,2}/\\d{1,2}";
|
|
|
+ String dateFormatRegex_yyyyMMdd = "\\d{4}/\\d{2}/\\d{2}";
|
|
|
+ String dateFormatRegex_chinese = "(\\d{4}年\\d{1,2}月\\d{1,2}日|\\d{4}年\\d{2}月\\d{2}日)";
|
|
|
+ SimpleDateFormat inputDateFormat = new SimpleDateFormat("yyyy/M/dd");
|
|
|
+ SimpleDateFormat outputDateFormat = new SimpleDateFormat("yyyy年MM月dd日");
|
|
|
+
|
|
|
+ // 临时文件路径(复用原逻辑)
|
|
|
+ Long id = SnowFlakeUtil.getId();
|
|
|
+ String importExcelFilePath = FileUtils.getSysLocalFileUrl();
|
|
|
+ String importExcelTOHtmlPath = importExcelFilePath + "/pdf//" + id + ".html";
|
|
|
+
|
|
|
+ com.spire.xls.Workbook workbook = null;
|
|
|
+ try {
|
|
|
+
|
|
|
+ // 导入的excel转换为html(复用原逻辑)
|
|
|
+ workbook = new com.spire.xls.Workbook();
|
|
|
+ workbook.loadFromHtml(inputStream); // 加载单个sheet的输入流
|
|
|
+ workbook.saveToFile(importExcelTOHtmlPath, com.spire.xls.FileFormat.HTML);
|
|
|
+ com.spire.xls.Worksheet sheet = workbook.getWorksheets().get(0);
|
|
|
+
|
|
|
+ // 获取转换后的html路径
|
|
|
+ String url_1 = importExcelTOHtmlPath.split("pdf//")[0];
|
|
|
+ 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.size() > i ? trElements2.get(i) : null;
|
|
|
+ if (tr2 == null) break;
|
|
|
+
|
|
|
+ Elements tdElements1 = tr1.select("td");
|
|
|
+ Elements tdElements2 = tr2.select("td");
|
|
|
+
|
|
|
+ for (int j = 0; j < tdElements1.size(); j++) {
|
|
|
+ Element td1 = tdElements1.get(j);
|
|
|
+ if (td1.attr("dqid").length() > 0) { // 跳过包含dqid的td
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 跳过包含hc-table-form-upload子元素的td
|
|
|
+ if (!td1.select("hc-table-form-upload").isEmpty()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ Element td2 = tdElements2.size() > j ? tdElements2.get(j) : null;
|
|
|
+ if (td2 == null) break;
|
|
|
+
|
|
|
+ String keyName = WbsTreeContractController.getKeyNameFromChildElement(td1); // 复用原方法获取key
|
|
|
+ if (StringUtils.isNotEmpty(keyName)) {
|
|
|
+ String divValue = td2.text();
|
|
|
+ if (StringUtils.isNotEmpty(divValue)) {
|
|
|
+ // 日期范围处理
|
|
|
+ if (WbsTreeContractController.parseDateRange(divValue).size() == 2) {
|
|
|
+ resultMap.put(keyName, WbsTreeContractController.parseDateRange(divValue));
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 日期格式转换(复用原逻辑)
|
|
|
+ Pattern pattern_XG = Pattern.compile(doubleSlashRegex_XG);
|
|
|
+ Matcher matcher_XG = pattern_XG.matcher(divValue);
|
|
|
+ if (matcher_XG.matches()) {
|
|
|
+ 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() || matcher_yyyyMMdd.matches()) {
|
|
|
+ Date date = inputDateFormat.parse(divValue);
|
|
|
+ divValue = outputDateFormat.format(date);
|
|
|
+ }
|
|
|
+ } else if (divValue.contains("年") && divValue.contains("月") && divValue.contains("日")) {
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ resultMap.put(keyName, divValue);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } finally {
|
|
|
+ if (workbook != null) {
|
|
|
+ workbook.dispose();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return resultMap;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @Scheduled(fixedDelay = 1000L * 60 * 10)
|
|
|
+ @Async
|
|
|
+ public void importInformationData() {
|
|
|
+ if (!RUNNING.compareAndSet(false, true)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ List<InformationImportRecord> records = informationImportRecordService.list(Wrappers.<InformationImportRecord>lambdaQuery()
|
|
|
+ .select(InformationImportRecord::getId, InformationImportRecord::getNodeId, InformationImportRecord::getUpdateTime, InformationImportRecord::getProcess)
|
|
|
+ .in(InformationImportRecord::getStatus, 0, 1).last(" order by create_time limit 100"));
|
|
|
+ if (!records.isEmpty()) {
|
|
|
+ for (InformationImportRecord record : records) {
|
|
|
+ IMPORT_EXECUTOR.submit(() -> {
|
|
|
+ try {
|
|
|
+ WbsTreeContract node = wbsTreeContractService.getOne(Wrappers.<WbsTreeContract>lambdaQuery().eq(WbsTreeContract::getPKeyId, record.getNodeId()));
|
|
|
+ if (node == null) {
|
|
|
+ informationImportRecordService.updateProcess(record.getId(), null, 3, "节点未找到-客户端", record.getUpdateTime());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (record.getProcess() <= 25) {
|
|
|
+ init(record.getId(), node);
|
|
|
+ }
|
|
|
+ if (record.getProcess() < 70) {
|
|
|
+ importData(record.getId());
|
|
|
+ }
|
|
|
+ if (record.getProcess() < 100) {
|
|
|
+ saveAgain(record.getId(), node.getProjectId());
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("导入数据失败", e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ List<InformationImportRecord> list = informationImportRecordService.list(Wrappers.<InformationImportRecord>lambdaQuery().select(InformationImportRecord::getId, InformationImportRecord::getFilePath)
|
|
|
+ .eq(InformationImportRecord::getStatus, 2).apply("update_time < DATE_SUB(NOW(), INTERVAL 3 DAY)"));
|
|
|
+ for (InformationImportRecord record : list) {
|
|
|
+ try {
|
|
|
+ Files.deleteIfExists(Paths.get(record.getFilePath()));
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("删除文件失败", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } finally {
|
|
|
+ RUNNING.set(false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|