设计思路

  1. 对于状态流转类的业务,正确的区分【操作】和【状态】是非常必要的
  2. 操作,对应请求后端的接口,一般为动词,记录在操作记录表中(或者不记录)。例如:新增,修改,启用,停用,注销,审批,撤回,等
  3. 状态,指操作后的状态,一般为形容词,以动词的过去分词形式命名。状态机的核心。记录在业务表中,例如:已提交,已启用,已停用,已审核通过,已审核拒绝,已注销。强烈建议不要省略【已】这个字。对应的,字段名应以过去分词形式记录,CREATED,ENABLED,DISABLED,REJECTED,AWAITING_ENABLE,AWAITING_DISABLE等
操作 ```java package top.haoshenqi.demo.enums;

import lombok.AllArgsConstructor;
import lombok.Getter;

import java.util.List;

@Getter
@AllArgsConstructor
public enum BusCodeOperateEnum {
CREATE("新建"),
UPDATE("更新"),
// CANCEL("取消"),
DISABLE("停用"),
REVIEW_PASS("复核通过"),
REVIEW_REJECT("复核拒绝"),
;
String desc;

public static List<BusCodeOperateEnum> updateOperTypeList(){
    return List.of(CREATE,UPDATE,DISABLE);
}

}

```
状态 ```java package top.haoshenqi.demo.enums;

import com.aexpec.fcp.common.exception.FcpRuntimeException;
import lombok.AllArgsConstructor;
import lombok.Getter;

import java.util.Arrays;

@Getter
@AllArgsConstructor
public enum BusCodeStatusEnum {
ENABLED("已启用"),
DISABLED("已停用"),
// CANCELED("已取消"),
REJECTED("已拒绝"),
// AWAITING_UPDATE("待修改"),
AWAITING_ENABLE("待启用"),
AWAITING_DISABLE("待停用"),
;
String desc;

public boolean changeAble() {
    return this == ENABLED;
}

public boolean approveAble() {
    if (this == AWAITING_ENABLE || this == AWAITING_DISABLE) {
        return true;
    }
    return false;
}

}

 </details>


<details>
<summary>操作</summary>

```java
package top.haoshenqi.demo.enums;

import lombok.Getter;

/**
 * 业务操作类型
 *
 * @author haoshenqi
 */
 
@Getter
public enum OperType {

    /**
     * 单据录入
     */
    BUS_INPUT("10", "单据录入", ""),
    /**
     * 单据复核
     */
    BUS_CHECK("11", "单据复核", "01"),
    /**
     * old 单据一审
     * new 业务审核
     */
    BUS_APPROVAL("12", "业务审核", "11"),


    /**
     * new 财务审核
     */

    BUS_FINANCIAL_APPROVAL("33", "财务审核", "13"),

    /**
     * new 资金一审
     */

    BUS_FIRST_FUND_APPROVAL("35", "资金一审", "17"),
    /**
     * old 单据终审
     * new 资金二审
     */
    BUS_SECOND_FUND_APPROVAL("13", "资金二审", "19"),
    /**
     * 单据修改
     */
    BUS_MODIFY("14", "单据修改", ""),
    /**
     * 单据保存
     */
    BUS_SAVE("15", "单据保存", "00"),
    /**
     * 单据废弃
     */
    BUS_CANCEL("16", "单据废弃", ""),
    /**
     * 撤回
     */
    BUS_RECALL("17", "单据撤回", ""),
    /**
     * 查询操作
     */
    OP_ALLQUERY("20", "全部查询", ""),

    /**
     * 我的单据查询
     */
    OP_MYQUERY("21", "我的查询", ""),

    /**
     * 新增操作
     */
    OP_INPUT("22", "新增操作", ""),
    /**
     * 修改操作
     */
    OP_MODIFY("23", "修改操作", ""),
    /**
     * 删除操作
     */
    OP_DELET("24", "删除操作", ""),

    /**
     * 录入查询 :用于录入查询导出
     */
    OP_INPUTQUERY("25", "录入查询", "");

    private OperType(String code, String message, String desc) {
        this.code = code;
        this.message = message;
        this.desc = desc;
    }


    private String code;
    private String message;
    private String desc;

    public static OperType getEnumByCode(String code) {
        OperType[] operTypes = values();
        for (OperType enums : operTypes) {
            if (enums != null && enums.getCode().equals(code)) {
                return enums;
            }
        }
        return null;
    }

    /**
     * 通过code 获取name
     *
     * @param code
     * @return
     */
    public static String getNameByCode(String code) {
        OperType[] operTypes = values();
        for (OperType enums : operTypes) {
            if (enums != null && enums.getCode().equals(code)) {
                return enums.getMessage();
            }

        }
        return null;
    }

    /**
     * 通过code 获取desc
     *
     * @param code
     * @return
     */
    public static String getDescByCode(String code) {
        OperType[] operTypes = values();
        for (OperType enums : operTypes) {
            if (enums != null && enums.getCode().equals(code)) {

                return enums.getDesc();
            }
        }
        return null;
    }


    public static String getCodeByDesc(String desc) {
        OperType[] operTypes = values();
        for (OperType enums : operTypes) {
            if (enums != null && enums.getDesc().equals(desc)) {

                return enums.getCode();
            }
        }
        return null;
    }


    public boolean match(BusStatus busStatus) {
        return this.desc.equals(busStatus.getCode());
    }

    public OperType nextApprovalOperType() {
        switch (this) {
            case BUS_APPROVAL -> {
                return BUS_FINANCIAL_APPROVAL;
            }
            case BUS_FINANCIAL_APPROVAL -> {
                return BUS_FIRST_FUND_APPROVAL;
            }
            case BUS_FIRST_FUND_APPROVAL -> {
                return BUS_SECOND_FUND_APPROVAL;
            }
            default -> {
                return null;
            }
        }
    }


    public BusStatus reject() {
        switch (this) {
            case BUS_APPROVAL -> {
                return BusStatus.BUS_REJECT;
            }
            case BUS_FINANCIAL_APPROVAL -> {
                return BusStatus.FINANCIAL_REJECT;
            }
            case BUS_FIRST_FUND_APPROVAL -> {
                return BusStatus.FIRST_FUND_REJECT;
            }
            case BUS_SECOND_FUND_APPROVAL -> {
                return BusStatus.SECOND_FUND_REJECT;
            }
            default -> {
                return null;
            }
        }
    }

    public boolean isFlowNode() {
        return this == BUS_INPUT || this == BUS_CHECK || this == BUS_APPROVAL || this == BUS_FINANCIAL_APPROVAL || this == BUS_FIRST_FUND_APPROVAL || this == BUS_SECOND_FUND_APPROVAL;
    }


    public String getCheckMsg() {
        return this.getMessage() + "通过";
    }
}

状态
package top.haoshenqi.demo.enums;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * TaskApplication
 * </p>
 *
 * <p>
 * Description:
 * </p>
 *
 * @author haoshenqi
 * @date 2020年2月29日
 */
public enum BusStatus {

    /**
     * 待提交
     */
    UN_COMMITED("00", "待提交"),

    /**
     * 待复核
     */
    UN_CHECKED("01", "待复核"),

    /**
     * 待一审
     * 待业务审核
     */
    WAITING_BUS_APPROVAL("11", "待业务审核"),

    /**
     * 待财务审核
     */
    WAITING_FINANCIAL_APPROVAL("13", "待财务审核"),
    /**
     * 待资金一审
     */
    WAITING_FIRST_FUND_APPROVAL("17", "待资金一审"),

    /**
     * 待终审
     * 待资金二审
     */
    WAITING_SECOND_FUND_APPROVAL("19", "待资金二审"),


    DELAY_SEND("20", "延时发送"),

    /**
     * 待发送
     */
    WAITING_SENDING("21", "待发送"),

    /**
     * 已发送待回执
     */
    WAITING_REPLY("22", "已发送待回执"),

    /**
     * 已受理
     */
    DEALED("23", "已受理"),

    /**
     * 已清算
     */
    CLEARED("31", "已清算"),


    /**
     * 财务审核驳回
     */
    FINANCIAL_REJECT("81", "财务审核驳回"),
    /**
     * 资金一审驳回
     */
    FIRST_FUND_REJECT("85", "资金一审驳回"),


    /**
     * 业务审核驳回
     */
    BUS_REJECT("91", "业务审核驳回"),

    /**
     * 资金二审驳回
     */
    SECOND_FUND_REJECT("92", "资金二审驳回"),

    /**
     * 已拒绝
     */
    REPLY_REJECT("93", "已拒绝"),

    /**
     * 对账异常
     */
    VERIFY_ABNORMAL("94", "对账异常"),

    /**
     * 复核失败
     */
    CHECK_FAILED("96", "复核驳回"),

    /**
     * 已废弃
     */
    CANCELED("97", "已废弃"),
    /**
     * 已撤回
     */
    WITHDRAW("95", "已撤回"),


    ;

    /**
     * 业务状态代码
     */
    private String code;

    /**
     * 业务状态名称
     */
    private String name;

    BusStatus(String code, String name) {
        this.code = code;
        this.name = name;
    }

    public String getCode() {
        return code;
    }

    public String getName() {
        return name;
    }


    /**
     * 通过code 获取name
     *
     * @param code
     * @return
     */
    public static BusStatus ofCode(String code) {
        BusStatus[] busStatus = values();
        for (BusStatus enums : busStatus) {
            if (enums != null && enums.getCode().equals(code)) {
                return enums;
            }
        }
        return null;
    }


    /**
     * 通过code 获取name
     *
     * @param code
     * @return
     */
    public static String getNameByCode(String code) {
        BusStatus[] busStatus = values();
        for (BusStatus enums : busStatus) {
            if (enums != null && enums.getCode().equals(code)) {
                return enums.getName();
            }
        }
        return null;
    }

    public static List<String> inProgressList() {
        //终态判断:(已撤回、复核驳回、业务驳回、财务管理驳回、  资金一审驳回、资金二审驳回、已拒绝、对账异常、已清算、  待发送、延时发送、已发送待回执、已受理)
        //进行中:  (待提交、待复核、 待业务审核、待财务管理审核、待资金一审、  待资金二审)
        List<BusStatus> inProgressStatusList = List.of(UN_COMMITED, UN_CHECKED,
                WAITING_BUS_APPROVAL, WAITING_FINANCIAL_APPROVAL, WAITING_FIRST_FUND_APPROVAL, WAITING_SECOND_FUND_APPROVAL);
        return inProgressStatusList.stream().map(BusStatus::getCode).toList();
    }

    public boolean awaitOrDelay() {
        return this == DELAY_SEND || this == WAITING_SENDING;
    }


    /**
     * 等待下个流程审核的状态
     *
     * @return
     */
    public boolean awaitNextApproval() {
        return this == WAITING_FINANCIAL_APPROVAL || this == WAITING_FIRST_FUND_APPROVAL || this == WAITING_SECOND_FUND_APPROVAL;
    }


    public boolean tobeApproved() {
        return this.awaitNextApproval() || this == UN_CHECKED || this == WAITING_BUS_APPROVAL;
    }

    public boolean after(BusStatus busStatus) {
        assert this.tobeApproved();
        return Integer.parseInt(this.getCode()) >= Integer.parseInt(busStatus.getCode());
    }

    /**
     * 已审核完成状态
     *
     * @return
     */
    public boolean approvalFinished() {
        return this == WAITING_SENDING
                || this == DELAY_SEND
                || this == WAITING_REPLY
                || this == DEALED
                || this == CLEARED;
    }



    /**
     * 40: status in ('11','13','17','19')
     * 待审核
     */
    public static List<BusStatus> statusesForQuery40() {
        return Arrays.asList(
                BusStatus.WAITING_BUS_APPROVAL,
                BusStatus.WAITING_FINANCIAL_APPROVAL,
                BusStatus.WAITING_FIRST_FUND_APPROVAL,
                BusStatus.WAITING_SECOND_FUND_APPROVAL
        );
    }

    /**
     * 41: status not in ('00','01') AND status < '31'
     * 待关注
     */
    public static List<BusStatus> statusesForQuery41() {
        return Arrays.stream(BusStatus.values())
                .filter(bs -> !bs.getCode().equals("00") && !bs.getCode().equals("01")
                        && Integer.parseInt(bs.getCode()) < 31)
                .collect(Collectors.toList());
    }

    /**
     * 42: status > '80'
     * 失败
     */
    public static List<BusStatus> statusesForQuery42() {
        return Arrays.stream(BusStatus.values())
                .filter(bs -> {
                    try {
                        return Integer.parseInt(bs.getCode()) > 80;
                    } catch (NumberFormatException e) {
                        return false;
                    }
                })
                .collect(Collectors.toList());
    }

    /**
     * 43: status in ('81','85','91','92','96')
     * 审核驳回
     */
    public static List<BusStatus> statusesForQuery43() {
        return Arrays.asList(
                BusStatus.FINANCIAL_REJECT,
                BusStatus.FIRST_FUND_REJECT,
                BusStatus.BUS_REJECT,
                BusStatus.SECOND_FUND_REJECT,
                BusStatus.CHECK_FAILED
        );
    }

}