更多nbcio-boot功能请看演示系统
gitee源代码地址
后端代码: https://gitee.com/nbacheng/nbcio-boot
前端代码:https://gitee.com/nbacheng/nbcio-vue.git
在线演示(包括H5) : http://122.227.135.243:9888
历史记录增加开始与结束的显示,以方便用户查看。
1、前端修改,代码如下:
<el-card class="box-card" v-if="flowRecordList"> <div slot="header" class="clearfix"> <span class="el-icon-notebook-1">审批记录</span> </div> <el-col :span="16" :offset="4"> <div class="block"> <el-timeline> <el-timeline-item v-for="(item,index ) in flowRecordList" :key="index" :icon="setIcon(item.finishTime)" :color="setColor(item.finishTime)"> <p style="font-weight: 700">{{item.taskName}}</p> <el-card v-if="item.activityType === 'startEvent'" class="box-card" shadow="hover"> {{ item.assigneeName }} 在 {{ item.createTime }} 发起流程 </el-card> <el-card v-if="item.activityType === 'userTask'" :body-style="{ padding: '10px' }"> <label v-if="item.assigneeName" style="font-weight: normal;margin-right: 30px;">实际办理: {{item.assigneeName}} <el-tag type="info" size="mini">{{item.deptName}}</el-tag> </label> <label v-if="item.candidate" style="font-weight: normal;margin-right: 30px;">候选办理: {{item.candidate}}</label> <label style="font-weight: normal">接收时间: </label><label style="color:#8a909c;font-weight: normal">{{item.createTime}}</label> <label v-if="item.finishTime" style="margin-left: 30px;font-weight: normal">办结时间: </label><label style="color:#8a909c;font-weight: normal">{{item.finishTime}}</label> <label v-if="item.duration" style="margin-left: 30px;font-weight: normal">耗时: </label><label style="color:#8a909c;font-weight: normal">{{item.duration}}</label> <p v-if="item.listFlowCommentDto" v-for="(commentitem,index ) in item.listFlowCommentDto" :key="index"> <el-tag type="success" v-if="commentitem.type === '1'"> {{commentitem.comment}}</el-tag> <el-form v-if= "commentitem.type === '1' && fileitem.type === '1' && item.listcommentFileDto.length>0" v-for="(fileitem,fileindex ) in item.listcommentFileDto" :key="fileindex"> <el-form-item label="附件" prop="listcommentFileDto"> <j-upload v-if="fileitem.type === '1'" v-model="fileitem.fileurl" :disabled = "true" text="上传的文件" ></j-upload> </el-form-item> </el-form> <el-tag type="warning" v-if="commentitem.type === '2'"> {{"退回: "+ commentitem.comment}}</el-tag> <el-form v-if= "commentitem.type === '2' && fileitem.type === '2' && item.listcommentFileDto.length>0" v-for="(fileitem,fileindex ) in item.listcommentFileDto" :key="fileindex"> <el-form-item label="附件" prop="listcommentFileDto"> <j-upload v-if="fileitem.type === '2'" v-model="fileitem.fileurl" :disabled = "true" text="退回上传的文件" ></j-upload> </el-form-item> </el-form> <el-tag type="danger" v-if="commentitem.type === '3'"> {{"驳回: "+commentitem.comment}}</el-tag> <el-form v-if= "commentitem.type === '3' && fileitem.type === '3' && item.listcommentFileDto.length>0" v-for="(fileitem,fileindex ) in item.listcommentFileDto" :key="fileindex"> <el-form-item label="附件" prop="listcommentFileDto"> <j-upload v-if="fileitem.type === '3'" v-model="fileitem.fileurl" :disabled = "true" text="驳回上传的文件" ></j-upload> </el-form-item> </el-form> <el-tag type="success" v-if="commentitem.type === '4'"> {{commentitem.comment}}</el-tag> <el-form v-if= "commentitem.type === '4' && fileitem.type === '4' && item.listcommentFileDto.length>0" v-for="(fileitem,fileindex ) in item.listcommentFileDto" :key="fileindex"> <el-form-item label="附件" prop="listcommentFileDto"> <j-upload v-if="fileitem.type === '4'" v-model="fileitem.fileurl" :disabled = "true" text="委派上传的文件" ></j-upload> </el-form-item> </el-form> <el-tag type="success" v-if="commentitem.type === '5'"> {{commentitem.comment}}</el-tag> <el-form v-if= "commentitem.type === '5' && fileitem.type === '5' && item.listcommentFileDto.length>0" v-for="(fileitem,fileindex ) in item.listcommentFileDto" :key="fileindex"> <el-form-item label="附件" prop="listcommentFileDto" > <j-upload v-model="fileitem.fileurl" :disabled = "true" text="转办上传的文件" ></j-upload> </el-form-item> </el-form> <el-tag type="warning" v-if="commentitem.type === '7'"> {{"撤回: "+commentitem.comment}}</el-tag> <!--撤回信息--> <el-tag type="warning" v-if="commentitem.type === '6'"> {{commentitem.comment}}</el-tag> <!--终止信息--> <el-tag type="warning" v-if="commentitem.type === '8'"> {{commentitem.comment}}</el-tag> <!--跳过信息--> <el-tag type="success" v-if="commentitem.type === '9'"> {{commentitem.comment}}</el-tag> <!--前加签--> <el-tag type="success" v-if="commentitem.type === '10'"> {{commentitem.comment}}</el-tag> <!--后加签--> <el-tag type="success" v-if="commentitem.type === '11'"> {{commentitem.comment}}</el-tag> <!--多实例加签--> <el-tag type="success" v-if="commentitem.type === '12'"> {{commentitem.comment}}</el-tag> <!--跳转信息--> </p> </el-card> <el-card v-if="item.activityType === 'endEvent'" class="box-card" shadow="hover"> {{ item.createTime }} 流程结束 </el-card> </el-timeline-item> </el-timeline> </div> </el-col> </el-card>
2、后端修改
/** * 流程历史流转记录 * add by nbacheng * @param procInsId 流程实例Id, 流程发布id, 任务id * @return */ @Override public Result flowRecord(String procInsId,String deployId, String businessKey, String taskId, String category) { Map<String, Object> map = new HashMap<String, Object>(); if (StringUtils.isNotBlank(procInsId)) { List<HistoricActivityInstance> list = historyService .createHistoricActivityInstanceQuery() .processInstanceId(procInsId) .activityTypes(CollUtil.newHashSet(BpmnXMLConstants.ELEMENT_EVENT_START, BpmnXMLConstants.ELEMENT_EVENT_END, BpmnXMLConstants.ELEMENT_TASK_USER)) .orderByHistoricActivityInstanceStartTime().desc() .orderByHistoricActivityInstanceEndTime().desc() .list(); List<FlowTaskDto> hisFlowList = new ArrayList<>(); // 获取流程实例 HistoricProcessInstance historicProcIns = historyService.createHistoricProcessInstanceQuery() .processInstanceId(procInsId) .includeProcessVariables() .singleResult(); String startUserId = historicProcIns.getStartUserId(); for (HistoricActivityInstance histIns : list) { FlowTaskDto flowTask = new FlowTaskDto(); if (BpmnXMLConstants.ELEMENT_EVENT_START.equals(histIns.getActivityType())) { SysUser startUser = iFlowThirdService.getUserByUsername(startUserId); flowTask.setAssigneeId(startUser.getUsername()); flowTask.setAssigneeName(startUser.getRealname()); flowTask.setCreateTime(histIns.getStartTime()); flowTask.setFinishTime(histIns.getEndTime()); flowTask.setActivityType(histIns.getActivityType()); } if (BpmnXMLConstants.ELEMENT_EVENT_END.equals(histIns.getActivityType())) { flowTask.setCreateTime(histIns.getStartTime()); flowTask.setFinishTime(histIns.getEndTime()); flowTask.setActivityType(histIns.getActivityType()); } if (StringUtils.isNotBlank(histIns.getTaskId())) { flowTask.setTaskId(histIns.getTaskId()); flowTask.setTaskName(histIns.getActivityName()); flowTask.setCreateTime(histIns.getStartTime()); flowTask.setFinishTime(histIns.getEndTime()); flowTask.setActivityType(histIns.getActivityType()); if (StringUtils.isNotBlank(histIns.getAssignee())) { SysUser sysUser = iFlowThirdService.getUserByUsername(histIns.getAssignee()); if(sysUser !=null) { flowTask.setAssigneeId(sysUser.getUsername()); flowTask.setAssigneeName(sysUser.getRealname()); List<String> departNamesByUsername = iFlowThirdService.getDepartNamesByUsername(histIns.getAssignee()); flowTask.setDeptName(CollUtil.join(departNamesByUsername,",")); } } // 展示审批人员 List<HistoricIdentityLink> linksForTask = historyService.getHistoricIdentityLinksForTask(histIns.getTaskId()); StringBuilder stringBuilder = new StringBuilder(); for (HistoricIdentityLink identityLink : linksForTask) { if ("candidate".equals(identityLink.getType())) { if (StringUtils.isNotBlank(identityLink.getUserId())) { SysUser sysUser = iFlowThirdService.getUserByUsername(identityLink.getUserId()); stringBuilder.append(sysUser.getRealname()).append(","); } if (StringUtils.isNotBlank(identityLink.getGroupId())) { List<SysRole> allRole = iFlowThirdService.getAllRole(); SysRole sysRole = allRole.stream().filter(o -> StringUtils.equals(identityLink.getGroupId(), o.getId())).findAny().orElse(new SysRole()); stringBuilder.append(sysRole.getRoleName()).append(","); } } } if (StringUtils.isNotBlank(stringBuilder)) { flowTask.setCandidate(stringBuilder.substring(0, stringBuilder.length() - 1)); } flowTask.setDuration(histIns.getDurationInMillis() == null || histIns.getDurationInMillis() == 0 ? null : getDate(histIns.getDurationInMillis())); // 获取意见评论内容 List<Comment> commentList = taskService.getProcessInstanceComments(histIns.getProcessInstanceId()); List<FlowCommentDto> listFlowCommentDto = new ArrayList<FlowCommentDto>(); commentList.forEach(comment -> { if (histIns.getTaskId().equals(comment.getTaskId())) { //flowTask.setComment(FlowCommentDto.builder().type(comment.getType()).comment(comment.getFullMessage()).build()); //FlowCommentDto flowcommentDto = FlowCommentDto.builder().type(comment.getType()).comment(comment.getFullMessage()).build(); FlowCommentDto flowcommentDto = new FlowCommentDto(); flowcommentDto.setType(comment.getType()); flowcommentDto.setComment(comment.getFullMessage()); listFlowCommentDto.add(flowcommentDto); } }); flowTask.setListFlowCommentDto(listFlowCommentDto); //获取附件 List<Attachment> commentfileList = taskService.getProcessInstanceAttachments(histIns.getProcessInstanceId()); List<FlowCommentFileDto> listcommentFileDto = new ArrayList<FlowCommentFileDto>(); commentfileList.forEach(commentfile -> { if (histIns.getTaskId().equals(commentfile.getTaskId())) { FlowCommentFileDto flowcommenfiletDto = new FlowCommentFileDto(); flowcommenfiletDto.setType(commentfile.getType()); flowcommenfiletDto.setFileurl(commentfile.getUrl()); listcommentFileDto.add(flowcommenfiletDto); } }); flowTask.setListcommentFileDto(listcommentFileDto); // 获取历史任务节点表单数据值 List<HistoricVariableInstance> listHistoricVariableInstance = historyService.createHistoricVariableInstanceQuery() .processInstanceId(procInsId) .taskId(histIns.getTaskId()) .list(); Map<String, Object> variables = new HashedMap<String, Object>(); Map<String, Object> formconf = new HashedMap<String, Object>(); for(HistoricVariableInstance historicVariableInstance:listHistoricVariableInstance) { variables.put(historicVariableInstance.getVariableName(), historicVariableInstance.getValue()); } formconf.put("formValue", variables); // 获取历史任务节点表单参数 if(Objects.nonNull(histIns.getTaskId())) { HistoricTaskInstance taskIns = historyService.createHistoricTaskInstanceQuery() .taskId(histIns.getTaskId()) .includeIdentityLinks() .includeProcessVariables() .includeTaskLocalVariables() .finished() .singleResult(); if (Objects.nonNull(taskIns)) { { String formId = taskIns.getFormKey(); SysForm sysForm = sysDeployFormService.selectCurSysDeployForm(formId, deployId, taskIns.getTaskDefinitionKey()); if (Objects.nonNull(sysForm)) { formconf.put("config", JSONObject.parseObject(sysForm.getFormContent()).get("config")); formconf.put("list", JSONObject.parseObject(sysForm.getFormContent()).get("list")); } } } } flowTask.setTaskFormValues(formconf); } hisFlowList.add(flowTask); } map.put("flowList", hisFlowList); } if (Objects.nonNull(category) && category.equalsIgnoreCase("online") && StringUtils.isNotBlank(businessKey)) {// 获取online数据表单配置 LambdaQueryWrapper<FlowMyOnline> flowMyOnlineLambdaQueryWrapper = new LambdaQueryWrapper<>(); flowMyOnlineLambdaQueryWrapper.eq(FlowMyOnline::getDataId, businessKey);//以后这里还要加上onlineId FlowMyOnline online = flowMyOnlineService.getOne(flowMyOnlineLambdaQueryWrapper); if (Objects.nonNull(online)) { Map<String, Object> onlCgformHeadMap = flowOnlCgformHeadService.getOnlCgformHeadByFormId(online.getOnlineId()); map.put("onlineConfig", onlCgformHeadMap.get("formData")); map.put("onlineId", online.getOnlineId()); } } else if (Objects.nonNull(category) && StringUtils.isNotBlank(businessKey) && !Objects.equals(businessKey, "null") && (category != "online")) { // 获取初始化自定义表单 FlowMyBusiness business = flowMyBusinessService.getByDataId(businessKey); String serviceImplName = business.getServiceImplName(); FlowCallBackServiceI flowCallBackService = (FlowCallBackServiceI) SpringContextUtils.getBean(serviceImplName); // 流程处理完后,进行回调业务层 if (flowCallBackService!=null){ Object businessDataById = flowCallBackService.getBusinessDataById(businessKey); map.put("formData",businessDataById); map.put("routeName", business.getRouteName()); } } else { if (StringUtils.isNotBlank(deployId)) { //获取当前节点的初始化表单 if(Objects.nonNull(taskId)) { HistoricTaskInstance taskIns = historyService.createHistoricTaskInstanceQuery() .taskId(taskId) .includeIdentityLinks() .includeProcessVariables() .includeTaskLocalVariables() .singleResult(); if (Objects.nonNull(taskIns)) { String formId = taskIns.getFormKey(); SysForm sysForm = sysDeployFormService.selectCurSysDeployForm(formId, deployId, taskIns.getTaskDefinitionKey()); if (Objects.nonNull(sysForm)) { map.put("taskFormData", JSONObject.parseObject(sysForm.getFormContent())); } } } else { SysForm sysForm = sysDeployFormService.selectSysDeployFormByDeployId(deployId); if (Objects.isNull(sysForm)) { return Result.error("请先配置流程表单"); } map.put("formData", JSONObject.parseObject(sysForm.getFormContent())); } } } if(isStartUserNode(taskId)) { map.put("isStartUserNode", true); } return Result.OK(map); }
3、效果图