需求描述:
芋道的动态表单就不再介绍了,相对来讲比较简单,跟着官网文档就可以实现,本文将详细的介绍如何新建独立的业务表记录申请的信息,并设计对应的工作流。
这里表中的每一条记录,都将通过流程实例编号(process_instance_id
)和对应的流程实例进行关联。
而每一个流程实例也都会通过业务键(BUSINESS_KEY_
)指向对应的业务记录
这里假设创建一个车辆申请工作流,来举例:
1.设计业务表:
CREATE TABLE `bpm_oa_apply` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '车辆申请表单主键',
`user_id` bigint NOT NULL COMMENT '申请人的用户编号',
`type` tinyint NOT NULL COMMENT '车辆类型',
`reason` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '申请原因',
`start_time` datetime NOT NULL COMMENT '开始时间',
`end_time` datetime NOT NULL COMMENT '结束时间',
`result` tinyint NOT NULL COMMENT '申请结果',
`process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '流程实例的编号',
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '更新者',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='OA 车辆申请表';
process_instance_id
字段,关联流程引擎的流程实例对应的ACT_HI_PROCINST
表的PROC_INST_ID_
字段result
字段,申请结果,需要通过 Listener 监听回调结果
2.代码生成
利用系统中的代码生成,可以快速的生成对应的结构,将生成的代码粘贴到对应的模块,具体可以看芋道官网的开发文档中 代码生成(单表)说明文档。代码生成【单表】(新增功能) | ruoyi-vue-pro 开发指南 (iocoder.cn)https://doc.iocoder.cn/new-feature/#_2-1-%E5%AF%BC%E5%85%A5%E8%A1%A8
生成的代码都导入完成后,我们创建审批流要用到的create和detail页面,这里我们仿照给的请假申请示例:
3.创建create和detail界面,具体如下:
create.vue:该页面用于填写业务表的信息,提交流程
<template>
<div class="app-container">
<el-form ref="formRef" :model="formData" :rules="formRules" v-loading="formLoading" label-width="100px">
<el-form-item label="车辆类型" prop="type">
<el-select v-model="formData.type" placeholder="请选择车辆类型">
<el-option v-for="dict in typeDictData" :key="parseInt(dict.value)" :label="dict.label" :value="parseInt(dict.value)"/>
</el-select>
</el-form-item>
<el-form-item label="申请原因" prop="reason">
<el-input v-model="formData.reason" placeholder="请输入申请原因" />
</el-form-item>
<el-form-item label="开始时间" prop="startTime">
<el-date-picker clearable v-model="formData.startTime" type="date" value-format="timestamp" placeholder="选择开始时间" />
</el-form-item>
<el-form-item label="结束时间" prop="endTime">
<el-date-picker clearable v-model="formData.endTime" type="date" value-format="timestamp" placeholder="选择结束时间" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm">提 交</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { getDictDatas, DICT_TYPE } from '@/utils/dict'
import * as OaApplyApi from '@/api/bpm/oaapply';
export default {
name: "OaApplyForm",
components: {
},
data() {
return {
formData: {
type: undefined,
reason: undefined,
startTime: undefined,
endTime: undefined,
},
typeDictData: getDictDatas(DICT_TYPE.BPM_OA_LEAVE_TYPE),
};
},
methods: {
/** 提交按钮 */
submitForm() {
this.$refs["formRef"].validate(valid => {
if (!valid) {
return;
}
const data = this.formData;
OaApplyApi.createOaApply(data);
this.$modal.msgSuccess("新增成功");
this.dialogVisible = false;
this.$emit('success');
});
},
}
};
</script>
detai.vue: 该页面用于查看业务表的信息
<template>
<div class="app-container">
<el-form ref="formRef" :model="formData" label-width="100px">
<el-form-item label="车辆类型" prop="type">
<dict-tag :type="DICT_TYPE.BPM_OA_CAR_TYPE" :value="formData.type"/>
</el-form-item>
<el-form-item label="申请原因" prop="reason">
{{ formData.reason}}
</el-form-item>
<el-form-item label="开始时间" prop="startTime">
{{parseTime(formData.startTime, '{y}-{m}-{d}')}}
</el-form-item>
<el-form-item label="结束时间" prop="endTime">
{{parseTime(formData.endTime, '{y}-{m}-{d}')}}
</el-form-item>
</el-form>
</div>
</template>
<script>
import {getOaApply} from '@/api/bpm/apply';
import {getDictDatas, DICT_TYPE} from '@/utils/dict'
export default {
name: "BpmOALeaveDetail",
components: {
},
props: {
id: {
type: [String, Number],
default: undefined
},
},
data() {
return {
carId: undefined, // 申请编号
// 表单参数
form: {
startTime: undefined,
endTime: undefined,
type: undefined,
reason: undefined,
},
typeDictData: getDictDatas(DICT_TYPE.BPM_OA_CAR_TYPE),
};
},
created() {
this.carId = this.id || this.$route.query.id;
if (!this.carId) {
this.$message.error('未传递 id 参数,无法查看 OA 信息');
return;
}
this.getDetail();
},
methods: {
/** 获得请假信息 */
getDetail() {
getOaApply(this.carId).then(response => {
this.formData = response.data;
});
},
}
};
</script>
3.配置路由
在 router/index.js 中定义 create.vue
和 detail.vue
的路由,配置如下:
{
path: '/bpm',
component: Layout,
hidden: true,
redirect: 'noredirect',
children: [{
path: 'oa/leave/create',
component: (resolve) => require(['@/views/bpm/oa/leave/create'], resolve),
name: 'BpmOALeaveCreate',
meta: {title: '发起 OA 请假', icon: 'form', activeMenu: '/bpm/oa/leave'}
}, {
path: 'oa/leave/detail',
component: (resolve) => require(['@/views/bpm/oa/leave/detail'], resolve),
name: 'BpmOALeaveDetail',
meta: {title: '查看 OA 请假', icon: 'view', activeMenu: '/bpm/oa/leave'}
},
{
path: 'oa/oaapply/create',
component: (resolve) => require(['@/views/bpm/oa/oaapply/create'], resolve),
name: 'BpmOAApplyCreate',
meta: {title: '发起 OA 申请', icon: 'form', activeMenu: '/bpm/oa/oaapply'}
}, {
path: 'oa/oaapply/detail',
component: (resolve) => require(['@/views/bpm/oa/oaapply/detail'], resolve),
name: 'BpmOAApplyDetail',
meta: {title: '查看 OA 申请', icon: 'view', activeMenu: '/bpm/oa/oaapply'}
}
]
},
4.修改权限
由于新增、查看OA申请,都在侧边的菜单栏当中,因此,审批人的角色中,应当配置对应的权限,如图所示
这样在审批的过程中就可以看到对应的表单信息了。
5.常见问题
1.如何区分这个流程是什么状态(处理中、同意、拒绝)?
首先,我们需要监听每个流程进展到哪一步了,因此这里实现流程引擎定义的BpmProcessInstanceResultEventListener监听器,在流程结束时,会回调通知最终的结果是否通过。
getProcessDefinitionKey()方法实际上就是返回业务key(在service对应的实现类中设置的)
而监听器捕捉到时间以后就会触发event方法,这个时候会更新业务表中的result字段,将对应的结果更新到业务表中。
2.枚举是如何获取,并赋值的呢?
流程状态的枚举类都是定义在BpmProcessInstanceResultEnum中,通过监听工作流中的处理结果,然后将其赋值到业务对象的result中。
3.审批流程每经过一个节点,处理完成后是如何触发短信通知的呢?
具体可以看对应的专栏芋道框架----(业务表单工作流)短信通知流程分析-CSDN博客
4.BpmOACarResultListener监听器是什么时候触发的呢?需要注意的点是什么?
首先,我们在创建监听器的时候记得要加注解@Component,否则不起作用,该监听器继承了BpmProcessInstanceResultEventListener,所以当流程示例的结果发生变更了就会触发该监听器。
6.如果不同的审批节点,需要看到业务表单中的不同模块,甚至想要补充业务表单,又该如何设计?
如果不同的审批节点,想看到不同的模块,我们可以根据角色来区分,例如,
这样,就只有有bpm:oa-car:name权限的角色才能够在detail页面中看到车辆名称,然后我们在将对应的权限赋给需要的角色即可。
想要补充表单,实际上就是在detail页面中将对应的内容写成可编辑即可,然后根据id去更新对应的业务表。
这里,根据我的业务,判断了一下是否是当前审批的人是否是申请人,如果是的话,在判断是哪一个节点,因为 如果是起始提交表单的时候,我们依旧是不露出这个input的。
tips:如果单从角色来控制显示业务表单还不够,因为有可能这个角色在多个节点都需要审批,但每一个节点所看到的内容又不一致,所以,我们根据角色以及当前节点两个条件来锁定,是否显示表单动态的那一部分。