feat(流程详情): 添加流转记录开始和结束节点显示

This commit is contained in:
konbai
2022-09-25 19:48:27 +08:00
parent 150094ddac
commit 307103be8c
5 changed files with 158 additions and 68 deletions

View File

@@ -21,9 +21,9 @@ public class WfDetailVo {
private FormConf taskFormData; private FormConf taskFormData;
/** /**
* 历史任务信息 * 历史流程节点信息
*/ */
private List<WfTaskVo> historyTaskList; private List<WfProcNodeVo> historyProcNodeList;
/** /**
* 流程表单列表 * 流程表单列表

View File

@@ -0,0 +1,67 @@
package com.ruoyi.workflow.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.flowable.engine.task.Comment;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* 工作流节点元素视图对象
*
* @author KonBAI
* @createTime 2022/9/11 22:04
*/
@Data
@ExcelIgnoreUnannotated
public class WfProcNodeVo implements Serializable {
/**
* 流程ID
*/
private String procDefId;
/**
* 活动ID
*/
private String activityId;
/**
* 活动名称
*/
private String activityName;
/**
* 活动类型
*/
private String activityType;
/**
* 活动耗时
*/
private String duration;
/**
* 执行人Id
*/
private Long assigneeId;
/**
* 执行人名称
*/
private String assigneeName;
/**
* 候选执行人
*/
private String candidate;
/**
* 任务意见
*/
private List<Comment> commentList;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/**
* 结束时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date endTime;
}

View File

@@ -29,10 +29,7 @@ import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.system.service.ISysUserService; import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.workflow.domain.WfDeployForm; import com.ruoyi.workflow.domain.WfDeployForm;
import com.ruoyi.workflow.domain.bo.WfProcessBo; import com.ruoyi.workflow.domain.bo.WfProcessBo;
import com.ruoyi.workflow.domain.vo.WfDefinitionVo; import com.ruoyi.workflow.domain.vo.*;
import com.ruoyi.workflow.domain.vo.WfDeployFormVo;
import com.ruoyi.workflow.domain.vo.WfDetailVo;
import com.ruoyi.workflow.domain.vo.WfTaskVo;
import com.ruoyi.workflow.mapper.WfDeployFormMapper; import com.ruoyi.workflow.mapper.WfDeployFormMapper;
import com.ruoyi.workflow.service.IWfProcessService; import com.ruoyi.workflow.service.IWfProcessService;
import com.ruoyi.workflow.service.IWfTaskService; import com.ruoyi.workflow.service.IWfTaskService;
@@ -214,7 +211,7 @@ public class WfProcessServiceImpl extends FlowServiceFactory implements IWfProce
throw new ServiceException("没有可办理的任务!"); throw new ServiceException("没有可办理的任务!");
} }
detailVo.setTaskFormData(currTaskFormData(deployId, taskIns)); detailVo.setTaskFormData(currTaskFormData(deployId, taskIns));
detailVo.setHistoryTaskList(historyTaskList(procInsId)); detailVo.setHistoryProcNodeList(historyProcNodeList(procInsId));
detailVo.setProcessFormList(processFormList(procInsId, deployId, taskIns)); detailVo.setProcessFormList(processFormList(procInsId, deployId, taskIns));
return detailVo; return detailVo;
} }
@@ -429,7 +426,7 @@ public class WfProcessServiceImpl extends FlowServiceFactory implements IWfProce
private void buildProcessVariables(Map<String, Object> variables) { private void buildProcessVariables(Map<String, Object> variables) {
String userIdStr = LoginHelper.getUserId().toString(); String userIdStr = LoginHelper.getUserId().toString();
identityService.setAuthenticatedUserId(userIdStr); identityService.setAuthenticatedUserId(userIdStr);
variables.put(TaskConstants.PROCESS_INITIATOR, userIdStr); variables.put(BpmnXMLConstants.ATTRIBUTE_EVENT_START_INITIATOR, userIdStr);
} }
@@ -546,67 +543,87 @@ public class WfProcessServiceImpl extends FlowServiceFactory implements IWfProce
/** /**
* 获取历史任务信息列表 * 获取历史任务信息列表
*/ */
private List<WfTaskVo> historyTaskList(String procInsId) { private List<WfProcNodeVo> historyProcNodeList(String procInsId) {
List<HistoricTaskInstance> taskInstanceList = historyService.createHistoricTaskInstanceQuery() List<HistoricActivityInstance> historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(procInsId) .processInstanceId(procInsId)
.orderByHistoricTaskInstanceStartTime().desc() .activityTypes(CollUtil.newHashSet(BpmnXMLConstants.ELEMENT_EVENT_START, BpmnXMLConstants.ELEMENT_EVENT_END, BpmnXMLConstants.ELEMENT_TASK_USER))
.orderByHistoricActivityInstanceStartTime().desc()
.orderByHistoricActivityInstanceEndTime().desc()
.list(); .list();
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
.processInstanceId(procInsId)
.singleResult();
List<Comment> commentList = taskService.getProcessInstanceComments(procInsId); List<Comment> commentList = taskService.getProcessInstanceComments(procInsId);
List<WfTaskVo> taskVoList = new ArrayList<>(taskInstanceList.size());
taskInstanceList.forEach(taskInstance -> { List<WfProcNodeVo> elementVoList = new ArrayList<>();
WfTaskVo taskVo = new WfTaskVo(); for (HistoricActivityInstance activityInstance : historicActivityInstanceList) {
taskVo.setProcDefId(taskInstance.getProcessDefinitionId()); WfProcNodeVo elementVo = new WfProcNodeVo();
taskVo.setTaskId(taskInstance.getId()); elementVo.setProcDefId(activityInstance.getProcessDefinitionId());
taskVo.setTaskDefKey(taskInstance.getTaskDefinitionKey()); elementVo.setActivityId(activityInstance.getActivityId());
taskVo.setTaskName(taskInstance.getName()); elementVo.setActivityName(activityInstance.getActivityName());
taskVo.setCreateTime(taskInstance.getStartTime()); elementVo.setActivityType(activityInstance.getActivityType());
taskVo.setFinishTime(taskInstance.getEndTime()); elementVo.setCreateTime(activityInstance.getStartTime());
if (StringUtils.isNotBlank(taskInstance.getAssignee())) { elementVo.setEndTime(activityInstance.getEndTime());
SysUser user = userService.selectUserById(Long.parseLong(taskInstance.getAssignee())); if (ObjectUtil.isNotNull(activityInstance.getDurationInMillis())) {
taskVo.setAssigneeId(user.getUserId()); elementVo.setDuration(DateUtil.formatBetween(activityInstance.getDurationInMillis(), BetweenFormatter.Level.SECOND));
taskVo.setAssigneeName(user.getNickName());
taskVo.setDeptName(user.getDept().getDeptName());
} }
// 展示审批人员
List<HistoricIdentityLink> linksForTask = historyService.getHistoricIdentityLinksForTask(taskInstance.getId()); if (BpmnXMLConstants.ELEMENT_EVENT_START.equals(activityInstance.getActivityType())) {
StringBuilder stringBuilder = new StringBuilder(); if (ObjectUtil.isNotNull(historicProcessInstance)) {
for (HistoricIdentityLink identityLink : linksForTask) { Long userId = Long.parseLong(historicProcessInstance.getStartUserId());
if ("candidate".equals(identityLink.getType())) { SysUser user = userService.selectUserById(userId);
if (StringUtils.isNotBlank(identityLink.getUserId())) { if (user != null) {
SysUser user = userService.selectUserById(Long.parseLong(identityLink.getUserId())); elementVo.setAssigneeId(user.getUserId());
stringBuilder.append(user.getNickName()).append(","); elementVo.setAssigneeName(user.getNickName());
} }
if (StringUtils.isNotBlank(identityLink.getGroupId())) { }
if (identityLink.getGroupId().startsWith(TaskConstants.ROLE_GROUP_PREFIX)) { } else if (BpmnXMLConstants.ELEMENT_TASK_USER.equals(activityInstance.getActivityType())) {
Long roleId = Long.parseLong(StringUtils.stripStart(identityLink.getGroupId(), TaskConstants.ROLE_GROUP_PREFIX)); if (StringUtils.isNotBlank(activityInstance.getAssignee())) {
SysRole role = roleService.selectRoleById(roleId); SysUser user = userService.selectUserById(Long.parseLong(activityInstance.getAssignee()));
stringBuilder.append(role.getRoleName()).append(","); elementVo.setAssigneeId(user.getUserId());
} else if (identityLink.getGroupId().startsWith(TaskConstants.DEPT_GROUP_PREFIX)) { elementVo.setAssigneeName(user.getNickName());
Long deptId = Long.parseLong(StringUtils.stripStart(identityLink.getGroupId(), TaskConstants.DEPT_GROUP_PREFIX)); }
SysDept dept = deptService.selectDeptById(deptId); // 展示审批人员
stringBuilder.append(dept.getDeptName()).append(","); List<HistoricIdentityLink> linksForTask = historyService.getHistoricIdentityLinksForTask(activityInstance.getTaskId());
StringBuilder stringBuilder = new StringBuilder();
for (HistoricIdentityLink identityLink : linksForTask) {
if ("candidate".equals(identityLink.getType())) {
if (StringUtils.isNotBlank(identityLink.getUserId())) {
SysUser user = userService.selectUserById(Long.parseLong(identityLink.getUserId()));
stringBuilder.append(user.getNickName()).append(",");
}
if (StringUtils.isNotBlank(identityLink.getGroupId())) {
if (identityLink.getGroupId().startsWith(TaskConstants.ROLE_GROUP_PREFIX)) {
Long roleId = Long.parseLong(StringUtils.stripStart(identityLink.getGroupId(), TaskConstants.ROLE_GROUP_PREFIX));
SysRole role = roleService.selectRoleById(roleId);
stringBuilder.append(role.getRoleName()).append(",");
} else if (identityLink.getGroupId().startsWith(TaskConstants.DEPT_GROUP_PREFIX)) {
Long deptId = Long.parseLong(StringUtils.stripStart(identityLink.getGroupId(), TaskConstants.DEPT_GROUP_PREFIX));
SysDept dept = deptService.selectDeptById(deptId);
stringBuilder.append(dept.getDeptName()).append(",");
}
} }
} }
} }
} if (StringUtils.isNotBlank(stringBuilder)) {
if (StringUtils.isNotBlank(stringBuilder)) { elementVo.setCandidate(stringBuilder.substring(0, stringBuilder.length() - 1));
taskVo.setCandidate(stringBuilder.substring(0, stringBuilder.length() - 1)); }
} // 获取意见评论内容
if (ObjectUtil.isNotNull(taskInstance.getDurationInMillis())) { if (CollUtil.isNotEmpty(commentList)) {
taskVo.setDuration(DateUtil.formatBetween(taskInstance.getDurationInMillis(), BetweenFormatter.Level.SECOND)); List<Comment> comments = new ArrayList<>();
} for (Comment comment : commentList) {
// 获取意见评论内容
if (CollUtil.isNotEmpty(commentList)) { if (comment.getTaskId().equals(activityInstance.getTaskId())) {
List<Comment> comments = new ArrayList<>(); comments.add(comment);
for (Comment comment : commentList) { }
if (comment.getTaskId().equals(taskInstance.getId())) { }
comments.add(comment); elementVo.setCommentList(comments);
}
} }
taskVo.setCommentList(comments);
} }
taskVoList.add(taskVo); elementVoList.add(elementVo);
}); }
return taskVoList; return elementVoList;
} }
} }

View File

@@ -178,7 +178,7 @@ export default {
this.dlgTitle = element.businessObject ? element.businessObject.name : undefined; this.dlgTitle = element.businessObject ? element.businessObject.name : undefined;
// 计算当前悬浮任务审批记录,如果记录为空不显示弹窗 // 计算当前悬浮任务审批记录,如果记录为空不显示弹窗
this.taskCommentList = (this.allCommentList || []).filter(item => { this.taskCommentList = (this.allCommentList || []).filter(item => {
return item.taskDefKey === this.selectTaskId; return item.activityId === this.selectTaskId;
}); });
this.dialogVisible = true; this.dialogVisible = true;
}, },

View File

@@ -77,14 +77,17 @@
<el-col :span="20" :offset="2"> <el-col :span="20" :offset="2">
<div class="block"> <div class="block">
<el-timeline> <el-timeline>
<el-timeline-item v-for="(item,index) in historyTaskList" :key="index" :icon="setIcon(item.finishTime)" :color="setColor(item.finishTime)"> <el-timeline-item v-for="(item,index) in historyProcNodeList" :key="index" :icon="setIcon(item.endTime)" :color="setColor(item.endTime)">
<p style="font-weight: 700">{{ item.taskName }}</p> <p style="font-weight: 700">{{ item.activityName }}</p>
<el-card class="box-card" shadow="hover"> <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'" class="box-card" shadow="hover">
<el-descriptions :column="5" :labelStyle="{'font-weight': 'bold'}"> <el-descriptions :column="5" :labelStyle="{'font-weight': 'bold'}">
<el-descriptions-item label="实际办理">{{ item.assigneeName || '-'}}</el-descriptions-item> <el-descriptions-item label="实际办理">{{ item.assigneeName || '-'}}</el-descriptions-item>
<el-descriptions-item label="候选办理">{{ item.candidate || '-'}}</el-descriptions-item> <el-descriptions-item label="候选办理">{{ item.candidate || '-'}}</el-descriptions-item>
<el-descriptions-item label="接收时间">{{ item.createTime || '-'}}</el-descriptions-item> <el-descriptions-item label="接收时间">{{ item.createTime || '-'}}</el-descriptions-item>
<el-descriptions-item label="办结时间">{{ item.finishTime || '-' }}</el-descriptions-item> <el-descriptions-item label="办结时间">{{ item.endTime || '-' }}</el-descriptions-item>
<el-descriptions-item label="耗时">{{ item.duration || '-'}}</el-descriptions-item> <el-descriptions-item label="耗时">{{ item.duration || '-'}}</el-descriptions-item>
</el-descriptions> </el-descriptions>
<div v-if="item.commentList && item.commentList.length > 0" v-for="comment in item.commentList"> <div v-if="item.commentList && item.commentList.length > 0" v-for="comment in item.commentList">
@@ -95,6 +98,9 @@
<span>{{ comment.fullMessage }}</span> <span>{{ comment.fullMessage }}</span>
</div> </div>
</el-card> </el-card>
<el-card v-if="item.activityType === 'endEvent'" class="box-card" shadow="hover">
{{ item.createTime }} 结束流程
</el-card>
</el-timeline-item> </el-timeline-item>
</el-timeline> </el-timeline>
</div> </div>
@@ -105,7 +111,7 @@
<el-tab-pane label="流程跟踪" name="track"> <el-tab-pane label="流程跟踪" name="track">
<el-card class="box-card" shadow="never"> <el-card class="box-card" shadow="never">
<process-viewer :key="`designer-${loadIndex}`" :style="'height:' + height" :xml="xmlData" <process-viewer :key="`designer-${loadIndex}`" :style="'height:' + height" :xml="xmlData"
:finishedInfo="finishedInfo" :allCommentList="historyTaskList" :finishedInfo="finishedInfo" :allCommentList="historyProcNodeList"
/> />
</el-card> </el-card>
</el-tab-pane> </el-tab-pane>
@@ -241,7 +247,7 @@ export default {
unfinishedTaskSet: [], unfinishedTaskSet: [],
rejectedTaskSet: [] rejectedTaskSet: []
}, },
historyTaskList: [], historyProcNodeList: [],
// 部门名称 // 部门名称
deptName: undefined, deptName: undefined,
// 部门树选项 // 部门树选项
@@ -428,7 +434,7 @@ export default {
if (this.taskFormOpen) { if (this.taskFormOpen) {
this.taskFormData = data.taskFormData; this.taskFormData = data.taskFormData;
} }
this.historyTaskList = data.historyTaskList; this.historyProcNodeList = data.historyProcNodeList;
this.formOpen = true this.formOpen = true
}) })
}, },