From ec121d4bb3e8d31bf6a8c6ee6fff1e9a211b7f3d Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Thu, 4 Jul 2024 18:24:32 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E5=85=A5=E8=81=8C=E7=94=B3=E8=AF=B7=20?= =?UTF-8?q?=E9=80=9A=E8=BF=87=E5=90=8E=20=E8=87=AA=E5=8A=A8=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E6=96=B0=E5=85=A5=E8=81=8C=E5=91=98=E5=B7=A5=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E8=87=B3=20=20=20=E7=94=A8=E6=88=B7=E8=A1=A8=E3=80=81?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E6=8B=93=E5=B1=95=E8=A1=A8=20=E5=B9=B6?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=20=E7=94=A8=E6=88=B7=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E7=AD=89=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/oa/BpmOAEntryController.java | 25 +++- .../admin/oa/vo/entry/BpmOAEntryRespVO.java | 3 + .../admin/upload/UploadUserFile.java | 9 +- .../rpc/config/RpcConfiguration.java | 3 +- .../bpm/service/oa/BpmOAEntryService.java | 5 +- .../bpm/service/oa/BpmOAEntryServiceImpl.java | 115 ++++++++++++++++-- .../oa/listener/BpmOAEntryResultListener.java | 2 +- .../task/BpmProcessInstanceServiceImpl.java | 2 +- .../bpm/service/task/BpmTaskService.java | 14 +++ .../bpm/service/task/BpmTaskServiceImpl.java | 8 ++ 10 files changed, 165 insertions(+), 21 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOAEntryController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOAEntryController.java index a0f06ec2..b1783c76 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOAEntryController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOAEntryController.java @@ -1,11 +1,15 @@ package cn.iocoder.yudao.module.bpm.controller.admin.oa; +import cn.hutool.core.collection.CollectionUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.entry.BpmOAEntryCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.entry.BpmOAEntryRespVO; import cn.iocoder.yudao.module.bpm.convert.oa.BpmOAEntryConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAEntryDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; +import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAEntryService; +import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.PostApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; @@ -19,6 +23,7 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.annotation.security.PermitAll; import javax.validation.Valid; +import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -42,6 +47,9 @@ public class BpmOAEntryController { @Resource private PostApi postApi; + @Resource + private BpmTaskService bpmTaskService; + @PostMapping("/create") @Operation(summary = "创建请求申请") @PermitAll @@ -66,13 +74,24 @@ public class BpmOAEntryController { @PermitAll public CommonResult getEntryByOpenId(@RequestParam("openId") String openId) { - BpmOAEntryDO entry = entryService.getEntryByOpenId(openId); + // 查询当前openId 是否存在 + List entryList = entryService.getEntryByOpenId(openId); - if (entry == null) { + if (CollectionUtil.isEmpty(entryList)) { return success(null); } + BpmOAEntryDO entry = entryList.get(0); BpmOAEntryRespVO respVO = BpmOAEntryConvert.INSTANCE.convert(entry); + if (entry.getResult().equals(BpmProcessInstanceResultEnum.REJECT.getResult())) { + + // 获得取消流程的 task + BpmTaskExtDO taskExtDO = bpmTaskService.getTaskByProcessInstanceIdAndResult(entry.getProcessInstanceId(), + BpmProcessInstanceResultEnum.REJECT.getResult()); + + respVO.setRemark(taskExtDO.getReason()); + } + // 设备部门名称 respVO.setEntryDeptName(getDept(entry.getEntryDeptId()).getName()); // 设备岗位名称 @@ -97,7 +116,7 @@ public class BpmOAEntryController { /** * 获得岗位信息 * @param postId 岗位ID - * @return + * @return 岗位信息 */ public PostRespVO getPost(Long postId) { diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/entry/BpmOAEntryRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/entry/BpmOAEntryRespVO.java index 9544f15c..16d84cc6 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/entry/BpmOAEntryRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/entry/BpmOAEntryRespVO.java @@ -62,4 +62,7 @@ public class BpmOAEntryRespVO extends BpmOABaseRespVO { @Schema(description = "上传文件", requiredMode = Schema.RequiredMode.REQUIRED) private List fileItems; + + @Schema(description = "备注") + private String remark; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/upload/UploadUserFile.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/upload/UploadUserFile.java index eba2f3ea..04851e7b 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/upload/UploadUserFile.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/upload/UploadUserFile.java @@ -5,16 +5,15 @@ import lombok.Data; /** * 功能描述 用于给oa流程附件同用的上传文件对象 - * - * @author: yj - * @date: 2024年02月07日 22:37 + * author: yj + * date: 2024年02月07日 22:37 */ @Data public class UploadUserFile { @Schema(description = "文件原始名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "123.jpg") - private String name; + private String name; @Schema(description = "文件URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://xxx.xxx/xx/xx/123.jpgss") - private String url; + private String url; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/config/RpcConfiguration.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/config/RpcConfiguration.java index 40e3b6d3..aba9c98d 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/config/RpcConfiguration.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/config/RpcConfiguration.java @@ -4,6 +4,7 @@ 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.PostApi; import cn.iocoder.yudao.module.system.api.dict.DictDataApi; +import cn.iocoder.yudao.module.system.api.equipment.UsersExtApi; import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi; import cn.iocoder.yudao.module.system.api.permission.RoleApi; import cn.iocoder.yudao.module.system.api.sms.SmsSendApi; @@ -15,7 +16,7 @@ import org.springframework.context.annotation.Configuration; @Configuration(proxyBeanMethods = false) @EnableFeignClients(clients = {FileApi.class,RoleApi.class, DeptApi.class, PostApi.class, AdminUserApi.class, SmsSendApi.class, DictDataApi.class, NotifyMessageSendApi.class, - SubscribeMessageSendApi.class, SocialClientApi.class + SubscribeMessageSendApi.class, SocialClientApi.class, UsersExtApi.class }) public class RpcConfiguration { } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAEntryService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAEntryService.java index 0bdf8667..d3dd273c 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAEntryService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAEntryService.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.entry.BpmOAEntryCreate import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAEntryDO; import javax.validation.Valid; +import java.util.List; public interface BpmOAEntryService { @@ -21,7 +22,7 @@ public interface BpmOAEntryService { * @param id 编号 * @param result 结果 */ - void updateEntryResult(Long id, Integer result); + void updateEntryResult(String processInstanceId, Long id, Integer result); /** * 获得入职申请 @@ -36,5 +37,5 @@ public interface BpmOAEntryService { * @param openId openId * @return 入职申请信息 */ - BpmOAEntryDO getEntryByOpenId(String openId); + List getEntryByOpenId(String openId); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAEntryServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAEntryServiceImpl.java index 1a2c667c..58bab62d 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAEntryServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAEntryServiceImpl.java @@ -1,21 +1,41 @@ package cn.iocoder.yudao.module.bpm.service.oa; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.common.util.string.DTO.IdCardDO; +import cn.iocoder.yudao.framework.common.util.string.StrUtils; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.web.config.WebProperties; import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.entry.BpmOAEntryCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.upload.UploadUserFile; +import cn.iocoder.yudao.module.bpm.convert.message.BpmMessageConvert; import cn.iocoder.yudao.module.bpm.convert.oa.BpmOAEntryConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAEntryDO; import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAEntryMapper; +import cn.iocoder.yudao.module.bpm.enums.message.BpmMessageEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import cn.iocoder.yudao.module.infra.api.file.FileApi; +import cn.iocoder.yudao.module.infra.api.file.dto.UserFileUpdateReqDTO; +import cn.iocoder.yudao.module.system.api.equipment.UsersExtApi; +import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.UserSaveRespDTO; +import org.flowable.engine.runtime.ProcessInstance; +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 java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; 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.module.bpm.enums.ErrorCodeConstants.OA_ENTRY_NOT_EXISTS; /** @@ -37,8 +57,28 @@ public class BpmOAEntryServiceImpl implements BpmOAEntryService{ @Resource private BpmProcessInstanceApi processInstanceApi; + + @Resource + @Lazy + private BpmProcessInstanceService bpmProcessInstanceService; + + @Resource + private AdminUserApi userApi; + + @Resource + private FileApi fileApi; + + @Resource + private UsersExtApi usersExtApi; + + @Resource + private WebProperties webProperties; + + @Resource + private NotifyMessageSendApi notifyMessageSendApi; @Override + @Transactional(rollbackFor = Exception.class) public Long createEntry(BpmOAEntryCreateReqVO createReqVO) { //插入OA 入职申请 @@ -59,16 +99,75 @@ public class BpmOAEntryServiceImpl implements BpmOAEntryService{ } @Override - public void updateEntryResult(Long id, Integer result) { + @Transactional(rollbackFor = Exception.class) + public void updateEntryResult(String processInstanceId, Long id, Integer result) { - validateLeaveExists(id); - entryMapper.updateById(new BpmOAEntryDO().setId(id).setResult(result)); + BpmOAEntryDO entry = validateLeaveExists(id); + + BpmOAEntryDO updateVO = new BpmOAEntryDO().setId(id).setResult(result); + //审核通过 (最后节点) + if (BpmProcessInstanceResultEnum.APPROVE.getResult().equals(result)) { + + ProcessInstance instance = bpmProcessInstanceService.getProcessInstance(processInstanceId); + + if (instance.isEnded()) { + + // 新增入职申请中的用户信息 + UserSaveRespDTO saveRespDTO = BeanUtils.toBean(entry, UserSaveRespDTO.class); + saveRespDTO.setId(null); + saveRespDTO.setDeptId(entry.getEntryDeptId()); + saveRespDTO.setPostIds(Collections.singleton(entry.getEntryPostId())); + saveRespDTO.setPassword("123456"); + + // 解析身份证号码 + IdCardDO idCardDO = StrUtils.IdCardAnalysis(saveRespDTO.getIdcard()); + // 设置性别、年龄、生日 + saveRespDTO.setSex(idCardDO.getSex()); + saveRespDTO.setAge(idCardDO.getAge()); + saveRespDTO.setBirthdayDay(idCardDO.getDate()); + + // 插入用户 获得用户编号 + Long userId = userApi.createUser(saveRespDTO).getCheckedData(); + updateVO.setEntryUserId(userId); + + // 同步修改用户文件数据 + List uploadUserFiles = BeanUtils.toBean(entry.getFileItems(), UploadUserFile.class); + UserFileUpdateReqDTO updateReqDTO = new UserFileUpdateReqDTO() + .setUrls(convertList(uploadUserFiles, UploadUserFile::getUrl)) + .setUserId(userId); + fileApi.updateUserFileUserId(updateReqDTO); + + // 同步修改business_file文件 更新用户编号 + fileApi.updateBusinessFileFormEntry(entry.getFaceImg(), String.valueOf(userId)); + + try { + // 同步插入用户拓展表 + usersExtApi.createUsersExt(userId, entry.getNickname(), entry.getEntryDeptId(), entry.getFaceImg()); + } catch (Exception e) { + + Map templateParams = new HashMap<>(); + templateParams.put("userName", entry.getNickname()); + templateParams.put("detailUrl", webProperties.getAdminUi().getUrl() + "/attendance/user?userName=" + entry.getNickname()); + + // 发送站内信 通知流程发起人, 新员工人脸图片上传失败 + notifyMessageSendApi.sendSingleMessageToAdmin(BpmMessageConvert.INSTANCE.convert1( + entry.getUserId(), BpmMessageEnum.BPM_OA_ENTRY_MESSAGE.getSmsTemplateCode(), templateParams)); + } + } + } + + // 更新入职申请状态 + entryMapper.updateById(updateVO); } - private void validateLeaveExists(Long id) { - if (entryMapper.selectById(id) == null) { + private BpmOAEntryDO validateLeaveExists(Long id) { + + BpmOAEntryDO entry = entryMapper.selectById(id); + if (entry == null) { throw exception(OA_ENTRY_NOT_EXISTS); } + + return entry; } @Override @@ -78,10 +177,10 @@ public class BpmOAEntryServiceImpl implements BpmOAEntryService{ } @Override - public BpmOAEntryDO getEntryByOpenId(String openId) { + public List getEntryByOpenId(String openId) { - return entryMapper.selectOne(new LambdaQueryWrapperX() + return entryMapper.selectList(new LambdaQueryWrapperX() .eq(BpmOAEntryDO::getOpenId, openId) - .eq(BpmOAEntryDO::getResult, BpmProcessInstanceResultEnum.REJECT.getResult())); + .orderByDesc(BpmOAEntryDO::getCreateTime)); } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOAEntryResultListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOAEntryResultListener.java index 4309070a..e987e376 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOAEntryResultListener.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOAEntryResultListener.java @@ -28,6 +28,6 @@ public class BpmOAEntryResultListener extends BpmProcessInstanceResultEventListe @Override protected void onEvent(BpmProcessInstanceResultEvent event) { - entryService.updateEntryResult(Long.parseLong(event.getBusinessKey()), event.getResult()); + entryService.updateEntryResult(event.getId(), Long.parseLong(event.getBusinessKey()), event.getResult()); } } 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 47888316..3f501f10 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.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.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.BpmOAImprestDO; 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.BpmOAImprestService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAProcureServiceImpl; 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.regex.Matcher; import java.util.regex.Pattern; 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.common.util.collection.CollectionUtils.convertSet; 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("]") ; } } //流程是采购计划时 if (definition.getKey().equals(BpmOAProcureServiceImpl.PROCESS_KEY)) { AdminUserRespDTO userRespDTO = adminUserApi.getUser(Long.valueOf(instance.getStartUserId())).getCheckedData(); DeptRespDTO deptRespDTO = deptApi.getDept(userRespDTO.getDeptId()).getCheckedData(); //发起人部门为 生产部及以下时 if (deptRespDTO.getFlag().contains("130")) { //添加 供应部抄送 BpmUserGroupDO userGroup = userGroupService.getUserGroup(121L); 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; @Resource @Lazy // 解决循环依赖 private BpmOAImprestService imprestService; @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("oa_reimbursement".equals(key)) { //报销流程 BpmOAReimbursementDO reimbursement = reimbursementService.getReimbursement(businessKey); BpmOAReimbursementRespVO bpmOAReimbursementRespVO = reimbursementService.convert(reimbursement); //报销业务数据 List taskRespVOList = taskService.getTaskListByProcessInstanceId(processInstanceId) ; //报销审核人数据 //给User添加签名地址 taskRespVOList.forEach(taskRespVO -> taskRespVO.getAssigneeUser().setSignURL( fileApi.getUserSignImgPath( taskRespVO.getAssigneeUser().getId() ).getData() ) ); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprestByReimbursementId(reimbursement.getId()); if (bpmOAImprestDO != null) { //设置备用金 金额 bpmOAReimbursementRespVO.setAmount(bpmOAImprestDO.getAmount()); } //获取流程抄送用户编号 BpmProcessInstanceExtDO processInstanceExtDO = getProcessInstanceDO(processInstanceId); //获取流程抄送用户信息 List ccUserIds = new ArrayList<>(); if (processInstanceExtDO.getCcids() != null && !processInstanceExtDO.getCcids().isEmpty()) { Pattern pattern = Pattern.compile("\\[(\\d+)]"); Matcher matcher = pattern.matcher(processInstanceExtDO.getCcids()); while (matcher.find()) { ccUserIds.add(Long.parseLong(matcher.group(1))); } } List userRespDTOS = adminUserApi.getUserList(ccUserIds).getCheckedData(); //获取抄送用户部门信息 Map deptMapDTO = deptApi.getDeptMap(convertSet(userRespDTOS, AdminUserRespDTO::getDeptId)); //拼接数据 List ccUsers = userRespDTOS.stream().map(user -> { BpmOAReimbursementPrintDataRespVO.CCUser cc = new BpmOAReimbursementPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOAReimbursementPrintDataRespVO reimbursementPrintData = new BpmOAReimbursementPrintDataRespVO() ; reimbursementPrintData.setBpmOAReimbursementRespVO(bpmOAReimbursementRespVO) ; reimbursementPrintData.setProcessTasks(taskRespVOList); reimbursementPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOAReimbursementPrintDataRespVO(reimbursementPrintData) ; } return bpmProcessInstancePrintDataRespVO ; } } \ 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.flowable.core.util.FlowableUtils; 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.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.BpmOAImprestDO; 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.BpmOAImprestService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAProcureServiceImpl; 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.regex.Matcher; import java.util.regex.Pattern; 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.common.util.collection.CollectionUtils.convertSet; 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); } // 设置当前用户 FlowableUtils.setAuthenticatedUserId(userId); // 创建流程实例 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("]") ; } } //流程是采购计划时 if (definition.getKey().equals(BpmOAProcureServiceImpl.PROCESS_KEY)) { AdminUserRespDTO userRespDTO = adminUserApi.getUser(Long.valueOf(instance.getStartUserId())).getCheckedData(); DeptRespDTO deptRespDTO = deptApi.getDept(userRespDTO.getDeptId()).getCheckedData(); //发起人部门为 生产部及以下时 if (deptRespDTO.getFlag().contains("130")) { //添加 供应部抄送 BpmUserGroupDO userGroup = userGroupService.getUserGroup(121L); 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; @Resource @Lazy // 解决循环依赖 private BpmOAImprestService imprestService; @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("oa_reimbursement".equals(key)) { //报销流程 BpmOAReimbursementDO reimbursement = reimbursementService.getReimbursement(businessKey); BpmOAReimbursementRespVO bpmOAReimbursementRespVO = reimbursementService.convert(reimbursement); //报销业务数据 List taskRespVOList = taskService.getTaskListByProcessInstanceId(processInstanceId) ; //报销审核人数据 //给User添加签名地址 taskRespVOList.forEach(taskRespVO -> taskRespVO.getAssigneeUser().setSignURL( fileApi.getUserSignImgPath( taskRespVO.getAssigneeUser().getId() ).getData() ) ); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprestByReimbursementId(reimbursement.getId()); if (bpmOAImprestDO != null) { //设置备用金 金额 bpmOAReimbursementRespVO.setAmount(bpmOAImprestDO.getAmount()); } //获取流程抄送用户编号 BpmProcessInstanceExtDO processInstanceExtDO = getProcessInstanceDO(processInstanceId); //获取流程抄送用户信息 List ccUserIds = new ArrayList<>(); if (processInstanceExtDO.getCcids() != null && !processInstanceExtDO.getCcids().isEmpty()) { Pattern pattern = Pattern.compile("\\[(\\d+)]"); Matcher matcher = pattern.matcher(processInstanceExtDO.getCcids()); while (matcher.find()) { ccUserIds.add(Long.parseLong(matcher.group(1))); } } List userRespDTOS = adminUserApi.getUserList(ccUserIds).getCheckedData(); //获取抄送用户部门信息 Map deptMapDTO = deptApi.getDeptMap(convertSet(userRespDTOS, AdminUserRespDTO::getDeptId)); //拼接数据 List ccUsers = userRespDTOS.stream().map(user -> { BpmOAReimbursementPrintDataRespVO.CCUser cc = new BpmOAReimbursementPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOAReimbursementPrintDataRespVO reimbursementPrintData = new BpmOAReimbursementPrintDataRespVO() ; reimbursementPrintData.setBpmOAReimbursementRespVO(bpmOAReimbursementRespVO) ; reimbursementPrintData.setProcessTasks(taskRespVOList); reimbursementPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOAReimbursementPrintDataRespVO(reimbursementPrintData) ; } return bpmProcessInstancePrintDataRespVO ; } } \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java index 3cbb70db..9e3f742e 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java @@ -205,5 +205,19 @@ public interface BpmTaskService { */ String getCurrentTaskIdByProcessInstanceId(String processInstanceId) ; + /** + * 获得指定的task记录 + * @param processInstanceId 流程实例id集合 + * @param result 结果 + * @return task + */ List getTaskByProcessInstanceIdAndResult(List processInstanceId, Integer result); + + /** + * 获得指定的task记录 + * @param processInstanceId 流程实例id + * @param result 结果 + * @return task + */ + BpmTaskExtDO getTaskByProcessInstanceIdAndResult(String processInstanceId, Integer result); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index d8d91257..e1820945 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -1235,4 +1235,12 @@ public class BpmTaskServiceImpl implements BpmTaskService { return taskExtMapper.selectTask(processInstanceId, result); } + + @Override + public BpmTaskExtDO getTaskByProcessInstanceIdAndResult(String processInstanceId, Integer result) { + + return taskExtMapper.selectOne(new LambdaQueryWrapperX() + .eq(BpmTaskExtDO::getProcessInstanceId, processInstanceId) + .eq(BpmTaskExtDO::getResult, result)); + } } From 9594f5493716dd451815f65ad6cddd816290ba68 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Thu, 4 Jul 2024 18:24:46 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E5=85=A5=E8=81=8C=E7=94=B3=E8=AF=B7=20?= =?UTF-8?q?=E9=80=9A=E8=BF=87=E5=90=8E=20=E8=87=AA=E5=8A=A8=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E6=96=B0=E5=85=A5=E8=81=8C=E5=91=98=E5=B7=A5=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E8=87=B3=20=20=20=E7=94=A8=E6=88=B7=E8=A1=A8=E3=80=81?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E6=8B=93=E5=B1=95=E8=A1=A8=20=E5=B9=B6?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=20=E7=94=A8=E6=88=B7=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E7=AD=89=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iocoder/yudao/module/bpm/enums/message/BpmMessageEnum.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/message/BpmMessageEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/message/BpmMessageEnum.java index 7ed21607..7890b712 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/message/BpmMessageEnum.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/message/BpmMessageEnum.java @@ -16,7 +16,8 @@ public enum BpmMessageEnum { PROCESS_INSTANCE_REJECT("bpm_process_instance_reject"), // 流程任务被审批不通过时,发送给申请人 TASK_ASSIGNED("bpm_task_assigned"), // 任务被分配时,发送给审批人 BPM_WORK_TASK("bpm_work_task"), //【任务分配】发起任务 - BPM_WORK_TASK_COMPLETE("bpm_work_task_complete"); //【任务分配】任务完成 + BPM_WORK_TASK_COMPLETE("bpm_work_task_complete"), //【任务分配】任务完成 + BPM_OA_ENTRY_MESSAGE("bpm_oa_entry_message"); // 【入职申请】消息通知 /** * 短信模板的标识 From e333671734cd3c73e16f09999e8be8fb42c9e242 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Thu, 4 Jul 2024 18:26:10 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E6=96=87=E4=BB=B6=E6=8E=A5=E5=8F=A3=20?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=20=E5=B0=8F=E7=A8=8B=E5=BA=8F=E7=A0=81?= =?UTF-8?q?=E7=94=9F=E6=88=90=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/infra/api/file/FileApi.java | 10 ++- .../module/infra/api/file/FileApiImpl.java | 9 +++ .../controller/admin/file/FileController.java | 69 +++++++++++++------ .../infra/dal/mysql/file/QRCodeDOMapper.java | 3 +- .../infra/service/file/FileService.java | 25 ++++++- .../infra/service/file/FileServiceImpl.java | 44 ++++++++++-- 6 files changed, 128 insertions(+), 32 deletions(-) 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 f849fa1c..667b1db6 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 @@ -74,14 +74,20 @@ public interface FileApi { String updateBusinessFileContent(@RequestParam("url") String url, @RequestParam("businessType") Long businessType, @RequestParam("name") String name, - @RequestBody byte[] content) ; + @RequestBody byte[] content); + + @PostMapping(PREFIX + "/updateBusinessFile") + @Operation(summary = "修改BusinessFile文件中的 businessInstanceId | 入职申请用") + CommonResult updateBusinessFileFormEntry(@RequestParam("url") String url, + @RequestParam("businessInstanceId") String businessInstanceId); + @DeleteMapping(PREFIX + "/deleteBpmFile") @Operation(summary = "删除工作流附件") @Parameter(name = "url", description = "附件URL地址", required = true) CommonResult deleteBpmFile(@RequestParam("url") String url) throws Exception; - @PutMapping(PREFIX + "/updateUserFile") + @PostMapping(PREFIX + "/updateUserFile") @Operation(summary = "修改用户文件绑定 用户编号") CommonResult updateUserFileUserId(@RequestBody UserFileUpdateReqDTO updateReqVO); } 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 c59226f4..3ea94bd0 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 @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.infra.api.file.dto.UserFileUpdateReqDTO; import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.BpmFileUploadReqVO; import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.UserFileUpdateReqVO; import cn.iocoder.yudao.module.infra.service.file.FileService; +import lombok.SneakyThrows; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.RestController; @@ -55,6 +56,14 @@ public class FileApiImpl implements FileApi { return fileService.updateBusinessFileContent(url, businessType, name, content) ; } + @Override + @SneakyThrows + public CommonResult updateBusinessFileFormEntry(String url, String businessInstanceId) { + + fileService.uploadBusinessFileFormEntry(url, businessInstanceId); + return success(true); + } + @Override public CommonResult deleteBpmFile(String url) throws Exception { diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java index 43cac017..61440f91 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java @@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import cn.iocoder.yudao.framework.security.config.SecurityProperties; import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.*; import cn.iocoder.yudao.module.infra.dal.dataobject.file.*; import cn.iocoder.yudao.module.infra.service.file.FileService; @@ -35,6 +36,7 @@ import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.time.LocalDate; @@ -61,6 +63,9 @@ public class FileController { @Resource private PostApi postApi; + @Resource + private SecurityProperties securityProperties; + @PostMapping("/uploadBpmFileProcessInstanceId") @Operation(summary = "更新文件的流程实例ID") @OperateLog(logArgs = false) // 上传文件,没有记录操作日志的必要 @@ -185,37 +190,45 @@ public class FileController { @Parameter(name = "deptId", description = "部门编号", required = true, example = "1024") @Parameter(name = "postId", description = "岗位编号", example = "1024") public CommonResult createQRCode(@RequestParam("userId") Long userId, - @RequestParam("deptId") Long deptId, - @RequestParam(value = "postId", required = false) Long postId) { + @RequestParam("deptId") Long deptId, + @RequestParam(value = "postId", required = false) Long postId) { + + // 查询当前部门编号下 是否存在小程序码 - QRCodeDO qrCodeDO = fileService.getQRCode(deptId); + QRCodeDO qrCodeDO = fileService.getQRCode(deptId, null); + + JSONObject scene = new JSONObject(); + scene.set("userId", userId); + scene.set("deptId", deptId); + scene.set("postId", postId); // 小程序码不存在,则 生成新的小程序码 if (qrCodeDO == null) { - // 生成小程序码 - File QRCode = socialClientApi.getQRCode("subPages/register/register", "deptId=" + deptId).getCheckedData(); - - JSONObject object = new JSONObject(); - object.set("userId", userId); - object.set("deptId", deptId); - object.set("postId", postId); - try { - FileInputStream fis = new FileInputStream(QRCode); - byte[] content = IoUtil.readBytes(fis); - - // 上传小程序码 获得url - qrCodeDO = fileService.createQRCodeFile(deptId, QRCode.getName(), content, object.toString()); + qrCodeDO = createQRCode(deptId, scene.toString()); } catch (IOException e) { return error(OA_QRCODE_ERROR); } - }else { // 存在的时候, 则更新小程序码的生成时间 + }else { // 存在的时候, 判断是否已存在相同参数的小程序码 - fileService.updateQRCodeFile(qrCodeDO.getId()); + // 查询是否存在 参数一致的小程序码 + qrCodeDO = fileService.getQRCode(deptId, scene.toString()); + if (qrCodeDO == null) { + + try { + qrCodeDO = createQRCode(deptId, scene.toString()); + + } catch (IOException e) { + + return error(OA_QRCODE_ERROR); + } + }else { + fileService.updateQRCodeFile(qrCodeDO.getId()); + } } return success(qrCodeDO); @@ -223,10 +236,11 @@ public class FileController { @GetMapping("getQRCode") @Operation(summary = "获得入职申请小程序码") - public CommonResult getQRCode(@RequestParam("deptId") Long deptId) { + @PermitAll + public CommonResult getQRCode(@RequestParam("id") Long id) { // 查询当前部门编号下 是否存在小程序码 - QRCodeDO qrCodeDO = fileService.getQRCode(deptId); + QRCodeDO qrCodeDO = fileService.getQRCode(id); if (qrCodeDO != null) { @@ -239,6 +253,7 @@ public class FileController { reqVO.setUserId(Long.valueOf(qrCodeDO.getUpdater())); // 获取部门信息 + Long deptId = Long.valueOf(scene.get("deptId").toString()); DeptRespDTO deptRespDTO = deptApi.getDept(deptId).getCheckedData(); reqVO.setDeptId(deptId); reqVO.setDeptName(deptRespDTO.getName()); @@ -267,4 +282,18 @@ public class FileController { return success(true); } + + public QRCodeDO createQRCode(Long deptId, String scene) throws FileNotFoundException { + + Long id = fileService.createQRCodeFile(deptId, scene.toString()); + + // 生成小程序码 + File QRCode = socialClientApi.getQRCode("subPages/register/register", "id=" + id).getCheckedData(); + + FileInputStream fis = new FileInputStream(QRCode); + byte[] content = IoUtil.readBytes(fis); + + // 上传小程序码 获得url + return fileService.updateQRCodeFile(id, deptId, QRCode.getName(), content); + } } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/QRCodeDOMapper.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/QRCodeDOMapper.java index 2b79a5f5..4c361b97 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/QRCodeDOMapper.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/QRCodeDOMapper.java @@ -8,10 +8,11 @@ import org.apache.ibatis.annotations.Mapper; @Mapper public interface QRCodeDOMapper extends BaseMapperX { - default QRCodeDO selectByDeptId(Long deptId) { + default QRCodeDO selectByDeptId(Long deptId, String scene) { return selectOne(new LambdaQueryWrapperX() .eq(QRCodeDO::getBusinessId, deptId) + .eqIfPresent(QRCodeDO::getScene, scene) .eq(QRCodeDO::getBusinessType, 1)); } } 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 e270ad83..070ce6a1 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 @@ -102,6 +102,12 @@ public interface FileService { */ void uploadBusinessFileProcessInstanceId(BusinessFileUploadReqVO reqVO) throws Exception ; + /** + * 更新文件的流程实例ID | 入职申请用 + * @param url 文件地址 + */ + void uploadBusinessFileFormEntry(String url, String businessInstanceId); + /** * 获取用户的签名图片地址 * @@ -153,14 +159,22 @@ public interface FileService { * @param content 字节流 * @return url */ - QRCodeDO createQRCodeFile(Long deptId, String name, byte[] content, String scene) ; + QRCodeDO updateQRCodeFile(Long id, Long deptId, String name, byte[] content) ; + + /** + * 获得小程序码信息 + * @param id 编号 + * @return 小程序码信息 + */ + QRCodeDO getQRCode(Long id); /** * 获得小程序码信息 * @param deptId 部门编号 + * @param scene 参数 * @return 小程序码信息 */ - QRCodeDO getQRCode(Long deptId); + QRCodeDO getQRCode(Long deptId, String scene); /** * 更新 小程序码生成时间 @@ -173,4 +187,11 @@ public interface FileService { * @param url 文件链接 */ void deleteQRCode(String url); + + /** + * 创建小程序码文件 + * @param deptId 部门编号 + * @param scene 参数 + */ + Long createQRCodeFile(Long deptId, String scene); } 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 b8e5e816..e4bbdc82 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 @@ -319,7 +319,6 @@ public class FileServiceImpl implements FileService { /** * 更新文件的流程实例ID * @param reqVO - * @throws Exception */ @Override @SneakyThrows @@ -333,6 +332,21 @@ public class FileServiceImpl implements FileService { businessFileMapper.update(null, lambdaUpdateWrapper); } + @Override + @SneakyThrows + public void uploadBusinessFileFormEntry(String url, String businessInstanceId) { + + LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper<>(); + lambdaUpdateWrapper.eq(BusinessFileDO::getUrl, url); + lambdaUpdateWrapper.set(BusinessFileDO::getBusinessInstanceId, businessInstanceId); // 假设 bid 是要更新的 bid 值 + lambdaUpdateWrapper.set(BusinessFileDO::getUploadUserId, businessInstanceId); + lambdaUpdateWrapper.set(BusinessFileDO::getCreator, businessInstanceId); + lambdaUpdateWrapper.set(BusinessFileDO::getUpdater, businessInstanceId); + + // 调用 MyBatis Plus 的 update 方法执行批量更新 + businessFileMapper.update(null, lambdaUpdateWrapper); + } + @Override public String getUserSignImgPath(Long userId) { BusinessFileDO businessFileDO = businessFileMapper.selectOneByBusinessInstanceId(2L, userId.toString()) ; @@ -472,7 +486,7 @@ public class FileServiceImpl implements FileService { @Override @SneakyThrows - public QRCodeDO createQRCodeFile(Long deptId, String name, byte[] content, String scene) { + public QRCodeDO updateQRCodeFile(Long id, Long deptId, String name, byte[] content) { long timestamp = System.currentTimeMillis(); // 计算默认的 path 名 @@ -491,20 +505,25 @@ public class FileServiceImpl implements FileService { // 插入 system_qr_code QRCodeDO fileDo = new QRCodeDO(); - fileDo.setBusinessId(deptId.toString()); + fileDo.setId(id); fileDo.setBusinessType(1); fileDo.setConfigId(client.getId()); fileDo.setUrl(url); - fileDo.setScene(scene); - qrCodeDOMapper.insert(fileDo); + qrCodeDOMapper.updateById(fileDo); return fileDo; } @Override - public QRCodeDO getQRCode(Long deptId) { + public QRCodeDO getQRCode(Long id) { - return qrCodeDOMapper.selectByDeptId(deptId); + return qrCodeDOMapper.selectById(id); + } + + @Override + public QRCodeDO getQRCode(Long deptId, String scene) { + + return qrCodeDOMapper.selectByDeptId(deptId, scene); } @Override @@ -533,6 +552,17 @@ public class FileServiceImpl implements FileService { qrCodeDOMapper.deleteById(qrCodeDO.getId()); } + @Override + public Long createQRCodeFile(Long deptId, String scene) { + + QRCodeDO createDO = new QRCodeDO() + .setBusinessId(String.valueOf(deptId)) + .setScene(scene); + + qrCodeDOMapper.insert(createDO); + return createDO.getId(); + } + /** * 从文件存储器删除 文件 */ From 0d3b39203869deeef58a92546267c4b45d40c9a9 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Thu, 4 Jul 2024 18:28:15 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E8=BF=9C=E7=A8=8Brpc?= =?UTF-8?q?=E8=B0=83=E7=94=A8=E6=8E=A5=E5=8F=A3=EF=BC=9A=20=20=20=E6=8F=92?= =?UTF-8?q?=E5=85=A5=E7=94=A8=E6=88=B7=E4=BF=A1=E6=81=AF=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E3=80=81=E6=8F=92=E5=85=A5=E7=94=A8=E6=88=B7=E6=8B=93=E5=B1=95?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E6=8E=A5=E5=8F=A3=20=E4=BF=AE=E6=94=B9=20?= =?UTF-8?q?=E8=80=83=E5=8B=A4=E8=AE=BE=E5=A4=87=E6=8E=A5=E5=8F=A3=20?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0=E6=9B=B4=E6=96=B0=E9=83=A8=E9=97=A8=E7=BC=96?= =?UTF-8?q?=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../system/api/equipment/UsersExtApi.java | 22 +++++++ .../module/system/api/user/AdminUserApi.java | 7 +++ .../system/api/user/dto/UserSaveRespDTO.java | 54 ++++++++++++++++ .../system/api/equipment/UsersExtApiImpl.java | 63 +++++++++++++++++++ .../system/api/user/AdminUserApiImpl.java | 9 ++- .../AttendanceMachineSaveReqVO.java | 6 +- .../AttendanceMachineServiceImpl.java | 2 +- .../websocket/WebsocketServiceImpl.java | 2 +- .../src/main/resources/application-dev.yaml | 6 ++ 9 files changed, 165 insertions(+), 6 deletions(-) create mode 100644 yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/equipment/UsersExtApi.java create mode 100644 yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/dto/UserSaveRespDTO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/equipment/UsersExtApiImpl.java diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/equipment/UsersExtApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/equipment/UsersExtApi.java new file mode 100644 index 00000000..926c7da6 --- /dev/null +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/equipment/UsersExtApi.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.system.api.equipment; + +import cn.iocoder.yudao.module.system.enums.ApiConstants; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - 用户拓展") +public interface UsersExtApi { + + String PREFIX = ApiConstants.PREFIX + "/attendance-machine"; + + @PostMapping(PREFIX + "/create") + @Operation(summary = "新增设备请求记录") + void createUsersExt(@RequestParam("userId") Long userId, + @RequestParam("userName") String userName, + @RequestParam("deptId") Long deptId, + @RequestParam("faceImg") String faceImg); +} diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApi.java index c0e7bfea..76a52806 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApi.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApi.java @@ -3,12 +3,15 @@ package cn.iocoder.yudao.module.system.api.user; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import cn.iocoder.yudao.module.system.api.user.dto.UserSaveRespDTO; import cn.iocoder.yudao.module.system.enums.ApiConstants; import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Operation; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import java.util.Collection; @@ -63,4 +66,8 @@ public interface AdminUserApi { @Operation(summary = "获取同部门所有用户id") @Parameter(name = "userId", description = "用户id", example = "1024", required = true) CommonResult> getUserIdsByUserIdGroupByDept(@RequestParam("userId") Long userId); + + @PostMapping(PREFIX + "/create") + @Operation(summary = "创建用户") + CommonResult createUser(@RequestBody UserSaveRespDTO saveRespDTO); } diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/dto/UserSaveRespDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/dto/UserSaveRespDTO.java new file mode 100644 index 00000000..7f523e7c --- /dev/null +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/dto/UserSaveRespDTO.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.system.api.user.dto; + +import cn.iocoder.yudao.framework.common.validation.IdCard; +import cn.iocoder.yudao.framework.common.validation.Mobile; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.Length; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.Size; +import java.time.LocalDate; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; + +@Schema(description = "RPC 服务 - Admin 用户创建 DTO") +@Data +public class UserSaveRespDTO { + + @Schema(description = "用户 ID", example = "1024") + private Long id; + + @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @Size(max = 30, message = "用户昵称长度不能超过30个字符") + private String nickname; + + @Schema(description = "部门ID", example = "我是一个用户") + private Long deptId; + + @Schema(description = "岗位编号数组", example = "1") + private Set postIds; + + @Schema(description = "手机号码", example = "15601691300") + @Mobile + private String mobile; + + @Schema(description = "用户性别,参见 SexEnum 枚举类", example = "1") + private Integer sex; + + @Schema(description = "身份证号码") + @IdCard + private String idcard; + + @Schema(description = "年龄", example = "23") + private Integer age; + + @Schema(description = "生日日期", example = "03-23") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + private LocalDate birthdayDay; + + @Schema(description = "密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456") + @Length(min = 4, max = 16, message = "密码长度为 4-16 位") + private String password; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/equipment/UsersExtApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/equipment/UsersExtApiImpl.java new file mode 100644 index 00000000..ed6414f5 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/equipment/UsersExtApiImpl.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.system.api.equipment; + +import cn.iocoder.yudao.module.system.controller.admin.equipment.vo.userExt.UsersExtSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.equipment.vo.websocket.AddUserVO; +import cn.iocoder.yudao.module.system.dal.dataobject.equipment.AttendanceMachineDO; +import cn.iocoder.yudao.module.system.service.equipment.AttendanceMachineService; +import cn.iocoder.yudao.module.system.service.equipment.UsersExtService; +import cn.iocoder.yudao.module.system.service.websocket.WebsocketService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.List; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class UsersExtApiImpl implements UsersExtApi{ + + @Resource + private UsersExtService usersExtService; + + @Resource + private AttendanceMachineService attendanceMachineService; + + @Resource + private WebsocketService websocketService; + + @Override + public void createUsersExt(Long userId, String userName, Long deptId, String faceImg) { + + // 查询当前部门下 是否存在考勤设备 + List deviceList = attendanceMachineService.getListByDeptId(deptId); + List deviceNos = new ArrayList<>(); + try { + + for (AttendanceMachineDO machineDO : deviceList) { + + // 设置下发命令 + AddUserVO addUserVO = new AddUserVO() + .setCmd("addUser") + .setUser_id(String.valueOf(userId)) + .setName(userName) + .setFace_template(faceImg) + .setId_valid(""); + + // 发送指令至 考勤设备 下发员工 + websocketService.sendSn(machineDO.getDeviceNo(), addUserVO, 1); + + deviceNos.add(machineDO.getDeviceNo()); + } + } finally { + + UsersExtSaveReqVO saveReqVO = new UsersExtSaveReqVO() + .setUserId(userId) + .setDeptId(deptId) + .setFaceImg(faceImg) + .setAttendanceMachineNos(deviceNos); + // 插入用户拓展信息 + usersExtService.createUsers(saveReqVO); + } + } +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApiImpl.java index bee060aa..0f2daf35 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApiImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApiImpl.java @@ -4,6 +4,8 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import cn.iocoder.yudao.module.system.api.user.dto.UserSaveRespDTO; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserSaveReqVO; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; import cn.iocoder.yudao.module.system.service.user.AdminUserService; import org.springframework.validation.annotation.Validated; @@ -12,7 +14,6 @@ import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.util.Collection; import java.util.List; -import java.util.Map; import java.util.Set; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -62,4 +63,10 @@ public class AdminUserApiImpl implements AdminUserApi { return success(userIds); } + @Override + public CommonResult createUser(UserSaveRespDTO saveRespDTO) { + + return success(userService.createUser(BeanUtils.toBean(saveRespDTO, UserSaveReqVO.class))); + } + } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/equipment/vo/attendancemachine/AttendanceMachineSaveReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/equipment/vo/attendancemachine/AttendanceMachineSaveReqVO.java index a71194b3..d03bb0f9 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/equipment/vo/attendancemachine/AttendanceMachineSaveReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/equipment/vo/attendancemachine/AttendanceMachineSaveReqVO.java @@ -3,9 +3,6 @@ package cn.iocoder.yudao.module.system.controller.admin.equipment.vo.attendancem import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; - @Schema(description = "管理后台 - 考勤设备新增/修改 Request VO") @Data public class AttendanceMachineSaveReqVO { @@ -28,4 +25,7 @@ public class AttendanceMachineSaveReqVO { @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED) private String deviceName; + @Schema(description = "是否分配资产") + private Boolean isAssets; + } \ 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/equipment/AttendanceMachineServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/equipment/AttendanceMachineServiceImpl.java index 552c1ca7..e5a4cccb 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/equipment/AttendanceMachineServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/equipment/AttendanceMachineServiceImpl.java @@ -91,7 +91,7 @@ public class AttendanceMachineServiceImpl implements AttendanceMachineService { validateAttendanceMachineExists(updateReqVO.getId(), updateReqVO.getDeviceNo()); //如果分配机构的情况, 则调用资产分配方法 - if (updateReqVO.getDeptId() != null) { + if (updateReqVO.getIsAssets()) { DeptAssetsInOutStockSaveReqVO vos = new DeptAssetsInOutStockSaveReqVO(); vos.setInDeptId(updateReqVO.getDeptId()); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/websocket/WebsocketServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/websocket/WebsocketServiceImpl.java index 5988834f..2ae8ab5e 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/websocket/WebsocketServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/websocket/WebsocketServiceImpl.java @@ -66,7 +66,7 @@ public class WebsocketServiceImpl implements WebsocketService{ if (StringUtil.isEmpty(stringRedisTemplate.opsForValue().get(deviceNo))) { stringRedisTemplate.opsForValue().set(deviceNo, "true"); } - // 发送修改密码命令给设备 + // 发送命令给设备 webSocketSenderApi.sendSN(deviceNo, "attendance-message-send", JsonUtils.toJsonString(baseVO)); Long startTime = System.currentTimeMillis(); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/application-dev.yaml b/yudao-module-system/yudao-module-system-biz/src/main/resources/application-dev.yaml index 3e19b2c2..af247677 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/resources/application-dev.yaml +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/application-dev.yaml @@ -116,6 +116,12 @@ spring: # Spring Boot Admin Server 服务端的相关配置 context-path: /admin # 配置 Spring +# 日志文件配置 +logging: + level: + # 配置自己写的 MyBatis Mapper 打印日志 + cn.iocoder.yudao.module.system.dal.mysql: debug + --- #################### 微信公众号、小程序相关配置 #################### wx: mp: # 公众号配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md 文档