Jelajahi Sumber

优化查询,增加sql条件

zhouhao 6 tahun lalu
induk
melakukan
f42fca7137
13 mengubah file dengan 333 tambahan dan 83 penghapusan
  1. 16 2
      hsweb-system/hsweb-system-workflow/README.md
  2. 5 12
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/service/BpmActivityService.java
  3. 12 59
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/service/imp/BpmActivityServiceImpl.java
  4. 1 1
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/service/imp/ProcessConfigurationServiceImpl.java
  5. 38 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/terms/ClaimSqlTerm.java
  6. 38 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/terms/CompletedSqlTerm.java
  7. 43 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/terms/ProcessParticipateSqlTerm.java
  8. 37 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/terms/TodoSqlTerm.java
  9. 33 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/terms/WorkflowTermsAutoConfiguration.java
  10. 53 7
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/web/FlowableProcessController.java
  11. 11 1
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/web/ProcessActivityConfigController.java
  12. 0 1
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/web/ProcessDefineConfigController.java
  13. 46 0
      hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/web/response/CandidateDetail.java

+ 16 - 2
hsweb-system/hsweb-system-workflow/README.md

@@ -1,5 +1,19 @@
 ## 工作流模板
 使用flowable(前activiti) 整合组织架构和动态表单。实现灵活的工作流配置和运行。
 
-## API
-//todo
+## SQL条件
+`hsweb-system-workflow-local`模块中提供了一些自定义的查询条件,用于对流程的关联查询.可以在动态查询中
+进行使用,例如:
+
+```java
+
+//查询id为userId用户的待办任务
+createQuery().where("processInstanceId","user-wf-todo",userId).list();
+
+```
+注意: 表中需要存在与属性`processInstanceId`关联的字段
+
+1. user-wf-claim : 用户待签收(领取)的流程数据
+2. user-wf-todo : 用户待处理的流程数据
+3. user-wf-completed : 用户已处理的流程数据
+4. user-wf-part : 用户参与的流程数据,通过options来参与的类型: `where("processInstanceId$user-wf-part$starter","admin")`.(参与类型为`starter`)

+ 5 - 12
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/service/BpmActivityService.java

@@ -1,5 +1,6 @@
 package org.hswebframework.web.workflow.service;
 
+import org.activiti.engine.delegate.DelegateExecution;
 import org.activiti.engine.impl.pvm.process.ActivityImpl;
 import org.activiti.engine.impl.task.TaskDefinition;
 
@@ -62,25 +63,17 @@ public interface BpmActivityService {
      * @param activityId 图元ID
      * @return List<TaskDefinition>  当前流程的所有下一环节资源
      */
-    List<TaskDefinition> getNextActivities(String procDefId, String activityId);
+    List<TaskDefinition> getNextActivities(String procDefId, String activityId,DelegateExecution execution);
+
 
     /**
      * 根据图元获取办理环节数据
      *
      * @param activityImpl
-     * @param elString     根据连线条件conditionText获取输出节点,主要用于网关分支(预留)
+     * @param execution     根据连线条件conditionText获取输出节点,主要用于网关分支(预留)
      * @return
      */
-    List<TaskDefinition> getTaskDefinition(ActivityImpl activityImpl, String elString);
-
-    /**
-     * 获取下一环节办理人
-     *
-     * @param procDefId  流程定义ID
-     * @param activityId 图元ID
-     * @return 节点id对应的办理人
-     */
-    Map<String, List<String>> getNextClaim(String procDefId, String activityId);
+    List<TaskDefinition> getTaskDefinition(ActivityImpl activityImpl,DelegateExecution execution);
 
     /**
      * 获取开始节点

+ 12 - 59
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/service/imp/BpmActivityServiceImpl.java

@@ -1,8 +1,11 @@
 package org.hswebframework.web.workflow.service.imp;
 
+import org.activiti.engine.delegate.DelegateExecution;
 import org.activiti.engine.delegate.Expression;
+import org.activiti.engine.impl.Condition;
 import org.activiti.engine.impl.RepositoryServiceImpl;
 import org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
+import org.activiti.engine.impl.bpmn.parser.BpmnParse;
 import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
 import org.activiti.engine.impl.pvm.PvmActivity;
 import org.activiti.engine.impl.pvm.PvmTransition;
@@ -72,13 +75,6 @@ public class BpmActivityServiceImpl extends AbstractFlowableService implements B
 
         return findActivities(procDefId, activity -> "userTask".equals(activity.getProperty("type")));
 
-//        ProcessDefinitionEntity pde = getProcessDefinition(procDefId);
-//        List<ActivityImpl> activityList = new ArrayList<>();
-//        for (ActivityImpl activity : pde.getActivities()) {
-//            if (activity.getProperty("type").equals("userTask"))
-//                activityList.add(activity);
-//        }
-//        return activityList;
     }
 
     @Override
@@ -87,12 +83,6 @@ public class BpmActivityServiceImpl extends AbstractFlowableService implements B
         String procDefId = definition.getId();
         List<ActivityImpl> activities = findActivities(procDefId, activity -> "userTask".equals(activity.getProperty("type")));
 //
-//        ProcessDefinitionEntity pde = getProcessDefinition(procDefId);
-//        List<ActivityImpl> activities = new ArrayList<>();
-//        for (ActivityImpl activity : pde.getActivities()) {
-//            if (activity.getProperty("type").equals("userTask"))
-//                activities.add(activity);
-//        }
         if (null != activities) {
             activities.sort(Comparator.comparing(ProcessElementImpl::getId));
         }
@@ -100,7 +90,7 @@ public class BpmActivityServiceImpl extends AbstractFlowableService implements B
     }
 
     @Override
-    public List<TaskDefinition> getNextActivities(String procDefId, String activityId) {
+    public List<TaskDefinition> getNextActivities(String procDefId, String activityId,DelegateExecution execution) {
         ActivityImpl activity;
         if (activityId != null) {
             activity = getActivityById(procDefId, activityId);
@@ -114,20 +104,14 @@ public class BpmActivityServiceImpl extends AbstractFlowableService implements B
                 .map(PvmTransition::getDestination)
                 .map(ActivityImpl.class::cast)          //强转为ActivityImpl
                 .filter(Objects::nonNull)
-                .map(act -> getTaskDefinition(act, "")) //获取TaskDefinition集合
+                .map(act -> getTaskDefinition(act, execution)) //获取TaskDefinition集合
                 .flatMap(Collection::stream)            //合并集合
                 .collect(Collectors.toList());
 
-//        List<TaskDefinition> taskDefinitions = new ArrayList<>();
-//        for (PvmTransition pvmTransition : pvmTransitions) {
-//            PvmActivity pvmActivity = pvmTransition.getDestination();
-//            taskDefinitions.addAll(getTaskDefinition((ActivityImpl) pvmActivity, ""));
-//        }
-//        return taskDefinitions;
     }
 
     @Override
-    public List<TaskDefinition> getTaskDefinition(ActivityImpl activityImpl, String elString) {
+    public List<TaskDefinition> getTaskDefinition(ActivityImpl activityImpl, DelegateExecution execution) {
         List<TaskDefinition> taskDefinitionList = new ArrayList<>();
         List<TaskDefinition> nextTaskDefinition;
         if ("userTask".equals(activityImpl.getProperty("type"))) {
@@ -141,13 +125,13 @@ public class BpmActivityServiceImpl extends AbstractFlowableService implements B
                 if ("exclusiveGateway".equals(pvmActivity.getProperty("type")) || "parallelGateway".equals(pvmActivity.getProperty("type"))) {
                     outTransitionsTemp = pvmActivity.getOutgoingTransitions();
                     if (outTransitionsTemp.size() == 1) {
-                        nextTaskDefinition = getTaskDefinition((ActivityImpl) outTransitionsTemp.get(0).getDestination(), elString);
+                        nextTaskDefinition = getTaskDefinition((ActivityImpl) outTransitionsTemp.get(0).getDestination(), execution);
                         taskDefinitionList.addAll(nextTaskDefinition);
                     } else if (outTransitionsTemp.size() > 1) {
-                        for (PvmTransition tr1 : outTransitionsTemp) {
-                            Object s = tr1.getProperty("conditionText");
-                            if (elString.equals(s.toString().trim())) {
-                                nextTaskDefinition = getTaskDefinition((ActivityImpl) tr1.getDestination(), elString);
+                        for (PvmTransition transition : outTransitionsTemp) {
+                            Condition condition = (Condition) transition.getProperty(BpmnParse.PROPERTYNAME_CONDITION);
+                            if (condition.evaluate(transition.getId(), execution)) {
+                                nextTaskDefinition = getTaskDefinition((ActivityImpl) transition.getDestination(), execution);
                                 taskDefinitionList.addAll(nextTaskDefinition);
                             }
                         }
@@ -160,46 +144,15 @@ public class BpmActivityServiceImpl extends AbstractFlowableService implements B
         return taskDefinitionList;
     }
 
-    @Override
-    public Map<String, List<String>> getNextClaim(String procDefId, String activityId) {
-        List<TaskDefinition> taskDefinitions = getNextActivities(procDefId, activityId);
-        Map<String, List<String>> map = new HashMap<>();
-        for (TaskDefinition taskDefinition : taskDefinitions) {
-            List<String> list = new ArrayList<>();
-            if (taskDefinition.getAssigneeExpression() != null) {
-                list.add(taskDefinition.getAssigneeExpression().getExpressionText());
-            } else if (taskDefinition.getCandidateUserIdExpressions() != null) {
-                for (Expression expression : taskDefinition.getCandidateUserIdExpressions()) {
-                    list.add(expression.getExpressionText());
-                }
-            }
-            if (taskDefinition.getNameExpression() != null) {
-                map.put(taskDefinition.getNameExpression().getExpressionText(), list);
-            } else {
-                map.put(taskDefinition.getKey(), list);
-            }
-        }
-        return map;
-    }
-
     @Override
     public ActivityImpl getStartEvent(String procDefId) {
         return findActivity(procDefId, activity -> "startEvent".equals(activity.getProperty("type")));
-
-//        List<ActivityImpl> activities = getActivitiesById(procDefId, null);
-//        ActivityImpl activity = null;
-//        for (ActivityImpl a : activities) {
-//            if (a.getProperty("type").equals("startEvent")) {
-//                activity = a;
-//            }
-//        }
-//        return activity;
     }
 
     private List<ActivityImpl> findActivities(String procDefId, Predicate<ActivityImpl> predicate) {
         ProcessDefinitionEntity pde = getProcessDefinition(procDefId);
         if (pde == null) {
-            return null;
+            return new ArrayList<>();
         }
         return pde.getActivities()
                 .stream()

+ 1 - 1
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/service/imp/ProcessConfigurationServiceImpl.java

@@ -156,7 +156,7 @@ public class ProcessConfigurationServiceImpl implements ProcessConfigurationServ
 
         @Override
         public void assertCanStartProcess(String userId, ProcessDefinition definition) {
-           // throw new AccessDenyException("没有权限启动此流程:" + definition.getName() + "(" + definition.getId() + ")");
+            // throw new AccessDenyException("没有权限启动此流程:" + definition.getName() + "(" + definition.getId() + ")");
         }
 
         @Override

+ 38 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/terms/ClaimSqlTerm.java

@@ -0,0 +1,38 @@
+package org.hswebframework.web.workflow.terms;
+
+import org.hswebframework.ezorm.core.param.Term;
+import org.hswebframework.ezorm.rdb.meta.RDBColumnMetaData;
+import org.hswebframework.ezorm.rdb.render.SqlAppender;
+import org.hswebframework.ezorm.rdb.render.dialect.term.BoostTermTypeMapper;
+import org.hswebframework.web.dao.mybatis.mapper.AbstractSqlTermCustomer;
+import org.hswebframework.web.dao.mybatis.mapper.ChangedTermValue;
+
+import java.util.List;
+
+/**
+ * 用户待签收的流程条件
+ *
+ * @author zhouhao
+ * @since 3.0.0-RC
+ */
+public class ClaimSqlTerm extends AbstractSqlTermCustomer {
+    public ClaimSqlTerm(String termType) {
+        super(termType);
+    }
+
+    @Override
+    public SqlAppender accept(String wherePrefix, Term term, RDBColumnMetaData column, String tableAlias) {
+        ChangedTermValue termValue = createChangedTermValue(term);
+        RDBColumnMetaData processInstanceId = column.getTableMetaData().findColumn("processInstanceId");
+
+        List<Object> val = BoostTermTypeMapper.convertList(column, termValue.getOld());
+
+        termValue.setValue(val);
+        SqlAppender appender = new SqlAppender();
+        appender.add("exists(select 1 from ACT_RU_TASK RES inner join ACT_RU_IDENTITYLINK I on I.TASK_ID_ = RES.ID_ WHERE ", createColumnName(processInstanceId, tableAlias), "=RES.PROC_INST_ID_ and RES.ASSIGNEE_ is null and I.TYPE_ = 'candidate' and I.USER_ID_  ");
+        appendCondition(val, wherePrefix, appender);
+        appender.add(")");
+
+        return appender;
+    }
+}

+ 38 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/terms/CompletedSqlTerm.java

@@ -0,0 +1,38 @@
+package org.hswebframework.web.workflow.terms;
+
+import org.hswebframework.ezorm.core.param.Term;
+import org.hswebframework.ezorm.rdb.meta.RDBColumnMetaData;
+import org.hswebframework.ezorm.rdb.render.SqlAppender;
+import org.hswebframework.ezorm.rdb.render.dialect.term.BoostTermTypeMapper;
+import org.hswebframework.web.dao.mybatis.mapper.AbstractSqlTermCustomer;
+import org.hswebframework.web.dao.mybatis.mapper.ChangedTermValue;
+
+import java.util.List;
+
+/**
+ * 已完成的任务查询条件
+ *
+ * @author zhouhao
+ * @since 3.0.0-RC
+ */
+public class CompletedSqlTerm extends AbstractSqlTermCustomer {
+    public CompletedSqlTerm(String termType) {
+        super(termType);
+    }
+
+    @Override
+    public SqlAppender accept(String wherePrefix, Term term, RDBColumnMetaData column, String tableAlias) {
+        ChangedTermValue termValue = createChangedTermValue(term);
+        RDBColumnMetaData processInstanceId = column.getTableMetaData().findColumn("processInstanceId");
+
+        List<Object> val = BoostTermTypeMapper.convertList(column, termValue.getOld());
+
+        termValue.setValue(val);
+        SqlAppender appender = new SqlAppender();
+        appender.add("exists(select 1 from ACT_HI_TASKINST RES WHERE ", createColumnName(processInstanceId, tableAlias), "= RES.PROC_INST_ID_ and RES.ASSIGNEE_ ");
+        appendCondition(val, wherePrefix, appender);
+        appender.add(")");
+
+        return appender;
+    }
+}

+ 43 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/terms/ProcessParticipateSqlTerm.java

@@ -0,0 +1,43 @@
+package org.hswebframework.web.workflow.terms;
+
+import org.hswebframework.ezorm.core.param.Term;
+import org.hswebframework.ezorm.rdb.meta.RDBColumnMetaData;
+import org.hswebframework.ezorm.rdb.render.SqlAppender;
+import org.hswebframework.ezorm.rdb.render.dialect.term.BoostTermTypeMapper;
+import org.hswebframework.web.dao.mybatis.mapper.AbstractSqlTermCustomer;
+import org.hswebframework.web.dao.mybatis.mapper.ChangedTermValue;
+
+import java.util.List;
+
+/**
+ * 参与的任务查询条件
+ *
+ * @author zhouhao
+ * @since 3.0.0-RC
+ */
+public class ProcessParticipateSqlTerm extends AbstractSqlTermCustomer {
+    public ProcessParticipateSqlTerm(String termType) {
+        super(termType);
+    }
+
+    @Override
+    public SqlAppender accept(String wherePrefix, Term term, RDBColumnMetaData column, String tableAlias) {
+        ChangedTermValue termValue = createChangedTermValue(term);
+        RDBColumnMetaData processInstanceId = column.getTableMetaData().findColumn("processInstanceId");
+
+        List<Object> val = BoostTermTypeMapper.convertList(column, termValue.getOld());
+
+        termValue.setValue(val);
+        SqlAppender appender = new SqlAppender();
+
+        appender.add("exists(select 1 from ACT_HI_IDENTITYLINK I  WHERE ",
+                createColumnName(processInstanceId, tableAlias),
+                "=I.PROC_INST_ID_  "
+                , (!term.getOptions().isEmpty() ? " and I.TYPE_ =" + wherePrefix + ".options[0]" : "")
+                , " and I.USER_ID_  ");
+        appendCondition(val, wherePrefix, appender);
+        appender.add(")");
+
+        return appender;
+    }
+}

+ 37 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/terms/TodoSqlTerm.java

@@ -0,0 +1,37 @@
+package org.hswebframework.web.workflow.terms;
+
+import org.hswebframework.ezorm.core.param.Term;
+import org.hswebframework.ezorm.rdb.meta.RDBColumnMetaData;
+import org.hswebframework.ezorm.rdb.render.SqlAppender;
+import org.hswebframework.ezorm.rdb.render.dialect.term.BoostTermTypeMapper;
+import org.hswebframework.web.dao.mybatis.mapper.AbstractSqlTermCustomer;
+import org.hswebframework.web.dao.mybatis.mapper.ChangedTermValue;
+
+import java.util.List;
+
+/**
+ * 代办的任务查询条件
+ * @author zhouhao
+ * @since 3.0.0-RC
+ */
+public class TodoSqlTerm extends AbstractSqlTermCustomer {
+    public TodoSqlTerm(String termType) {
+        super(termType);
+    }
+
+    @Override
+    public SqlAppender accept(String wherePrefix, Term term, RDBColumnMetaData column, String tableAlias) {
+        ChangedTermValue termValue = createChangedTermValue(term);
+        RDBColumnMetaData processInstanceId = column.getTableMetaData().findColumn("processInstanceId");
+
+        List<Object> val = BoostTermTypeMapper.convertList(column, termValue.getOld());
+
+        termValue.setValue(val);
+        SqlAppender appender = new SqlAppender();
+        appender.add("exists(select 1 from ACT_RU_TASK RES WHERE ", createColumnName(processInstanceId, tableAlias), "= RES.PROC_INST_ID_ and RES.ASSIGNEE_ ");
+        appendCondition(val, wherePrefix, appender);
+        appender.add(")");
+
+        return appender;
+    }
+}

+ 33 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/terms/WorkflowTermsAutoConfiguration.java

@@ -0,0 +1,33 @@
+package org.hswebframework.web.workflow.terms;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author zhouhao
+ * @since 3.0.0-RC
+ */
+@Configuration
+public class WorkflowTermsAutoConfiguration {
+
+    @Bean
+    public ClaimSqlTerm claimSqlTerm() {
+        return new ClaimSqlTerm("user-wf-claim");
+    }
+
+    @Bean
+    public CompletedSqlTerm completedSqlTerm() {
+        return new CompletedSqlTerm("user-wf-completed");
+    }
+
+    @Bean
+    public ProcessParticipateSqlTerm participateSqlTerm() {
+        return new ProcessParticipateSqlTerm("user-wf-part");
+    }
+
+    @Bean
+    public TodoSqlTerm todoSqlTerm() {
+        return new TodoSqlTerm("user-wf-todo");
+    }
+
+}

+ 53 - 7
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/web/FlowableProcessController.java

@@ -7,9 +7,14 @@ import org.activiti.engine.RepositoryService;
 import org.activiti.engine.RuntimeService;
 import org.activiti.engine.TaskService;
 import org.activiti.engine.history.HistoricTaskInstanceQuery;
+import org.activiti.engine.impl.RepositoryServiceImpl;
+import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
+import org.activiti.engine.impl.task.TaskDefinition;
 import org.activiti.engine.repository.ProcessDefinition;
+import org.activiti.engine.runtime.Execution;
 import org.activiti.engine.runtime.ProcessInstance;
 import org.activiti.engine.runtime.ProcessInstanceQuery;
+import org.activiti.engine.task.Task;
 import org.activiti.engine.task.TaskQuery;
 import org.hswebframework.web.NotFoundException;
 import org.hswebframework.web.authorization.Authentication;
@@ -18,18 +23,23 @@ import org.hswebframework.web.authorization.annotation.Authorize;
 import org.hswebframework.web.commons.entity.PagerResult;
 import org.hswebframework.web.commons.entity.param.QueryParamEntity;
 import org.hswebframework.web.controller.message.ResponseMessage;
+import org.hswebframework.web.workflow.service.BpmActivityService;
+import org.hswebframework.web.workflow.service.config.CandidateInfo;
 import org.hswebframework.web.workflow.service.config.ProcessConfigurationService;
 import org.hswebframework.web.workflow.service.BpmProcessService;
 import org.hswebframework.web.workflow.service.BpmTaskService;
 import org.hswebframework.web.workflow.service.request.CompleteTaskRequest;
 import org.hswebframework.web.workflow.service.request.StartProcessRequest;
 import org.hswebframework.web.workflow.util.QueryUtils;
+import org.hswebframework.web.workflow.web.response.CandidateDetail;
 import org.hswebframework.web.workflow.web.response.ProcessInfo;
 import org.hswebframework.web.workflow.web.response.TaskInfo;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
+import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 
 /**
@@ -48,6 +58,9 @@ public class FlowableProcessController {
     @Autowired
     private BpmTaskService bpmTaskService;
 
+    @Autowired
+    private BpmActivityService bpmActivityService;
+
     @Autowired
     private BpmProcessService bpmProcessService;
 
@@ -112,7 +125,9 @@ public class FlowableProcessController {
         return ResponseMessage.ok(result).exclude(query.getExcludes()).include(query.getIncludes());
     }
 
-    @PostMapping("start/key/{defineKey}")
+
+
+    @PostMapping("/start/key/{defineKey}")
     @ApiOperation("提交表单数据并根据流程定义key启动流程")
     @Authorize(merge = false)
     public ResponseMessage<String> startProcessByKey(@PathVariable String defineKey,
@@ -143,7 +158,7 @@ public class FlowableProcessController {
         return ResponseMessage.ok(instance.getId());
     }
 
-    @PostMapping("start/id/{defId}")
+    @PostMapping("/start/id/{defId}")
     @ApiOperation("提交表单数据并根据流程定义ID启动流程")
     @Authorize(merge = false)
     public ResponseMessage<String> startProcess(@PathVariable String defId,
@@ -172,10 +187,10 @@ public class FlowableProcessController {
         return ResponseMessage.ok(instance.getId());
     }
 
-    @GetMapping("todo")
+    @GetMapping("/todo")
     @ApiOperation("获取待办任务")
     @Authorize(merge = false)
-    public ResponseMessage<PagerResult<TaskInfo>> getTodoLst(QueryParamEntity query, Authentication authentication) {
+    public ResponseMessage<PagerResult<TaskInfo>> getTodoList(QueryParamEntity query, Authentication authentication) {
         TaskQuery taskQuery = taskService.createTaskQuery();
 
         taskQuery.taskAssignee(authentication.getUser().getId());
@@ -185,7 +200,7 @@ public class FlowableProcessController {
         return ResponseMessage.ok(result).exclude(query.getExcludes()).include(query.getIncludes());
     }
 
-    @GetMapping("claims")
+    @GetMapping("/claims")
     @ApiOperation("获取待签收任务")
     @Authorize(merge = false)
     public ResponseMessage<PagerResult<TaskInfo>> getClaims(QueryParamEntity query, Authentication authentication) {
@@ -197,7 +212,7 @@ public class FlowableProcessController {
         return ResponseMessage.ok(result);
     }
 
-    @PutMapping("claim/{taskId}")
+    @PutMapping("/claim/{taskId}")
     @ApiOperation("签收任务")
     @Authorize(merge = false)
     public ResponseMessage<Void> claim(@PathVariable String taskId, Authentication authentication) {
@@ -205,7 +220,7 @@ public class FlowableProcessController {
         return ResponseMessage.ok();
     }
 
-    @PutMapping("complete/{taskId}")
+    @PutMapping("/complete/{taskId}")
     @Authorize(merge = false)
     public ResponseMessage<Void> complete(@PathVariable String taskId,
                                           @RequestBody(required = false) Map<String, Object> formData,
@@ -220,4 +235,35 @@ public class FlowableProcessController {
         return ResponseMessage.ok();
     }
 
+    @PostMapping("/next-task-candidate/{taskId}")
+    @Authorize(merge = false)
+    public ResponseMessage<List<CandidateDetail>> candidateList(@PathVariable String taskId,
+                                                                @RequestBody Map<String, Object> data,
+                                                                Authentication authentication) {
+
+        Task task = taskService.createTaskQuery()
+                .taskId(taskId)
+                .singleResult();
+
+        ExecutionEntity execution = (ExecutionEntity) runtimeService.createExecutionQuery()
+                .processInstanceId(task.getProcessInstanceId())
+                .activityId(task.getTaskDefinitionKey())
+                .singleResult();
+
+        execution.setVariablesLocal(data);
+
+        List<TaskDefinition> taskDefinitions = bpmActivityService
+                .getNextActivities(task.getProcessDefinitionId(), task.getTaskDefinitionKey(), (execution));
+
+        List<CandidateDetail> candidates = taskDefinitions.stream().map(TaskDefinition::getKey)
+                .flatMap(key ->
+                        processConfigurationService
+                                .getActivityConfiguration(authentication.getUser().getId(), task.getProcessDefinitionId(), key)
+                                .getCandidateInfo(task).stream())
+                .map(CandidateDetail::of)
+                .collect(Collectors.toList());
+
+
+        return ResponseMessage.ok(candidates);
+    }
 }

+ 11 - 1
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/web/ProcessActivityConfigController.java

@@ -1,18 +1,29 @@
 package org.hswebframework.web.workflow.web;
 
 import io.swagger.annotations.Api;
+import org.activiti.engine.RuntimeService;
+import org.activiti.engine.TaskService;
+import org.activiti.engine.task.Task;
+import org.hswebframework.web.authorization.Authentication;
 import org.hswebframework.web.authorization.annotation.Authorize;
 import org.hswebframework.web.commons.entity.param.QueryParamEntity;
 import org.hswebframework.web.controller.SimpleGenericEntityController;
+import org.hswebframework.web.controller.message.ResponseMessage;
 import org.hswebframework.web.service.CrudService;
 import org.hswebframework.web.workflow.dao.entity.ActivityConfigEntity;
 import org.hswebframework.web.workflow.dao.entity.ProcessDefineConfigEntity;
 import org.hswebframework.web.workflow.service.ActivityConfigService;
 import org.hswebframework.web.workflow.service.ProcessDefineConfigService;
+import org.hswebframework.web.workflow.service.config.CandidateInfo;
+import org.hswebframework.web.workflow.service.config.ProcessConfigurationService;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.List;
+
 /**
  * @author zhouhao
  * @since 3.0.0-RC
@@ -31,5 +42,4 @@ public class ProcessActivityConfigController
         return service;
     }
 
-
 }

+ 0 - 1
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/web/ProcessDefineConfigController.java

@@ -29,5 +29,4 @@ public class ProcessDefineConfigController
         return service;
     }
 
-
 }

+ 46 - 0
hsweb-system/hsweb-system-workflow/hsweb-system-workflow-local/src/main/java/org/hswebframework/web/workflow/web/response/CandidateDetail.java

@@ -0,0 +1,46 @@
+package org.hswebframework.web.workflow.web.response;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.hswebframework.web.commons.bean.Bean;
+import org.hswebframework.web.organizational.authorization.Position;
+import org.hswebframework.web.workflow.service.config.CandidateInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author zhouhao
+ * @since 3.0.0-RC
+ */
+@Getter
+@Setter
+public class CandidateDetail implements Bean {
+
+    private static final long serialVersionUID = 7568237438666348299L;
+
+    private String userId;
+
+    private String personId;
+
+    private String name;
+
+    private List<Position> positions;
+
+    public static CandidateDetail of(CandidateInfo candidateInfo) {
+        CandidateDetail detail = new CandidateDetail();
+
+        if (candidateInfo.user() != null) {
+            detail.setName(candidateInfo.user().getUser().getName());
+            detail.setUserId(candidateInfo.user().getUser().getId());
+        }
+
+        if (candidateInfo.person() != null) {
+            detail.setPersonId(candidateInfo.person().getPersonnel().getId());
+            detail.setName(candidateInfo.person().getPersonnel().getName());
+            detail.setPositions(new ArrayList<>(candidateInfo.person().getPositions()));
+        }
+
+        return detail;
+    }
+}