- 宣傳官網(wǎng) http://xb.exrick.cn
- 在線Demo http://xboot.exrick.cn
- 開源版Github地址 https://github.com/Exrick/x-boot
- 開發(fā)文檔 https://www.kancloud.cn/exrick/xboot/1009234
- 獲取完整版 http://xpay.exrick.cn/pay?xboot
在這里插入圖片描述
集成Activiti 5.22胧砰,考慮到文檔資料較多未選用新版本(模型設(shè)計器改動較大)或Flowable
集成的工作流編輯器在后臺靜態(tài)資源中,記得在系統(tǒng)配置中設(shè)置訪問域名超升,開發(fā)時直接填后臺請求地址前綴 http://localhost:8888 即可
幾大常用接口
- RepositoryService:提供一系列管理流程部署和流程定義的API
- RuntimeService:在流程運行時對流程實例進(jìn)行管理與控制
- TaskService:對流程任務(wù)進(jìn)行管理干像,例如任務(wù)提醒、任務(wù)完成和創(chuàng)建任務(wù)等
- IdentityService:提供對流程角色數(shù)據(jù)進(jìn)行管理的API倦畅,這些角色數(shù)據(jù)包括用戶組遮糖、用戶及它們之間的關(guān)系
- HistoryService:對流程的歷史數(shù)據(jù)進(jìn)行操作,包括查詢叠赐、刪除這些歷史數(shù)據(jù)
25張表
1欲账、act_ge_ 通用數(shù)據(jù)表,ge是general的縮寫
2芭概、act_hi_ 歷史數(shù)據(jù)表赛不,hi是history的縮寫,對應(yīng)HistoryService接口
3罢洲、act_id_ 身份數(shù)據(jù)表踢故,id是identity的縮寫,對應(yīng)IdentityService接口
4惹苗、act_re_ 流程存儲表殿较,re是repository的縮寫,對應(yīng)RepositoryService接口桩蓉,存儲流程部署和流程定義等靜態(tài)數(shù)據(jù)
5淋纲、act_ru_ 運行時數(shù)據(jù)表,ru是runtime的縮寫院究,對應(yīng)RuntimeService接口和TaskService接口洽瞬,存儲流程實例和用戶任務(wù)等動態(tài)數(shù)
XBoot擴展基本開發(fā)指南
通用流程狀態(tài)表
t_act_bussiness
,其中table_id
字段存儲關(guān)聯(lián)的表單ID后臺僅需開發(fā)相應(yīng)表單增刪改接口业汰,存儲至單張表中片任,如
t_leave
,唯一需注意的地方為新增接口(添加新數(shù)據(jù)時)需關(guān)聯(lián)業(yè)務(wù)act_buniess
表蔬胯,向其添加流程和表ID等信息对供,參考LeaveController
前臺僅需開發(fā)相應(yīng)單個表單頁面(可以通過路由傳參實現(xiàn)相應(yīng)按鈕顯示),參考
leave.vue
(以菜單中配置的該路由名name跳轉(zhuǎn))氛濒,記得在src/router/router.js
中添加路由-
最后記得在系統(tǒng)中配置相應(yīng)流程信息
- 數(shù)據(jù)字典"業(yè)務(wù)表"中添加相應(yīng)業(yè)務(wù)表名产场,如"t_leave";"業(yè)務(wù)表單路由"中添加相應(yīng)前端表單組件路由名舞竿,如"leave"
- 流程管理中編輯填寫關(guān)聯(lián)剛開發(fā)的表單信息京景,業(yè)務(wù)表的作用主要為用戶刪除申請時關(guān)聯(lián)刪除相應(yīng)表單數(shù)據(jù),表單路由名作用為跳轉(zhuǎn)顯示剛前端開發(fā)的表單頁面
QQ截圖20190113212518.png 流程節(jié)點審批人可根據(jù)角色骗奖、部門負(fù)責(zé)人确徙、人員設(shè)置多個醒串,設(shè)置后默認(rèn)勾選,為或簽(任意一人審批鄙皇,流程進(jìn)入下一步芜赌,即先到先審)
-
如何實現(xiàn)會簽?
- 請增加審批節(jié)點伴逸!
image -
分支網(wǎng)關(guān)設(shè)定
- 注意:暫僅支持互斥(排他)網(wǎng)關(guān)設(shè)置缠沈。為保證工作流簡單性,建議僅使用開始错蝴、結(jié)束洲愤、任務(wù)節(jié)點和單向連線,設(shè)置分支后流程將變得不靈活顷锰,用戶容易編輯出錯柬赐。
若部署后流程圖中文字符無法顯示,是因為服務(wù)器環(huán)境jdk中無相應(yīng)中文字體官紫,百度安裝即可(配置文件已配置微軟雅黑肛宋,若未配置默認(rèn)宋體)
互斥(排他)網(wǎng)關(guān)設(shè)定
顧名思義,當(dāng)出現(xiàn)多個分支時僅選擇一個滿足條件的分支流轉(zhuǎn)
-
點擊互斥網(wǎng)關(guān)后的連線設(shè)置流轉(zhuǎn)條件的條件UEL表達(dá)式 https://www.activiti.org/userguide/#apiExpressions
WX20190523-221523@2x.png -
注意勾選默認(rèn)網(wǎng)關(guān)后不得設(shè)置流轉(zhuǎn)條件万矾,否則無法部署成功
WX20190523-221700@2x.png 啟動流程時或完成一個任務(wù)節(jié)點時務(wù)必加入該變量(否則配置了流轉(zhuǎn)條件變量的流程會報錯)悼吱,示例:
// 啟動流程時添加變量,詳見ActBusinessController的apply或start方法良狈,在ActBusiness中設(shè)置params
actBusiness.getParams().put("duration", 36);
// 或者完成任務(wù)節(jié)點時加入變量
Map<String, Object> params = new HashMap<>(16);
taskService.complete(id, params);
綁定監(jiān)聽器示例
常見的業(yè)務(wù)需求需要完成一個審批流程后改變原數(shù)據(jù)狀態(tài)后添、通知審批結(jié)果消息或執(zhí)行其他操作,在結(jié)束節(jié)點上綁定監(jiān)聽器即可薪丁,一旦結(jié)束說明流程全部通過遇西,觸發(fā)自定義業(yè)務(wù)。
- 繪制流程圖填寫定義的監(jiān)聽器類
- 監(jiān)聽器示例代碼
@Slf4j
public class MyListener implements ExecutionListener {
@Override
public void notify(DelegateExecution delegateExecution) throws Exception {
// 獲取關(guān)聯(lián)業(yè)務(wù)表ID變量(啟動流程代碼里已存入tableId严嗜,此處直接獲取即可)
String tableId = (String) delegateExecution.getVariable("tableId");
log.info(tableId);
LeaveService leaveService = SpringContextUtil.getBean(LeaveService.class);
Leave leave = leaveService.get(tableId);
... ...
}
}
使用發(fā)起流程組件示例
- 前端vue示例粱檀,注意各狀態(tài)下僅能顯示的各操作按鈕
<template>
<process-start
ref="processStart"
@on-submit="submitedProcess"
@on-loading="processLoading=true"
@on-loaded="processLoading=false"
/>
<process-cancel ref="processCancel" @on-submit="submitedProcess"/>
</template>
<script>
...
import processStart from '../../../views/my-components/xboot/process-start'
import processCancel from '../../../views/my-components/xboot/process-cancel'
export default {
name: 'demo',
components: {
processStart,
processCancel
},
data () {
return {
...
columns: [
// 表頭
{
title: '申請狀態(tài)',
key: 'status',
sortable: true,
minWidth: 110,
fixed: 'right',
render: (h, params) => {
let text = '未知',
color = ''
if (params.row.status === 0) {
text = '草稿'
color = 'default'
} else if (params.row.status === 1) {
text = '處理中'
color = 'orange'
} else if (params.row.status === 2) {
text = '已結(jié)束'
color = 'blue'
}
return h('div', [
h(
'Tag',
{
props: {
color: color,
},
},
text,
),
])
},
},
{
title: '申請結(jié)果',
key: 'result',
sortable: true,
minWidth: 110,
fixed: 'right',
render: (h, params) => {
let text = '未知',
color = ''
if (params.row.result == 0) {
text = '未提交'
color = 'default'
} else if (params.row.result == 1) {
text = '處理中'
color = 'orange'
} else if (params.row.result == 2) {
text = '已通過'
color = 'green'
} else if (params.row.result == 3) {
text = '已駁回'
color = 'red'
}
return h('div', [
h(
'Tag',
{
props: {
color: color,
},
},
text,
),
])
},
},
{
title: '操作',
key: 'action',
align: 'center',
fixed: 'right',
width: 260,
render: (h, params) => {
let result = params.row.result
if (result == 0) {
return h('div', [
h(
'Button',
{
props: {
type: 'primary',
size: 'small',
},
style: {
marginRight: '5px',
},
on: {
click: () => {
this.showProcess(params.row)
},
},
},
'發(fā)起申請',
),
h(
'Button',
{
props: {
size: 'small',
icon: 'ios-create-outline',
},
style: {
marginRight: '5px',
},
on: {
click: () => {
this.edit(params.row)
},
},
},
'編輯',
),
h(
'Button',
{
props: {
type: 'error',
size: 'small',
icon: 'md-trash',
},
on: {
click: () => {
this.remove(params.row)
},
},
},
'刪除',
),
])
}
if (result == 1) {
return h('div', [
h(
'Button',
{
props: {
size: 'small',
type: 'warning',
},
style: {
marginRight: '5px',
},
on: {
click: () => {
this.cancelProcess(params.row)
},
},
},
'撤回申請',
),
h(
'Button',
{
props: {
size: 'small',
},
style: {
marginRight: '5px',
},
on: {
click: () => {
this.history(params.row)
},
},
},
'審批歷史',
),
])
}
if (result == 2) {
h(
'Button',
{
props: {
size: 'small',
},
style: {
marginRight: '5px',
},
on: {
click: () => {
this.history(params.row)
},
},
},
'審批歷史',
),
])
}
if (result === 3) {
return h('div', [
h(
'Button',
{
props: {
type: 'primary',
size: 'small',
},
style: {
marginRight: '5px',
},
on: {
click: () => {
this.showProcess(params.row)
},
},
},
'重新申請',
),
h(
'Button',
{
props: {
size: 'small',
icon: 'ios-create-outline',
},
style: {
marginRight: '5px',
},
on: {
click: () => {
this.edit(params.row)
},
},
},
'編輯',
),
])
}
},
},
]
}
},
methods: {
...
showProcess (v) {
// 顯示通過key發(fā)起流程組件
this.$refs.processStart.show('demand', v.actBusinessId)
},
cancelProcess (v) {
// 取消流程
this.$refs.processCancel.show(v.actBusinessId, v.procInstId)
},
submitedProcess () {
// 進(jìn)行流程操作后刷新表單數(shù)據(jù)顯示流程狀態(tài)
this.getDataList()
},
history (v) {
// 審批歷史
if (!v.procInstId) {
this.$Message.error('流程實例ID不存在')
return
}
let query = { id: v.procInstId, backRoute: this.$route.name }
this.$router.push({
name: 'historic_detail',
query: query,
})
}}
}
}
- 后端業(yè)務(wù)接口,注意與“工作流程-我的申請”中已有請假示例LeaveController示例中的區(qū)別漫玄,這里無需傳入流程定義ID茄蚯,ActBussines表與業(yè)務(wù)表兩兩關(guān)聯(lián)記錄對方ID方便查詢
@RequestMapping(value = "/add",method = RequestMethod.POST)
@ApiOperation(value = "添加審批需求")
public Result<Object> add(@ModelAttribute Demand demand){
Demand d = demandService.save(demand);
// 保存至我的申請業(yè)務(wù)
String userId = securityUtil.getCurrUser().getId();
ActBusiness actBusiness = new ActBusiness();
actBusiness.setUserId(userId);
// 記錄關(guān)聯(lián)業(yè)務(wù)表ID
actBusiness.setTableId(d.getId());
ActBusiness a = actBusinessService.save(actBusiness);
// 記錄關(guān)聯(lián)流程狀態(tài)表ID
d.setActBusinessId(a.getId());
demandService.update(d);
return new ResultUtil<Object>().setSuccessMsg("操作成功");
}
- 效果預(yù)覽