feat(流程详情): 添加流转记录开始和结束节点显示
This commit is contained in:
@@ -21,9 +21,9 @@ public class WfDetailVo {
|
|||||||
private FormConf taskFormData;
|
private FormConf taskFormData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 历史任务信息
|
* 历史流程节点信息
|
||||||
*/
|
*/
|
||||||
private List<WfTaskVo> historyTaskList;
|
private List<WfProcNodeVo> historyProcNodeList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程表单列表
|
* 流程表单列表
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user