目录
项目详解
前端
API
flowable/api/definition.js:实现流程定义相关操作的api,连接后端FlowDefinitionController.java中的方法
flowable/api/finished.js、flowable/api/process.js、flowable/api/tode.js:实现流程执行相关操作的api
组件
flowable/components/ActApplyBtn.vue:提交按钮(启动流程)
flowable/components/ActCancelBtn.vue:撤回(销毁流程)
flowable/components/ActHandleBtn.vue:处理流程(0 通过、退回节点:1 驳回、2 退回、3 重新提交)
flowable/components/ActHistoricDetailBtn.vue:审批处理历史
flowable/components/HistoricDetail.vue:审批处理历史页面组件
后端
FlowDefinitionController.java
flowable/controller/FlowDefinitionController.java:工作流程定义
例如:获取流程定义列表、导入流程文件、读取xml文件等
FlowTaskController.java
flowable/controller/FlowTaskController.java:工作流任务管理
例如:查看发起流程、取消申请、撤回流程、获取待办任务等
FlowInstanceController.java
flowable/controller/FlowInstanceController.java:工作流流程实例管理
例如:激活或挂起流程实例、删除流程实例
项目开发
首先要实现任课老师提交实验课授课方式申请的工作流
流程图
先用部署好的流程设计页面画好流程图:
创建流程图时要选好候选人员:
若有网关要写好网关的条件表达式(排他网关一定得写条件表达式):
创建数据库
利用Jeecg-boot Online表单在线开发功能,为老师申请实验课任课方式创建数据库exc_apply
生成代码包ExcApply
后端
ExcApply包详解
ExcApply/controller/ExcApplyController.java:完成后端相关操作例如添加、修改、删除、查询等)
实现relationAct接口,使得申请能够关联上流程
@AutoLog(value = "关联流程")
@ApiOperation(value="关联流程", notes="关联流程")
@RequestMapping(value = "/relationAct",method = RequestMethod.GET)
public Result<?> relationAct(HttpServletRequest request,HttpServletResponse response){
String dataId = request.getParameter("dataId");
excApplyService.relationAct(dataId);
return Result.OK();
}
ExcApply/entity/ExcApply.java:对应exc_apply数据库的属性类
ExcApply/mapper/xml/ExcApplyMapper.xml:数据库exc_apply的xml
ExcApply/mapper/ExcApplyMapper.java:对应任课老师申请授课方式model的属性类
为使用IPage和Page实现分页:
public interface ExcApplyMapper extends BaseMapper<ExCApply> {
IPage<ExcApply> myPage(Page<ExcApply> page, @Param(Constants.WRAPPER) QueryWrapper<ExcApply> queryWrapper);
}
service/IExcApplyServiceImpl.java:服务接口
为使用IPage和Page实现分页:
public interface IExCApplyService extends IService<ExCApply> {
IPage<ExcApply> myPage(Page<ExcApply> page, QueryWrapper<ExcApply> queryWrapper);
void relationAct(String dataId);
}
service/impl/ExCApplyServiceImpl.java:
Service必须继承FlowCallBackServiceI接口并实现其方法
@Service("excApplyService")
public class ExcApplyServiceImpl extends ServiceImpl<ExcApplyMapper, ExcApply> implements IExcApplyService , FlowCallBackServiceI {
@Autowired
FlowCommonService flowCommonService;
/**
* 初始生成业务与流程的关联信息<br/>
* 当业务模块新增一条数据后调用,此时业务数据关联一个流程定义,以备后续流程使用
* @return 是否成功
* @param title 必填。流程业务简要描述。例:2021年11月26日xxxxx申请
* @param dataId 必填。业务数据Id,如果是一对多业务关系,传入主表的数据Id
* @param serviceImplName 必填。业务service注入spring容器的名称。
* 例如:@Service("demoService")则传入 demoService
* @param processDefinitionKey 必填。流程定义Key,传入此值,未来启动的会是该类流程的最新一个版本
* @param processDefinitionId 选填。流程定义Id,传入此值,未来启动的为指定版本的流程
*/
public void initActBusiness(String title, String dataId, String serviceImplName, String processDefinitionKey, String processDefinitionId){
flowCommonService.initActBusiness(title,dataId,"exCApplyService","process_tpho5a4q","ExcApply:14:de1f495f-d7d9-11ec-9c5d-927841cf098b");
}
@Override
public void relationAct(String dataId) {
flowCommonService.initActBusiness("实验授课申请:dataId"+dataId,dataId,"excApplyService","process_tpho5a4q","process_tpho5a4q:4:32128f7c-ce77-11ec-843e-927841cf098b");
}
@Override
public IPage<ExcApply> myPage(Page<ExcApply> page, QueryWrapper<ExcApply> queryWrapper) {
return this.baseMapper.myPage(page,queryWrapper);
}
@Override
public void afterFlowHandle(FlowMyBusiness business) {
//流程操作后做些什么
business.getTaskNameId();//接下来审批的节点
business.getValues();//前端传进来的参数
business.getActStatus();//流程状态 ActStatus.java
//....其他
}
@Override
public Object getBusinessDataById(String dataId) {
return this.getById(dataId);
}
@Override
public Map<String, Object> flowValuesOfTask(String taskNameId, Map<String, Object> values) {
return null;
}
@Override
public List<String> flowCandidateUsernamesOfTask(String taskNameId, Map<String, Object> values) {
// 案例,写死了jeecg,实际业务中通过当前节点来判断下一个节点的候选人并写回到反参中,如果为null,流程模块会根据默认设置处理
return Lists.newArrayList("jeecg");
}
@Override
public boolean save(ExcApply excApply){
/**新增数据,初始化流程关联信息**/
excApply.setId(IdUtil.fastSimpleUUID());
this.relationAct(excApply.getId());
return super.save(excApply);
}
@Override
public boolean removeById(Serializable id){
/**删除数据,移除流程关联信息**/
flowCommonService.delActBusiness(id.toString());
return super.removeById(id);
}
}
所实现的方法afterFlowHandle将在流程处理过程中被回调,用以增强处理业务层业务逻辑(之后修改
@Override
public void afterFlowHandle(FlowMyBusiness business) {
//流程操作后做些什么
business.getTaskNameId();//接下来审批的节点
business.getValues();//前端传进来的参数
business.getActStatus();//流程状态 ActStatus.java
//....其他
}
在业务数据新增时,必须初始化业务和流程间的关联,调用FlowCommonService.initActBusiness方法
/**
* 初始生成业务与流程的关联信息<br/>
* 当业务模块新增一条数据后调用,此时业务数据关联一个流程定义,以备后续流程使用
* @return 是否成功
* @param title 必填。流程业务简要描述。例:2021年11月26日xxxxx申请
* @param dataId 必填。业务数据Id,如果是一对多业务关系,传入主表的数据Id
* @param serviceImplName 必填。业务service注入spring容器的名称。
* 例如:@Service("demoService")则传入 demoService
* @param processDefinitionKey 必填。流程定义Key,传入此值,未来启动的会是该类流程的最新一个版本
* @param processDefinitionId 选填。流程定义Id,传入此值,未来启动的为指定版本的流程
*/
public void initActBusiness(String title, String dataId, String serviceImplName, String processDefinitionKey, String processDefinitionId){
flowCommonService.initActBusiness(title,dataId,"exCApplyService","process_tpho5a4q","process_tpho5a4q:3:b18ae95d-ce02-11ec-8534-927841cf098b");
}
删除业务数据时调用flowCommonService.delActBusiness(id.toString());
@Override
public boolean removeById(Serializable id){
/**删除数据,移除流程关联信息**/
flowCommonService.delActBusiness(id.toString());
return super.removeById(id);
}
前端
创建教师申请页面:
关联流程
教师申请完首先得点击“关联流程”按钮,让其与流程相关联:
<a @click="relationAct(record)">关联流程</a>
relationAct(r){
getAction("/ExcApply/excApply/relationAct",{dataId:r.id}).then(res=>{
if(res.success){
this.$message.success("操作成功")
this.loadData()
}else{
this.$message.error("操作失败")
}
})
}
relationAct方法调用后端relationAct方法:
@AutoLog(value = "关联流程")
@ApiOperation(value="关联流程", notes="关联流程")
@RequestMapping(value = "/relationAct",method = RequestMethod.GET)
public Result<?> relationAct(HttpServletRequest request,HttpServletResponse response){
String dataId = request.getParameter("dataId");
excApplyService.relationAct(dataId);
return Result.OK();
}
申请(ActApplyBtn.vue)
然后点击申请按钮提交申请:
必须传入流程需要的variables,如此流程之后是一个排他网关,${isNeeded == 'true'}为此网关的跳转条件,所以需要传入isNeeded来判断走哪一条路
<act-apply-btn @success="loadData" :data-id="record.id" :variables="{isNeeded:record.needextea}"></act-apply-btn>
调用ActApplyBtn组件,此组件添加点击事件,调用definitionStartByDataId方法:
import {definitionStartByDataId} from "@views/flowable/api/definition";
applySubmit() {
if (this.dataId && this.dataId.length < 1) {
this.error = '必须传入参数dataId';
this.$message.error(this.error);
return;
} else {
this.error = '';
}
this.submitLoading = true;
var params = Object.assign({
dataId: this.dataId
}, this.variables);
console.log(params);
definitionStartByDataId(this.dataId, params)
.then(res => {
if (res.success) {
this.$message.success('操作成功');
this.$emit('success');
} else {
this.$message.error(res.message);
}
})
.finally(() => (this.submitLoading = false));
}
definitionStartByDataId()方法调用后端FlowDefinitionServiceImpl.java中的startByDataId接口实现流程实例的部署:
// 部署流程实例
export function definitionStartByDataId(dataId,data) {
return request({
url: '/flowable/definition/startByDataId/' + dataId,
method: 'post',
data: data
})
}
重新提交(ActHandleBtn.vue):
<act-handle-btn @success="loadData" :data-id="record.id" :type="3" text="重新提交"></act-handle-btn>
调用ActHandleBtn组件,0通过、退回节点(1驳回、2退回、3重新提交)。此组件添加点击事件处理不同类型的按钮:
handle() {
this.form.comment = ''
this.candidateUsersSelecteds = []
if (this.type === this.handleType.delegate) {
// this.delegateTask();
} else if (this.type === this.handleType.pass) {
this.passTask();
} else if (this.type === this.handleType.back) {
this.backTask();
} else if(this.type === this.handleType.return){
this.returnTask();
} else if(this.type === this.handleType.reApply){
this.reApply();
}
else {
this.$message.warn('未知类型type,参见 handleType');
}
}
重新提交:
reApply() {
const v = this;
this.modalTaskTitle = '确认重新提交';
this.modalTaskVisible = true;
},
其他类似
撤销(ActCancelBtn.vue):
<act-cancel-btn @success="loadData" :data-id="record.id"></act-cancel-btn>
撤销按钮绑定点击事件cancel(),让撤销面板可见,填写撤销原因
cancel() {
this.modalCancelVisible = true;
},
handelSubmitCancel() {
this.submitLoading = true;
deleteByDataId(this.dataId, this.cancelForm.reason)
.then(res => {
if (res.success) {
this.$message.success('操作成功');
this.modalCancelVisible = false;
this.$emit('success');
} else {
this.$message.error(res.message);
}
})
.finally(() => (this.submitLoading = false));
}
}
审批历史(ActHandleBtn.vue)
点击审批历史按钮可查看进展:
<act-historic-detail-btn :data-id="record.id"></act-historic-detail-btn>
点击事件与提交类似