fix: 提交预检先带受理部门快照;导出列序与原顺序兼容并批量取实例

This commit is contained in:
weicw
2026-10-31 06:30:49 +08:00
parent d5001c981c
commit e6442c1777
3 changed files with 22 additions and 7 deletions
@@ -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,
@@ -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<Long, List<ApprovalNode>> nodeCache = new HashMap<>();
// 批量取实例,避免逐行往返(5000 行导出时 N+1 会拖到分钟级)
// 批量取实例(分块 IN),避免逐行往返;5000 行导出时 N+1 会拖到分钟级
Map<Long, ApprovalInstance> instances = new HashMap<>();
List<Long> 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<Long> 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<ApprovalNode> nodes = flowService.parseNodes(instance.getDefinitionId());
private String countersignProgress(ApprovalInstance instance,
Map<Long, List<ApprovalNode>> nodeCache) {
List<ApprovalNode> nodes = nodeCache.computeIfAbsent(instance.getDefinitionId(),
flowService::parseNodes);
List<String> 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;
@@ -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()));