diff --git a/src/main/java/com/gxwebsoft/approval/mapper/xml/ApprovalExportMapper.xml b/src/main/java/com/gxwebsoft/approval/mapper/xml/ApprovalExportMapper.xml index 4fab8e7..4d2e824 100644 --- a/src/main/java/com/gxwebsoft/approval/mapper/xml/ApprovalExportMapper.xml +++ b/src/main/java/com/gxwebsoft/approval/mapper/xml/ApprovalExportMapper.xml @@ -18,7 +18,7 @@ i.approve_time, i.archive_time, i.archivist_name, - i.title, + COALESCE(i.title, f.name, co.title) AS title, f.implement_org, f.fee, f.service_content, diff --git a/src/main/java/com/gxwebsoft/approval/service/ApprovalExportService.java b/src/main/java/com/gxwebsoft/approval/service/ApprovalExportService.java index 514a8cc..58c9875 100644 --- a/src/main/java/com/gxwebsoft/approval/service/ApprovalExportService.java +++ b/src/main/java/com/gxwebsoft/approval/service/ApprovalExportService.java @@ -48,6 +48,9 @@ public class ApprovalExportService { /** 单次导出上限,超过即要求缩小筛选范围。 */ public static final int MAX_EXPORT_ROWS = 5000; + /** 批量取实例的 IN 分块大小。 */ + private static final int INSTANCE_BATCH = 500; + private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); /** 一期 16 列顺序保持不变,二期三列追加在末尾(ADR 0004 / 0003)。 */ @@ -187,14 +190,15 @@ public class ApprovalExportService { header.createCell(i).setCellValue(HEADERS[i]); } Map> nodeCache = new HashMap<>(); - // 批量取实例,避免逐行往返(5000 行导出时 N+1 会拖到分钟级) + // 批量取实例(分块 IN),避免逐行往返;5000 行导出时 N+1 会拖到分钟级 Map instances = new HashMap<>(); List instanceIds = new ArrayList<>(); for (ApprovalExportRow row : rows) { instanceIds.add(row.getId()); } - if (!instanceIds.isEmpty()) { - for (ApprovalInstance instance : instanceMapper.selectBatchIds(instanceIds)) { + for (int start = 0; start < instanceIds.size(); start += INSTANCE_BATCH) { + List chunk = instanceIds.subList(start, Math.min(start + INSTANCE_BATCH, instanceIds.size())); + for (ApprovalInstance instance : instanceMapper.selectBatchIds(chunk)) { instances.put(instance.getId(), instance); } } @@ -212,7 +216,7 @@ public class ApprovalExportService { BigDecimal amountTotal = type == null ? null : amountCache.computeIfAbsent(cacheKey, k -> documentRegistry.lineAmountTotal(type, instance)); String progress = instance == null ? "" : progressCache.computeIfAbsent(cacheKey, - k -> countersignProgress(instance)); + k -> countersignProgress(instance, nodeCache)); SXSSFRow dataRow = sheet.createRow(rowNum++); String[] values = toValues(row, nodeCache, lineCount, amountTotal, progress); for (int i = 0; i < values.length; i++) { @@ -256,9 +260,14 @@ public class ApprovalExportService { /** * 会签进度列:仅会签节点有组时填「已签 N/M」,其余为空。 */ - private String countersignProgress(ApprovalInstance instance) { - List nodes = flowService.parseNodes(instance.getDefinitionId()); + private String countersignProgress(ApprovalInstance instance, + Map> nodeCache) { + List nodes = nodeCache.computeIfAbsent(instance.getDefinitionId(), + flowService::parseNodes); List parts = new ArrayList<>(); + if (nodes.stream().noneMatch(node -> node.getGroups() != null && !node.getGroups().isEmpty())) { + return ""; + } for (ApprovalNode node : nodes) { if (node.getGroups() == null || node.getGroups().isEmpty()) { continue; diff --git a/src/main/java/com/gxwebsoft/approval/service/ApprovalInstanceService.java b/src/main/java/com/gxwebsoft/approval/service/ApprovalInstanceService.java index ca1469f..cbeed15 100644 --- a/src/main/java/com/gxwebsoft/approval/service/ApprovalInstanceService.java +++ b/src/main/java/com/gxwebsoft/approval/service/ApprovalInstanceService.java @@ -133,6 +133,12 @@ public class ApprovalInstanceService { } // 协调单的受理部门在提交时快照到实例;外部流程的分管领导按受理部门解析 ApprovalOrganizationVO acceptOrganization = preflightAcceptOrganization(type, instance); + // 预检要在内存里先带上受理部门快照:节点解析器(acceptOrgLeader/acceptOrgDeputy)读的是实例字段, + // 而快照在 doSubmit 才落库 + if (acceptOrganization != null) { + instance.setAcceptOrgId(acceptOrganization.getOrganizationId()); + instance.setAcceptOrgName(acceptOrganization.getOrganizationName()); + } // 附件分类与逐节点逐组审批人解析(ADR 0003 / 0005) documentService.preflight(instance, flowService.parseNodes(instance.getDefinitionId()));