diff --git a/backend/src/main/java/com/yfd/platform/qgc_data/service/impl/FishDraftDataServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_data/service/impl/FishDraftDataServiceImpl.java index 92fdd607..45c47f12 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_data/service/impl/FishDraftDataServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_data/service/impl/FishDraftDataServiceImpl.java @@ -35,6 +35,9 @@ import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.support.TransactionTemplate; import java.util.*; @@ -86,6 +89,9 @@ public class FishDraftDataServiceImpl extends ServiceImpl queryPageList(DataSourceRequest dataSourceRequest) { Page page = KendoUtil.getPage(dataSourceRequest); @@ -295,12 +301,13 @@ public class FishDraftDataServiceImpl extends ServiceImpl ids) { if (ids == null || ids.isEmpty()) { return false; } String operatorId = SecurityUtils.getUserId(); + Map originalStatusMap = new HashMap<>(); + List succeededIds = new ArrayList<>(); ApprovalMain approvalMain = new ApprovalMain(); approvalMain.setApprovalNo("APR" + System.currentTimeMillis()); @@ -311,19 +318,46 @@ public class FishDraftDataServiceImpl extends ServiceImpl { + approvalMainService.save(approvalMain); + return true; + }); - List unlockedIds = listIdsByLockFlag(ids, 0); - Date submitTime = new Date(); - updateByIdsInBatches(unlockedIds, entity -> { - entity.setApprovalId(approvalMain.getId()); - entity.setStatus("PENDING"); - entity.setSubmitTime(submitTime); - }); + List unlockedDrafts = listDraftsByIdsAndLockFlag(ids, 0); + for (FishDraftData draft : unlockedDrafts) { + originalStatusMap.put(draft.getId(), draft.getStatus()); + } + Date submitTime = new Date(); + for (List batchDrafts : splitList(unlockedDrafts, IN_QUERY_BATCH_SIZE)) { + executeInNewTransaction(() -> { + List batchIds = new ArrayList<>(); + for (FishDraftData batchDraft : batchDrafts) { + batchIds.add(batchDraft.getId()); + } + updateByIdsBatch(batchIds, entity -> { + entity.setApprovalId(approvalMain.getId()); + entity.setStatus("PENDING"); + entity.setSubmitTime(submitTime); + }); + return true; + }); + for (FishDraftData batchDraft : batchDrafts) { + succeededIds.add(batchDraft.getId()); + } + } - approvalLogService.logSubmit(approvalMain.getId(), operatorId, "批量提交草稿,共" + ids.size() + "条"); - return true; + executeInNewTransaction(() -> { + approvalLogService.logSubmit(approvalMain.getId(), operatorId, "批量提交草稿,共" + ids.size() + "条"); + return true; + }); + return true; + } catch (Exception e) { + log.error("批量提交草稿失败", e); + rollbackSubmittedDrafts(approvalMain.getId(), succeededIds, originalStatusMap, e); + return false; + } } private void setUserDataScope(ApprovalMain approvalMain) { @@ -413,7 +447,6 @@ public class FishDraftDataServiceImpl extends ServiceImpl ids, String approveComment) { if (ids == null || ids.isEmpty()) { return false; @@ -422,43 +455,59 @@ public class FishDraftDataServiceImpl extends ServiceImpl dataList = listByIdsInBatches(ids); - Set processedApprovalIds = new HashSet<>(); - List validIds = new ArrayList<>(); - List fpssRList = new ArrayList<>(); - + Map> approvalDraftMap = new LinkedHashMap<>(); for (FishDraftData fishDraftData : dataList) { if ("PENDING".equals(fishDraftData.getStatus())) { - validIds.add(fishDraftData.getId()); - if (fishDraftData.getApprovalId() != null) { - processedApprovalIds.add(fishDraftData.getApprovalId()); - } - SdFpssR fpssR = convertToSdFpssR(fishDraftData, operatorId); - fpssRList.add(fpssR); + String approvalId = StrUtil.blankToDefault(fishDraftData.getApprovalId(), "__NO_APPROVAL__"); + approvalDraftMap.computeIfAbsent(approvalId, key -> new ArrayList<>()).add(fishDraftData); } } - if (!validIds.isEmpty()) { - updateByIdsInBatches(validIds, entity -> { - entity.setStatus("APPROVED"); - entity.setApproveTime(now); - entity.setUpdatedBy(operatorId); - }); - boolean b = sdFpssRService.saveOrUpdateBatch(fpssRList); - log.info("=======================插入数据条数======================="+fpssRList.size()); - for (String approvalId : processedApprovalIds) { - ApprovalMain approvalMain = approvalMainService.getById(approvalId); - approvalLogService.logApprove(approvalId, SecurityUtils.getUserId(), approveComment); - if (approvalMain != null) { - approvalMain.setStatus("APPROVED"); - approvalMain.setApproverId(operatorId); - approvalMain.setApproveTime(now); - approvalMain.setRemark(approveComment); - approvalMainService.updateById(approvalMain); + try { + for (Map.Entry> entry : approvalDraftMap.entrySet()) { + String approvalId = entry.getKey(); + List approvalDrafts = entry.getValue(); + for (List batchDrafts : splitList(approvalDrafts, IN_QUERY_BATCH_SIZE)) { + executeInNewTransaction(() -> { + List batchIds = new ArrayList<>(); + List fpssRList = new ArrayList<>(); + for (FishDraftData batchDraft : batchDrafts) { + batchIds.add(batchDraft.getId()); + fpssRList.add(convertToSdFpssR(batchDraft, operatorId)); + } + updateByIdsBatch(batchIds, entity -> { + entity.setStatus("APPROVED"); + entity.setApproveTime(now); + entity.setUpdatedBy(operatorId); + }); + boolean saved = sdFpssRService.saveOrUpdateBatch(fpssRList, IN_QUERY_BATCH_SIZE); + if (!saved) { + throw new RuntimeException("保存正式表失败"); + } + log.info("=======================插入数据条数======================={}", fpssRList.size()); + return true; + }); + } + if (!"__NO_APPROVAL__".equals(approvalId)) { + executeInNewTransaction(() -> { + ApprovalMain approvalMain = approvalMainService.getById(approvalId); + approvalLogService.logApprove(approvalId, SecurityUtils.getUserId(), approveComment); + if (approvalMain != null) { + approvalMain.setStatus("APPROVED"); + approvalMain.setApproverId(operatorId); + approvalMain.setApproveTime(now); + approvalMain.setRemark(approveComment); + approvalMainService.updateById(approvalMain); + } + return true; + }); } } + return true; + } catch (Exception e) { + log.error("批量审批失败", e); + return false; } - - return true; } private SdFpssR convertToSdFpssR(FishDraftData draft, String operatorId) { @@ -536,7 +585,6 @@ public class FishDraftDataServiceImpl extends ServiceImpl ids, String rejectReason) { if (ids == null || ids.isEmpty()) { return false; @@ -548,39 +596,52 @@ public class FishDraftDataServiceImpl extends ServiceImpl dataList = listByIdsInBatches(ids); - Set processedApprovalIds = new HashSet<>(); - List validIds = new ArrayList<>(); - + Map> approvalDraftMap = new LinkedHashMap<>(); for (FishDraftData fishDraftData : dataList) { if ("PENDING".equals(fishDraftData.getStatus())) { - validIds.add(fishDraftData.getId()); - if (fishDraftData.getApprovalId() != null) { - processedApprovalIds.add(fishDraftData.getApprovalId()); - } + String approvalId = StrUtil.blankToDefault(fishDraftData.getApprovalId(), "__NO_APPROVAL__"); + approvalDraftMap.computeIfAbsent(approvalId, key -> new ArrayList<>()).add(fishDraftData); } } - if (!validIds.isEmpty()) { - updateByIdsInBatches(validIds, entity -> { - entity.setStatus("REJECTED"); - entity.setApproveTime(now); - entity.setUpdatedBy(operatorId); - }); - - for (String approvalId : processedApprovalIds) { - approvalLogService.logReject(approvalId, operatorId, rejectReason); - ApprovalMain approvalMain = approvalMainService.getById(approvalId); - if (approvalMain != null) { - approvalMain.setStatus("REJECTED"); - approvalMain.setApproverId(operatorId); - approvalMain.setApproveTime(now); - approvalMain.setRemark(rejectReason); - approvalMainService.updateById(approvalMain); + try { + for (Map.Entry> entry : approvalDraftMap.entrySet()) { + String approvalId = entry.getKey(); + List approvalDrafts = entry.getValue(); + for (List batchDrafts : splitList(approvalDrafts, IN_QUERY_BATCH_SIZE)) { + executeInNewTransaction(() -> { + List batchIds = new ArrayList<>(); + for (FishDraftData batchDraft : batchDrafts) { + batchIds.add(batchDraft.getId()); + } + updateByIdsBatch(batchIds, entity -> { + entity.setStatus("REJECTED"); + entity.setApproveTime(now); + entity.setUpdatedBy(operatorId); + }); + return true; + }); + } + if (!"__NO_APPROVAL__".equals(approvalId)) { + executeInNewTransaction(() -> { + approvalLogService.logReject(approvalId, operatorId, rejectReason); + ApprovalMain approvalMain = approvalMainService.getById(approvalId); + if (approvalMain != null) { + approvalMain.setStatus("REJECTED"); + approvalMain.setApproverId(operatorId); + approvalMain.setApproveTime(now); + approvalMain.setRemark(rejectReason); + approvalMainService.updateById(approvalMain); + } + return true; + }); } } + return true; + } catch (Exception e) { + log.error("批量驳回失败", e); + return false; } - - return true; } @Override @@ -720,6 +781,36 @@ public class FishDraftDataServiceImpl extends ServiceImpl listDraftsByIdsAndLockFlag(List ids, Integer lockFlag) { + List normalizedIds = normalizeBatchValues(ids); + if (normalizedIds.isEmpty()) { + return Collections.emptyList(); + } + List result = new ArrayList<>(); + for (List batchIds : splitList(normalizedIds, IN_QUERY_BATCH_SIZE)) { + result.addAll(this.list(new LambdaQueryWrapper() + .in(FishDraftData::getId, batchIds) + .eq(FishDraftData::getLockFlag, lockFlag))); + } + return result; + } + + private boolean updateByIdsBatch(List ids, + java.util.function.Consumer entityCustomizer) { + List normalizedIds = normalizeBatchValues(ids); + if (normalizedIds.isEmpty()) { + return false; + } + List batchEntities = new ArrayList<>(normalizedIds.size()); + for (String batchId : normalizedIds) { + FishDraftData entity = new FishDraftData(); + entity.setId(batchId); + entityCustomizer.accept(entity); + batchEntities.add(entity); + } + return this.updateBatchById(batchEntities, IN_QUERY_BATCH_SIZE); + } + private boolean updateByIdsInBatches(List ids, java.util.function.Consumer entityCustomizer) { List normalizedIds = normalizeBatchValues(ids); @@ -728,18 +819,42 @@ public class FishDraftDataServiceImpl extends ServiceImpl batchIds : splitList(normalizedIds, IN_QUERY_BATCH_SIZE)) { - List batchEntities = new ArrayList<>(batchIds.size()); - for (String batchId : batchIds) { - FishDraftData entity = new FishDraftData(); - entity.setId(batchId); - entityCustomizer.accept(entity); - batchEntities.add(entity); - } - updated = this.updateBatchById(batchEntities, IN_QUERY_BATCH_SIZE) || updated; + updated = updateByIdsBatch(batchIds, entityCustomizer) || updated; } return updated; } + private void rollbackSubmittedDrafts(String approvalId, + List succeededIds, + Map originalStatusMap, + Exception originalException) { + try { + for (List batchIds : splitList(normalizeBatchValues(succeededIds), IN_QUERY_BATCH_SIZE)) { + executeInNewTransaction(() -> { + List rollbackEntities = new ArrayList<>(); + for (String batchId : batchIds) { + FishDraftData entity = new FishDraftData(); + entity.setId(batchId); + entity.setApprovalId(null); + entity.setSubmitTime(null); + entity.setStatus(originalStatusMap.get(batchId)); + rollbackEntities.add(entity); + } + return this.updateBatchById(rollbackEntities, IN_QUERY_BATCH_SIZE); + }); + } + executeInNewTransaction(() -> approvalMainService.removeById(approvalId)); + } catch (Exception rollbackException) { + log.error("批量提交草稿回退失败,原始异常: {}", originalException.getMessage(), rollbackException); + } + } + + private T executeInNewTransaction(java.util.function.Supplier action) { + TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager); + transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + return transactionTemplate.execute(status -> action.get()); + } + private List normalizeBatchValues(List values) { if (values == null || values.isEmpty()) { return Collections.emptyList(); diff --git a/backend/src/main/resources/application-devtw.yml b/backend/src/main/resources/application-devtw.yml index 597cd003..609aa2bc 100644 --- a/backend/src/main/resources/application-devtw.yml +++ b/backend/src/main/resources/application-devtw.yml @@ -111,6 +111,19 @@ spring: mvc: pathmatch: matching-strategy: ant_path_matcher + data: + redis: + host: "${REDIS_HOST:172.16.21.142}" + port: "${REDIS_PORT:6379}" + password: "${REDIS_PASSWORD:zny5678}" + database: "${REDIS_DATABASE:15}" + timeout: 10000ms + lettuce: + pool: + max-active: 8 + max-idle: 8 + min-idle: 2 + max-wait: 10000ms servlet: multipart: max-file-size: 300MB