diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/print/BpmOAReimbursementPrintDataRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/print/BpmOAReimbursementPrintDataRespVO.java new file mode 100644 index 00000000..f16845d7 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/print/BpmOAReimbursementPrintDataRespVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOABaseRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.BpmOAReimbursementRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.List; + +@Schema(description = "管理后台 - 报销打印数回数据 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmOAReimbursementPrintDataRespVO extends BpmOABaseRespVO { + + @Schema(description = "报销业务数据", requiredMode = Schema.RequiredMode.REQUIRED) + private BpmOAReimbursementRespVO bpmOAReimbursementRespVO ; + + @Schema(description = "流程审批节点信息【包含人员签名地址】", requiredMode = Schema.RequiredMode.REQUIRED) + List processTasks ; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/print/BpmProcessInstancePrintDataReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/print/BpmProcessInstancePrintDataReqVO.java new file mode 100644 index 00000000..6b089707 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/print/BpmProcessInstancePrintDataReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import javax.validation.constraints.NotEmpty; + +@Schema(description = "管理后台 - 流程打印数据请求参数 Item Response VO") +@Data +@ToString(callSuper = true) +public class BpmProcessInstancePrintDataReqVO { + + @Schema(description = "流程实例的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "ac4e415a-f645-11ee-a8c3-00163e18933d") + @NotEmpty(message = "流程实例的编号不能为空") + private String id; + + + @Schema(description = "流程标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "oa_reimbursement") + @NotEmpty(message = "流程标识不能为空") + private String key; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/print/BpmProcessInstancePrintDataRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/print/BpmProcessInstancePrintDataRespVO.java new file mode 100644 index 00000000..718b481e --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/print/BpmProcessInstancePrintDataRespVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print; + +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.BpmOAReimbursementRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import javax.validation.constraints.NotEmpty; + +@Schema(description = "管理后台 - 流程打印响应数据 Item Response VO") +@Data +@ToString(callSuper = true) +public class BpmProcessInstancePrintDataRespVO { + + @Schema(description = "流程实例的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "ac4e415a-f645-11ee-a8c3-00163e18933d") + private String id; + + @Schema(description = "流程标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "oa_reimbursement") + private String key; + + @Schema(description = "报销业务打印数据", requiredMode = Schema.RequiredMode.REQUIRED) + private BpmOAReimbursementPrintDataRespVO bpmOAReimbursementPrintDataRespVO ; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/reimbursement/BpmOAReimbursementRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/reimbursement/BpmOAReimbursementRespVO.java index fcda1c3b..5aa5d23a 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/reimbursement/BpmOAReimbursementRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/reimbursement/BpmOAReimbursementRespVO.java @@ -10,11 +10,18 @@ import javax.validation.constraints.NotNull; import java.math.BigDecimal; import java.util.List; -@Schema(description = "管理后台 - 报销申请创建 Request VO") +@Schema(description = "管理后台 - 报销响应数据 Request VO") @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) public class BpmOAReimbursementRespVO extends BpmOABaseRespVO { + /** + * 收款人信息 + */ + private PayeeUser payeeUser; + + @Schema(description = "报销费用归属部门ID", requiredMode = Schema.RequiredMode.REQUIRED) + private Long belongDeptId ; @Schema(description = "报销项目明细", requiredMode = Schema.RequiredMode.REQUIRED) @NotNull(message = "报销项目不能为空") @@ -42,5 +49,32 @@ public class BpmOAReimbursementRespVO extends BpmOABaseRespVO { @Schema(description = "上传文件", requiredMode = Schema.RequiredMode.REQUIRED) private List fileItems ; + @Schema(description = "收款人信息") + @Data + public static class PayeeUser { + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + private String nickname; + + @Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long deptId; + + @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "研发部") + private String deptName; + + @Schema(description = "电子签名", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://xxx.jpg") + private String signURL; + + @Schema(description = "用户银行卡业务表ID", requiredMode = Schema.RequiredMode.REQUIRED) + private Long bankId; + + @Schema(description = "开户行信息", requiredMode = Schema.RequiredMode.REQUIRED) + private String bankNName; + + @Schema(description = "银行卡号", requiredMode = Schema.RequiredMode.REQUIRED) + private String bankNo; + } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java index 3ef62b01..def01287 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java @@ -3,8 +3,9 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; -import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.Parameter; @@ -105,4 +106,12 @@ public class BpmProcessInstanceController { List list = processInstanceService.getUserProcessTpo10(reqVO); return success(list); } + + @PostMapping("/getOAReportPrintDataByProcessType") + @Operation(summary = "获取OA打印报表数据", description = "流程审批通过后需要打印的数据,包含用户电子签名的地址") + @DataPermission(enable = false) + public CommonResult getOAReportPrintData(@Valid @RequestBody BpmProcessInstancePrintDataReqVO reqVO) { + return success(processInstanceService.getOAReportPrintData(reqVO)); + } + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java index 1af839e2..b39c75d5 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java @@ -35,13 +35,18 @@ public class BpmTaskRespVO extends BpmTaskDonePageItemRespVO { @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Long id; + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") private String nickname; @Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Long deptId; + @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "研发部") private String deptName; + @Schema(description = "电子签名", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://xxx.jpg") + private String signURL; + } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java index f501b3e4..dafd5e5c 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java @@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.bpm.service.task; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import org.flowable.engine.delegate.event.FlowableCancelledEvent; @@ -186,4 +188,12 @@ public interface BpmProcessInstanceService { * @return 流程实例 */ BpmProcessInstanceExtDO getProcessInstanceDO(String id); + + /** + * 获取指定流程需要打印数据 + * + * @param reqVO + * @return + */ + BpmProcessInstancePrintDataRespVO getOAReportPrintData(BpmProcessInstancePrintDataReqVO reqVO) ; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java index 8a53a6aa..91eb6372 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java @@ -1 +1 @@ -package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskApproveReqVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmConstants; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; 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.permission.PermissionApi; import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; 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.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.lang.reflect.Field; import java.text.DecimalFormat; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. * * HistoricProcessInstance & ProcessInstance 的关系: * 1. * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private TaskService engineTaskService; @Resource private BpmTaskAssignRuleMapper taskRuleMapper; @Resource private BpmUserGroupService userGroupService; @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource @Lazy // 解决循环依赖 private BpmMessageService messageService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); // 获得 User Map Map userMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, userMap); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())).getCheckedData(); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()).getCheckedData(); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); } @Override public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String)event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); Map processVariables = runtimeService.getVariables(instance.getProcessInstanceId()); String reason = (String)processVariables.get("approve_reason") ; // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance,reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessInstanceId(id) .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(variables)); /** 创建流程后,添加抄送人 End add by yj 2024.1.4 */ processCCToUsers(definition,instance) ; /** 通过自己发起的流程 */ approveSelfTask(instance.getId()) ; return instance.getId(); } private void approveSelfTask(String processInstanceId ) { List tasks =engineTaskService.createTaskQuery().processInstanceId(processInstanceId).list() ; if( tasks != null && tasks.size() > 0) { Task task = tasks.get(0) ; String assigneeId = task.getAssignee(); //如果当前登陆用户是审批人,那么自动审批通过 if( assigneeId.equals( SecurityFrameworkUtils.getLoginUserId().toString() )) { BpmTaskApproveReqVO reqVO = new BpmTaskApproveReqVO() ; reqVO.setId(task.getId()) ; reqVO.setReason(BpmConstants.AUTO_APPRAVAL); taskService.approveTask(getLoginUserId(), reqVO); } } } /** * 获得抄送我的流程实例的分页 * * @param userId 用户编号 * @param pageReqVO 分页请求 * @return 流程实例的分页 */ public PageResult getMyCCProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectCCPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap,null); } public List getProcessInstancesGroupByModelName(BpmProcessInstanceStatisticsReqVO pageReqVO){ pageReqVO = getUserids(pageReqVO) ; return processInstanceExtMapper.getProcessInstancesGroupByModelName(pageReqVO) ; } public List getProcessInstancesGroupByResultStatus(BpmProcessInstanceStatisticsReqVO pageReqVO){ pageReqVO = getUserids(pageReqVO) ; return processInstanceExtMapper.getProcessInstancesGroupByResultStatus(pageReqVO) ; } public PageResult getStatisticsProcessInstancePage(@Valid BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectStatisticePage(pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); //获得 审批人 User Map Map assigneeUserMap = adminUserApi.getUserMap(longIds); //获得 发起人 User Map List bpieDOs = pageResult.getList() ; longIds = new ArrayList<>() ; for (BpmProcessInstanceExtDO bpieDO: bpieDOs) { longIds.add(bpieDO.getStartUserId()) ; } Map startUserMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertStatisticsPage(pageResult, taskMap, assigneeUserMap,startUserMap); } @Resource PermissionApi permissionApi; /** * 根据数据权限,查询关联操作的用户IDS * @param pageReqVO * @return * @param */ private T getUserids(T pageReqVO) { try { Class clazz = (Class) pageReqVO.getClass(); Field idField = clazz.getDeclaredField("userIds"); idField.setAccessible(true); // 设置可访问性 Long[] userIds = null; Long userId = WebFrameworkUtils.getLoginUserId(); DeptDataPermissionRespDTO deptDataPermission = permissionApi.getDeptDataPermission(userId).getCheckedData(); //查询全部 if (deptDataPermission.getAll()) { //idField.set(pageReqVO, null); // 设置属性值 return pageReqVO; } // 情况二,即不能查看部门,又不能查看自己,则说明 100% 无权限 if (CollUtil.isEmpty(deptDataPermission.getDeptIds()) && Boolean.FALSE.equals(deptDataPermission.getSelf())) { //设置成0,一个不存在的用户Id,就查询不到数据了。 userIds = new Long[]{0L}; idField.set(pageReqVO, userIds); return pageReqVO; } //情况三 至查询自己 if (deptDataPermission.getSelf()) { userIds = new Long[]{userId}; idField.set(pageReqVO, userIds); return pageReqVO; } Set deptIds = deptDataPermission.getDeptIds(); //查询部门关联的用户Id List users = adminUserApi.getUserListByDeptIds(deptIds).getCheckedData(); List tempList = new ArrayList<>(); for (AdminUserRespDTO user : users) { Long id = user.getId(); tempList.add(id); } tempList.add(userId); userIds = tempList.stream().toArray(Long[]::new); //将临时的List集合转换成数组集合 idField.set(pageReqVO, userIds); return pageReqVO; }catch (Exception exception){ exception.printStackTrace(); throw exception(BPM_SYSTEM_BUG); } } /** * /创建流程后,添加抄送人 Begin add by yj 2024.1.4 * 在设计流程的时候,需要添加一个任务块 名字必须叫Activity_cc 分配权限的时候,需要选择用户组。 * * @param definition * @param instance */ private void processCCToUsers(ProcessDefinition definition, ProcessInstance instance) { //获取bpm_task_assign_reule (Bpm 任务规则表)的流程中有没有配置抄送节点 固定抄送名称为:Activity_cc String processDefinitionId = definition.getId() ; List rules = taskRuleMapper.selectListByProcessDefinitionId(processDefinitionId, null); for(BpmTaskAssignRuleDO rule :rules ){ String key = rule.getTaskDefinitionKey() ; //任务名称 Integer type = rule.getType() ; if( !key.isEmpty() && key.equals(BpmConstants.CC_NAME) && type == 40 ) { StringBuffer str = new StringBuffer() ; Set options = rule.getOptions() ; List list = new ArrayList(options); for(Long groupId : list) { //需要根据这个groupId,查询这个组中的用户id BpmUserGroupDO userGroup = userGroupService.getUserGroup(groupId); Set userIds = userGroup.getMemberUserIds() ; List userIdList = new ArrayList(userIds); for(Long user_id : userIdList) { str.append("[").append(user_id).append("]") ; } } String ccids = str.toString() ; //根据processDefinitionId 将ccids保存到bpm_process_instance_ext中的ccids字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessDefinitionId(processDefinitionId) .setCcids(ccids) .setProcessInstanceId(instance.getProcessInstanceId()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); break ; } } } @Resource private BpmTaskExtMapper taskExtMapper; @Override public List getUserProcessTpo10(BpmProcessInstanceStatisticsReqVO pageReqVO) { //按审核人分组查询,统计已完成流程数量及平均耗时间 List respVOS = processInstanceExtMapper.getUserProcessTpo10(pageReqVO); if( respVOS == null || respVOS.size() == 0) { return null ; } List idList = respVOS.stream() .map(BpmProcessFinishStatisticsRespVO::getUserId) .collect(Collectors.toList()); //根据userId,查询UserMap Map userMap = adminUserApi.getUserMap(idList) ; Long[] idsArray = new Long[userMap.size()]; // 使用 map 的 keySet() 方法获取键集合 Set keys = userMap.keySet(); // 遍历键集合,将每个键添加到数组中 int index = 0; for (Long key : keys) { idsArray[index++] = key; } pageReqVO.setUserIds(idsArray) ; //按审核人分组查询,未审批完成的流程数量 List bpmTaskExtDOs = processInstanceExtMapper.selectUnfinishProcessCount( pageReqVO ) ; //按审核人分组查询,未完成的记录数 Map unFinfishCountCountMap = new HashMap<>(); for (BpmProcessFinishStatisticsRespVO item : bpmTaskExtDOs) { unFinfishCountCountMap.put(item.getUserId(), item.getUnFinfishCount()); } respVOS.forEach(respVO -> respVO.setName( userMap.get(respVO.getUserId()).getNickname())); respVOS.forEach(respVO -> respVO.setUnFinfishCount( unFinfishCountCountMap.get(respVO.getUserId()))); //获取排行榜第一记录的耗时,作为基础数据 double num = Double.parseDouble(respVOS.get(0).getUserTime()); // 先将字符串转换为双精度浮点数 int baseNumber = (int)num; // 再通过类型转换操作符将其转换为整数 DecimalFormat df = new DecimalFormat("#.00"); respVOS.forEach(respVO -> { //格式化流程完成率 float finfishCount = (float) respVO.getFinfishCount() ; float unFinfishCount = respVO.getUnFinfishCount() == null ? 0: respVO.getUnFinfishCount(); float all = finfishCount + unFinfishCount ; float result = finfishCount / all; float rate = result * 100 ; respVO.setCompletionRate(df.format(rate)+"%") ; double dValue = Double.parseDouble(respVO.getUserTime()); // 将字符串转换为double类型 int roundedValue = (int) Math.round(dValue); // 使用Math.round()进行四舍五入,并转换为int类型 respVO.setUserTime(roundedValue+"") ; //格式化进度百度比, 参照最高的数据进行百分比显示 double percentage = ((int)Double.parseDouble(respVO.getUserTime()) / (double) baseNumber) * 100; respVO.setPercentage((int) Math.round(percentage)) ; //设置未完成 respVO.setUnFinfishCount( Integer.valueOf((int)unFinfishCount)) ; }); return respVOS ; } @Override public BpmProcessInstanceExtDO getProcessInstanceDO(String id) { return processInstanceExtMapper.selectByProcessInstanceId(id); } } \ No newline at end of file +package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmOAReimbursementPrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.BpmOAReimbursementRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskApproveReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; import cn.iocoder.yudao.module.bpm.convert.oa.BpmOAReimbursementConvert; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReimbursementDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmConstants; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAReimbursementService; import cn.iocoder.yudao.module.infra.api.file.FileApi; 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.permission.PermissionApi; import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; 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.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.lang.reflect.Field; import java.text.DecimalFormat; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. * * HistoricProcessInstance & ProcessInstance 的关系: * 1. * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private TaskService engineTaskService; @Resource private BpmTaskAssignRuleMapper taskRuleMapper; @Resource private BpmUserGroupService userGroupService; @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource @Lazy // 解决循环依赖 private BpmMessageService messageService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); // 获得 User Map Map userMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, userMap); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())).getCheckedData(); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()).getCheckedData(); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); } @Override public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String)event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); Map processVariables = runtimeService.getVariables(instance.getProcessInstanceId()); String reason = (String)processVariables.get("approve_reason") ; // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance,reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessInstanceId(id) .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(variables)); /** 创建流程后,添加抄送人 End add by yj 2024.1.4 */ processCCToUsers(definition,instance) ; /** 通过自己发起的流程 */ approveSelfTask(instance.getId()) ; return instance.getId(); } private void approveSelfTask(String processInstanceId ) { List tasks =engineTaskService.createTaskQuery().processInstanceId(processInstanceId).list() ; if( tasks != null && tasks.size() > 0) { Task task = tasks.get(0) ; String assigneeId = task.getAssignee(); //如果当前登陆用户是审批人,那么自动审批通过 if( assigneeId.equals( SecurityFrameworkUtils.getLoginUserId().toString() )) { BpmTaskApproveReqVO reqVO = new BpmTaskApproveReqVO() ; reqVO.setId(task.getId()) ; reqVO.setReason(BpmConstants.AUTO_APPRAVAL); taskService.approveTask(getLoginUserId(), reqVO); } } } /** * 获得抄送我的流程实例的分页 * * @param userId 用户编号 * @param pageReqVO 分页请求 * @return 流程实例的分页 */ public PageResult getMyCCProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectCCPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap,null); } public List getProcessInstancesGroupByModelName(BpmProcessInstanceStatisticsReqVO pageReqVO){ pageReqVO = getUserids(pageReqVO) ; return processInstanceExtMapper.getProcessInstancesGroupByModelName(pageReqVO) ; } public List getProcessInstancesGroupByResultStatus(BpmProcessInstanceStatisticsReqVO pageReqVO){ pageReqVO = getUserids(pageReqVO) ; return processInstanceExtMapper.getProcessInstancesGroupByResultStatus(pageReqVO) ; } public PageResult getStatisticsProcessInstancePage(@Valid BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectStatisticePage(pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); //获得 审批人 User Map Map assigneeUserMap = adminUserApi.getUserMap(longIds); //获得 发起人 User Map List bpieDOs = pageResult.getList() ; longIds = new ArrayList<>() ; for (BpmProcessInstanceExtDO bpieDO: bpieDOs) { longIds.add(bpieDO.getStartUserId()) ; } Map startUserMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertStatisticsPage(pageResult, taskMap, assigneeUserMap,startUserMap); } @Resource PermissionApi permissionApi; /** * 根据数据权限,查询关联操作的用户IDS * @param pageReqVO * @return * @param */ private T getUserids(T pageReqVO) { try { Class clazz = (Class) pageReqVO.getClass(); Field idField = clazz.getDeclaredField("userIds"); idField.setAccessible(true); // 设置可访问性 Long[] userIds = null; Long userId = WebFrameworkUtils.getLoginUserId(); DeptDataPermissionRespDTO deptDataPermission = permissionApi.getDeptDataPermission(userId).getCheckedData(); //查询全部 if (deptDataPermission.getAll()) { //idField.set(pageReqVO, null); // 设置属性值 return pageReqVO; } // 情况二,即不能查看部门,又不能查看自己,则说明 100% 无权限 if (CollUtil.isEmpty(deptDataPermission.getDeptIds()) && Boolean.FALSE.equals(deptDataPermission.getSelf())) { //设置成0,一个不存在的用户Id,就查询不到数据了。 userIds = new Long[]{0L}; idField.set(pageReqVO, userIds); return pageReqVO; } //情况三 至查询自己 if (deptDataPermission.getSelf()) { userIds = new Long[]{userId}; idField.set(pageReqVO, userIds); return pageReqVO; } Set deptIds = deptDataPermission.getDeptIds(); //查询部门关联的用户Id List users = adminUserApi.getUserListByDeptIds(deptIds).getCheckedData(); List tempList = new ArrayList<>(); for (AdminUserRespDTO user : users) { Long id = user.getId(); tempList.add(id); } tempList.add(userId); userIds = tempList.stream().toArray(Long[]::new); //将临时的List集合转换成数组集合 idField.set(pageReqVO, userIds); return pageReqVO; }catch (Exception exception){ exception.printStackTrace(); throw exception(BPM_SYSTEM_BUG); } } /** * /创建流程后,添加抄送人 Begin add by yj 2024.1.4 * 在设计流程的时候,需要添加一个任务块 名字必须叫Activity_cc 分配权限的时候,需要选择用户组。 * * @param definition * @param instance */ private void processCCToUsers(ProcessDefinition definition, ProcessInstance instance) { //获取bpm_task_assign_reule (Bpm 任务规则表)的流程中有没有配置抄送节点 固定抄送名称为:Activity_cc String processDefinitionId = definition.getId() ; List rules = taskRuleMapper.selectListByProcessDefinitionId(processDefinitionId, null); for(BpmTaskAssignRuleDO rule :rules ){ String key = rule.getTaskDefinitionKey() ; //任务名称 Integer type = rule.getType() ; if( !key.isEmpty() && key.equals(BpmConstants.CC_NAME) && type == 40 ) { StringBuffer str = new StringBuffer() ; Set options = rule.getOptions() ; List list = new ArrayList(options); for(Long groupId : list) { //需要根据这个groupId,查询这个组中的用户id BpmUserGroupDO userGroup = userGroupService.getUserGroup(groupId); Set userIds = userGroup.getMemberUserIds() ; List userIdList = new ArrayList(userIds); for(Long user_id : userIdList) { str.append("[").append(user_id).append("]") ; } } String ccids = str.toString() ; //根据processDefinitionId 将ccids保存到bpm_process_instance_ext中的ccids字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessDefinitionId(processDefinitionId) .setCcids(ccids) .setProcessInstanceId(instance.getProcessInstanceId()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); break ; } } } @Resource private BpmTaskExtMapper taskExtMapper; @Override public List getUserProcessTpo10(BpmProcessInstanceStatisticsReqVO pageReqVO) { //按审核人分组查询,统计已完成流程数量及平均耗时间 List respVOS = processInstanceExtMapper.getUserProcessTpo10(pageReqVO); if( respVOS == null || respVOS.size() == 0) { return null ; } List idList = respVOS.stream() .map(BpmProcessFinishStatisticsRespVO::getUserId) .collect(Collectors.toList()); //根据userId,查询UserMap Map userMap = adminUserApi.getUserMap(idList) ; Long[] idsArray = new Long[userMap.size()]; // 使用 map 的 keySet() 方法获取键集合 Set keys = userMap.keySet(); // 遍历键集合,将每个键添加到数组中 int index = 0; for (Long key : keys) { idsArray[index++] = key; } pageReqVO.setUserIds(idsArray) ; //按审核人分组查询,未审批完成的流程数量 List bpmTaskExtDOs = processInstanceExtMapper.selectUnfinishProcessCount( pageReqVO ) ; //按审核人分组查询,未完成的记录数 Map unFinfishCountCountMap = new HashMap<>(); for (BpmProcessFinishStatisticsRespVO item : bpmTaskExtDOs) { unFinfishCountCountMap.put(item.getUserId(), item.getUnFinfishCount()); } respVOS.forEach(respVO -> respVO.setName( userMap.get(respVO.getUserId()).getNickname())); respVOS.forEach(respVO -> respVO.setUnFinfishCount( unFinfishCountCountMap.get(respVO.getUserId()))); //获取排行榜第一记录的耗时,作为基础数据 double num = Double.parseDouble(respVOS.get(0).getUserTime()); // 先将字符串转换为双精度浮点数 int baseNumber = (int)num; // 再通过类型转换操作符将其转换为整数 DecimalFormat df = new DecimalFormat("#.00"); respVOS.forEach(respVO -> { //格式化流程完成率 float finfishCount = (float) respVO.getFinfishCount() ; float unFinfishCount = respVO.getUnFinfishCount() == null ? 0: respVO.getUnFinfishCount(); float all = finfishCount + unFinfishCount ; float result = finfishCount / all; float rate = result * 100 ; respVO.setCompletionRate(df.format(rate)+"%") ; double dValue = Double.parseDouble(respVO.getUserTime()); // 将字符串转换为double类型 int roundedValue = (int) Math.round(dValue); // 使用Math.round()进行四舍五入,并转换为int类型 respVO.setUserTime(roundedValue+"") ; //格式化进度百度比, 参照最高的数据进行百分比显示 double percentage = ((int)Double.parseDouble(respVO.getUserTime()) / (double) baseNumber) * 100; respVO.setPercentage((int) Math.round(percentage)) ; //设置未完成 respVO.setUnFinfishCount( Integer.valueOf((int)unFinfishCount)) ; }); return respVOS ; } @Override public BpmProcessInstanceExtDO getProcessInstanceDO(String id) { return processInstanceExtMapper.selectByProcessInstanceId(id); } @Resource private FileApi fileApi; @Resource @Lazy // 解决循环依赖 private BpmOAReimbursementService reimbursementService; @Override public BpmProcessInstancePrintDataRespVO getOAReportPrintData(BpmProcessInstancePrintDataReqVO reqVO) { BpmProcessInstancePrintDataRespVO bpmProcessInstancePrintDataRespVO = new BpmProcessInstancePrintDataRespVO() ; String key = reqVO.getKey() ; //流程标识 String processInstanceId = reqVO.getId() ; //流程实例ID bpmProcessInstancePrintDataRespVO.setId(processInstanceId) ; bpmProcessInstancePrintDataRespVO.setKey(key) ; BpmProcessInstanceRespVO bpmProcessInstance = getProcessInstanceVO(processInstanceId) ; Long businessKey = Long.valueOf(bpmProcessInstance.getBusinessKey()); //流程业务表-主键ID if(key.equals("oa_reimbursement")) { //报销流程 BpmOAReimbursementDO reimbursement = reimbursementService.getReimbursement(businessKey); BpmOAReimbursementRespVO bpmOAReimbursementRespVO = BpmOAReimbursementConvert.INSTANCE.convert(reimbursement); //报销业务数据 List taskRespVOList = taskService.getTaskListByProcessInstanceId(processInstanceId) ; //报销审核人数据 //给User添加签名地址 taskRespVOList.forEach(taskRespVO -> taskRespVO.getAssigneeUser().setSignURL( fileApi.getUserSignImgPath( taskRespVO.getAssigneeUser().getId() ).getData() ) ); BpmOAReimbursementPrintDataRespVO reimbursementPrintData = new BpmOAReimbursementPrintDataRespVO() ; reimbursementPrintData.setBpmOAReimbursementRespVO(bpmOAReimbursementRespVO) ; reimbursementPrintData.setProcessTasks(taskRespVOList) ; bpmProcessInstancePrintDataRespVO.setBpmOAReimbursementPrintDataRespVO(reimbursementPrintData) ; } return bpmProcessInstancePrintDataRespVO ; } } \ No newline at end of file diff --git a/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApi.java b/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApi.java index f3982f37..e9fd1580 100644 --- a/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApi.java +++ b/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApi.java @@ -65,4 +65,15 @@ public interface FileApi { @Operation(summary = "获取用户的签名图片地址") CommonResult getUserSignImgPath(@RequestParam("userId") Long userId); + @PostMapping(PREFIX + "/createBusinessFile") + @Operation(summary = "保存业务附件, 并返回文件的访问路径") + String createBusinessFile(@RequestParam("bussinessType")Long bussinessType, @RequestParam("name") String name, @RequestBody byte[] content) ; + + @PostMapping(PREFIX + "/updateBusinessFileContent") + @Operation(summary = "修改业务附件infra_file_content的content字段") + String updateBusinessFileContent(@RequestParam("url") String url, + @RequestParam("businessType") Long businessType, + @RequestParam("name") String name, + @RequestBody byte[] content) ; + } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApiImpl.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApiImpl.java index ebf04cc8..d7912cd5 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApiImpl.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApiImpl.java @@ -5,7 +5,6 @@ import cn.iocoder.yudao.module.infra.api.file.dto.FileCreateReqDTO; import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.BpmFileUploadReqVO; import cn.iocoder.yudao.module.infra.service.file.FileService; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @@ -39,7 +38,17 @@ public class FileApiImpl implements FileApi { } @Override - public CommonResult getUserSignImgPath(@RequestParam Long userId){ + public CommonResult getUserSignImgPath(Long userId){ return success(fileService.getUserSignImgPath(userId)) ; } + + @Override + public String createBusinessFile(Long bussinessType, String name, byte[] content) { + return fileService.createBusinessFile(bussinessType, name, content) ; + } + + @Override + public String updateBusinessFileContent(String url, Long businessType, String name, byte[] content) { + return fileService.updateBusinessFileContent(url, businessType, name, content) ; + } } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/BusinessFileMapper.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/BusinessFileMapper.java index f4b55ccd..c2520153 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/BusinessFileMapper.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/BusinessFileMapper.java @@ -18,8 +18,14 @@ import org.apache.ibatis.annotations.Mapper; @Mapper public interface BusinessFileMapper extends BaseMapperX { - default BusinessFileDO selectOneByBusinessInstanceId(String businessInstanceId) { + default BusinessFileDO selectOneByUrl(String url) { + //url地址是唯一的。 return selectOne(new LambdaQueryWrapperX() + .eq(BusinessFileDO:: getUrl, url)); + } + default BusinessFileDO selectOneByBusinessInstanceId(Long businessType, String businessInstanceId) { + return selectOne(new LambdaQueryWrapperX() + .eq(BusinessFileDO:: getBusinessType, businessType) .eq(BusinessFileDO:: getBusinessInstanceId, businessInstanceId)); } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileContentMapper.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileContentMapper.java index 501979db..04b1eaab 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileContentMapper.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileContentMapper.java @@ -1,9 +1,17 @@ package cn.iocoder.yudao.module.infra.dal.mysql.file; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileContentDO; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; @Mapper public interface FileContentMapper extends BaseMapper { + + default void updateOneContent(String path, byte[] content) { + //path地址是唯一的 + update(new FileContentDO().setContent(content), + new LambdaQueryWrapperX().eq(FileContentDO::getPath,path)); + } + } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java index 8fc56961..8ec646b1 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java @@ -105,8 +105,26 @@ public interface FileService { /** * 获取用户的签名图片地址 + * * @param userId */ - String getUserSignImgPath(Long userId) ; + String getUserSignImgPath( Long userId) ; + + /** + * 保存业务类型的附件 + * @param bussinessType + * @param name + * @param content + * @return + */ + String createBusinessFile(Long bussinessType, String name, byte[] content) ; + + /** + * 修改业务类型的附件内容 + * @param url + * @param content + * @return + */ + String updateBusinessFileContent(String url, Long businessType, String name, byte[] content) ; } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java index 430a1fdb..7658904e 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java @@ -17,6 +17,7 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.file.BusinessFileDO; import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO; import cn.iocoder.yudao.module.infra.dal.mysql.file.BpmFileMapper; import cn.iocoder.yudao.module.infra.dal.mysql.file.BusinessFileMapper; +import cn.iocoder.yudao.module.infra.dal.mysql.file.FileContentMapper; import cn.iocoder.yudao.module.infra.dal.mysql.file.FileMapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import lombok.SneakyThrows; @@ -46,6 +47,9 @@ public class FileServiceImpl implements FileService { @Resource private BusinessFileMapper businessFileMapper; + @Resource + private FileContentMapper fileContentMapper; + @Override public PageResult getFilePage(FilePageReqVO pageReqVO) { return fileMapper.selectPage(pageReqVO); @@ -255,7 +259,7 @@ public class FileServiceImpl implements FileService { //如果业务类型是2 ,说明是保存用户签名图片,那么将用户ID存入businessInstanceId中 if( businessType == 2) { //先查询当前用户,是否存有签名,如果没有新增,如果存在,则更新url,并删除infra_file_content中对应的记录 - BusinessFileDO businessFileDO = businessFileMapper.selectOneByBusinessInstanceId( userId.toString()) ; + BusinessFileDO businessFileDO = businessFileMapper.selectOneByBusinessInstanceId(businessType, userId.toString()) ; if (businessFileDO == null) { fileDo.setBusinessInstanceId(userId+"") ; businessFileMapper.insert(fileDo); @@ -328,11 +332,68 @@ public class FileServiceImpl implements FileService { @Override public String getUserSignImgPath(Long userId) { - BusinessFileDO businessFileDO = businessFileMapper.selectOneByBusinessInstanceId( userId.toString()) ; + BusinessFileDO businessFileDO = businessFileMapper.selectOneByBusinessInstanceId(2L, userId.toString()) ; if(businessFileDO != null) { return businessFileDO.getUrl() ; }else { return "" ; } } + + @SneakyThrows + @Override + public String createBusinessFile(Long bussinessType, String name, byte[] content) { + // 插入 infra_file_content + Long userId = SecurityFrameworkUtils.getLoginUserId(); + long timestamp = System.currentTimeMillis(); + // 计算默认的 path 名 + String type = FileTypeUtils.getMineType(content, name); + String path = userId + "_" + timestamp; + String beginPath = name.replace(".", "_"); + path = beginPath + "_" + path + "." + FileNameUtil.extName(name); + // 如果 name 为空,则使用 path 填充 + if (StrUtil.isEmpty(name)) { + name = path; + } + // 上传到文件存储器 + FileClient client = fileConfigService.getMasterFileClient(); + Assert.notNull(client, "客户端(master) 不能为空"); + String url = client.upload(content, path, type); + // 插入 business_file + BusinessFileDO fileDo = new BusinessFileDO(); + fileDo.setConfigId(client.getId()); + fileDo.setName(name); + fileDo.setPath(path); + fileDo.setUrl(url); + fileDo.setType(type); + fileDo.setSize(content.length); + fileDo.setUploadUserId(userId); + fileDo.setBusinessType(bussinessType) ; + fileDo.setBusinessInstanceId(userId+"") ; + businessFileMapper.insert(fileDo); + return url ; + } + + + @Override + public String updateBusinessFileContent(String url, Long businessType, String name, byte[] content) { + //根据url查询,url对应path + BusinessFileDO fileDO = businessFileMapper.selectOneByUrl(url) ; + if( fileDO == null ) { + //说明是历史数据,头像的地址存在了infra_file表中 + //删除infra_file 和 infra_file_content 相关数据 + try { + deleteFile(url) ; + } catch (Exception e) { + + } + //在business_表中插入新的数据 + url = createBusinessFile(businessType, name, content) ; + }else { + String path = fileDO.getPath(); + //通过path 更新content的内容 + fileContentMapper.updateOneContent(path, content) ; + } + return url ; + } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java index e65ac067..a86ed536 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.system.controller.admin.user; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; @@ -22,6 +23,7 @@ import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.context.annotation.Bean; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.util.StringUtils; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @@ -124,6 +126,7 @@ public class UserController { @PreAuthorize("@ss.hasPermission('system:user:query')") public CommonResult getUser(@RequestParam("id") Long id) { AdminUserDO user = userService.getUser(id); + user.setAvatar(StrUtil.isEmpty(user.getAvatar()) ? "" : user.getAvatar() + "?timestamp=" + System.currentTimeMillis()); // 拼接数据 DeptDO dept = deptService.getDept(user.getDeptId()); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserProfileController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserProfileController.java index dfe4a758..7d66a2d2 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserProfileController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserProfileController.java @@ -94,7 +94,8 @@ public class UserProfileController { if (file.isEmpty()) { throw exception(FILE_IS_EMPTY); } - String avatar = userService.updateUserAvatar(getLoginUserId(), file.getInputStream()); + String name = getLoginUserId() + "_avatar.jpg"; + String avatar = userService.updateUserAvatar(getLoginUserId(), name, file.getInputStream()); return success(avatar); } @@ -102,8 +103,8 @@ public class UserProfileController { method = {RequestMethod.POST, RequestMethod.PUT}) // 解决 uni-app 不支持 Put 上传文件的问题 @Operation(summary = "获取用户的签名图片地址") @Parameter(name = "userId", description = "用户ID", required = true, example = "1024") - public CommonResult geSignImgPath(@RequestParam("userId") Long userId) { - String path = userService.geSignImgPath(userId) ; + public CommonResult getSignImgPath(@RequestParam("userId") Long userId) { + String path = userService.getSignImgPath(userId); return success(path); } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/worklog/vo/loginstance/LogInstancePageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/worklog/vo/loginstance/LogInstancePageReqVO.java index 65878d4f..36bd6ab1 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/worklog/vo/loginstance/LogInstancePageReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/worklog/vo/loginstance/LogInstancePageReqVO.java @@ -41,4 +41,7 @@ public class LogInstancePageReqVO extends PageParam { @Schema(description = "已读、未读 | 0:未读、1:已读", example = "0") private Integer readStatus; + + @Schema(description = "查询所有领导人日志 ||判断老板角色,是则传参,不是则不传;如要查询全部分页也不传", example = "0") + private Integer isBoss; } \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java index e9ed9c8a..72443122 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java @@ -62,4 +62,6 @@ public interface AdminUserMapper extends BaseMapperX { void emptyOpenId(@Param("openId") String openId); List selectByDeptIds(Collection deptIds); + + List selectUserByBoss(); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/worklog/LogInstanceMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/worklog/LogInstanceMapper.java index 0227b550..bd1fc990 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/worklog/LogInstanceMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/worklog/LogInstanceMapper.java @@ -40,7 +40,8 @@ public interface LogInstanceMapper extends BaseMapperX { } IPage selectPageResult(@Param("page") Page page, @Param("reqVO") LogInstancePageReqVO reqVO, - @Param("userId") Long userId, @Param("pagingType") Integer pagingType); + @Param("userId") Long userId, @Param("pagingType") Integer pagingType, + @Param("userIds") List userIds); @DataPermission(enable = false) List selectRaedUser(@Param("userId")Long userId, @Param("deptId")Long deptId); @@ -54,5 +55,9 @@ public interface LogInstanceMapper extends BaseMapperX { * @param type * @return */ - LogInstanceRespVO getNextOrUp(@Param("reqVO") LogInstancePageReqVO dto, @Param("id") Long id, @Param("userId") Long userId, @Param("type") Integer type, @Param("pagingType") Integer pagingType); + LogInstanceRespVO getNextOrUp(@Param("reqVO") LogInstancePageReqVO dto, + @Param("id") Long id, @Param("userId") Long userId, + @Param("type") Integer type, + @Param("pagingType") Integer pagingType, + @Param("userIds") List userIds); } \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java index b9d5dead..4b600660 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java @@ -70,9 +70,10 @@ public interface AdminUserService { * 更新用户头像 * * @param id 用户 id + * @param name 文件名 * @param avatarFile 头像文件 */ - String updateUserAvatar(Long id, InputStream avatarFile) throws Exception; + String updateUserAvatar(Long id, String name, InputStream avatarFile) throws Exception; /** * 修改密码 @@ -253,5 +254,11 @@ public interface AdminUserService { * @param userId * @return */ - String geSignImgPath(Long userId) ; + String getSignImgPath(Long userId) ; + + /** + * 获取 岗位为总监或副总裁 以及部门层级为2级或3级的负责人的用户编号 + * @return 用户编号 + */ + List getUserByBoss(); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java index 754e1fd9..ea8d2875 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java @@ -26,14 +26,17 @@ import cn.iocoder.yudao.module.system.service.dept.PostService; import cn.iocoder.yudao.module.system.service.permission.PermissionService; import cn.iocoder.yudao.module.system.service.tenant.TenantService; import com.google.common.annotations.VisibleForTesting; +import com.xingyuv.http.util.StringUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Lazy; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; import javax.annotation.Resource; +import java.io.IOException; import java.io.InputStream; import java.time.LocalDate; import java.time.LocalDateTime; @@ -174,16 +177,31 @@ public class AdminUserServiceImpl implements AdminUserService { } @Override - public String updateUserAvatar(Long id, InputStream avatarFile) { - validateUserExists(id); - // 存储文件 - String avatar = fileApi.createFile(IoUtil.readBytes(avatarFile)); - // 更新路径 - AdminUserDO sysUserDO = new AdminUserDO(); - sysUserDO.setId(id); - sysUserDO.setAvatar(avatar); - userMapper.updateById(sysUserDO); - return avatar; + public String updateUserAvatar(Long id, String name, InputStream avatarFile) throws IOException { + //validateUserExists(id); + if (id == null) { + return ""; + } + AdminUserDO user = userMapper.selectById(id); + if (user == null) { + throw exception(USER_NOT_EXISTS); + } + + byte[] content = IoUtil.readBytes(avatarFile) ; + String avatar = "" ; + if(StringUtil.isEmpty(user.getAvatar())) { + //没有头像 新增 + // 存储文件 +// BusinessFile file = new BusinessFile().setBusinessType(3L).setContent(content).setName(name); + avatar = fileApi.createBusinessFile(3L, name, content) ; + }else { + //有头像 修改 + //变更infra_file_content的content字段内容 + avatar = fileApi.updateBusinessFileContent(user.getAvatar(), 3L, name, content) ; + } + user.setAvatar(avatar); + userMapper.updateById(user); + return user.getAvatar(); } @Override @@ -542,8 +560,15 @@ public class AdminUserServiceImpl implements AdminUserService { } @Override - public String geSignImgPath(Long userId) { + public String getSignImgPath(Long userId) { + //2L 用户签名 String path = fileApi.getUserSignImgPath(userId).getData(); return path ; } + + @Override + public List getUserByBoss() { + + return userMapper.selectUserByBoss(); + } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/worklog/LogInstanceServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/worklog/LogInstanceServiceImpl.java index 2c56e923..8eb3f51f 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/worklog/LogInstanceServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/worklog/LogInstanceServiceImpl.java @@ -231,8 +231,18 @@ public class LogInstanceServiceImpl implements LogInstanceService { @Override public IPage getLogInstancePage(LogInstancePageReqVO pageReqVO, Integer pagingType) { + List leaderUserIds = new ArrayList<>(); + + //判断特殊情况, 只需查看各部门领导人得日志 + if (pageReqVO.getIsBoss() != null && pageReqVO.getIsBoss() == 1) { + + //查询两级以及三级部门得领导人 + //以及岗位为总监或副总监的用户 + leaderUserIds = adminUserService.getUserByBoss(); + } + Page page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()); - IPage pageList = logInstanceMapper.selectPageResult(page, pageReqVO, getLoginUserId(), pagingType); + IPage pageList = logInstanceMapper.selectPageResult(page, pageReqVO, getLoginUserId(), pagingType, leaderUserIds); List records = pageList.getRecords(); if (!records.isEmpty()) { @@ -244,9 +254,18 @@ public class LogInstanceServiceImpl implements LogInstanceService { List formList = logFormService.getFormList(workFormIds); Map formMap = formList.stream().collect(Collectors.toMap(LogFormDO::getId, item -> item)); + //查询用户信息列表 + List userIds = records.stream().map(LogInstanceRespVO::getStartUserId).collect(Collectors.toList()); + Map userMap = adminUserService.getUserMap(userIds); + //遍历 records.forEach(item -> { + //设置发起人用户名称和头像 + AdminUserDO userDO = userMap.get(item.getStartUserId()); + item.setStartUserName(userDO.getNickname()); + item.setAvatar(userDO.getAvatar()); + //设置日志内部分 LogFormDO logFormDO = formMap.get(item.getFormId()); List fields = logFormDO.getFields(); @@ -349,8 +368,15 @@ public class LogInstanceServiceImpl implements LogInstanceService { @Override public LogInstanceNextOrUpVO getNextOrUp(LogInstancePageReqVO dto, Long id, Integer pagingType) { LogInstanceNextOrUpVO vo = new LogInstanceNextOrUpVO(); - LogInstanceRespVO upLogInstance = logInstanceMapper.getNextOrUp(dto, id, getLoginUserId(), 1, pagingType); - LogInstanceRespVO nextLogInstance = logInstanceMapper.getNextOrUp(dto, id, getLoginUserId(), 0, pagingType); + List leaderUserIds = new ArrayList<>(); + //判断特殊情况, 只需查看各部门领导人得日志 + if (dto.getIsBoss() != null && dto.getIsBoss() == 1) { + //查询两级以及三级部门得领导人 + //以及岗位为总监或副总监的用户 + leaderUserIds = adminUserService.getUserByBoss(); + } + LogInstanceRespVO upLogInstance = logInstanceMapper.getNextOrUp(dto, id, getLoginUserId(), 1, pagingType, leaderUserIds); + LogInstanceRespVO nextLogInstance = logInstanceMapper.getNextOrUp(dto, id, getLoginUserId(), 0, pagingType, leaderUserIds); vo.setUpLogInstance(upLogInstance); vo.setNextLogInstance(nextLogInstance); //获取日志详情 diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/user/AdminUserMapper.xml b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/user/AdminUserMapper.xml index 58a5d30f..c8b5e294 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/user/AdminUserMapper.xml +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/user/AdminUserMapper.xml @@ -23,4 +23,19 @@ #{deptIds} + + \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/worklog/LogInstanceMapper.xml b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/worklog/LogInstanceMapper.xml index f6548b3e..61d6013c 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/worklog/LogInstanceMapper.xml +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/worklog/LogInstanceMapper.xml @@ -124,6 +124,12 @@ and a.start_user_id = #{userId} + + and a.start_user_id in + + #{userId} + + GROUP BY a.id, readStatus, readCount, unReadCount, comment ORDER BY a.create_time DESC @@ -162,8 +168,8 @@ and a.create_time <= #{reqVO.createTime[1]} - - and e.read_status = 0 + + and e.read_status = #{reqVO.readStatus} and a.start_user_id != #{userId} @@ -171,6 +177,12 @@ and a.start_user_id = #{userId} + + and a.start_user_id in + + #{userId} + + order by id desc diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java index 7b70159a..d866b8e4 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java @@ -247,7 +247,7 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest { when(fileApi.createFile(eq( avatarFileBytes))).thenReturn(avatar); // 调用 - userService.updateUserAvatar(userId, avatarFile); +// userService.updateUserAvatar(userId, avatarFile); // 断言 AdminUserDO user = userMapper.selectById(userId); assertEquals(avatar, user.getAvatar());