一、mysql表结构
#工作流主表
DROP TABLE IF EXISTS `work_flow`;
CREATE TABLE `work_flow` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
`work_type` int(2) COMMENT '流程类型',
`work_type_name` varchar(255) COMMENT '流程类型名称',
`create_time` datetime(0) COMMENT '创建时间',
`modify_time` datetime(0) COMMENT '修改时间,时间戳',
`process_code` varchar(255) COMMENT '流程号(雪花算法)',
`states` int(255) COMMENT '流程状态(1.待审核/2.撤销/3.驳回/4.通过)',
PRIMARY KEY (`id`) USING BTREE
);
#流程实例表
DROP TABLE IF EXISTS `work_flow_process`;
CREATE TABLE `work_flow_process`(
`id` int(11) COMMENT '主键',
`work_flow_id` int(11) COMMENT '关联流程主表ID',
`business_id` int(11) COMMENT '业务流程节点(1校长/2副校长/3班主任)',
`audit_user_id` int(11) COMMENT '审核人id',
`audit_user_name` varchar(255) COMMENT '审核人名称',
`audit_user_remark` varchar(500) COMMENT '审核意见',
`audit_time` datetime(0) COMMENT '审核时间',
`audit_status` int(10) COMMENT '1审核中/2待我审核/3通过/4驳回',
`delete_state` int(1) COMMENT '删除状态,默认0'
);
二、Java核心逻辑实现
public class workFlowProcess {
@Override
public PageUtils selectAgendaList(Query query) {
PageHelper.startPage(query.getPage(), query.getLimit(),query.getOrderBy());
List<MeteWorkProcessNodeNongHang> agendaList = this.mapper.selectAgendaList(query);
List<WorkFlowProssNodeDefinition> definitions = WorkFlowProssNodeDefinition.workFlowIDCNongHang();
WorkFlowProssNodeDefinition head = definitions.get(0);
for (MeteWorkProcessNodeNongHang node : agendaList) {
List<String> btns = new ArrayList<>();
btns.add("审核通过");
if (head.getUserId() != node.getAuditUserId()){
btns.add("驳回");
}
List<Map<String,Object>> backNodes = new ArrayList<>();
for (WorkFlowProssNodeDefinition definition : definitions) {
if (definition.getUserId() == node.getAuditUserId()){
break;
}
Map<String,Object> backInfo = new HashMap<>();
backInfo.put("workId",node.getWorkId());
backInfo.put("userId",definition.getUserId());
backInfo.put("userName",definition.getUserName());
backNodes.add(backInfo);
}
node.setAuditBtns(btns);
node.setBackNodes(backNodes);
}
List<Map<String,Object>> datas = new ArrayList<>();
for (MeteWorkProcessNodeNongHang l : agendaList) {
try {
Map<String, Object> map = mergerData(l, l.getOneToOne());
datas.add(map);
} catch (IllegalAccessException e) {
log.error("属性合并失败:",e);
}
}
return new PageUtils(datas);
}
public String auditPass(WorkFlowModel model) {
int processNodeId = model.getProcessNodeId();
int workId = model.getWorkId();
Integer userId = model.getUserId();
String comment = model.getComment();
MeteWorkProcessNodeNongHang workProcessNode = Optional
.ofNullable(this.selectById(processNodeId))
.orElseThrow(() -> new RuntimeException("没有找id为" + processNodeId + "工单的流程节点"));
if (userId.equals(workProcessNode.getAuditUserId()) && WorkFlowProcessNodeStateEnun.CURR_USER_APPROVAL.getId() == workProcessNode.getAuditStatus()){
Map<String,Object> auditParams = new HashMap<>();
auditParams.put("processNodeId",processNodeId);
auditParams.put("workId",workId);
auditParams.put("userId",userId);
auditParams.put("status",WorkFlowProcessNodeStateEnun.PASS.getId());
auditParams.put("comment",comment);
auditParams.put("auditTime",new Date());
if (this.mapper.auditPass(auditParams) == 0){
throw new RuntimeException("工单[" + workId + "]审核通过失败");
}else {
List<MeteWorkProcessNodeNongHang> workProcessNodes = this.mapper.selectWorkProcessNodeInfoByWorkFlowStatus(new HashMap<String,Object>(){{
this.put("workId",workId);
this.put("status",WorkFlowProcessNodeStateEnun.UNDER_REVIEW.getId());
}});
if (workProcessNodes.size() == 0){
if (this.workMapper.updateStatusById(workId, WorkFlowStateEnun.PASS.getId()) == 0){
return "工单[" + workId + "]流程审批完成失败";
}
new Thread(() -> this.ftpPush(workId)).start();
return "工单[" + workId + "]流程已全部审批完成";
}else{
MeteWorkProcessNodeNongHang next = workProcessNodes.get(0);
next.setAuditStatus(WorkFlowProcessNodeStateEnun.CURR_USER_APPROVAL.getId());
if (this.mapper.flowNext(next) == 0){
throw new RuntimeException("工单[" + workId + "]流转到下一个节点失败");
}
this.calculateBill(model);
return "工单[" + workId + "]审核通过,流程流转到下一个节点,等待用户[ " + next.getAuditUserId() + " ]审核";
}
}
}
return "当前工单[" + workId + "] 用户[" + userId + "]没有待办任务不能审核";
}
@Override
public List<MeteWorkProcessNodeNongHang> auditHistory(Query query) {
PageHelper.startPage(query.getPage(), query.getLimit(),"id asc");
return this.mapper.auditHistory(query);
}
public String auditReject(WorkFlowModel model) {
int processNodeId = model.getProcessNodeId();
int workId = model.getWorkId();
int backUserId = model.getBackUserId();
String comment = model.getComment();
MeteWorkProcessNodeNongHang workProcessNode = Optional
.ofNullable(this.selectById(processNodeId))
.orElseThrow(() -> new RuntimeException("没有找id为" + processNodeId + "工单的流程节点"));
List<WorkFlowProssNodeDefinition> definitions = WorkFlowProssNodeDefinition.workFlowIDCNongHang();
int backIndex = -1,currIndex = -1;
for (int i = 0; i < definitions.size(); i++) {
WorkFlowProssNodeDefinition definition = definitions.get(i);
if (definition.getUserId() == backUserId){
backIndex = i;
}
if (definition.getUserId() == workProcessNode.getAuditUserId()){
currIndex = i;
}
}
if (backIndex == -1 || currIndex == -1 || currIndex <= backIndex){
throw new RuntimeException("驳回节点[" + backUserId + "]不是当前节点[" + workProcessNode.getAuditUserId() + "]的前继节点");
}
if (this.mapper.updateStatusByIdAndStatus(processNodeId,WorkFlowProcessNodeStateEnun.REJECT.getId(),comment) == 0){
throw new RuntimeException("设置驳回节点失败");
}
this.mapper.deleteHistoryByStatus(workId,WorkFlowProcessNodeStateEnun.UNDER_REVIEW.getId());
boolean isStartNode = false;
int first = 0;
for (WorkFlowProssNodeDefinition definition : definitions) {
if (definition.getUserId() == backUserId){
isStartNode = true;
}
if (isStartNode){
MeteWorkProcessNodeNongHang processNode = new MeteWorkProcessNodeNongHang();
processNode.setWorkId(workId);
processNode.setBusinessId(definition.getBusinessId());
processNode.setAuditUserId(definition.getUserId());
processNode.setAuditUserName(definition.getUserName());
if (first == 0){
processNode.setAuditStatus(WorkFlowProcessNodeStateEnun.CURR_USER_APPROVAL.getId());
}else {
processNode.setAuditStatus(WorkFlowProcessNodeStateEnun.UNDER_REVIEW.getId());
}
this.mapper.insert(processNode);
first++;
}
}
return "当前流程[" + workId + "]驳回到节点[" + backUserId + "]";
}
@Override
public int updateStatusById(int id, int status,String comment) {
return this.mapper.updateStatusById(id,status,comment);
}
@Override
public PageUtils selectAuditPassList(Query query) {
List<MeteWorkProcessNodeNongHang> list = this.mapper.selectAuditPassList(query);
List<Map<String,Object>> datas = new ArrayList<>();
for (MeteWorkProcessNodeNongHang l : list) {
try {
Map<String, Object> map = mergerData(l, l.getOneToOne());
datas.add(map);
} catch (IllegalAccessException e) {
log.error("属性合并失败:",e);
}
}
return new PageUtils(datas);
}
@Override
public PageUtils selectFinishList(Query query) {
List<MeteWorkProcessNodeNongHang> list = this.mapper.selectFinishList(query);
List<Map<String,Object>> datas = new ArrayList<>();
for (MeteWorkProcessNodeNongHang l : list) {
try {
Map<String, Object> map = mergerData(l, l.getOneToOne());
datas.add(map);
} catch (IllegalAccessException e) {
log.error("属性合并失败:",e);
}
}
return new PageUtils(datas);
}
@Override
public Map<String, Object> workFlowDetails(WorkFlowModel model) {
boolean bindingUserId = false;
for (WorkFlowProssNodeDefinition definition : WorkFlowProssNodeDefinition.workFlowIDCNongHang()) {
if (definition.getUserId() == model.getUserId()){
bindingUserId = true;
}
}
if (!bindingUserId){
model.setUserId(-1);
}
MeteWorkProcessNodeNongHang processNode = this.mapper.workFlowDetails(model);
try {
if (processNode != null && processNode.getOneToOne() != null){
return mergerData(processNode, processNode.getOneToOne());
}
} catch (IllegalAccessException e) {
log.error("合并失败:",e);
}
return new HashMap<>();
}
}
三、流程节点
public enum WorkFlowStateEnun {
CHECK_PENDING(1,"待审核"),
REVOCATION(2,"撤销"),
REJECT(3,"驳回"),
PASS(4,"通过(已办结)");
WorkFlowStateEnun(int id,String name){
this.id = id;
this.name = name;
}
private int id;
private String name;
public static String getNameById(int id){
for (WorkFlowProcessNodeStateEnun value : WorkFlowProcessNodeStateEnun.values()) {
if (value.getId() == id){
return value.getName();
}
}
return null;
}
}
四、 流程实例
public enum WorkFlowProcessNodeStateEnun {
UNDER_REVIEW(1,"审核中"),
CURR_USER_APPROVAL(2,"待我审核"),
PASS(3,"通过"),
REJECT(4,"驳回");
WorkFlowProcessNodeStateEnun(int id, String name){
this.id = id;
this.name = name;
}
private int id;
private String name;
public static String getNameById(int id){
for (WorkFlowProcessNodeStateEnun value : WorkFlowProcessNodeStateEnun.values()) {
if (value.getId() == id){
return value.getName();
}
}
return null;
}
}
五、流程定义
public class WorkFlowProssNodeDefinition {
private int id;
private int businessId;
private int userId;
private String userName;
private static final List<WorkFlowProssNodeDefinition> definitions = new ArrayList<>();
public WorkFlowProssNodeDefinition(int id,int businessId,int userId,String userName){
this.id = id;
this.businessId = businessId;
this.userId = userId;
this.userName = userName;
}
public static List<WorkFlowProssNodeDefinition> workFlowIDCNongHang(){
if (CollectionUtils.isEmpty(definitions)){
WorkFlowProssNodeDefinition node1 = new WorkFlowProssNodeDefinition(1,1001,1,"校长");
WorkFlowProssNodeDefinition node2 = new WorkFlowProssNodeDefinition(2,1002,2,"副校长");
WorkFlowProssNodeDefinition node3 = new WorkFlowProssNodeDefinition(2,1002,2,"班主任");
definitions.add(node1);
definitions.add(node2);
definitions.add(node3);
}
return definitions;
}
}
Mapper实现
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.idc.mapper.MeteWorkProcessNodeNongHangMapper">
<select id="list" resultType="com.idc.entity.MeteWorkProcessNodeNongHang">
select * from mete_work_process_node_nonghang
</select>
<select id="selectById" resultType="com.idc.entity.MeteWorkProcessNodeNongHang">
select * from mete_work_process_node_nonghang
where id =
</select>
<insert id="insert">
INSERT INTO `energy`.`mete_work_process_node_nonghang`(
`work_id`, `business_id`, `audit_user_id`,`audit_user_name`,
`audit_user_remark`, `audit_time`,`audit_status`, `delete_state`)
VALUES (
NULL,NULL,
);
</insert>
<select id="selectWorkProcessNodeInfo" resultMap="oneToOne">
select * from mete_work_process_node_nonghang
</select>
<!
<select id="selectAgendaList" resultMap="oneToOne">
select
a.id as `process_node_id`,a.work_id,a.business_id ,a.audit_user_id ,a.audit_user_name,
a.audit_user_remark ,a.audit_time,a.audit_status,a.delete_state,b.*
from
mete_work_process_node_nonghang a
left join
mete_work_nonghang b
on
a.work_id = b.id
where
a.audit_user_id =
<if test="workId != null and workId != ''">
and b.id =
</if>
<if test="startTime != null and startTime != '' and endTime != null and endTime != ''">
and b.create_time between
</if>
</select>
<!
<select id="auditHistory" resultType="com.idc.entity.MeteWorkProcessNodeNongHang">
select * from mete_work_process_node_nonghang
where work_id =
order by id
</select>
<!
<update id="auditPass">
update mete_work_process_node_nonghang
set audit_status =
where
id =
</update>
<!
<update id="flowNext">
update mete_work_process_node_nonghang set audit_status =
where id =
</update>
<!
<select id="selectWorkProcessNodeInfoByWorkFlowStatus" resultType="com.idc.entity.MeteWorkProcessNodeNongHang">
select * from mete_work_process_node_nonghang
where work_id =
</select>
<update id="updateStatusById">
update mete_work_process_node_nonghang set audit_status =
where id =
</update>
<update id="updateStatusByIdAndStatus">
update mete_work_process_node_nonghang set audit_status =
where id =
</update>
<delete id="deleteHistoryByStatus">
delete from mete_work_process_node_nonghang
where work_id =
</delete>
</mapper>