This commit is contained in:
那些花儿
2025-07-29 14:25:33 +08:00
parent 72546696fa
commit 9d8002ec93
40 changed files with 1410 additions and 13555 deletions
@@ -5,9 +5,12 @@ import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.vo.LabelValueVO;
import com.budwk.app.flow.constant.FlowConst;
import com.budwk.app.flow.engine.FlowEngine;
import com.budwk.app.flow.engine.model.ProcessModel;
import com.budwk.app.flow.engine.model.TaskModel;
import com.budwk.app.flow.entity.Candidate;
import com.budwk.app.flow.entity.ProcessDefine;
import com.budwk.app.flow.entity.ProcessInstance;
import com.budwk.app.flow.entity.ProcessTask;
@@ -27,9 +30,7 @@ import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.*;
@IocBean
@At("/flow/common")
@@ -163,6 +164,14 @@ public class FlowCommonController {
return Result.success();
}
@At
@SaCheckLogin
@ApiOperation("撤回流程实例")
public Result withdrawInstance(@Param("instanceId") Long instanceId) {
flowEngine.processInstanceService().withdraw(instanceId, SecurityUtil.getUserId());
return Result.success();
}
@At("/executeTask")
@SaCheckLogin
@@ -177,6 +186,14 @@ public class FlowCommonController {
submitType = ProcessSubmitTypeEnum.AGREE.getCode();
}
args.put(FlowConst.SUBMIT_TYPE, submitType);
// 设置办理人信息到表单参数
args.put(FlowConst.TASK_FORM_DATA_PREFIX + "userName", SecurityUtil.getUserUsername());
args.put(FlowConst.TASK_FORM_DATA_PREFIX + "loginName", SecurityUtil.getUserLoginname());
args.put(FlowConst.TASK_FORM_DATA_PREFIX + "unitId", SecurityUtil.getUnitId());
args.put(FlowConst.TASK_FORM_DATA_PREFIX + "unitName", SecurityUtil.getUnitId());
args.put(FlowConst.TASK_FORM_DATA_PREFIX + "unionId", SecurityUtil.getUnionId());
if (ObjectUtil.equals(submitType, ProcessSubmitTypeEnum.ROLLBACK.getCode())) {
// 退回上一个节点
flowEngine.executeAndJumpTask(processTaskId, operator, args, null);
@@ -201,4 +218,35 @@ public class FlowCommonController {
return Result.success();
}
@At("/candidate")
@SaCheckLogin
@ApiOperation("获取候选用户")
public Result candidate(@Param("taskId") Long taskId) {
ProcessTask task = flowEngine.processTaskService().fetch(taskId);
ProcessInstance instance = flowEngine.processInstanceService().fetch(task.getProcessInstanceId());
ProcessModel processModel = flowEngine.processDefineService().getProcessModel(instance.getProcessDefineId());
// 是否存在候选处理
List<TaskModel> nextTaskModels = processModel.getNextTaskModels(task.getTaskName());
boolean b = nextTaskModels.stream().anyMatch(item -> item.getCandidateHandler() != null);
List<Candidate> candidates = processModel.getNextTaskModelCandidates(task.getTaskName());
return Result.success(Map.of("candidates", candidates, "support", b));
}
@At("/jumpTaskNames")
@SaCheckLogin
@ApiOperation("获取可跳转的任务节点")
public Result jumpAbleTaskNames(@Param("instanceId") Long instanceId) {
List<LabelValueVO> vos = flowEngine.processTaskService().jumpAbleTaskNameList(instanceId);
return Result.success(vos);
}
@At("/surrogate")
@SaCheckLogin
@ApiOperation("代理")
public Result surrogate(@Param("taskId") Long taskId, @Param("actorIds") String[] actorIds) {
flowEngine.processTaskService().addTaskActor(taskId, Arrays.asList(actorIds));
return Result.success();
}
}
@@ -4,11 +4,10 @@ import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.hutool.core.lang.ClassScanner;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.result.Result;
import com.budwk.app.flow.constant.FlowConst;
import com.budwk.app.flow.engine.AssignmentHandler;
import com.budwk.app.flow.engine.CandidateHandler;
import com.budwk.app.flow.entity.ProcessDesign;
import com.budwk.app.flow.service.ProcessDesignService;
import com.budwk.app.sys.services.SysUserService;
@@ -47,6 +46,8 @@ public class FlowDesignController {
// 获取所有任务参与者处理类
public static final List<JSONObject> ASSIGMENT_HANDLER_LIST;
// 获取所有候选用户处理类
public static final List<JSONObject> CANDIDATE_HANDLER_LIST;
static {
Set<Class<?>> classes = ClassScanner.scanPackageBySuper("com.budwk.app", AssignmentHandler.class);
@@ -68,6 +69,26 @@ public class FlowDesignController {
ASSIGMENT_HANDLER_LIST = Collections.unmodifiableList(list);
}
static {
Set<Class<?>> classes = ClassScanner.scanPackageBySuper("com.budwk.app", CandidateHandler.class);
ArrayList<JSONObject> list = new ArrayList<>(classes.size());
for (Class<?> aClass : classes) {
try {
CandidateHandler handler = (CandidateHandler) ReflectUtil.newInstance(aClass);
JSONObject jsonObject = new JSONObject();
jsonObject.set("value", handler.getClass().getName());
jsonObject.set("order", handler.getOrder());
jsonObject.set("name", handler.getMessage());
list.add(jsonObject);
} catch (Exception e) {
log.error("初始化CandidateHandler失败: {}", aClass.getName());
}
}
// 排序 按order
list.sort(Comparator.comparingInt(o -> o.getInt("order")));
CANDIDATE_HANDLER_LIST = Collections.unmodifiableList(list);
}
@At("")
@Ok("beetl:/platform/flow/design/index.html")
@@ -101,6 +122,8 @@ public class FlowDesignController {
jsonObject.set("category", processDesign.getCategory());
jsonObject.set("instanceUrl", processDesign.getInstanceUrl());
jsonObject.set("h5InstanceUrl", processDesign.getH5InstanceUrl());
jsonObject.set("instanceViewUrl",processDesign.getInstanceViewUrl());
jsonObject.set("h5InstanceViewUrl",processDesign.getH5InstanceViewUrl());
processDesign.setContent(jsonObject);
dao.insert(processDesign);
return Result.success();
@@ -116,6 +139,8 @@ public class FlowDesignController {
jsonObject.set("category", processDesign.getCategory());
jsonObject.set("instanceUrl", processDesign.getInstanceUrl());
jsonObject.set("h5InstanceUrl", processDesign.getH5InstanceUrl());
jsonObject.set("instanceViewUrl",processDesign.getInstanceViewUrl());
jsonObject.set("h5InstanceViewUrl",processDesign.getH5InstanceViewUrl());
processDesign.setContent(jsonObject);
processDesignService.update(processDesign);
return Result.success();
@@ -125,6 +150,15 @@ public class FlowDesignController {
@SaCheckLogin
@ApiOperation("修改流程设计")
public Result updateContent(@Param("design") ProcessDesign processDesign) {
JSONObject jsonObject = processDesign.getContent();
jsonObject.set("name", processDesign.getName());
jsonObject.set("displayName", processDesign.getDisplayName());
jsonObject.set("category", processDesign.getCategory());
jsonObject.set("instanceUrl", processDesign.getInstanceUrl());
jsonObject.set("h5InstanceUrl", processDesign.getH5InstanceUrl());
jsonObject.set("instanceViewUrl",processDesign.getInstanceViewUrl());
jsonObject.set("h5InstanceViewUrl",processDesign.getH5InstanceViewUrl());
processDesign.setContent(jsonObject);
processDesignService.update(processDesign);
return Result.success();
}
@@ -160,9 +194,17 @@ public class FlowDesignController {
@ApiOperation("获取流程设计任务参与者处理类")
public Result assigmentHandlerClass() {
return Result.success(ASSIGMENT_HANDLER_LIST);
}
@At
@SaCheckLogin
@ApiOperation("获取流程设计任务参与者处理类")
public Result candidateHandlerClass() {
return Result.success(CANDIDATE_HANDLER_LIST);
}
@At
@SaCheckLogin
@ApiOperation("获取流程设计任务参与者分页数据")
@@ -19,4 +19,12 @@ public interface CandidateHandler {
* @return
*/
List<Candidate> handle(TaskModel model);
default String getMessage() {
return this.getClass().getSimpleName();
}
default int getOrder() {
return Integer.MIN_VALUE;
}
}
@@ -25,6 +25,8 @@ public class ProcessModel extends BaseModel {
private String category; // 流程定义分类
private String instanceUrl; // 启动实例要填写的表单key
private String h5InstanceUrl; // 启动实例要填写的手机端表单key
private String instanceViewUrl;
private String h5InstanceViewUrl;
private String expireTime; // 期待完成时间变量key
private String instanceNoClass; // 实例编号生成器实现类
private String preInterceptors; // 节点前置拦截器
@@ -74,9 +76,7 @@ public class ProcessModel extends BaseModel {
NodeModel nodeModel = getNode(nodeName);
if(nodeModel == null) return res;
// 获取所有输出边的目标节点
List<NodeModel> nextNodeModelList = nodeModel.getOutputs().stream().map(item->{
return item.getTarget();
}).collect(Collectors.toList());
List<NodeModel> nextNodeModelList = nodeModel.getOutputs().stream().map(TransitionModel::getTarget).toList();
nextNodeModelList.forEach(item->{
if(item instanceof TaskModel) {
res.add((TaskModel) item);
@@ -15,6 +15,9 @@ public class LfModel extends BaseModel {
private String type; // 流程定义分类
private String expireTime;// 过期时间(常量或变量)
private String instanceUrl; // 启动实例的url,前后端分离后,定义为路由名或或路由地址
private String h5InstanceUrl;
private String instanceViewUrl;
private String h5InstanceViewUrl;
private String instanceNoClass; // 启动流程时,流程实例的流水号生成类
private String preInterceptors; // 节点前置拦截器
private String postInterceptors; // 节点后置拦截器
@@ -79,6 +79,9 @@ public class ModelParser {
processModel.setDisplayName(lfModel.getDisplayName());
processModel.setType(lfModel.getType());
processModel.setInstanceUrl(lfModel.getInstanceUrl());
processModel.setH5InstanceUrl(lfModel.getH5InstanceUrl());
processModel.setInstanceViewUrl(lfModel.getInstanceViewUrl());
processModel.setH5InstanceViewUrl(lfModel.getH5InstanceViewUrl());
processModel.setInstanceNoClass(lfModel.getInstanceNoClass());
processModel.setPostInterceptors(lfModel.getPostInterceptors());
processModel.setPreInterceptors(lfModel.getPreInterceptors());
@@ -47,6 +47,14 @@ public class ProcessDefine extends BaseModel {
@Column
private String h5InstanceUrl;
@Comment("电脑端发起地址")
@Column
private String instanceViewUrl;
@Comment("手机端发起地址")
@Column
private String h5InstanceViewUrl;
@Comment("图标")
@Column
private String icon;
@@ -50,6 +50,14 @@ public class ProcessDesign extends BaseModel {
@Column
private String h5InstanceUrl;
@Comment("电脑端发起地址")
@Column
private String instanceViewUrl;
@Comment("手机端发起地址")
@Column
private String h5InstanceViewUrl;
@Comment("图标")
@Column
private String icon;
@@ -34,4 +34,16 @@ public class ProcessTaskActor extends BaseModel {
@Column
private String actorId;
@Comment("参与者账号")
@Column
private String actorAccount;
@Comment("参与者名称")
@Column
private String actorName;
@Comment("参与者单位")
@Column
private String actorUnitName;
}
@@ -0,0 +1,30 @@
package com.budwk.app.flow.handler;
import cn.hutool.core.lang.Dict;
import com.budwk.app.flow.engine.CandidateHandler;
import com.budwk.app.flow.engine.model.TaskModel;
import com.budwk.app.flow.entity.Candidate;
import java.util.List;
//@IocBean 此处加了会从容器里面获取 反之反射获取
public class FLowDemoCandidateHandler implements CandidateHandler {
@Override
public List<Candidate> handle(TaskModel model) {
Candidate build = Candidate.builder().userId("1").userName("测试1").ext(
Dict.of("loginName", "superadmin", "unitName", "工会")
).build();
return List.of(build);
}
@Override
public String getMessage() {
return "候选人测试DEMO";
}
@Override
public int getOrder() {
return 10;
}
}
@@ -120,6 +120,12 @@ public class ProcessDefineServiceImpl extends BaseServiceImpl<ProcessDefine> imp
define.setCategory(processModel.getCategory());
define.setInstanceUrl(processModel.getInstanceUrl());
define.setH5InstanceUrl(processModel.getH5InstanceUrl());
define.setInstanceViewUrl(processModel.getInstanceViewUrl());
define.setH5InstanceViewUrl(processModel.getH5InstanceViewUrl());
// define.setInstanceViewUrl(latestDefine.getInstanceViewUrl());
// define.setH5InstanceViewUrl(latestDefine.getH5InstanceViewUrl());
define.setState(1);
define.setContent(JSONUtil.parseObj(defineJsonStr));
insert(define);
@@ -7,7 +7,6 @@ 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;
@@ -35,9 +34,12 @@ 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.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.ArrayList;
import java.util.Collection;
@@ -201,16 +203,31 @@ public class ProcessTaskServiceImpl extends BaseServiceImpl<ProcessTask> impleme
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 -> {
List<String> newActors = actors.stream().filter(actor -> !dbActors.contains(actor)).toList();
Sql sql = Sqls.create("select id,username,loginname,unitname from vw_user where id in (@ids)");
sql.setParam("ids", newActors);
List<NutMap> list = listMap(sql);
for (NutMap actor : list) {
ProcessTaskActor processTaskActor = new ProcessTaskActor();
processTaskActor.setProcessTaskId(processTaskId);
processTaskActor.setActorId(actor);
processTaskActor.setActorId(actor.getString("id"));
processTaskActor.setActorName(actor.getString("username"));
processTaskActor.setActorAccount(actor.getString("loginname"));
processTaskActor.setActorUnitName(actor.getString("unitname"));
processTaskActor.setCreatedAt(System.currentTimeMillis());
System.out.println(StrUtil.format("给任务:{},添加参与者:{}", processTaskId, actor));
System.out.println(StrUtil.format("给任务:{},添加参与者:{}", processTaskId, actor.toString()));
insert(processTaskActor);
});
}
// actors.stream().filter(actor -> !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
@@ -2,7 +2,9 @@ package com.budwk.app.flow.vo;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.budwk.app.flow.constant.FlowConst;
import com.budwk.app.flow.engine.core.Execution;
import com.budwk.app.flow.engine.model.TaskModel;
import com.budwk.app.flow.entity.ProcessTask;
@@ -39,6 +41,9 @@ public class ProcessTaskVO extends ProcessTask {
private Dict taskFormData;
// @Schema(description = "任务参与者ID")
private List<String> taskActorIdList;
private List<JSONObject> taskActorList;
// @Schema(description = "当前用户是否可执行")
private boolean executable;
// @Schema(description = "节点定义信息")
@@ -47,7 +52,6 @@ public class ProcessTaskVO extends ProcessTask {
if(this.ext!=null) return this.ext;
String variable = getVariable();
if(ObjectUtil.isEmpty(ext) && JSONUtil.isTypeJSON(variable)){
// this.ext = JsonTool.fromJson(variable, Dict.class);
this.ext = JSONUtil.toBean(variable, Dict.class);
}
return ext;
@@ -57,37 +61,21 @@ public class ProcessTaskVO extends ProcessTask {
if(this.instanceExt!=null) return this.instanceExt;
String variable = getVariable();
if(ObjectUtil.isEmpty(instanceExt) && JSONUtil.isTypeJSON(instanceVariable)){
// this.instanceExt = JsonTool.fromJson(instanceVariable,Dict.class);
this.instanceExt = JSONUtil.toBean(instanceVariable, Dict.class);
}
return instanceExt;
}
// public Dict getTaskFormData() {
// // f_前辍才是表单数据
// this.taskFormData = Dict.of();
// Dict ext = this.getExt();
// List<String> formDataKeys = ext.keySet().stream().filter(key->key.startsWith(FlowConst.TASK_FORM_DATA_PREFIX)).collect(Collectors.toList());
// formDataKeys.forEach(key->{
// this.taskFormData.put(key,ext.get(key));
// this.taskFormData.put(key.replaceAll(FlowConst.TASK_FORM_DATA_PREFIX,""),ext.get(key));
// });
// return taskFormData;
// }
/**
* 后续个任务
*/
private List<TaskModel> nextTaskModels;
// private List<TaskModel> nextTaskModels() {
// List<TaskModel> nextModels = new ArrayList<>();
//
// TaskModel model = getTaskModel();
//
//
// }
public Dict getTaskFormData() {
// f_前辍才是表单数据
this.taskFormData = Dict.of();
Dict ext = this.getExt();
List<String> formDataKeys = ext.keySet().stream().filter(key->key.startsWith(FlowConst.TASK_FORM_DATA_PREFIX)).toList();
formDataKeys.forEach(key->{
this.taskFormData.put(key,ext.get(key));
this.taskFormData.put(key.replaceAll(FlowConst.TASK_FORM_DATA_PREFIX,""),ext.get(key));
});
return taskFormData;
}
}