Commit a5b8b9b67e9853e1ddf30e51b450029d19b4256b

Authored by YunaiV
1 parent fc6a7680

1. 修复已办任务的 API 接口的 NPE

2. 实现已办任务的 UI 界面
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/task/BpmTaskConvert.java
... ... @@ -6,6 +6,7 @@ import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task.TaskStep
6 6 import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
7 7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
8 8 import org.activiti.engine.history.HistoricActivityInstance;
  9 +import org.activiti.engine.history.HistoricProcessInstance;
9 10 import org.activiti.engine.history.HistoricTaskInstance;
10 11 import org.activiti.engine.impl.persistence.entity.SuspensionState;
11 12 import org.activiti.engine.runtime.ProcessInstance;
... ... @@ -64,10 +65,10 @@ public interface BpmTaskConvert {
64 65 }
65 66  
66 67 default List<BpmTaskDonePageItemRespVO> convertList2(List<HistoricTaskInstance> tasks,
67   - Map<String, ProcessInstance> processInstanceMap,
  68 + Map<String, HistoricProcessInstance> historicProcessInstanceMap,
68 69 Map<Long, SysUserDO> userMap) {
69 70 return CollectionUtils.convertList(tasks, task -> {
70   - ProcessInstance processInstance = processInstanceMap.get(task.getProcessInstanceId());
  71 + HistoricProcessInstance processInstance = historicProcessInstanceMap.get(task.getProcessInstanceId());
71 72 return convert(task, processInstance, userMap.get(Long.valueOf(processInstance.getStartUserId())));
72 73 });
73 74 }
... ... @@ -85,6 +86,6 @@ public interface BpmTaskConvert {
85 86 @Mapping(source = "processInstance.processDefinitionId", target = "processInstance.processDefinitionId"),
86 87 @Mapping(source = "user.nickname", target = "processInstance.startUserNickname")
87 88 })
88   - BpmTaskDonePageItemRespVO convert(HistoricTaskInstance task, ProcessInstance processInstance, SysUserDO user);
  89 + BpmTaskDonePageItemRespVO convert(HistoricTaskInstance task, HistoricProcessInstance processInstance, SysUserDO user);
89 90  
90 91 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmProcessInstanceService.java
... ... @@ -8,6 +8,7 @@ import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceDel
8 8 import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceResultEnum;
9 9 import cn.iocoder.yudao.framework.common.pojo.PageResult;
10 10 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  11 +import org.activiti.engine.history.HistoricProcessInstance;
11 12 import org.activiti.engine.runtime.ProcessInstance;
12 13  
13 14 import javax.validation.Valid;
... ... @@ -91,4 +92,30 @@ public interface BpmProcessInstanceService {
91 92 return CollectionUtils.convertMap(getProcessInstances(ids), ProcessInstance::getProcessInstanceId);
92 93 }
93 94  
  95 + /**
  96 + * 获得历史的流程实例
  97 + *
  98 + * @param id 流程实例的编号
  99 + * @return 历史的流程实例
  100 + */
  101 + HistoricProcessInstance getHistoricProcessInstance(String id);
  102 +
  103 + /**
  104 + * 获得历史的流程实例列表
  105 + *
  106 + * @param ids 流程实例的编号集合
  107 + * @return 历史的流程实例列表
  108 + */
  109 + List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids);
  110 +
  111 + /**
  112 + * 获得历史的流程实例 Map
  113 + *
  114 + * @param ids 流程实例的编号集合
  115 + * @return 历史的流程实例列表 Map
  116 + */
  117 + default Map<String, HistoricProcessInstance> getHistoricProcessInstanceMap(Set<String> ids) {
  118 + return CollectionUtils.convertMap(getHistoricProcessInstances(ids), HistoricProcessInstance::getId);
  119 + }
  120 +
94 121 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmProcessInstanceServiceImpl.java
... ... @@ -186,8 +186,14 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
186 186 * @param id 流程实例的编号
187 187 * @return 历史的流程实例
188 188 */
189   - private HistoricProcessInstance getHistoricProcessInstance(String id) {
  189 + @Override
  190 + public HistoricProcessInstance getHistoricProcessInstance(String id) {
190 191 return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult();
191 192 }
192 193  
  194 + @Override
  195 + public List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids) {
  196 + return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list();
  197 + }
  198 +
193 199 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmTaskServiceImpl.java
... ... @@ -144,13 +144,13 @@ public class BpmTaskServiceImpl implements BpmTaskService {
144 144 }
145 145  
146 146 // 获得 ProcessInstance Map
147   - Map<String, ProcessInstance> processInstanceMap = processInstanceService.getProcessInstanceMap(
  147 + Map<String, HistoricProcessInstance> historicProcessInstanceMap = processInstanceService.getHistoricProcessInstanceMap(
148 148 convertSet(tasks, HistoricTaskInstance::getProcessInstanceId));
149 149 // 获得 User Map
150 150 Map<Long, SysUserDO> userMap = userService.getUserMap(
151   - convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())));
  151 + convertSet(historicProcessInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())));
152 152 // 拼接结果
153   - return new PageResult<>(BpmTaskConvert.INSTANCE.convertList2(tasks, processInstanceMap, userMap),
  153 + return new PageResult<>(BpmTaskConvert.INSTANCE.convertList2(tasks, historicProcessInstanceMap, userMap),
154 154 taskQuery.count());
155 155 }
156 156  
... ...
yudao-admin-ui/src/api/bpm/task.js
... ... @@ -8,6 +8,14 @@ export function getTodoTaskPage(query) {
8 8 })
9 9 }
10 10  
  11 +export function getDoneTaskPage(query) {
  12 + return request({
  13 + url: '/bpm/task/done-page',
  14 + method: 'get',
  15 + params: query
  16 + })
  17 +}
  18 +
11 19 export function completeTask(data) {
12 20 return request({
13 21 url: '/bpm/task/complete',
... ...
yudao-admin-ui/src/views/bpm/task/done.vue 0 → 100644
  1 +<template>
  2 + <div class="app-container">
  3 +
  4 + <!-- 搜索工作栏 -->
  5 + <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
  6 + <el-form-item label="流程名" prop="name">
  7 + <el-input v-model="queryParams.name" placeholder="请输入流程名" clearable size="small" @keyup.enter.native="handleQuery"/>
  8 + </el-form-item>
  9 + <el-form-item label="创建时间">
  10 + <el-date-picker v-model="dateRangeCreateTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
  11 + type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
  12 + </el-form-item>
  13 + <el-form-item>
  14 + <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  15 + <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  16 + </el-form-item>
  17 + </el-form>
  18 +
  19 + <!-- 列表 -->
  20 + <el-table v-loading="loading" :data="list">
  21 + <el-table-column label="任务编号" align="center" prop="id" width="300" />
  22 + <el-table-column label="任务名称" align="center" prop="name" />
  23 + <el-table-column label="所属流程" align="center" prop="processInstance.name" />
  24 + <el-table-column label="流程发起人" align="center" prop="processInstance.startUserNickname" />
  25 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
  26 + <template slot-scope="scope">
  27 + <span>{{ parseTime(scope.row.createTime) }}</span>
  28 + </template>
  29 + </el-table-column>
  30 + <el-table-column label="审批时间" align="center" prop="endTime" width="180">
  31 + <template slot-scope="scope">
  32 + <span>{{ parseTime(scope.row.endTime) }}</span>
  33 + </template>
  34 + </el-table-column>
  35 + <!-- TODO 耗时 -->
  36 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  37 + <template slot-scope="scope">
  38 + <!-- TODO 权限、颜色 -->
  39 + <el-button size="mini" type="text" icon="el-icon-edit">详情</el-button>
  40 + </template>
  41 + </el-table-column>
  42 + </el-table>
  43 + <!-- 分页组件 -->
  44 + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  45 + @pagination="getList"/>
  46 +
  47 + </div>
  48 +</template>
  49 +
  50 +<script>
  51 +import {getDoneTaskPage} from '@/api/bpm/task'
  52 +
  53 +export default {
  54 + name: "Done",
  55 + components: {
  56 + },
  57 + data() {
  58 + return {
  59 + // 遮罩层
  60 + loading: true,
  61 + // 显示搜索条件
  62 + showSearch: true,
  63 + // 总条数
  64 + total: 0,
  65 + // 待办任务列表
  66 + list: [],
  67 + // 查询参数
  68 + dateRangeCreateTime: [],
  69 + queryParams: {
  70 + pageNo: 1,
  71 + pageSize: 10,
  72 + name: null,
  73 + },
  74 + };
  75 + },
  76 + created() {
  77 + this.getList();
  78 + },
  79 + methods: {
  80 + /** 查询列表 */
  81 + getList() {
  82 + this.loading = true;
  83 + // 处理查询参数
  84 + let params = {...this.queryParams};
  85 + this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
  86 + getDoneTaskPage(params).then(response => {
  87 + this.list = response.data.list;
  88 + this.total = response.data.total;
  89 + this.loading = false;
  90 + });
  91 + },
  92 + /** 搜索按钮操作 */
  93 + handleQuery() {
  94 + this.queryParams.pageNo = 1;
  95 + this.getList();
  96 + },
  97 + /** 重置按钮操作 */
  98 + resetQuery() {
  99 + this.dateRangeCreateTime = [];
  100 + this.resetForm("queryForm");
  101 + this.handleQuery();
  102 + },
  103 + }
  104 +};
  105 +</script>
... ...
yudao-admin-ui/src/views/bpm/task/todo.vue
... ... @@ -52,7 +52,7 @@
52 52 </template>
53 53  
54 54 <script>
55   -import {approveTask, completeTask, getTodoTaskPage, rejectTask} from '@/api/bpm/task'
  55 +import {approveTask, getTodoTaskPage, rejectTask} from '@/api/bpm/task'
56 56  
57 57 export default {
58 58 name: "Todo",
... ... @@ -93,27 +93,6 @@ export default {
93 93 this.loading = false;
94 94 });
95 95 },
96   - /** 取消按钮 */
97   - cancel() {
98   - this.open = false;
99   - this.reset();
100   - },
101   - /** 表单重置 */
102   - reset() {
103   - this.form = {
104   - id: undefined,
105   - processInstanceId: undefined,
106   - status: undefined,
107   - userId: undefined,
108   - startTime: undefined,
109   - endTime: undefined,
110   - leaveType: undefined,
111   - reason: undefined,
112   - applyTime: undefined,
113   - };
114   - this.resetForm("form");
115   - },
116   -
117 96 /** 搜索按钮操作 */
118 97 handleQuery() {
119 98 this.queryParams.pageNo = 1;
... ... @@ -122,7 +101,6 @@ export default {
122 101 /** 重置按钮操作 */
123 102 resetQuery() {
124 103 this.dateRangeCreateTime = [];
125   - this.dateRangeApplyTime = [];
126 104 this.resetForm("queryForm");
127 105 this.handleQuery();
128 106 },
... ...
yudao-framework/yudao-spring-boot-starter-activiti/src/main/java/cn/iocoder/yudao/framework/activiti/core/util/ActivitiUtils.java
... ... @@ -2,7 +2,10 @@ package cn.iocoder.yudao.framework.activiti.core.util;
2 2  
3 3 import cn.hutool.core.util.ReflectUtil;
4 4 import com.alibaba.ttl.TransmittableThreadLocal;
  5 +import org.activiti.engine.history.HistoricProcessInstance;
5 6 import org.activiti.engine.impl.identity.Authentication;
  7 +import org.activiti.engine.impl.persistence.entity.HistoricProcessInstanceEntityImpl;
  8 +import org.activiti.engine.impl.persistence.entity.HistoricScopeInstanceEntityImpl;
6 9  
7 10 /**
8 11 * Activiti 工具类
... ... @@ -15,6 +18,8 @@ public class ActivitiUtils {
15 18 setAuthenticationThreadLocal();
16 19 }
17 20  
  21 + // ========== Authentication 相关 ==========
  22 +
18 23 /**
19 24 * 反射修改 Authentication 的 authenticatedUserIdThreadLocal 静态变量,使用 TTL 线程变量
20 25 * 目的:保证 @Async 等异步执行时,变量丢失的问题
... ...