Activiti工作流管理系统(四)

前言

在上一章内容中,介绍了工作流的启动和执行,只要掌握了这两个驱动工作流引擎的方法,那么对于工作流就等于掌握了60%,因此上章内容的对于工作流的启动和执行的基本用法十分重要!
在这一章内容中,主要介绍:
1.正在运行中实例和历史流程查看
2.工作流实例的挂起与激活
以上这两类功能,在本质上分别两两相对应,即分别成对存在,难舍难分。因此在本章进行介绍。废话不多说,下面就让我们进入正题吧~

系列四内容

1.正在运行中实例和历史流程查看
2.工作流实例的挂起与激活

主界面总览

超链接.png

说明:为了简单方便,进入正在运行实例和历史实例,我只用了最简单的超链接。若各位觉得过菜,请使用vue的路由跳转等其他方式实现,在此不再赘述。

功能详细说明

说明

首先,先说说第一对兄弟,在实际项目运用中,很少会将这两块内容放入到实际开发项目的前台页面中,大多都是通过查询数据库的方式对某个实例(正在运行:act_ru_task或历史:act_hi_taskinst)进行追踪,但是本系统为了想要对全部实例有一个整体的把控,决定把这一对幕后英雄请上前台。各位可根据项目实际需要进行查阅。

注:获取列表的查询参数为defId(processDefineKey),即流程定义KEY。方案不止此一种,各位看官可以根据实际项目需求进行斟酌选用

页面

正在运行实例.png

查看历史明细.png
历史实例.png

正在运行实例

前端代码

ActiveProcess.vue

展示正在运行实例列表(含查看历史功能)

<template>
  <div class="div-class">
    <Card style="height: 750px">
      <p slot="title">
        <Icon type="ios-film-outline"></Icon>
        活动实例列表({{this.$route.params.defId}})
      </p>
      <Button type="primary" class="btn-class" @click="returnPage">返回</Button>
      <ul>
          <Table height="550" border ref="selection" :columns="columns12" :data="data6" style="margin-top: 50px">
            <template slot-scope="{ row, index }" slot="action">
              <div class="slot_class">
                <Button type="success" size="small" v-show="row.suspended==false" @click="suspendTask(row)">挂起</Button>
                <Button type="error" size="small" v-show="row.suspended==true" @click="activateTask(row)">激活</Button>
                <Button type="info" size="small" @click="showHistory(row)">查看历史</Button>
              </div>
            </template>
          </Table>
      </ul>
    </Card>
    <Modal width="850px" :closable="false" :mask-closable="false" v-model="historyDetailModal">
      <Card>
        <HistoryDetail ref="historyDetail"></HistoryDetail>
      </Card>
      <div slot="footer" style="text-align: center">
        <Button type="primary" @click="historyDetailModal=false">确定</Button>
      </div>
    </Modal>
  </div>
</template>
<script>
 import {
    getHistoryActivitiIds, getTaskListByDefId
  } from '../../api/activityManagement'
export default {
    name: 'ActiveProcess',
    data () {
      return {
        flowId:'',
        processInstanceId:'',
        historyDetailModal:false,
        columns12: [
          {
            type: 'selection',
            width: 60,
            align: 'center'
          },
          { title: '序号', align:'center', type: 'index', key:'index', width:'80px'},
          { title: '工作项', align:'center', key:'id', width:'80px'},
          { title: '任务名称', align:'center', key: 'name', width:'140px'},
          { title: '任务KEY', align:'center', key: 'taskDefinitionKey', width:'140px'},
          { title: '处理人', align:'center', key: 'assignee', width:'100px'},
          { title: '创建时间', align:'center', key: 'createTime',
            render: (h, params) => {
              // 这里要求h中的第一个参数是注册成功的组件
              if(params.row.createTime !== null){
                return h('div',getDate(new Date(params.row.createTime),'day')
                )
              }
            }
          },
          { title: '流程实例ID', align:'center', key: 'processInstanceId', width:'120px'},
          { title: '部署定义ID', align:'center', key: 'processDefinitionId'},
          {
            title: '操作项',
            slot: 'action',
            width: 350,
            align: 'center'
          }

        ],
        data6: []
      }
    },
    mounted(){
      this.getTableData() ;
    },
    methods: {
        openCallBack(row){
        const processInstanceId = row.processInstanceId ;
        getHistoryActivitiIds({
          processInstanceId: processInstanceId
        }).then(res => {
          if(res.data.responseCode === 1){
            const list = res.data.responseData.list ;
            this.selectData =  list;
            this.workFlowCallBackModal = true ;
            //②这里赋值回退的流程实例ID
            this.processInstanceId = processInstanceId ;
          }
        })
      },
      showHistory(row){
        this.$refs.historyDetail.detailData = row.historyList ;
        this.historyDetailModal = true
      },
        getTableData(){
        const defId = this.$route.params.defId ;
        getTaskListByDefId({
          defId:defId
        }).then(res =>{
          if(res.data.responseCode === 1){
            this.data6 = res.data.responseData.list
          }
        })
      },
      returnPage(){
        //返回这个路由对应的组件
        this.$router.push('/homePage');
      }
    }
}
</script>

activityManagement.js

/**defId(processDefineId)获取task**/
export const getTaskListByDefId = params => {
 return axios.request({
   url: 'workflow/getTaskListByDefId',
   params: params,
   method: 'post'
 })
}
/**根据defId(processDefineId)获取历史实例列表**/
export const getHistoryListByDefId = params => {
 return axios.request({
   url: 'workflow/getHistoryListByDefId',
   params: params,
   method: 'post'
 })
}

后端代码

WorkflowController

展示正在运行实例列表

@RequestMapping("/getTaskListByDefId")
    public JsonResult getTaskListByDefId(String defId){
        JsonResult jr = new JsonResult() ;
        resultMap = new HashMap<String,Object>() ;
        List<ActivitiTaskVO> voList = new ArrayList<ActivitiTaskVO>();
        try {
            //获取正在运行实例的列表
            List<Task> list = taskService.createTaskQuery().processDefinitionId(defId).orderByProcessInstanceId().asc().list();
            if(list != null){
                for(Task task : list){
                    //遍历查询出来的所有实例
                    ActivitiTaskVO vo = new ActivitiTaskVO() ;
                    //使用API将实例对象copy为自己的非持久化类方便展示和后续拓展
                    BeanUtils.copyProperties(task, vo);
                    String processInstanceId = vo.getProcessInstanceId() ;
                    List<HistoricTaskInstance> historicTaskInstanceList = historyService
                   .createHistoricTaskInstanceQuery().processInstanceId(processInstanceId)
                    .orderByExecutionId().asc().list();
                    //如果有历史记录(原则上必须有),则将其转化为自定义VO,然后赋值给历史记录的HistoryList属性,放到前台进行展示
                    if(historicTaskInstanceList != null && historicTaskInstanceList.size()>0){
                        List<HistoryDetailVO> historyDetailVOS = new ArrayList<HistoryDetailVO>() ;
                        for(HistoricTaskInstance historicTaskInstance:historicTaskInstanceList){
                            //使用同样的方式获取该实例的所有历史环节进行前台展示
                            HistoryDetailVO historyDetailVO = new HistoryDetailVO() ;
                            BeanUtils.copyProperties(historicTaskInstance, historyDetailVO);
                            historyDetailVOS.add(historyDetailVO) ;
                        }
                        vo.setHistoryList(historyDetailVOS);
                    }
                    voList.add(vo) ;
                }
            }
            resultMap.put("list",voList) ;
            jr.setResponseData(resultMap);
            jr.setResponseCode(1);
            jr.setResponseMessage(ResultEnum.SUCCESS);
        }catch (Exception e){
            e.printStackTrace();
            jr.setResponseCode(0);
            jr.setResponseMessage(ResultEnum.EXCEPTION);
        }
        return jr ;
    }

历史实例

说明

由于历史实例和正在运行实例两个功能的前端页面和后端处理思路完全相同,仅在后台获取历史实例列表的API选择上与正在运行实例功能不同,因此为节约篇幅,仅把后台不同代码段进行展示。

后台代码

WorkflowController

/**
     * 根据defId(processDefineKey)查询历史记录
     * @param defId
     * @return
     */
    @RequestMapping("/getHistoryListByDefId")
    public JsonResult getHistoryListByDefId(String defId){
        JsonResult jr = new JsonResult() ;
        resultMap = new HashMap<String,Object>() ;
        List<HistoryListVO> voList = new ArrayList<HistoryListVO>();
        try {
            //此list直接转到前台接收即可,getTaskListByFlowKey同
            List<HistoricProcessInstance> list = historyService
                    .createHistoricProcessInstanceQuery()
                    .processDefinitionId(defId).finished().list() ;

            if(list != null){
                for(HistoricProcessInstance historicProcessInstance : list){
                    HistoryListVO vo = new HistoryListVO() ;
                    BeanUtils.copyProperties(historicProcessInstance, vo);
                    //获取所有的历史活动
                    String processInstanceId = vo.getProcessInstanceId() ;
                    List<HistoricTaskInstance> historicTaskInstanceList = historyService
                    .createHistoricTaskInstanceQuery()
                    .processInstanceId(processInstanceId).orderByExecutionId().asc()
                    .list();
                    //如果有历史记录(原则上必须有),则将其转化为自定义VO,然后赋值给历史记录的HistoryList属性,放到前台进行展示
                    if(historicTaskInstanceList != null && historicTaskInstanceList.size()>0){
                        List<HistoryDetailVO> historyDetailVOS = new ArrayList<HistoryDetailVO>() ;
                        for(HistoricTaskInstance historicTaskInstance:historicTaskInstanceList){
                            HistoryDetailVO historyDetailVO = new HistoryDetailVO() ;
                            BeanUtils.copyProperties(historicTaskInstance, historyDetailVO);
                            historyDetailVOS.add(historyDetailVO) ;
                        }
                        vo.setHistoryList(historyDetailVOS);
                    }
                    voList.add(vo) ;
                }
            }
            resultMap.put("list",voList) ;
            jr.setResponseData(resultMap);
            jr.setResponseCode(1);
            jr.setResponseMessage(ResultEnum.SUCCESS);
        }catch (Exception e){
            e.printStackTrace();
            jr.setResponseCode(0);
            jr.setResponseMessage(ResultEnum.EXCEPTION);
        }
        return jr ;
    }

流程实例的挂起与激活

说明

顾名思义,流程实例的挂起与激活标志着该实例的一种当前状态,若实例被挂起,则代表该实例不能被用户所执行,被称为挂起态,反之则允许用户执行该实例,为激活态。
本功能点在代码上实现十分简单,仅需调用官方API即可实现(参数为流程实例ID:processInstanceId)

页面

激活态显示.png

挂起态显示.png

后台代码

WorkflowController

//挂起流程
runtimeService.suspendProcessInstanceById(processInstanceId);
//激活流程
runtimeService.activateProcessInstanceById(processInstanceId);

补充说明

  • 流程实例的状态表示字段在act_ru_task表的SUSPENSION_STATE_字段,
    其中 1为激活状态;2为挂起状态,如下图所示:


    act_ru_task.png
  • 当流程实例被挂起时,若执行该实例,后台则会抛出ActivitiException异常(Cannot complete a suspended task),如下图所示:


    异常.png

总结

至此,有关于运行实例和历史实例的展示功能和流程的激活挂起功能开发完成。其中对于运行实例和历史实例列表查询的方式并不唯一,本文使用的查询参数为processDefineKey,还可用部署ID,流程实例ID等参数进行查询实现,各位可以根据实际项目需求进行取舍。

好了,以上就是本文的全部内容,各位若对代码有任何不同的意见或建议欢迎下方留言,大家共同进步!

下篇预告

流程图的查看

敬请期待~~~
第四篇完结~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容