# 开发审批应用
接下来以开发【合同管理】为例,介绍整个过程。
# 创建实体
创建合同实体(Contract),包含以下的字段:

查看代码 (Contract.json)
{
"name": "Contract",
"packageName": "",
"title": "合同",
"tableName": "contract",
"fields": {
"id": {
"name": "id",
"packageName": "",
"title": "唯一ID",
"primaryKey": true,
"autoIncrement": false,
"type": "VARCHAR",
"length": 36,
"nullable": false,
"columnName": "id",
"insertable": true,
"updatable": true,
"order": 1
},
"name": {
"name": "name",
"packageName": "",
"title": "合同名称",
"autoIncrement": false,
"type": "VARCHAR",
"length": 150,
"nullable": true,
"columnName": "name",
"insertable": true,
"updatable": true,
"sortable": true,
"filterable": true,
"searchable": true,
"order": 2
},
"code": {
"name": "code",
"packageName": "",
"title": "合同编码",
"autoIncrement": false,
"type": "VARCHAR",
"length": 50,
"nullable": true,
"columnName": "code",
"insertable": true,
"updatable": true,
"sortable": true,
"filterable": true,
"searchable": true,
"order": 3
},
"salesId": {
"name": "salesId",
"packageName": "",
"title": "销售经理 ID",
"autoIncrement": false,
"type": "VARCHAR",
"length": 36,
"nullable": true,
"columnName": "sales_id",
"insertable": true,
"updatable": true,
"sortable": true,
"filterable": true,
"order": 4
},
"deptId": {
"name": "deptId",
"packageName": "",
"title": "所属部门 ID",
"autoIncrement": false,
"type": "VARCHAR",
"length": 36,
"nullable": true,
"columnName": "dept_id",
"sortable": true,
"filterable": true,
"order": 5
},
"description": {
"name": "description",
"packageName": "",
"title": "合同描述",
"autoIncrement": false,
"type": "VARCHAR",
"length": 2000,
"nullable": true,
"columnName": "description",
"sortable": true,
"filterable": true,
"order": 6
},
"signDate": {
"name": "signDate",
"packageName": "",
"title": "签约日期",
"autoIncrement": false,
"type": "TIMESTAMP",
"length": 19,
"nullable": true,
"columnName": "sign_date",
"sortable": true,
"filterable": true,
"order": 7
},
"status": {
"name": "status",
"packageName": "",
"title": "合同状态",
"autoIncrement": false,
"type": "VARCHAR",
"length": 15,
"nullable": true,
"columnName": "status",
"sortable": true,
"filterable": true,
"order": 8
},
"tenantId": {
"name": "tenantId",
"packageName": "",
"title": "租户号",
"autoIncrement": false,
"type": "VARCHAR",
"length": 60,
"nullable": true,
"columnName": "tenant_id",
"sortable": true,
"filterable": true,
"defaultValue": "#vars.tenant_id",
"order": 9
},
"isDeleted": {
"name": "isDeleted",
"packageName": "",
"title": "是否删除",
"autoIncrement": false,
"type": "BIT",
"length": 1,
"nullable": true,
"columnName": "is_deleted",
"sortable": true,
"filterable": true,
"columnDefault": "0",
"order": 10
},
"createdBy": {
"name": "createdBy",
"packageName": "",
"title": "创建人",
"autoIncrement": false,
"type": "VARCHAR",
"length": 36,
"nullable": true,
"columnName": "created_by",
"sortable": true,
"filterable": true,
"defaultValue": "#vars.user.id",
"order": 11
},
"createdByName": {
"name": "createdByName",
"packageName": "",
"title": "创建人姓名",
"autoIncrement": false,
"type": "VARCHAR",
"length": 150,
"nullable": true,
"columnName": "created_by_name",
"sortable": true,
"filterable": true,
"defaultValue": "#vars.user.name",
"order": 12
},
"createdAt": {
"name": "createdAt",
"packageName": "",
"title": "创建时间",
"autoIncrement": false,
"type": "TIMESTAMP",
"length": 19,
"nullable": false,
"columnName": "created_at",
"sortable": true,
"filterable": true,
"columnDefault": "now(3)",
"defaultValue": "#vars.now",
"order": 13
},
"updatedBy": {
"name": "updatedBy",
"packageName": "",
"title": "更新人",
"autoIncrement": false,
"type": "VARCHAR",
"length": 36,
"nullable": true,
"columnName": "updated_by",
"sortable": true,
"filterable": true,
"defaultValue": "#vars.user.id",
"updateValue": "#vars.user.id",
"order": 14
},
"updatedByName": {
"name": "updatedByName",
"packageName": "",
"title": "更新人姓名",
"autoIncrement": false,
"type": "VARCHAR",
"length": 150,
"nullable": true,
"columnName": "updated_by_name",
"sortable": true,
"filterable": true,
"defaultValue": "#vars.user.name",
"updateValue": "#vars.user.name",
"order": 15
},
"updatedAt": {
"name": "updatedAt",
"packageName": "",
"title": "更新时间",
"autoIncrement": false,
"type": "TIMESTAMP",
"length": 19,
"nullable": false,
"columnName": "updated_at",
"sortable": true,
"filterable": true,
"columnDefault": "now(3)",
"defaultValue": "#vars.now",
"updateValue": "#vars.now",
"order": 16
}
},
"relations": {},
"indexes": {},
"onEvents": {}
}
# 生成接口
实体生成后,需要创建实体的CRUD接口。

# 开发页面
开发合同管理功能,主要包括,合同列表、新增合同和修改合同。 可以在此下载:合同管理页面 (opens new window) 放到 app/modules 目录下。
除此之外,里面的【流程表单】,该页面是需要在流程设计器中进行绑定,将会在【我的申请】【我的审批】中查看【审批信息】的时候呈现。
⚠️注意:在流程表单页面的外层使用流程表单容器组件,可以在审批页面自动生成操作按钮。


流程表单页面可以获得如下参数:
- businessKey:业务数据ID(编排发起流程时传入的数据)
- processInstanceId:流程实例ID
页面获取参数的方式为:request.params.businessKey 、request.params.processInstanceId
# 设计流程
下面演示如何创建一个合同审批流程,包含三个步骤:拟稿、部门经理审批、财务审批。
# 1.全局配置
创建完一个新的流程后,在设计界面的右侧栏,可以修改流程名称和流程Key。

⚠️注意:当前版本需要保证流程Key的全局唯一性,不能与其他应用的流程Key重复,后续版本会增加应用租户支持。
# 2.流程表单
表单主要用于填报数据,并且带有数据的协作功能,如修改,删除,导入,导出。也就是说没有设置特定的表单权限的情况下,申请人和每一个环节的审批人都有权限对表单的字段进行修改操作。表单可以给不同的人不同的管理权限。
- 流程级表单:流程中每个环节审批时都默认使用这个表单,也就是说流程级的表单贯穿整个流程的流转,如上图所示,点击空白区域,就可以在全局页面中设置流程级表单
- 环节级表单:没配置表单的环节,默认使用流程级表单,环节配置了表单,在这个环节审批时,使用这个特定的表单
# 3.用户任务
用户任务是流程中需要用户来操作的任务。在这个任务中需要设置审批人,也称为候选人,用户任务只有通过审批人处理了才能进行流程的流转。本例中的部门经理审批、财务审批就是用户任务。
# 4.设置审批人
这里支持多种类型的人员,用户、部门、角色等。
如果涉及到审批人是根据业务动态计算的,请参考流程动态参与者。
# 5.服务任务
服务任务用于在流程运行中自动执行一些业务逻辑,无需人工参与,常见场景包括调用外部接口、写回业务数据、发送通知等,以上业务功能在本平台中通过编排函数来实现。服务任务环节调用编排函数处理完成后返回结果,流程继续流转。
# 用法实践
此处用例子帮助大家了解服务任务的用法。场景如下:流程定义中增加一个服务任务环节,触发函数编排,在函数编排里调用远程接口获取SSO的版本信息,将结果写到流程变量,流程继续往下流转,在排他网关环节根据SSO的版本信息来决定流程的分支流向。
- 创建编排:创建一个给服务任务调用的编排函数,调用远程接口:https://dfuse.bingosoft.net/workflow/api/web.json,从里面拿到SSO运行版本(auth2.serverVersion)。此处需要特别注意,编排的返回结果要放入流程变量,长度有限制,可以通过下图所示的方式,用输出结果过滤器只返回需要用于后续业务逻辑的内容。

- 环节配置:选择刚刚创建的编排用于服务环节的触发动作,通过设置结果变量名,写回到流程变量,用于后续环节使用。

- 结果使用:通过服务任务环节返回的结果进行条件判断,控制网关的分支流向。

# 发起流程
设想一个场景,在填写完合同申请表单后,需要发起一个【合同申请流程】的动作,这个动作的发起有两种做法,一是直接调用API接口发起流程、二是通过实体事件发起流程。推荐使用第二种做法。
# 基于实体事件发起流程
# 1.创建编排函数
在低代码的编排模块中提供了发起流程的组件,通过创建一个发起流程的编排函数,就可以便捷的实现流程的发起动作。

- 通过实体事件的方式调用编排函数,会将实体数据通过上下文参数的方式传入进来,参数key为
entity - 流程定义Key 选择前文设计的流程
- 绑定流程实体信息,上图例子中把流程名称设置为实体的name字段
${.entity.name},业务数据id设置的是实体的id字段${.entity.id}
# 2.添加实体监听事件
配置实体的【创建后执行】的事件,执行的方式是调用上文创建的编排函数。

至此,【合同管理】就可以实现合同申请过程的流转了。更多的开发指引,将会在后续的章节中呈现。
# 流程自动发布配置
通过配置以下参数,可以启用流程应用的自动发布功能,初次部署或后续更新,都无需在IDE的流程设计页面手动发布流程定义。
services:
workflow:
startupAutoPublish: true