工作流演示开发文档
1. 概述
梵医云工作流模块基于 Flowable 6 实现,提供完整的业务流程管理(Business Process Management)功能。本文档将详细介绍工作流的演示开发流程,帮助开发者快速上手工作流功能。
2. 工作流核心概念
2.1 核心组件
| 组件 | 描述 | 对应类 |
|---|---|---|
| 流程模型 | 工作流的设计蓝图,包含流程定义和表单配置 | BpmModel |
| 流程定义 | 已部署的流程模型,可用于创建流程实例 | ProcessDefinition |
| 流程实例 | 流程的具体执行实例,对应一次业务流程的运行 | ProcessInstance |
| 流程任务 | 流程中的具体任务,需要用户或系统处理 | Task |
| 流程活动 | 流程执行过程中的各种活动,如开始、结束、用户任务等 | Activity |
| 流程表单 | 与流程关联的表单,用于收集和展示数据 | BpmFormDO |
2.2 任务分配策略
工作流支持 7 种任务分配规则:
| 策略 | 描述 | 实现类 |
|---|---|---|
| 用户分配 | 直接指定具体用户 | BpmTaskCandidateUserStrategy |
| 角色分配 | 基于用户角色分配 | BpmTaskCandidateRoleStrategy |
| 部门领导 | 分配给部门领导 | BpmTaskCandidateDeptLeaderStrategy |
| 部门成员 | 分配给部门所有成员 | BpmTaskCandidateDeptMemberStrategy |
| 岗位分配 | 基于用户岗位分配 | BpmTaskCandidatePostStrategy |
| 分组分配 | 基于用户分组分配 | BpmTaskCandidateGroupStrategy |
| 表达式分配 | 基于表达式动态计算 | BpmTaskCandidateExpressionStrategy |
| 发起人选择 | 由流程发起人选择审批人 | BpmTaskCandidateStartUserSelectStrategy |
3. 工作流演示开发步骤
3.1 步骤一:创建流程模型
3.1.1 在线设计流程
- 访问流程模型管理:进入后台管理系统,点击「工作流程」→「流程模型」
- 创建新模型:点击「新建」按钮,填写模型名称和描述
- 设计流程图:
- 拖拽左侧组件到画布
- 连接各个节点形成流程
- 配置每个节点的属性
3.1.2 配置用户任务
- 选择用户任务节点
- 配置任务属性:
- 任务名称:如「部门领导审批」
- 分配类型:选择合适的任务分配策略
- 审批人:根据分配类型设置具体值
3.1.3 关联流程表单
- 进入流程表单管理:点击「工作流程」→「流程表单」
- 创建新表单:
- 拖拽表单元素生成表单
- 配置表单字段属性
- 保存表单
- 关联表单:在流程模型设计时,为用户任务节点关联对应的表单
3.2 步骤二:部署流程定义
- 发布流程模型:在流程模型列表中,点击「发布」按钮
- 验证部署:进入「流程定义」页面,查看已部署的流程
3.3 步骤三:创建流程实例
3.3.1 前端发起流程
vue
<template>
<el-button type="primary" @click="startProcess">发起流程</el-button>
</template>
<script>
export default {
methods: {
async startProcess() {
const formData = {
// 表单数据
};
const response = await this.$http.post('/bpm/process-instance/create', {
processDefinitionId: '流程定义ID',
variables: formData,
businessKey: '业务标识'
});
if (response.code === 0) {
this.$message.success('流程发起成功');
}
}
}
};
</script>3.3.2 后端创建流程实例
java
@Service
public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService {
@Override
public String createProcessInstance(BpmProcessInstanceCreateReqVO createReqVO) {
// 1. 获取流程定义
ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition(
createReqVO.getProcessDefinitionId());
// 2. 构建流程变量
Map<String, Object> variables = createReqVO.getVariables();
// 3. 创建流程实例
ProcessInstance processInstance = runtimeService.startProcessInstanceById(
createReqVO.getProcessDefinitionId(),
createReqVO.getBusinessKey(),
variables
);
// 4. 保存流程实例信息
// ...
return processInstance.getId();
}
}3.4 步骤四:处理流程任务
3.4.1 待办任务列表
前端代码:
vue
<template>
<el-table :data="taskList">
<el-table-column prop="name" label="任务名称" />
<el-table-column prop="processInstanceName" label="流程名称" />
<el-table-column label="操作">
<template slot-scope="scope">
<el-button @click="approveTask(scope.row.id, true)">通过</el-button>
<el-button @click="approveTask(scope.row.id, false)">拒绝</el-button>
</template>
</el-table-column>
</el-table>
</template>
<script>
export default {
data() {
return {
taskList: []
};
},
mounted() {
this.loadTasks();
},
methods: {
async loadTasks() {
const response = await this.$http.get('/bpm/task/page');
if (response.code === 0) {
this.taskList = response.data.list;
}
},
async approveTask(taskId, approved) {
const response = await this.$http.post('/bpm/task/approve', {
id: taskId,
approved: approved,
reason: approved ? '同意' : '不同意'
});
if (response.code === 0) {
this.$message.success('审批成功');
this.loadTasks();
}
}
}
};
</script>3.4.2 任务审批处理
后端代码:
java
@Service
public class BpmTaskServiceImpl implements BpmTaskService {
@Override
public void approveTask(String id, BpmTaskApproveReqVO reqVO) {
// 1. 获取任务
Task task = taskService.createTaskQuery().taskId(id).singleResult();
// 2. 验证任务状态
// ...
// 3. 设置任务变量
Map<String, Object> variables = new HashMap<>();
variables.put(BpmConstants.TASK_VARIABLE_STATUS, reqVO.getApproved() ? "APPROVED" : "REJECTED");
variables.put(BpmConstants.TASK_VARIABLE_REASON, reqVO.getReason());
// 4. 完成任务
taskService.complete(id, variables);
// 5. 处理审批结果
// ...
}
}3.5 步骤五:流程状态跟踪
3.5.1 流程实例详情
前端代码:
vue
<template>
<div>
<h3>流程详情</h3>
<el-descriptions :column="2">
<el-descriptions-item label="流程名称">{{ processInstance.name }}</el-descriptions-item>
<el-descriptions-item label="状态">{{ getStatusText(processInstance.status) }}</el-descriptions-item>
<el-descriptions-item label="发起人">{{ processInstance.startUser }}</el-descriptions-item>
<el-descriptions-item label="发起时间">{{ formatDate(processInstance.startTime) }}</el-descriptions-item>
</el-descriptions>
<h3>审批 timeline</h3>
<el-timeline>
<el-timeline-item
v-for="activity in activities"
:key="activity.id"
:timestamp="formatDate(activity.startTime)"
:type="activity.type === 'approve' ? 'success' : 'warning'"
>
{{ activity.name }} - {{ activity.assignee }}
<div v-if="activity.reason">{{ activity.reason }}</div>
</el-timeline-item>
</el-timeline>
</div>
</template>
<script>
export default {
data() {
return {
processInstance: {},
activities: []
};
},
mounted() {
this.loadProcessInstance();
this.loadActivities();
},
methods: {
async loadProcessInstance() {
const response = await this.$http.get(`/bpm/process-instance/get?id=${this.$route.params.id}`);
if (response.code === 0) {
this.processInstance = response.data;
}
},
async loadActivities() {
const response = await this.$http.get(`/bpm/activity/list?processInstanceId=${this.$route.params.id}`);
if (response.code === 0) {
this.activities = response.data;
}
},
getStatusText(status) {
const statusMap = {
'RUNNING': '运行中',
'COMPLETED': '已完成',
'CANCELLED': '已取消'
};
return statusMap[status] || status;
},
formatDate(date) {
return this.$moment(date).format('YYYY-MM-DD HH:mm:ss');
}
}
};
</script>4. 工作流演示示例
4.1 OA 请假流程
4.1.1 流程设计
创建流程模型:
- 流程名称:OA 请假流程
- 流程标识:oa_leave
- 流程分类:OA 流程
设计流程图:
- 开始事件 → 填写请假表单 → 部门领导审批 → 人事审批 → 结束事件
配置表单:
- 请假类型:下拉选择(事假、病假、年假等)
- 请假开始时间:日期时间选择器
- 请假结束时间:日期时间选择器
- 请假天数:计算字段
- 请假原因:文本域
配置任务分配:
- 部门领导审批:部门领导策略
- 人事审批:角色分配(人事专员)
4.1.2 代码实现
流程发起:
java
@RestController
@RequestMapping("/bpm/oa/leave")
public class BpmOALeaveController {
@PostMapping("/create")
public CommonResult<Long> createBpmOALeave(@Valid @RequestBody BpmOALeaveCreateReqVO createReqVO) {
return success(bpmOALeaveService.createBpmOALeave(createReqVO));
}
}流程服务:
java
@Service
public class BpmOALeaveServiceImpl implements BpmOALeaveService {
@Override
public Long createBpmOALeave(BpmOALeaveCreateReqVO createReqVO) {
// 1. 计算请假天数
long days = DateUtils.betweenDays(createReqVO.getStartTime(), createReqVO.getEndTime()) + 1;
// 2. 保存请假记录
BpmOALeaveDO leave = BpmOALeaveConvert.INSTANCE.convert(createReqVO);
leave.setDays(days);
leaveMapper.insert(leave);
// 3. 发起流程
BpmProcessInstanceCreateReqDTO processInstanceCreateReqDTO = new BpmProcessInstanceCreateReqDTO();
processInstanceCreateReqDTO.setProcessDefinitionId(createReqVO.getProcessDefinitionId());
processInstanceCreateReqDTO.setBusinessKey(leave.getId().toString());
Map<String, Object> variables = new HashMap<>();
variables.put("leaveId", leave.getId());
variables.put("leaveType", createReqVO.getType());
variables.put("startTime", createReqVO.getStartTime());
variables.put("endTime", createReqVO.getEndTime());
variables.put("days", days);
variables.put("reason", createReqVO.getReason());
processInstanceCreateReqDTO.setVariables(variables);
String processInstanceId = bpmProcessInstanceApi.createProcessInstance(processInstanceCreateReqDTO);
// 4. 更新请假记录的流程实例ID
leave.setProcessInstanceId(processInstanceId);
leaveMapper.updateById(leave);
return leave.getId();
}
}4.2 采购审批流程
4.2.1 流程设计
创建流程模型:
- 流程名称:采购审批流程
- 流程标识:purchase_approval
- 流程分类:业务流程
设计流程图:
- 开始事件 → 填写采购申请 → 部门领导审批 → 财务审批 → 总经理审批 → 结束事件
配置表单:
- 采购物品:文本框
- 采购数量:数字输入框
- 采购金额:数字输入框
- 采购原因:文本域
- 供应商信息:文本框
配置任务分配:
- 部门领导审批:部门领导策略
- 财务审批:角色分配(财务专员)
- 总经理审批:条件网关(金额 > 10000 时需要)
5. 工作流高级功能
5.1 流程监听器
流程监听器可以在流程执行的不同阶段触发自定义逻辑:
java
public class BpmProcessInstanceEventListener {
@EventListener
public void onProcessStarted(ProcessStartedEvent event) {
// 流程开始时的处理逻辑
log.info("Process started: {}", event.getProcessInstanceId());
}
@EventListener
public void onProcessCompleted(ProcessCompletedEvent event) {
// 流程完成时的处理逻辑
log.info("Process completed: {}", event.getProcessInstanceId());
}
@EventListener
public void onTaskCreated(TaskCreatedEvent event) {
// 任务创建时的处理逻辑
log.info("Task created: {}", event.getTask().getId());
// 发送任务通知
bpmMessageService.sendTaskCreatedMessage(event.getTask());
}
@EventListener
public void onTaskCompleted(TaskCompletedEvent event) {
// 任务完成时的处理逻辑
log.info("Task completed: {}", event.getTask().getId());
}
}5.2 自定义任务分配策略
如果内置的任务分配策略不能满足需求,可以自定义策略:
java
@Component
public class CustomTaskCandidateStrategy implements BpmTaskCandidateStrategy {
@Override
public List<Long> calculateCandidates(UserTask userTask, BpmTaskCandidateStrategyContext context) {
// 自定义任务分配逻辑
// 例如:基于业务规则计算审批人
return Collections.singletonList(1L); // 返回审批人ID列表
}
@Override
public String getType() {
return "custom"; // 策略类型标识
}
}5.3 流程变量管理
流程变量用于在流程执行过程中传递数据:
java
// 设置流程变量
runtimeService.setVariable(processInstanceId, "key", "value");
// 获取流程变量
Object value = runtimeService.getVariable(processInstanceId, "key");
// 获取所有流程变量
Map<String, Object> variables = runtimeService.getVariables(processInstanceId);6. 工作流最佳实践
6.1 设计原则
- 流程清晰:流程图应该清晰易懂,避免过于复杂的分支逻辑
- 表单简洁:表单字段应该简洁明了,只包含必要的信息
- 权限明确:任务分配策略应该明确,避免审批人不明确的情况
- 业务关联:流程应该与业务系统紧密关联,通过 businessKey 建立联系
- 异常处理:考虑流程执行过程中的异常情况,如审批人离职等
6.2 性能优化
流程设计优化:
- 避免过长的流程链
- 合理使用子流程
- 减少不必要的网关
数据库优化:
- 为 Flowable 表添加索引
- 定期清理历史数据
- 使用合适的数据库连接池配置
代码优化:
- 避免在流程监听器中执行耗时操作
- 使用异步任务处理复杂逻辑
- 合理使用缓存减少数据库查询
6.3 常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 流程无法启动 | 流程定义未激活 | 检查流程定义状态,确保已激活 |
| 任务分配错误 | 任务分配策略配置错误 | 检查任务分配策略配置,确保正确设置审批人 |
| 流程卡住 | 网关条件不满足 | 检查网关条件表达式,确保流程能够正常流转 |
| 性能问题 | 流程实例过多 | 定期清理历史流程实例,优化流程设计 |
7. 开发工具和调试
7.1 开发工具
- Flowable Modeler:在线流程设计器
- Flowable Admin:流程管理控制台
- Flowable IDM:身份管理系统
7.2 调试技巧
查看流程实例状态:
- 通过
runtimeService.getProcessInstance(processInstanceId)获取流程实例 - 通过
historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult()获取历史流程实例
- 通过
查看任务状态:
- 通过
taskService.createTaskQuery().processInstanceId(processInstanceId).list()获取任务列表 - 通过
historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).list()获取历史任务
- 通过
查看流程变量:
- 通过
runtimeService.getVariables(processInstanceId)获取流程变量 - 通过
historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).list()获取历史变量
- 通过
查看流程日志:
- 配置 Flowable 日志级别为 DEBUG
- 查看应用服务器日志
8. 总结
工作流是梵医云系统的重要组成部分,基于 Flowable 6 实现了完整的业务流程管理功能。本文档介绍了工作流的核心概念、开发步骤、演示示例和最佳实践,希望能够帮助开发者快速上手工作流开发。
通过合理的流程设计和代码实现,可以构建高效、可靠的业务流程系统,提高企业的运营效率和管理水平。
