From c26e6f3f5efbf41913178a59dfd35891298fc1ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E4=B9=BE=E7=BF=94?= Date: Wed, 20 May 2026 17:55:04 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=86=E6=B4=BE=E9=85=8D=E7=BD=AE=E5=AE=A1?= =?UTF-8?q?=E6=89=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../constant/DispatchConfigApprovalConst.java | 11 +- .../dto/DispatchConfigApprovalSearch.java | 37 +++ .../entity/DispatchConfigApprovalRecord.java | 87 +++++++ .../vo/DispatchConfigApprovalTimelineVO.java | 40 ++++ .../pojo/vo/ProReTemplateTimelineVO.java | 37 +++ .../DispatchConfigApprovalController.java | 15 +- .../DispatchConfigApprovalRecordMapper.java | 36 +++ .../DispatchConfigApprovalRecordMapper.xml | 74 ++++++ .../IDispatchConfigApprovalService.java | 9 +- .../DispatchConfigApprovalServiceImpl.java | 223 ++++++++++++++++-- 10 files changed, 541 insertions(+), 28 deletions(-) create mode 100644 blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/quality/pojo/dto/DispatchConfigApprovalSearch.java create mode 100644 blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/quality/pojo/entity/DispatchConfigApprovalRecord.java create mode 100644 blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/quality/pojo/vo/DispatchConfigApprovalTimelineVO.java create mode 100644 blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/quality/pojo/vo/ProReTemplateTimelineVO.java create mode 100644 blade-service/blade-desk/src/main/java/org/springblade/desk/quality/mapper/DispatchConfigApprovalRecordMapper.java create mode 100644 blade-service/blade-desk/src/main/java/org/springblade/desk/quality/mapper/DispatchConfigApprovalRecordMapper.xml diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/quality/constant/DispatchConfigApprovalConst.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/quality/constant/DispatchConfigApprovalConst.java index 6813edfba..0f46e1026 100644 --- a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/quality/constant/DispatchConfigApprovalConst.java +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/quality/constant/DispatchConfigApprovalConst.java @@ -14,9 +14,9 @@ public interface DispatchConfigApprovalConst { Integer STATUS_DRAFT = 0; /** - * 状态-审批中 + * 状态-一级审批中(室主任审批) */ - Integer STATUS_APPROVING = 1; + Integer STATUS_LEVEL1_APPROVING = 1; /** * 状态-审批通过 @@ -28,10 +28,15 @@ public interface DispatchConfigApprovalConst { */ Integer STATUS_REJECTED = 3; + /** + * 状态-二级审批中(领导审批) + */ + Integer STATUS_LEVEL2_APPROVING = 4; + /** * 状态-已撤销 */ - Integer STATUS_CANCELLED = 4; + Integer STATUS_CANCELLED = 5; /** * 审批结果-通过 diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/quality/pojo/dto/DispatchConfigApprovalSearch.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/quality/pojo/dto/DispatchConfigApprovalSearch.java new file mode 100644 index 000000000..c6e8d4dfb --- /dev/null +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/quality/pojo/dto/DispatchConfigApprovalSearch.java @@ -0,0 +1,37 @@ +package org.springblade.desk.quality.pojo.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 分派配置审批查询条件 + * + * @author AI + * @since 2026-05-19 + */ +@Data +@Schema(description = "分派配置审批查询条件") +public class DispatchConfigApprovalSearch implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 申请单号(模糊查询) + */ + @Schema(description = "申请单号") + private String applicationNo; + + /** + * 申请人姓名(模糊查询) + */ + @Schema(description = "申请人姓名") + private String applicantName; + + /** + * 状态 + */ + @Schema(description = "状态: 0-草稿, 1-审批中, 2-审批通过, 3-审批驳回, 4-已撤销") + private Integer status; +} diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/quality/pojo/entity/DispatchConfigApprovalRecord.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/quality/pojo/entity/DispatchConfigApprovalRecord.java new file mode 100644 index 000000000..903c4a655 --- /dev/null +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/quality/pojo/entity/DispatchConfigApprovalRecord.java @@ -0,0 +1,87 @@ +package org.springblade.desk.quality.pojo.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springblade.core.mp.base.BaseEntity; + +import java.util.Date; + +/** + * 分派配置审批记录实体类 + * + * @author AI + * @since 2026-05-20 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("QA_DISPATCH_CFG_APPR_REC") +@Schema(description = "分派配置审批记录实体") +public class DispatchConfigApprovalRecord extends BaseEntity { + + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @TableId(value = "ID", type = IdType.ASSIGN_ID) + @Schema(description = "主键ID") + private Long id; + + /** + * 审批主表ID + */ + @Schema(description = "审批主表ID") + private Long approvalId; + + /** + * 审批节点:1-室主任审批,2-领导审批 + */ + @Schema(description = "审批节点:1-室主任审批,2-领导审批") + private Integer approvalNode; + + /** + * 审批节点名称 + */ + @Schema(description = "审批节点名称") + private String approvalNodeName; + + /** + * 审批人ID + */ + @Schema(description = "审批人ID") + private Long auditorId; + + /** + * 审批人姓名 + */ + @Schema(description = "审批人姓名") + private String auditorName; + + /** + * 审批结果:1-通过,2-驳回 + */ + @Schema(description = "审批结果:1-通过,2-驳回") + private Integer auditResult; + + /** + * 审批意见 + */ + @Schema(description = "审批意见") + private String auditRemark; + + /** + * 审批时间 + */ + @Schema(description = "审批时间") + private Date auditTime; + + /** + * 排序号 + */ + @Schema(description = "排序号") + private Integer sortOrder; +} diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/quality/pojo/vo/DispatchConfigApprovalTimelineVO.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/quality/pojo/vo/DispatchConfigApprovalTimelineVO.java new file mode 100644 index 000000000..de2086600 --- /dev/null +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/quality/pojo/vo/DispatchConfigApprovalTimelineVO.java @@ -0,0 +1,40 @@ +package org.springblade.desk.quality.pojo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 分派配置审批时间线数据VO + * + * @author AI + * @since 2026-05-20 + */ +@Data +@Schema(description = "分派配置审批时间线数据VO") +public class DispatchConfigApprovalTimelineVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "类型: submit-提交, audit-审核") + private String type; + + @Schema(description = "标签: 提交人/审核人") + private String label; + + @Schema(description = "值: 人员姓名") + private String value; + + @Schema(description = "时间") + private String time; + + @Schema(description = "状态: pending-待处理, success-已完成, rejected-已驳回") + private String status; + + @Schema(description = "审批节点:1-室主任审批,2-领导审批") + private Integer approvalNode; + + @Schema(description = "审批意见") + private String remark; +} diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/quality/pojo/vo/ProReTemplateTimelineVO.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/quality/pojo/vo/ProReTemplateTimelineVO.java new file mode 100644 index 000000000..18ff7cb23 --- /dev/null +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/quality/pojo/vo/ProReTemplateTimelineVO.java @@ -0,0 +1,37 @@ +package org.springblade.desk.quality.pojo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 过程记录模板审核时间线数据VO + * + * @author AI + * @since 2026-05-20 + */ +@Data +@Schema(description = "过程记录模板审核时间线数据VO") +public class ProReTemplateTimelineVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "类型: submit-提交, audit-审核") + private String type; + + @Schema(description = "标签: 提交人/审核人") + private String label; + + @Schema(description = "值: 人员姓名") + private String value; + + @Schema(description = "时间") + private String time; + + @Schema(description = "状态: pending-待处理, success-已完成") + private String status; + + @Schema(description = "备注") + private String remark; +} diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/quality/controller/DispatchConfigApprovalController.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/quality/controller/DispatchConfigApprovalController.java index 71c45c1b2..dd678ca9d 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/quality/controller/DispatchConfigApprovalController.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/quality/controller/DispatchConfigApprovalController.java @@ -25,6 +25,7 @@ import org.springblade.desk.quality.constant.QAModuleConst; import org.springblade.desk.quality.excel.DispatchConfigApprovalExcel; import org.springblade.desk.quality.pojo.entity.DispatchConfigApproval; import org.springblade.desk.quality.pojo.request.DispatchConfigApprovalRequest; +import org.springblade.desk.quality.pojo.vo.DispatchConfigApprovalTimelineVO; import org.springblade.desk.quality.pojo.vo.DispatchConfigApprovalVO; import org.springblade.desk.quality.service.IDispatchConfigApprovalService; import org.springblade.desk.quality.wrapper.DispatchConfigApprovalWrapper; @@ -178,12 +179,12 @@ public class DispatchConfigApprovalController extends BladeController { } /** - * [分派配置审批] 审批(待实现) + * [分派配置审批] 审批(两级审批) */ @PostMapping("/audit") @ApiOperationSupport(order = 80) @ApiLog("审批分派配置") - @Operation(summary = "审批", description = "审批功能待实现") + @Operation(summary = "审批", description = "根据当前状态自动判断是一级还是二级审批") public R audit(@Parameter(description = "主键ID", required = true) @RequestParam Long id, @Parameter(description = "审批结果: 1-通过, 2-驳回", required = true) @RequestParam Integer result, @Parameter(description = "审批意见") @RequestParam(required = false) String remark) { @@ -191,12 +192,12 @@ public class DispatchConfigApprovalController extends BladeController { } /** - * [分派配置审批] 查询审批历史 + * [分派配置审批] 查询审批时间线 */ - @GetMapping("/auditHistory/{id}") + @GetMapping("/auditTimeline/{id}") @ApiOperationSupport(order = 90) - @Operation(summary = "查询审批历史", description = "传入主键ID") - public R getAuditHistory(@Parameter(description = "主键ID", required = true) @PathVariable Long id) { - return R.data(service.getAuditHistory(id)); + @Operation(summary = "查询审批时间线", description = "传入主键ID") + public R> getAuditTimeline(@Parameter(description = "主键ID", required = true) @PathVariable Long id) { + return R.data(service.getAuditTimeline(id)); } } diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/quality/mapper/DispatchConfigApprovalRecordMapper.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/quality/mapper/DispatchConfigApprovalRecordMapper.java new file mode 100644 index 000000000..400b7412d --- /dev/null +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/quality/mapper/DispatchConfigApprovalRecordMapper.java @@ -0,0 +1,36 @@ +package org.springblade.desk.quality.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Select; +import org.springblade.desk.quality.pojo.entity.DispatchConfigApprovalRecord; + +import java.util.List; + +/** + * 分派配置审批记录 Mapper 接口 + * + * @author AI + * @since 2026-05-20 + */ +public interface DispatchConfigApprovalRecordMapper extends BaseMapper { + + /** + * 查询室主任审批节点的所有审批人 + */ + List selectLevel1Auditors(); + + /** + * 查询领导审批节点的所有审批人 + */ + List selectLevel2Auditors(); + + /** + * 根据审批ID查询审批记录 + */ + List selectByApprovalId(Long approvalId); + + /** + * 根据审批ID和审批节点查询审批记录 + */ + List selectByApprovalIdAndNode(Long approvalId, Integer approvalNode); +} diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/quality/mapper/DispatchConfigApprovalRecordMapper.xml b/blade-service/blade-desk/src/main/java/org/springblade/desk/quality/mapper/DispatchConfigApprovalRecordMapper.xml new file mode 100644 index 000000000..52bd097e8 --- /dev/null +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/quality/mapper/DispatchConfigApprovalRecordMapper.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/quality/service/IDispatchConfigApprovalService.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/quality/service/IDispatchConfigApprovalService.java index fe810ac43..0873df913 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/quality/service/IDispatchConfigApprovalService.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/quality/service/IDispatchConfigApprovalService.java @@ -5,6 +5,7 @@ import org.springblade.core.tool.api.R; import org.springblade.desk.basic.service.en.EnBaseService; import org.springblade.desk.quality.excel.DispatchConfigApprovalExcel; import org.springblade.desk.quality.pojo.entity.DispatchConfigApproval; +import org.springblade.desk.quality.pojo.vo.DispatchConfigApprovalTimelineVO; import org.springblade.desk.quality.pojo.vo.DispatchConfigApprovalVO; import java.util.List; @@ -67,7 +68,7 @@ public interface IDispatchConfigApprovalService extends EnBaseService getAuditTimeline(Long id); } diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/quality/service/impl/DispatchConfigApprovalServiceImpl.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/quality/service/impl/DispatchConfigApprovalServiceImpl.java index 08e4e35ab..0853e7763 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/quality/service/impl/DispatchConfigApprovalServiceImpl.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/quality/service/impl/DispatchConfigApprovalServiceImpl.java @@ -1,5 +1,6 @@ package org.springblade.desk.quality.service.impl; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; @@ -11,8 +12,11 @@ import org.springblade.desk.basic.service.en.impl.EnBaseServiceImpl; import org.springblade.desk.quality.constant.DispatchConfigApprovalConst; import org.springblade.desk.quality.excel.DispatchConfigApprovalExcel; import org.springblade.desk.quality.mapper.DispatchConfigApprovalMapper; +import org.springblade.desk.quality.mapper.DispatchConfigApprovalRecordMapper; import org.springblade.desk.quality.pojo.entity.DispatchConfigApproval; +import org.springblade.desk.quality.pojo.entity.DispatchConfigApprovalRecord; import org.springblade.desk.quality.pojo.request.DispatchConfigApprovalRequest; +import org.springblade.desk.quality.pojo.vo.DispatchConfigApprovalTimelineVO; import org.springblade.desk.quality.pojo.vo.DispatchConfigApprovalVO; import org.springblade.desk.quality.service.IDispatchConfigApprovalService; import org.springblade.desk.quality.wrapper.DispatchConfigApprovalWrapper; @@ -20,10 +24,9 @@ import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Objects; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * 分派配置审批服务实现类 @@ -35,6 +38,9 @@ import java.util.Objects; @Service public class DispatchConfigApprovalServiceImpl extends EnBaseServiceImpl implements IDispatchConfigApprovalService { + @jakarta.annotation.Resource + private DispatchConfigApprovalRecordMapper approvalRecordMapper; + @Override public IPage selectDispatchConfigApprovalPage(IPage page, DispatchConfigApprovalVO entity) { QueryWrapper queryWrapper = new QueryWrapper<>(); @@ -168,29 +174,218 @@ public class DispatchConfigApprovalServiceImpl extends EnBaseServiceImpl currentLevelAuditors = + currentNode == 1 ? approvalRecordMapper.selectLevel1Auditors() : approvalRecordMapper.selectLevel2Auditors(); + + if (CollUtil.isEmpty(currentLevelAuditors)) { + return R.fail("当前节点没有审批人"); + } + + // 检查当前用户是否在当前节点的审批人列表中 + boolean isAuditor = false; + for (DispatchConfigApprovalRecord auditor : currentLevelAuditors) { + if (auditor.getAuditorId().equals(currentUserId)) { + isAuditor = true; + break; + } + } + + // 如果当前用户不是当前节点的审批人 + if (!isAuditor) { + return R.fail("您不是当前审批节点的审批人"); + } + + // 检查当前用户是否已经审批过 + QueryWrapper recordQuery = new QueryWrapper<>(); + recordQuery.eq("APPROVAL_ID", id) + .eq("AUDITOR_ID", currentUserId) + .eq("APPROVAL_NODE", currentNode) + .eq("IS_DELETED", 0); + DispatchConfigApprovalRecord existingRecord = approvalRecordMapper.selectOne(recordQuery); + + if (existingRecord != null) { + return R.fail("您已经完成审批,不能重复审批"); + } + + // 创建新的审批记录 + DispatchConfigApprovalRecord newRecord = new DispatchConfigApprovalRecord(); + newRecord.setApprovalId(id); + newRecord.setApprovalNode(currentNode); + newRecord.setApprovalNodeName(currentNodeName); + newRecord.setAuditorId(currentUserId); + newRecord.setAuditorName(currentUserName); + newRecord.setAuditResult(result); + newRecord.setAuditRemark(remark); + newRecord.setAuditTime(now); + approvalRecordMapper.insert(newRecord); + + // 如果审批驳回,直接驳回到发起人,并删除审批记录 + if (DispatchConfigApprovalConst.AUDIT_RESULT_REJECT.equals(result)) { + entity.setStatus(DispatchConfigApprovalConst.STATUS_REJECTED); + entity.setUpdateUser(currentUserId); + entity.setUpdateTime(now); + updateById(entity); + + // 删除当前节点的审批记录,以便重新审批 + QueryWrapper deleteQuery = new QueryWrapper<>(); + deleteQuery.eq("APPROVAL_ID", id); + approvalRecordMapper.delete(deleteQuery); + + return R.success("审批已驳回"); + } + + // 审批通过,检查当前节点是否全部通过 + // 查询当前节点已通过的审批人数 + QueryWrapper passedQuery = new QueryWrapper<>(); + passedQuery.eq("APPROVAL_ID", id) + .eq("APPROVAL_NODE", currentNode) + .eq("AUDIT_RESULT", DispatchConfigApprovalConst.AUDIT_RESULT_PASS) + .eq("IS_DELETED", 0); + List passedList = approvalRecordMapper.selectList(passedQuery); + Set passedAuditorIds + = passedList.stream().map(DispatchConfigApprovalRecord::getAuditorId).collect(Collectors.toSet()); + + Set auditorIds = currentLevelAuditors.stream().map(DispatchConfigApprovalRecord::getAuditorId).collect(Collectors.toSet()); + + // 检查当前节点的所有审批人是否都已通过 + boolean allPassed = passedAuditorIds.containsAll(auditorIds); + + if (allPassed) { + // 当前节点所有人都通过了 + if (currentNode == 1) { + // 一级审批全部通过,进入二级审批 + entity.setStatus(DispatchConfigApprovalConst.STATUS_LEVEL2_APPROVING); + entity.setUpdateUser(currentUserId); + entity.setUpdateTime(now); + updateById(entity); + + } else if (currentNode == 2) { + // 二级审批全部通过,审批完成 + entity.setStatus(DispatchConfigApprovalConst.STATUS_APPROVED); + entity.setUpdateUser(currentUserId); + entity.setUpdateTime(now); + updateById(entity); + } + } + + return R.success("审批成功"); } @Override - public DispatchConfigApprovalVO getAuditHistory(Long id) { + public List getAuditTimeline(Long id) { DispatchConfigApproval entity = getById(id); if (entity == null) { - return null; + return new ArrayList<>(); + } + + List timelineList = new ArrayList<>(); + + // 1. 添加提交记录 + DispatchConfigApprovalTimelineVO submitNode = new DispatchConfigApprovalTimelineVO(); + submitNode.setType("submit"); + submitNode.setLabel("提交人:"); + submitNode.setValue(entity.getApplicantName() != null ? entity.getApplicantName() : "未知"); + submitNode.setTime(entity.getApplicationTime() != null ? DateUtil.format(entity.getApplicationTime(), "yyyy-MM-dd HH:mm:ss") : ""); + submitNode.setStatus("success"); + submitNode.setApprovalNode(0); + timelineList.add(submitNode); + + // 2. 查询所有审批记录 + List allRecords = approvalRecordMapper.selectByApprovalId(id); + + // 按审批节点分组 + Map> nodeMap = allRecords.stream() + .collect(Collectors.groupingBy(DispatchConfigApprovalRecord::getApprovalNode)); + + // 3. 添加一级审批节点(如果有审批记录) + if (nodeMap.containsKey(1)) { + List level1Records = nodeMap.get(1); + // 只展示第一个通过的审批人 + DispatchConfigApprovalRecord firstRecord = level1Records.get(0); + DispatchConfigApprovalTimelineVO node = new DispatchConfigApprovalTimelineVO(); + node.setType("audit"); + node.setLabel("一级审批:"); + node.setValue("已通过"); + node.setTime(firstRecord.getAuditTime() != null ? DateUtil.format(firstRecord.getAuditTime(), "yyyy-MM-dd HH:mm:ss") : ""); + node.setApprovalNode(1); + node.setStatus("success"); + timelineList.add(node); + } + + // 4. 添加二级审批节点(如果有审批记录) + if (nodeMap.containsKey(2)) { + List level2Records = nodeMap.get(2); + // 只展示第一个通过的审批人 + DispatchConfigApprovalRecord firstRecord = level2Records.get(0); + DispatchConfigApprovalTimelineVO node = new DispatchConfigApprovalTimelineVO(); + node.setType("audit"); + node.setLabel("二级审批:"); + node.setValue("已通过"); + node.setTime(firstRecord.getAuditTime() != null ? DateUtil.format(firstRecord.getAuditTime(), "yyyy-MM-dd HH:mm:ss") : ""); + node.setApprovalNode(2); + node.setStatus("success"); + timelineList.add(node); } - return DispatchConfigApprovalVO.fromEntity(entity); + + // 按时间倒序排列(最新的在前面) + timelineList.sort((a, b) -> { + if (a.getTime() == null || b.getTime() == null) { + return 0; + } + return b.getTime().compareTo(a.getTime()); + }); + + return timelineList; } /**