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 +6,7 @@ import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task.TaskStep
6 import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO; 6 import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
8 import org.activiti.engine.history.HistoricActivityInstance; 8 import org.activiti.engine.history.HistoricActivityInstance;
  9 +import org.activiti.engine.history.HistoricProcessInstance;
9 import org.activiti.engine.history.HistoricTaskInstance; 10 import org.activiti.engine.history.HistoricTaskInstance;
10 import org.activiti.engine.impl.persistence.entity.SuspensionState; 11 import org.activiti.engine.impl.persistence.entity.SuspensionState;
11 import org.activiti.engine.runtime.ProcessInstance; 12 import org.activiti.engine.runtime.ProcessInstance;
@@ -64,10 +65,10 @@ public interface BpmTaskConvert { @@ -64,10 +65,10 @@ public interface BpmTaskConvert {
64 } 65 }
65 66
66 default List<BpmTaskDonePageItemRespVO> convertList2(List<HistoricTaskInstance> tasks, 67 default List<BpmTaskDonePageItemRespVO> convertList2(List<HistoricTaskInstance> tasks,
67 - Map<String, ProcessInstance> processInstanceMap, 68 + Map<String, HistoricProcessInstance> historicProcessInstanceMap,
68 Map<Long, SysUserDO> userMap) { 69 Map<Long, SysUserDO> userMap) {
69 return CollectionUtils.convertList(tasks, task -> { 70 return CollectionUtils.convertList(tasks, task -> {
70 - ProcessInstance processInstance = processInstanceMap.get(task.getProcessInstanceId()); 71 + HistoricProcessInstance processInstance = historicProcessInstanceMap.get(task.getProcessInstanceId());
71 return convert(task, processInstance, userMap.get(Long.valueOf(processInstance.getStartUserId()))); 72 return convert(task, processInstance, userMap.get(Long.valueOf(processInstance.getStartUserId())));
72 }); 73 });
73 } 74 }
@@ -85,6 +86,6 @@ public interface BpmTaskConvert { @@ -85,6 +86,6 @@ public interface BpmTaskConvert {
85 @Mapping(source = "processInstance.processDefinitionId", target = "processInstance.processDefinitionId"), 86 @Mapping(source = "processInstance.processDefinitionId", target = "processInstance.processDefinitionId"),
86 @Mapping(source = "user.nickname", target = "processInstance.startUserNickname") 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,6 +8,7 @@ import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceDel
8 import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceResultEnum; 8 import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceResultEnum;
9 import cn.iocoder.yudao.framework.common.pojo.PageResult; 9 import cn.iocoder.yudao.framework.common.pojo.PageResult;
10 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 10 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  11 +import org.activiti.engine.history.HistoricProcessInstance;
11 import org.activiti.engine.runtime.ProcessInstance; 12 import org.activiti.engine.runtime.ProcessInstance;
12 13
13 import javax.validation.Valid; 14 import javax.validation.Valid;
@@ -91,4 +92,30 @@ public interface BpmProcessInstanceService { @@ -91,4 +92,30 @@ public interface BpmProcessInstanceService {
91 return CollectionUtils.convertMap(getProcessInstances(ids), ProcessInstance::getProcessInstanceId); 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,8 +186,14 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
186 * @param id 流程实例的编号 186 * @param id 流程实例的编号
187 * @return 历史的流程实例 187 * @return 历史的流程实例
188 */ 188 */
189 - private HistoricProcessInstance getHistoricProcessInstance(String id) { 189 + @Override
  190 + public HistoricProcessInstance getHistoricProcessInstance(String id) {
190 return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); 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,13 +144,13 @@ public class BpmTaskServiceImpl implements BpmTaskService {
144 } 144 }
145 145
146 // 获得 ProcessInstance Map 146 // 获得 ProcessInstance Map
147 - Map<String, ProcessInstance> processInstanceMap = processInstanceService.getProcessInstanceMap( 147 + Map<String, HistoricProcessInstance> historicProcessInstanceMap = processInstanceService.getHistoricProcessInstanceMap(
148 convertSet(tasks, HistoricTaskInstance::getProcessInstanceId)); 148 convertSet(tasks, HistoricTaskInstance::getProcessInstanceId));
149 // 获得 User Map 149 // 获得 User Map
150 Map<Long, SysUserDO> userMap = userService.getUserMap( 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 taskQuery.count()); 154 taskQuery.count());
155 } 155 }
156 156
yudao-admin-ui/src/api/bpm/task.js
@@ -8,6 +8,14 @@ export function getTodoTaskPage(query) { @@ -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 export function completeTask(data) { 19 export function completeTask(data) {
12 return request({ 20 return request({
13 url: '/bpm/task/complete', 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,7 +52,7 @@
52 </template> 52 </template>
53 53
54 <script> 54 <script>
55 -import {approveTask, completeTask, getTodoTaskPage, rejectTask} from '@/api/bpm/task' 55 +import {approveTask, getTodoTaskPage, rejectTask} from '@/api/bpm/task'
56 56
57 export default { 57 export default {
58 name: "Todo", 58 name: "Todo",
@@ -93,27 +93,6 @@ export default { @@ -93,27 +93,6 @@ export default {
93 this.loading = false; 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 handleQuery() { 97 handleQuery() {
119 this.queryParams.pageNo = 1; 98 this.queryParams.pageNo = 1;
@@ -122,7 +101,6 @@ export default { @@ -122,7 +101,6 @@ export default {
122 /** 重置按钮操作 */ 101 /** 重置按钮操作 */
123 resetQuery() { 102 resetQuery() {
124 this.dateRangeCreateTime = []; 103 this.dateRangeCreateTime = [];
125 - this.dateRangeApplyTime = [];  
126 this.resetForm("queryForm"); 104 this.resetForm("queryForm");
127 this.handleQuery(); 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,7 +2,10 @@ package cn.iocoder.yudao.framework.activiti.core.util;
2 2
3 import cn.hutool.core.util.ReflectUtil; 3 import cn.hutool.core.util.ReflectUtil;
4 import com.alibaba.ttl.TransmittableThreadLocal; 4 import com.alibaba.ttl.TransmittableThreadLocal;
  5 +import org.activiti.engine.history.HistoricProcessInstance;
5 import org.activiti.engine.impl.identity.Authentication; 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 * Activiti 工具类 11 * Activiti 工具类
@@ -15,6 +18,8 @@ public class ActivitiUtils { @@ -15,6 +18,8 @@ public class ActivitiUtils {
15 setAuthenticationThreadLocal(); 18 setAuthenticationThreadLocal();
16 } 19 }
17 20
  21 + // ========== Authentication 相关 ==========
  22 +
18 /** 23 /**
19 * 反射修改 Authentication 的 authenticatedUserIdThreadLocal 静态变量,使用 TTL 线程变量 24 * 反射修改 Authentication 的 authenticatedUserIdThreadLocal 静态变量,使用 TTL 线程变量
20 * 目的:保证 @Async 等异步执行时,变量丢失的问题 25 * 目的:保证 @Async 等异步执行时,变量丢失的问题