Browse Source

任意一人通过:有一条已批准就显示审批时间;

全部通过:必须当前批次全部已批准才显示审批时间;
master
han\hanst 21 hours ago
parent
commit
07699c0bc2
  1. 266
      src/main/java/com/xujie/sys/modules/erf/service/impl/ErfApprovalCycleReportServiceImpl.java

266
src/main/java/com/xujie/sys/modules/erf/service/impl/ErfApprovalCycleReportServiceImpl.java

@ -2,13 +2,20 @@ package com.xujie.sys.modules.erf.service.impl;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.xujie.sys.common.utils.PageUtils;
import com.xujie.sys.modules.erf.data.ErfApprovalCycleReportExportData;
import com.xujie.sys.modules.erf.data.ErfApprovalCycleQueryData;
import com.xujie.sys.modules.erf.dto.ErfApprovalCycleReportDto;
import com.xujie.sys.modules.erf.entity.ErfFlowInstance;
import com.xujie.sys.modules.erf.entity.ErfFlowNodeInstance;
import com.xujie.sys.modules.erf.mapper.ErfExpApplyMapper;
import com.xujie.sys.modules.erf.mapper.ErfFlowInstanceMapper;
import com.xujie.sys.modules.erf.mapper.ErfFlowNodeInstanceMapper;
import com.xujie.sys.modules.erf.service.ErfApprovalCycleReportService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
@ -35,11 +42,14 @@ import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
@ -60,12 +70,17 @@ import java.util.stream.Collectors;
@Service
public class ErfApprovalCycleReportServiceImpl implements ErfApprovalCycleReportService {
private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
private static final int HEADER_ROW_COUNT = 2;
private static final int COL_APPROVAL_CYCLE_DAYS = 13;
private static final int COL_APPROVE_STATUS = 14;
@Autowired
private ErfExpApplyMapper erfExpApplyMapper;
@Autowired
private ErfFlowNodeInstanceMapper erfFlowNodeInstanceMapper;
@Autowired
private ErfFlowInstanceMapper erfFlowInstanceMapper;
@Override
public PageUtils queryPage(ErfApprovalCycleQueryData data) {
@ -76,6 +91,9 @@ public class ErfApprovalCycleReportServiceImpl implements ErfApprovalCycleReport
List<ErfApprovalCycleReportDto> reportList = erfExpApplyMapper.getApprovalCycleReportList(data);
PageInfo<ErfApprovalCycleReportDto> pageInfo = new PageInfo<>(reportList);
// 重新按当前审批批次计算各角色审批人和审批时间
enrichApprovalFields(reportList);
// 计算审批周期及完成状态
reportList.forEach(this::calculateApprovalCycle);
reportList = filterByAllApproveDate(reportList, data);
@ -90,6 +108,10 @@ public class ErfApprovalCycleReportServiceImpl implements ErfApprovalCycleReport
log.info("=== 导出审批周期报表 ===");
try {
List<ErfApprovalCycleReportDto> reportList = erfExpApplyMapper.getApprovalCycleReportList(data);
// 导出与列表页保持同一套审批字段计算逻辑
enrichApprovalFields(reportList);
reportList.forEach(this::calculateApprovalCycle);
reportList = filterByAllApproveDate(reportList, data);
reportList = filterByCycleDays(reportList, data);
@ -338,6 +360,250 @@ public class ErfApprovalCycleReportServiceImpl implements ErfApprovalCycleReport
cell.setCellStyle(cellStyle);
}
/**
* 重新计算审批相关字段审批人审批时间
*
* <p><b>背景</b>流程节点实例表采用联合主键(apply_no,node_code,attempt_no)多人审批会产生多条不同attempt_no记录
* 报表不能只取MAX(attempt_no)否则会把最后创建但未审批的节点当成当前结果导致已审批却显示待审批</p>
*
* <p><b>处理规则</b></p>
* <ul>
* <li>按流程remark中的审批人数截取该节点最新N条记录作为当前批次</li>
* <li>优先展示当前批次内已批准/已完成的审批人和审批时间</li>
* <li>若当前批次尚无人审批展示候选审批人审批时间置空</li>
* </ul>
*/
private void enrichApprovalFields(List<ErfApprovalCycleReportDto> reportList) {
if (reportList == null || reportList.isEmpty()) {
return;
}
Map<String, ManagerBatchConfig> configCache = new HashMap<>();
Map<String, List<ErfFlowNodeInstance>> nodeCache = new HashMap<>();
for (ErfApprovalCycleReportDto dto : reportList) {
if (dto == null || isBlank(dto.getApplyNo())) {
continue;
}
String applyNo = dto.getApplyNo();
ManagerBatchConfig config = configCache.computeIfAbsent(applyNo, this::loadManagerBatchConfig);
ApprovalSnapshot techSnapshot = resolveApprovalSnapshot(
getCurrentBatchNodes(applyNo, "技术经理审批", 1, nodeCache), true);
dto.setTechManagerName(techSnapshot.getApproverNames());
dto.setTechApproveTime(techSnapshot.getApproveTime());
ApprovalSnapshot prodSnapshot = resolveApprovalSnapshot(
getCurrentBatchNodes(applyNo, "生产经理审批", config.getProdManagerCount(), nodeCache),
config.isProdManagerAnyApproved());
dto.setProdManagerName(prodSnapshot.getApproverNames());
dto.setProdApproveTime(prodSnapshot.getApproveTime());
ApprovalSnapshot qualSnapshot = resolveApprovalSnapshot(
getCurrentBatchNodes(applyNo, "质量经理审批", config.getQualityManagerCount(), nodeCache),
config.isQualityManagerAnyApproved());
dto.setQualManagerName(qualSnapshot.getApproverNames());
dto.setQualApproveTime(qualSnapshot.getApproveTime());
}
}
/**
* 加载经理审批批次配置来源erf_flow_instance.remark
*/
private ManagerBatchConfig loadManagerBatchConfig(String applyNo) {
ManagerBatchConfig config = new ManagerBatchConfig();
ErfFlowInstance flowInstance = erfFlowInstanceMapper.selectById(applyNo);
if (flowInstance == null || isBlank(flowInstance.getRemark())) {
return config;
}
try {
JsonNode root = JSON_MAPPER.readTree(flowInstance.getRemark());
config.setProdManagerAnyApproved(root.path("prodManagerAnyApproved").asBoolean(false));
config.setQualityManagerAnyApproved(root.path("qualityManagerAnyApproved").asBoolean(false));
JsonNode prodArray = root.path("prodManagerIds");
if (prodArray.isArray()) {
config.setProdManagerCount(prodArray.size());
} else if (root.path("prodManagerId").asLong(0L) > 0) {
config.setProdManagerCount(1);
}
JsonNode qualityArray = root.path("qualityManagerIds");
if (qualityArray.isArray()) {
config.setQualityManagerCount(qualityArray.size());
} else if (root.path("qualityManagerId").asLong(0L) > 0) {
config.setQualityManagerCount(1);
}
} catch (Exception e) {
log.warn("解析经理审批批次配置失败,applyNo={}, remark={}, error={}",
applyNo, flowInstance.getRemark(), e.getMessage());
}
return config;
}
/**
* 获取指定节点当前批次记录
*
* <p>按attempt_no倒序读取全部节点若expectedCount>0取最新expectedCount条作为当前批次</p>
*/
private List<ErfFlowNodeInstance> getCurrentBatchNodes(String applyNo,
String nodeCode,
int expectedCount,
Map<String, List<ErfFlowNodeInstance>> nodeCache) {
String cacheKey = applyNo + "|" + nodeCode;
List<ErfFlowNodeInstance> allNodes = nodeCache.computeIfAbsent(cacheKey, key -> {
QueryWrapper<ErfFlowNodeInstance> query = new QueryWrapper<>();
query.eq("apply_no", applyNo)
.eq("node_code", nodeCode)
.orderByDesc("attempt_no");
return erfFlowNodeInstanceMapper.selectList(query);
});
if (allNodes == null || allNodes.isEmpty()) {
return Collections.emptyList();
}
if (expectedCount > 0 && allNodes.size() > expectedCount) {
return new ArrayList<>(allNodes.subList(0, expectedCount));
}
return allNodes;
}
/**
* 从节点列表中提取展示快照
*/
private ApprovalSnapshot resolveApprovalSnapshot(List<ErfFlowNodeInstance> nodes, boolean anyApprovedRule) {
if (nodes == null || nodes.isEmpty()) {
return ApprovalSnapshot.empty();
}
List<ErfFlowNodeInstance> validNodes = nodes.stream()
.filter(Objects::nonNull)
.collect(Collectors.toList());
if (validNodes.isEmpty()) {
return ApprovalSnapshot.empty();
}
List<ErfFlowNodeInstance> approvedNodes = validNodes.stream()
.filter(node -> "已批准".equals(node.getStatus()) || "已完成".equals(node.getStatus()))
.collect(Collectors.toList());
String approvedNames = joinDistinctNames(approvedNodes);
Date latestApproveTime = approvedNodes.stream()
.map(ErfFlowNodeInstance::getCompleteTime)
.filter(Objects::nonNull)
.max(Date::compareTo)
.orElse(null);
if (anyApprovedRule) {
if (!approvedNodes.isEmpty()) {
return new ApprovalSnapshot(approvedNames, latestApproveTime);
}
String candidateNames = joinDistinctNames(validNodes);
return new ApprovalSnapshot(candidateNames, null);
}
// 全部通过策略必须当前批次全部已批准/已完成才给审批时间
boolean allApproved = validNodes.stream()
.allMatch(node -> "已批准".equals(node.getStatus()) || "已完成".equals(node.getStatus()));
if (allApproved && !approvedNodes.isEmpty()) {
return new ApprovalSnapshot(approvedNames, latestApproveTime);
}
// 未全部完成时仅回显已审批人无则显示候选人审批时间保持待审批
if (!approvedNodes.isEmpty()) {
return new ApprovalSnapshot(approvedNames, null);
}
String candidateNames = joinDistinctNames(validNodes);
return new ApprovalSnapshot(candidateNames, null);
}
/**
* 拼接去重审批人名称
*/
private String joinDistinctNames(List<ErfFlowNodeInstance> nodes) {
String names = nodes.stream()
.map(ErfFlowNodeInstance::getAssigneeName)
.filter(name -> !isBlank(name))
.distinct()
.collect(Collectors.joining("、"));
return isBlank(names) ? null : names;
}
private boolean isBlank(String text) {
return text == null || text.trim().isEmpty();
}
/**
* 当前批次配置
*/
private static class ManagerBatchConfig {
private int prodManagerCount;
private int qualityManagerCount;
private boolean prodManagerAnyApproved;
private boolean qualityManagerAnyApproved;
public int getProdManagerCount() {
return prodManagerCount;
}
public void setProdManagerCount(int prodManagerCount) {
this.prodManagerCount = prodManagerCount;
}
public int getQualityManagerCount() {
return qualityManagerCount;
}
public void setQualityManagerCount(int qualityManagerCount) {
this.qualityManagerCount = qualityManagerCount;
}
public boolean isProdManagerAnyApproved() {
return prodManagerAnyApproved;
}
public void setProdManagerAnyApproved(boolean prodManagerAnyApproved) {
this.prodManagerAnyApproved = prodManagerAnyApproved;
}
public boolean isQualityManagerAnyApproved() {
return qualityManagerAnyApproved;
}
public void setQualityManagerAnyApproved(boolean qualityManagerAnyApproved) {
this.qualityManagerAnyApproved = qualityManagerAnyApproved;
}
}
/**
* 审批快照
*/
private static class ApprovalSnapshot {
private final String approverNames;
private final Date approveTime;
private ApprovalSnapshot(String approverNames, Date approveTime) {
this.approverNames = approverNames;
this.approveTime = approveTime;
}
public static ApprovalSnapshot empty() {
return new ApprovalSnapshot(null, null);
}
public String getApproverNames() {
return approverNames;
}
public Date getApproveTime() {
return approveTime;
}
}
/**
* 计算审批周期相关字段
*

Loading…
Cancel
Save