mirror of
				https://github.com/YunaiV/ruoyi-vue-pro.git
				synced 2025-11-01 03:28:41 +08:00 
			
		
		
		
	1. 修复已办任务的 API 接口的 NPE
2. 实现已办任务的 UI 界面
This commit is contained in:
		| @ -6,6 +6,7 @@ import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task.TaskStep | |||||||
| import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO; | import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO; | ||||||
| import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||||||
| import org.activiti.engine.history.HistoricActivityInstance; | import org.activiti.engine.history.HistoricActivityInstance; | ||||||
|  | import org.activiti.engine.history.HistoricProcessInstance; | ||||||
| import org.activiti.engine.history.HistoricTaskInstance; | import org.activiti.engine.history.HistoricTaskInstance; | ||||||
| import org.activiti.engine.impl.persistence.entity.SuspensionState; | import org.activiti.engine.impl.persistence.entity.SuspensionState; | ||||||
| import org.activiti.engine.runtime.ProcessInstance; | import org.activiti.engine.runtime.ProcessInstance; | ||||||
| @ -64,10 +65,10 @@ public interface BpmTaskConvert { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     default List<BpmTaskDonePageItemRespVO> convertList2(List<HistoricTaskInstance> tasks, |     default List<BpmTaskDonePageItemRespVO> convertList2(List<HistoricTaskInstance> tasks, | ||||||
|                                                          Map<String, ProcessInstance> processInstanceMap, |                                                          Map<String, HistoricProcessInstance> historicProcessInstanceMap, | ||||||
|                                                          Map<Long, SysUserDO> userMap) { |                                                          Map<Long, SysUserDO> userMap) { | ||||||
|         return CollectionUtils.convertList(tasks, task -> { |         return CollectionUtils.convertList(tasks, task -> { | ||||||
|             ProcessInstance processInstance = processInstanceMap.get(task.getProcessInstanceId()); |             HistoricProcessInstance processInstance = historicProcessInstanceMap.get(task.getProcessInstanceId()); | ||||||
|             return convert(task, processInstance, userMap.get(Long.valueOf(processInstance.getStartUserId()))); |             return convert(task, processInstance, userMap.get(Long.valueOf(processInstance.getStartUserId()))); | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| @ -85,6 +86,6 @@ public interface BpmTaskConvert { | |||||||
|             @Mapping(source = "processInstance.processDefinitionId", target = "processInstance.processDefinitionId"), |             @Mapping(source = "processInstance.processDefinitionId", target = "processInstance.processDefinitionId"), | ||||||
|             @Mapping(source = "user.nickname", target = "processInstance.startUserNickname") |             @Mapping(source = "user.nickname", target = "processInstance.startUserNickname") | ||||||
|     }) |     }) | ||||||
|     BpmTaskDonePageItemRespVO convert(HistoricTaskInstance task, ProcessInstance processInstance, SysUserDO user); |     BpmTaskDonePageItemRespVO convert(HistoricTaskInstance task, HistoricProcessInstance processInstance, SysUserDO user); | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -8,6 +8,7 @@ import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceDel | |||||||
| import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceResultEnum; | import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceResultEnum; | ||||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||||
| import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||||||
|  | import org.activiti.engine.history.HistoricProcessInstance; | ||||||
| import org.activiti.engine.runtime.ProcessInstance; | import org.activiti.engine.runtime.ProcessInstance; | ||||||
|  |  | ||||||
| import javax.validation.Valid; | import javax.validation.Valid; | ||||||
| @ -91,4 +92,30 @@ public interface BpmProcessInstanceService { | |||||||
|         return CollectionUtils.convertMap(getProcessInstances(ids), ProcessInstance::getProcessInstanceId); |         return CollectionUtils.convertMap(getProcessInstances(ids), ProcessInstance::getProcessInstanceId); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获得历史的流程实例 | ||||||
|  |      * | ||||||
|  |      * @param id 流程实例的编号 | ||||||
|  |      * @return 历史的流程实例 | ||||||
|  |      */ | ||||||
|  |     HistoricProcessInstance getHistoricProcessInstance(String id); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获得历史的流程实例列表 | ||||||
|  |      * | ||||||
|  |      * @param ids 流程实例的编号集合 | ||||||
|  |      * @return 历史的流程实例列表 | ||||||
|  |      */ | ||||||
|  |     List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获得历史的流程实例 Map | ||||||
|  |      * | ||||||
|  |      * @param ids 流程实例的编号集合 | ||||||
|  |      * @return 历史的流程实例列表 Map | ||||||
|  |      */ | ||||||
|  |     default Map<String, HistoricProcessInstance> getHistoricProcessInstanceMap(Set<String> ids) { | ||||||
|  |         return CollectionUtils.convertMap(getHistoricProcessInstances(ids), HistoricProcessInstance::getId); | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -186,8 +186,14 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | |||||||
|      * @param id 流程实例的编号 |      * @param id 流程实例的编号 | ||||||
|      * @return 历史的流程实例 |      * @return 历史的流程实例 | ||||||
|      */ |      */ | ||||||
|     private HistoricProcessInstance getHistoricProcessInstance(String id) { |     @Override | ||||||
|  |     public HistoricProcessInstance getHistoricProcessInstance(String id) { | ||||||
|         return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); |         return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids) { | ||||||
|  |         return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -144,13 +144,13 @@ public class BpmTaskServiceImpl implements BpmTaskService { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         // 获得 ProcessInstance Map |         // 获得 ProcessInstance Map | ||||||
|         Map<String, ProcessInstance> processInstanceMap = processInstanceService.getProcessInstanceMap( |         Map<String, HistoricProcessInstance> historicProcessInstanceMap = processInstanceService.getHistoricProcessInstanceMap( | ||||||
|                 convertSet(tasks, HistoricTaskInstance::getProcessInstanceId)); |                 convertSet(tasks, HistoricTaskInstance::getProcessInstanceId)); | ||||||
|         // 获得 User Map |         // 获得 User Map | ||||||
|         Map<Long, SysUserDO> userMap = userService.getUserMap( |         Map<Long, SysUserDO> userMap = userService.getUserMap( | ||||||
|                 convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId()))); |                 convertSet(historicProcessInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId()))); | ||||||
|         // 拼接结果 |         // 拼接结果 | ||||||
|         return new PageResult<>(BpmTaskConvert.INSTANCE.convertList2(tasks, processInstanceMap, userMap), |         return new PageResult<>(BpmTaskConvert.INSTANCE.convertList2(tasks, historicProcessInstanceMap, userMap), | ||||||
|                 taskQuery.count()); |                 taskQuery.count()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | |||||||
| @ -8,6 +8,14 @@ export function getTodoTaskPage(query) { | |||||||
|   }) |   }) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | export function getDoneTaskPage(query) { | ||||||
|  |   return request({ | ||||||
|  |     url: '/bpm/task/done-page', | ||||||
|  |     method: 'get', | ||||||
|  |     params: query | ||||||
|  |   }) | ||||||
|  | } | ||||||
|  |  | ||||||
| export function completeTask(data) { | export function completeTask(data) { | ||||||
|   return request({ |   return request({ | ||||||
|     url: '/bpm/task/complete', |     url: '/bpm/task/complete', | ||||||
|  | |||||||
							
								
								
									
										105
									
								
								yudao-admin-ui/src/views/bpm/task/done.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								yudao-admin-ui/src/views/bpm/task/done.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,105 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="app-container"> | ||||||
|  |  | ||||||
|  |     <!-- 搜索工作栏 --> | ||||||
|  |     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px"> | ||||||
|  |       <el-form-item label="流程名" prop="name"> | ||||||
|  |         <el-input v-model="queryParams.name" placeholder="请输入流程名" clearable size="small" @keyup.enter.native="handleQuery"/> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item label="创建时间"> | ||||||
|  |         <el-date-picker v-model="dateRangeCreateTime" size="small" style="width: 240px" value-format="yyyy-MM-dd" | ||||||
|  |                         type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" /> | ||||||
|  |       </el-form-item> | ||||||
|  |       <el-form-item> | ||||||
|  |         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> | ||||||
|  |         <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> | ||||||
|  |       </el-form-item> | ||||||
|  |     </el-form> | ||||||
|  |  | ||||||
|  |     <!-- 列表 --> | ||||||
|  |     <el-table v-loading="loading" :data="list"> | ||||||
|  |       <el-table-column label="任务编号" align="center" prop="id" width="300" /> | ||||||
|  |       <el-table-column label="任务名称" align="center" prop="name" /> | ||||||
|  |       <el-table-column label="所属流程" align="center" prop="processInstance.name" /> | ||||||
|  |       <el-table-column label="流程发起人" align="center" prop="processInstance.startUserNickname" /> | ||||||
|  |       <el-table-column label="创建时间" align="center" prop="createTime" width="180"> | ||||||
|  |         <template slot-scope="scope"> | ||||||
|  |           <span>{{ parseTime(scope.row.createTime) }}</span> | ||||||
|  |         </template> | ||||||
|  |       </el-table-column> | ||||||
|  |       <el-table-column label="审批时间" align="center" prop="endTime" width="180"> | ||||||
|  |         <template slot-scope="scope"> | ||||||
|  |           <span>{{ parseTime(scope.row.endTime) }}</span> | ||||||
|  |         </template> | ||||||
|  |       </el-table-column> | ||||||
|  |       <!-- TODO 耗时 --> | ||||||
|  |       <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> | ||||||
|  |         <template slot-scope="scope"> | ||||||
|  |           <!-- TODO 权限、颜色 --> | ||||||
|  |           <el-button size="mini" type="text" icon="el-icon-edit">详情</el-button> | ||||||
|  |         </template> | ||||||
|  |       </el-table-column> | ||||||
|  |     </el-table> | ||||||
|  |     <!-- 分页组件 --> | ||||||
|  |     <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" | ||||||
|  |                 @pagination="getList"/> | ||||||
|  |  | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import {getDoneTaskPage} from '@/api/bpm/task' | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "Done", | ||||||
|  |   components: { | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       // 遮罩层 | ||||||
|  |       loading: true, | ||||||
|  |       // 显示搜索条件 | ||||||
|  |       showSearch: true, | ||||||
|  |       // 总条数 | ||||||
|  |       total: 0, | ||||||
|  |       // 待办任务列表 | ||||||
|  |       list: [], | ||||||
|  |       // 查询参数 | ||||||
|  |       dateRangeCreateTime: [], | ||||||
|  |       queryParams: { | ||||||
|  |         pageNo: 1, | ||||||
|  |         pageSize: 10, | ||||||
|  |         name: null, | ||||||
|  |       }, | ||||||
|  |     }; | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     this.getList(); | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     /** 查询列表 */ | ||||||
|  |     getList() { | ||||||
|  |       this.loading = true; | ||||||
|  |       // 处理查询参数 | ||||||
|  |       let params = {...this.queryParams}; | ||||||
|  |       this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime'); | ||||||
|  |       getDoneTaskPage(params).then(response => { | ||||||
|  |         this.list = response.data.list; | ||||||
|  |         this.total = response.data.total; | ||||||
|  |         this.loading = false; | ||||||
|  |       }); | ||||||
|  |     }, | ||||||
|  |     /** 搜索按钮操作 */ | ||||||
|  |     handleQuery() { | ||||||
|  |       this.queryParams.pageNo = 1; | ||||||
|  |       this.getList(); | ||||||
|  |     }, | ||||||
|  |     /** 重置按钮操作 */ | ||||||
|  |     resetQuery() { | ||||||
|  |       this.dateRangeCreateTime = []; | ||||||
|  |       this.resetForm("queryForm"); | ||||||
|  |       this.handleQuery(); | ||||||
|  |     }, | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | </script> | ||||||
| @ -52,7 +52,7 @@ | |||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script> | <script> | ||||||
| import {approveTask, completeTask, getTodoTaskPage, rejectTask} from '@/api/bpm/task' | import {approveTask, getTodoTaskPage, rejectTask} from '@/api/bpm/task' | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
|   name: "Todo", |   name: "Todo", | ||||||
| @ -93,27 +93,6 @@ export default { | |||||||
|         this.loading = false; |         this.loading = false; | ||||||
|       }); |       }); | ||||||
|     }, |     }, | ||||||
|     /** 取消按钮 */ |  | ||||||
|     cancel() { |  | ||||||
|       this.open = false; |  | ||||||
|       this.reset(); |  | ||||||
|     }, |  | ||||||
|     /** 表单重置 */ |  | ||||||
|     reset() { |  | ||||||
|       this.form = { |  | ||||||
|         id: undefined, |  | ||||||
|         processInstanceId: undefined, |  | ||||||
|         status: undefined, |  | ||||||
|         userId: undefined, |  | ||||||
|         startTime: undefined, |  | ||||||
|         endTime: undefined, |  | ||||||
|         leaveType: undefined, |  | ||||||
|         reason: undefined, |  | ||||||
|         applyTime: undefined, |  | ||||||
|       }; |  | ||||||
|       this.resetForm("form"); |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     /** 搜索按钮操作 */ |     /** 搜索按钮操作 */ | ||||||
|     handleQuery() { |     handleQuery() { | ||||||
|       this.queryParams.pageNo = 1; |       this.queryParams.pageNo = 1; | ||||||
| @ -122,7 +101,6 @@ export default { | |||||||
|     /** 重置按钮操作 */ |     /** 重置按钮操作 */ | ||||||
|     resetQuery() { |     resetQuery() { | ||||||
|       this.dateRangeCreateTime = []; |       this.dateRangeCreateTime = []; | ||||||
|       this.dateRangeApplyTime = []; |  | ||||||
|       this.resetForm("queryForm"); |       this.resetForm("queryForm"); | ||||||
|       this.handleQuery(); |       this.handleQuery(); | ||||||
|     }, |     }, | ||||||
|  | |||||||
| @ -2,7 +2,10 @@ package cn.iocoder.yudao.framework.activiti.core.util; | |||||||
|  |  | ||||||
| import cn.hutool.core.util.ReflectUtil; | import cn.hutool.core.util.ReflectUtil; | ||||||
| import com.alibaba.ttl.TransmittableThreadLocal; | import com.alibaba.ttl.TransmittableThreadLocal; | ||||||
|  | import org.activiti.engine.history.HistoricProcessInstance; | ||||||
| import org.activiti.engine.impl.identity.Authentication; | import org.activiti.engine.impl.identity.Authentication; | ||||||
|  | import org.activiti.engine.impl.persistence.entity.HistoricProcessInstanceEntityImpl; | ||||||
|  | import org.activiti.engine.impl.persistence.entity.HistoricScopeInstanceEntityImpl; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Activiti 工具类 |  * Activiti 工具类 | ||||||
| @ -15,6 +18,8 @@ public class ActivitiUtils { | |||||||
|         setAuthenticationThreadLocal(); |         setAuthenticationThreadLocal(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     // ========== Authentication 相关 ========== | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 反射修改 Authentication 的 authenticatedUserIdThreadLocal 静态变量,使用 TTL 线程变量 |      * 反射修改 Authentication 的 authenticatedUserIdThreadLocal 静态变量,使用 TTL 线程变量 | ||||||
|      * 目的:保证 @Async 等异步执行时,变量丢失的问题 |      * 目的:保证 @Async 等异步执行时,变量丢失的问题 | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV