• java实现审核流程
```java
CREATE TABLE `t_process_flow` (
  `process_id` bigint NOT NULL AUTO_INCREMENT COMMENT '审批任务流程id\r\n',
  `purchase_id` int DEFAULT NULL COMMENT '供应商子公司采购id',
  `operator_id` bigint DEFAULT NULL,
  `action` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `result` varchar(255) DEFAULT NULL,
  `reason` varchar(255) DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  `audit_time` datetime DEFAULT NULL,
  `order_no` int DEFAULT NULL,
  `state` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `is_last` int DEFAULT NULL COMMENT '是否是最后节点 0-否 1-是',
  PRIMARY KEY (`process_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;```
@Service
public class PurchaseServiceImpl extends ServiceImpl<PurchaseMapper, Purchase> implements IPurchaseService {

    @Autowired
    private PurchaseMapper purchaseMapper;
    @Autowired
    private ProcessFlowMapper processFlowMapper;

    @Override
    public Purchase createPurchase(Purchase purchase,Integer adminUserId) {
        //todo 事业部领导或者集团领导会不会直接添加供应商子公司采购??????
        //月度合作额度(元)
        Double monthlyCooperationQuota = purchase.getMonthlyCooperationQuota();

        // todo 查询当前用户的信息,及根据金额规则区间获取审批人

        // todo 保存供应商子公司采购信息
        purchase.setCreateTime(new Date());
        purchase.setCreator(1);
        purchase.setState(1);
        purchaseMapper.insert(purchase);
        // todo 保存审理流程表信息
        //1.保存第一条流程信息,表名表单提交,状态为complete
        ProcessFlow flow1 = new ProcessFlow();
        flow1.setPurchaseId(purchase.getId());
        flow1.setOperatorId(adminUserId.longValue());
        flow1.setAction("apply");
        flow1.setCreateTime(new Date());
        flow1.setOrderNo(1);
        flow1.setState("complete");
        flow1.setIsLast(0);
        processFlowMapper.insert(flow1);
        //2. 分情况保存审批人流程信息
        //2.1  根据月度合作额度决定审核主体
        Integer routeFlag = route(monthlyCooperationQuota);
        //todo 获取审核下一节点领导id
        ProcessFlow flow2 = new ProcessFlow();
        flow2.setPurchaseId(purchase.getId());
        flow2.setAction("audit");
        flow2.setCreateTime(new Date());
        flow2.setOrderNo(2);
        flow2.setState("process");

        if(Objects.equals(ApprovalProcessEnum.BUSINESS_DIVISION.getCode(), routeFlag)||
                Objects.equals(ApprovalProcessEnum.GROUP.getCode(), routeFlag)){
            //2.1.1 一级审核:事业部一级审核 或者 集团一级审核
            flow2.setOperatorId(getLeader(ApprovalProcessEnum.BUSINESS_DIVISION.getCode()));
            flow2.setIsLast(1);
            processFlowMapper.insert(flow2);
        }else {
            //2.1.2 事业部和集团两级审核
            //todo 获取当前用户的所属事业部领导和集团领导
            //事业部审核
            flow2.setOperatorId(getLeader(ApprovalProcessEnum.BUSINESS_DIVISION.getCode()));
            flow2.setIsLast(0);
            processFlowMapper.insert(flow2);
            //集团审核
            ProcessFlow flow3 = new ProcessFlow();
            flow3.setPurchaseId(purchase.getId());
            flow3.setAction("audit");
            flow3.setCreateTime(new Date());
            flow3.setOrderNo(3);
            flow3.setState("ready");
            flow3.setIsLast(1);
            processFlowMapper.insert(flow3);
        }

        // todo 保存流程通知表信息

        return purchase;
    }

    @Override
    public void audit(Long purchaseId, Long operatorId, Integer result, String reason) {
        //当前审核任务对象
        ProcessFlow process;

        //1.无论同意/驳回,当前任务状态变更为complete
        //通过采购id查询业务流程集合,按照审核流程序号
        Wrapper<ProcessFlow> wrapper = new EntityWrapper<>();
        wrapper.eq("purchase_id", purchaseId).last("order by order_no");
        List<ProcessFlow> flowList = processFlowMapper.selectList(wrapper);

        if(flowList.size() == 0){
            throw new ResponseException("无效的审批流程");
        }
        //获取当前任务ProcessFlow对象
        List<ProcessFlow> processList = flowList.stream()
                .filter(p -> Objects.equals(p.getOperatorId(), operatorId) && p.getState().equals(ProvessStateEnum.PROCESS.getValue()))
                .collect(Collectors.toList());

        if(processList.size()==0){
            throw new ResponseException("未找到待处理任务");
        }else {
            process = processList.get(0);
            process.setState(ProvessStateEnum.COMPLETE.getValue());
            //result审核结果状态:2-审核通过,3-审核拒绝
            //todo 把String改成int类型的
            process.setResult(result.toString());
            process.setReason(reason);
            process.setAuditTime(new Date());
            processFlowMapper.updateById(process);
        }
        //2.如果当前任务是最后一个节点,代表流程结束,更新请假单状态为对应的 2-审核通过,3-审核拒绝
        Purchase purchase = purchaseMapper.selectById(purchaseId);
        if(process.getIsLast() == 1){
            //状态:1-待审核,2-审核通过,3-审核拒绝
            purchase.setState(result);
            purchaseMapper.updateById(purchase);
        }else {
            //readyList包含所有后续任务节点
            List<ProcessFlow> readyList = flowList.stream()
                    .filter(p -> p.getState().equals(ProvessStateEnum.READY.getValue()))
                    .collect(Collectors.toList());
            //3.如果当前任务不是最后一个节点且审批通过,那下一个节点的状态从ready变为process
            if(result.equals(PurchaseAuditTypeEnum.APPROVED.getCode())){
                ProcessFlow readyProcess = readyList.get(0);
                readyProcess.setState(ProvessStateEnum.PROCESS.getValue());
                processFlowMapper.updateById(readyProcess);
            }else if(result.equals(PurchaseAuditTypeEnum.REFUSED.getCode())) {
                //4.如果当前任务不是最后一个节点且审批驳回,则后续所有任务状态变为cancel,请假单状态变为refused
                for(ProcessFlow p:readyList){
                    p.setState(ProvessStateEnum.CANCEL.getValue());
                    processFlowMapper.updateById(p);
                }
                purchase.setState(result);
                purchaseMapper.updateById(purchase);
            }
        }
    }


    /**
     * 审核流-路由方法
     * 月度合作额度(元)
     * @param monthlyCooperationQuota
     * @return 路由标识 1-事业部一级审核 2-事业部->集团两级审核 3.集团一级审核
     */
    private Integer route(Double monthlyCooperationQuota) {
        //todo 使用数据字典返回对应值,逻辑待实现
        return 1;
    }

    /**
     * 获取分管领导id
     * @param level 1-事业部 3-集团
     * @return
     */
    private Long getLeader(Integer level) {
        //todo 实现获取分管领导id逻辑
        return null;
    }
}