From c51c46262cfadeaeaed8c53edb7690a7ccdf4397 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Fri, 29 Nov 2024 17:05:42 +0800 Subject: [PATCH 1/7] =?UTF-8?q?feat(bpm):=20=E5=A2=9E=E5=8A=A0=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E7=BC=96=E5=8F=B7=E5=92=8C=E5=90=8D=E7=A7=B0=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=EF=BC=8C=E5=B9=B6=E4=BC=98=E5=8C=96=E6=8A=A5=E9=94=80?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 BpmOACash 和 BpmOAReimbursement 模型中添加项目编号字段 - 在 API 接口中增加项目名称的获取和展示 - 新增 BpmOAReimbursementItem 模型和相关 Mapper- 优化报销申请创建逻辑,支持明细数据插入 -调整抄送人处理逻辑,使用事务提交后执行 -重构领导审批规则计算方法,提高灵活性和准确性 --- .../admin/oa/BpmOACashController.java | 20 ++++- .../oa/BpmOAReimbursementController.java | 22 +++++- .../oa/vo/cash/BpmOACashCreateReqVO.java | 3 + .../admin/oa/vo/cash/BpmOACashRespVO.java | 6 ++ .../BpmOAReimbursementCreateReqVO.java | 7 +- .../BpmOAReimbursementRespVO.java | 6 ++ .../oa/vo/reimbursement/Reimbursement.java | 3 + .../bpm/dal/dataobject/oa/BpmOACashDO.java | 5 ++ .../dataobject/oa/BpmOAReimbursementDO.java | 7 +- .../oa/BpmOAReimbursementItemDO.java | 71 ++++++++++++++++++ .../oa/BpmOAReimbursementItemMapper.java | 9 +++ .../BpmTaskAssignLeaderAbstractScript.java | 73 ++++++++++++------ .../definition/BpmProcessCcServiceImpl.java | 2 +- .../service/oa/BpmOAReimbursementService.java | 11 +++ .../oa/BpmOAReimbursementServiceImpl.java | 75 ++++++++++++------- .../task/BpmProcessInstanceServiceImpl.java | 2 +- 16 files changed, 262 insertions(+), 60 deletions(-) create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAReimbursementItemDO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAReimbursementItemMapper.java diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOACashController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOACashController.java index a81763f2..dacf7f76 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOACashController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOACashController.java @@ -5,9 +5,12 @@ import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.cash.BpmOACashCreateRe import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.cash.BpmOACashRespVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOACashDO; import cn.iocoder.yudao.module.bpm.service.oa.BpmOACashService; +import cn.iocoder.yudao.module.system.api.project.ProjectApi; +import cn.iocoder.yudao.module.system.api.project.dto.ProjectDTO; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; +import org.mapstruct.ap.internal.util.Strings; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -32,6 +35,9 @@ public class BpmOACashController { @Resource private BpmOACashService cashService; + @Resource + private ProjectApi projectApi; + @PostMapping("/create") @Operation(summary = "创建请求申请") public CommonResult createCash(@Valid @RequestBody BpmOACashCreateReqVO createReqVO) { @@ -45,8 +51,13 @@ public class BpmOACashController { public CommonResult getCash(@RequestParam("id") Long id) { BpmOACashDO cashDO = cashService.getCash(id); + BpmOACashRespVO respVO = cashService.convertCash(cashDO); + if (respVO != null && Strings.isNotEmpty(respVO.getProjectNo())) { + ProjectDTO projectDTO = projectApi.getProject(respVO.getProjectNo()).getCheckedData(); + respVO.setProjectName(projectDTO.getName()); + } - return success(cashService.convertCash(cashDO)); + return success(respVO); } @GetMapping("/getByProcessInstanceId") @@ -55,7 +66,12 @@ public class BpmOACashController { public CommonResult getCashByProcessInstanceId(@RequestParam("processInstanceId") String processInstanceId) { BpmOACashDO cashDO = cashService.getByProcessInstanceId(processInstanceId); + BpmOACashRespVO respVO = cashService.convertCash(cashDO); + if (respVO != null && Strings.isNotEmpty(respVO.getProjectNo())) { + ProjectDTO projectDTO = projectApi.getProject(respVO.getProjectNo()).getCheckedData(); + respVO.setProjectName(projectDTO.getName()); + } - return success(cashService.convertCash(cashDO)); + return success(respVO); } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOAReimbursementController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOAReimbursementController.java index 71398575..757b0449 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOAReimbursementController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOAReimbursementController.java @@ -5,9 +5,12 @@ import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.BpmOARei import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.BpmOAReimbursementRespVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReimbursementDO; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAReimbursementService; +import cn.iocoder.yudao.module.system.api.project.ProjectApi; +import cn.iocoder.yudao.module.system.api.project.dto.ProjectDTO; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; +import org.mapstruct.ap.internal.util.Strings; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -31,6 +34,9 @@ public class BpmOAReimbursementController { @Resource private BpmOAReimbursementService service; + @Resource + private ProjectApi projectApi; + @PostMapping("/create") // @PreAuthorize("@ss.hasPermission('bpm:oa-reimbursement:create')") @Operation(summary = "创建请求申请") @@ -45,7 +51,13 @@ public class BpmOAReimbursementController { public CommonResult getReimbursement(@RequestParam("id") Long id) { BpmOAReimbursementDO reimbursement = service.getReimbursement(id); - return success(service.convert(reimbursement)); + BpmOAReimbursementRespVO respVO = service.convert(reimbursement); + if (respVO != null && Strings.isNotEmpty(respVO.getProjectNo())) { + // 设置项目名称 + ProjectDTO projectDTO = projectApi.getProject(respVO.getProjectNo()).getCheckedData(); + respVO.setProjectName(projectDTO.getName()); + } + return success(respVO); } // @GetMapping("/page") @@ -62,6 +74,12 @@ public class BpmOAReimbursementController { public CommonResult getByProcessInstanceId(@RequestParam("processInstanceId") String processInstanceId) { BpmOAReimbursementDO reimbursement = service.getByProcessInstanceId(processInstanceId); - return success(service.convert(reimbursement)); + BpmOAReimbursementRespVO respVO = service.convert(reimbursement); + if (respVO != null && Strings.isNotEmpty(respVO.getProjectNo())) { + // 设置项目名称 + ProjectDTO projectDTO = projectApi.getProject(respVO.getProjectNo()).getCheckedData(); + respVO.setProjectName(projectDTO.getName()); + } + return success(respVO); } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/cash/BpmOACashCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/cash/BpmOACashCreateReqVO.java index f129e02a..a7451533 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/cash/BpmOACashCreateReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/cash/BpmOACashCreateReqVO.java @@ -31,6 +31,9 @@ public class BpmOACashCreateReqVO { @NotNull(message = "报销总金额不能为空") private BigDecimal totalMoney; + @Schema(description = "项目编号") + private String projectNo; + @Schema(description = "备用金申请编号") private Long imprestId; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/cash/BpmOACashRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/cash/BpmOACashRespVO.java index 9228d0ae..e1f57ec6 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/cash/BpmOACashRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/cash/BpmOACashRespVO.java @@ -37,6 +37,12 @@ public class BpmOACashRespVO extends BpmOABaseRespVO { @Schema(description = "报销总金额") private BigDecimal totalMoney; + @Schema(description = "项目编号") + private String projectNo; + + @Schema(description = "项目名称") + private String projectName; + @Schema(description = "备用金申请编号") private Long imprestId; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/reimbursement/BpmOAReimbursementCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/reimbursement/BpmOAReimbursementCreateReqVO.java index 7b89f875..9bc353e5 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/reimbursement/BpmOAReimbursementCreateReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/reimbursement/BpmOAReimbursementCreateReqVO.java @@ -36,9 +36,12 @@ public class BpmOAReimbursementCreateReqVO { @NotNull(message = "报销总金额中文大写不能为空") private String totalMoneyChinese ; - @Schema(description = "报销类型", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "报销类型 | 1正常报销 2备用金报销", requiredMode = Schema.RequiredMode.REQUIRED) @NotNull(message = "报销类型不能为空") - private BigDecimal reimbursementType ; + private BigDecimal reimbursementType; + + @Schema(description = "项目编号") + private String projectNo; @Schema(description = "备用金ID") private Long imprestId; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/reimbursement/BpmOAReimbursementRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/reimbursement/BpmOAReimbursementRespVO.java index 73d29593..a659c86d 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/reimbursement/BpmOAReimbursementRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/reimbursement/BpmOAReimbursementRespVO.java @@ -43,6 +43,12 @@ public class BpmOAReimbursementRespVO extends BpmOABaseRespVO { @NotNull(message = "报销类型不能为空") private BigDecimal reimbursementType ; + @Schema(description = "项目编号") + private String projectNo; + + @Schema(description = "项目名称") + private String projectName; + @Schema(description = "备用金金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED) private BigDecimal amount; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/reimbursement/Reimbursement.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/reimbursement/Reimbursement.java index 96445a67..6c4091ca 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/reimbursement/Reimbursement.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/reimbursement/Reimbursement.java @@ -15,6 +15,9 @@ import java.util.Date; @Data public class Reimbursement { + @Schema(description = "主键ID") + private Long id; + @Schema(description = "所属部门ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "128") private Long deptId; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOACashDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOACashDO.java index 7b5b9d72..4dc637f8 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOACashDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOACashDO.java @@ -50,6 +50,11 @@ public class BpmOACashDO extends BaseDO { */ private BigDecimal totalMoney; + /** + * 项目编号 + */ + private String projectNo; + /** * 备用金申请编号 */ diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAReimbursementDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAReimbursementDO.java index ab03eb21..311bea39 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAReimbursementDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAReimbursementDO.java @@ -29,7 +29,7 @@ import java.util.List; public class BpmOAReimbursementDO extends BaseDO { /** - * 1: 自费 + * 1: 办公报销 */ public static final Integer EXPENSE_TYPE = 1; /** @@ -79,6 +79,11 @@ public class BpmOAReimbursementDO extends BaseDO { */ private String totalMoneyChinese; + /** + * 项目编号 + */ + private String projectNo; + /** * 报销类型 */ diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAReimbursementItemDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAReimbursementItemDO.java new file mode 100644 index 00000000..813a974a --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAReimbursementItemDO.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.oa; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * OA 报销明细 DO + * + * @author 姚君 + * + */ +@TableName(value ="bpm_oa_reimbursement_item", autoResultMap = true) +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmOAReimbursementItemDO extends BaseDO { + + /** + * 报销明细表单主键 + */ + @TableId + private Long id; + + /** + * 报销编号 + */ + private Long reimbursementId; + + /** + * 费用产生部门编号 + */ + private Long deptId; + + /** + * 报销金额 + */ + private BigDecimal money; + + /** + * 费用类型 | 字典值 参考bpm_oa_reimbursement_type + */ + private String type; + + /** + * 发生时间 + */ + private Date happenTime; + + /** + * 发票张数 + */ + private Integer quantity ; + + /** + * 费用明细 + */ + private String detail ; + + /** + * 采购申请编号 + */ + private Long procureId; +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAReimbursementItemMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAReimbursementItemMapper.java new file mode 100644 index 00000000..0e3e2fb8 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAReimbursementItemMapper.java @@ -0,0 +1,9 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.oa; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReimbursementItemDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface BpmOAReimbursementItemMapper extends BaseMapperX { +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderAbstractScript.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderAbstractScript.java index 6341e572..8da82110 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderAbstractScript.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderAbstractScript.java @@ -9,10 +9,12 @@ import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.runtime.ProcessInstance; +import org.omg.CORBA.IRObject; import org.springframework.context.annotation.Lazy; import org.springframework.util.Assert; import javax.annotation.Resource; +import java.util.Objects; import java.util.Set; import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; @@ -39,32 +41,59 @@ public abstract class BpmTaskAssignLeaderAbstractScript implements BpmTaskAssign // 获得发起人 ProcessInstance processInstance = bpmProcessInstanceService.getProcessInstance(execution.getProcessInstanceId()); Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId()); - // 获得对应 leve 的部门 - DeptRespDTO dept = null; - for (int i = 0; i < level; i++) { - // 获得 level 对应的部门 - if (dept == null) { - dept = getStartUserDept(startUserId); - if (dept == null) { // 找不到发起人的部门,所以无法使用该规则 - return emptySet(); - } - } else { - DeptRespDTO parentDept = deptApi.getDept(dept.getParentId()).getCheckedData(); - if (parentDept == null) { // 找不到父级部门,所以只好结束寻找。原因是:例如说,级别比较高的人,所在部门层级比较少 - break; - } - dept = parentDept; - } + // 获得发起人部门信息 + DeptRespDTO startUserDept = getStartUserDept(startUserId); + // 如果发起人部门为空,则直接返回空 + if (startUserDept == null) { + return emptySet(); } - Long leaderUserId = dept.getLeaderUserId() ; - if( leaderUserId !=null && !startUserId.toString().equals(leaderUserId.toString()) ) { - return asSet(dept.getLeaderUserId()) ; - }else if( leaderUserId !=null && startUserId.toString().equals(leaderUserId.toString()) ) { + // 如果发起人部门层级 小于等于 level,则直接返回发起人的部门负责人 + if (startUserDept.getLevel() <= level) { + return startUserDept.getLeaderUserId() == null ? emptySet() : asSet(startUserDept.getLeaderUserId()); + } + + // 获取发起人部门flag + String [] flag = startUserDept.getFlag().split("-"); + // 获取指定层级部门信息 + DeptRespDTO dept = deptApi.getDept(Long.valueOf(flag[level])).getCheckedData(); + Long leaderUserId = dept.getLeaderUserId(); + if(leaderUserId == null) { + return emptySet(); + } + + if (Objects.equals(leaderUserId, startUserId)) { //如果领导ID和发起人ID一致,那么需要再往上级机构寻找 - return calculateTaskCandidateUsers(execution, level+1) ; + return calculateTaskCandidateUsers(execution, level+1); }else { - return emptySet() ; + return asSet(dept.getLeaderUserId()); } + +// // 获得对应 leve 的部门 +// DeptRespDTO dept = null; +// for (int i = 0; i < level; i++) { +// // 获得 level 对应的部门 +// if (dept == null) { +// dept = getStartUserDept(startUserId); +// if (dept == null) { // 找不到发起人的部门,所以无法使用该规则 +// return emptySet(); +// } +// } else { +// DeptRespDTO parentDept = deptApi.getDept(dept.getParentId()).getCheckedData(); +// if (parentDept == null) { // 找不到父级部门,所以只好结束寻找。原因是:例如说,级别比较高的人,所在部门层级比较少 +// break; +// } +// dept = parentDept; +// } +// } +// Long leaderUserId = dept.getLeaderUserId() ; +// if( leaderUserId !=null && !startUserId.toString().equals(leaderUserId.toString()) ) { +// return asSet(dept.getLeaderUserId()) ; +// }else if( leaderUserId !=null && startUserId.toString().equals(leaderUserId.toString()) ) { +// //如果领导ID和发起人ID一致,那么需要再往上级机构寻找 +// return calculateTaskCandidateUsers(execution, level+1) ; +// }else { +// return emptySet() ; +// } //return dept.getLeaderUserId() != null ? asSet(dept.getLeaderUserId()) : emptySet(); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessCcServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessCcServiceImpl.java index 7d375d15..1a764aa5 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessCcServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessCcServiceImpl.java @@ -83,6 +83,6 @@ public class BpmProcessCcServiceImpl implements BpmProcessCcService { return processCcMapper.selectList(new LambdaQueryWrapperX() .likeIfPresent(BpmProcessCcDO::getName, name) - .eqIfPresent(BpmProcessCcDO::getCompanyDeptId, dto.getId())); + .likeIfPresent(BpmProcessCcDO::getCompanyDeptId, String.valueOf(dto.getId()))); } } \ 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/oa/BpmOAReimbursementService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAReimbursementService.java index 31907edb..b728922f 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAReimbursementService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAReimbursementService.java @@ -3,9 +3,12 @@ package cn.iocoder.yudao.module.bpm.service.oa; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.BpmOAReimbursementCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.BpmOAReimbursementRespVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOACashItemDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReimbursementDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReimbursementItemDO; import javax.validation.Valid; +import java.util.List; /** * 报销申请 Service 接口 @@ -40,6 +43,14 @@ public interface BpmOAReimbursementService { */ BpmOAReimbursementDO getReimbursement(Long id); + /** + * 获得指定得报销明细 + * + * @param reimbursementId 报销主表编号 + * @return 明细列表 + */ + List getReimbursementItem(Long reimbursementId); + BpmOAReimbursementRespVO convert(BpmOAReimbursementDO bpmOAReimbursementDO); /** diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAReimbursementServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAReimbursementServiceImpl.java index 23df388d..62dea807 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAReimbursementServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAReimbursementServiceImpl.java @@ -15,11 +15,10 @@ import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.Reimburs import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.ReimbursementDTO; import cn.iocoder.yudao.module.bpm.convert.oa.BpmOAReimbursementConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.financialpayment.FinancialPaymentDO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAImprestDO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAProcureDO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReimbursementDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.*; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAImprestMapper; +import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAReimbursementItemMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAReimbursementMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.service.financialpayment.FinancialPaymentService; @@ -80,6 +79,9 @@ public class BpmOAReimbursementServiceImpl extends BpmOABaseService implements B @Resource private BpmOAImprestMapper bpmOAImprestMapper; + @Resource + private BpmOAReimbursementItemMapper reimbursementItemMapper; + @Resource private BpmOAProcureService bpmOAProcureService; @@ -102,6 +104,11 @@ public class BpmOAReimbursementServiceImpl extends BpmOABaseService implements B .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); reimbursementMapper.insert(reimbursement); + // 同步插入明细数据 + List createDO = BeanUtils.toBean(createReqVO.getReimbursements(), BpmOAReimbursementItemDO.class); + createDO.forEach(item -> item.setReimbursementId(reimbursement.getId())); + reimbursementItemMapper.insertBatch(createDO); + // 发起 BPM 流程 Map processInstanceVariables = new HashMap<>(); String processInstanceId = processInstanceApi.createProcessInstance(userId, @@ -125,7 +132,7 @@ public class BpmOAReimbursementServiceImpl extends BpmOABaseService implements B //判断是否有 采购报销 List procureIds = new ArrayList<>(); - for (Reimbursement data : reimbursement.getReimbursements()) { + for (BpmOAReimbursementItemDO data : createDO) { //报销类别为 采购费时 if ("4".equals(data.getType())) { @@ -158,7 +165,8 @@ public class BpmOAReimbursementServiceImpl extends BpmOABaseService implements B BpmOAReimbursementDO bpmOAReimbursementDO = validateLeaveExists(id); - reimbursementMapper.updateById(new BpmOAReimbursementDO().setId(id).setResult(result)); + // 获取明细数据 + List reimbursements = getReimbursementItem(id); //审核通过 (最后节点) if (BpmProcessInstanceResultEnum.APPROVE.getResult().equals(result)) { @@ -169,13 +177,13 @@ public class BpmOAReimbursementServiceImpl extends BpmOABaseService implements B //判断是否有采购报销 List procureIds = new ArrayList<>(); - List reimbursements = bpmOAReimbursementDO.getReimbursements(); - - //直接从数据库取出来的List 实际上是List类型 所以不能直接遍历 - //将list再次转为json串,然后由json串再转为list - String json = JsonUtils.toJsonString(reimbursements); - reimbursements = JsonUtils.parseArray(json, Reimbursement.class); - for (Reimbursement reimbursement : reimbursements) { +// List reimbursements = bpmOAReimbursementDO.getReimbursements(); +// +// //直接从数据库取出来的List 实际上是List类型 所以不能直接遍历 +// //将list再次转为json串,然后由json串再转为list +// String json = JsonUtils.toJsonString(reimbursements); +// reimbursements = JsonUtils.parseArray(json, Reimbursement.class); + for (BpmOAReimbursementItemDO reimbursement : reimbursements) { //报销类别为 采购费时 if ("4".equals(reimbursement.getType())) { procureIds.add(reimbursement.getProcureId()); @@ -219,7 +227,7 @@ public class BpmOAReimbursementServiceImpl extends BpmOABaseService implements B } } - String reason = reimbursements.stream().map(Reimbursement::getDetail) + String reason = reimbursements.stream().map(BpmOAReimbursementItemDO::getDetail) .filter(StrUtil::isNotEmpty) .collect(Collectors.joining(",")); @@ -264,14 +272,14 @@ public class BpmOAReimbursementServiceImpl extends BpmOABaseService implements B //判断是否有采购报销 List procureIds = new ArrayList<>(); - List reimbursements = bpmOAReimbursementDO.getReimbursements(); +// List reimbursements = bpmOAReimbursementDO.getReimbursements(); +// +// //直接从数据库取出来的List 实际上是List类型 所以不能直接遍历 +// //将list再次转为json串,然后由json串再转为list +// String json = JsonUtils.toJsonString(reimbursements); +// reimbursements = JsonUtils.parseArray(json, Reimbursement.class); - //直接从数据库取出来的List 实际上是List类型 所以不能直接遍历 - //将list再次转为json串,然后由json串再转为list - String json = JsonUtils.toJsonString(reimbursements); - reimbursements = JsonUtils.parseArray(json, Reimbursement.class); - - for (Reimbursement reimbursement : reimbursements) { + for (BpmOAReimbursementItemDO reimbursement : reimbursements) { //报销类别为 采购费时 if ("4".equals(reimbursement.getType())) { @@ -294,7 +302,7 @@ public class BpmOAReimbursementServiceImpl extends BpmOABaseService implements B ); } } - + reimbursementMapper.updateById(new BpmOAReimbursementDO().setId(id).setResult(result)); } private BpmOAReimbursementDO validateLeaveExists(Long id) { @@ -311,19 +319,28 @@ public class BpmOAReimbursementServiceImpl extends BpmOABaseService implements B return reimbursementMapper.selectById(id); } + @Override + public List getReimbursementItem(Long reimbursementId) { + + return reimbursementItemMapper.selectList(BpmOAReimbursementItemDO::getReimbursementId, reimbursementId); + } + @Override public BpmOAReimbursementRespVO convert(BpmOAReimbursementDO reimbursementDO) { - List reimbursement = reimbursementDO.getReimbursements(); + // 获取明细数据 + List reimbursements = getReimbursementItem(reimbursementDO.getId()); - //直接从数据库取出来的List 实际上是List类型 所以不能直接遍历 - //将list再次转为json串,然后由json串再转为list - String json = JsonUtils.toJsonString(reimbursement); - reimbursement = JsonUtils.parseArray(json, Reimbursement.class); +// List reimbursement = reimbursementDO.getReimbursements(); +// +// //直接从数据库取出来的List 实际上是List类型 所以不能直接遍历 +// //将list再次转为json串,然后由json串再转为list +// String json = JsonUtils.toJsonString(reimbursement); +// reimbursement = JsonUtils.parseArray(json, Reimbursement.class); //针对之前的数据, 没有设置明细所属部门的 手动设置发起人的部门编号 AdminUserRespDTO userRespDTO = userApi.getUser(reimbursementDO.getUserId()).getCheckedData(); - for (Reimbursement data : reimbursement) { + for (BpmOAReimbursementItemDO data : reimbursements) { if (data.getDeptId() != null) { break; @@ -333,9 +350,9 @@ public class BpmOAReimbursementServiceImpl extends BpmOABaseService implements B } //获取部门信息map - Map deptMap = deptApi.getDeptMap(convertSet(reimbursement, Reimbursement::getDeptId)); + Map deptMap = deptApi.getDeptMap(convertSet(reimbursements, BpmOAReimbursementItemDO::getDeptId)); - List reimbursementDTOS = BeanUtils.toBean(reimbursement, ReimbursementDTO.class); + List reimbursementDTOS = BeanUtils.toBean(reimbursements, ReimbursementDTO.class); BpmOAReimbursementRespVO bpmOAReimbursementRespVO = BeanUtils.toBean(reimbursementDO, BpmOAReimbursementRespVO.class); bpmOAReimbursementRespVO.setReimbursements(BpmOAReimbursementConvert.INSTANCE.convertList(reimbursementDTOS, deptMap)); //拼接数据 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 fcfbf2b3..7b0c78e7 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.collection.CollectionUtil; import cn.hutool.core.date.LocalDateTimeUtil; 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.date.DateUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; 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.cash.BpmOACashRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmOACashPrintDataRespVO; 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.BpmProcessCcDO; 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.BpmOACashDO; 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.DynamicMapper; 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.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.BpmProcessCcService; 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.BpmOACashService; 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.bpm.service.task.dto.ProcessInstanceVariablesDTO; import cn.iocoder.yudao.module.infra.api.config.ConfigApi; 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 jodd.util.StringUtil; 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.time.temporal.ChronoUnit; 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; @Resource private ConfigApi configApi; @Resource private DynamicMapper dynamicMapper ; @Resource private BpmProcessCcService processCcService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } public String transform(String input) { if(StringUtil.isNotEmpty(input)) { String[] parts = input.split(","); StringBuilder result = new StringBuilder(); for (String part : parts) { String[] keyValue = part.split(":"); if (keyValue.length > 1) { result.append(keyValue[1]).append(","); } } if (result.length() > 0) { return result.substring(0, result.length() - 1); } } return ""; } public String replaceValues(String input, Map map) { String[] parts = input.split(","); StringBuilder result = new StringBuilder(); for (String part : parts) { String[] keyValue = part.split(":"); if (keyValue.length > 1) { String key = keyValue[1].trim(); // 去除可能的空格 if (map.containsKey(key)) { Object value = map.get(key); String stringValue = (value != null) ? value.toString() : ""; // 将值转换为字符串 result.append(keyValue[0].trim()).append(":").append(stringValue).append(","); } else { //result.append(part).append(","); } } } if (result.length() > 0) { return result.substring(0, result.length() - 1); } return ""; } @Override @TenantIgnore public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); List bpmProcessInstanceExtDOList = pageResult.getList() ; for (int i = 0; i < bpmProcessInstanceExtDOList.size() ; i++) { BpmProcessInstanceExtDO bpmProcessInstanceExtDO = bpmProcessInstanceExtDOList.get(i) ; String input = bpmProcessInstanceExtDO.getFieldNames() ; if(StringUtil.isNotEmpty(input)) { String sql = "SELECT " + transform(bpmProcessInstanceExtDO.getFieldNames()) + " FROM " + bpmProcessInstanceExtDO.getTableName() + " WHERE id=" + bpmProcessInstanceExtDO.getBusinessKey(); log.info(sql); Map map = dynamicMapper.selectListByTableName(sql) ; String detailInfo = replaceValues(bpmProcessInstanceExtDO.getFieldNames(),map) ; bpmProcessInstanceExtDO.setDetailInfo(detailInfo); } } 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); // 查询流程变量 List variables = processInstanceExtMapper.selectFormVariables(instance.getProcessInstanceId()); Map paramMap = variables.stream().collect(Collectors.toMap(ProcessInstanceVariablesDTO::getName, ProcessInstanceVariablesDTO::getValue)); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(paramMap)); // 创建流程后,添加抄送人 processCCToUsers(instance); } @Override @DataPermission(enable = false) 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 @DataPermission(enable = false) 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) @DataPermission(enable = false) 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) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .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); //获取流程发起人User AdminUserRespDTO startUser = adminUserApi.getUser(userId).getCheckedData(); //获取流程发起人部门信息 DeptRespDTO startDeptInfo = deptApi.getDept(startUser.getDeptId()).getCheckedData(); // 获取岗位信息 Set postIds = startUser.getPostIds(); ArrayList list = new ArrayList<>(postIds); //配置通用流程变量 variables.put("post_id", list.get(0).toString()); // 只获配置的首个岗位 variables.put("user_id", userId.toString()); // 配置发起人用户id variables.put("dept_id", startUser.getDeptId().toString()); // 配置发起人部门id variables.put("dept_flag", startDeptInfo.getFlag()); // 配置发起人部门flag // 创建流程实例 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 * @param * @return */ 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); String BpmConstantsName = BpmConstants.CC_NAME; // 获取发起人信息 AdminUserRespDTO userRespDTO = adminUserApi.getUser(Long.valueOf(instance.getStartUserId())).getCheckedData(); DeptRespDTO deptRespDTO = deptApi.getDept(userRespDTO.getDeptId()).getCheckedData(); //发起人是深圳分公司 if (deptRespDTO.getFlag().contains("136")) { BpmConstantsName = BpmConstants.CCSZ_NAME; } for (BpmTaskAssignRuleDO rule : rules) { String key = rule.getTaskDefinitionKey(); //任务名称 Integer type = rule.getType(); if (!key.isEmpty() && key.equals(BpmConstantsName) && 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)) { //发起人部门为 生产部及以下时 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; } } } /** * 创建流程后,添加抄送人 * @param instance 流程实例 */ private void processCCToUsers(ProcessInstance instance) { // 根据流程名称、流程发起人 查询流程配置的抄送人信息 List processCcList = processCcService.getCCListByName(instance.getName(), Long.valueOf(instance.getStartUserId())); // 提取抄送信息用中对应的用户组编号 Set userGroupIds = processCcList.stream() .flatMap(data -> data.getUserGroupId().stream()) .collect(Collectors.toSet()); if (CollectionUtil.isNotEmpty(userGroupIds)) { // 获取用户组信息 List userGroups = userGroupService.getUserGroupList(userGroupIds); // 提取用户组中对应的用户ID Set userIds = userGroups.stream() .flatMap(data -> data.getMemberUserIds().stream()) .collect(Collectors.toSet()); // 将用户ID列表转换为字符串 String ccIds = userIds.stream() .map(id -> "[" + id + "]") // 每个值用方括号包裹 .collect(Collectors.joining()); //根据processDefinitionId 将ccIds保存到bpm_process_instance_ext中的ccIds字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessDefinitionId(instance.getProcessDefinitionId()) .setCcids(ccIds) .setProcessInstanceId(instance.getProcessInstanceId()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); } } @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 @DataPermission(enable = false) public BpmProcessInstanceExtDO getProcessInstanceDO(String id) { return processInstanceExtMapper.selectByProcessInstanceId(id); } @Resource private FileApi fileApi; @Resource @Lazy // 解决循环依赖 private BpmOAReimbursementService reimbursementService; @Resource @Lazy // 解决循环依赖 private BpmOACashService cashService; @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 // 判断是否可见外勤人员信息 List userIds = new ArrayList<>(); String type = configApi.getConfigKey("sys.user.type").getCheckedData(); if ("1".equals(type)) { //不可见时 // 获取所有外勤人员 用户编号 userIds = adminUserApi.getUserIdsByUserNature(4).getCheckedData(); } // 获得流程审批信息 List taskRespVOList = taskService.getTaskListByProcessInstanceId(processInstanceId); // 移除外勤人员信息 List finalUserIds = userIds; taskRespVOList.removeIf(data -> finalUserIds.contains(data.getAssigneeUser().getId())); //给User添加签名地址 taskRespVOList.forEach(taskRespVO -> taskRespVO.getAssigneeUser().setSignURL( fileApi.getUserSignImgPath( taskRespVO.getAssigneeUser().getId() ).getData() ) ); //获取流程抄送用户编号 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))); } // 移除 外勤人员信息 ccUserIds.removeAll(userIds); } List userRespDTOS = adminUserApi.getUserList(ccUserIds).getCheckedData(); //获取抄送用户部门信息 Map deptMapDTO = deptApi.getDeptMap(convertSet(userRespDTOS, AdminUserRespDTO::getDeptId)); if ("oa_reimbursement".equals(key)) { //报销流程 BpmOAReimbursementDO reimbursement = reimbursementService.getReimbursement(businessKey); BpmOAReimbursementRespVO bpmOAReimbursementRespVO = reimbursementService.convert(reimbursement); //报销业务数据 // 移除自己得审批节点 taskRespVOList.removeIf(data -> data.getAssigneeUser().getId().equals(reimbursement.getUserId())); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprest(reimbursement.getImprestId()); if (bpmOAImprestDO != null) { //设置备用金 金额 bpmOAReimbursementRespVO.setAmount(bpmOAImprestDO.getAmount()); // 设置备用金 剩余金额 bpmOAReimbursementRespVO.setRemainingAmount(bpmOAImprestDO.getAmount().subtract(bpmOAImprestDO.getReimbursedAmount())); } // 设置抄送人信息 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); } if ("oa_cash".equals(key)) { BpmOACashDO cashDO = cashService.getCash(businessKey); BpmOACashRespVO cashRespVO = cashService.convertCash(cashDO); // 移除自己得审批节点 taskRespVOList.removeIf(data -> data.getAssigneeUser().getId().equals(cashDO.getUserId())); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprest(cashDO.getImprestId()); if (bpmOAImprestDO != null) { //设置备用金 金额 cashRespVO.setAmount(bpmOAImprestDO.getAmount()); // 设置备用金 剩余金额 cashRespVO.setRemainingAmount(bpmOAImprestDO.getAmount().subtract(bpmOAImprestDO.getReimbursedAmount())); } // 设置抄送人信息 List ccUsers = userRespDTOS.stream().map(user -> { BpmOACashPrintDataRespVO.CCUser cc = new BpmOACashPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOACashPrintDataRespVO cashPrintData = new BpmOACashPrintDataRespVO(); cashPrintData.setBpmOACashRespVO(cashRespVO); cashPrintData.setProcessTasks(taskRespVOList); cashPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOACashPrintDataRespVO(cashPrintData); } return bpmProcessInstancePrintDataRespVO; } @Override public Map> getProcessInstanceResultStatusStatisticsGroupTime(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); pageReqVO.setRecentDays(pageReqVO.getRecentDays() == null ? 7 : pageReqVO.getRecentDays()); List list = processInstanceExtMapper.getProcessInstanceResultStatusStatisticsGroupTime(pageReqVO); // -- 获取到日期列表 LocalDateTime now = LocalDateTimeUtil.now(); LocalDateTime offset = LocalDateTimeUtil.offset(LocalDateTimeUtil.now(), -1L * pageReqVO.getRecentDays(), ChronoUnit.DAYS); List dateList = DateUtils.betweenDayList(offset, now); //根据时间分组 Map> map = list.stream().collect(Collectors.groupingBy(BpmProcessInstanceResultStatusStatisticsGroupTimeVO::getTime)); List keys = new ArrayList<>(CollectionUtil.subtract(dateList, new ArrayList<>(map.keySet()))); if (CollectionUtil.isNotEmpty(keys)) { for (String key : keys) { map.put(key, new ArrayList<>()); } } List statusList = Arrays.asList(1, 2, 3, 4); for (Map.Entry> entry : map.entrySet()) { List items = entry.getValue(); List results = items.stream().map(BpmProcessInstanceResultStatusStatisticsGroupTimeVO::getResult).collect(Collectors.toList()); List saveList = new ArrayList<>(CollectionUtil.subtract(statusList, results)); // -- 如果没有的话组装上缺少的 if (CollectionUtil.isNotEmpty(saveList)) { for (Integer status : saveList) { items.add(new BpmProcessInstanceResultStatusStatisticsGroupTimeVO() .setTime(entry.getKey()) .setTotalCount(0) .setResult(status) .setName("")); } } } return map; } } \ No newline at end of file +package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.LocalDateTimeUtil; 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.date.DateUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; 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.cash.BpmOACashRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmOACashPrintDataRespVO; 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.convert.task.BpmTaskConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessCcDO; 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.BpmOACashDO; 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.DynamicMapper; 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.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.BpmProcessCcService; 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.BpmOACashService; 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.bpm.service.task.dto.ProcessInstanceVariablesDTO; import cn.iocoder.yudao.module.infra.api.config.ConfigApi; 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 jodd.util.StringUtil; import liquibase.pro.packaged.T; 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.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronizationManager; 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.time.temporal.ChronoUnit; 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; @Resource private ConfigApi configApi; @Resource private DynamicMapper dynamicMapper ; @Resource private BpmProcessCcService processCcService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } public String transform(String input) { if(StringUtil.isNotEmpty(input)) { String[] parts = input.split(","); StringBuilder result = new StringBuilder(); for (String part : parts) { String[] keyValue = part.split(":"); if (keyValue.length > 1) { result.append(keyValue[1]).append(","); } } if (result.length() > 0) { return result.substring(0, result.length() - 1); } } return ""; } public String replaceValues(String input, Map map) { String[] parts = input.split(","); StringBuilder result = new StringBuilder(); for (String part : parts) { String[] keyValue = part.split(":"); if (keyValue.length > 1) { String key = keyValue[1].trim(); // 去除可能的空格 if (map.containsKey(key)) { Object value = map.get(key); String stringValue = (value != null) ? value.toString() : ""; // 将值转换为字符串 result.append(keyValue[0].trim()).append(":").append(stringValue).append(","); } else { //result.append(part).append(","); } } } if (result.length() > 0) { return result.substring(0, result.length() - 1); } return ""; } @Override @TenantIgnore public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); List bpmProcessInstanceExtDOList = pageResult.getList() ; for (int i = 0; i < bpmProcessInstanceExtDOList.size() ; i++) { BpmProcessInstanceExtDO bpmProcessInstanceExtDO = bpmProcessInstanceExtDOList.get(i) ; String input = bpmProcessInstanceExtDO.getFieldNames() ; if(StringUtil.isNotEmpty(input)) { String sql = "SELECT " + transform(bpmProcessInstanceExtDO.getFieldNames()) + " FROM " + bpmProcessInstanceExtDO.getTableName() + " WHERE id=" + bpmProcessInstanceExtDO.getBusinessKey(); log.info(sql); Map map = dynamicMapper.selectListByTableName(sql) ; String detailInfo = replaceValues(bpmProcessInstanceExtDO.getFieldNames(),map) ; bpmProcessInstanceExtDO.setDetailInfo(detailInfo); } } 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 @Transactional(rollbackFor = Exception.class) 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 @DataPermission(enable = false) 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 @DataPermission(enable = false) 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) @DataPermission(enable = false) 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) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .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); //获取流程发起人User AdminUserRespDTO startUser = adminUserApi.getUser(userId).getCheckedData(); //获取流程发起人部门信息 DeptRespDTO startDeptInfo = deptApi.getDept(startUser.getDeptId()).getCheckedData(); // 获取岗位信息 Set postIds = startUser.getPostIds(); ArrayList list = new ArrayList<>(postIds); //配置通用流程变量 variables.put("post_id", list.get(0).toString()); // 只获配置的首个岗位 variables.put("user_id", userId.toString()); // 配置发起人用户id variables.put("dept_id", startUser.getDeptId().toString()); // 配置发起人部门id variables.put("dept_flag", startDeptInfo.getFlag()); // 配置发起人部门flag // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // 发送通知。在事务提交时,批量执行操作,所以直接查询会无法查询到 ProcessInstance,所以这里是通过监听事务的提交来实现。 TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { @Override public void afterCommit() { // 创建流程后,添加抄送人 processCCToUsers(instance, variables); } }); return instance.getId(); // // 补全流程实例的拓展表 // processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) // .setFormVariables(variables)); // // /** 创建流程后,添加抄送人 End add by yj 2024.1.4 */ // processCCToUsers(definition, instance); // /** 通过自己发起的流程 */ // approveSelfTask(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 * @param * @return */ 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); String BpmConstantsName = BpmConstants.CC_NAME; // 获取发起人信息 AdminUserRespDTO userRespDTO = adminUserApi.getUser(Long.valueOf(instance.getStartUserId())).getCheckedData(); DeptRespDTO deptRespDTO = deptApi.getDept(userRespDTO.getDeptId()).getCheckedData(); //发起人是深圳分公司 if (deptRespDTO.getFlag().contains("136")) { BpmConstantsName = BpmConstants.CCSZ_NAME; } for (BpmTaskAssignRuleDO rule : rules) { String key = rule.getTaskDefinitionKey(); //任务名称 Integer type = rule.getType(); if (!key.isEmpty() && key.equals(BpmConstantsName) && 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)) { //发起人部门为 生产部及以下时 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; } } } /** * 创建流程后,添加抄送人 * @param instance 流程实例 */ private void processCCToUsers(ProcessInstance instance, Map variables) { // 根据流程名称、流程发起人 查询流程配置的抄送人信息 List processCcList = processCcService.getCCListByName(instance.getName(), Long.valueOf(instance.getStartUserId())); // 提取抄送信息用中对应的用户组编号 Set userGroupIds = processCcList.stream() .flatMap(data -> data.getUserGroupId().stream()) .collect(Collectors.toSet()); //根据processDefinitionId 将ccIds保存到bpm_process_instance_ext中的ccIds字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessDefinitionId(instance.getProcessDefinitionId()) .setFormVariables(variables) .setProcessInstanceId(instance.getProcessInstanceId()); if (CollectionUtil.isNotEmpty(userGroupIds)) { // 获取用户组信息 List userGroups = userGroupService.getUserGroupList(userGroupIds); // 提取用户组中对应的用户ID Set userIds = userGroups.stream() .flatMap(data -> data.getMemberUserIds().stream()) .collect(Collectors.toSet()); // 将用户ID列表转换为字符串 String ccIds = userIds.stream() .map(id -> "[" + id + "]") // 每个值用方括号包裹 .collect(Collectors.joining()); //根据processDefinitionId 将ccIds保存到bpm_process_instance_ext中的ccIds字段 instanceExtDO.setCcids(ccIds); } processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); } @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 @DataPermission(enable = false) public BpmProcessInstanceExtDO getProcessInstanceDO(String id) { return processInstanceExtMapper.selectByProcessInstanceId(id); } @Resource private FileApi fileApi; @Resource @Lazy // 解决循环依赖 private BpmOAReimbursementService reimbursementService; @Resource @Lazy // 解决循环依赖 private BpmOACashService cashService; @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 // 判断是否可见外勤人员信息 List userIds = new ArrayList<>(); String type = configApi.getConfigKey("sys.user.type").getCheckedData(); if ("1".equals(type)) { //不可见时 // 获取所有外勤人员 用户编号 userIds = adminUserApi.getUserIdsByUserNature(4).getCheckedData(); } // 获得流程审批信息 List taskRespVOList = taskService.getTaskListByProcessInstanceId(processInstanceId); // 移除外勤人员信息 List finalUserIds = userIds; taskRespVOList.removeIf(data -> finalUserIds.contains(data.getAssigneeUser().getId())); //给User添加签名地址 taskRespVOList.forEach(taskRespVO -> taskRespVO.getAssigneeUser().setSignURL( fileApi.getUserSignImgPath( taskRespVO.getAssigneeUser().getId() ).getData() ) ); //获取流程抄送用户编号 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))); } // 移除 外勤人员信息 ccUserIds.removeAll(userIds); } List userRespDTOS = adminUserApi.getUserList(ccUserIds).getCheckedData(); //获取抄送用户部门信息 Map deptMapDTO = deptApi.getDeptMap(convertSet(userRespDTOS, AdminUserRespDTO::getDeptId)); if ("oa_reimbursement".equals(key)) { //报销流程 BpmOAReimbursementDO reimbursement = reimbursementService.getReimbursement(businessKey); BpmOAReimbursementRespVO bpmOAReimbursementRespVO = reimbursementService.convert(reimbursement); //报销业务数据 // 移除自己得审批节点 taskRespVOList.removeIf(data -> data.getAssigneeUser().getId().equals(reimbursement.getUserId())); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprest(reimbursement.getImprestId()); if (bpmOAImprestDO != null) { //设置备用金 金额 bpmOAReimbursementRespVO.setAmount(bpmOAImprestDO.getAmount()); // 设置备用金 剩余金额 bpmOAReimbursementRespVO.setRemainingAmount(bpmOAImprestDO.getAmount().subtract(bpmOAImprestDO.getReimbursedAmount())); } // 设置抄送人信息 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); } if ("oa_cash".equals(key)) { BpmOACashDO cashDO = cashService.getCash(businessKey); BpmOACashRespVO cashRespVO = cashService.convertCash(cashDO); // 移除自己得审批节点 taskRespVOList.removeIf(data -> data.getAssigneeUser().getId().equals(cashDO.getUserId())); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprest(cashDO.getImprestId()); if (bpmOAImprestDO != null) { //设置备用金 金额 cashRespVO.setAmount(bpmOAImprestDO.getAmount()); // 设置备用金 剩余金额 cashRespVO.setRemainingAmount(bpmOAImprestDO.getAmount().subtract(bpmOAImprestDO.getReimbursedAmount())); } // 设置抄送人信息 List ccUsers = userRespDTOS.stream().map(user -> { BpmOACashPrintDataRespVO.CCUser cc = new BpmOACashPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOACashPrintDataRespVO cashPrintData = new BpmOACashPrintDataRespVO(); cashPrintData.setBpmOACashRespVO(cashRespVO); cashPrintData.setProcessTasks(taskRespVOList); cashPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOACashPrintDataRespVO(cashPrintData); } return bpmProcessInstancePrintDataRespVO; } @Override public Map> getProcessInstanceResultStatusStatisticsGroupTime(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); pageReqVO.setRecentDays(pageReqVO.getRecentDays() == null ? 7 : pageReqVO.getRecentDays()); List list = processInstanceExtMapper.getProcessInstanceResultStatusStatisticsGroupTime(pageReqVO); // -- 获取到日期列表 LocalDateTime now = LocalDateTimeUtil.now(); LocalDateTime offset = LocalDateTimeUtil.offset(LocalDateTimeUtil.now(), -1L * pageReqVO.getRecentDays(), ChronoUnit.DAYS); List dateList = DateUtils.betweenDayList(offset, now); //根据时间分组 Map> map = list.stream().collect(Collectors.groupingBy(BpmProcessInstanceResultStatusStatisticsGroupTimeVO::getTime)); List keys = new ArrayList<>(CollectionUtil.subtract(dateList, new ArrayList<>(map.keySet()))); if (CollectionUtil.isNotEmpty(keys)) { for (String key : keys) { map.put(key, new ArrayList<>()); } } List statusList = Arrays.asList(1, 2, 3, 4); for (Map.Entry> entry : map.entrySet()) { List items = entry.getValue(); List results = items.stream().map(BpmProcessInstanceResultStatusStatisticsGroupTimeVO::getResult).collect(Collectors.toList()); List saveList = new ArrayList<>(CollectionUtil.subtract(statusList, results)); // -- 如果没有的话组装上缺少的 if (CollectionUtil.isNotEmpty(saveList)) { for (Integer status : saveList) { items.add(new BpmProcessInstanceResultStatusStatisticsGroupTimeVO() .setTime(entry.getKey()) .setTotalCount(0) .setResult(status) .setName("")); } } } return map; } } \ No newline at end of file From 9d75942a8b031354bbc042bd4e7e7318be53a4b6 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Fri, 29 Nov 2024 17:06:56 +0800 Subject: [PATCH 2/7] =?UTF-8?q?refactor(bpm):=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E8=A7=84=E5=88=99=E8=84=9A=E6=9C=AC=E6=9E=9A?= =?UTF-8?q?=E4=B8=BE=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -将 LEADER_X4 的描述从 "审批人的一级领导" 修改为 "审批人的上级领导" - 这个修改使得枚举描述更加通用,适用于不同的审批场景 --- .../module/bpm/enums/definition/BpmTaskRuleScriptEnum.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskRuleScriptEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskRuleScriptEnum.java index dccf2c7c..ff987f2e 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskRuleScriptEnum.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskRuleScriptEnum.java @@ -18,7 +18,7 @@ public enum BpmTaskRuleScriptEnum { LEADER_X1(20L, "流程发起人的一级领导"), LEADER_X2(21L, "流程发起人的二级领导"), LEADER_X3(22L, "流程发起人的三级领导"), - LEADER_X4(23L, "审批人的一级领导"), + LEADER_X4(23L, "审批人的上级领导"), LEADER_X5(24L, "调岗部门领导"), LEADER_X6(25L, "分配任务的责任人"), LEADER_X7(26L, "入职部门领导"), From a2de6d84b124a8a8c16b7a36ac8a8e0489c978fb Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Fri, 29 Nov 2024 17:07:17 +0800 Subject: [PATCH 3/7] =?UTF-8?q?feat(system):=20=E6=96=B0=E5=A2=9E=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E7=AE=A1=E7=90=86=E7=9B=B8=E5=85=B3=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增获取项目信息接口 - 新增获取我参与的项目列表接口 - 优化考勤机状态更新任务 - 重构生日提醒任务逻辑 - 新增合同提醒相关功能 --- .../module/system/api/project/ProjectApi.java | 6 +++++- .../system/api/project/ProjectApiImpl.java | 7 +++++++ .../admin/project/ProjectController.java | 10 ++++++++++ .../admin/project/vo/ProjectSaveReqVO.java | 1 - .../mysql/laborcontract/LaborContractMapper.java | 3 +++ .../module/system/job/birthday/BirthdayJob.java | 15 ++++----------- .../job/equipment/AttendanceMachineJob.java | 10 +++++++--- .../laborcontract/LaborContractService.java | 8 ++++++++ .../laborcontract/LaborContractServiceImpl.java | 6 ++++++ .../system/service/project/ProjectService.java | 15 +++++++++++++++ .../service/project/ProjectServiceImpl.java | 16 ++++++++++++++++ .../mapper/laborcontract/LaborContractMapper.xml | 10 ++++++++++ .../resources/mapper/user/AdminUserMapper.xml | 1 + 13 files changed, 92 insertions(+), 16 deletions(-) diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/project/ProjectApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/project/ProjectApi.java index ab99f57c..99555a67 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/project/ProjectApi.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/project/ProjectApi.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.system.api.project; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.system.api.position.dto.PositionDTO; import cn.iocoder.yudao.module.system.api.project.dto.ProjectDTO; import cn.iocoder.yudao.module.system.enums.ApiConstants; import io.swagger.v3.oas.annotations.Operation; @@ -22,4 +21,9 @@ public interface ProjectApi { @PostMapping(PREFIX + "/create") @Operation(summary = "创建项目") CommonResult create(@RequestBody ProjectDTO createReqVO); + + @GetMapping(PREFIX + "/get") + @Operation(summary = "获得项目") + @Parameter(name = "projectNo", description = "项目编号", required = true) + CommonResult getProject(@RequestParam("projectNo") String projectNo); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/project/ProjectApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/project/ProjectApiImpl.java index ba9a7202..a2da17ca 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/project/ProjectApiImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/project/ProjectApiImpl.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.system.api.project.dto.ProjectDTO; import cn.iocoder.yudao.module.system.controller.admin.project.vo.ProjectSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.project.ProjectDO; import cn.iocoder.yudao.module.system.service.project.ProjectService; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.RestController; @@ -23,4 +24,10 @@ public class ProjectApiImpl implements ProjectApi { public CommonResult create(ProjectDTO createReqVO) { return success(projectService.createProject(BeanUtils.toBean(createReqVO, ProjectSaveReqVO.class))); } + + @Override + public CommonResult getProject(String projectNo) { + ProjectDO projectDO = projectService.getProject(projectNo); + return success(BeanUtils.toBean(projectDO, ProjectDTO.class)); + } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/ProjectController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/ProjectController.java index 66299591..45ed5562 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/ProjectController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/ProjectController.java @@ -29,6 +29,7 @@ import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; @Tag(name = "管理后台 - 项目管理") @RestController @@ -180,4 +181,13 @@ public class ProjectController { return success(respVOs); } + + @GetMapping("/get-my-project") + @Operation(summary = "获得我参与的项目") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:project:query')") + public CommonResult> getMyProject() { + List projectList = projectService.getMyProject(getLoginUserId()); + return success(BeanUtils.toBean(projectList, ProjectRespVO.class)); + } } \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectSaveReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectSaveReqVO.java index 950dfe6f..fd97fd43 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectSaveReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectSaveReqVO.java @@ -32,7 +32,6 @@ public class ProjectSaveReqVO { private Long responsibleDept; @Schema(description = "参与部门集合", requiredMode = Schema.RequiredMode.REQUIRED) - @NotEmpty(message = "参与部门集合不能为空") private Set participationDept; @Schema(description = "责任人用户编号", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/laborcontract/LaborContractMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/laborcontract/LaborContractMapper.java index 1c44f45d..027b78e1 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/laborcontract/LaborContractMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/laborcontract/LaborContractMapper.java @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.laborcontract.LaborContract import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; +import java.time.LocalDate; import java.util.List; /** @@ -35,4 +36,6 @@ public interface LaborContractMapper extends BaseMapperX { * @return */ LaborContractDO getTheEarliestContract(@Param("userId") Long userId); + + List selectListByRemindDate(@Param("remindDate")LocalDate remindDate); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/birthday/BirthdayJob.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/birthday/BirthdayJob.java index 45d93e09..b324113e 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/birthday/BirthdayJob.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/birthday/BirthdayJob.java @@ -27,7 +27,6 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Set; -import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; @@ -115,17 +114,11 @@ public class BirthdayJob { // 获得提醒日期 LocalDate remindDate = LocalDate.now().plusDays(remindDuration == null ? 7 : remindDuration); - // 查询所有试用人员 - List userDOS = userService.getUserListByUserStaffing(5); - List userIds = convertList(userDOS, AdminUserDO::getId); + // 查询提醒日期内的试用人员合同 + List laborContractDOS = laborContractService.getListByRemindDate(remindDate); - List laborContractDOS = laborContractService.getListByUserIds(userIds); - List contractUserIds = laborContractDOS.stream().filter(item -> remindDate.isEqual(item.getSigningDate().plusMonths(item.getProbationPeriodTime()))) - .map(LaborContractDO::getUserId) - .collect(Collectors.toList()); - - // 过滤需要提醒的用户 - List positiveUserList = userDOS.stream().filter(item -> contractUserIds.contains(item.getId())).collect(Collectors.toList()); + // 获取需要提醒的用户 + List positiveUserList = userService.getUserList(convertList(laborContractDOS, LaborContractDO::getUserId)); for (AdminUserDO adminUserDO : positiveUserList) { if( adminUserDO.getOpenId() != null && !adminUserDO.getOpenId().isEmpty()) { diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/equipment/AttendanceMachineJob.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/equipment/AttendanceMachineJob.java index 4e93b134..92841ddd 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/equipment/AttendanceMachineJob.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/job/equipment/AttendanceMachineJob.java @@ -8,10 +8,11 @@ import cn.iocoder.yudao.module.system.controller.admin.equipment.vo.attendancema import cn.iocoder.yudao.module.system.dal.dataobject.equipment.AttendanceMachineDO; import cn.iocoder.yudao.module.system.service.equipment.AttendanceMachineService; import com.github.yulichang.toolkit.SpringContentUtils; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.handler.annotation.XxlJob; import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import javax.annotation.Resource; @@ -31,9 +32,9 @@ public class AttendanceMachineJob { @Resource private StringRedisTemplate stringRedisTemplate; - @Scheduled(initialDelay = 5000, fixedRate = 30000) + @XxlJob("updateAttendanceMachineStatusJob") @TenantJob - public void updateAttendanceMachineStatus() { + public ReturnT execute() { WebSocketSessionManager webSocketSessionManager = SpringContentUtils.getBean(WebSocketSessionManager.class); @@ -62,5 +63,8 @@ public class AttendanceMachineJob { attendanceMachineService.updateAttendanceMachineStatus(statusUpdateVOS); } + + // 返回执行成功 + return ReturnT.SUCCESS; } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/laborcontract/LaborContractService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/laborcontract/LaborContractService.java index 33639c5c..2d171520 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/laborcontract/LaborContractService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/laborcontract/LaborContractService.java @@ -102,4 +102,12 @@ public interface LaborContractService { * @return */ LaborContractDO getTheEarliestContract(Long userId); + + /** + * 获取指定日期内即将转正的人员 + * + * @param remindDate 日期 + * @return 合同列表 + */ + List getListByRemindDate(LocalDate remindDate); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/laborcontract/LaborContractServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/laborcontract/LaborContractServiceImpl.java index b79881d7..95caafb0 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/laborcontract/LaborContractServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/laborcontract/LaborContractServiceImpl.java @@ -165,4 +165,10 @@ public class LaborContractServiceImpl implements LaborContractService { public LaborContractDO getTheEarliestContract(Long userId) { return laborContractMapper.getTheEarliestContract(userId); } + + @Override + public List getListByRemindDate(LocalDate remindDate) { + + return laborContractMapper.selectListByRemindDate(remindDate); + } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/project/ProjectService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/project/ProjectService.java index bf942b7d..54562973 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/project/ProjectService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/project/ProjectService.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.system.controller.admin.project.vo.ProjectSaveReq import cn.iocoder.yudao.module.system.dal.dataobject.project.ProjectDO; import javax.validation.Valid; +import java.util.List; /** * 项目管理 Service 接口 @@ -44,6 +45,14 @@ public interface ProjectService { */ ProjectDO getProject(Long id); + /** + * 获得项目管理 + * + * @param projectNo 项目编号 + * @return 项目 + */ + ProjectDO getProject(String projectNo); + /** * 获得项目管理分页 * @@ -52,4 +61,10 @@ public interface ProjectService { */ PageResult getProjectPage(ProjectPageReqVO pageReqVO); + /** + * 获得我参与的项目列表 + * @param userId 用户编号 + * @return 项目列表 + */ + List getMyProject(Long userId); } \ 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/project/ProjectServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/project/ProjectServiceImpl.java index faf15d46..f88027af 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/project/ProjectServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/project/ProjectServiceImpl.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.service.project; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.system.controller.admin.project.vo.ProjectPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.project.vo.ProjectSaveReqVO; import cn.iocoder.yudao.module.system.dal.dataobject.project.ProjectDO; @@ -11,6 +12,7 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; +import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.PROJECT_NOT_EXISTS; @@ -65,9 +67,23 @@ public class ProjectServiceImpl implements ProjectService { return projectMapper.selectById(id); } + @Override + public ProjectDO getProject(String projectNo) { + return projectMapper.selectOne(ProjectDO::getProjectNo, projectNo); + } + @Override public PageResult getProjectPage(ProjectPageReqVO pageReqVO) { return projectMapper.selectPage(pageReqVO); } + @Override + public List getMyProject(Long userId) { + return projectMapper.selectList(new LambdaQueryWrapperX() + .eq(ProjectDO::getDirectorUserId, userId) + .or() + .like(ProjectDO::getStaff, userId) + .eq(ProjectDO::getStatus, 1)); + } + } \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/laborcontract/LaborContractMapper.xml b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/laborcontract/LaborContractMapper.xml index d42a3258..de8317a9 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/laborcontract/LaborContractMapper.xml +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/laborcontract/LaborContractMapper.xml @@ -29,4 +29,14 @@ system_labor_contract where deleted = 0 and user_id = #{userId} + diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/user/AdminUserMapper.xml b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/user/AdminUserMapper.xml index 67eaa202..0ed5ee3d 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/user/AdminUserMapper.xml +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/user/AdminUserMapper.xml @@ -21,6 +21,7 @@ a.dept_id = b.id and a.status = 0 and a.user_type = 1 + and a.deleted = 0 and a.dept_id in #{deptIds} From 5c1689039770717630e238578eb7db2c14619be4 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Fri, 29 Nov 2024 17:08:51 +0800 Subject: [PATCH 4/7] =?UTF-8?q?refactor(bpm):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=BB=93=E6=9E=84=E5=92=8C=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除了不必要的导入语句 -调整了部分类的导入方式 - 删除了未使用的变量和方法 --- .../script/impl/BpmTaskAssignLeaderAbstractScript.java | 1 - .../module/bpm/service/oa/BpmOAReimbursementService.java | 1 - .../bpm/service/oa/BpmOAReimbursementServiceImpl.java | 7 ++++--- .../bpm/service/task/BpmProcessInstanceServiceImpl.java | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderAbstractScript.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderAbstractScript.java index 8da82110..048e95d7 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderAbstractScript.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderAbstractScript.java @@ -9,7 +9,6 @@ import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.runtime.ProcessInstance; -import org.omg.CORBA.IRObject; import org.springframework.context.annotation.Lazy; import org.springframework.util.Assert; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAReimbursementService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAReimbursementService.java index b728922f..74c1c2af 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAReimbursementService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAReimbursementService.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.bpm.service.oa; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.BpmOAReimbursementCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.BpmOAReimbursementRespVO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOACashItemDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReimbursementDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReimbursementItemDO; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAReimbursementServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAReimbursementServiceImpl.java index 62dea807..b275c0fa 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAReimbursementServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAReimbursementServiceImpl.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.bpm.service.oa; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; @@ -11,11 +10,13 @@ import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.procure.BpmOAProcureListEditReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.BpmOAReimbursementCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.BpmOAReimbursementRespVO; -import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.Reimbursement; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.ReimbursementDTO; import cn.iocoder.yudao.module.bpm.convert.oa.BpmOAReimbursementConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.financialpayment.FinancialPaymentDO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.*; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAImprestDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAProcureDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReimbursementDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReimbursementItemDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAImprestMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAReimbursementItemMapper; 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 7b0c78e7..df835872 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.collection.CollectionUtil; import cn.hutool.core.date.LocalDateTimeUtil; 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.date.DateUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; 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.cash.BpmOACashRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmOACashPrintDataRespVO; 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.convert.task.BpmTaskConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessCcDO; 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.BpmOACashDO; 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.DynamicMapper; 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.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.BpmProcessCcService; 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.BpmOACashService; 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.bpm.service.task.dto.ProcessInstanceVariablesDTO; import cn.iocoder.yudao.module.infra.api.config.ConfigApi; 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 jodd.util.StringUtil; import liquibase.pro.packaged.T; 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.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronizationManager; 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.time.temporal.ChronoUnit; 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; @Resource private ConfigApi configApi; @Resource private DynamicMapper dynamicMapper ; @Resource private BpmProcessCcService processCcService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } public String transform(String input) { if(StringUtil.isNotEmpty(input)) { String[] parts = input.split(","); StringBuilder result = new StringBuilder(); for (String part : parts) { String[] keyValue = part.split(":"); if (keyValue.length > 1) { result.append(keyValue[1]).append(","); } } if (result.length() > 0) { return result.substring(0, result.length() - 1); } } return ""; } public String replaceValues(String input, Map map) { String[] parts = input.split(","); StringBuilder result = new StringBuilder(); for (String part : parts) { String[] keyValue = part.split(":"); if (keyValue.length > 1) { String key = keyValue[1].trim(); // 去除可能的空格 if (map.containsKey(key)) { Object value = map.get(key); String stringValue = (value != null) ? value.toString() : ""; // 将值转换为字符串 result.append(keyValue[0].trim()).append(":").append(stringValue).append(","); } else { //result.append(part).append(","); } } } if (result.length() > 0) { return result.substring(0, result.length() - 1); } return ""; } @Override @TenantIgnore public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); List bpmProcessInstanceExtDOList = pageResult.getList() ; for (int i = 0; i < bpmProcessInstanceExtDOList.size() ; i++) { BpmProcessInstanceExtDO bpmProcessInstanceExtDO = bpmProcessInstanceExtDOList.get(i) ; String input = bpmProcessInstanceExtDO.getFieldNames() ; if(StringUtil.isNotEmpty(input)) { String sql = "SELECT " + transform(bpmProcessInstanceExtDO.getFieldNames()) + " FROM " + bpmProcessInstanceExtDO.getTableName() + " WHERE id=" + bpmProcessInstanceExtDO.getBusinessKey(); log.info(sql); Map map = dynamicMapper.selectListByTableName(sql) ; String detailInfo = replaceValues(bpmProcessInstanceExtDO.getFieldNames(),map) ; bpmProcessInstanceExtDO.setDetailInfo(detailInfo); } } 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 @Transactional(rollbackFor = Exception.class) 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 @DataPermission(enable = false) 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 @DataPermission(enable = false) 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) @DataPermission(enable = false) 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) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .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); //获取流程发起人User AdminUserRespDTO startUser = adminUserApi.getUser(userId).getCheckedData(); //获取流程发起人部门信息 DeptRespDTO startDeptInfo = deptApi.getDept(startUser.getDeptId()).getCheckedData(); // 获取岗位信息 Set postIds = startUser.getPostIds(); ArrayList list = new ArrayList<>(postIds); //配置通用流程变量 variables.put("post_id", list.get(0).toString()); // 只获配置的首个岗位 variables.put("user_id", userId.toString()); // 配置发起人用户id variables.put("dept_id", startUser.getDeptId().toString()); // 配置发起人部门id variables.put("dept_flag", startDeptInfo.getFlag()); // 配置发起人部门flag // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // 发送通知。在事务提交时,批量执行操作,所以直接查询会无法查询到 ProcessInstance,所以这里是通过监听事务的提交来实现。 TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { @Override public void afterCommit() { // 创建流程后,添加抄送人 processCCToUsers(instance, variables); } }); return instance.getId(); // // 补全流程实例的拓展表 // processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) // .setFormVariables(variables)); // // /** 创建流程后,添加抄送人 End add by yj 2024.1.4 */ // processCCToUsers(definition, instance); // /** 通过自己发起的流程 */ // approveSelfTask(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 * @param * @return */ 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); String BpmConstantsName = BpmConstants.CC_NAME; // 获取发起人信息 AdminUserRespDTO userRespDTO = adminUserApi.getUser(Long.valueOf(instance.getStartUserId())).getCheckedData(); DeptRespDTO deptRespDTO = deptApi.getDept(userRespDTO.getDeptId()).getCheckedData(); //发起人是深圳分公司 if (deptRespDTO.getFlag().contains("136")) { BpmConstantsName = BpmConstants.CCSZ_NAME; } for (BpmTaskAssignRuleDO rule : rules) { String key = rule.getTaskDefinitionKey(); //任务名称 Integer type = rule.getType(); if (!key.isEmpty() && key.equals(BpmConstantsName) && 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)) { //发起人部门为 生产部及以下时 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; } } } /** * 创建流程后,添加抄送人 * @param instance 流程实例 */ private void processCCToUsers(ProcessInstance instance, Map variables) { // 根据流程名称、流程发起人 查询流程配置的抄送人信息 List processCcList = processCcService.getCCListByName(instance.getName(), Long.valueOf(instance.getStartUserId())); // 提取抄送信息用中对应的用户组编号 Set userGroupIds = processCcList.stream() .flatMap(data -> data.getUserGroupId().stream()) .collect(Collectors.toSet()); //根据processDefinitionId 将ccIds保存到bpm_process_instance_ext中的ccIds字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessDefinitionId(instance.getProcessDefinitionId()) .setFormVariables(variables) .setProcessInstanceId(instance.getProcessInstanceId()); if (CollectionUtil.isNotEmpty(userGroupIds)) { // 获取用户组信息 List userGroups = userGroupService.getUserGroupList(userGroupIds); // 提取用户组中对应的用户ID Set userIds = userGroups.stream() .flatMap(data -> data.getMemberUserIds().stream()) .collect(Collectors.toSet()); // 将用户ID列表转换为字符串 String ccIds = userIds.stream() .map(id -> "[" + id + "]") // 每个值用方括号包裹 .collect(Collectors.joining()); //根据processDefinitionId 将ccIds保存到bpm_process_instance_ext中的ccIds字段 instanceExtDO.setCcids(ccIds); } processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); } @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 @DataPermission(enable = false) public BpmProcessInstanceExtDO getProcessInstanceDO(String id) { return processInstanceExtMapper.selectByProcessInstanceId(id); } @Resource private FileApi fileApi; @Resource @Lazy // 解决循环依赖 private BpmOAReimbursementService reimbursementService; @Resource @Lazy // 解决循环依赖 private BpmOACashService cashService; @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 // 判断是否可见外勤人员信息 List userIds = new ArrayList<>(); String type = configApi.getConfigKey("sys.user.type").getCheckedData(); if ("1".equals(type)) { //不可见时 // 获取所有外勤人员 用户编号 userIds = adminUserApi.getUserIdsByUserNature(4).getCheckedData(); } // 获得流程审批信息 List taskRespVOList = taskService.getTaskListByProcessInstanceId(processInstanceId); // 移除外勤人员信息 List finalUserIds = userIds; taskRespVOList.removeIf(data -> finalUserIds.contains(data.getAssigneeUser().getId())); //给User添加签名地址 taskRespVOList.forEach(taskRespVO -> taskRespVO.getAssigneeUser().setSignURL( fileApi.getUserSignImgPath( taskRespVO.getAssigneeUser().getId() ).getData() ) ); //获取流程抄送用户编号 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))); } // 移除 外勤人员信息 ccUserIds.removeAll(userIds); } List userRespDTOS = adminUserApi.getUserList(ccUserIds).getCheckedData(); //获取抄送用户部门信息 Map deptMapDTO = deptApi.getDeptMap(convertSet(userRespDTOS, AdminUserRespDTO::getDeptId)); if ("oa_reimbursement".equals(key)) { //报销流程 BpmOAReimbursementDO reimbursement = reimbursementService.getReimbursement(businessKey); BpmOAReimbursementRespVO bpmOAReimbursementRespVO = reimbursementService.convert(reimbursement); //报销业务数据 // 移除自己得审批节点 taskRespVOList.removeIf(data -> data.getAssigneeUser().getId().equals(reimbursement.getUserId())); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprest(reimbursement.getImprestId()); if (bpmOAImprestDO != null) { //设置备用金 金额 bpmOAReimbursementRespVO.setAmount(bpmOAImprestDO.getAmount()); // 设置备用金 剩余金额 bpmOAReimbursementRespVO.setRemainingAmount(bpmOAImprestDO.getAmount().subtract(bpmOAImprestDO.getReimbursedAmount())); } // 设置抄送人信息 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); } if ("oa_cash".equals(key)) { BpmOACashDO cashDO = cashService.getCash(businessKey); BpmOACashRespVO cashRespVO = cashService.convertCash(cashDO); // 移除自己得审批节点 taskRespVOList.removeIf(data -> data.getAssigneeUser().getId().equals(cashDO.getUserId())); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprest(cashDO.getImprestId()); if (bpmOAImprestDO != null) { //设置备用金 金额 cashRespVO.setAmount(bpmOAImprestDO.getAmount()); // 设置备用金 剩余金额 cashRespVO.setRemainingAmount(bpmOAImprestDO.getAmount().subtract(bpmOAImprestDO.getReimbursedAmount())); } // 设置抄送人信息 List ccUsers = userRespDTOS.stream().map(user -> { BpmOACashPrintDataRespVO.CCUser cc = new BpmOACashPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOACashPrintDataRespVO cashPrintData = new BpmOACashPrintDataRespVO(); cashPrintData.setBpmOACashRespVO(cashRespVO); cashPrintData.setProcessTasks(taskRespVOList); cashPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOACashPrintDataRespVO(cashPrintData); } return bpmProcessInstancePrintDataRespVO; } @Override public Map> getProcessInstanceResultStatusStatisticsGroupTime(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); pageReqVO.setRecentDays(pageReqVO.getRecentDays() == null ? 7 : pageReqVO.getRecentDays()); List list = processInstanceExtMapper.getProcessInstanceResultStatusStatisticsGroupTime(pageReqVO); // -- 获取到日期列表 LocalDateTime now = LocalDateTimeUtil.now(); LocalDateTime offset = LocalDateTimeUtil.offset(LocalDateTimeUtil.now(), -1L * pageReqVO.getRecentDays(), ChronoUnit.DAYS); List dateList = DateUtils.betweenDayList(offset, now); //根据时间分组 Map> map = list.stream().collect(Collectors.groupingBy(BpmProcessInstanceResultStatusStatisticsGroupTimeVO::getTime)); List keys = new ArrayList<>(CollectionUtil.subtract(dateList, new ArrayList<>(map.keySet()))); if (CollectionUtil.isNotEmpty(keys)) { for (String key : keys) { map.put(key, new ArrayList<>()); } } List statusList = Arrays.asList(1, 2, 3, 4); for (Map.Entry> entry : map.entrySet()) { List items = entry.getValue(); List results = items.stream().map(BpmProcessInstanceResultStatusStatisticsGroupTimeVO::getResult).collect(Collectors.toList()); List saveList = new ArrayList<>(CollectionUtil.subtract(statusList, results)); // -- 如果没有的话组装上缺少的 if (CollectionUtil.isNotEmpty(saveList)) { for (Integer status : saveList) { items.add(new BpmProcessInstanceResultStatusStatisticsGroupTimeVO() .setTime(entry.getKey()) .setTotalCount(0) .setResult(status) .setName("")); } } } return map; } } \ No newline at end of file +package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.LocalDateTimeUtil; 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.date.DateUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; 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.cash.BpmOACashRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmOACashPrintDataRespVO; 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.BpmProcessCcDO; 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.BpmOACashDO; 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.DynamicMapper; 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.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.BpmProcessCcService; 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.BpmOACashService; 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.config.ConfigApi; 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 jodd.util.StringUtil; 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.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronizationManager; 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.time.temporal.ChronoUnit; 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; @Resource private ConfigApi configApi; @Resource private DynamicMapper dynamicMapper ; @Resource private BpmProcessCcService processCcService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } public String transform(String input) { if(StringUtil.isNotEmpty(input)) { String[] parts = input.split(","); StringBuilder result = new StringBuilder(); for (String part : parts) { String[] keyValue = part.split(":"); if (keyValue.length > 1) { result.append(keyValue[1]).append(","); } } if (result.length() > 0) { return result.substring(0, result.length() - 1); } } return ""; } public String replaceValues(String input, Map map) { String[] parts = input.split(","); StringBuilder result = new StringBuilder(); for (String part : parts) { String[] keyValue = part.split(":"); if (keyValue.length > 1) { String key = keyValue[1].trim(); // 去除可能的空格 if (map.containsKey(key)) { Object value = map.get(key); String stringValue = (value != null) ? value.toString() : ""; // 将值转换为字符串 result.append(keyValue[0].trim()).append(":").append(stringValue).append(","); } else { //result.append(part).append(","); } } } if (result.length() > 0) { return result.substring(0, result.length() - 1); } return ""; } @Override @TenantIgnore public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); List bpmProcessInstanceExtDOList = pageResult.getList() ; for (int i = 0; i < bpmProcessInstanceExtDOList.size() ; i++) { BpmProcessInstanceExtDO bpmProcessInstanceExtDO = bpmProcessInstanceExtDOList.get(i) ; String input = bpmProcessInstanceExtDO.getFieldNames() ; if(StringUtil.isNotEmpty(input)) { String sql = "SELECT " + transform(bpmProcessInstanceExtDO.getFieldNames()) + " FROM " + bpmProcessInstanceExtDO.getTableName() + " WHERE id=" + bpmProcessInstanceExtDO.getBusinessKey(); log.info(sql); Map map = dynamicMapper.selectListByTableName(sql) ; String detailInfo = replaceValues(bpmProcessInstanceExtDO.getFieldNames(),map) ; bpmProcessInstanceExtDO.setDetailInfo(detailInfo); } } 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 @Transactional(rollbackFor = Exception.class) 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 @DataPermission(enable = false) 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 @DataPermission(enable = false) 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) @DataPermission(enable = false) 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) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .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); //获取流程发起人User AdminUserRespDTO startUser = adminUserApi.getUser(userId).getCheckedData(); //获取流程发起人部门信息 DeptRespDTO startDeptInfo = deptApi.getDept(startUser.getDeptId()).getCheckedData(); // 获取岗位信息 Set postIds = startUser.getPostIds(); ArrayList list = new ArrayList<>(postIds); //配置通用流程变量 variables.put("post_id", list.get(0).toString()); // 只获配置的首个岗位 variables.put("user_id", userId.toString()); // 配置发起人用户id variables.put("dept_id", startUser.getDeptId().toString()); // 配置发起人部门id variables.put("dept_flag", startDeptInfo.getFlag()); // 配置发起人部门flag // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // 发送通知。在事务提交时,批量执行操作,所以直接查询会无法查询到 ProcessInstance,所以这里是通过监听事务的提交来实现。 TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { @Override public void afterCommit() { // 创建流程后,添加抄送人 processCCToUsers(instance, variables); } }); return instance.getId(); // // 补全流程实例的拓展表 // processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) // .setFormVariables(variables)); // // /** 创建流程后,添加抄送人 End add by yj 2024.1.4 */ // processCCToUsers(definition, instance); // /** 通过自己发起的流程 */ // approveSelfTask(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 * @param * @return */ 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); String BpmConstantsName = BpmConstants.CC_NAME; // 获取发起人信息 AdminUserRespDTO userRespDTO = adminUserApi.getUser(Long.valueOf(instance.getStartUserId())).getCheckedData(); DeptRespDTO deptRespDTO = deptApi.getDept(userRespDTO.getDeptId()).getCheckedData(); //发起人是深圳分公司 if (deptRespDTO.getFlag().contains("136")) { BpmConstantsName = BpmConstants.CCSZ_NAME; } for (BpmTaskAssignRuleDO rule : rules) { String key = rule.getTaskDefinitionKey(); //任务名称 Integer type = rule.getType(); if (!key.isEmpty() && key.equals(BpmConstantsName) && 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)) { //发起人部门为 生产部及以下时 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; } } } /** * 创建流程后,添加抄送人 * @param instance 流程实例 */ private void processCCToUsers(ProcessInstance instance, Map variables) { // 根据流程名称、流程发起人 查询流程配置的抄送人信息 List processCcList = processCcService.getCCListByName(instance.getName(), Long.valueOf(instance.getStartUserId())); // 提取抄送信息用中对应的用户组编号 Set userGroupIds = processCcList.stream() .flatMap(data -> data.getUserGroupId().stream()) .collect(Collectors.toSet()); //根据processDefinitionId 将ccIds保存到bpm_process_instance_ext中的ccIds字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessDefinitionId(instance.getProcessDefinitionId()) .setFormVariables(variables) .setProcessInstanceId(instance.getProcessInstanceId()); if (CollectionUtil.isNotEmpty(userGroupIds)) { // 获取用户组信息 List userGroups = userGroupService.getUserGroupList(userGroupIds); // 提取用户组中对应的用户ID Set userIds = userGroups.stream() .flatMap(data -> data.getMemberUserIds().stream()) .collect(Collectors.toSet()); // 将用户ID列表转换为字符串 String ccIds = userIds.stream() .map(id -> "[" + id + "]") // 每个值用方括号包裹 .collect(Collectors.joining()); //根据processDefinitionId 将ccIds保存到bpm_process_instance_ext中的ccIds字段 instanceExtDO.setCcids(ccIds); } processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); } @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 @DataPermission(enable = false) public BpmProcessInstanceExtDO getProcessInstanceDO(String id) { return processInstanceExtMapper.selectByProcessInstanceId(id); } @Resource private FileApi fileApi; @Resource @Lazy // 解决循环依赖 private BpmOAReimbursementService reimbursementService; @Resource @Lazy // 解决循环依赖 private BpmOACashService cashService; @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 // 判断是否可见外勤人员信息 List userIds = new ArrayList<>(); String type = configApi.getConfigKey("sys.user.type").getCheckedData(); if ("1".equals(type)) { //不可见时 // 获取所有外勤人员 用户编号 userIds = adminUserApi.getUserIdsByUserNature(4).getCheckedData(); } // 获得流程审批信息 List taskRespVOList = taskService.getTaskListByProcessInstanceId(processInstanceId); // 移除外勤人员信息 List finalUserIds = userIds; taskRespVOList.removeIf(data -> finalUserIds.contains(data.getAssigneeUser().getId())); //给User添加签名地址 taskRespVOList.forEach(taskRespVO -> taskRespVO.getAssigneeUser().setSignURL( fileApi.getUserSignImgPath( taskRespVO.getAssigneeUser().getId() ).getData() ) ); //获取流程抄送用户编号 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))); } // 移除 外勤人员信息 ccUserIds.removeAll(userIds); } List userRespDTOS = adminUserApi.getUserList(ccUserIds).getCheckedData(); //获取抄送用户部门信息 Map deptMapDTO = deptApi.getDeptMap(convertSet(userRespDTOS, AdminUserRespDTO::getDeptId)); if ("oa_reimbursement".equals(key)) { //报销流程 BpmOAReimbursementDO reimbursement = reimbursementService.getReimbursement(businessKey); BpmOAReimbursementRespVO bpmOAReimbursementRespVO = reimbursementService.convert(reimbursement); //报销业务数据 // 移除自己得审批节点 taskRespVOList.removeIf(data -> data.getAssigneeUser().getId().equals(reimbursement.getUserId())); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprest(reimbursement.getImprestId()); if (bpmOAImprestDO != null) { //设置备用金 金额 bpmOAReimbursementRespVO.setAmount(bpmOAImprestDO.getAmount()); // 设置备用金 剩余金额 bpmOAReimbursementRespVO.setRemainingAmount(bpmOAImprestDO.getAmount().subtract(bpmOAImprestDO.getReimbursedAmount())); } // 设置抄送人信息 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); } if ("oa_cash".equals(key)) { BpmOACashDO cashDO = cashService.getCash(businessKey); BpmOACashRespVO cashRespVO = cashService.convertCash(cashDO); // 移除自己得审批节点 taskRespVOList.removeIf(data -> data.getAssigneeUser().getId().equals(cashDO.getUserId())); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprest(cashDO.getImprestId()); if (bpmOAImprestDO != null) { //设置备用金 金额 cashRespVO.setAmount(bpmOAImprestDO.getAmount()); // 设置备用金 剩余金额 cashRespVO.setRemainingAmount(bpmOAImprestDO.getAmount().subtract(bpmOAImprestDO.getReimbursedAmount())); } // 设置抄送人信息 List ccUsers = userRespDTOS.stream().map(user -> { BpmOACashPrintDataRespVO.CCUser cc = new BpmOACashPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOACashPrintDataRespVO cashPrintData = new BpmOACashPrintDataRespVO(); cashPrintData.setBpmOACashRespVO(cashRespVO); cashPrintData.setProcessTasks(taskRespVOList); cashPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOACashPrintDataRespVO(cashPrintData); } return bpmProcessInstancePrintDataRespVO; } @Override public Map> getProcessInstanceResultStatusStatisticsGroupTime(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); pageReqVO.setRecentDays(pageReqVO.getRecentDays() == null ? 7 : pageReqVO.getRecentDays()); List list = processInstanceExtMapper.getProcessInstanceResultStatusStatisticsGroupTime(pageReqVO); // -- 获取到日期列表 LocalDateTime now = LocalDateTimeUtil.now(); LocalDateTime offset = LocalDateTimeUtil.offset(LocalDateTimeUtil.now(), -1L * pageReqVO.getRecentDays(), ChronoUnit.DAYS); List dateList = DateUtils.betweenDayList(offset, now); //根据时间分组 Map> map = list.stream().collect(Collectors.groupingBy(BpmProcessInstanceResultStatusStatisticsGroupTimeVO::getTime)); List keys = new ArrayList<>(CollectionUtil.subtract(dateList, new ArrayList<>(map.keySet()))); if (CollectionUtil.isNotEmpty(keys)) { for (String key : keys) { map.put(key, new ArrayList<>()); } } List statusList = Arrays.asList(1, 2, 3, 4); for (Map.Entry> entry : map.entrySet()) { List items = entry.getValue(); List results = items.stream().map(BpmProcessInstanceResultStatusStatisticsGroupTimeVO::getResult).collect(Collectors.toList()); List saveList = new ArrayList<>(CollectionUtil.subtract(statusList, results)); // -- 如果没有的话组装上缺少的 if (CollectionUtil.isNotEmpty(saveList)) { for (Integer status : saveList) { items.add(new BpmProcessInstanceResultStatusStatisticsGroupTimeVO() .setTime(entry.getKey()) .setTotalCount(0) .setResult(status) .setName("")); } } } return map; } } \ No newline at end of file From 687d35eb5386ca58fb37cc99c050b06116b99491 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Fri, 29 Nov 2024 19:41:34 +0800 Subject: [PATCH 5/7] =?UTF-8?q?refactor(system):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E9=83=A8=E9=97=A8=E5=92=8C=E9=A1=B9=E7=9B=AE=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E7=9A=84=E6=9F=A5=E8=AF=A2=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改DeptServiceImpl中的getChildDept方法,使用正则表达式进行精确匹配- 更新ProjectMapper中的查询条件,使用正则表达式替代like操作以提高查询准确度 --- .../yudao/module/system/dal/mysql/project/ProjectMapper.java | 5 ++++- .../yudao/module/system/service/dept/DeptServiceImpl.java | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/project/ProjectMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/project/ProjectMapper.java index 134f819b..2f8b350f 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/project/ProjectMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/project/ProjectMapper.java @@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.system.controller.admin.project.vo.ProjectPageReq import cn.iocoder.yudao.module.system.dal.dataobject.project.ProjectDO; import org.apache.ibatis.annotations.Mapper; +import java.util.Objects; + /** * 项目管理 Mapper * @@ -21,12 +23,13 @@ public interface ProjectMapper extends BaseMapperX { .eqIfPresent(ProjectDO::getType, reqVO.getType()) .likeIfPresent(ProjectDO::getName, reqVO.getName()) .eqIfPresent(ProjectDO::getResponsibleDept, reqVO.getResponsibleDept()) - .likeIfPresent(ProjectDO::getParticipationDept, reqVO.getParticipationDept()) +// .likeIfPresent(ProjectDO::getParticipationDept, reqVO.getParticipationDept()) .eqIfPresent(ProjectDO::getDirectorUserId, reqVO.getDirectorUserId()) .betweenIfPresent(ProjectDO::getStartDate, reqVO.getStartDate()) .betweenIfPresent(ProjectDO::getEndDate, reqVO.getEndDate()) .eqIfPresent(ProjectDO::getIsLongTerm, reqVO.getIsLongTerm()) .eqIfPresent(ProjectDO::getStatus, reqVO.getStatus()) + .apply(Objects.nonNull(reqVO.getParticipationDept()),"participation_dept REGEXP CONCAT('(^|,)',{0},'(,|$)')", reqVO.getParticipationDept()) .orderByDesc(ProjectDO::getId)); } } \ 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/dept/DeptServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java index 34ab8caa..a8d9c4ec 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java @@ -271,8 +271,8 @@ public class DeptServiceImpl implements DeptService { public List getChildDept(Long id) { return deptMapper.selectList(new LambdaQueryWrapperX() - .like(DeptDO::getFlag, id) - .eq(DeptDO::getStatus, CommonStatusEnum.ENABLE.getStatus())); + .eq(DeptDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) + .apply("flag REGEXP CONCAT('(^|-)',{0},'(-|$)')", id)); } @Override From 66419fe9ab7a19134f8289362e64352f84759181 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Mon, 2 Dec 2024 09:19:42 +0800 Subject: [PATCH 6/7] =?UTF-8?q?refactor(system):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E9=83=A8=E9=97=A8=E5=92=8C=E9=A1=B9=E7=9B=AE=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E7=9A=84=20SQL=20=E6=AD=A3=E5=88=99=E8=A1=A8=E8=BE=BE=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 getChildDept 方法中的正则表达式替换为更高效的模糊查询组合 - 优化 ProjectMapper 中的参与部门查询条件,提高查询效率 - 在 DeptServiceImpl 中添加数据权限注解,控制访问权限 --- .../module/system/dal/mysql/project/ProjectMapper.java | 8 ++++++-- .../yudao/module/system/service/dept/DeptServiceImpl.java | 8 +++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/project/ProjectMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/project/ProjectMapper.java index 2f8b350f..d465a17f 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/project/ProjectMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/project/ProjectMapper.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.system.controller.admin.project.vo.ProjectPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; import cn.iocoder.yudao.module.system.dal.dataobject.project.ProjectDO; import org.apache.ibatis.annotations.Mapper; @@ -23,13 +24,16 @@ public interface ProjectMapper extends BaseMapperX { .eqIfPresent(ProjectDO::getType, reqVO.getType()) .likeIfPresent(ProjectDO::getName, reqVO.getName()) .eqIfPresent(ProjectDO::getResponsibleDept, reqVO.getResponsibleDept()) -// .likeIfPresent(ProjectDO::getParticipationDept, reqVO.getParticipationDept()) .eqIfPresent(ProjectDO::getDirectorUserId, reqVO.getDirectorUserId()) .betweenIfPresent(ProjectDO::getStartDate, reqVO.getStartDate()) .betweenIfPresent(ProjectDO::getEndDate, reqVO.getEndDate()) .eqIfPresent(ProjectDO::getIsLongTerm, reqVO.getIsLongTerm()) .eqIfPresent(ProjectDO::getStatus, reqVO.getStatus()) - .apply(Objects.nonNull(reqVO.getParticipationDept()),"participation_dept REGEXP CONCAT('(^|,)',{0},'(,|$)')", reqVO.getParticipationDept()) + .likeLeft(ProjectDO::getParticipationDept, "-" + reqVO.getParticipationDept()) + .or() + .likeRight(ProjectDO::getParticipationDept, reqVO.getParticipationDept() + "-") + .or() + .like(ProjectDO::getParticipationDept, "-" + reqVO.getParticipationDept() + "-") .orderByDesc(ProjectDO::getId)); } } \ 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/dept/DeptServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java index a8d9c4ec..f3f4cc53 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java @@ -268,11 +268,17 @@ public class DeptServiceImpl implements DeptService { } @Override + @DataPermission(enable = false) + @Cacheable(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST, key = "#id") public List getChildDept(Long id) { return deptMapper.selectList(new LambdaQueryWrapperX() .eq(DeptDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) - .apply("flag REGEXP CONCAT('(^|-)',{0},'(-|$)')", id)); + .likeLeft(DeptDO::getFlag, "-" + id) + .or() + .likeRight(DeptDO::getFlag, id + "-") + .or() + .like(DeptDO::getFlag, "-" + id + "-")); } @Override From 9e48b0b30277d8d9b45064de32da478c893e67ec Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Tue, 3 Dec 2024 18:12:56 +0800 Subject: [PATCH 7/7] =?UTF-8?q?refactor(bpm):=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E5=A4=87=E7=94=A8=E9=87=91=E8=A1=A8=E5=8D=95=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 getByProcessInstanceId 方法的路径从 /getByProcessInstanceId 改为 /getProcessInstanceId - 优化接口路径,使其更加简洁和一致 --- .../module/bpm/controller/admin/oa/BpmOAImprestController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOAImprestController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOAImprestController.java index 3b15a189..1825cc36 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOAImprestController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOAImprestController.java @@ -69,7 +69,7 @@ public class BpmOAImprestController { return success(respVO); } - @GetMapping("/getByProcessInstanceId") + @GetMapping("/getProcessInstanceId") @Operation(summary = "获得备用金表单") @Parameter(name = "processInstanceId", description = "流程实例编号", required = true, example = "1024") public CommonResult getByProcessInstanceId(@RequestParam("processInstanceId") String processInstanceId) {