应用开发平台集成工作流系列之14——流程表单实现示例
背景
流程审批,通常对应一个业务表单。这个表单一般有两种实现模式,一是不同的环节对应不同表单,二是做一张大表单,分为不同的区域,从业务角度考虑,前者通常对应复杂业务处理;后面一种则更常见和更常用,更友好和实用一些。
Camunda只是工作流引擎,负责流程的流转。Camunda自身实际也附带了一个表单功能,但是,实在简陋到没法用的地步,感兴趣的可以去了解下,我保证你不会有在项目或系统中使用的想法。
基于上述原因,流程表单需要自行设计与实现。从技术角度而言,流程表单本质上依旧是一个业务实体,仍旧可以使用平台的低代码平台进行配置生成,只不过相比普通的表单多了一些工作流相关的属性和特色。
以常见的请假流程为例,我们通过平台的低代码配置功能,先实现请假申请单的基本功能。
业务流程模块
新增模块businessflow,用于存放集中存放具体的业务流程,如请假申请、设备申请、资产报废等
流程单据模型
实体模型之前预设了一个业务模型,将实体公共属性进行存放,包括标识、创建人、创建时间、修改人,修改时间、版本号、逻辑删除标识,所有实体都继承该模型。
借本次流程实现时机,进行了重构优化,提取出来一个只有标识id的标识模式,由业务模型继承。
对于流程相关的表单实体,如请假申请,同样有大量公共属性,因此设计了一个流程单据的公共实体模型来承载。
该模型继承自业务模型,从而拥有了业务模型的标识,创建人、创建时间、修改人,修改时间、版本号、逻辑删除标识属性,自身配置如下与流程表单相关的公共属性,如下:
请假申请实例
配置实体
使用平台的低代码配置功能,在业务流程模块businessflow下新建请假申请实体Leave,继承流程表单模型。
该实体继承关系如下:
生成库表
通过平台“生成库表”功能,平台自动处理实体模型继承关系,从当前模型递归找到最顶级,获取所有属性,转换成库表字段后生成库表,清单如下:
运行效果
使用平台的低代码配置功能,配置列表、新增、修改、查看视图,生成代码,编译,实现请假申请表单的基本的增删改查操作。
结合流程调整
前面说过,流程表单虽然本质上是实体,但会多一些跟工作流结合衍生出来的元素。
调整表单
调整UI实现,对表单进行分区域显示,兼顾用户体验和表单权限细粒度控制。
源码如下:
<template>
<div>
<basic-info :entity-data="entityData" />
<el-card>
<template #header>
<span>申请信息</span>
</template>
<el-form
ref="form"
:model="entityData"
:rules="rules"
label-width="80px"
label-position="right"
:disabled="permissionConfigData.applyArea == 'READONLY'"
>
<el-row>
<el-col :span="12">
<el-form-item label="开始时间" prop="startTime">
<el-date-picker
v-model="entityData.startTime"
:value-format="$dateFormatter.getDatetimeFormat('SECOND')"
:type="$dateFormatter.getDatetimeType('SECOND')"
align="right"
unlink-panels
class="form-item"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="结束时间" prop="endTime">
<el-date-picker
v-model="entityData.endTime"
:value-format="$dateFormatter.getDatetimeFormat('SECOND')"
:type="$dateFormatter.getDatetimeType('SECOND')"
align="right"
unlink-panels
class="form-item"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="总计天数" prop="total">
<el-input v-model="entityData.total" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="请假类型" prop="leaveType">
<dictionary-select v-model="entityData.leaveType" code="LeaveType" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="原因" prop="reason">
<el-input v-model="entityData.reason" type="textarea" :rows="3" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<el-card v-show="permissionConfigData.organizationApproval != 'INVISIBLE'">
<template #header>
<span>部门审批</span>
</template>
<el-form
ref="form"
:model="entityData"
:rules="rules"
label-width="80px"
label-position="right"
:disabled="permissionConfigData.organizationApproval == 'READONLY'"
>
<el-row>
<el-col :span="12">
<el-form-item label="审批人" prop="organizationApprovalName">
<el-input v-model="entityData.organizationApprovalName" :readonly="readonly" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="审批时间" prop="organizationApprovalTime">
<el-input v-model="entityData.organizationApprovalTime" :readonly="readonly" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="审批意见" prop="organizationApprovalAdvice">
<el-input
v-model="entityData.organizationApprovalAdvice"
:readonly="readonly"
type="textarea"
:rows="3"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<el-card v-show="permissionConfigData.hrApproval != 'INVISIBLE'">
<template #header>
<span>人事审批</span>
</template>
<el-form
ref="form"
:model="entityData"
:rules="rules"
label-width="80px"
label-position="right"
:disabled="permissionConfigData.hrApproval == 'READONLY'"
>
<el-row>
<el-col :span="12">
<el-form-item label="审批人" prop="hrApprovalName">
<el-input v-model="entityData.hrApprovalName" :readonly="readonly" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="审批时间" prop="hrApprovalTime">
<el-input v-model="entityData.hrApprovalTime" :readonly="readonly" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="审批意见" prop="hrApprovalAdvice">
<el-input
v-model="entityData.hrApprovalAdvice"
:readonly="readonly"
type="textarea"
:rows="3"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
</div>
</template>
<script>
import { flowMixin } from '@/mixin/flowMixin'
const MODULE_CODE = 'businessflow'
const ENTITY_TYPE = 'leave'
export default {
name: ENTITY_TYPE,
mixins: [flowMixin],
data() {
return {
entityType: ENTITY_TYPE,
moduleCode: MODULE_CODE,
// eslint-disable-next-line no-eval
api: eval('this.$api.' + MODULE_CODE + '.' + ENTITY_TYPE),
pageCode: MODULE_CODE + ':' + ENTITY_TYPE + ':',
entityData: {},
rules: {
startTime: [{ required: true, message: '【开始时间】不能为空', trigger: 'blur' }],
endTime: [{ required: true, message: '【结束时间】不能为空', trigger: 'blur' }],
total: [{ required: true, message: '【总计天数】不能为空', trigger: 'blur' }],
leaveType: [{ required: true, message: '【请假类型】不能为空', trigger: 'blur' }],
reason: [{ required: true, message: '【原因】不能为空', trigger: 'blur' }]
}
}
},
methods: {}
}
</script>
<style scoped></style>
封装基本信息组件
对于工作流单据而言,存在共性,如单据编号、发起人、发起时间、发起部门等信息,在这里封装了一个基本信息的组件,界面如下:
源码如下:
<template>
<el-card class="box-card">
<template #header>
<span>基本信息</span>
</template>
<el-form ref="form" :model="entityData" label-width="80px" label-position="right">
<el-row>
<el-col :span="12">
<el-form-item label="单据编号">{{ entityData.billNo }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="发起时间">{{
$dateFormatter.formatUTCTime(entityData.initiateTime)
}}</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="发起人">{{ entityData.initiateUserName }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系方式">{{ entityData.initiateUserPhone }}</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="发起部门">{{
entityData.initiateOrganizationFullName
}}</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
</template>
<script>
export default {
props: {
entityData: {
type: Object,
required: false,
default() {
return {}
}
}
},
data() {
return {}
}
}
</script>
<style scoped>
</style>
处理工作流相关工作
流程表单实体新增的时候,除了需要将自身数据持久化外,还需要进行工作流相关操作。
结合平台的运行机制,只需要覆写afterAdd方法即可,包括验证流程启动权限、设置流程启动处理人、设置流程变量、启动流程、更新流程表单的与工作流相关的属性(流程类型、流程实例标识、流程状态等)
@Override
protected void afterAdd(Leave entity) {
String userId=UserUtil.getId();
String code= entity.getClass().getSimpleName();
//验证流程启动权限
flowTemplateService.checkProcessStartPermission(code);
//设置流程启动处理人,缺失此句会导致act_hi_procinst表的START_USER_ID_字段,即流程启动人数据为空
identityService.setAuthenticatedUserId(userId);
// 首环节处理人默认为启动人
Map<String,Object> instanceParams=new HashMap<>(5);
instanceParams.put(WorkFlowConstant.INSTANCE_FIRST_STEP_HANDLER,userId);
//设置请假天数
instanceParams.put("total",entity.getTotal());
WorkflowTemplate workflowTemplate=flowTemplateService.getByCode(code);
//启动流程
ProcessInstance processInstance =runtimeService.startProcessInstanceById(workflowTemplate.getProcessDefinitionId(),entity.getBillNo(),instanceParams);
//更新流程相关字段
//流程类型
entity.setFlowTypeName(workflowTemplate.getName());
//流程实例标识
entity.setFlowInstanceId(processInstance.getProcessInstanceId());
//流程状态
entity.setFlowStatus(WorkflowInstanceStatusEnum.ACTIVE.name());
//发起时间
entity.setInitiateTime(LocalDateTime.now());
//保存
modify(entity);
}
开发平台资料
平台名称:一二三开发平台
简介: 企业级通用开发平台
设计资料:csdn专栏
开源地址:Gitee
开源协议:MIT
开源不易,欢迎收藏、点赞、评论。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!