流转记录扩展修改
Some checks failed
Java CI with Maven / build (11) (push) Has been cancelled
Java CI with Maven / build (17) (push) Has been cancelled
Java CI with Maven / build (8) (push) Has been cancelled
yudao-ui-admin CI / build (14.x) (push) Has been cancelled
yudao-ui-admin CI / build (16.x) (push) Has been cancelled

This commit is contained in:
pch 2025-01-24 11:33:44 +08:00
parent b606c2c873
commit 088d8a5e90
15 changed files with 870 additions and 11 deletions

View File

@ -102,7 +102,8 @@ public interface ErrorCodeConstants {
ErrorCode PROCESS_KEY_NOT_PROVIDED = new ErrorCode(1_009_022_001, "工作流表单key没有提供");
// ========== BPM 流程实例信息 1_009_023_000 ==========
ErrorCode PROCESS_INSTANCE_TODO_NOT_EXISTS = new ErrorCode(1_009_023_000, "BPM 流程实例信息不存在");
// ========== BPM 流转记录扩展 1_009_024_000 ==========
ErrorCode TASK_EXTEND_RECORD_NOT_EXISTS = new ErrorCode(1_009_024_000, "BPM 流转记录扩展不存在");
// ========== only 1_011_013_000 ==========
ErrorCode DOC_FILE_NOT_EXISTS = new ErrorCode(1_011_013_000, "目标文档不存在");

View File

@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.bpm.service.definition.BpmFormService;
import cn.iocoder.yudao.module.bpm.service.processinstancetodo.ProcessInstanceTodoService;
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService;
import cn.iocoder.yudao.module.bpm.service.taskextendrecord.TaskTransitionLog;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
@ -144,7 +145,30 @@ public class BpmTaskController {
return success(BpmTaskConvert.INSTANCE.buildTaskListByProcessInstanceId(taskList,
formMap, userMap, deptMap));
}
@GetMapping("/list-by-process-instance-id2")
@Operation(summary = "获得指定流程实例的任务列表", description = "包括完成的、未完成的")
@Parameter(name = "processInstanceId", description = "流程实例的编号", required = true)
@PreAuthorize("@ss.hasPermission('bpm:task:query')")
public CommonResult<List<BpmTaskRespVO>> getTaskListByProcessInstanceId2(
@RequestParam("processInstanceId") String processInstanceId) {
//List<HistoricTaskInstance> taskList = taskService.getTaskListByProcessInstanceId(processInstanceId, true);
List<TaskTransitionLog> taskList = taskService.getTaskListByProcessInstanceId2(processInstanceId, true);
if (CollUtil.isEmpty(taskList)) {
return success(Collections.emptyList());
}
// 拼接数据
Set<Long> userIds = convertSetByFlatMap(taskList, task ->
Stream.of(NumberUtils.parseLong(task.getUserId()), NumberUtils.parseLong(task.getUserId())));
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(
convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
// 获得 Form Map
Map<Long, BpmFormDO> formMap = formService.getFormMap(
convertSet(taskList, task -> NumberUtils.parseLong(task.getFormKey())));
return success(BpmTaskConvert.INSTANCE.buildTaskListByProcessInstanceId2(taskList,
formMap, userMap, deptMap));
}
@PutMapping("/approve")
@Operation(summary = "通过任务")
@PreAuthorize("@ss.hasPermission('bpm:task:update')")

View File

@ -0,0 +1,95 @@
package cn.iocoder.yudao.module.bpm.controller.admin.taskextendrecord;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import javax.validation.constraints.*;
import javax.validation.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.IOException;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
import cn.iocoder.yudao.module.bpm.controller.admin.taskextendrecord.vo.*;
import cn.iocoder.yudao.module.bpm.dal.dataobject.taskextendrecord.TaskExtendRecordDO;
import cn.iocoder.yudao.module.bpm.service.taskextendrecord.TaskExtendRecordService;
@Tag(name = "管理后台 - BPM 流转记录扩展")
@RestController
@RequestMapping("/bpm/task-extend-record")
@Validated
public class TaskExtendRecordController {
@Resource
private TaskExtendRecordService taskExtendRecordService;
@PostMapping("/create")
@Operation(summary = "创建BPM 流转记录扩展")
@PreAuthorize("@ss.hasPermission('bpm:task-extend-record:create')")
public CommonResult<Long> createTaskExtendRecord(@Valid @RequestBody TaskExtendRecordSaveReqVO createReqVO) {
return success(taskExtendRecordService.createTaskExtendRecord(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新BPM 流转记录扩展")
@PreAuthorize("@ss.hasPermission('bpm:task-extend-record:update')")
public CommonResult<Boolean> updateTaskExtendRecord(@Valid @RequestBody TaskExtendRecordSaveReqVO updateReqVO) {
taskExtendRecordService.updateTaskExtendRecord(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除BPM 流转记录扩展")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('bpm:task-extend-record:delete')")
public CommonResult<Boolean> deleteTaskExtendRecord(@RequestParam("id") Long id) {
taskExtendRecordService.deleteTaskExtendRecord(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得BPM 流转记录扩展")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('bpm:task-extend-record:query')")
public CommonResult<TaskExtendRecordRespVO> getTaskExtendRecord(@RequestParam("id") Long id) {
TaskExtendRecordDO taskExtendRecord = taskExtendRecordService.getTaskExtendRecord(id);
return success(BeanUtils.toBean(taskExtendRecord, TaskExtendRecordRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得BPM 流转记录扩展分页")
@PreAuthorize("@ss.hasPermission('bpm:task-extend-record:query')")
public CommonResult<PageResult<TaskExtendRecordRespVO>> getTaskExtendRecordPage(@Valid TaskExtendRecordPageReqVO pageReqVO) {
PageResult<TaskExtendRecordDO> pageResult = taskExtendRecordService.getTaskExtendRecordPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, TaskExtendRecordRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出BPM 流转记录扩展 Excel")
@PreAuthorize("@ss.hasPermission('bpm:task-extend-record:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportTaskExtendRecordExcel(@Valid TaskExtendRecordPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<TaskExtendRecordDO> list = taskExtendRecordService.getTaskExtendRecordPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "BPM 流转记录扩展.xls", "数据", TaskExtendRecordRespVO.class,
BeanUtils.toBean(list, TaskExtendRecordRespVO.class));
}
}

View File

@ -0,0 +1,66 @@
package cn.iocoder.yudao.module.bpm.controller.admin.taskextendrecord.vo;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - BPM 流转记录扩展分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class TaskExtendRecordPageReqVO extends PageParam {
@Schema(description = "任务id", example = "12523")
private String taskId;
@Schema(description = "任务名称", example = "李四")
private String taskName;
@Schema(description = "开始时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] startTime;
@Schema(description = "结束时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] endTime;
@Schema(description = "用户id", example = "13977")
private String userId;
@Schema(description = "用户名称", example = "张三")
private String userName;
@Schema(description = "意见", example = "不对")
private String reason;
@Schema(description = "持续时间")
private Long duration;
@Schema(description = "工作时间")
private Long workTime;
@Schema(description = "流程实例id", example = "1932")
private String processInstanceId;
@Schema(description = "备用字段1")
private String field1;
@Schema(description = "备用字段2")
private String field2;
@Schema(description = "备用字段3")
private String field3;
@Schema(description = "审批状态", example = "1")
private Integer status;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -0,0 +1,79 @@
package cn.iocoder.yudao.module.bpm.controller.admin.taskextendrecord.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import com.alibaba.excel.annotation.*;
@Schema(description = "管理后台 - BPM 流转记录扩展 Response VO")
@Data
@ExcelIgnoreUnannotated
public class TaskExtendRecordRespVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "6915")
@ExcelProperty("编号")
private Long id;
@Schema(description = "任务id", example = "12523")
@ExcelProperty("任务id")
private String taskId;
@Schema(description = "任务名称", example = "李四")
@ExcelProperty("任务名称")
private String taskName;
@Schema(description = "开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("开始时间")
private LocalDateTime startTime;
@Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("结束时间")
private LocalDateTime endTime;
@Schema(description = "用户id", example = "13977")
@ExcelProperty("用户id")
private String userId;
@Schema(description = "用户名称", example = "张三")
@ExcelProperty("用户名称")
private String userName;
@Schema(description = "意见", requiredMode = Schema.RequiredMode.REQUIRED, example = "不对")
@ExcelProperty("意见")
private String reason;
@Schema(description = "持续时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("持续时间")
private Long duration;
@Schema(description = "工作时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("工作时间")
private Long workTime;
@Schema(description = "流程实例id", example = "1932")
@ExcelProperty("流程实例id")
private String processInstanceId;
@Schema(description = "备用字段1")
@ExcelProperty("备用字段1")
private String field1;
@Schema(description = "备用字段2")
@ExcelProperty("备用字段2")
private String field2;
@Schema(description = "备用字段3")
@ExcelProperty("备用字段3")
private String field3;
@Schema(description = "审批状态", example = "1")
@ExcelProperty("审批状态")
private Integer status;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

View File

@ -0,0 +1,64 @@
package cn.iocoder.yudao.module.bpm.controller.admin.taskextendrecord.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import javax.validation.constraints.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - BPM 流转记录扩展新增/修改 Request VO")
@Data
public class TaskExtendRecordSaveReqVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "6915")
private Long id;
@Schema(description = "任务id", example = "12523")
private String taskId;
@Schema(description = "任务名称", example = "李四")
private String taskName;
@Schema(description = "开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "开始时间不能为空")
private LocalDateTime startTime;
@Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "结束时间不能为空")
private LocalDateTime endTime;
@Schema(description = "用户id", example = "13977")
private String userId;
@Schema(description = "用户名称", example = "张三")
private String userName;
@Schema(description = "意见", requiredMode = Schema.RequiredMode.REQUIRED, example = "不对")
@NotEmpty(message = "意见不能为空")
private String reason;
@Schema(description = "持续时间", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "持续时间不能为空")
private Long duration;
@Schema(description = "工作时间", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "工作时间不能为空")
private Long workTime;
@Schema(description = "流程实例id", example = "1932")
private String processInstanceId;
@Schema(description = "备用字段1")
private String field1;
@Schema(description = "备用字段2")
private String field2;
@Schema(description = "备用字段3")
private String field3;
@Schema(description = "审批状态", example = "1")
private Integer status;
}

View File

@ -15,6 +15,7 @@ import cn.iocoder.yudao.module.bpm.dal.dataobject.processinstancetodo.ProcessIns
import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO;
import cn.iocoder.yudao.module.bpm.service.taskextendrecord.TaskTransitionLog;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import org.flowable.engine.history.HistoricProcessInstance;
@ -119,6 +120,34 @@ public interface BpmTaskConvert {
return taskVO;
});
}
default List<BpmTaskRespVO> buildTaskListByProcessInstanceId2(List<TaskTransitionLog> taskList,
Map<Long, BpmFormDO> formMap,
Map<Long, AdminUserRespDTO> userMap,
Map<Long, DeptRespDTO> deptMap) {
return CollectionUtils.convertList(taskList, task -> {
// 特殊已取消的任务不返回
BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class);
Integer taskStatus = task.getStatus();
if (BpmTaskStatusEnum.isCancelStatus(taskStatus)) {
return null;
}
taskVO.setStatus(taskStatus).setReason(task.getReason() );
// 表单信息
BpmFormDO form = MapUtil.get(formMap, NumberUtils.parseLong(task.getFormKey()), BpmFormDO.class);
if (form != null) {
// taskVO.setFormId(form.getId()).setFormName(form.getName()).setFormConf(form.getConf())
// .setFormFields(form.getFields()).setFormVariables(FlowableUtils.getTaskFormVariable(task));
}
// 用户信息
// buildTaskAssignee(taskVO, task.getAssignee(), userMap, deptMap);
// buildTaskOwner(taskVO, task.getOwner(), userMap, deptMap);
buildTaskAssignee(taskVO, task.getUserId(), userMap, deptMap);
buildTaskOwner(taskVO, task.getUserId(), userMap, deptMap);
return taskVO;
});
}
default PageResult<BpmTaskRespVO> buildTaskPageNew(PageResult<HistoricTaskInstance> pageResult,
Map<String, HistoricProcessInstance> processInstanceMap,

View File

@ -0,0 +1,89 @@
package cn.iocoder.yudao.module.bpm.dal.dataobject.taskextendrecord;
import lombok.*;
import java.util.*;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
/**
* BPM 流转记录扩展 DO
*
* @author 君风
*/
@TableName("bpm_task_extend_record")
@KeySequence("bpm_task_extend_record_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TaskExtendRecordDO extends BaseDO {
/**
* 编号
*/
@TableId
private Long id;
/**
* 任务id
*/
private String taskId;
/**
* 任务名称
*/
private String taskName;
/**
* 开始时间
*/
private LocalDateTime startTime;
/**
* 结束时间
*/
private LocalDateTime endTime;
/**
* 用户id
*/
private String userId;
/**
* 用户名称
*/
private String userName;
/**
* 意见
*/
private String reason;
/**
* 持续时间
*/
private Long duration;
/**
* 工作时间
*/
private Long workTime;
/**
* 流程实例id
*/
private String processInstanceId;
/**
* 备用字段1
*/
private String field1;
/**
* 备用字段2
*/
private String field2;
/**
* 备用字段3
*/
private String field3;
/**
* 审批状态
*/
private Integer status;
}

View File

@ -0,0 +1,48 @@
package cn.iocoder.yudao.module.bpm.dal.mysql.taskextendrecord;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.bpm.dal.dataobject.taskextendrecord.TaskExtendRecordDO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.bpm.controller.admin.taskextendrecord.vo.*;
/**
* BPM 流转记录扩展 Mapper
*
* @author 君风
*/
@Mapper
public interface TaskExtendRecordMapper extends BaseMapperX<TaskExtendRecordDO> {
default PageResult<TaskExtendRecordDO> selectPage(TaskExtendRecordPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<TaskExtendRecordDO>()
.eqIfPresent(TaskExtendRecordDO::getTaskId, reqVO.getTaskId())
.likeIfPresent(TaskExtendRecordDO::getTaskName, reqVO.getTaskName())
.betweenIfPresent(TaskExtendRecordDO::getStartTime, reqVO.getStartTime())
.betweenIfPresent(TaskExtendRecordDO::getEndTime, reqVO.getEndTime())
.eqIfPresent(TaskExtendRecordDO::getUserId, reqVO.getUserId())
.likeIfPresent(TaskExtendRecordDO::getUserName, reqVO.getUserName())
.eqIfPresent(TaskExtendRecordDO::getReason, reqVO.getReason())
.eqIfPresent(TaskExtendRecordDO::getDuration, reqVO.getDuration())
.eqIfPresent(TaskExtendRecordDO::getWorkTime, reqVO.getWorkTime())
.eqIfPresent(TaskExtendRecordDO::getProcessInstanceId, reqVO.getProcessInstanceId())
.eqIfPresent(TaskExtendRecordDO::getField1, reqVO.getField1())
.eqIfPresent(TaskExtendRecordDO::getField2, reqVO.getField2())
.eqIfPresent(TaskExtendRecordDO::getField3, reqVO.getField3())
.eqIfPresent(TaskExtendRecordDO::getStatus, reqVO.getStatus())
.betweenIfPresent(TaskExtendRecordDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(TaskExtendRecordDO::getId));
}
// 根据任务 ID 查询扩展记录
default List<TaskExtendRecordDO> getRecordsByProcessInstanceId(String processInstanceId) {
return selectList(new LambdaQueryWrapperX<TaskExtendRecordDO>()
.eq(TaskExtendRecordDO::getProcessInstanceId, processInstanceId)
.eq(TaskExtendRecordDO::getDeleted, 0) // 确保只查询未删除的记录
.orderByDesc(TaskExtendRecordDO::getCreateTime)); // 按照创建时间降序排列
}
}

View File

@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskTimeoutHandlerTypeEnum;
import cn.iocoder.yudao.module.bpm.service.taskextendrecord.TaskTransitionLog;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.task.api.Task;
@ -87,8 +88,8 @@ public interface BpmTaskService {
* @param asc 是否升序
* @return 流程任务列表
*/
List<TaskTransitionLog> getTaskListByProcessInstanceId2(String processInstanceId, Boolean asc);
List<HistoricTaskInstance> getTaskListByProcessInstanceId(String processInstanceId, Boolean asc);
/**
* 获取任务
*

View File

@ -9,10 +9,12 @@ import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.common.util.object.PageUtils;
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.taskextendrecord.TaskExtendRecordDO;
import cn.iocoder.yudao.module.bpm.enums.definition.*;
import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum;
import cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum;
@ -26,15 +28,14 @@ import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService;
import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService;
import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskTimeoutReqDTO;
import cn.iocoder.yudao.module.bpm.service.taskextendrecord.TaskExtendRecordService;
import cn.iocoder.yudao.module.bpm.service.taskextendrecord.TaskTransitionLog;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.EndEvent;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.UserTask;
import org.flowable.bpmn.model.*;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.runtime.ProcessInstance;
@ -53,8 +54,13 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
import javax.annotation.Resource;
import javax.validation.Valid;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@ -102,6 +108,9 @@ public class BpmTaskServiceImpl implements BpmTaskService {
@Resource
private RepositoryService repositoryService;
@Resource
private TaskExtendRecordService taskExtendRecordService;
// ========== Query 查询相关方法 ==========
@Override
@ -225,9 +234,9 @@ public class BpmTaskServiceImpl implements BpmTaskService {
}
return taskService.createTaskQuery().processInstanceIdIn(processInstanceIds).list();
}
@Override
public List<HistoricTaskInstance> getTaskListByProcessInstanceId(String processInstanceId, Boolean asc) {
// 1. 获取 Flowable 历史任务记录
HistoricTaskInstanceQuery query = historyService.createHistoricTaskInstanceQuery()
.includeTaskLocalVariables()
.processInstanceId(processInstanceId);
@ -236,7 +245,84 @@ public class BpmTaskServiceImpl implements BpmTaskService {
} else {
query.orderByHistoricTaskInstanceStartTime().desc();
}
return query.list();
List<HistoricTaskInstance> historicTasks = query.list();
return historicTasks;
}
@Override
public List<TaskTransitionLog> getTaskListByProcessInstanceId2(String processInstanceId, Boolean asc) {
// 1. 获取 Flowable 历史任务记录
HistoricTaskInstanceQuery query = historyService.createHistoricTaskInstanceQuery()
.includeTaskLocalVariables()
.processInstanceId(processInstanceId);
if (Boolean.TRUE.equals(asc)) {
query.orderByHistoricTaskInstanceStartTime().asc();
} else {
query.orderByHistoricTaskInstanceStartTime().desc();
}
List<HistoricTaskInstance> historicTasks = query.list();
// 2.获取所有相关的扩展记录
List<TaskExtendRecordDO> relatedRecords = taskExtendRecordService.getTaskExtendRecordsByProcessInstanceId(processInstanceId);
// 3. 转换 TaskExtendRecordDO TaskTransitionLog
List<TaskTransitionLog> transitionLogs = relatedRecords.stream()
.map(record -> {
TaskTransitionLog log = new TaskTransitionLog();
log.setId(record.getTaskId());
log.setName(record.getTaskName());
log.setUserId(record.getUserId());
log.setUserName(record.getUserName());
log.setCreateTime(record.getStartTime()); // 使用 startTime 作为时间戳
log.setEndTime(record.getEndTime());
log.setReason(record.getReason());
if ( record.getStatus() != null ) {
log.setStatus(record.getStatus());
}
if ( record.getDuration() != null ) {
log.setDurationInMillis( record.getDuration() );
}
return log;
}).collect(Collectors.toList());
// 4. historicTasks 转换为 TaskTransitionLog
List<TaskTransitionLog> taskLogs = historicTasks.stream()
.map(task -> {
TaskTransitionLog log = new TaskTransitionLog();
log.setId( task.getId() );
log.setName( task.getName() );
log.setUserId( task.getAssignee());
log.setReason( FlowableUtils.getTaskReason(task) ); // 可以从评论或其他字段获取具体原因
//startTime-------------------- Date 转换为 LocalDateTime
Date startDate = task.getStartTime();
if ( startDate != null ) {
LocalDateTime startTime = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
log.setCreateTime(startTime);
}
//endTime---------------------- Date 转换为 LocalDateTime
Date endDate = task.getEndTime();
if ( endDate != null) {
LocalDateTime endTime = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
log.setEndTime( endTime );
}
log.setFormKey( task.getFormKey() );
log.setStatus( FlowableUtils.getTaskStatus(task) );
if ( task.getDurationInMillis() != null ) {
log.setDurationInMillis( task.getDurationInMillis() );
}
return log;
}).collect(Collectors.toList());
// 5. 合并流转记录和任务记录
List<TaskTransitionLog> allLogs = new ArrayList<>();
allLogs.addAll(transitionLogs); // 加入扩展记录
allLogs.addAll(taskLogs); // 加入历史任务记录
// 6. 按时间排序所有记录升序
allLogs.sort(Comparator.comparing(TaskTransitionLog::getCreateTime).thenComparing(TaskTransitionLog::getEndTime));
return allLogs;
}
/**
@ -309,13 +395,51 @@ public class BpmTaskServiceImpl implements BpmTaskService {
// 2.1 查询该任务的前置任务节点的 key 集合
List<UserTask> previousUserList = BpmnModelUtils.getPreviousUserTaskList(source, null, null);
if (CollUtil.isEmpty(previousUserList)) {
return Collections.emptyList();
}
// 2.2 过滤只有串行可到达的节点才可以退回类似非串行子流程无法退回
previousUserList.removeIf(userTask -> !BpmnModelUtils.isSequentialReachable(source, userTask, null));
return previousUserList;
//return Collections.emptyList();
}
// 2.2 过滤只有串行可到达的节点才可以退回类似非串行子流程无法退回
previousUserList.removeIf(userTask -> !BpmnModelUtils.isSequentialReachable(source, userTask, null));
// 3. 获取流程模型中的起始节点开始事件
// FlowElement startElement = getStartEvent(bpmnModel);
// if (startElement != null) {
// // 将起始节点信息转换为 UserTask 对象
// UserTask startUserTask = new UserTask();
// startUserTask.setId(startElement.getId()); // 设置起始节点 ID
// if (startElement.getName().equals("")) {
// startUserTask.setName("开始");
// }else{
// startUserTask.setName(startElement.getName()); // 设置起始节点名称
// }
// startUserTask.setAssignee(""); // 可以为空通常起始节点不直接关联任务的处理人
// startUserTask.setCategory("StartEvent"); // 设置类别为 StartEvent表示这是一个起始节点
//
// // 添加起始节点到 previousUserList
// previousUserList.add(startUserTask);
// // 打印或者记录起始节点信息
// //System.out.println("起始节点: " + startElement.getId() + " - " + startElement.getName());
// }
return previousUserList;
}
/**
* 获取流程模型中的起始节点开始事件
*
* @param bpmnModel 流程模型
* @return 起始节点
*/
private FlowElement getStartEvent(BpmnModel bpmnModel) {
System.out.println("getStartEvent");
// 获取流程的开始事件通常是第一个节点
for (FlowElement flowElement : bpmnModel.getMainProcess().getFlowElements()) {
if (flowElement instanceof StartEvent) {
System.out.println(flowElement);
return flowElement;
}
}
return null; // 如果没有找到起始事件返回 null
}
@Override
public <T extends TaskInfo> List<T> getAllChildrenTaskListByParentTaskId(String parentTaskId, List<T> tasks) {
if (CollUtil.isEmpty(tasks)) {
@ -764,13 +888,13 @@ public class BpmTaskServiceImpl implements BpmTaskService {
.moveExecutionsToSingleActivityId(runExecutionIds, reqVO.getTargetTaskDefinitionKey())
.changeState();
}
@Override
@Transactional(rollbackFor = Exception.class)
public void delegateTask(Long userId, BpmTaskDelegateReqVO reqVO) {
String taskId = reqVO.getId();
// 1.1 校验任务
Task task = validateTask(userId, reqVO.getId());
Date startDate = task.getCreateTime();
if (task.getAssignee().equals(reqVO.getDelegateUserId().toString())) { // 校验当前审批人和被委派人不是同一人
throw exception(TASK_DELEGATE_FAIL_USER_REPEAT);
}
@ -790,13 +914,34 @@ public class BpmTaskServiceImpl implements BpmTaskService {
// 3.2 执行委派将任务委派给 delegateUser
taskService.delegateTask(taskId, reqVO.getDelegateUserId().toString());
// 补充说明委托不单独设置状态如果需要可通过 Task DelegationState 字段判断是否为 DelegationState.PENDING 委托中
LocalDateTime startTime = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().minusSeconds(1);
LocalDateTime endTime = LocalDateTime.now();
Duration duration = Duration.between(startTime, endTime);
long seconds = duration.getSeconds();
//同步更新到流转记录库
taskExtendRecordService.toCreateTaskExtendRecord(
task.getId(),
task.getName()+"("+currentUser.getNickname()+"委托)",
startTime,
endTime,
String.valueOf(userId),
reqVO.getReason(),
duration.getSeconds()*1000,
task.getProcessInstanceId(),
2
);
}
@Override
@DataPermission(enable = false)
public void transferTask(Long userId, BpmTaskTransferReqVO reqVO) {
String taskId = reqVO.getId();
// 1.1 校验任务
Task task = validateTask(userId, reqVO.getId());
Date startDate = task.getCreateTime();
if (task.getAssignee().equals(reqVO.getAssigneeUserId().toString())) { // 校验当前审批人和被转派人不是同一人
throw exception(TASK_TRANSFER_FAIL_USER_REPEAT);
}
@ -816,6 +961,24 @@ public class BpmTaskServiceImpl implements BpmTaskService {
// 3.2 执行转派审批人将任务转派给 assigneeUser
// 委托 delegate和转派transfer的差别就在这块的调用
taskService.setAssignee(taskId, reqVO.getAssigneeUserId().toString());
LocalDateTime startTime = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().minusSeconds(1);
LocalDateTime endTime = LocalDateTime.now();
Duration duration = Duration.between(startTime, endTime);
long seconds = duration.getSeconds();
//同步更新到流转记录库
taskExtendRecordService.toCreateTaskExtendRecord(
task.getId(),
task.getName()+"("+currentUser.getNickname()+"转办)",
startTime,
endTime,
String.valueOf(userId),
reqVO.getReason(),
duration.getSeconds()*1000,
task.getProcessInstanceId(),
2
);
}
@Override
@ -1300,6 +1463,16 @@ public class BpmTaskServiceImpl implements BpmTaskService {
});
});
// 扩展属性
userTask.getExtensionElements().forEach((key, value) -> {
//System.out.println("Extension Key: " + key);
if ( key.equals( itemStr ) ) {
value.forEach(extensionElement -> {
//System.out.println("Extension Value: " + extensionElement.getElementText());
valueStrRef.set( extensionElement.getElementText() );
});
}
});
}
} else {
return "";

View File

@ -0,0 +1,58 @@
package cn.iocoder.yudao.module.bpm.service.taskextendrecord;
import java.time.LocalDateTime;
import java.util.*;
import javax.validation.*;
import cn.iocoder.yudao.module.bpm.controller.admin.taskextendrecord.vo.*;
import cn.iocoder.yudao.module.bpm.dal.dataobject.taskextendrecord.TaskExtendRecordDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
/**
* BPM 流转记录扩展 Service 接口
*
* @author 君风
*/
public interface TaskExtendRecordService {
/**
* 创建BPM 流转记录扩展
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createTaskExtendRecord(@Valid TaskExtendRecordSaveReqVO createReqVO);
void toCreateTaskExtendRecord(String taskId, String taskName, LocalDateTime startTime, LocalDateTime endTime, String userId, String reason, Long duration, String processInstanceId, Integer status) ;
/**
* 更新BPM 流转记录扩展
*
* @param updateReqVO 更新信息
*/
void updateTaskExtendRecord(@Valid TaskExtendRecordSaveReqVO updateReqVO);
/**
* 删除BPM 流转记录扩展
*
* @param id 编号
*/
void deleteTaskExtendRecord(Long id);
/**
* 获得BPM 流转记录扩展
*
* @param id 编号
* @return BPM 流转记录扩展
*/
TaskExtendRecordDO getTaskExtendRecord(Long id);
/**
* 获得BPM 流转记录扩展分页
*
* @param pageReqVO 分页查询
* @return BPM 流转记录扩展分页
*/
PageResult<TaskExtendRecordDO> getTaskExtendRecordPage(TaskExtendRecordPageReqVO pageReqVO);
public List<TaskExtendRecordDO> getTaskExtendRecordsByProcessInstanceId(String taskId);
}

View File

@ -0,0 +1,93 @@
package cn.iocoder.yudao.module.bpm.service.taskextendrecord;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.*;
import cn.iocoder.yudao.module.bpm.controller.admin.taskextendrecord.vo.*;
import cn.iocoder.yudao.module.bpm.dal.dataobject.taskextendrecord.TaskExtendRecordDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.bpm.dal.mysql.taskextendrecord.TaskExtendRecordMapper;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
/**
* BPM 流转记录扩展 Service 实现类
*
* @author 君风
*/
@Service
@Validated
public class TaskExtendRecordServiceImpl implements TaskExtendRecordService {
@Resource
private TaskExtendRecordMapper taskExtendRecordMapper;
@Override
public Long createTaskExtendRecord(TaskExtendRecordSaveReqVO createReqVO) {
// 插入
TaskExtendRecordDO taskExtendRecord = BeanUtils.toBean(createReqVO, TaskExtendRecordDO.class);
taskExtendRecordMapper.insert(taskExtendRecord);
// 返回
return taskExtendRecord.getId();
}
@Override
public void toCreateTaskExtendRecord(String taskId, String taskName, LocalDateTime startTime,LocalDateTime endTime,String userId,String reason,Long duration,String processInstanceId,Integer status) {
// 插入
TaskExtendRecordDO taskExtendRecord = new TaskExtendRecordDO();
taskExtendRecord.setTaskId(taskId);
taskExtendRecord.setTaskName(taskName);
taskExtendRecord.setStartTime( startTime );
taskExtendRecord.setEndTime( endTime );
taskExtendRecord.setUserId( userId );
taskExtendRecord.setReason( reason );
taskExtendRecord.setDuration( duration );
taskExtendRecord.setProcessInstanceId( processInstanceId );
taskExtendRecord.setStatus( status );
taskExtendRecordMapper.insert(taskExtendRecord);
}
@Override
public void updateTaskExtendRecord(TaskExtendRecordSaveReqVO updateReqVO) {
// 校验存在
validateTaskExtendRecordExists(updateReqVO.getId());
// 更新
TaskExtendRecordDO updateObj = BeanUtils.toBean(updateReqVO, TaskExtendRecordDO.class);
taskExtendRecordMapper.updateById(updateObj);
}
@Override
public void deleteTaskExtendRecord(Long id) {
// 校验存在
validateTaskExtendRecordExists(id);
// 删除
taskExtendRecordMapper.deleteById(id);
}
private void validateTaskExtendRecordExists(Long id) {
if (taskExtendRecordMapper.selectById(id) == null) {
throw exception(TASK_EXTEND_RECORD_NOT_EXISTS);
}
}
@Override
public TaskExtendRecordDO getTaskExtendRecord(Long id) {
return taskExtendRecordMapper.selectById(id);
}
@Override
public PageResult<TaskExtendRecordDO> getTaskExtendRecordPage(TaskExtendRecordPageReqVO pageReqVO) {
return taskExtendRecordMapper.selectPage(pageReqVO);
}
@Override
public List<TaskExtendRecordDO> getTaskExtendRecordsByProcessInstanceId(String taskId) {
return taskExtendRecordMapper.getRecordsByProcessInstanceId(taskId);
}
}

View File

@ -0,0 +1,20 @@
package cn.iocoder.yudao.module.bpm.service.taskextendrecord;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class TaskTransitionLog {
private String id; //任务id
private String name; //任务名称
private String actionType; // 起草转办委托
private String userId; // 执行该操作的用户
private String userName; //用户姓名
private LocalDateTime createTime; //开始时间
private LocalDateTime endTime; //结束时间
private String reason; // 操作意见
private String FormKey;
private long durationInMillis; // 操作意见
private int status;
}

View File

@ -1,10 +1,12 @@
package cn.iocoder.yudao.module.home.service.fwgl;
import cn.iocoder.yudao.module.bpm.service.taskextendrecord.TaskExtendRecordService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.*;
import cn.iocoder.yudao.module.home.controller.admin.fwgl.vo.*;
import cn.iocoder.yudao.module.home.dal.dataobject.fwgl.FwglDO;
@ -42,6 +44,9 @@ public class FwglServiceImpl implements FwglService {
@Resource
private FwglMapper fwglMapper;
@Resource
private TaskExtendRecordService taskExtendRecordService;
@Override
public Long saveDraft(Long userId,FwglSaveReqVO createReqVO) {
// 插入
@ -71,6 +76,7 @@ public class FwglServiceImpl implements FwglService {
.setVariables(processInstanceVariables).setBusinessKey(String.valueOf(fwgl.getId()))
.setStartUserSelectAssignees(createReqVO.getStartUserSelectAssignees()));
// 将工作流的编号更新到 OA 请假单中
fwglMapper.updateById(new FwglDO().setId(fwgl.getId()).setProcessInstanceId(processInstanceId));
//同步更新流程待办库
@ -80,6 +86,19 @@ public class FwglServiceImpl implements FwglService {
processInstanceId,
createReqVO.getCurfullpath()
);
//同步更新到流转记录库
// taskExtendRecordService.toCreateTaskExtendRecord(
// processInstanceId,
// "起草",
// LocalDateTime.now().minusSeconds(20),
// LocalDateTime.now().minusSeconds(20),
// String.valueOf(userId),
// "",
// 0L,
// processInstanceId,
// 2
// );
// 返回
return fwgl.getId();
}