This commit is contained in:
那些花儿
2025-07-28 10:48:38 +08:00
parent 030cf7cc4c
commit 3b51ed7a51
450 changed files with 82310 additions and 1213 deletions
@@ -0,0 +1,46 @@
//package com.budwk.app.flow.service;
//
//import com.baomidou.mybatisplus.extension.service.IService;
//import com.budwk.app.base.service.BaseService;
//import com.budwk.app.flow.entity.ProcessCcInstance;
//import com.mldong.base.CommonPage;
//import com.mldong.modules.wf.dto.ProcessCcInstancePageParam;
//import com.mldong.modules.wf.dto.ProcessCcInstanceParam;
//import com.mldong.modules.wf.entity.ProcessCcInstance;
//import com.mldong.modules.wf.vo.ProcessCcInstanceVO;
///**
// * <p>
// * 流程实例抄送 服务类
// * </p>
// *
// * @author mldong
// * @since 2023-12-05
// */
//public interface ProcessCcInstanceService extends BaseService<ProcessCcInstance> {
// /**
// * 添加流程实例抄送
// * @param param
// * @return
// */
// boolean save(ProcessCcInstanceParam param);
//
// /**
// * 更新流程实例抄送
// * @param param
// * @return
// */
// boolean update(ProcessCcInstanceParam param);
//
// /**
// * 自定义分页查询流程实例抄送
// * @param param
// * @return
// */
// CommonPage<ProcessCcInstanceVO> page(ProcessCcInstancePageParam param);
// /**
// * 通过id查询
// * @param id
// * @return
// */
// ProcessCcInstanceVO findById(Long id);
//}
@@ -0,0 +1,161 @@
package com.budwk.app.flow.service;
import cn.hutool.core.lang.Dict;
import cn.hutool.json.JSONObject;
import com.budwk.app.base.enums.UpAndDownParam;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.flow.engine.model.ProcessModel;
import com.budwk.app.flow.entity.ProcessDefine;
import com.budwk.app.flow.vo.ProcessDefineVO;
import java.io.InputStream;
/**
* <p>
* 流程定义 服务类
* </p>
*
* @author mldong
* @since 2023-09-26
*/
public interface ProcessDefineService extends BaseService<ProcessDefine> {
/**
* 添加流程定义
* @param param
* @return
*/
boolean save(ProcessDefine param);
/**
* 更新流程定义
* @param param
* @return
*/
boolean update(ProcessDefine param);
/**
* 自定义分页查询流程定义
* @param param
* @return
*/
// CommonPage<ProcessDefineVO> page(ProcessDefinePageParam param);
/**
* 通过id查询
* @param id
* @return
*/
ProcessDefineVO findById(Long id);
/**
* 部署流程定义文件,同name存在多个版本
* @param inputStream
* @see #deploy(byte[])
* @return Long
* @see Long deploy(byte[] bytes);
*/
Long deploy(InputStream inputStream);
/**
* 部署流程定义文件,同name存在多个版本
* @param bytes
* @return Long
*/
Long deploy(byte[] bytes);
/**
* 部署流程定义文件,同name存在多个版本
* @param defineJsonStr
* @see #deploy(byte[])
* @return Long
* @see Long deploy(byte[] bytes);
*/
Long deploy(String defineJsonStr);
/**
* 重新部署定义文件,按id更新json
* @param processDefineId
* @param inputStream
* @return Long
*/
void redeploy(Long processDefineId,InputStream inputStream);
/**
* 重新部署定义文件,按id更新json
* @param processDefineId
* @param bytes
* @return Long
*/
void redeploy(Long processDefineId,byte[] bytes);
/**
* 重新部署定义文件,按id更新json
* @param defineJsonStr
* @return Long
*/
void redeploy(Long processDefineId,String defineJsonStr);
/**
* 卸载流程
* @param processDefineId
*/
void unDeploy(Long processDefineId);
/**
* 回恢流程
* @param processDefineId
*/
void reDeploy(Long processDefineId);
/**
* 只更新type
* @param processDefineId
* @param type
*/
void updateType(Long processDefineId, String type);
/**
* 根据ID获取流程定义对象
* @param processDefineId
* @return
*/
ProcessDefine getById(Long processDefineId);
/**
* 根据id获取流程模型
* @param processDefineId
* @return
*/
ProcessModel getProcessModel(Long processDefineId);
/**
* 流程定义转成流程模型
* @param processDefine
* @return
*/
ProcessModel processDefineToModel(ProcessDefine processDefine);
/**
* 根据id获取定义json字符串
* @param processDefineId
* @return
*/
String getDefineJsonStr(Long processDefineId);
/**
* 获取流程定义json对象
* @param processDefineId
* @return
*/
JSONObject getDefineJsonObject(Long processDefineId);
/**
* 启用/禁用
* @param param
*/
void upAndDown(UpAndDownParam param);
/**
* 根据名称获取最新的流程定义
* @param name
* @return
*/
ProcessDefine getLastByName(String name);
/**
* 通过流程定义名称和版本获取流程定义
* @param name
* @param version
* @return
*/
ProcessDefine getProcessDefineByVersion(String name,Integer version);
}
@@ -0,0 +1,49 @@
package com.budwk.app.flow.service;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.flow.entity.ProcessDesignHis;
import com.budwk.app.flow.vo.ProcessDesignHisVO;
/**
* <p>
* 流程设计历史 服务类
* </p>
*
* @author mldong
* @since 2023-09-25
*/
public interface ProcessDesignHisService extends BaseService<ProcessDesignHis> {
/**
* 添加流程设计历史
* @param param
* @return
*/
boolean save(ProcessDesignHis param);
/**
* 更新流程设计历史
* @param param
* @return
*/
boolean update(ProcessDesignHis param);
/**
* 自定义分页查询流程设计历史
* @param param
* @return
*/
// CommonPage<ProcessDesignHisVO> page(ProcessDesignHisPageParam param);
/**
* 通过id查询
* @param id
* @return
*/
ProcessDesignHisVO findById(Long id);
/**
* 获取最新的流程设计
* @param processDesignId
* @return
*/
ProcessDesignHis getLatestByProcessDesignId(Long processDesignId);
}
@@ -0,0 +1,58 @@
package com.budwk.app.flow.service;
import cn.hutool.json.JSONObject;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.flow.entity.ProcessDesign;
import com.budwk.app.flow.vo.ProcessDesignTypeVO;
import java.util.List;
/**
* <p>
* 流程设计 服务类
* </p>
*
* @author mldong
* @since 2023-09-25
*/
public interface ProcessDesignService extends BaseService<ProcessDesign> {
/**
* 添加流程设计
* @param param
* @return
*/
boolean save(ProcessDesign param);
/**
* 更新流程设计
* @param param
* @return
*/
boolean update(ProcessDesign param);
/**
* 更新流程定义信息
* @param jsonObject
* @return
*/
boolean updateDefine(JSONObject jsonObject);
/**
* 流程定义部署
* @param processDesignId
*/
void deploy(Long processDesignId);
/**
* 重新部署流程定义文件,覆盖最新版本(即不生成新版本)
* @param processDesignId
*/
void redeploy(Long processDesignId);
/**
* 按流程分类给流程设计分组
* @return
*/
List<ProcessDesignTypeVO> listByType();
}
@@ -0,0 +1,236 @@
package com.budwk.app.flow.service;
import cn.hutool.core.lang.Dict;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.base.vo.LabelValueVO;
import com.budwk.app.flow.engine.core.Execution;
import com.budwk.app.flow.engine.model.TaskModel;
import com.budwk.app.flow.entity.ProcessDefine;
import com.budwk.app.flow.entity.ProcessInstance;
import com.budwk.app.flow.vo.HighLightVO;
import com.budwk.app.flow.vo.ProcessInstanceVO;
import com.budwk.app.flow.vo.ProcessTaskVO;
import java.util.List;
/**
* <p>
* 流程实例 服务类
* </p>
*
* @author mldong
* @since 2023-09-26
*/
public interface ProcessInstanceService extends BaseService<ProcessInstance> {
/**
* 添加流程实例
*
* @param param
* @return
*/
boolean save(ProcessInstance param);
/**
* 更新流程实例
*
* @param param
* @return
*/
boolean update(ProcessInstance param);
/**
* 自定义分页查询流程实例
* @param param
* @return
*/
// CommonPage<ProcessInstanceVO> page(ProcessInstancePageParam param);
/**
* 通过id查询
*
* @param id
* @return
*/
ProcessInstanceVO findById(Long id);
/**
* 将流程实例修改为已完成
*
* @param processInstanceId
*/
void finishProcessInstance(Long processInstanceId);
/**
* 将流程实例修改为拒绝
*
* @param processInstanceId
*/
void rejectProcessInstance(Long processInstanceId);
/**
* 根据流程、操作人员、父流程实例ID创建流程实例
*
* @param processDefine 流程定义对象
* @param businessKey 业务KEY
* @param operator 操作人员ID
* @param args 参数列表
* @return ProcessInstance 活动流程实例对象
*/
ProcessInstance createProcessInstance(ProcessDefine processDefine, String businessKey, String operator, Dict args);
/**
* 根据流程、操作人员、父流程实例ID创建流程实例
*
* @param processDefine 流程定义对象
* @param businessKey 业务KEY
* @param operator 操作人员ID
* @param args 参数列表
* @param parentId
* @param parentNodeName
* @return ProcessInstance 活动流程实例对象
*/
ProcessInstance createProcessInstance(ProcessDefine processDefine, String businessKey, String operator, Dict args, Long parentId, String parentNodeName);
/**
* 向指定实例id添加全局变量数据
*
* @param processDefineId 实例id
* @param args 变量数据
*/
void addVariable(Long processDefineId, Dict args);
/**
* 移除指定实例id中的全局变量
*
* @param processDefineId 实例id
* @param keys 移除变量keys
*/
void removeVariable(Long processDefineId, String... keys);
/**
* 保存流程实例
*
* @param processInstance 流程实例对象
*/
void saveProcessInstance(ProcessInstance processInstance);
/**
* 流程实例强制终止与唤醒相对应
*
* @param processInstanceId 流程实例id
* @param operator 处理人员
*/
void interrupt(Long processInstanceId, String operator);
/**
* 唤醒历史流程实例与终止相对应
*
* @param processInstanceId 流程实例id
* @param operator
*/
void resume(Long processInstanceId, String operator);
/**
* 挂起流程与激活相对应
*
* @param processInstanceId 流程实例id
* @param operator 处理人员
*/
void pending(Long processInstanceId, String operator);
/**
* 激活流程与挂起相对应
*
* @param processInstanceId
* @param operator
*/
void activate(Long processInstanceId, String operator);
/**
* 更新流程实例
*
* @param processInstance 流程实例对象
*/
void updateProcessInstance(ProcessInstance processInstance);
/**
* 根据ID获取流程实例
*
* @param id
* @return
*/
ProcessInstance getById(Long id);
/**
* 启动且执行流程(自动执行第一个节点)
*
* @param processDefineId
* @param args
*/
Dict startAndExecute(Long processDefineId, Dict args);
/**
* 获取流程实例高亮数据
*
* @param processInstanceId
* @return
*/
HighLightVO highLight(Long processInstanceId);
/**
* 审批记录
*
* @param processInstanceId
* @return
*/
List<ProcessTaskVO> approvalRecord(Long processInstanceId);
/**
* 撤回
*
* @param processInstanceId
* @param operator
*/
void withdraw(Long processInstanceId, String operator);
/**
* 更新会签变量
*
* @param taskModel
* @param execution
* @param taskActors
*/
void updateCountersignVariable(TaskModel taskModel, Execution execution, List<String> taskActors);
/**
* 创建实例抄送
*
* @param processInstanceId
* @param creator
* @param actorIds
*/
void createCCInstance(Long processInstanceId, String creator, String... actorIds);
/**
* 更新抄送状态
*
* @param processInstanceId
* @param actorId
*/
void updateCCStatus(Long processInstanceId, String actorId);
/**
* 自定义分页查询我的抄送
* @param param
* @return
*/
// CommonPage<ProcessInstanceVO> ccInstancePage(ProcessInstancePageParam param);
/**
* 获取流程参与人回显文本数据
*
* @param processInstanceId
* @return
*/
List<LabelValueVO> getAssigneeTextData(Long processInstanceId);
}
@@ -0,0 +1,50 @@
package com.budwk.app.flow.service;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.flow.entity.ProcessSurrogate;
import com.budwk.app.flow.vo.ProcessSurrogateVO;
/**
* <p>
* 流程委托代理 服务类
* </p>
*
* @author mldong
* @since 2023-12-06
*/
public interface ProcessSurrogateService extends BaseService<ProcessSurrogate> {
/**
* 添加流程委托代理
* @param param
* @return
*/
boolean save(ProcessSurrogate param);
/**
* 更新流程委托代理
* @param param
* @return
*/
boolean update(ProcessSurrogate param);
/**
* 自定义分页查询流程委托代理
* @param param
* @return
*/
// CommonPage<ProcessSurrogateVO> page(ProcessSurrogatePageParam param);
/**
* 通过id查询
* @param id
* @return
*/
ProcessSurrogateVO findById(Long id);
/**
* 获取代理人
* @param operator
* @param processName
* @return
*/
String getSurrogate(String operator,String processName);
}
@@ -0,0 +1,43 @@
package com.budwk.app.flow.service;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.flow.entity.ProcessTaskActor;
import com.budwk.app.flow.vo.ProcessTaskActorVO;
/**
* <p>
* 流程任务和参与人关系 服务类
* </p>
*
* @author mldong
* @since 2023-09-26
*/
public interface ProcessTaskActorService extends BaseService<ProcessTaskActor> {
/**
* 添加流程任务和参与人关系
* @param param
* @return
*/
boolean save(ProcessTaskActor param);
/**
* 更新流程任务和参与人关系
* @param param
* @return
*/
boolean update(ProcessTaskActor param);
/**
* 自定义分页查询流程任务和参与人关系
* @param param
* @return
*/
// CommonPage<ProcessTaskActorVO> page(ProcessTaskActorPageParam param);
/**
* 通过id查询
* @param id
* @return
*/
ProcessTaskActorVO findById(Long id);
}
@@ -0,0 +1,194 @@
package com.budwk.app.flow.service;
import cn.hutool.core.lang.Dict;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.base.vo.LabelValueVO;
import com.budwk.app.flow.engine.core.Execution;
import com.budwk.app.flow.engine.model.CustomModel;
import com.budwk.app.flow.engine.model.ProcessModel;
import com.budwk.app.flow.engine.model.TaskModel;
import com.budwk.app.flow.entity.ProcessTask;
import com.budwk.app.flow.vo.ProcessTaskVO;
import java.util.List;
import java.util.Map;
/**
* <p>
* 流程任务 服务类
* </p>
*
* @author mldong
* @since 2023-09-26
*/
public interface ProcessTaskService extends BaseService<ProcessTask> {
/**
* 添加流程任务
* @param param
* @return
*/
boolean save(ProcessTask param);
/**
* 更新流程任务
* @param param
* @return
*/
boolean update(ProcessTask param);
/**
* 自定义分页查询流程任务
* @param param
* @return
*/
// CommonPage<ProcessTaskVO> page(ProcessTaskPageParam param);
/**
* 通过id查询
* @param id
* @return
*/
ProcessTaskVO findById(Long id);
/**
* 保存流程任务
* @param processTask
*/
void saveProcessTask(ProcessTask processTask);
/**
* 更新流程任务
* @param processTask
*/
void updateProcessTask(ProcessTask processTask);
/**
* 根据流程实例ID获取正在进行的任务
* @param processInstanceId 流程实例ID
* @param taskNames 任务名称
* @return
*/
List<ProcessTask> getDoingTaskList(Long processInstanceId, String[] taskNames);
/**
* 根据流程实例ID获取已完成的任务
* @param processInstanceId 流程实例ID
* @param taskNames 任务名称
* @return
*/
List<ProcessTask> getDoneTaskList(Long processInstanceId, String[] taskNames);
/**
* 将流程任务修改为已完成
* @param processTaskId
* @param operator 任务处理人
* @param args
*/
void finishProcessTask(Long processTaskId, String operator, Dict args);
/**
* 废弃任务
* @param processTaskId
* @param operator
* @param args
*/
void abandonProcessTask(Long processTaskId, String operator, Dict args);
/**
* 根据任务模型和流程执行对象创建任务
* @param taskModel
* @param execution
* @return
*/
List<ProcessTask> createTask(TaskModel taskModel, Execution execution);
/**
* 通过id获取流程任务
* @param id
* @return
*/
ProcessTask getById(Long id);
/**
* 向指定的任务id添加参与者
* @param processTaskId 任务id
* @param actors 参与者
*/
void addTaskActor(Long processTaskId, List<String> actors);
/**
* 向指定的任务id添加参与者
* @param processTaskId 流程任务id
* @param actors 参与者
*/
void addCandidateActor(Long processTaskId, List<String> actors);
/**
* 向指定任务移除参与者
* @param processTaskId 任务id
* @param actors 参与者
*/
void removeTaskActor(Long processTaskId, List<String> actors);
/**
* 根据taskId、operator,判断操作人operator是否允许执行任务
* @param task 任务对象
* @param operator 操作人
* @return boolean 是否允许操作
*/
boolean isAllowed(ProcessTask task, String operator);
/**
* 根据任务ID获取参与者ID
* @param processTaskId
* @return
*/
List<String> getTaskActors(Long processTaskId);
/**
* 查询待办列表
* @param param
* @return
*/
// CommonPage<ProcessTaskVO> todoList(ProcessTaskPageParam param);
/**
* 查询已办列表
* @param param
* @return
*/
// CommonPage<ProcessTaskVO> doneList(ProcessTaskPageParam param);
/**
* 根据当前任务对象驳回至上一步处理
* @param model 流程定义模型,用以获取上一步模型对象
* @param currentTask 当前任务对象
* @return Task 任务对象
*/
ProcessTask rejectTask(ProcessModel model, ProcessTask currentTask);
/**
* 获取可跳转的任务节点名称
* @param processInstanceId
* @return
*/
List<LabelValueVO> jumpAbleTaskNameList(Long processInstanceId);
/**
* 分页查询获取候选人
* @param query
* @return
*/
// CommonPage<Map<String,Object>> candidatePage(Dict query);
/**
* 创建会签任务
* @param taskModel
* @param execution
* @return
*/
List<ProcessTask> createCountersignTask(TaskModel taskModel, Execution execution);
/**
* 根据执行对象、自定义节点模型创建历史任务记录
* @param execution 执行对象
* @param model 自定义节点模型
* @return 历史任务
*/
ProcessTask history(Execution execution, CustomModel model);
/**
* 根据流程实例ID获取最新的进行中的任务
* @param processInstanceId
* @return
*/
ProcessTaskVO latest(Long processInstanceId);
}
@@ -0,0 +1,242 @@
package com.budwk.app.flow.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.budwk.app.base.enums.UpAndDownParam;
import com.budwk.app.base.exception.BaseException;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.flow.engine.model.ProcessModel;
import com.budwk.app.flow.engine.parser.ModelParser;
import com.budwk.app.flow.entity.ProcessDefine;
import com.budwk.app.flow.entity.ProcessInstance;
import com.budwk.app.flow.service.ProcessDefineService;
import com.budwk.app.flow.vo.ProcessDefineVO;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.IocBean;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.List;
@IocBean(args = {"refer:dao"})
public class ProcessDefineServiceImpl extends BaseServiceImpl<ProcessDefine> implements ProcessDefineService {
public ProcessDefineServiceImpl(Dao dao) {
super(dao);
}
@Override
@Aop(TransAop.READ_COMMITTED)
public boolean save(ProcessDefine param) {
param.setId(null);
insert(param);
return true;
}
@Override
public boolean update(ProcessDefine param) {
updateIgnoreNull(param);
return true;
}
@Override
@Aop(TransAop.READ_COMMITTED)
public ProcessDefineVO findById(Long id) {
ProcessDefine define = fetch(id);
ProcessDefineVO defineVO = BeanUtil.copyProperties(define, ProcessDefineVO.class);
if (defineVO != null) {
defineVO.setJsonObject(getDefineJsonObject(id));
}
return defineVO;
}
@Override
public Long deploy(InputStream inputStream) {
return deploy(IoUtil.readBytes(inputStream));
}
@Override
public Long deploy(byte[] bytes) {
// Date now = new Date();
// 1. json定义文件转成流程模型
// ProcessModel processModel = ModelParser.parse(bytes);
// 2. 根据名称查询,取最新版本的流程定义记录
// List<ProcessDefine> processDefineList = query(Cnd.where(ProcessDefine::getName, "=", processModel.getName()).desc(ProcessDefine::getId));
//
// ProcessDefine processDefine = null;
// // 3.1 如果存在,则版本+1,并插入一条新的流程定义记录
// if (!processDefineList.isEmpty()) {
// processDefine = processDefineList.get(0);
// processDefine.setId(null);
// processDefine.setVersion(processDefine.getVersion() + 1);
// } else {
// // 3.2 如果不存在,则版本默认为1,并插入一条新的流程定义记录
// processDefine = new ProcessDefine();
// processDefine.setVersion(0);
// }
// processDefine.setName(processModel.getName());
// processDefine.setDisplayName(processModel.getDisplayName());
// processDefine.setType(processModel.getType());
// processDefine.setState(1);
//// processDefine.setContent(bytes);
// insert(processDefine);
// return processDefine.getId();
return null;
}
@Override
@Aop(TransAop.READ_COMMITTED)
public Long deploy(String defineJsonStr) {
Date now = new Date();
// 1. json定义文件转成流程模型
ProcessModel processModel = ModelParser.parse(defineJsonStr);
// 2. 根据名称查询,取最新版本的流程定义记录
List<ProcessDefine> processDefineList = query(Cnd.where(ProcessDefine::getName, "=", processModel.getName()).desc(ProcessDefine::getId));
ProcessDefine latestDefine = dao().fetch(ProcessDefine.class, Cnd.where(ProcessDefine::getName, "=", processModel.getName()).desc(ProcessDefine::getId));
ProcessDefine define = null;
if (latestDefine != null) {
define = latestDefine;
define.setId(null);
define.setVersion(latestDefine.getVersion() + 1);
} else {
define = new ProcessDefine();
define.setVersion(1);
}
define.setName(processModel.getName());
define.setDisplayName(processModel.getDisplayName());
define.setCategory(processModel.getCategory());
define.setInstanceUrl(processModel.getInstanceUrl());
define.setH5InstanceUrl(processModel.getH5InstanceUrl());
define.setState(1);
define.setContent(JSONUtil.parseObj(defineJsonStr));
insert(define);
return define.getId();
}
@Override
public void redeploy(Long processDefineId, InputStream inputStream) {
redeploy(processDefineId, IoUtil.readBytes(inputStream));
}
@Override
public void redeploy(Long processDefineId, byte[] bytes) {
Date now = new Date();
// // 1. json定义文件转成流程模型
// ProcessModel processModel = ModelParser.parse(bytes);
// // 2. 构造模型定义信息
// ProcessDefine processDefine = new ProcessDefine();
// processDefine.setId(processDefineId);
// processDefine.setType(processModel.getType());
// processDefine.setName(processModel.getName());
// processDefine.setDisplayName(processModel.getDisplayName());
//// processDefine.setContent(bytes);
// // 3. 更新模型定义文件
// updateIgnoreNull(processDefine);
}
@Override
public void redeploy(Long processDefineId, String defineJsonStr) {
redeploy(processDefineId, defineJsonStr.getBytes());
}
@Override
public void unDeploy(Long processDefineId) {
ProcessDefine processDefine = new ProcessDefine();
processDefine.setId(processDefineId);
processDefine.setState(0);
updateIgnoreNull(processDefine);
}
@Override
public void reDeploy(Long processDefineId) {
ProcessDefine processDefine = new ProcessDefine();
processDefine.setId(processDefineId);
processDefine.setState(1);
updateIgnoreNull(processDefine);
}
@Override
public void updateType(Long processDefineId, String type) {
ProcessDefine processDefine = new ProcessDefine();
processDefine.setId(processDefineId);
processDefine.setType(type);
updateIgnoreNull(processDefine);
}
@Override
public ProcessDefine getById(Long processDefineId) {
return fetch(processDefineId);
}
@Override
public ProcessModel getProcessModel(Long processDefineId) {
return processDefineToModel(getById(processDefineId));
}
@Override
public ProcessModel processDefineToModel(ProcessDefine processDefine) {
if (processDefine == null) return null;
ProcessModel processModel = ModelParser.parse(JSONUtil.toJsonStr(processDefine.getContent()));
// 注:后续再进行缓存优化,减少频繁解析
return processModel;
}
@Override
public String getDefineJsonStr(Long processDefineId) {
ProcessDefine processDefine = getById(processDefineId);
if (processDefine == null) return null;
return JSONUtil.toJsonStr(processDefine.getContent());
}
@Override
public JSONObject getDefineJsonObject(Long processDefineId) {
String s = Convert.toStr(getDefineJsonStr(processDefineId), "{}");
return JSONUtil.parseObj(s);
}
@Override
public void upAndDown(UpAndDownParam param) {
}
@Override
public ProcessDefine getLastByName(String name) {
return fetch(Cnd.where(ProcessDefine::getName, "=", name).and(ProcessDefine::getState, "=", 1).desc(ProcessDefine::getVersion));
}
@Override
public ProcessDefine getProcessDefineByVersion(String name, Integer version) {
Cnd cnd = Cnd.NEW();
cnd.and(ProcessDefine::getName, "=", name);
cnd.andEX(ProcessDefine::getVersion, "=", 1);
cnd.desc(ProcessDefine::getId);
// List<ProcessDefine> list = query(cnd);
ProcessDefine define = fetch(cnd);
return define;
// LambdaQueryWrapper<ProcessDefine> queryWrapper = Wrappers.lambdaQuery(ProcessDefine.class);
// queryWrapper.eq(ProcessDefine::getName,name);
// if(version!=null) {
// queryWrapper.eq(ProcessDefine::getVersion, version);
// }
// queryWrapper.orderByDesc(ProcessDefine::getId);
// List<ProcessDefine> processDefineList = baseMapper.selectList(queryWrapper);
// if(!processDefineList.isEmpty()) {
// return processDefineList.get(0);
// }
// return null;
}
}
@@ -0,0 +1,41 @@
package com.budwk.app.flow.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.flow.entity.ProcessDesignHis;
import com.budwk.app.flow.service.ProcessDesignHisService;
import com.budwk.app.flow.vo.ProcessDesignHisVO;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.IocBean;
@IocBean(args = {"refer:dao"})
public class ProcessDesignHisServiceImpl extends BaseServiceImpl<ProcessDesignHis> implements ProcessDesignHisService {
public ProcessDesignHisServiceImpl(Dao dao) {
super(dao);
}
@Override
public boolean save(ProcessDesignHis param) {
param.setId(null);
insert(param);
return true;
}
@Override
public boolean update(ProcessDesignHis param) {
updateIgnoreNull(param);
return true;
}
@Override
public ProcessDesignHisVO findById(Long id) {
ProcessDesignHis his = fetch(id);
return BeanUtil.copyProperties(his, ProcessDesignHisVO.class);
}
@Override
public ProcessDesignHis getLatestByProcessDesignId(Long processDesignId) {
return fetch(Cnd.where(ProcessDesignHis::getProcessDesignId, "=", processDesignId).desc(ProcessDesignHis::getId));
}
}
@@ -0,0 +1,136 @@
package com.budwk.app.flow.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.budwk.app.base.exception.BaseException;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.flow.constant.FlowConst;
import com.budwk.app.flow.entity.ProcessDesign;
import com.budwk.app.flow.service.ProcessDefineService;
import com.budwk.app.flow.service.ProcessDesignService;
import com.budwk.app.flow.vo.ProcessDesignTypeVO;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
@IocBean(args = {"refer:dao"})
public class ProcessDesignServiceImpl extends BaseServiceImpl<ProcessDesign> implements ProcessDesignService {
public ProcessDesignServiceImpl(Dao dao) {
super(dao);
}
@Inject
private ProcessDefineService processDefineService;
@Override
public boolean save(ProcessDesign param) {
int count = count(Cnd.where(ProcessDesign::getName, "=", param.getName()));
if (count > 0) {
throw new BaseException("编码已存在");
}
insert(param);
return true;
}
@Override
public boolean update(ProcessDesign param) {
int count = count(Cnd.where(ProcessDesign::getId, "!=", param.getId()).and(ProcessDesign::getName, "=", param.getName()));
if (count > 0) {
throw new BaseException("编码已存在");
}
updateIgnoreNull(param);
return true;
}
// @Override
// public ProcessDesignVO findById(Long id) {
// ProcessDesignVO vo = BeanUtil.copyProperties(fetch(id), ProcessDesignVO.class);
// byte[] content = vo.getContent();
// if (content != null) {
// String jsonStr = Convert.toStr(StrUtil.str(content, Charset.defaultCharset()), "{}");
// JSONObject jsonObject = JSONUtil.parseObj(jsonStr);
// vo.setJsonObject(jsonObject);
// }
// JSONObject jsonObject = vo.getJsonObject();
// if (!jsonObject.containsKey(FlowConst.PROCESS_NAME_KEY)) {
// jsonObject.set(FlowConst.PROCESS_NAME_KEY, vo.getName());
// }
// if (!jsonObject.containsKey(FlowConst.PROCESS_DISPLAY_NAME_KEY)) {
// jsonObject.set(FlowConst.PROCESS_DISPLAY_NAME_KEY, vo.getDisplayName());
// }
// if (!jsonObject.containsKey("category")) {
// jsonObject.set("category", vo.getType());
// }
// if (!jsonObject.containsKey("instanceUrl")) {
// jsonObject.set("instanceUrl", vo.getInstanceUrl());
// }
// if (!jsonObject.containsKey("h5InstanceUrl")) {
// jsonObject.set("h5InstanceUrl", vo.getH5InstanceUrl());
// }
// return vo;
// return null;
// }
@Override
public boolean updateDefine(JSONObject jsonObject) {
Long processDesignId = jsonObject.getLong(FlowConst.PROCESS_DESIGN_ID_KEY);
jsonObject.remove(FlowConst.PROCESS_DESIGN_ID_KEY);
String name = jsonObject.getStr(FlowConst.PROCESS_NAME_KEY);
String displayName = jsonObject.getStr(FlowConst.PROCESS_DISPLAY_NAME_KEY);
String type = jsonObject.getStr(FlowConst.PROCESS_TYPE);
String instanceUrl = jsonObject.getStr("instanceUrl");
String h5InstanceUrl = jsonObject.getStr("h5InstanceUrl");
String category = jsonObject.getStr("category");
ProcessDesign processDesign = new ProcessDesign();
processDesign.setId(processDesignId);
processDesign.setName(name);
processDesign.setDisplayName(displayName);
processDesign.setCategory(category);
processDesign.setInstanceUrl(instanceUrl);
processDesign.setH5InstanceUrl(h5InstanceUrl);
processDesign.setIsDeployed(0);
// processDesign.setType(type);
update(processDesign);
return true;
}
@Override
@Aop(TransAop.READ_COMMITTED)
public void deploy(Long processDesignId) {
ProcessDesign design = fetch(processDesignId);
design.setIsDeployed(1);
update(design);
// 部署到流程定义
processDefineService.deploy(JSONUtil.toJsonStr(design.getContent()));
}
@Override
public void redeploy(Long processDesignId) {
ProcessDesign design = fetch(processDesignId);
design.setIsDeployed(0);
dao().update(design, "isDeployed");
}
@Override
public List<ProcessDesignTypeVO> listByType() {
return List.of();
}
}
@@ -0,0 +1,534 @@
package com.budwk.app.flow.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.expression.ExpressionUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.budwk.app.base.enums.YesNoEnum;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.base.vo.LabelValueVO;
import com.budwk.app.flow.constant.FlowConst;
import com.budwk.app.flow.engine.Context;
import com.budwk.app.flow.engine.DecisionHandler;
import com.budwk.app.flow.engine.FlowEngine;
import com.budwk.app.flow.engine.core.Execution;
import com.budwk.app.flow.engine.core.ServiceContext;
import com.budwk.app.flow.engine.handlers.impl.MergeBranchHandler;
import com.budwk.app.flow.engine.model.*;
import com.budwk.app.flow.engine.util.FlowUtil;
import com.budwk.app.flow.entity.ProcessCcInstance;
import com.budwk.app.flow.entity.ProcessDefine;
import com.budwk.app.flow.entity.ProcessInstance;
import com.budwk.app.flow.entity.ProcessTask;
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
import com.budwk.app.flow.enums.ProcessSubmitTypeEnum;
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
import com.budwk.app.flow.service.ProcessDefineService;
import com.budwk.app.flow.service.ProcessInstanceService;
import com.budwk.app.flow.service.ProcessTaskService;
import com.budwk.app.flow.vo.HighLightVO;
import com.budwk.app.flow.vo.ProcessInstanceVO;
import com.budwk.app.flow.vo.ProcessTaskVO;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
import java.util.*;
import java.util.stream.Collectors;
@IocBean(args = {"refer:dao"})
public class ProcessInstanceServiceImpl extends BaseServiceImpl<ProcessInstance> implements ProcessInstanceService {
public ProcessInstanceServiceImpl(Dao dao) {
super(dao);
}
@Inject
private ProcessDefineService processDefineService;
@Override
@Aop(TransAop.READ_COMMITTED)
public boolean save(ProcessInstance param) {
param.setId(null);
insert(param);
return true;
}
@Override
public boolean update(ProcessInstance param) {
updateIgnoreNull(param);
return true;
}
@Override
public ProcessInstanceVO findById(Long id) {
Sql sql = Sqls.create("""
SELECT
pd.NAME,
pd.displayName,
pd.version,
t.*
FROM
wf_process_instance t
LEFT JOIN wf_process_define pd ON t.processDefineId = pd.id
WHERE
t.id = @id
""");
sql.setParam("id", id);
sql.setCallback(Sqls.callback.map());
execute(sql);
NutMap nutMap = (NutMap) sql.getResult();
ProcessInstanceVO instanceVO = new ProcessInstanceVO();
BeanUtil.fillBeanWithMapIgnoreCase(nutMap, instanceVO, true);
instanceVO.setJsonObject(processDefineService.getDefineJsonObject(instanceVO.getProcessDefineId()));
return instanceVO;
}
@Override
@Aop(TransAop.READ_COMMITTED)
public void finishProcessInstance(Long processInstanceId) {
ProcessInstance processInstance = new ProcessInstance();
processInstance.setId(processInstanceId);
processInstance.setState(ProcessInstanceStateEnum.FINISHED.getCode());
updateIgnoreNull(processInstance);
}
@Override
public void rejectProcessInstance(Long processInstanceId) {
ProcessInstance processInstance = new ProcessInstance();
processInstance.setId(processInstanceId);
processInstance.setState(ProcessInstanceStateEnum.REJECT.getCode());
updateIgnoreNull(processInstance);
}
@Override
public ProcessInstance createProcessInstance(ProcessDefine processDefine, String businessKey, String operator, Dict args) {
return createProcessInstance(processDefine, businessKey, operator, args, null, null);
}
@Override
public ProcessInstance createProcessInstance(ProcessDefine processDefine, String businessKey, String operator, Dict args, Long parentId, String parentNodeName) {
if (args == null) {
args = Dict.create();
}
// 追加用户信息到参数
FlowUtil.addUserInfoToArgs(operator, args);
// 追加自动构造标题
FlowUtil.addAutoGenTitle(processDefine.getDisplayName(), args);
ProcessInstance processInstance = new ProcessInstance();
processInstance.setParentId(parentId);
processInstance.setParentNodeName(parentNodeName);
processInstance.setProcessDefineId(processDefine.getId());
processInstance.setOperator(operator);
processInstance.setState(ProcessInstanceStateEnum.DOING.getCode());
processInstance.setBusinessNo(businessKey);
processInstance.setVariable(JSONUtil.toJsonStr(args));
ProcessModel processModel = ServiceContext.find(ProcessDefineService.class).processDefineToModel(processDefine);
String expireTime = processModel.getExpireTime();
if (StrUtil.isNotEmpty(expireTime)) {
processInstance.setExpireTime(FlowUtil.processTime(expireTime, args));
}
saveProcessInstance(processInstance);
return processInstance;
}
@Override
public void addVariable(Long processDefineId, Dict args) {
ProcessInstance processInstance = fetch(processDefineId);
Dict newDict = Dict.create();
newDict.putAll(JSONUtil.toBean(processInstance.getVariable(), Dict.class));
newDict.putAll(args);
ProcessInstance up = new ProcessInstance();
up.setId(processDefineId);
up.setVariable(JSONUtil.toJsonStr(newDict));
updateIgnoreNull(up);
}
@Override
public void removeVariable(Long processDefineId, String... keys) {
ProcessInstance processInstance = fetch(processDefineId);
Dict oldDict = JSONUtil.toBean(processInstance.getVariable(), Dict.class);
for (String key : keys) {
oldDict.remove(key);
}
ProcessInstance up = new ProcessInstance();
up.setId(processDefineId);
up.setVariable(JSONUtil.toJsonStr(oldDict));
updateIgnoreNull(up);
}
@Override
public void saveProcessInstance(ProcessInstance processInstance) {
insert(processInstance);
}
@Override
@Aop(TransAop.READ_COMMITTED)
public void interrupt(Long processInstanceId, String operator) {
Date now = new Date();
// 1. 将该流程实例产生的任务状态修改为终止
ProcessTask processTask = new ProcessTask();
processTask.setTaskState(ProcessTaskStateEnum.INTERRUPT.getCode());
dao().update(ProcessTask.class, Chain.from(processTask), Cnd.where(ProcessTask::getProcessInstanceId, "=", processInstanceId)
.and(ProcessTask::getTaskState, "=", ProcessTaskStateEnum.DOING.getCode()));
// 2. 将该流程实例状态修改为终止
ProcessInstance processInstance = new ProcessInstance();
processInstance.setState(ProcessInstanceStateEnum.INTERRUPT.getCode());
dao().update(ProcessInstance.class, Chain.from(processInstance), Cnd.where(ProcessInstance::getId, "=", processInstanceId)
.and(ProcessInstance::getState, "=", ProcessInstanceStateEnum.DOING.getCode()));
}
@Override
public void resume(Long processInstanceId, String operator) {
Date now = new Date();
ProcessInstance processInstance = fetch(processInstanceId);
// 1. 更新流程实例状态为进行中
processInstance.setState(ProcessInstanceStateEnum.DOING.getCode());
updateIgnoreNull(processInstance);
// 2.被终止的任务状态修改为进行中
ProcessTask processTask = new ProcessTask();
processTask.setTaskState(ProcessTaskStateEnum.DOING.getCode());
dao().update(ProcessTask.class, Chain.from(processTask), Cnd.where(ProcessTask::getProcessInstanceId, "=", processInstanceId)
.and(ProcessTask::getTaskState, "=", ProcessTaskStateEnum.INTERRUPT.getCode()));
}
@Override
public void pending(Long processInstanceId, String operator) {
Date now = new Date();
// 1. 将该流程实例产生的任务状态修改为挂起
ProcessTask processTask = new ProcessTask();
processTask.setTaskState(ProcessTaskStateEnum.PENDING.getCode());
dao().update(ProcessTask.class, Chain.from(processTask), Cnd.where(ProcessTask::getProcessInstanceId, "=", processInstanceId)
.and(ProcessTask::getTaskState, "=", ProcessTaskStateEnum.DOING.getCode()));
// 2. 将该流程实例状态修改为挂起
ProcessInstance processInstance = new ProcessInstance();
processInstance.setState(ProcessInstanceStateEnum.PENDING.getCode());
dao().update(ProcessInstance.class, Chain.from(processInstance), Cnd.where(ProcessInstance::getId, "=", processInstanceId)
.and(ProcessInstance::getState, "=", ProcessInstanceStateEnum.DOING.getCode()));
}
@Override
public void activate(Long processInstanceId, String operator) {
ProcessInstance processInstance = fetch(processInstanceId);
// 1. 更新流程实例状态为进行中
processInstance.setState(ProcessInstanceStateEnum.DOING.getCode());
updateIgnoreNull(processInstance);
// 2.被终止的任务状态修改为进行中
ProcessTask processTask = new ProcessTask();
processTask.setTaskState(ProcessTaskStateEnum.DOING.getCode());
dao().update(ProcessTask.class, Chain.from(processTask), Cnd.where(ProcessTask::getProcessInstanceId, "=", processInstanceId)
.and(ProcessTask::getTaskState, "=", ProcessTaskStateEnum.INTERRUPT.getCode()));
}
@Override
public void updateProcessInstance(ProcessInstance processInstance) {
updateIgnoreNull(processInstance);
}
@Override
public ProcessInstance getById(Long id) {
return fetch(id);
}
@Override
@Aop(TransAop.READ_COMMITTED)
public Dict startAndExecute(Long processDefineId, Dict args) {
Dict res = Dict.create();
String operator = SecurityUtil.getUserId();
FlowEngine flowEngine = ServiceContext.find(FlowEngine.class);
ProcessInstance processInstance = flowEngine.startProcessInstanceById(processDefineId, null, operator, args);
res.put(FlowConst.PROCESS_INSTANCE_ID_KEY, processInstance.getId());
List<ProcessTask> processTaskList = flowEngine.processTaskService().getDoingTaskList(processInstance.getId(), new String[]{});
// 取任务自动执行
processTaskList.forEach(processTask -> {
args.put(FlowConst.SUBMIT_TYPE, ProcessSubmitTypeEnum.APPLY.getCode());
flowEngine.executeProcessTask(processTask.getId(), FlowConst.AUTO_ID, args);
});
return res;
}
@Override
public HighLightVO highLight(Long processInstanceId) {
HighLightVO vo = new HighLightVO();
ProcessInstanceVO processInstance = findById(processInstanceId);
FlowEngine flowEngine = ServiceContext.find(FlowEngine.class);
if (processInstance != null) {
ProcessModel processModel = flowEngine.processDefineService().getProcessModel(processInstance.getProcessDefineId());
// 拿到正在进行中的任务==>活跃节点
List<ProcessTask> processTaskList = flowEngine.processTaskService().getDoingTaskList(processInstanceId, new String[]{});
// 拿到历史任务-按更新时间倒序
List<ProcessTask> hisProcessTaskList = flowEngine.processTaskService().query(Cnd.where(ProcessTask::getProcessInstanceId, "=", processInstanceId).desc(ProcessTask::getUpdatedAt));
processTaskList.forEach(task -> {
if (!vo.getActiveNodeNames().contains(task.getTaskName())) {
vo.getActiveNodeNames().add(task.getTaskName());
recursionModel(processModel.getStart(), processInstance, processTaskList, hisProcessTaskList, task.getTaskName(), vo);
}
});
// 拿到非正常结束的流程实例状态值
List<Integer> orderStatusList = Arrays.stream(ProcessInstanceStateEnum.values()).filter(item -> !item.equals(ProcessInstanceStateEnum.DOING) && !item.equals(ProcessInstanceStateEnum.FINISHED)).map(ProcessInstanceStateEnum::getCode).toList();
// 非正常结束,需要进行特殊处理
if (orderStatusList.contains(processInstance.getState())) {
if (CollectionUtil.isNotEmpty(hisProcessTaskList)) {
ProcessTask lastProcessTask = hisProcessTaskList.get(hisProcessTaskList.size() - 1);
NodeModel nodeModel = processModel.getNode(lastProcessTask.getTaskName());
recursionModel(processModel.getStart(), processInstance, processTaskList, hisProcessTaskList, nodeModel.getOutputs().get(0).getTo(), vo);
}
} else {
List<EndModel> endModels = processModel.getModels(EndModel.class);
if (endModels != null) {
endModels.forEach(endModel -> {
recursionModel(processModel.getStart(), processInstance, processTaskList, hisProcessTaskList, endModel.getName(), vo);
});
}
}
}
return vo;
}
@Override
public List<ProcessTaskVO> approvalRecord(Long processInstanceId) {
List<ProcessTask> processTaskList = dao().query(ProcessTask.class, Cnd.where(ProcessTask::getProcessInstanceId, "=", processInstanceId)
.and(ProcessTask::getTaskState, "not in", List.of(ProcessTaskStateEnum.DOING, ProcessTaskStateEnum.WITHDRAW, ProcessTaskStateEnum.ABANDON))
.asc(ProcessTask::getUpdatedAt));
List<ProcessTaskVO> res = new ArrayList<>();
processTaskList.forEach(processTask -> {
ProcessTaskVO vo = BeanUtil.toBean(processTask, ProcessTaskVO.class);
res.add(vo);
});
return res;
}
@Override
public void withdraw(Long processInstanceId, String operator) {
Date now = new Date();
// 1. 将该流程实例状态修改为撤回
ProcessInstance processInstance = new ProcessInstance();
processInstance.setState(ProcessInstanceStateEnum.WITHDRAW.getCode());
processInstance.setUpdatedAt(System.currentTimeMillis());
processInstance.setUpdatedBy(operator);
int update = dao().update(ProcessInstance.class, Chain.from(processInstance), Cnd.where(ProcessInstance::getId, "=", processInstanceId)
.and(ProcessInstance::getState, "=", ProcessInstanceStateEnum.DOING.getCode()));
if (update >= 1) {
// 2. 将该流程实例产生的任务状态修改为撤回
ProcessTask processTask = new ProcessTask();
processTask.setTaskState(ProcessTaskStateEnum.WITHDRAW.getCode());
processTask.setUpdatedAt(System.currentTimeMillis());
processTask.setUpdatedBy(operator);
dao().update(ProcessTask.class, Chain.from(processTask), Cnd.where(ProcessTask::getProcessInstanceId, "=", processInstanceId)
.and(ProcessTask::getTaskState, "=", ProcessTaskStateEnum.DOING.getCode()));
}
}
/**
* 递归模型处理历史节点与历史边
*
* @param nodeModel 下一个节点
* @param processInstance 历史实例
* @param processTaskList 正在进行的任务
* @param hisProcessTaskList 正在进行的任务
* @param taskName 当前任务节点名称(递归停止标识)
* @param vo 结果
*/
private void recursionModel(NodeModel nodeModel, ProcessInstance processInstance, List<ProcessTask> processTaskList, List<ProcessTask> hisProcessTaskList, String taskName, HighLightVO vo) {
if (nodeModel.getName().equals(taskName)) {
if (nodeModel instanceof EndModel) {
vo.getHistoryNodeNames().add(nodeModel.getName());
}
return;
}
if (!vo.getHistoryNodeNames().contains(nodeModel.getName())) {
vo.getHistoryNodeNames().add(nodeModel.getName());
nodeModel.getOutputs().stream().filter(output -> {
// 默认取决策节点前面第一个节点为任务节点-待优化
NodeModel defaultDecisionInputModel = null;
ProcessTask historyTask = null;
if (nodeModel instanceof DecisionModel) {
defaultDecisionInputModel = nodeModel.getInputs().get(0).getSource();
NodeModel finalDefaultDecisionInputModel = defaultDecisionInputModel;
historyTask = hisProcessTaskList.stream().filter(hisTask -> {
return finalDefaultDecisionInputModel.getName().equals(hisTask.getTaskName());
}).findFirst().orElse(null);
}
Map<String, Object> args = new HashMap<>();
args.putAll(JSONUtil.parseObj(processInstance.getVariable()));
if (historyTask != null) {
args.putAll(JSONUtil.parseObj(historyTask.getVariable()));
}
if (StrUtil.isNotEmpty(output.getExpr())
&& nodeModel instanceof DecisionModel
&& defaultDecisionInputModel != null) {
return Convert.toBool(ExpressionUtil.eval(output.getExpr(), args));
}
if (nodeModel instanceof DecisionModel) {
String expr = ((DecisionModel) nodeModel).getExpr();
String handleClass = ((DecisionModel) nodeModel).getHandleClass();
if (StrUtil.isNotEmpty(expr)) {
String nextNodeName = Convert.toStr(ExpressionUtil.eval(expr, args));
return output.getTo().equals(nextNodeName);
} else if (StrUtil.isNotEmpty(handleClass)) {
DecisionHandler decisionHandler = ReflectUtil.newInstance(handleClass);
Execution execution = new Execution();
execution.setProcessInstanceId(processInstance.getId());
execution.setProcessInstance(processInstance);
execution.setNodeModel(nodeModel);
execution.setArgs(BeanUtil.toBean(args, Dict.class));
String nextNodeName = decisionHandler.decide(execution);
return output.getTo().equals(nextNodeName);
} else {
return false;
}
}
if (nodeModel instanceof JoinModel) {
// 合并节点
boolean isMerged = MergeBranchHandler.isMerged(processInstance.getId(), nodeModel);
if (!isMerged) {
// 未能合并,要把已加入历史的节点和边删除
vo.getHistoryNodeNames().remove(nodeModel.getName());
nodeModel.getInputs().forEach(input -> {
vo.getHistoryEdgeNames().remove(input.getName());
});
}
return isMerged;
}
return true;
}).forEach(transitionModel -> {
if (!vo.getHistoryEdgeNames().contains(transitionModel.getName())) {
vo.getHistoryEdgeNames().add(transitionModel.getName());
recursionModel(transitionModel.getTarget(), processInstance, processTaskList, hisProcessTaskList, taskName, vo);
}
});
}
}
@Override
public void updateCountersignVariable(TaskModel taskModel, Execution execution, List<String> taskActors) {
/**
* ● nrOfActivateInstances:当前活动的实例数量,即还没有完成的实例数量
* ● loopCounter :循环计数器,办理人在列表中的索引
* ● nrOfInstances:会签中总共的实例数
* ● nrOfCompletedInstances:已经完成的实例数量
* ● operatorList:会签办理人列表
*/
String taskName = taskModel.getName();
Long processInstanceId = execution.getProcessInstanceId();
// 会签任务变量,csv_{taskName}_为前辍
String prefix = FlowConst.COUNTERSIGN_VARIABLE_PREFIX + taskName + "_";
Dict addVariable = Dict.create();
// 更新会签总实例数,nrOfInstances
addVariable.put(prefix + FlowConst.NR_OF_INSTANCES, taskActors.size());
// 更新会签当前活动实例数,nrOfActivateInstances
addVariable.put(prefix + FlowConst.NR_OF_ACTIVATE_INSTANCES, execution.getDoingTaskList().size());
// 更新会签已完的实例数,nrOfCompletedInstances
addVariable.put(prefix + FlowConst.NR_OF_COMPLETED_INSTANCES, execution.getArgs().get(prefix + FlowConst.NR_OF_COMPLETED_INSTANCES));
// 更新会签操作人列表countersignOperatorList
addVariable.put(prefix + FlowConst.COUNTERSIGN_OPERATOR_LIST, taskActors);
ProcessInstanceService processInstanceService = SpringUtil.getBean(ProcessInstanceService.class);
processInstanceService.addVariable(processInstanceId, addVariable);
}
@Override
public void createCCInstance(Long processInstanceId, String creator, String... actorIds) {
Date now = new Date();
Arrays.stream(actorIds).forEach(actorId -> {
// long count = processCcInstanceMapper.selectCount(
// Wrappers.lambdaQuery(ProcessCcInstance.class)
// .eq(ProcessCcInstance::getProcessInstanceId,processInstanceId)
// .eq(ProcessCcInstance::getActorId,actorId)
// );
// if(count==0) {
// // 同一条流程实例下,同一个人,只允许有一条抄送
// ProcessCcInstance processCcInstance = new ProcessCcInstance();
// processCcInstance.setProcessInstanceId(processInstanceId);
// processCcInstance.setActorId(actorId);
// processCcInstance.setState(YesNoEnum.NO.getCode());
// processCcInstance.setCreateUser(creator);
// processCcInstance.setCreateTime(now);
// processCcInstance.setUpdateUser(creator);
// processCcInstance.setUpdateTime(now);
// processCcInstanceMapper.insert(processCcInstance);
// }
});
}
@Override
public void updateCCStatus(Long processInstanceId, String actorId) {
ProcessCcInstance processCcInstance = new ProcessCcInstance();
processCcInstance.setState(1);
// processCcInstance.setUpdateTime(new Date());
// processCcInstance.setUpdateUser(actorId);
// processCcInstanceMapper.update(processCcInstance, Wrappers.<ProcessCcInstance>lambdaQuery()
// .eq(ProcessCcInstance::getProcessInstanceId,processInstanceId)
// .eq(ProcessCcInstance::getActorId,actorId));
}
@Override
public List<LabelValueVO> getAssigneeTextData(Long processInstanceId) {
List<ProcessTask> hisProcessTaskList = dao().query(ProcessTask.class, Cnd.where(ProcessTask::getProcessInstanceId, "=", processInstanceId)
.and(ProcessTask::getTaskState, "not in", List.of(ProcessTaskStateEnum.DOING.getCode(), ProcessTaskStateEnum.WITHDRAW.getCode(), ProcessTaskStateEnum.ABANDON.getCode()))
.asc(ProcessTask::getUpdatedAt));
if (CollectionUtil.isEmpty(hisProcessTaskList)) return Collections.emptyList();
// 历史任务:使用 LinkedHashMap 保持顺序并去重
Map<String, Set<String>> hisTaskToUniqueActors = new LinkedHashMap<>();
for (ProcessTask task : hisProcessTaskList) {
String taskName = task.getTaskName();
Dict dict = JSONUtil.toBean(task.getVariable(), Dict.class);
String realName = dict.getStr(FlowConst.USER_REAL_NAME);
// 初始化或获取当前taskName对应的Set
hisTaskToUniqueActors.computeIfAbsent(taskName, k -> new LinkedHashSet<>()).add(realName);
}
// 处理正在进行节点
List<ProcessTask> doingProcessTaskList = dao().query(ProcessTask.class, Cnd.where(ProcessTask::getProcessInstanceId, "=", processInstanceId)
.and(ProcessTask::getTaskState, "=", ProcessTaskStateEnum.DOING.getCode()));
// 正在进行中的任务:使用 LinkedHashMap 保持顺序并去重
Map<String, Set<String>> taskToUniqueActors = new LinkedHashMap<>();
ProcessTaskService processTaskService = ServiceContext.find(ProcessTaskService.class);
// WfUserApi wfUserApi = ServiceContext.find(WfUserApi.class);
for (ProcessTask task : doingProcessTaskList) {
String taskName = task.getTaskName();
List<String> realNameList = new ArrayList<>();
List<String> actorIds = processTaskService.getTaskActors(task.getId());
actorIds.forEach(actorId -> {
// String realName = wfUserApi.getRealName(actorId);
// if(StrUtil.isNotEmpty(realName)) {
// realNameList.add(realName);
// }
});
// 初始化或获取当前taskName对应的Set
taskToUniqueActors.computeIfAbsent(taskName, k -> new LinkedHashSet<>()).add(realNameList.stream().distinct().collect(Collectors.joining(",")));
}
// 追加到his中,重复key则覆盖
hisTaskToUniqueActors.putAll(taskToUniqueActors);
// 转换为LabelValueVO列表
List<LabelValueVO> result = hisTaskToUniqueActors.entrySet().stream()
.map(entry -> {
// 使用StrUtil.join来避免空指针异常,当集合为空时返回空字符串
String actorsJoined = StrUtil.join(",", entry.getValue());
return LabelValueVO.builder().value(entry.getKey()).label(actorsJoined).build();
})
.collect(Collectors.toList());
return result;
}
}
@@ -0,0 +1,84 @@
package com.budwk.app.flow.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.flow.entity.ProcessSurrogate;
import com.budwk.app.flow.service.ProcessSurrogateService;
import com.budwk.app.flow.vo.ProcessSurrogateVO;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.IocBean;
import java.util.List;
@IocBean(args = {"refer:dao"})
public class ProcessSurrogateServiceImpl extends BaseServiceImpl<ProcessSurrogate> implements ProcessSurrogateService {
public ProcessSurrogateServiceImpl(Dao dao) {
super(dao);
}
@Override
@Aop(TransAop.READ_COMMITTED)
public boolean save(ProcessSurrogate param) {
param.setId(null);
param.setOperator(SecurityUtil.getUserId());
insert(param);
return true;
}
@Override
public boolean update(ProcessSurrogate param) {
param.setOperator(SecurityUtil.getUserId());
updateIgnoreNull(param);
return true;
}
@Override
public ProcessSurrogateVO findById(Long id) {
ProcessSurrogate surrogate = fetch(id);
return BeanUtil.copyProperties(surrogate, ProcessSurrogateVO.class);
}
@Override
public String getSurrogate(String operator, String processName) {
List<ProcessSurrogate> processSurrogateList = query(Cnd.where(ProcessSurrogate::getOperator, "=", operator)
.and(ProcessSurrogate::getEnabled, "=", 1)
.desc(ProcessSurrogate::getId)
);
for (ProcessSurrogate processSurrogate : processSurrogateList) {
// 为空表示全部,优先级最高,直接返回
if(StrUtil.isEmpty(processSurrogate.getProcessName())) {
// 开始时间判断
if(processSurrogate.getStartTime()!= null && processSurrogate.getStartTime().getTime() > System.currentTimeMillis()) {
continue;
}
// 结束时间判断
if(processSurrogate.getEndTime()!= null && processSurrogate.getEndTime().getTime() < System.currentTimeMillis()) {
continue;
}
return processSurrogate.getSurrogate();
}
}
// 取满足条件的最新一条
return processSurrogateList.stream().filter(processSurrogate -> {
// 只查询流程名称一样的
return ObjectUtil.equals(processSurrogate.getProcessName(),processName);
}).filter(processSurrogate -> {
// 开始时间判断
if(processSurrogate.getStartTime()!= null && processSurrogate.getStartTime().getTime() > System.currentTimeMillis()) {
return false;
}
// 结束时间判断
if(processSurrogate.getEndTime()!= null && processSurrogate.getEndTime().getTime() < System.currentTimeMillis()) {
return false;
}
return true;
}).map(ProcessSurrogate::getSurrogate).findFirst().orElse(null);
}
}
@@ -0,0 +1,38 @@
package com.budwk.app.flow.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.flow.entity.ProcessTaskActor;
import com.budwk.app.flow.service.ProcessTaskActorService;
import com.budwk.app.flow.vo.ProcessTaskActorVO;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.IocBean;
@IocBean(args = {"refer:dao"})
public class ProcessTaskActorServiceImpl extends BaseServiceImpl<ProcessTaskActor> implements ProcessTaskActorService {
public ProcessTaskActorServiceImpl(Dao dao) {
super(dao);
}
@Override
public boolean save(ProcessTaskActor param) {
param.setId(null);
insert(param);
return true;
}
@Override
public boolean update(ProcessTaskActor param) {
updateIgnoreNull(param);
return true;
}
@Override
public ProcessTaskActorVO findById(Long id) {
ProcessTaskActor taskActor = fetch(id);
if (taskActor != null) {
return BeanUtil.copyProperties(taskActor, ProcessTaskActorVO.class);
}
return null;
}
}
@@ -0,0 +1,482 @@
package com.budwk.app.flow.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.expression.ExpressionUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.budwk.app.base.exception.BaseException;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.base.vo.LabelValueVO;
import com.budwk.app.flow.constant.FlowConst;
import com.budwk.app.flow.engine.AssignmentHandler;
import com.budwk.app.flow.engine.core.Execution;
import com.budwk.app.flow.engine.event.ProcessEvent;
import com.budwk.app.flow.engine.event.ProcessPublisher;
import com.budwk.app.flow.engine.model.CustomModel;
import com.budwk.app.flow.engine.model.NodeModel;
import com.budwk.app.flow.engine.model.ProcessModel;
import com.budwk.app.flow.engine.model.TaskModel;
import com.budwk.app.flow.engine.util.FlowUtil;
import com.budwk.app.flow.entity.ProcessInstance;
import com.budwk.app.flow.entity.ProcessTask;
import com.budwk.app.flow.entity.ProcessTaskActor;
import com.budwk.app.flow.enums.*;
import com.budwk.app.flow.service.ProcessDefineService;
import com.budwk.app.flow.service.ProcessInstanceService;
import com.budwk.app.flow.service.ProcessTaskService;
import com.budwk.app.flow.vo.ProcessTaskVO;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@IocBean(args = {"refer:dao"})
public class ProcessTaskServiceImpl extends BaseServiceImpl<ProcessTask> implements ProcessTaskService {
public ProcessTaskServiceImpl(Dao dao) {
super(dao);
}
@Inject
private ProcessDefineService processDefineService;
@Override
public boolean save(ProcessTask param) {
param.setId(null);
insert(param);
return true;
}
@Override
public boolean update(ProcessTask param) {
updateIgnoreNull(param);
return true;
}
@Override
public ProcessTaskVO findById(Long id) {
ProcessTask task = fetch(id);
ProcessTaskVO vo = BeanUtil.copyProperties(task, ProcessTaskVO.class);
if (vo != null) {
// 参与人员
vo.setTaskActorIdList(getTaskActors(vo.getId()));
// 是否可执行
vo.setExecutable(vo.getTaskActorIdList().contains(SecurityUtil.getUserId()));
// 追加节点定义信息
ProcessInstance processInstance = dao().fetch(ProcessInstance.class, task.getProcessInstanceId());
ProcessModel processModel = processDefineService.getProcessModel(processInstance.getProcessDefineId());
TaskModel taskModel = (TaskModel) processModel.getNode(vo.getTaskName());
vo.setTaskModel(taskModel);
}
return vo;
}
@Override
@Aop(TransAop.READ_COMMITTED)
public void saveProcessTask(ProcessTask processTask) {
insert(processTask);
}
@Override
public void updateProcessTask(ProcessTask processTask) {
updateIgnoreNull(processTask);
}
@Override
public List<ProcessTask> getDoingTaskList(Long processInstanceId, String[] taskNames) {
Cnd cnd = Cnd.where(ProcessTask::getProcessInstanceId, "=", processInstanceId).and(ProcessTask::getTaskState, "=", ProcessTaskStateEnum.DOING.getCode());
cnd.andEX(ProcessTask::getTaskName, "in", taskNames);
List<ProcessTask> processTaskList = query(cnd);
return processTaskList;
}
@Override
public List<ProcessTask> getDoneTaskList(Long processInstanceId, String[] taskNames) {
Cnd cnd = Cnd.where(ProcessTask::getProcessInstanceId, "=", processInstanceId).and(ProcessTask::getTaskState, "!=", ProcessTaskStateEnum.DOING.getCode());
cnd.andEX(ProcessTask::getTaskName, "", taskNames);
List<ProcessTask> processTaskList = query(cnd);
return processTaskList;
}
@Override
public void finishProcessTask(Long processTaskId, String operator, Dict args) {
ProcessTask his = fetch(processTaskId);
ProcessTask processTask = new ProcessTask();
processTask.setId(processTaskId);
processTask.setTaskState(ProcessTaskStateEnum.FINISHED.getCode());
processTask.setUpdatedAt(System.currentTimeMillis());
processTask.setUpdatedBy(operator);
processTask.setOperator(operator);
processTask.setFinishTime(new Date());
Dict newArgs = Dict.create();
newArgs.putAll(FlowUtil.variableToDict(his.getVariable()));
newArgs.putAll(args);
if (FlowConst.AUTO_ID.equalsIgnoreCase(operator)) {
FlowUtil.addUserInfoToArgs(SecurityUtil.getUserId(), newArgs);
} else {
FlowUtil.addUserInfoToArgs(operator, newArgs);
}
processTask.setVariable(JSONUtil.toJsonStr(newArgs));
updateIgnoreNull(processTask);
// 发布流程任务结束事件
ProcessPublisher.notify(ProcessEvent.builder().eventType(ProcessEventTypeEnum.PROCESS_TASK_END).sourceId(processTaskId).build());
}
@Override
public void abandonProcessTask(Long processTaskId, String operator, Dict args) {
ProcessTask his = fetch(processTaskId);
ProcessTask processTask = new ProcessTask();
processTask.setId(processTaskId);
processTask.setTaskState(ProcessTaskStateEnum.ABANDON.getCode());
processTask.setUpdatedAt(System.currentTimeMillis());
processTask.setUpdatedBy(operator);
processTask.setOperator(operator);
processTask.setFinishTime(new Date());
Dict newArgs = Dict.create();
newArgs.putAll(FlowUtil.variableToDict(his.getVariable()));
newArgs.putAll(args);
if (FlowConst.AUTO_ID.equalsIgnoreCase(operator)) {
FlowUtil.addUserInfoToArgs(SecurityUtil.getUserId(), newArgs);
} else {
FlowUtil.addUserInfoToArgs(operator, newArgs);
}
processTask.setVariable(JSONUtil.toJsonStr(newArgs));
updateIgnoreNull(processTask);
// 发布流程任务结束事件
ProcessPublisher.notify(ProcessEvent.builder().eventType(ProcessEventTypeEnum.PROCESS_TASK_END).sourceId(processTaskId).build());
}
@Override
@Aop(TransAop.READ_COMMITTED)
public List<ProcessTask> createTask(TaskModel taskModel, Execution execution) {
List<ProcessTask> processTaskList = new ArrayList<>();
long now = System.currentTimeMillis();
ProcessTask processTask = new ProcessTask();
processTask.setPerformType(ProcessTaskPerformTypeEnum.NORMAL.getCode());
processTask.setTaskName(taskModel.getName());
processTask.setDisplayName(taskModel.getDisplayName());
processTask.setTaskState(ProcessTaskStateEnum.DOING.getCode());
processTask.setTaskType(taskModel.getTaskType().getCode());
processTask.setFormKey(taskModel.getForm());
processTask.setProcessInstanceId(execution.getProcessInstanceId());
execution.getArgs().put(FlowConst.IS_FIRST_TASK_NODE, FlowUtil.isFistTaskName(execution.getProcessModel(), taskModel.getName()));
// 增加是否为第一个任务节点标识
processTask.setVariable(JSONUtil.toJsonStr(execution.getArgs()));
processTask.setCreatedAt(now);
processTask.setUpdatedAt(now);
processTask.setTaskParentId(Convert.toLong(execution.getProcessTaskId(), 0L));
String expireTime = taskModel.getExpireTime();
if (StrUtil.isNotEmpty(expireTime)) {
processTask.setExpireTime(FlowUtil.processTime(expireTime, execution.getArgs()));
}
insert(processTask);
execution.setProcessTask(processTask);
System.out.println("创建任务:" + processTask.getTaskName() + "," + processTask.getDisplayName());
processTaskList.add(processTask);
addTaskActor(processTask.getId(), getTaskActors(taskModel, execution));
return processTaskList;
}
@Override
public ProcessTask getById(Long id) {
return fetch(id);
}
@Override
@Aop(TransAop.READ_COMMITTED)
public void addTaskActor(Long processTaskId, List<String> actors) {
if (CollectionUtil.isEmpty(actors)) return;
List<String> dbActors = getTaskActors(processTaskId);
actors.stream().filter(actor -> {
return !dbActors.contains(actor);
}).forEach(actor -> {
ProcessTaskActor processTaskActor = new ProcessTaskActor();
processTaskActor.setProcessTaskId(processTaskId);
processTaskActor.setActorId(actor);
processTaskActor.setCreatedAt(System.currentTimeMillis());
System.out.println(StrUtil.format("给任务:{},添加参与者:{}", processTaskId, actor));
insert(processTaskActor);
});
}
@Override
@Aop(TransAop.READ_COMMITTED)
public void addCandidateActor(Long processTaskId, List<String> actors) {
if (CollectionUtil.isEmpty(actors)) return;
ProcessTask processTask = fetch(processTaskId);
String prefix = FlowConst.COUNTERSIGN_VARIABLE_PREFIX + processTask.getTaskName() + "_";
// 主要调整流程变量中的参与者
ProcessInstance processInstance = dao().fetch(ProcessInstance.class, processTask.getProcessInstanceId());
if (processInstance != null) {
Dict args = JSONUtil.toBean(processInstance.getVariable(), Dict.class);
// 会签办理人列表
List<String> operatorList = Convert.toList(String.class, args.get(prefix + FlowConst.COUNTERSIGN_OPERATOR_LIST));
if (args != null) {
operatorList.addAll(actors);
operatorList = operatorList.stream().distinct().collect(Collectors.toList());
// 更新列表
args.put(prefix + FlowConst.COUNTERSIGN_OPERATOR_LIST, operatorList);
// 更新实例数
args.put(prefix + FlowConst.NR_OF_INSTANCES, operatorList.size());
ProcessInstance up = new ProcessInstance();
up.setId(processInstance.getId());
up.setVariable(JSONUtil.toJsonStr(args));
dao().updateIgnoreNull(up);
}
}
Dict taskArgs = JSONUtil.toBean(processTask.getVariable(), Dict.class);
String countersignType = taskArgs.getStr(FlowConst.COUNTERSIGN_VARIABLE_PREFIX + FlowConst.COUNTERSIGN_TYPE);
if (CountersignTypeEnum.PARALLEL.toString().equalsIgnoreCase(countersignType)) {
// 并行会签,要直接创建会签任务
actors.forEach(actor -> {
ProcessTask clone = BeanUtil.toBean(processTask, ProcessTask.class);
clone.setId(null);
clone.setCreatedBy(null);
clone.setCreatedAt(null);
clone.setUpdatedAt(null);
clone.setUpdatedBy(null);
dao().insert(clone);
addTaskActor(clone.getId(), CollectionUtil.newArrayList(actor));
});
}
}
@Override
public void removeTaskActor(Long processTaskId, List<String> actors) {
dao().clear(ProcessTaskActor.class, Cnd.where(ProcessTaskActor::getProcessTaskId, "=", processTaskId).and(ProcessTaskActor::getActorId, "in", actors));
}
@Override
public boolean isAllowed(ProcessTask task, String operator) {
// 执行者为超级管理员或自动执行用户
if (FlowConst.ADMIN_ID.equalsIgnoreCase(operator) || FlowConst.AUTO_ID.equalsIgnoreCase(operator)) {
return true;
}
// 任务操作者==执行者
if (ObjectUtil.equals(task.getOperator(), operator)) {
return true;
}
// 任务参考者==执行者
if (getTaskActors(task.getId()).contains(operator)) {
return true;
}
return false;
}
@Override
public List<String> getTaskActors(Long processTaskId) {
List<ProcessTaskActor> processTaskActorList = dao().query(ProcessTaskActor.class, Cnd.where(ProcessTaskActor::getProcessTaskId, "=", processTaskId));
return processTaskActorList.stream().map(ProcessTaskActor::getActorId).collect(Collectors.toList());
}
@Override
public ProcessTask rejectTask(ProcessModel model, ProcessTask currentTask) {
Long taskParentId = currentTask.getTaskParentId();
if (ObjectUtil.isEmpty(taskParentId) || taskParentId.equals(0L)) {
throw new BaseException("上步任务ID为空,无法驳回至上一步处理");
}
NodeModel current = model.getNode(currentTask.getTaskName());
ProcessTask history = fetch(taskParentId);
NodeModel parent = model.getNode(history.getTaskName());
if (!NodeModel.canRejected(current, parent)) {
throw new BaseException("无法驳回至上一步处理,请确认上步任务并非fork、join、suprocess以及会签任务");
}
ProcessTask task = BeanUtil.toBean(history, ProcessTask.class);
task.setId(null);
task.setTaskState(ProcessTaskStateEnum.DOING.getCode());
task.setCreatedAt(null);
task.setCreatedBy(null);
task.setUpdatedAt(null);
task.setUpdatedBy(null);
task.setFinishTime(null);
String operator = history.getOperator();
Dict hisVariable = FlowUtil.variableToDict(history.getVariable());
if (hisVariable.get(FlowConst.IS_FIRST_TASK_NODE, false)) {
// 第一个节点的操作人从任务变量中获取
operator = hisVariable.getStr(FlowConst.USER_USER_ID);
}
task.setVariable(JSONUtil.toJsonStr(hisVariable));
task.setOperator(operator);
String expireTime = ((TaskModel) current).getExpireTime();
if (StrUtil.isNotEmpty(expireTime)) {
task.setExpireTime(FlowUtil.processTime(expireTime, hisVariable));
}
saveProcessTask(task);
addTaskActor(task.getId(), CollectionUtil.newArrayList(task.getOperator()));
return task;
}
@Override
public List<LabelValueVO> jumpAbleTaskNameList(Long processInstanceId) {
List<String> taskNames = new ArrayList<>();
List<LabelValueVO> res = new ArrayList<>();
List<ProcessTask> processTaskList = getDoneTaskList(processInstanceId, new String[]{});
processTaskList.stream().filter(processTask -> {
// 不能跳转到会签节点
return !ProcessTaskPerformTypeEnum.COUNTERSIGN.getCode().equals(processTask.getPerformType());
}).forEach(processTask -> {
String taskName = processTask.getTaskName();
if (!taskNames.contains(taskName)) {
taskNames.add(taskName);
res.add(LabelValueVO.builder().label(processTask.getDisplayName()).value(taskName).build());
}
});
return res;
}
@Override
public List<ProcessTask> createCountersignTask(TaskModel taskModel, Execution execution) {
List<ProcessTask> processTaskList = new ArrayList<>();
List<String> taskActors = getTaskActors(taskModel, execution);
List<String> createTaskActors = new ArrayList<>();
if (CountersignTypeEnum.PARALLEL.equals(taskModel.getCountersignType())) {
// 并行:一个参与者一个任务,同时创建
createTaskActors.addAll(taskActors);
// 追加会签类型参数
execution.getArgs().put(FlowConst.COUNTERSIGN_VARIABLE_PREFIX + FlowConst.COUNTERSIGN_TYPE, CountersignTypeEnum.PARALLEL.toString());
} else {
// 串行:一个参与者一个任务,顺序创建,默认只创建第一个,其他等执行完一个后再创建
String prefix = FlowConst.COUNTERSIGN_VARIABLE_PREFIX + taskModel.getName() + "_";
// 获取循环计数器,默认值为-1
int loopCounter = execution.getArgs().get(prefix + FlowConst.LOOP_COUNTER, -1);
if (loopCounter == -1) {
createTaskActors.add(taskActors.get(0));
} else {
createTaskActors.add(taskActors.get(loopCounter + 1));
}
// 追加会签类型参数
execution.getArgs().put(FlowConst.COUNTERSIGN_VARIABLE_PREFIX + FlowConst.COUNTERSIGN_TYPE, CountersignTypeEnum.SEQUENTIAL.toString());
}
createTaskActors.forEach(taskActor -> {
long now = System.currentTimeMillis();
ProcessTask processTask = new ProcessTask();
processTask.setPerformType(ProcessTaskPerformTypeEnum.COUNTERSIGN.getCode());
processTask.setTaskName(taskModel.getName());
processTask.setFormKey(taskModel.getForm());
processTask.setDisplayName(taskModel.getDisplayName());
processTask.setTaskState(ProcessTaskStateEnum.DOING.getCode());
processTask.setTaskType(taskModel.getTaskType().getCode());
processTask.setProcessInstanceId(execution.getProcessInstanceId());
execution.getArgs().put(FlowConst.IS_FIRST_TASK_NODE, FlowUtil.isFistTaskName(execution.getProcessModel(), taskModel.getName()));
processTask.setVariable(JSONUtil.toJsonStr(execution.getArgs()));
processTask.setCreatedAt(now);
processTask.setUpdatedAt(now);
processTask.setTaskParentId(Convert.toLong(execution.getProcessTaskId(), 0L));
String expireTime = taskModel.getExpireTime();
if (StrUtil.isNotEmpty(expireTime)) {
processTask.setExpireTime(FlowUtil.processTime(expireTime, execution.getArgs()));
}
insert(processTask);
execution.setProcessTask(processTask);
System.out.println("创建会签任务:" + processTask.getTaskName() + "," + processTask.getDisplayName());
processTaskList.add(processTask);
addTaskActor(processTask.getId(), CollectionUtil.newArrayList(taskActor));
});
ProcessInstanceService processInstanceService = SpringUtil.getBean(ProcessInstanceService.class);
// 更新会签变量到流程实例参数中
processInstanceService.updateCountersignVariable(taskModel, execution, taskActors);
return processTaskList;
}
@Override
public ProcessTask history(Execution execution, CustomModel model) {
ProcessTask processTask = new ProcessTask();
processTask.setProcessInstanceId(execution.getProcessInstanceId());
long now = System.currentTimeMillis();
processTask.setCreatedAt(now);
processTask.setFinishTime(new Date());
processTask.setDisplayName(model.getDisplayName());
processTask.setTaskName(model.getName());
processTask.setTaskState(ProcessTaskStateEnum.FINISHED.getCode());
processTask.setTaskType(ProcessTaskTypeEnum.RECORD.getCode());
processTask.setTaskParentId(Convert.toLong(execution.getProcessTaskId(), 0L));
processTask.setVariable(JSONUtil.toJsonStr(execution.getArgs()));
insert(processTask);
return processTask;
}
@Override
public ProcessTaskVO latest(Long processInstanceId) {
List<ProcessTask> processTaskList = query(Cnd.where(ProcessTask::getProcessInstanceId, "=", processInstanceId)
.and(ProcessTask::getTaskState, "=", ProcessTaskStateEnum.DOING.getCode()).desc(ProcessTask::getId));
if (processTaskList.isEmpty()) {
return null;
}
if (processTaskList.size() > 1) {
List<Long> processTaskIds = processTaskList.stream().map(ProcessTask::getId).collect(Collectors.toList());
List<ProcessTaskActor> processTaskActors = dao().query(ProcessTaskActor.class, Cnd.where(ProcessTaskActor::getProcessTaskId, "in", processTaskIds));
ProcessTaskActor processTaskActor = processTaskActors.stream().filter(item -> {
return ObjectUtil.equals(SecurityUtil.getUserId(), item.getActorId());
}).findAny().orElse(null);
if (processTaskActor != null) {
return findById(processTaskActor.getProcessTaskId());
}
}
return findById(processTaskList.get(0).getId());
}
/**
* 根据Task模型的assignee、assignmentHandler属性以及运行时数据,确定参与者
*
* @param model 任务模型
* @param execution 流程执行对象
* @return
*/
private List<String> getTaskActors(TaskModel model, Execution execution) {
Object nextNodeOperator = execution.getArgs().get(FlowConst.NEXT_NODE_OPERATOR);
if (ObjectUtil.isNotEmpty(nextNodeOperator)) {
// 指定下一节点处理人的优先级最高
if (nextNodeOperator instanceof String) {
return CollectionUtil.newArrayList(((String) nextNodeOperator).split(","));
} else if (nextNodeOperator instanceof Collection) {
return CollectionUtil.newArrayList((Collection) nextNodeOperator);
}
}
List<String> res = new ArrayList<>();
Dict args = execution.getArgs();
String assignee = model.getAssignee();
// 参与者属性不为空
if (StrUtil.isNotEmpty(assignee)) {
// 多个使用英文逗号分割
String[] assigneeArr = assignee.split(",");
for (int i = 0; i < assigneeArr.length; i++) {
// // 2025-07-26 增加表达式解析
// if (assigneeArr[i].startsWith("{") && assigneeArr[i].endsWith("}")) {
// Object eval = ExpressionUtil.eval(assigneeArr[i], args);
// // 如果转换失败,则使用原值
// res.add(Convert.toStr(eval, assigneeArr[i]));
// }
// 如果args中存在assigneeArr[i]为key的数据==>参与者设置方式中的动态传递
// 如果args中不存在assigneeArr[i]为key的数据==>参与者设置方式中的静态配置
res.add(args.get(assigneeArr[i], assigneeArr[i]));
}
} else {
String assignmentHandler = model.getAssignmentHandler();
if (StrUtil.isNotEmpty(assignmentHandler)) {
AssignmentHandler assignmentHandlerObj = ReflectUtil.newInstance(assignmentHandler);
res.addAll(assignmentHandlerObj.assign(model, execution));
}
}
return res;
}
}