From 0e303652fa48ee2c46e407470c7ef237b4868171 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Thu, 10 Oct 2024 18:30:25 +0800 Subject: [PATCH 01/20] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=B7=A5=E4=BD=9C?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E6=9F=A5=E7=9C=8B=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除了基于角色ID列表的动态查询,改为固定排除特定角色ID(1, 101, 162) -简化了查询参数,移除了不再使用的角色ID集合 - 增加了异常捕获和日志记录,以提高系统稳定性 - 注释了原来的动态查询逻辑,以便未来可能的恢复或调整 --- .../dal/mysql/worklog/LogInstanceMapper.java | 2 +- .../worklog/LogInstanceServiceImpl.java | 34 ++++++++++++------- .../mapper/worklog/LogInstanceMapper.xml | 13 +++---- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/worklog/LogInstanceMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/worklog/LogInstanceMapper.java index 755b2b57..137bef3c 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/worklog/LogInstanceMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/worklog/LogInstanceMapper.java @@ -98,7 +98,7 @@ public interface LogInstanceMapper extends BaseMapperX { @Param("userId") Long userId); @DataPermission(enable = false) - List selectRaedUser(@Param("userId")Long userId, @Param("deptId")Long deptId, @Param("roleIds")Collection roleIds); + List selectRaedUser(@Param("userId")Long userId, @Param("deptId")Long deptId); /** * 获取上一篇下一篇 diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/worklog/LogInstanceServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/worklog/LogInstanceServiceImpl.java index e8c59607..ed8cf884 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/worklog/LogInstanceServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/worklog/LogInstanceServiceImpl.java @@ -24,6 +24,7 @@ import cn.iocoder.yudao.module.system.service.worklog.dto.LogReadUserRespDTO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.extern.slf4j.Slf4j; import org.mapstruct.ap.internal.util.Strings; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; @@ -48,6 +49,7 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; */ @Service @Validated +@Slf4j public class LogInstanceServiceImpl implements LogInstanceService { @Resource @@ -137,23 +139,29 @@ public class LogInstanceServiceImpl implements LogInstanceService { //创建日志时,查询可以查看发起人日志的用户组 用线程控制 new Thread(() -> { - List roleIds = Arrays.asList(1L,101L); - String roleId = configApi.getConfigKey("system_work_log_role_id").getCheckedData(); - if (Strings.isNotEmpty(roleId)) { - roleIds = Arrays.stream(roleId.split(",")).map(Long::valueOf).collect(Collectors.toList()); - } - List respDTOS = logInstanceMapper.selectRaedUser(userId, adminUserDO.getDeptId(), roleIds); + try { +// List roleIds = Arrays.asList(1L,101L); +// String roleId = configApi.getConfigKey("system_work_log_role_id").getCheckedData(); +// +// if (Strings.isNotEmpty(roleId)) { +// roleIds = Arrays.stream(roleId.split(",")).map(Long::valueOf).collect(Collectors.toList()); +// } + List respDTOS = logInstanceMapper.selectRaedUser(userId, adminUserDO.getDeptId()); - //特殊情况, 日志发起人为研发部时 手动添加查看者 - if (adminUserDO.getDeptId() == 128L && adminUserDO.getId() != 126L) { + //特殊情况, 日志发起人为研发部时 手动添加查看者 + if (adminUserDO.getDeptId() == 128L && adminUserDO.getId() != 126L) { - LogReadUserRespDTO dto = new LogReadUserRespDTO(); - dto.setUserId(126L); - dto.setDeptId(128L); - respDTOS.add(dto); + LogReadUserRespDTO dto = new LogReadUserRespDTO(); + dto.setUserId(126L); + dto.setDeptId(128L); + respDTOS.add(dto); + } + + logReadService.createLogRule(respDTOS, logInstance.getId(), logInstance.getStartUserId()); + } catch (Exception e) { + log.error("获取日志查看用户失败", e); } - logReadService.createLogRule(respDTOS, logInstance.getId(), logInstance.getStartUserId()); }).start(); // 返回 diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/worklog/LogInstanceMapper.xml b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/worklog/LogInstanceMapper.xml index a2a617f7..9f2f86e0 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/worklog/LogInstanceMapper.xml +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/worklog/LogInstanceMapper.xml @@ -71,12 +71,13 @@ WHERE role.permission = 'system:view-log:query' AND a.deleted = 0 - - AND a.role_id NOT IN - - #{roleId} - - + AND a.role_id NOT IN (1,101,162) + + + + + + ) menu LEFT JOIN system_role role on role.id = menu.role_id ) role_id ON u_role.role_id = role_id.id From bea58eddc99411840c995b2852feb14b2b572650 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Fri, 11 Oct 2024 09:24:35 +0800 Subject: [PATCH 02/20] =?UTF-8?q?=E7=AE=80=E5=8C=96=E8=A7=92=E8=89=B2?= =?UTF-8?q?=E6=9D=83=E9=99=90=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 删除了 LogInstanceMapper.xml 文件中针对 roleIds 的复杂条件查询,该查询可能导致性能问题和逻辑混乱。现在直接排除特定角色 ID,简化了查询逻辑,提高了代码的可读性和维护性。 --- .../src/main/resources/mapper/worklog/LogInstanceMapper.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/worklog/LogInstanceMapper.xml b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/worklog/LogInstanceMapper.xml index 9f2f86e0..b87791c9 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/worklog/LogInstanceMapper.xml +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/worklog/LogInstanceMapper.xml @@ -72,12 +72,6 @@ role.permission = 'system:view-log:query' AND a.deleted = 0 AND a.role_id NOT IN (1,101,162) - - - - - - ) menu LEFT JOIN system_role role on role.id = menu.role_id ) role_id ON u_role.role_id = role_id.id From e315b8bfa92e036b7fbb887a2d36194b4669d198 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Sun, 13 Oct 2024 21:29:34 +0800 Subject: [PATCH 03/20] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=A4=87=E7=94=A8?= =?UTF-8?q?=E9=87=91=E6=8A=A5=E9=94=80=E6=B5=81=E7=A8=8B=E5=92=8C=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E8=96=AA=E8=B5=84=E8=B0=83=E6=95=B4=E7=94=B3=E8=AF=B7?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 优化备用金报销逻辑,支持部分报销和超额报销 - 新增薪资调整申请功能,包括创建、查询和审批 - 重构部分OA相关Controller和Service - 更新数据库表结构,增加备用金报销相关字段 --- .../admin/oa/BpmOAImprestController.java | 17 +-- .../oa/BpmOAReimbursementController.java | 2 +- .../oa/BpmOASalaryAdjustmentController.java | 111 ++++++++++++++ .../oa/vo/cash/BpmOACashCreateReqVO.java | 3 + .../admin/oa/vo/cash/BpmOACashRespVO.java | 6 + .../oa/vo/imprest/BpmOAImprestRespVO.java | 3 - .../BpmOAReimbursementCreateReqVO.java | 3 + .../BpmOAReimbursementRespVO.java | 3 + .../BpmOASalaryAdjustmentCreateReqVO.java | 67 +++++++++ .../BpmOASalaryAdjustmentRespVO.java | 60 ++++++++ .../admin/task/BpmTaskController.java | 34 +++++ .../task/vo/task/BpmTaskTodoPageReqVO.java | 3 + .../task/vo/task/BpmTaskTodoPageRespVO.java | 38 +++++ .../convert/message/BpmMessageConvert.java | 7 +- .../oa/BpmOASalaryAdjustmentConvert.java | 22 +++ .../bpm/dal/dataobject/oa/BpmOACashDO.java | 5 + .../bpm/dal/dataobject/oa/BpmOAImprestDO.java | 8 +- .../oa/BpmOASalaryAdjustmentDO.java | 100 +++++++++++++ .../bpm/dal/mysql/oa/BpmOAImprestMapper.java | 6 +- .../mysql/oa/BpmOASalaryAdjustmentMapper.java | 9 ++ .../bpm/dal/mysql/task/BpmTaskExtMapper.java | 15 +- .../FinancialPaymentServiceImpl.java | 2 +- .../bpm/service/oa/BpmOACashServiceImpl.java | 82 ++++++++-- .../bpm/service/oa/BpmOAImprestService.java | 8 - .../service/oa/BpmOAImprestServiceImpl.java | 12 +- .../service/oa/BpmOAReimbursementService.java | 1 + .../oa/BpmOAReimbursementServiceImpl.java | 82 ++++++---- .../oa/BpmOASalaryAdjustmentService.java | 46 ++++++ .../oa/BpmOASalaryAdjustmentServiceImpl.java | 100 +++++++++++++ .../BpmOASalaryAdjustmentResultListener.java | 32 ++++ .../task/BpmProcessInstanceServiceImpl.java | 2 +- .../bpm/service/task/BpmTaskService.java | 16 ++ .../bpm/service/task/BpmTaskServiceImpl.java | 140 +++++++++++++----- .../mapper/task/BpmTaskExtMapper.xml | 76 ++++++++++ 34 files changed, 999 insertions(+), 122 deletions(-) create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOASalaryAdjustmentController.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/salaryadjustment/BpmOASalaryAdjustmentCreateReqVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/salaryadjustment/BpmOASalaryAdjustmentRespVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTodoPageRespVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/oa/BpmOASalaryAdjustmentConvert.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOASalaryAdjustmentDO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOASalaryAdjustmentMapper.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOASalaryAdjustmentService.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOASalaryAdjustmentServiceImpl.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOASalaryAdjustmentResultListener.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/task/BpmTaskExtMapper.xml 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 f6d11932..c7e91a23 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 @@ -3,9 +3,13 @@ package cn.iocoder.yudao.module.bpm.controller.admin.oa; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.imprest.BpmOAImprestCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.imprest.BpmOAImprestRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.Reimbursement; import cn.iocoder.yudao.module.bpm.convert.oa.BpmOAImprestConvert; 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.mysql.oa.BpmOAReimbursementMapper; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAImprestService; +import cn.iocoder.yudao.module.bpm.service.oa.BpmOAReimbursementService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -61,17 +65,6 @@ public class BpmOAImprestController { return success(BpmOAImprestConvert.INSTANCE.convert(imprest)); } - @GetMapping("/getProcessInstanceId") - @Operation(summary = "获得备用金表单") - @Parameter(name = "reimbursementId", description = "编号", required = true, example = "1024") - public CommonResult getImprestByReimbursementId(@RequestParam("reimbursementId") Long reimbursementId) { - - //根据user 查询审批通过并且未报销得表单。 - BpmOAImprestDO imprest = imprestService.getImprestByReimbursementId(reimbursementId); - - return success(BpmOAImprestConvert.INSTANCE.convert(imprest)); - } - @GetMapping("/getByProcessInstanceId") @Operation(summary = "获得备用金表单") @Parameter(name = "processInstanceId", description = "流程实例编号", required = true, example = "1024") @@ -81,4 +74,4 @@ public class BpmOAImprestController { return success(BpmOAImprestConvert.INSTANCE.convert(imprest)); } -} +} \ No newline at end of file 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 17660416..d49ec5ce 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 @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.bpm.controller.admin.oa; import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 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.BpmOAReimbursementDO; @@ -64,5 +65,4 @@ public class BpmOAReimbursementController { BpmOAReimbursementDO reimbursement = service.getByProcessInstanceId(processInstanceId); return success(service.convert(reimbursement)); } - } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOASalaryAdjustmentController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOASalaryAdjustmentController.java new file mode 100644 index 00000000..cb91ed71 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOASalaryAdjustmentController.java @@ -0,0 +1,111 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.salaryadjustment.BpmOASalaryAdjustmentCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.salaryadjustment.BpmOASalaryAdjustmentRespVO; +import cn.iocoder.yudao.module.bpm.convert.oa.BpmOASalaryAdjustmentConvert; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOASalaryAdjustmentDO; +import cn.iocoder.yudao.module.bpm.service.oa.BpmOASalaryAdjustmentService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +/** + * OA 薪资付款申请 Controller + * + * @author 符溶馨 + + */ +@Tag(name = "管理后台 - OA 薪资调整申请") +@RestController +@RequestMapping("/bpm/oa/salary-adjustment") +@Validated +public class BpmOASalaryAdjustmentController { + + @Resource + private BpmOASalaryAdjustmentService salaryService; + + @Resource + private DeptApi deptApi; + + @Resource + private AdminUserApi userApi; + + @PostMapping("/create") + @Operation(summary = "创建请求申请") + public CommonResult createSalaryAdjustment(@Valid @RequestBody BpmOASalaryAdjustmentCreateReqVO createReqVO) { + + return success(salaryService.createSalaryAdjustment(getLoginUserId(), createReqVO)); + } + + @GetMapping("/get") + @Operation(summary = "获得薪资付款申请") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + public CommonResult getSalaryAdjustment(@RequestParam("id") Long id) { + + BpmOASalaryAdjustmentDO salary = salaryService.getSalaryAdjustment(id); + if (salary == null) { + return success(new BpmOASalaryAdjustmentRespVO()); + } + + // 获得用户详情 + AdminUserRespDTO userRespDTO = userApi.getUser(salary.getAdjustmentUserId()).getCheckedData(); + + // 获取部门详情 + DeptRespDTO dto = getDept(salary.getAdjustmentDeptId()); + + BpmOASalaryAdjustmentRespVO respVO = BpmOASalaryAdjustmentConvert.INSTANCE.convert(salary) + .setAdjustmentDeptName(dto.getName()) + .setAdjustmentUserName(userRespDTO.getNickname()); + + return success(respVO); + } + + @GetMapping("/getByProcessInstanceId") + @Operation(summary = "获得薪资付款申请") + @Parameter(name = "processInstanceId", description = "流程实例编号", required = true, example = "1024") + public CommonResult getByProcessInstanceId(@RequestParam("processInstanceId") String processInstanceId) { + + BpmOASalaryAdjustmentDO salary = salaryService.getByProcessInstanceId(processInstanceId); + if (salary == null) { + return success(new BpmOASalaryAdjustmentRespVO()); + } + + // 获得用户详情 + AdminUserRespDTO userRespDTO = userApi.getUser(salary.getAdjustmentUserId()).getCheckedData(); + + // 获取部门详情 + DeptRespDTO dto = getDept(salary.getAdjustmentDeptId()); + + BpmOASalaryAdjustmentRespVO respVO = BpmOASalaryAdjustmentConvert.INSTANCE.convert(salary) + .setAdjustmentDeptName(dto.getName()) + .setAdjustmentUserName(userRespDTO.getNickname()); + + return success(respVO); + } + + /** + * 获得部门信息 + * @param deptId 部门id + * @return 部门信息 + */ + public DeptRespDTO getDept(Long deptId) { + + if (deptId == null) { + return new DeptRespDTO(); + } + return deptApi.getDept(deptId).getCheckedData(); + } +} 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 a95647ad..d726e3df 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 Long imprestId; + @Schema(description = "流程实例编号") private String processInstanceId; 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 9c14dee6..b1f5e63d 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 Long imprestId; + + @Schema(description = "备用金金额") + private BigDecimal amount; + @Schema(description = "上传文件", requiredMode = Schema.RequiredMode.REQUIRED) private List fileItems; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/imprest/BpmOAImprestRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/imprest/BpmOAImprestRespVO.java index e7455b96..3cb4d84b 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/imprest/BpmOAImprestRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/imprest/BpmOAImprestRespVO.java @@ -44,9 +44,6 @@ public class BpmOAImprestRespVO extends BpmOABaseRespVO { @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) private LocalDate date; - @Schema(description = "报销流程编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED) - private Integer reimbursementId; - @Schema(description = "报销状态", requiredMode = Schema.RequiredMode.REQUIRED) @NotNull(message = "报销状态不能为空") private Integer status; 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 80110abc..7b89f875 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 @@ -40,6 +40,9 @@ public class BpmOAReimbursementCreateReqVO { @NotNull(message = "报销类型不能为空") private BigDecimal reimbursementType ; + @Schema(description = "备用金ID") + private Long imprestId; + @Schema(description = "备用金差额", requiredMode = Schema.RequiredMode.NOT_REQUIRED) private BigDecimal difference ; 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 e296c027..0a9f68af 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 @@ -46,6 +46,9 @@ public class BpmOAReimbursementRespVO extends BpmOABaseRespVO { @Schema(description = "备用金金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED) private BigDecimal amount ; + @Schema(description = "备用金ID") + private Long imprestId; + @Schema(description = "备用金差额 = 备用金额 - 报销总金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED) private BigDecimal difference ; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/salaryadjustment/BpmOASalaryAdjustmentCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/salaryadjustment/BpmOASalaryAdjustmentCreateReqVO.java new file mode 100644 index 00000000..ba68cd30 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/salaryadjustment/BpmOASalaryAdjustmentCreateReqVO.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.salaryadjustment; + +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.time.LocalDate; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; + +/** + * 薪资付款申请 创建 Request VO + * + * @author 符溶馨 + */ +@Schema(description = "管理后台 - 薪资付款申请创建 Request VO") +@Data +@EqualsAndHashCode() +@ToString(callSuper = true) +public class BpmOASalaryAdjustmentCreateReqVO { + + @Schema(description = "调整类型 | 1:涨薪 2:降薪", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "调整类型不能为空") + private Integer type; + + @Schema(description = "调整人用户编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "调整人用户编号不能为空") + private Long adjustmentUserId; + + @Schema(description = "调整人部门编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "调整人部门编号不能为空") + private Long adjustmentDeptId; + + @Schema(description = "调整日期", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "调整日期不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + private LocalDate adjustmentDate; + + @Schema(description = "调整前薪资", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "调整前薪资不能为空") + private Integer salaryBefore; + + @Schema(description = "调整后薪资", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "调整后薪资不能为空") + private Integer salaryAfter; + + @Schema(description = "调整原因", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "调整原因不能为空") + private String reason; + + @Schema(description = "调整原因描述") + private String description; + + @Schema(description = "流程实例编号") + private String processInstanceId; + + @Schema(description = "状态-参见 bpm_process_instance_result 枚举") + private Integer result; + + @Schema(description = "上传文件") + private List fileItems; +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/salaryadjustment/BpmOASalaryAdjustmentRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/salaryadjustment/BpmOASalaryAdjustmentRespVO.java new file mode 100644 index 00000000..f0eedf20 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/salaryadjustment/BpmOASalaryAdjustmentRespVO.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.salaryadjustment; + +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOABaseRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; + +/** + * @author 符溶馨 + */ +@Schema(description = "管理后台 - 薪资付款申请 请求Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmOASalaryAdjustmentRespVO extends BpmOABaseRespVO { + + @Schema(description = "调整类型 | 1:涨薪 2:降薪") + private Integer type; + + @Schema(description = "调整人用户编号") + private Long adjustmentUserId; + + @Schema(description = "调整人用户名称") + private String adjustmentUserName; + + @Schema(description = "调整人部门编号") + private Long adjustmentDeptId; + + @Schema(description = "调整人部门名称") + private String adjustmentDeptName; + + @Schema(description = "调整日期") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + private String adjustmentDate; + + @Schema(description = "调整前薪资") + private BigDecimal salaryBefore; + + @Schema(description = "调整后薪资") + private BigDecimal salaryAfter; + + @Schema(description = "调整原因") + private String reason; + + @Schema(description = "调整原因描述") + private String description; + + @Schema(description = "上传文件", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "附件不能为空") + private List fileItems; +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java index c5a9f9f9..f7eed624 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java @@ -9,6 +9,8 @@ import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmHistoryProcessInstanceDO; import cn.iocoder.yudao.module.bpm.service.task.BpmHistoryProcessInstanceService; import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import io.swagger.v3.oas.annotations.Operation; @@ -46,6 +48,9 @@ public class BpmTaskController { @Resource private BpmHistoryProcessInstanceService historyProcessInstanceService; + @Resource + private DeptApi deptApi; + /** * add by yaojun 2024.1.3 * 流程审核添加了抄送用户(多用户)的功能 @@ -69,6 +74,35 @@ public class BpmTaskController { return success(taskService.getTodoTaskPage(getLoginUserId(), pageVO)); } + @GetMapping("get-todo-page") + @Operation(summary = "获取 Todo 待办任务分页") + @PreAuthorize("@ss.hasPermission('bpm:task:query')") + public CommonResult> getTodoTaskPage1(@Valid BpmTaskTodoPageReqVO pageVO) { + return success(taskService.getTodoTaskPage1(getLoginUserId(), pageVO)); + } + + @GetMapping("get-todo-dept") + @Operation(summary = "获取 Todo 待办任务公司列表") + @PreAuthorize("@ss.hasPermission('bpm:task:query')") + public CommonResult> getTodoTaskDept(@Valid BpmTaskTodoPageReqVO pageVO) { + + List deptIds = taskService.getTodoTaskDept(pageVO, getLoginUserId()); + + // 获取待审批的部门列表 + List deptList = deptApi.getDeptList(deptIds).getCheckedData(); + // 获取公司类型的部门信息 + List companyDeptList = deptApi.getCompanyDept().getCheckedData(); + + List respVO = new ArrayList<>(); + for (DeptRespDTO companyDept : companyDeptList) { + if (deptList.stream().anyMatch(dept -> dept.getFlag().contains(companyDept.getId().toString()))) { + respVO.add(companyDept); + } + } + + return success(respVO); + } + @GetMapping("done-page") @Operation(summary = "获取 Done 已办任务分页") @PreAuthorize("@ss.hasPermission('bpm:task:query')") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTodoPageReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTodoPageReqVO.java index 8a4f0247..9d76f95a 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTodoPageReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTodoPageReqVO.java @@ -19,6 +19,9 @@ public class BpmTaskTodoPageReqVO extends PageParam { @Schema(description = "流程任务名", example = "芋道") private String name; + @Schema(description = "公司部门编号") + private Long deptId; + @Schema(description = "创建时间") @DateTimeFormat(pattern = DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime[] createTime; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTodoPageRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTodoPageRespVO.java new file mode 100644 index 00000000..ac282240 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskTodoPageRespVO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 流程任务的 Running 进行中的分页项 Response VO") +@Data +public class BpmTaskTodoPageRespVO { + + @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String id; + + @Schema(description = "任务名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String name; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "流程实例编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String processInstanceId; + + @Schema(description = "流程实例名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") + private String processInstanceName; + + @Schema(description = "发起人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long startUserId; + + @Schema(description = "发起人的用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + private String startUserNickname; + + @Schema(description = "流程定义的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private String processDefinitionId; + + @Schema(description = "被抄送人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "100,200") + private String ccUserIds; +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/message/BpmMessageConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/message/BpmMessageConvert.java index b01a122d..95d49860 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/message/BpmMessageConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/message/BpmMessageConvert.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.bpm.convert.message; import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAWorkTaskDO; +import cn.iocoder.yudao.module.bpm.enums.task.BpmConstants; import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO; import cn.iocoder.yudao.module.system.api.sms.dto.send.SmsSendSingleToUserReqDTO; import cn.iocoder.yudao.module.system.api.subscribe.dto.MsgData; @@ -65,7 +66,7 @@ public interface BpmMessageConvert { //审批结果 MsgData approvalResult = new MsgData(); approvalResult.setName("phrase3"); - approvalResult.setValue(result); + approvalResult.setValue(result.equals(BpmConstants.AUTO_APPRAVAL) ? "通过" : result); message.addData(approvalResult); if (reason != null) { @@ -80,7 +81,7 @@ public interface BpmMessageConvert { } message.setMiniprogramState(miniProgramState); - message.setPage("pages/bpm/task/todo/examineApprove?id=" + processInstanceId + "&isDetail=1"); + message.setPage("subPagesB/bpm/task/todo/examineApprove?id=" + processInstanceId + "&isDetail=1"); return message; } @@ -178,7 +179,7 @@ public interface BpmMessageConvert { message.addData(currentSchedule); message.setMiniprogramState(miniProgramState); - message.setPage("pages/bpm/task/todo/examineApprove?id=" + processInstanceId); + message.setPage("subPagesB/bpm/task/todo/examineApprove?id=" + processInstanceId); return message; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/oa/BpmOASalaryAdjustmentConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/oa/BpmOASalaryAdjustmentConvert.java new file mode 100644 index 00000000..0096d83d --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/oa/BpmOASalaryAdjustmentConvert.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.bpm.convert.oa; + +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.salaryadjustment.BpmOASalaryAdjustmentCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.salaryadjustment.BpmOASalaryAdjustmentRespVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOASalaryAdjustmentDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * 薪资调整 Convert + * + * @author 符溶馨 + */ +@Mapper +public interface BpmOASalaryAdjustmentConvert { + + BpmOASalaryAdjustmentConvert INSTANCE = Mappers.getMapper(BpmOASalaryAdjustmentConvert.class); + + BpmOASalaryAdjustmentDO convert(BpmOASalaryAdjustmentCreateReqVO bean); + + BpmOASalaryAdjustmentRespVO convert(BpmOASalaryAdjustmentDO bean); +} 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 8c492bab..10abe4bb 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 Long imprestId; + /** * 用章的结果 * diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAImprestDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAImprestDO.java index dfa7dc0b..b7800460 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAImprestDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAImprestDO.java @@ -30,11 +30,12 @@ import java.util.List; public class BpmOAImprestDO extends BaseDO { /** - * 是否已报销 0否 1是 2报销中 + * 是否已报销 0否 1是 2报销中 3未报销完毕 */ public static final Integer FLAG_FALSE = 0; public static final Integer FLAG_TRUE = 1; public static final Integer IN_PROGRESS = 2; + public static final Integer NOT_COMPLETED = 3; /** * 出差表单主键 @@ -74,11 +75,6 @@ public class BpmOAImprestDO extends BaseDO { */ private LocalDate date; - /** - * 报销流程业务编号 - */ - private Long reimbursementId; - /** * 申请的结果 * diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOASalaryAdjustmentDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOASalaryAdjustmentDO.java new file mode 100644 index 00000000..0783cf6f --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOASalaryAdjustmentDO.java @@ -0,0 +1,100 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.oa; + +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; + +/** + * OA 用章申请 DO + * + * @author 符溶馨 + */ +@TableName(value ="bpm_oa_salary_adjustment", autoResultMap = true) +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmOASalaryAdjustmentDO extends BaseDO { + + /** + * 出差表单主键 + */ + @TableId + private Long id; + + /** + * 申请人的用户编号 + * 关联 AdminUserDO 的 id 属性 + */ + private Long userId; + + /** + * 调整类型 | 1:涨薪 2:降薪 + */ + private Integer type; + + /** + * 调整人用户编号 + */ + private Long adjustmentUserId; + + /** + * 调整人部门编号 + */ + private Long adjustmentDeptId; + + /** + * 调整日期 + */ + private LocalDate adjustmentDate; + + /** + * 调整前薪资 + */ + private BigDecimal salaryBefore; + + /** + * 调整后薪资 + */ + private BigDecimal salaryAfter; + + /** + * 调整原因 + */ + private Integer reason; + + /** + * 调整原因描述 + */ + private String description; + + /** + * 薪资付款申请的结果 + * 枚举 {@link BpmProcessInstanceResultEnum} + * 考虑到简单,所以直接复用了 BpmProcessInstanceResultEnum 枚举,也可以自己定义一个枚举哈 + */ + private Integer result; + + /** + * 对应的流程编号 + * 关联 ProcessInstance 的 id 属性 + */ + private String processInstanceId; + + /** + * 附件基本信息 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List fileItems ; +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAImprestMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAImprestMapper.java index b2f7e549..3ee1785d 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAImprestMapper.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAImprestMapper.java @@ -6,6 +6,8 @@ import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAImprestDO; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + /** * 备用金申请 Mapper * @@ -15,10 +17,10 @@ import org.apache.ibatis.annotations.Mapper; @Mapper public interface BpmOAImprestMapper extends BaseMapperX { - default BpmOAImprestDO selectByUserId(Long userId, Integer status){ + default BpmOAImprestDO selectByUserId(Long userId, List status){ return selectOne(new LambdaQueryWrapperX().eq(BpmOAImprestDO::getUserId, userId) .eq(BpmOAImprestDO::getResult, BpmProcessInstanceResultEnum.APPROVE.getResult()) - .eq(BpmOAImprestDO::getStatus, status)); + .notIn(BpmOAImprestDO::getStatus, status)); } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOASalaryAdjustmentMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOASalaryAdjustmentMapper.java new file mode 100644 index 00000000..2f55b90e --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOASalaryAdjustmentMapper.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.BpmOASalaryAdjustmentDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface BpmOASalaryAdjustmentMapper extends BaseMapperX { +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java index dab3b6fd..e2f4254e 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java @@ -2,10 +2,16 @@ package cn.iocoder.yudao.module.bpm.dal.mysql.task; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageRespVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; import java.util.Collection; import java.util.List; @@ -13,8 +19,6 @@ import java.util.List; @Mapper public interface BpmTaskExtMapper extends BaseMapperX { - - default void updateByTaskId(BpmTaskExtDO entity) { update(entity, new LambdaQueryWrapper().eq(BpmTaskExtDO::getTaskId, entity.getTaskId())); } @@ -52,4 +56,11 @@ public interface BpmTaskExtMapper extends BaseMapperX { .eqIfPresent(BpmTaskExtDO::getResult, result) .orderByDesc(BpmTaskExtDO::getCreateTime)); } + + IPage selectTodoTaskPage(@Param("page") IPage page, + @Param("reqVO") BpmTaskTodoPageReqVO reqVO, + @Param("userId") Long userId); + + List selectTodoTaskDept(@Param("reqVO") BpmTaskTodoPageReqVO pageVO, + @Param("userId") Long userId); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/financialpayment/FinancialPaymentServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/financialpayment/FinancialPaymentServiceImpl.java index 2124eb0e..95e7db6b 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/financialpayment/FinancialPaymentServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/financialpayment/FinancialPaymentServiceImpl.java @@ -118,7 +118,7 @@ public class FinancialPaymentServiceImpl implements FinancialPaymentService { String result = vo.getStatus() == 1 ? "通过" : "拒绝"; String page = vo.getStatus() == 1 ? "subPages/paymentVoucher/paymentVoucher?id=" + financialPayment.getId() : - "pages/bpm/task/todo/examineApprove?id=" + financialPayment.getId() + "&isDetail=1"; + "subPagesB/bpm/task/todo/examineApprove?id=" + financialPayment.getId() + "&isDetail=1"; // --- 发消息通知发起人 String time = financialPaymentItem.getCreateTime().format(Constants.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND); subscribeMessageSendApi.sendApprovalResultNotification( diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOACashServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOACashServiceImpl.java index 001f46f3..8efdac84 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOACashServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOACashServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; 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; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.cash.BpmOACashCreateReqVO; @@ -12,12 +13,11 @@ import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.procure.BpmOAProcureLi import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; import cn.iocoder.yudao.module.bpm.convert.oa.BpmOACashConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.financialpayment.FinancialPaymentDO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOACashDO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOACashItemDO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAProcureDO; +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.BpmOACashItemMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOACashMapper; +import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAImprestMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.service.financialpayment.FinancialPaymentService; import cn.iocoder.yudao.module.bpm.service.task.BpmHistoryProcessInstanceService; @@ -36,6 +36,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -91,6 +92,12 @@ public class BpmOACashServiceImpl extends BpmOABaseService implements BpmOACashS @Lazy // 解决循环依赖 private BpmHistoryProcessInstanceService historyProcessInstanceService; + @Resource + private BpmOAImprestMapper bpmOAImprestMapper; + + @Resource + private BpmOAImprestService bpmOAImprestService; + @Override public Long createCash(Long userId, BpmOACashCreateReqVO createReqVO) { @@ -120,6 +127,12 @@ public class BpmOACashServiceImpl extends BpmOABaseService implements BpmOACashS historyProcessInstanceService.createHistoryProcessInstance(processInstanceId, createReqVO.getProcessInstanceId()); } + //如果是备用金报销,则更新备用金流程status,并存入当前报销流程ID + if (createReqVO.getImprestId() != null) { + + bpmOAImprestMapper.updateById(new BpmOAImprestDO().setId(createReqVO.getImprestId()).setStatus(BpmOAImprestDO.IN_PROGRESS)); + } + List procureIds = new ArrayList<>(); for (BpmOACashItemDO cashItemDO : bpmOACashItemDOS) { //报销类别为 采购费时 @@ -150,10 +163,8 @@ public class BpmOACashServiceImpl extends BpmOABaseService implements BpmOACashS @Transactional(rollbackFor = Exception.class) public void updateCashResult(String processInstanceId, Long id, Integer result) { - validateLeaveExists(id); - // 获得现金支出业务数据 - BpmOACashDO cash = getCash(id); + BpmOACashDO cash = validateLeaveExists(id); // 获取现金支出明细 List cashItemDOs = getCashItem(id); @@ -171,8 +182,6 @@ public class BpmOACashServiceImpl extends BpmOABaseService implements BpmOACashS procureIds.add(cashItemDO.getProcureId()); } } - - String reason = cashItemDOs.stream().map(BpmOACashItemDO::getReason).filter(StrUtil::isNotEmpty).collect(Collectors.joining(",")); //报销类别为 采购费时 if (!CollectionUtil.isEmpty(procureIds)) { //所有关联的采购申请改为 已支付状态 @@ -183,6 +192,40 @@ public class BpmOACashServiceImpl extends BpmOABaseService implements BpmOACashS ); } + //判断是否为备用金报销 + boolean isImprest = false; + BigDecimal amount = null; + if (cash.getImprestId() != null) { + + // 获取备用金详情 + BpmOAImprestDO bpmOAImprestDO = bpmOAImprestService.getImprest(cash.getImprestId()); + + BpmOAImprestDO updateVO = new BpmOAImprestDO() + .setId(cash.getImprestId()) + .setReimbursedAmount(bpmOAImprestDO.getReimbursedAmount().add(cash.getTotalMoney())); + + // 获取 剩余备用金报销金额 + amount = bpmOAImprestDO.getAmount().subtract(updateVO.getReimbursedAmount()); + if (amount.compareTo(BigDecimal.ZERO) <= 0) { + + //将相应备用金申请状态改为 已报销 + bpmOAImprestMapper.updateById(updateVO.setStatus(BpmOAImprestDO.FLAG_TRUE)); + + if (amount.compareTo(BigDecimal.ZERO) < 0) { + isImprest = true; + }else { + return; + } + }else { + //将相应备用金申请状态改为 未报销完毕 + bpmOAImprestMapper.updateById(updateVO.setStatus(BpmOAImprestDO.NOT_COMPLETED)); + + return; + } + } + + String reason = cashItemDOs.stream().map(BpmOACashItemDO::getReason).filter(StrUtil::isNotEmpty).collect(Collectors.joining(",")); + BpmProcessInstanceExtDO processInstance = bpmProcessInstanceService.getProcessInstanceDO(processInstanceId); CommonResult user = userApi.getUser(cash.getUserId()); // -- 插入到财务支付表中 @@ -195,11 +238,10 @@ public class BpmOACashServiceImpl extends BpmOABaseService implements BpmOACashS .setObjectId(id) .setType(1) .setStatus(0) - .setAmountPayable(cash.getTotalMoney()) + .setAmountPayable(isImprest ? amount.abs() : cash.getTotalMoney()) .setBeginTime(processInstance.getCreateTime()) .setEndTime(processInstance.getEndTime()) ); - } } @@ -210,6 +252,19 @@ public class BpmOACashServiceImpl extends BpmOABaseService implements BpmOACashS || BpmProcessInstanceResultEnum.CANCEL.getResult().equals(result) || BpmProcessInstanceResultEnum.BACK.getResult().equals(result)) { + if (cash.getImprestId() != null) { + + Long count = cashMapper.selectCount(new LambdaQueryWrapperX() + .eq(BpmOACashDO::getImprestId, cash.getImprestId()) + .eq(BpmOACashDO::getResult, BpmProcessInstanceResultEnum.APPROVE)); + if (count > 0L) { + //将相应备用金申请状态改为 未报销 + bpmOAImprestMapper.updateById(new BpmOAImprestDO().setId(cash.getImprestId()).setStatus(BpmOAImprestDO.NOT_COMPLETED)); + }else { + bpmOAImprestMapper.updateById(new BpmOAImprestDO().setId(cash.getImprestId()).setStatus(BpmOAImprestDO.FLAG_FALSE)); + } + } + //判断是否有采购报销 for (BpmOACashItemDO cashItemDO : cashItemDOs) { @@ -232,10 +287,13 @@ public class BpmOACashServiceImpl extends BpmOABaseService implements BpmOACashS cashMapper.updateById(new BpmOACashDO().setId(id).setResult(result)); } - private void validateLeaveExists(Long id) { - if (cashMapper.selectById(id) == null) { + private BpmOACashDO validateLeaveExists(Long id) { + BpmOACashDO cash = cashMapper.selectById(id); + if (cash == null) { throw exception(OA_CASH_NOT_EXISTS); } + + return cash; } @Override diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAImprestService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAImprestService.java index 18b3b654..094c79f2 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAImprestService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAImprestService.java @@ -45,14 +45,6 @@ public interface BpmOAImprestService { */ BpmOAImprestDO getImprestByUserId(Long userId); - /** - * 获得备用金表单 - * - * @param reimbursementId 编号 - * @return 备用金申请 - */ - BpmOAImprestDO getImprestByReimbursementId(Long reimbursementId); - /** * 通过流程实例id获取 * diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAImprestServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAImprestServiceImpl.java index 3646140a..c661d3c1 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAImprestServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAImprestServiceImpl.java @@ -23,6 +23,7 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -141,14 +142,7 @@ public class BpmOAImprestServiceImpl extends BpmOABaseService implements BpmOAIm public BpmOAImprestDO getImprestByUserId(Long userId) { //根据user 查询审批通过并且未报销得表单。 - return imprestMapper.selectByUserId(userId, BpmOAImprestDO.FLAG_FALSE); - } - - @Override - public BpmOAImprestDO getImprestByReimbursementId(Long reimbursementId) { - - //根据报销业务编号获取备用金详情 - return imprestMapper.selectOne(BpmOAImprestDO::getReimbursementId, reimbursementId); + return imprestMapper.selectByUserId(userId, Arrays.asList(BpmOAImprestDO.FLAG_TRUE, BpmOAImprestDO.IN_PROGRESS)); } @Override @@ -160,4 +154,4 @@ public class BpmOAImprestServiceImpl extends BpmOABaseService implements BpmOAIm } return null; } -} +} \ 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 8169d6f1..31907edb 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 @@ -49,4 +49,5 @@ public interface BpmOAReimbursementService { * @return */ BpmOAReimbursementDO getByProcessInstanceId(String processInstanceId); + } 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 b7332359..4db52665 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 @@ -1,9 +1,13 @@ package cn.iocoder.yudao.module.bpm.service.oa; +import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 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; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.procure.BpmOAProcureListEditReqVO; @@ -36,6 +40,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -116,9 +121,9 @@ public class BpmOAReimbursementServiceImpl extends BpmOABaseService implements B } //如果是备用金报销,则更新备用金流程status,并存入当前报销流程ID - if (createReqVO.getDifference() != null) { - BpmOAImprestDO bpmOAImprestDO = bpmOAImprestService.getImprestByUserId(userId); - bpmOAImprestMapper.updateById(new BpmOAImprestDO().setId(bpmOAImprestDO.getId()).setReimbursementId(reimbursement.getId()).setStatus(BpmOAImprestDO.IN_PROGRESS)); + if (createReqVO.getImprestId() != null) { + + bpmOAImprestMapper.updateById(new BpmOAImprestDO().setId(createReqVO.getImprestId()).setStatus(BpmOAImprestDO.IN_PROGRESS)); } //判断是否有 采购报销 @@ -162,12 +167,6 @@ public class BpmOAReimbursementServiceImpl extends BpmOABaseService implements B if (instance.isEnded()) { - //判断是否为备用金报销 - if (bpmOAReimbursementDO.getImprestId() != null) { - //将相应备用金申请状态改为 已报销 - bpmOAImprestMapper.updateById(new BpmOAImprestDO().setId(bpmOAReimbursementDO.getImprestId()).setStatus(BpmOAImprestDO.FLAG_TRUE)); - } - //判断是否有采购报销 List procureIds = new ArrayList<>(); List reimbursements = bpmOAReimbursementDO.getReimbursements(); @@ -183,6 +182,44 @@ public class BpmOAReimbursementServiceImpl extends BpmOABaseService implements B } } + if (!procureIds.isEmpty()) { + + //所有关联的采购申请改为 已支付状态 + bpmOAProcureService.updatePayFlagByIds( + new BpmOAProcureListEditReqVO() + .setPayFlag(BpmOAProcureDO.FLAG_TRUE) + .setProcureIds(procureIds) + ); + } + + //判断是否为备用金报销 + boolean isImprest = false; + if (bpmOAReimbursementDO.getImprestId() != null) { + + // 获取备用金详情 + BpmOAImprestDO bpmOAImprestDO = bpmOAImprestService.getImprest(bpmOAReimbursementDO.getImprestId()); + + BpmOAImprestDO updateVO = new BpmOAImprestDO() + .setId(bpmOAReimbursementDO.getImprestId()) + .setReimbursedAmount(bpmOAImprestDO.getReimbursedAmount().add(bpmOAReimbursementDO.getTotalMoney())); + if (bpmOAReimbursementDO.getDifference().compareTo(BigDecimal.ZERO) <= 0) { + + //将相应备用金申请状态改为 已报销 + bpmOAImprestMapper.updateById(updateVO.setStatus(BpmOAImprestDO.FLAG_TRUE)); + + if (bpmOAReimbursementDO.getDifference().compareTo(BigDecimal.ZERO) < 0) { + isImprest = true; + }else { + return; + } + }else { + //将相应备用金申请状态改为 未报销完毕 + bpmOAImprestMapper.updateById(updateVO.setStatus(BpmOAImprestDO.NOT_COMPLETED)); + + return; + } + } + String reason = reimbursements.stream().map(Reimbursement::getDetail) .filter(StrUtil::isNotEmpty) .collect(Collectors.joining(",")); @@ -198,21 +235,11 @@ public class BpmOAReimbursementServiceImpl extends BpmOABaseService implements B .setObjectId(id) .setType(4) .setStatus(0) - .setAmountPayable(bpmOAReimbursementDO.getTotalMoney()) + .setAmountPayable(isImprest ? bpmOAReimbursementDO.getDifference().abs() : bpmOAReimbursementDO.getTotalMoney()) .setProcessInstanceName(processInstance.getName()) .setBeginTime(processInstance.getCreateTime()) .setEndTime(processInstance.getEndTime()) ); - - if (!procureIds.isEmpty()) { - - //所有关联的采购申请改为 已支付状态 - bpmOAProcureService.updatePayFlagByIds( - new BpmOAProcureListEditReqVO() - .setPayFlag(BpmOAProcureDO.FLAG_TRUE) - .setProcureIds(procureIds) - ); - } } } @@ -223,12 +250,17 @@ public class BpmOAReimbursementServiceImpl extends BpmOABaseService implements B || BpmProcessInstanceResultEnum.CANCEL.getResult().equals(result) || BpmProcessInstanceResultEnum.BACK.getResult().equals(result)) { - BpmOAImprestDO bpmOAImprestDO = bpmOAImprestMapper.selectOne(BpmOAImprestDO::getReimbursementId, id); + if (bpmOAReimbursementDO.getImprestId() != null) { - if (bpmOAImprestDO != null) { - - //将相应备用金申请状态改为 未报销 - bpmOAImprestMapper.updateById(new BpmOAImprestDO().setId(bpmOAImprestDO.getId()).setStatus(BpmOAImprestDO.FLAG_FALSE)); + Long count = reimbursementMapper.selectCount(new LambdaQueryWrapperX() + .eq(BpmOAReimbursementDO::getImprestId, bpmOAReimbursementDO.getImprestId()) + .eq(BpmOAReimbursementDO::getResult, BpmProcessInstanceResultEnum.APPROVE)); + if (count > 0L) { + //将相应备用金申请状态改为 未报销 + bpmOAImprestMapper.updateById(new BpmOAImprestDO().setId(bpmOAReimbursementDO.getImprestId()).setStatus(BpmOAImprestDO.NOT_COMPLETED)); + }else { + bpmOAImprestMapper.updateById(new BpmOAImprestDO().setId(bpmOAReimbursementDO.getImprestId()).setStatus(BpmOAImprestDO.FLAG_FALSE)); + } } //判断是否有采购报销 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOASalaryAdjustmentService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOASalaryAdjustmentService.java new file mode 100644 index 00000000..4441dbb2 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOASalaryAdjustmentService.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.bpm.service.oa; + +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.salaryadjustment.BpmOASalaryAdjustmentCreateReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOASalaryAdjustmentDO; + +import javax.validation.Valid; + +/** + * 薪资付款申请 Service 接口 + * + * @author 符溶馨 + */ +public interface BpmOASalaryAdjustmentService { + + /** + * 创建用章申请 + * + * @param userId 用户编号 + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createSalaryAdjustment(Long userId, @Valid BpmOASalaryAdjustmentCreateReqVO createReqVO); + + /** + * 更新用章申请的状态 + * + * @param id 编号 + * @param result 结果 + */ + void updateSalaryAdjustmentResult(Long id, Integer result); + + /** + * 获得用章申请 + * + * @param id 编号 + * @return 用章申请 + */ + BpmOASalaryAdjustmentDO getSalaryAdjustment(Long id); + + /** + * 获得指定的用章申请 + * @param processInstanceId 流程实例编号 + * @return 用章申请 + */ + BpmOASalaryAdjustmentDO getByProcessInstanceId(String processInstanceId); +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOASalaryAdjustmentServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOASalaryAdjustmentServiceImpl.java new file mode 100644 index 00000000..14dc2db0 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOASalaryAdjustmentServiceImpl.java @@ -0,0 +1,100 @@ +package cn.iocoder.yudao.module.bpm.service.oa; + +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; +import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.salaryadjustment.BpmOASalaryAdjustmentCreateReqVO; +import cn.iocoder.yudao.module.bpm.convert.oa.BpmOASalaryAdjustmentConvert; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOASalaryAdjustmentDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOASalaryAdjustmentMapper; +import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; +import cn.iocoder.yudao.module.bpm.service.task.BpmHistoryProcessInstanceService; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_SALARY_NOT_EXISTS; + +/** + * OA 薪资付款申请 Service 实现类 + * + * @author 符溶馨 + */ +@Service +@Validated +public class BpmOASalaryAdjustmentServiceImpl extends BpmOABaseService implements BpmOASalaryAdjustmentService{ + + /** + * OA 薪资付款对应的流程定义 KEY + */ + public static final String PROCESS_KEY = "oa_salary_adjustment_2"; + + @Resource + private BpmOASalaryAdjustmentMapper salaryMapper; + + @Resource + private BpmProcessInstanceApi processInstanceApi; + + @Resource + private BpmHistoryProcessInstanceService historyProcessInstanceService; + + @Override + public Long createSalaryAdjustment(Long userId, BpmOASalaryAdjustmentCreateReqVO createReqVO) { + + //插入OA 薪资付款申请 + BpmOASalaryAdjustmentDO salary = BpmOASalaryAdjustmentConvert.INSTANCE.convert(createReqVO).setUserId(userId) + .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); + salaryMapper.insert(salary) ; + + // 发起 BPM 流程 + Map processInstanceVariables = new HashMap<>(); + String processInstanceId = processInstanceApi.createProcessInstance(userId, + new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(PROCESS_KEY) + .setVariables(processInstanceVariables).setBusinessKey(String.valueOf(salary.getId()))).getCheckedData(); + + // 将工作流的编号,更新到 OA 用章单中 + salaryMapper.updateById(new BpmOASalaryAdjustmentDO().setId(salary.getId()).setProcessInstanceId(processInstanceId)); + + // 判断是否为重新发起的流程 + if (createReqVO.getProcessInstanceId() != null && createReqVO.getResult() == 3) { + + historyProcessInstanceService.createHistoryProcessInstance(processInstanceId, createReqVO.getProcessInstanceId()); + } + + List fileItems = createReqVO.getFileItems() ; + //这里的逻辑,如果fileItems不为空,且有数据,那么说明是上传了附件的,则需要更工作流文件表对应的实例Id + if (fileItems != null && !fileItems.isEmpty()) { + uploadBpmFileProcessInstanceId(processInstanceId,fileItems) ; + } + return salary.getId(); + } + + @Override + public void updateSalaryAdjustmentResult(Long id, Integer result) { + validateLeaveExists(id); + salaryMapper.updateById(new BpmOASalaryAdjustmentDO().setId(id).setResult(result)); + } + + private void validateLeaveExists(Long id) { + if (salaryMapper.selectById(id) == null) { + throw exception(OA_SALARY_NOT_EXISTS); + } + } + + @Override + public BpmOASalaryAdjustmentDO getSalaryAdjustment(Long id) { + + return salaryMapper.selectById(id); + } + + @Override + public BpmOASalaryAdjustmentDO getByProcessInstanceId(String processInstanceId) { + + return salaryMapper.selectOne(BpmOASalaryAdjustmentDO::getProcessInstanceId, processInstanceId); + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOASalaryAdjustmentResultListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOASalaryAdjustmentResultListener.java new file mode 100644 index 00000000..b649ace9 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOASalaryAdjustmentResultListener.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.bpm.service.oa.listener; + +import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEvent; +import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventListener; +import cn.iocoder.yudao.module.bpm.service.oa.BpmOASalaryAdjustmentService; +import cn.iocoder.yudao.module.bpm.service.oa.BpmOASalaryAdjustmentServiceImpl; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * OA 用章单的结果的监听器实现类 + * + * @author 符溶馨 + */ +@Component +public class BpmOASalaryAdjustmentResultListener extends BpmProcessInstanceResultEventListener { + + @Resource + private BpmOASalaryAdjustmentService SalaryAdjustmentService; + + @Override + protected String getProcessDefinitionKey() { + + return BpmOASalaryAdjustmentServiceImpl.PROCESS_KEY; + } + + @Override + protected void onEvent(BpmProcessInstanceResultEvent event) { + SalaryAdjustmentService.updateSalaryAdjustmentResult(Long.parseLong(event.getBusinessKey()), event.getResult()); + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java index dbddfbc9..0422fcf3 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.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.dal.mysql.task.BpmTaskExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmConstants; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.bpm.service.oa.*; 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.bank.BankApi; 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.HistoricActivityInstance; import org.flowable.engine.history.HistoricActivityInstanceQuery; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; 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 ; @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); } @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); // 创建流程实例 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; } } } @Resource private BpmTaskExtMapper taskExtMapper; @Override public List getUserProcessTpo10(BpmProcessInstanceStatisticsReqVO pageReqVO) { //按审核人分组查询,统计已完成流程数量及平均耗时间 List respVOS = processInstanceExtMapper.getUserProcessTpo10(pageReqVO); if (respVOS == null || respVOS.size() == 0) { return null; } List idList = respVOS.stream() .map(BpmProcessFinishStatisticsRespVO::getUserId) .collect(Collectors.toList()); //根据userId,查询UserMap Map userMap = adminUserApi.getUserMap(idList); Long[] idsArray = new Long[userMap.size()]; // 使用 map 的 keySet() 方法获取键集合 Set keys = userMap.keySet(); // 遍历键集合,将每个键添加到数组中 int index = 0; for (Long key : keys) { idsArray[index++] = key; } pageReqVO.setUserIds(idsArray); //按审核人分组查询,未审批完成的流程数量 List bpmTaskExtDOs = processInstanceExtMapper.selectUnfinishProcessCount(pageReqVO); //按审核人分组查询,未完成的记录数 Map unFinfishCountCountMap = new HashMap<>(); for (BpmProcessFinishStatisticsRespVO item : bpmTaskExtDOs) { unFinfishCountCountMap.put(item.getUserId(), item.getUnFinfishCount()); } respVOS.forEach(respVO -> respVO.setName(userMap.get(respVO.getUserId()).getNickname())); respVOS.forEach(respVO -> respVO.setUnFinfishCount(unFinfishCountCountMap.get(respVO.getUserId()))); //获取排行榜第一记录的耗时,作为基础数据 double num = Double.parseDouble(respVOS.get(0).getUserTime()); // 先将字符串转换为双精度浮点数 int baseNumber = (int) num; // 再通过类型转换操作符将其转换为整数 DecimalFormat df = new DecimalFormat("#.00"); respVOS.forEach(respVO -> { //格式化流程完成率 float finfishCount = (float) respVO.getFinfishCount(); float unFinfishCount = respVO.getUnFinfishCount() == null ? 0 : respVO.getUnFinfishCount(); float all = finfishCount + unFinfishCount; float result = finfishCount / all; float rate = result * 100; respVO.setCompletionRate(df.format(rate) + "%"); double dValue = Double.parseDouble(respVO.getUserTime()); // 将字符串转换为double类型 int roundedValue = (int) Math.round(dValue); // 使用Math.round()进行四舍五入,并转换为int类型 respVO.setUserTime(roundedValue + ""); //格式化进度百度比, 参照最高的数据进行百分比显示 double percentage = ((int) Double.parseDouble(respVO.getUserTime()) / (double) baseNumber) * 100; respVO.setPercentage((int) Math.round(percentage)); //设置未完成 respVO.setUnFinfishCount(Integer.valueOf((int) unFinfishCount)); }); return respVOS; } @Override @DataPermission(enable = false) public BpmProcessInstanceExtDO getProcessInstanceDO(String id) { return processInstanceExtMapper.selectByProcessInstanceId(id); } @Resource private FileApi fileApi; @Resource private BankApi bankApi; @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.getImprestByReimbursementId(reimbursement.getId()); if (bpmOAImprestDO != null) { //设置备用金 金额 bpmOAReimbursementRespVO.setAmount(bpmOAImprestDO.getAmount()); } // 设置抄送人信息 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())); // 设置抄送人信息 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.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.dal.mysql.task.BpmTaskExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmConstants; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.bpm.service.oa.*; 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.bank.BankApi; 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.HistoricActivityInstance; import org.flowable.engine.history.HistoricActivityInstanceQuery; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; 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 ; @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); } @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); // 创建流程实例 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; } } } @Resource private BpmTaskExtMapper taskExtMapper; @Override public List getUserProcessTpo10(BpmProcessInstanceStatisticsReqVO pageReqVO) { //按审核人分组查询,统计已完成流程数量及平均耗时间 List respVOS = processInstanceExtMapper.getUserProcessTpo10(pageReqVO); if (respVOS == null || respVOS.size() == 0) { return null; } List idList = respVOS.stream() .map(BpmProcessFinishStatisticsRespVO::getUserId) .collect(Collectors.toList()); //根据userId,查询UserMap Map userMap = adminUserApi.getUserMap(idList); Long[] idsArray = new Long[userMap.size()]; // 使用 map 的 keySet() 方法获取键集合 Set keys = userMap.keySet(); // 遍历键集合,将每个键添加到数组中 int index = 0; for (Long key : keys) { idsArray[index++] = key; } pageReqVO.setUserIds(idsArray); //按审核人分组查询,未审批完成的流程数量 List bpmTaskExtDOs = processInstanceExtMapper.selectUnfinishProcessCount(pageReqVO); //按审核人分组查询,未完成的记录数 Map unFinfishCountCountMap = new HashMap<>(); for (BpmProcessFinishStatisticsRespVO item : bpmTaskExtDOs) { unFinfishCountCountMap.put(item.getUserId(), item.getUnFinfishCount()); } respVOS.forEach(respVO -> respVO.setName(userMap.get(respVO.getUserId()).getNickname())); respVOS.forEach(respVO -> respVO.setUnFinfishCount(unFinfishCountCountMap.get(respVO.getUserId()))); //获取排行榜第一记录的耗时,作为基础数据 double num = Double.parseDouble(respVOS.get(0).getUserTime()); // 先将字符串转换为双精度浮点数 int baseNumber = (int) num; // 再通过类型转换操作符将其转换为整数 DecimalFormat df = new DecimalFormat("#.00"); respVOS.forEach(respVO -> { //格式化流程完成率 float finfishCount = (float) respVO.getFinfishCount(); float unFinfishCount = respVO.getUnFinfishCount() == null ? 0 : respVO.getUnFinfishCount(); float all = finfishCount + unFinfishCount; float result = finfishCount / all; float rate = result * 100; respVO.setCompletionRate(df.format(rate) + "%"); double dValue = Double.parseDouble(respVO.getUserTime()); // 将字符串转换为double类型 int roundedValue = (int) Math.round(dValue); // 使用Math.round()进行四舍五入,并转换为int类型 respVO.setUserTime(roundedValue + ""); //格式化进度百度比, 参照最高的数据进行百分比显示 double percentage = ((int) Double.parseDouble(respVO.getUserTime()) / (double) baseNumber) * 100; respVO.setPercentage((int) Math.round(percentage)); //设置未完成 respVO.setUnFinfishCount(Integer.valueOf((int) unFinfishCount)); }); return respVOS; } @Override @DataPermission(enable = false) public BpmProcessInstanceExtDO getProcessInstanceDO(String id) { return processInstanceExtMapper.selectByProcessInstanceId(id); } @Resource private FileApi fileApi; @Resource private BankApi bankApi; @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().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().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 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java index a1b1ce5e..b97155e9 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import org.flowable.task.api.Task; import org.flowable.task.api.history.HistoricTaskInstance; @@ -37,6 +38,15 @@ public interface BpmTaskService { */ PageResult getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageReqVO); + /** + * 获得待办的流程任务分页 + * + * @param userId 用户编号 + * @param pageReqVO 分页请求 + * @return 流程任务分页 + */ + PageResult getTodoTaskPage1(Long userId, BpmTaskTodoPageReqVO pageReqVO); + /** * 获得已办的流程任务分页 * @@ -249,4 +259,10 @@ public interface BpmTaskService { */ Map getCurrentToDoProcessInstacePreAndNex(Long userId, String processInstanceId,BpmTaskTodoPageReqVO pageReqVO); + /** + * 获取 待办任务公司列表 + * @param pageVO 查询条件 + * @return 公司列表 + */ + List getTodoTaskDept(BpmTaskTodoPageReqVO pageVO, Long userId); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index 88a13ca2..f12fc078 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -17,6 +17,7 @@ import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessI import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAEntryDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOARegularDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOASalaryDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOASealDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; @@ -28,12 +29,15 @@ import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAEntryService; +import cn.iocoder.yudao.module.bpm.service.oa.BpmOARegularService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOASalaryService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOASealService; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.BpmnModel; import org.flowable.bpmn.model.FlowElement; @@ -63,6 +67,7 @@ import javax.annotation.Resource; import javax.validation.Valid; import java.time.LocalDateTime; import java.util.*; +import java.util.concurrent.CountDownLatch; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -117,6 +122,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { @Resource private BpmOASalaryService bpmOASalaryService; + @Resource + private BpmOARegularService bpmOARegularService; + @Override public PageResult getCCTaskPage(Long userId, BpmTaskDonePageReqVO pageVO) { // 查询被抄送的Task @@ -200,6 +208,14 @@ public class BpmTaskServiceImpl implements BpmTaskService { taskQuery.count()); } + @Override + public PageResult getTodoTaskPage1(Long userId, BpmTaskTodoPageReqVO pageReqVO) { + + Page page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()); + IPage pageResp = taskExtMapper.selectTodoTaskPage(page, pageReqVO, userId); + return new PageResult<>(pageResp.getRecords(), pageResp.getTotal()); + } + @Override public PageResult getDoneTaskPage(Long userId, BpmTaskDonePageReqVO pageVO) { //查询bpm_task_ext扩展表, 接受人是自己,不是自动审批的任务, 按任务名称分组 @@ -559,6 +575,16 @@ public class BpmTaskServiceImpl implements BpmTaskService { } } + // 判断 转正流程时 + if (instance.getProcessDefinitionId().contains("oa_regular")) { + BpmOARegularDO regularDO = bpmOARegularService.getByProcessInstanceId(instance.getProcessInstanceId()); + if (regularDO != null) { + + DeptRespDTO dto = deptApi.getDept(regularDO.getDeptId()).getCheckedData(); + paramMap.put("regular_dept_flag", dto.getFlag()); //配置工厂idflag + } + } + ArrayList list = new ArrayList<>(postIds); // 只获配置的首个岗位 Long postId = list.get(0); @@ -876,22 +902,22 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 发送通知。在事务提交时,批量执行操作,所以直接查询会无法查询到 ProcessInstance,所以这里是通过监听事务的提交来实现。 TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { - @Override - public void afterCommit() { - - if (StrUtil.isNotEmpty(task.getAssignee())) { - - ProcessInstance processInstance = processInstanceService.getProcessInstance(task.getProcessInstanceId()); - if (processInstance != null) { - // 获得任务列表 - List BpmTaskRespVOs = getTaskListByProcessInstanceId(processInstance.getProcessInstanceId()); - AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId())).getCheckedData(); - //发送信息通知 - messageService.sendMessageWhenTaskAssigned( - BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task, BpmTaskRespVOs)); - } - } - } +// @Override +// public void afterCommit() { +// +// if (StrUtil.isNotEmpty(task.getAssignee())) { +// +// ProcessInstance processInstance = processInstanceService.getProcessInstance(task.getProcessInstanceId()); +// if (processInstance != null) { +// // 获得任务列表 +// List BpmTaskRespVOs = getTaskListByProcessInstanceId(processInstance.getProcessInstanceId()); +// AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId())).getCheckedData(); +// //发送信息通知 +// messageService.sendMessageWhenTaskAssigned( +// BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task, BpmTaskRespVOs)); +// } +// } +// } @Override public void afterCompletion(int status) { @@ -917,12 +943,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 则自动通过当前审批节点 if (processInstance.getStartUserId().toString().equals(task.getAssignee())) { - BpmTaskApproveReqVO reqVO = new BpmTaskApproveReqVO(); - reqVO.setId(task.getId()); - reqVO.setReason(BpmConstants.AUTO_APPRAVAL); - // 另起线程处理 任务通过, 避免事务之间重复调用异常 - new Thread(() -> approveTask(Long.valueOf(task.getAssignee()), reqVO)).start(); - + // 自动审核通过任务 + autoApproveTask(task); + return; } else { // 判断当前审批人是否在该流程中 已通过审批, @@ -931,18 +954,54 @@ public class BpmTaskServiceImpl implements BpmTaskService { if (count > 0L) { - BpmTaskApproveReqVO reqVO = new BpmTaskApproveReqVO(); - reqVO.setId(task.getId()); - reqVO.setReason(BpmConstants.AUTO_APPRAVAL); - // 另起线程处理 任务通过, 避免事务之间重复调用异常 - new Thread(() -> approveTask(Long.valueOf(task.getAssignee()), reqVO)).start(); + // 自动审核通过任务 + autoApproveTask(task); + return; } } + + ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId()); + if (instance != null) { + // 获得任务列表 + List BpmTaskRespVOs = getTaskListByProcessInstanceId(instance.getProcessInstanceId()); + AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(instance.getStartUserId())).getCheckedData(); + //发送信息通知 + messageService.sendMessageWhenTaskAssigned( + BpmTaskConvert.INSTANCE.convert(instance, startUser, task, BpmTaskRespVOs)); + } } } }); } + /** + * 自动审核通过任务 + */ + private void autoApproveTask(Task task) { + + BpmTaskApproveReqVO reqVO = new BpmTaskApproveReqVO(); + reqVO.setId(task.getId()); + reqVO.setReason(BpmConstants.AUTO_APPRAVAL); + + CountDownLatch countDownLatch = new CountDownLatch(1); + // 另起线程处理 任务通过, 避免事务之间重复调用异常 + new Thread(() -> { + try { + approveTask(Long.valueOf(task.getAssignee()), reqVO) ; + } catch (Exception e) { + e.printStackTrace(); + } finally { + // 执行完毕,计数器减1 + countDownLatch.countDown(); + } + }).start(); + try { + countDownLatch.await(); // 等待直到计数器为0 + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + private Task validateTaskExist(String id) { Task task = getTask(id); if (task == null) { @@ -1408,13 +1467,15 @@ public class BpmTaskServiceImpl implements BpmTaskService { * @param pageVO 分页请求 * @return 流程任务分页 */ + @Override public Map getCurrentToDoProcessInstacePreAndNex(Long userId, String processInstanceId,BpmTaskTodoPageReqVO pageVO) { - PageResult list = getTodoTaskPage(userId, pageVO) ; + pageVO.setPageSize(100); + PageResult list = getTodoTaskPage1(userId, pageVO) ; - List vos = list.getList() ; + List vos = list.getList() ; List processInstanceIds = new ArrayList<>() ; - for (BpmTaskTodoPageItemRespVO vo : vos) { - processInstanceIds.add(vo.getProcessInstance().getId()) ; + for (BpmTaskTodoPageRespVO vo : vos) { + processInstanceIds.add(vo.getProcessInstanceId()) ; } String pre = null ; String next = null ; @@ -1432,9 +1493,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { pre = processInstanceIds.get(i - 1) ; }else if( hasPre ) { pageVO.setPageNo(pageNo - 1); - list = getTodoTaskPage(userId, pageVO) ; - BpmTaskTodoPageItemRespVO vo = list.getList().get(list.getList().size()-1); - pre = vo.getProcessInstance().getId() ; + list = getTodoTaskPage1(userId, pageVO) ; + BpmTaskTodoPageRespVO vo = list.getList().get(list.getList().size()-1); + pre = vo.getProcessDefinitionId() ; }else { pre = null ; } @@ -1447,9 +1508,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { next = processInstanceIds.get(i + 1) ; }else if( hasNext ) { pageVO.setPageNo(pageNo + 1); - list = getTodoTaskPage(userId, pageVO) ; - BpmTaskTodoPageItemRespVO vo = list.getList().get(0); - next = vo.getProcessInstance().getId() ; + list = getTodoTaskPage1(userId, pageVO) ; + BpmTaskTodoPageRespVO vo = list.getList().get(0); + next = vo.getProcessDefinitionId() ; }else { next = null ; } @@ -1526,5 +1587,10 @@ public class BpmTaskServiceImpl implements BpmTaskService { return map ; } + @Override + public List getTodoTaskDept(BpmTaskTodoPageReqVO pageVO, Long userId) { + + return taskExtMapper.selectTodoTaskDept(pageVO, userId); + } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/task/BpmTaskExtMapper.xml b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/task/BpmTaskExtMapper.xml new file mode 100644 index 00000000..8be8d1c9 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/task/BpmTaskExtMapper.xml @@ -0,0 +1,76 @@ + + + + + + + + + + From 3aa9fec844a038ed032284cda08c27130e6976c5 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Sun, 13 Oct 2024 21:29:48 +0800 Subject: [PATCH 04/20] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=85=AC=E5=8F=B8?= =?UTF-8?q?=E9=83=A8=E9=97=A8=E4=BF=A1=E6=81=AF=E6=8E=A5=E5=8F=A3=E5=92=8C?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 DeptApi 中添加 getCompanyDept 接口,用于获取部门类型为公司的部门信息 - 在 DeptRespDTO、DeptDO、DeptListReqVO、DeptRespVO、DeptSaveReqVO 和 DeptSimpleRespVO 中添加 shortName 字段,用于存储部门简称 - 修改 LogInstanceMapper 中的 SQL 查询,移除不必要的左连接条件 - 在 LogReadDo 中删除 deleted 字段,简化数据结构 --- .../cn/iocoder/yudao/module/system/api/dept/DeptApi.java | 4 ++++ .../yudao/module/system/api/dept/dto/DeptRespDTO.java | 3 +++ .../yudao/module/system/api/dept/DeptApiImpl.java | 7 +++++++ .../controller/admin/dept/vo/dept/DeptListReqVO.java | 3 +++ .../system/controller/admin/dept/vo/dept/DeptRespVO.java | 3 +++ .../controller/admin/dept/vo/dept/DeptSaveReqVO.java | 3 +++ .../controller/admin/dept/vo/dept/DeptSimpleRespVO.java | 3 +++ .../yudao/module/system/dal/dataobject/dept/DeptDO.java | 4 ++++ .../module/system/dal/dataobject/worklog/LogReadDo.java | 5 ----- .../system/dal/mysql/worklog/LogInstanceMapper.java | 9 +++++---- 10 files changed, 35 insertions(+), 9 deletions(-) diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApi.java index 602f2a69..5d78e764 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApi.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApi.java @@ -91,4 +91,8 @@ public interface DeptApi { @PostMapping(PREFIX + "/getDeptListByFactoryIds") @Operation(summary = "根据工厂ids获取部门ids") CommonResult> getDeptListByFactoryIds(@RequestBody List factoryIds); + + @GetMapping("/getCompanyDept") + @Operation(summary = "获取部门类型为公司的部门信息") + CommonResult> getCompanyDept(); } diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/dto/DeptRespDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/dto/DeptRespDTO.java index 93db4209..6efff426 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/dto/DeptRespDTO.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/dto/DeptRespDTO.java @@ -13,6 +13,9 @@ public class DeptRespDTO { @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "研发部") private String name; + @Schema(description = "部门简称", example = "芋道") + private String shortName; + @Schema(description = "父部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Long parentId; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApiImpl.java index 9ecd4202..24a64626 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApiImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApiImpl.java @@ -127,4 +127,11 @@ public class DeptApiImpl implements DeptApi { Map map = deptDOS.stream().collect(Collectors.toMap(DeptDO::getFactoryId, DeptDO::getId)); return success(map); } + + @Override + @DataPermission(enable = false) + public CommonResult> getCompanyDept() { + List deptDOS = deptService.getCompanyDept(); + return success(BeanUtils.toBean(deptDOS, DeptRespDTO.class)); + } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptListReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptListReqVO.java index 27af2e9f..e8496de4 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptListReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptListReqVO.java @@ -10,6 +10,9 @@ public class DeptListReqVO { @Schema(description = "部门名称,模糊匹配", example = "芋道") private String name; + @Schema(description = "部门简称", example = "芋道") + private String shortName; + @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1") private Integer status; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptRespVO.java index ab2e19e9..9b276890 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptRespVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptRespVO.java @@ -15,6 +15,9 @@ public class DeptRespVO { @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") private String name; + @Schema(description = "部门简称", example = "芋道") + private String shortName; + @Schema(description = "父部门 ID", example = "1024") private Long parentId; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptSaveReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptSaveReqVO.java index fbe84023..d3128323 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptSaveReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptSaveReqVO.java @@ -22,6 +22,9 @@ public class DeptSaveReqVO { @Size(max = 30, message = "部门名称长度不能超过 30 个字符") private String name; + @Schema(description = "部门简称", example = "芋道") + private String shortName; + @Schema(description = "父部门 ID", example = "1024") private Long parentId; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptSimpleRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptSimpleRespVO.java index feab10fd..d66af8aa 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptSimpleRespVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptSimpleRespVO.java @@ -17,6 +17,9 @@ public class DeptSimpleRespVO { @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") private String name; + @Schema(description = "部门简称", example = "芋道") + private String shortName; + @Schema(description = "父部门 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private Long parentId; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dept/DeptDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dept/DeptDO.java index 3ad1ce63..46b1d0a7 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dept/DeptDO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dept/DeptDO.java @@ -32,6 +32,10 @@ public class DeptDO extends TenantBaseDO { * 部门名称 */ private String name; + /** + * 简称 + */ + private String shortName; /** * 父部门ID * 关联 {@link #id} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/worklog/LogReadDo.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/worklog/LogReadDo.java index 61a916ea..5b6321cf 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/worklog/LogReadDo.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/worklog/LogReadDo.java @@ -51,9 +51,4 @@ public class LogReadDo extends BaseDO { * 1:已读 */ private Integer readStatus; - - /** - * 是否删除 - */ - private Boolean deleted; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/worklog/LogInstanceMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/worklog/LogInstanceMapper.java index 137bef3c..d7bba160 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/worklog/LogInstanceMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/worklog/LogInstanceMapper.java @@ -62,10 +62,11 @@ public interface LogInstanceMapper extends BaseMapperX { queryWrapper.innerJoin(UserPostDO.class, "userPost", UserPostDO::getUserId, LogInstanceDO::getStartUserId); queryWrapper.innerJoin(DeptDO.class, "dept", DeptDO::getId, LogInstanceDO::getDeptId); queryWrapper.innerJoin(PostDO.class, "post", PostDO::getId, UserPostDO::getPostId); - queryWrapper.leftJoin(LogReadDo.class, "e", on -> on - .eq(LogReadDo::getLogInstanceId, LogInstanceDO::getId) - .eq(LogReadDo::getReadUserId, userId) - .eq(LogReadDo::getDeleted, 0)); +// queryWrapper.leftJoin(LogReadDo.class, "e", on -> on +// .eq(LogReadDo::getLogInstanceId, LogInstanceDO::getId) +// .eq(LogReadDo::getReadUserId, userId) +// .eq(LogReadDo::getDeleted, 0)); + queryWrapper.leftJoin("work_log_read e on e.log_instance_id = t.id and e.deleted = 0 and e.read_user_id = " + userId); queryWrapper.leftJoin("(SELECT log_instance_id, COUNT(log_instance_id) AS readCount FROM work_log_read where read_status = 1 and deleted = 0 GROUP BY log_instance_id) c on t.id = c.log_instance_id"); queryWrapper.leftJoin("(SELECT log_instance_id, COUNT(log_instance_id) AS unReadCount FROM work_log_read where read_status = 0 and deleted = 0 GROUP BY log_instance_id) AS d ON t.id = d.log_instance_id"); queryWrapper.leftJoin("(SELECT work_log_id, COUNT(work_log_id) AS comment FROM work_log_comment GROUP BY work_log_id) AS b ON t.id = b.work_log_id"); From 7e70308c23382ee9fe5d556d7c527bf33192ca2b Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Sun, 13 Oct 2024 21:29:56 +0800 Subject: [PATCH 05/20] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B7=A5=E5=8E=82?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E7=BB=9F=E8=AE=A1=E6=9F=A5=E8=AF=A2=E5=92=8C?= =?UTF-8?q?=E8=AE=A1=E7=AE=97=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 扩展查询条件,增加数据类型筛选 - 优化数据损坏数量的计算逻辑,处理空值情况 - 保证统计服务的准确性和健壮性 --- .../dal/mysql/factorydata/FactoryDataMapper.java | 5 +++-- .../service/factorydata/FactoryDataServiceImpl.java | 8 +++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/zn-module-smartfactory/zn-module-smartfactory-biz/src/main/java/cn/iocoder/yudao/module/smartfactory/dal/mysql/factorydata/FactoryDataMapper.java b/zn-module-smartfactory/zn-module-smartfactory-biz/src/main/java/cn/iocoder/yudao/module/smartfactory/dal/mysql/factorydata/FactoryDataMapper.java index 2cbce43d..a1f68b2f 100644 --- a/zn-module-smartfactory/zn-module-smartfactory-biz/src/main/java/cn/iocoder/yudao/module/smartfactory/dal/mysql/factorydata/FactoryDataMapper.java +++ b/zn-module-smartfactory/zn-module-smartfactory-biz/src/main/java/cn/iocoder/yudao/module/smartfactory/dal/mysql/factorydata/FactoryDataMapper.java @@ -31,11 +31,12 @@ public interface FactoryDataMapper extends BaseMapperX { .eqIfPresent(FactoryDataDO::getDataType, type)); } - default List selectListByFactoryAndDate(Long factoryId, String date) { + default List selectListByFactoryAndDate(Long factoryId, String date, Integer type) { return selectList(new LambdaQueryWrapperX() .eq(FactoryDataDO::getFactoryId, factoryId) - .eq(FactoryDataDO::getDate, date)); + .eq(FactoryDataDO::getDate, date) + .eq(FactoryDataDO::getDataType, type)); } FactoryDataTotalVO selectDataSum(@Param("factoryId") Long factoryId, @Param("date") LocalDate[] date); diff --git a/zn-module-smartfactory/zn-module-smartfactory-biz/src/main/java/cn/iocoder/yudao/module/smartfactory/service/factorydata/FactoryDataServiceImpl.java b/zn-module-smartfactory/zn-module-smartfactory-biz/src/main/java/cn/iocoder/yudao/module/smartfactory/service/factorydata/FactoryDataServiceImpl.java index d53f9342..5667cdc9 100644 --- a/zn-module-smartfactory/zn-module-smartfactory-biz/src/main/java/cn/iocoder/yudao/module/smartfactory/service/factorydata/FactoryDataServiceImpl.java +++ b/zn-module-smartfactory/zn-module-smartfactory-biz/src/main/java/cn/iocoder/yudao/module/smartfactory/service/factorydata/FactoryDataServiceImpl.java @@ -76,7 +76,9 @@ public class FactoryDataServiceImpl implements FactoryDataService { dataSizeService.updateData(updateReqVO); //校验 出入库统计数据是否存在 - List factoryDataDOS = dataMapper.selectListByFactoryAndDate(updateReqVO.getFactoryId(), updateReqVO.getDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); + List factoryDataDOS = dataMapper.selectListByFactoryAndDate(updateReqVO.getFactoryId(), + updateReqVO.getDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")), + updateReqVO.getType()); if (factoryDataDOS != null && !factoryDataDOS.isEmpty()) { // 更新 @@ -87,13 +89,13 @@ public class FactoryDataServiceImpl implements FactoryDataService { //出库数据 case 1: data.setTotalNum(updateReqVO.getItems().stream().mapToInt(FactoryDataSizeSaveReqVO::getOutNum).sum()); - data.setDamageNum(updateReqVO.getItems().stream().mapToInt(FactoryDataSizeSaveReqVO::getOutDamageNum).sum()); + data.setDamageNum(updateReqVO.getItems().stream().mapToInt(date -> Optional.ofNullable(date.getOutDamageNum()).orElse(0)).sum()); break; //入库数据 case 2: data.setTotalNum(updateReqVO.getItems().stream().mapToInt(FactoryDataSizeSaveReqVO::getInNum).sum()); - data.setDamageNum(updateReqVO.getItems().stream().mapToInt(FactoryDataSizeSaveReqVO::getInDamageNum).sum()); + data.setDamageNum(updateReqVO.getItems().stream().mapToInt(date -> Optional.ofNullable(date.getInDamageNum()).orElse(0)).sum()); } }); From 7de24693c364fdec1a9649b1f8b0c46546f73037 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Sun, 13 Oct 2024 21:33:18 +0800 Subject: [PATCH 06/20] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E7=BB=93=E6=9E=84=E5=92=8C=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -移除了多个未使用的导入语句和代码片段 - 调整了部分控制器和服务类的代码组织结构 - 删除了重复或无用的代码行,提高了代码整洁度 - 优化了部分方法的实现,提高了代码效率 --- .../bpm/controller/admin/oa/BpmOAImprestController.java | 4 ---- .../controller/admin/oa/BpmOAReimbursementController.java | 1 - .../yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java | 2 -- .../module/bpm/service/oa/BpmOAReimbursementServiceImpl.java | 5 +---- .../bpm/service/task/BpmProcessInstanceServiceImpl.java | 2 +- .../yudao/module/bpm/service/task/BpmTaskService.java | 1 - .../module/system/dal/mysql/worklog/LogInstanceMapper.java | 2 -- 7 files changed, 2 insertions(+), 15 deletions(-) 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 c7e91a23..332e97cb 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 @@ -3,13 +3,9 @@ package cn.iocoder.yudao.module.bpm.controller.admin.oa; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.imprest.BpmOAImprestCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.imprest.BpmOAImprestRespVO; -import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.Reimbursement; import cn.iocoder.yudao.module.bpm.convert.oa.BpmOAImprestConvert; 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.mysql.oa.BpmOAReimbursementMapper; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAImprestService; -import cn.iocoder.yudao.module.bpm.service.oa.BpmOAReimbursementService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; 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 d49ec5ce..71398575 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 @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.bpm.controller.admin.oa; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 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.BpmOAReimbursementDO; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java index e2f4254e..ce80b2f5 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmTaskExtMapper.java @@ -2,12 +2,10 @@ package cn.iocoder.yudao.module.bpm.dal.mysql.task; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageRespVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; -import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import org.apache.ibatis.annotations.Mapper; 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 4db52665..627b92d1 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 @@ -1,10 +1,8 @@ package cn.iocoder.yudao.module.bpm.service.oa; -import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +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; @@ -15,7 +13,6 @@ 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.controller.admin.oa.vo.reimbursement.Reimbursement; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.ReimbursementDTO; -import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; 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; 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 0422fcf3..b493bc9a 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.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.dal.mysql.task.BpmTaskExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmConstants; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.bpm.service.oa.*; 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.bank.BankApi; 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.HistoricActivityInstance; import org.flowable.engine.history.HistoricActivityInstanceQuery; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; 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 ; @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); } @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); // 创建流程实例 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; } } } @Resource private BpmTaskExtMapper taskExtMapper; @Override public List getUserProcessTpo10(BpmProcessInstanceStatisticsReqVO pageReqVO) { //按审核人分组查询,统计已完成流程数量及平均耗时间 List respVOS = processInstanceExtMapper.getUserProcessTpo10(pageReqVO); if (respVOS == null || respVOS.size() == 0) { return null; } List idList = respVOS.stream() .map(BpmProcessFinishStatisticsRespVO::getUserId) .collect(Collectors.toList()); //根据userId,查询UserMap Map userMap = adminUserApi.getUserMap(idList); Long[] idsArray = new Long[userMap.size()]; // 使用 map 的 keySet() 方法获取键集合 Set keys = userMap.keySet(); // 遍历键集合,将每个键添加到数组中 int index = 0; for (Long key : keys) { idsArray[index++] = key; } pageReqVO.setUserIds(idsArray); //按审核人分组查询,未审批完成的流程数量 List bpmTaskExtDOs = processInstanceExtMapper.selectUnfinishProcessCount(pageReqVO); //按审核人分组查询,未完成的记录数 Map unFinfishCountCountMap = new HashMap<>(); for (BpmProcessFinishStatisticsRespVO item : bpmTaskExtDOs) { unFinfishCountCountMap.put(item.getUserId(), item.getUnFinfishCount()); } respVOS.forEach(respVO -> respVO.setName(userMap.get(respVO.getUserId()).getNickname())); respVOS.forEach(respVO -> respVO.setUnFinfishCount(unFinfishCountCountMap.get(respVO.getUserId()))); //获取排行榜第一记录的耗时,作为基础数据 double num = Double.parseDouble(respVOS.get(0).getUserTime()); // 先将字符串转换为双精度浮点数 int baseNumber = (int) num; // 再通过类型转换操作符将其转换为整数 DecimalFormat df = new DecimalFormat("#.00"); respVOS.forEach(respVO -> { //格式化流程完成率 float finfishCount = (float) respVO.getFinfishCount(); float unFinfishCount = respVO.getUnFinfishCount() == null ? 0 : respVO.getUnFinfishCount(); float all = finfishCount + unFinfishCount; float result = finfishCount / all; float rate = result * 100; respVO.setCompletionRate(df.format(rate) + "%"); double dValue = Double.parseDouble(respVO.getUserTime()); // 将字符串转换为double类型 int roundedValue = (int) Math.round(dValue); // 使用Math.round()进行四舍五入,并转换为int类型 respVO.setUserTime(roundedValue + ""); //格式化进度百度比, 参照最高的数据进行百分比显示 double percentage = ((int) Double.parseDouble(respVO.getUserTime()) / (double) baseNumber) * 100; respVO.setPercentage((int) Math.round(percentage)); //设置未完成 respVO.setUnFinfishCount(Integer.valueOf((int) unFinfishCount)); }); return respVOS; } @Override @DataPermission(enable = false) public BpmProcessInstanceExtDO getProcessInstanceDO(String id) { return processInstanceExtMapper.selectByProcessInstanceId(id); } @Resource private FileApi fileApi; @Resource private BankApi bankApi; @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().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().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.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.dal.mysql.task.BpmTaskExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmConstants; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.bpm.service.oa.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.bank.BankApi; 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 ; @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); } @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); // 创建流程实例 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; } } } @Resource private BpmTaskExtMapper taskExtMapper; @Override public List getUserProcessTpo10(BpmProcessInstanceStatisticsReqVO pageReqVO) { //按审核人分组查询,统计已完成流程数量及平均耗时间 List respVOS = processInstanceExtMapper.getUserProcessTpo10(pageReqVO); if (respVOS == null || respVOS.size() == 0) { return null; } List idList = respVOS.stream() .map(BpmProcessFinishStatisticsRespVO::getUserId) .collect(Collectors.toList()); //根据userId,查询UserMap Map userMap = adminUserApi.getUserMap(idList); Long[] idsArray = new Long[userMap.size()]; // 使用 map 的 keySet() 方法获取键集合 Set keys = userMap.keySet(); // 遍历键集合,将每个键添加到数组中 int index = 0; for (Long key : keys) { idsArray[index++] = key; } pageReqVO.setUserIds(idsArray); //按审核人分组查询,未审批完成的流程数量 List bpmTaskExtDOs = processInstanceExtMapper.selectUnfinishProcessCount(pageReqVO); //按审核人分组查询,未完成的记录数 Map unFinfishCountCountMap = new HashMap<>(); for (BpmProcessFinishStatisticsRespVO item : bpmTaskExtDOs) { unFinfishCountCountMap.put(item.getUserId(), item.getUnFinfishCount()); } respVOS.forEach(respVO -> respVO.setName(userMap.get(respVO.getUserId()).getNickname())); respVOS.forEach(respVO -> respVO.setUnFinfishCount(unFinfishCountCountMap.get(respVO.getUserId()))); //获取排行榜第一记录的耗时,作为基础数据 double num = Double.parseDouble(respVOS.get(0).getUserTime()); // 先将字符串转换为双精度浮点数 int baseNumber = (int) num; // 再通过类型转换操作符将其转换为整数 DecimalFormat df = new DecimalFormat("#.00"); respVOS.forEach(respVO -> { //格式化流程完成率 float finfishCount = (float) respVO.getFinfishCount(); float unFinfishCount = respVO.getUnFinfishCount() == null ? 0 : respVO.getUnFinfishCount(); float all = finfishCount + unFinfishCount; float result = finfishCount / all; float rate = result * 100; respVO.setCompletionRate(df.format(rate) + "%"); double dValue = Double.parseDouble(respVO.getUserTime()); // 将字符串转换为double类型 int roundedValue = (int) Math.round(dValue); // 使用Math.round()进行四舍五入,并转换为int类型 respVO.setUserTime(roundedValue + ""); //格式化进度百度比, 参照最高的数据进行百分比显示 double percentage = ((int) Double.parseDouble(respVO.getUserTime()) / (double) baseNumber) * 100; respVO.setPercentage((int) Math.round(percentage)); //设置未完成 respVO.setUnFinfishCount(Integer.valueOf((int) unFinfishCount)); }); return respVOS; } @Override @DataPermission(enable = false) public BpmProcessInstanceExtDO getProcessInstanceDO(String id) { return processInstanceExtMapper.selectByProcessInstanceId(id); } @Resource private FileApi fileApi; @Resource private BankApi bankApi; @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().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().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 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java index b97155e9..67a6bb5e 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java @@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; -import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import org.flowable.task.api.Task; import org.flowable.task.api.history.HistoricTaskInstance; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/worklog/LogInstanceMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/worklog/LogInstanceMapper.java index d7bba160..ad0801f2 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/worklog/LogInstanceMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/worklog/LogInstanceMapper.java @@ -12,14 +12,12 @@ import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO; import cn.iocoder.yudao.module.system.dal.dataobject.dept.UserPostDO; import cn.iocoder.yudao.module.system.dal.dataobject.worklog.LogInstanceDO; -import cn.iocoder.yudao.module.system.dal.dataobject.worklog.LogReadDo; import cn.iocoder.yudao.module.system.service.worklog.dto.LogReadUserRespDTO; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; -import java.util.Collection; import java.util.List; /** From 5b31190d35f4a3f8689bc92851422dd56e48f8e0 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Tue, 15 Oct 2024 12:29:45 +0800 Subject: [PATCH 07/20] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=B5=81=E7=A8=8B?= =?UTF-8?q?=E5=AE=9E=E4=BE=8B=E5=8F=98=E9=87=8F=E9=85=8D=E7=BD=AE=E5=92=8C?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E5=AE=A1=E6=89=B9=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将流程发起人和审批人的用户信息和部门信息的获取逻辑统一移至 BpmProcessInstanceServiceImpl 类 - 优化了入职、用章、薪资付款、转正等流程的变量配置逻辑,避免重复代码 -简化了任务审批逻辑,移除了不必要的判断条件和冗余代码 - 优化了 BpmTaskEntryLeaderScript 中的部门层级判断逻辑 --- .../oa/vo/entry/BpmOAEntryCreateReqVO.java | 7 +- .../script/impl/BpmTaskEntryLeaderScript.java | 4 +- .../bpm/service/oa/BpmOAEntryServiceImpl.java | 12 ++- .../service/oa/BpmOASalaryServiceImpl.java | 12 ++- .../bpm/service/oa/BpmOASealServiceImpl.java | 12 ++- .../task/BpmProcessInstanceServiceImpl.java | 2 +- .../bpm/service/task/BpmTaskServiceImpl.java | 102 ++++-------------- 7 files changed, 62 insertions(+), 89 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/entry/BpmOAEntryCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/entry/BpmOAEntryCreateReqVO.java index 9f483f5f..d1bcf325 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/entry/BpmOAEntryCreateReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/entry/BpmOAEntryCreateReqVO.java @@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.entry; import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import cn.iocoder.yudao.framework.common.validation.IdCard; +import cn.iocoder.yudao.framework.common.validation.Mobile; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; @@ -39,9 +41,12 @@ public class BpmOAEntryCreateReqVO { @Schema(description = "手机号码", requiredMode = Schema.RequiredMode.REQUIRED) @NotEmpty(message = "手机号码不能为空") + @Mobile(message = "手机号码格式不正确") private String mobile; @Schema(description = "身份证号码") + @NotNull(message = "身份证号码不能为空") + @IdCard(message = "身份证号码格式不正确") private String idcard; @Schema(description = "入职时间", requiredMode = Schema.RequiredMode.REQUIRED) @@ -50,7 +55,7 @@ public class BpmOAEntryCreateReqVO { private LocalDate entryDate; @Schema(description = "面试评价", requiredMode = Schema.RequiredMode.REQUIRED) - @NotEmpty(message = "面试评价不能为空") + @NotNull(message = "面试评价不能为空") private String interviewEvaluation; @Schema(description = "薪资情况", example = "27005") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskEntryLeaderScript.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskEntryLeaderScript.java index 65dd6a4b..7718cac3 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskEntryLeaderScript.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskEntryLeaderScript.java @@ -55,8 +55,8 @@ public class BpmTaskEntryLeaderScript implements BpmTaskAssignScript { DeptRespDTO dept = deptApi.getDept(deptId).getCheckedData(); if (dept.getLevel() > 3) { //判断部门层级 - String [] flag = dept.getFlag().split("-"); - dept = deptApi.getDept(Long.valueOf(flag[3])).getCheckedData(); + String[] flag = dept.getFlag().split("-"); + dept = deptApi.getDept(Long.valueOf(flag[2])).getCheckedData(); } 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/oa/BpmOAEntryServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAEntryServiceImpl.java index 95495316..8c559a3e 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAEntryServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAEntryServiceImpl.java @@ -16,6 +16,8 @@ import cn.iocoder.yudao.module.bpm.service.task.BpmHistoryProcessInstanceService import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; import cn.iocoder.yudao.module.infra.api.file.FileApi; import cn.iocoder.yudao.module.infra.api.file.dto.UserFileUpdateReqDTO; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.UserSaveRespDTO; import org.flowable.engine.runtime.ProcessInstance; @@ -69,6 +71,9 @@ public class BpmOAEntryServiceImpl implements BpmOAEntryService{ @Resource private BpmHistoryProcessInstanceService historyProcessInstanceService; + @Resource + private DeptApi deptApi; + @Override @Transactional(rollbackFor = Exception.class) public Long createEntry(BpmOAEntryCreateReqVO createReqVO) { @@ -79,8 +84,13 @@ public class BpmOAEntryServiceImpl implements BpmOAEntryService{ .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); entryMapper.insert(entry) ; - // 发起 BPM 流程 + // 获取入职部门信息 + DeptRespDTO dto = deptApi.getDept(entry.getEntryDeptId()).getCheckedData(); + Map processInstanceVariables = new HashMap<>(); + //配置入职部门flag + processInstanceVariables.put("entry_dept_flag", dto.getFlag()); + // 发起 BPM 流程 String processInstanceId = processInstanceApi.createProcessInstance(entry.getUserId(), new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(PROCESS_KEY) .setVariables(processInstanceVariables).setBusinessKey(String.valueOf(entry.getId()))).getCheckedData(); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOASalaryServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOASalaryServiceImpl.java index b01cdda3..d38ba577 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOASalaryServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOASalaryServiceImpl.java @@ -9,6 +9,8 @@ import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOASalaryDO; import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOaSalaryMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.service.task.BpmHistoryProcessInstanceService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -43,6 +45,9 @@ public class BpmOASalaryServiceImpl extends BpmOABaseService implements BpmOASal @Resource private BpmHistoryProcessInstanceService historyProcessInstanceService; + @Resource + private DeptApi deptApi; + @Override public Long createSalary(Long userId, BpmOASalaryCreateReqVO createReqVO) { @@ -51,8 +56,13 @@ public class BpmOASalaryServiceImpl extends BpmOABaseService implements BpmOASal .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); salaryMapper.insert(salary) ; - // 发起 BPM 流程 + // 获取申请公司或工厂信息 + DeptRespDTO dto = deptApi.getDept(salary.getCompanyDeptId()).getCheckedData(); + + // 配置申请公司或工厂部门flag Map processInstanceVariables = new HashMap<>(); + processInstanceVariables.put("company_dept_flag", dto.getFlag()); + // 发起 BPM 流程 String processInstanceId = processInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(PROCESS_KEY) .setVariables(processInstanceVariables).setBusinessKey(String.valueOf(salary.getId()))).getCheckedData(); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOASealServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOASealServiceImpl.java index e3252e17..a2017cfc 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOASealServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOASealServiceImpl.java @@ -9,6 +9,8 @@ import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOASealDO; import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOASealMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.service.task.BpmHistoryProcessInstanceService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -44,6 +46,9 @@ public class BpmOASealServiceImpl extends BpmOABaseService implements BpmOASealS @Resource private BpmHistoryProcessInstanceService historyProcessInstanceService; + @Resource + private DeptApi deptApi; + @Override public Long createSeal(Long userId, BpmOASealCreateReqVO createReqVO) { @@ -52,8 +57,13 @@ public class BpmOASealServiceImpl extends BpmOABaseService implements BpmOASealS .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); sealMapper.insert(seal) ; - // 发起 BPM 流程 + // 获取用章公司的部门信息 + DeptRespDTO dto = deptApi.getDept(seal.getContractCompany()).getCheckedData(); + + //配置合同公司flag Map processInstanceVariables = new HashMap<>(); + processInstanceVariables.put("contract_company_flag", dto.getFlag()); + // 发起 BPM 流程 String processInstanceId = processInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(PROCESS_KEY) .setVariables(processInstanceVariables).setBusinessKey(String.valueOf(seal.getId()))).getCheckedData(); 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 b493bc9a..3a6fc90f 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.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.dal.mysql.task.BpmTaskExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmConstants; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.bpm.service.oa.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.bank.BankApi; 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 ; @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); } @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); // 创建流程实例 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; } } } @Resource private BpmTaskExtMapper taskExtMapper; @Override public List getUserProcessTpo10(BpmProcessInstanceStatisticsReqVO pageReqVO) { //按审核人分组查询,统计已完成流程数量及平均耗时间 List respVOS = processInstanceExtMapper.getUserProcessTpo10(pageReqVO); if (respVOS == null || respVOS.size() == 0) { return null; } List idList = respVOS.stream() .map(BpmProcessFinishStatisticsRespVO::getUserId) .collect(Collectors.toList()); //根据userId,查询UserMap Map userMap = adminUserApi.getUserMap(idList); Long[] idsArray = new Long[userMap.size()]; // 使用 map 的 keySet() 方法获取键集合 Set keys = userMap.keySet(); // 遍历键集合,将每个键添加到数组中 int index = 0; for (Long key : keys) { idsArray[index++] = key; } pageReqVO.setUserIds(idsArray); //按审核人分组查询,未审批完成的流程数量 List bpmTaskExtDOs = processInstanceExtMapper.selectUnfinishProcessCount(pageReqVO); //按审核人分组查询,未完成的记录数 Map unFinfishCountCountMap = new HashMap<>(); for (BpmProcessFinishStatisticsRespVO item : bpmTaskExtDOs) { unFinfishCountCountMap.put(item.getUserId(), item.getUnFinfishCount()); } respVOS.forEach(respVO -> respVO.setName(userMap.get(respVO.getUserId()).getNickname())); respVOS.forEach(respVO -> respVO.setUnFinfishCount(unFinfishCountCountMap.get(respVO.getUserId()))); //获取排行榜第一记录的耗时,作为基础数据 double num = Double.parseDouble(respVOS.get(0).getUserTime()); // 先将字符串转换为双精度浮点数 int baseNumber = (int) num; // 再通过类型转换操作符将其转换为整数 DecimalFormat df = new DecimalFormat("#.00"); respVOS.forEach(respVO -> { //格式化流程完成率 float finfishCount = (float) respVO.getFinfishCount(); float unFinfishCount = respVO.getUnFinfishCount() == null ? 0 : respVO.getUnFinfishCount(); float all = finfishCount + unFinfishCount; float result = finfishCount / all; float rate = result * 100; respVO.setCompletionRate(df.format(rate) + "%"); double dValue = Double.parseDouble(respVO.getUserTime()); // 将字符串转换为double类型 int roundedValue = (int) Math.round(dValue); // 使用Math.round()进行四舍五入,并转换为int类型 respVO.setUserTime(roundedValue + ""); //格式化进度百度比, 参照最高的数据进行百分比显示 double percentage = ((int) Double.parseDouble(respVO.getUserTime()) / (double) baseNumber) * 100; respVO.setPercentage((int) Math.round(percentage)); //设置未完成 respVO.setUnFinfishCount(Integer.valueOf((int) unFinfishCount)); }); return respVOS; } @Override @DataPermission(enable = false) public BpmProcessInstanceExtDO getProcessInstanceDO(String id) { return processInstanceExtMapper.selectByProcessInstanceId(id); } @Resource private FileApi fileApi; @Resource private BankApi bankApi; @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().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().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.mybatis.core.query.LambdaQueryWrapperX; 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.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.dal.mysql.task.BpmTaskExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmConstants; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.bpm.service.oa.*; 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.bank.BankApi; 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 com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; 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.*; 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 ; @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); } @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; } } } @Resource private BpmTaskExtMapper taskExtMapper; @Override public List getUserProcessTpo10(BpmProcessInstanceStatisticsReqVO pageReqVO) { //按审核人分组查询,统计已完成流程数量及平均耗时间 List respVOS = processInstanceExtMapper.getUserProcessTpo10(pageReqVO); if (respVOS == null || respVOS.size() == 0) { return null; } List idList = respVOS.stream() .map(BpmProcessFinishStatisticsRespVO::getUserId) .collect(Collectors.toList()); //根据userId,查询UserMap Map userMap = adminUserApi.getUserMap(idList); Long[] idsArray = new Long[userMap.size()]; // 使用 map 的 keySet() 方法获取键集合 Set keys = userMap.keySet(); // 遍历键集合,将每个键添加到数组中 int index = 0; for (Long key : keys) { idsArray[index++] = key; } pageReqVO.setUserIds(idsArray); //按审核人分组查询,未审批完成的流程数量 List bpmTaskExtDOs = processInstanceExtMapper.selectUnfinishProcessCount(pageReqVO); //按审核人分组查询,未完成的记录数 Map unFinfishCountCountMap = new HashMap<>(); for (BpmProcessFinishStatisticsRespVO item : bpmTaskExtDOs) { unFinfishCountCountMap.put(item.getUserId(), item.getUnFinfishCount()); } respVOS.forEach(respVO -> respVO.setName(userMap.get(respVO.getUserId()).getNickname())); respVOS.forEach(respVO -> respVO.setUnFinfishCount(unFinfishCountCountMap.get(respVO.getUserId()))); //获取排行榜第一记录的耗时,作为基础数据 double num = Double.parseDouble(respVOS.get(0).getUserTime()); // 先将字符串转换为双精度浮点数 int baseNumber = (int) num; // 再通过类型转换操作符将其转换为整数 DecimalFormat df = new DecimalFormat("#.00"); respVOS.forEach(respVO -> { //格式化流程完成率 float finfishCount = (float) respVO.getFinfishCount(); float unFinfishCount = respVO.getUnFinfishCount() == null ? 0 : respVO.getUnFinfishCount(); float all = finfishCount + unFinfishCount; float result = finfishCount / all; float rate = result * 100; respVO.setCompletionRate(df.format(rate) + "%"); double dValue = Double.parseDouble(respVO.getUserTime()); // 将字符串转换为double类型 int roundedValue = (int) Math.round(dValue); // 使用Math.round()进行四舍五入,并转换为int类型 respVO.setUserTime(roundedValue + ""); //格式化进度百度比, 参照最高的数据进行百分比显示 double percentage = ((int) Double.parseDouble(respVO.getUserTime()) / (double) baseNumber) * 100; respVO.setPercentage((int) Math.round(percentage)); //设置未完成 respVO.setUnFinfishCount(Integer.valueOf((int) unFinfishCount)); }); return respVOS; } @Override @DataPermission(enable = false) public BpmProcessInstanceExtDO getProcessInstanceDO(String id) { return processInstanceExtMapper.selectByProcessInstanceId(id); } @Resource private FileApi fileApi; @Resource private BankApi bankApi; @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().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().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 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index f12fc078..08c8dfc6 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ObjectUtil; @@ -494,105 +495,42 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 情况三:自己审批的任务,调用 complete 去完成任务 // 完成任务,审批通过,并设置paramMap的post_id值 // paramMap 中的值,可用于流程图中分支路线条件 - /** + /* * 判定流程的走向,这里是流程审核节点(就是流程设计中的任意审核节点) * 根据当前审核人的岗位判定流程走向 */ - Map paramMap = instance.getProcessVariables(); + Map paramMap = processInstanceExtMapper.selectOne(BpmProcessInstanceExtDO::getProcessInstanceId, instance.getProcessInstanceId()).getFormVariables(); -// // 获得 User -// AdminUserRespDTO examineUser = adminUserApi.getUser(userId).getCheckedData(); + // 获得审批人User + AdminUserRespDTO examineUser = adminUserApi.getUser(userId).getCheckedData(); + //获取流程审批人部门信息 + DeptRespDTO examineDept = deptApi.getDept(examineUser.getDeptId()).getCheckedData(); -// // 获取部门信息 -// Long deptId = examineUser.getDeptId(); - - //获取流程发起人User - AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(instance.getStartUserId())).getCheckedData(); - //获取流程发起人部门信息 - DeptRespDTO startDeptInfo = deptApi.getDept(startUser.getDeptId()).getCheckedData(); - // 获取岗位信息 - Set postIds = startUser.getPostIds(); + if (CollectionUtil.isEmpty(examineUser.getPostIds())) { + // 当前审批用户未配置岗位 + // 操作失败,原因:您未配置岗位,请联系管理员操作 + throw exception(TASK_OPERATE_FAIL_USER_NO_POST); + } + if( examineUser.getDeptId() == null ) { + // 当前审批用户未配置部门 + // 操作失败,原因:您未配置部门,请联系管理员操作 + throw exception(TASK_OPERATE_FAIL_USER_NO_DEPT); + } //根据审批人用户ID,获取审批人 担任的负责人的部门信息 List deptRespDTOs = deptApi.getDeptByLeaderId(userId).getCheckedData(); + // 设置审批人所在部门的负责人 + paramMap.put("leader_id", examineDept.getLeaderUserId().toString()); //遍历查找, 发起人的上级部门 for (DeptRespDTO deptRespDTO : deptRespDTOs) { - if (startDeptInfo.getFlag().contains(deptRespDTO.getFlag())) { + if (paramMap.get("dept_flag").toString().contains(deptRespDTO.getFlag())) { paramMap.put("level", deptRespDTO.getLevel().toString()); break; } } - //如果审核人是发起人的时候 - if (userId.toString().equals(instance.getStartUserId())) { - //获取发起人部门负责人编号和部门层级 - paramMap.put("leader_id", startDeptInfo.getLeaderUserId().toString()); - paramMap.put("level", startDeptInfo.getLevel().toString()); - } - - if (postIds == null || postIds.isEmpty()) { - // 当前审批用户未配置岗位 - // 操作失败,原因:您未配置岗位,请联系管理员操作 - throw exception(TASK_OPERATE_FAIL_USER_NO_POST); - } -// if( deptId == null ) { -// // 当前审批用户未配置部门 -// // 操作失败,原因:您未配置部门,请联系管理员操作 -// throw exception(TASK_OPERATE_FAIL_USER_NO_DEPT); -// } - - // 判断 入职申请流程时 - if (instance.getProcessDefinitionId().contains("oa_entry")) { - - BpmOAEntryDO entryDO = bpmOAEntryService.getEntryByProcessInstanceId(instance.getProcessInstanceId()); - if (entryDO != null) { - - DeptRespDTO dto = deptApi.getDept(entryDO.getEntryDeptId()).getCheckedData(); - paramMap.put("entry_dept_flag", dto.getFlag()); //配置入职部门flag - } - } - - // 判断 用章流程时 - if (instance.getProcessDefinitionId().contains("oa_seal")) { - - BpmOASealDO sealDO = bpmOASealService.getByProcessInstanceId(instance.getProcessInstanceId()); - if (sealDO != null) { - - DeptRespDTO dto = deptApi.getDept(sealDO.getContractCompany()).getCheckedData(); - paramMap.put("contract_company_flag", dto.getFlag()); //配置合同公司flag - } - } - - // 判断 薪资付款流程时 - if (instance.getProcessDefinitionId().contains("oa_salary")) { - BpmOASalaryDO salaryDO = bpmOASalaryService.getByProcessInstanceId(instance.getProcessInstanceId()); - if (salaryDO != null) { - - DeptRespDTO dto = deptApi.getDept(salaryDO.getCompanyDeptId()).getCheckedData(); - paramMap.put("company_dept_flag", dto.getFlag()); //配置工厂idflag - } - } - - // 判断 转正流程时 - if (instance.getProcessDefinitionId().contains("oa_regular")) { - BpmOARegularDO regularDO = bpmOARegularService.getByProcessInstanceId(instance.getProcessInstanceId()); - if (regularDO != null) { - - DeptRespDTO dto = deptApi.getDept(regularDO.getDeptId()).getCheckedData(); - paramMap.put("regular_dept_flag", dto.getFlag()); //配置工厂idflag - } - } - - ArrayList list = new ArrayList<>(postIds); - // 只获配置的首个岗位 - Long postId = list.get(0); - paramMap.put("post_id", postId.toString()); - paramMap.put("user_id", userId.toString()); - paramMap.put("dept_id", startUser.getDeptId().toString()); //配置发起人部门id - paramMap.put("dept_flag", startDeptInfo.getFlag()); //配置发起人部门flag - paramMap.put("approve_reason", reqVO.getReason()); //通过原因---因为Task任务的通过,是通过监听事件处理的,reason数据无法传递给监听函数。所以通过此中方法传递 taskService.complete(task.getId(), paramMap); // 更新任务拓展表为通过 From 40819c8d6f9ef43a499c3f78b04b3621cfc9a1b6 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Tue, 15 Oct 2024 16:34:39 +0800 Subject: [PATCH 08/20] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=B5=81=E7=A8=8B?= =?UTF-8?q?=E5=AE=9E=E4=BE=8B=E5=8F=98=E9=87=8F=E8=8E=B7=E5=8F=96=E6=96=B9?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 selectFormVariables 方法,直接获取流程实例变量 - 修改 getProcessInstanceExtDO 方法中的变量获取逻辑 - 优化代码结构,提高可维护性 --- .../mysql/task/BpmProcessInstanceExtMapper.java | 7 +++++++ .../bpm/service/task/BpmTaskServiceImpl.java | 7 +++++-- .../task/dto/ProcessInstanceVariablesDTO.java | 15 +++++++++++++++ .../mapper/task/BpmProcessInstanceExtMapper.xml | 7 +++++++ 4 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/dto/ProcessInstanceVariablesDTO.java diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmProcessInstanceExtMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmProcessInstanceExtMapper.java index bd1b3a53..e8c4b00d 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmProcessInstanceExtMapper.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmProcessInstanceExtMapper.java @@ -4,14 +4,18 @@ 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.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; +import cn.iocoder.yudao.module.bpm.service.task.dto.ProcessInstanceVariablesDTO; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; import java.util.Arrays; import java.util.List; +import java.util.Map; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; @@ -113,4 +117,7 @@ public interface BpmProcessInstanceExtMapper extends BaseMapperX getProcessInstanceResultStatusStatisticsGroupTime(BpmProcessInstanceStatisticsReqVO pageReqVO); + + @TenantIgnore + List selectFormVariables(@Param("processInstanceId") String processInstanceId); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index 08c8dfc6..3207f91e 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -33,6 +33,7 @@ import cn.iocoder.yudao.module.bpm.service.oa.BpmOAEntryService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOARegularService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOASalaryService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOASealService; +import cn.iocoder.yudao.module.bpm.service.task.dto.ProcessInstanceVariablesDTO; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; @@ -499,7 +500,8 @@ public class BpmTaskServiceImpl implements BpmTaskService { * 判定流程的走向,这里是流程审核节点(就是流程设计中的任意审核节点) * 根据当前审核人的岗位判定流程走向 */ - Map paramMap = processInstanceExtMapper.selectOne(BpmProcessInstanceExtDO::getProcessInstanceId, instance.getProcessInstanceId()).getFormVariables(); + List variables = processInstanceExtMapper.selectFormVariables(instance.getProcessInstanceId()); + Map paramMap = variables.stream().collect(Collectors.toMap(ProcessInstanceVariablesDTO::getName, ProcessInstanceVariablesDTO::getValue)); // 获得审批人User AdminUserRespDTO examineUser = adminUserApi.getUser(userId).getCheckedData(); @@ -520,8 +522,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { //根据审批人用户ID,获取审批人 担任的负责人的部门信息 List deptRespDTOs = deptApi.getDeptByLeaderId(userId).getCheckedData(); - // 设置审批人所在部门的负责人 + // 设置审批人所在部门的负责人和部门层级 paramMap.put("leader_id", examineDept.getLeaderUserId().toString()); + paramMap.put("level", examineDept.getLevel().toString()); //遍历查找, 发起人的上级部门 for (DeptRespDTO deptRespDTO : deptRespDTOs) { if (paramMap.get("dept_flag").toString().contains(deptRespDTO.getFlag())) { diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/dto/ProcessInstanceVariablesDTO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/dto/ProcessInstanceVariablesDTO.java new file mode 100644 index 00000000..e1dad337 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/dto/ProcessInstanceVariablesDTO.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.bpm.service.task.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "流程Variables Request VO") +@Data +public class ProcessInstanceVariablesDTO { + + @Schema(description = "流程变量的key") + private String name; + + @Schema(description = "流程变量的值") + private String value; +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/task/BpmProcessInstanceExtMapper.xml b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/task/BpmProcessInstanceExtMapper.xml index 95b4ddf7..f260a1c1 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/task/BpmProcessInstanceExtMapper.xml +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/task/BpmProcessInstanceExtMapper.xml @@ -106,5 +106,12 @@ GROUP BY name,DATE_FORMAT( create_time, '%Y-%m-%d' ); + From ca9b6b6d28bb77df8e0fd1f55515bc132d689fed Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Tue, 15 Oct 2024 19:32:55 +0800 Subject: [PATCH 09/20] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=96=AA=E9=85=AC?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E4=BB=BB=E5=8A=A1=E5=88=86=E9=85=8D=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=E5=92=8C=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 - 新增 BpmTaskSalaryLeaderScript 类,用于处理薪酬调整任务的分配 - 在 BpmTaskRuleScriptEnum 枚举中添加 LEADER_X8项 - 修改 BpmOASalaryAdjustmentServiceImpl 以支持薪酬调整流程 - 更新 BpmTaskEntryLeaderScript 以修复部门层级判断逻辑 --- .../definition/BpmTaskRuleScriptEnum.java | 3 +- .../script/impl/BpmTaskEntryLeaderScript.java | 8 +- .../impl/BpmTaskSalaryLeaderScript.java | 75 +++++++++++++++++++ .../oa/BpmOASalaryAdjustmentServiceImpl.java | 36 ++++++++- 4 files changed, 115 insertions(+), 7 deletions(-) create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskSalaryLeaderScript.java 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 694023d9..da61c5f9 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 @@ -21,7 +21,8 @@ public enum BpmTaskRuleScriptEnum { LEADER_X4(23L, "审批人的一级领导"), LEADER_X5(24L, "调岗部门领导"), LEADER_X6(25L, "分配任务的责任人"), - LEADER_X7(26L, "入职部门领导"); + LEADER_X7(26L, "入职部门领导"), + LEADER_X8(27L, "调薪部门领导"); /** * 脚本编号 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskEntryLeaderScript.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskEntryLeaderScript.java index 7718cac3..1e0ef6ec 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskEntryLeaderScript.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskEntryLeaderScript.java @@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.List; @@ -21,11 +22,14 @@ import java.util.Set; import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; import static java.util.Collections.emptySet; +@Component public class BpmTaskEntryLeaderScript implements BpmTaskAssignScript { @Resource + @Lazy // 解决循环依赖 private DeptApi deptApi; @Resource + @Lazy // 解决循环依赖 private BpmOAEntryService entryService; @Resource @@ -47,7 +51,7 @@ public class BpmTaskEntryLeaderScript implements BpmTaskAssignScript { } //根据流程实例ID 取到调岗流程表单 - BpmOAEntryDO entryDO = entryService.getEntryByProcessInstanceId(processInstance.getProcessInstanceId()); + BpmOAEntryDO entryDO = entryService.getEntry(Long.valueOf(processInstance.getBusinessKey())); //获取调岗部门ID Long deptId = entryDO.getEntryDeptId(); @@ -56,7 +60,7 @@ public class BpmTaskEntryLeaderScript implements BpmTaskAssignScript { if (dept.getLevel() > 3) { //判断部门层级 String[] flag = dept.getFlag().split("-"); - dept = deptApi.getDept(Long.valueOf(flag[2])).getCheckedData(); + dept = deptApi.getDept(Long.valueOf(flag[3])).getCheckedData(); } 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/framework/flowable/core/behavior/script/impl/BpmTaskSalaryLeaderScript.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskSalaryLeaderScript.java new file mode 100644 index 00000000..566d51f2 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskSalaryLeaderScript.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOASalaryAdjustmentDO; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; +import cn.iocoder.yudao.module.bpm.service.oa.BpmOASalaryAdjustmentService; +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.runtime.ProcessInstance; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static java.util.Collections.emptySet; + +@Component +public class BpmTaskSalaryLeaderScript implements BpmTaskAssignScript { + + @Resource + private DeptApi deptApi; + @Resource + @Lazy // 解决循环依赖 + private BpmOASalaryAdjustmentService salaryAdjustmentService; + + @Resource + @Lazy // 解决循环依赖 + private BpmProcessInstanceService bpmProcessInstanceService; + + @Resource + @Lazy // 解决循环依赖 + private BpmTaskService bpmTaskService ; + + @Override + public Set calculateTaskCandidateUsers(DelegateExecution execution) { + + // 获得发起人 + ProcessInstance processInstance = bpmProcessInstanceService.getProcessInstance(execution.getProcessInstanceId()); + List bpmTaskRespVOs = bpmTaskService.getTaskListByProcessInstanceId(processInstance.getProcessInstanceId()); + if (CollUtil.isEmpty(bpmTaskRespVOs)) { + return emptySet(); + } + + //根据流程实例ID 取到调岗流程表单 + BpmOASalaryAdjustmentDO salaryAdjustmentDO = salaryAdjustmentService.getSalaryAdjustment(Long.valueOf(processInstance.getBusinessKey())); + //获取调岗部门ID + Long deptId = salaryAdjustmentDO.getAdjustmentDeptId(); + + //根据部门ID 获取部门信息 + DeptRespDTO dept = deptApi.getDept(deptId).getCheckedData(); + // 调整人为部门负责人时 + if (dept.getLeaderUserId().equals(salaryAdjustmentDO.getAdjustmentUserId())) { + dept = deptApi.getDept(dept.getParentId()).getCheckedData(); + }else if (dept.getLevel() > 3) { //判断部门层级 + + String[] flag = dept.getFlag().split("-"); + dept = deptApi.getDept(Long.valueOf(flag[3])).getCheckedData(); + } + + return dept.getLeaderUserId() != null ? asSet(dept.getLeaderUserId()) : emptySet(); + } + + @Override + public BpmTaskRuleScriptEnum getEnum() { + return BpmTaskRuleScriptEnum.LEADER_X8; + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOASalaryAdjustmentServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOASalaryAdjustmentServiceImpl.java index 14dc2db0..31447f06 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOASalaryAdjustmentServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOASalaryAdjustmentServiceImpl.java @@ -9,6 +9,11 @@ import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOASalaryAdjustmentDO; import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOASalaryAdjustmentMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.service.task.BpmHistoryProcessInstanceService; +import cn.iocoder.yudao.module.infra.api.config.ConfigApi; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import io.netty.util.internal.StringUtil; +import org.mapstruct.ap.internal.util.Strings; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -21,7 +26,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_SALARY_NOT_EXISTS; /** - * OA 薪资付款申请 Service 实现类 + * OA 薪资调整申请 Service 实现类 * * @author 符溶馨 */ @@ -30,7 +35,7 @@ import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_SALARY_NOT public class BpmOASalaryAdjustmentServiceImpl extends BpmOABaseService implements BpmOASalaryAdjustmentService{ /** - * OA 薪资付款对应的流程定义 KEY + * OA 薪资调整对应的流程定义 KEY */ public static final String PROCESS_KEY = "oa_salary_adjustment_2"; @@ -43,16 +48,39 @@ public class BpmOASalaryAdjustmentServiceImpl extends BpmOABaseService implement @Resource private BpmHistoryProcessInstanceService historyProcessInstanceService; + @Resource + private DeptApi deptApi; + + @Resource + private ConfigApi configApi; + @Override public Long createSalaryAdjustment(Long userId, BpmOASalaryAdjustmentCreateReqVO createReqVO) { - //插入OA 薪资付款申请 + //插入OA 薪资调整申请 BpmOASalaryAdjustmentDO salary = BpmOASalaryAdjustmentConvert.INSTANCE.convert(createReqVO).setUserId(userId) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); salaryMapper.insert(salary) ; - // 发起 BPM 流程 + // 获取调整人所在部门信息 + DeptRespDTO deptRespDTO = deptApi.getDept(createReqVO.getAdjustmentDeptId()).getCheckedData(); + + // 配置变量 调整人部门flag Map processInstanceVariables = new HashMap<>(); + processInstanceVariables.put("company_dept_flag", deptRespDTO.getFlag()); + + if (deptRespDTO.getLevel() == 2 && deptRespDTO.getLeaderUserId().equals(createReqVO.getAdjustmentUserId())) { + processInstanceVariables.put("is_leader", 1); + }else { + processInstanceVariables.put("is_leader", 0); + } + + // 查询配置文件,获取行政部门编号 + String hrDeptId = configApi.getConfigKey("system_hr_dept").getCheckedData(); + if (Strings.isNotEmpty(hrDeptId)) { + processInstanceVariables.put("hr_dept", hrDeptId); + } + // 发起 BPM 流程 String processInstanceId = processInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(PROCESS_KEY) .setVariables(processInstanceVariables).setBusinessKey(String.valueOf(salary.getId()))).getCheckedData(); From 88853cbb3794bca18ed9a300b2918cfbdb8ec88c Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Wed, 16 Oct 2024 19:52:39 +0800 Subject: [PATCH 10/20] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=B7=A5=E8=B5=84?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E7=AE=A1=E7=90=86=E5=92=8C=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加工资类型和配置的数据模型、数据库表以及相关服务接口 - 实现工资类型创建、更新、查询等基础功能 - 为后续人事管理中的工资计算提供基础 --- .../system/enums/ErrorCodeConstants.java | 5 +- .../admin/hr/SalaryTypeController.java | 67 ++++++++++++++++ .../admin/hr/SalaryTypeItemController.java | 35 +++++++++ .../hr/vo/type/SalaryTypeItemCreateReqVO.java | 30 ++++++++ .../hr/vo/type/SalaryTypeItemRespVO.java | 30 ++++++++ .../admin/hr/vo/type/SalaryTypeRespVO.java | 18 +++++ .../dal/dataobject/hr/SalaryTypeDO.java | 31 ++++++++ .../dal/dataobject/hr/SalaryTypeItemDO.java | 52 +++++++++++++ .../dal/mysql/hr/SalaryTypeItemMapper.java | 9 +++ .../system/dal/mysql/hr/SalaryTypeMapper.java | 9 +++ .../service/hr/SalaryTypeItemService.java | 21 +++++ .../service/hr/SalaryTypeItemServiceImpl.java | 13 ++++ .../system/service/hr/SalaryTypeService.java | 47 +++++++++++ .../service/hr/SalaryTypeServiceImpl.java | 77 +++++++++++++++++++ 14 files changed, 443 insertions(+), 1 deletion(-) create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/SalaryTypeController.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/SalaryTypeItemController.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeItemCreateReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeItemRespVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeRespVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/hr/SalaryTypeDO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/hr/SalaryTypeItemDO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/hr/SalaryTypeItemMapper.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/hr/SalaryTypeMapper.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeItemService.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeItemServiceImpl.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeService.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeServiceImpl.java diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java index 886f2f76..3004218d 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java @@ -259,6 +259,9 @@ public interface ErrorCodeConstants { ErrorCode DEVICE_NO_EXISTS = new ErrorCode(1_011_002_004, "设备号已存在!"); - // ========== 劳动合同相关 1-012-001-001 ========== + // ========== 人事管理相关 1-012-001-001 ========== ErrorCode LABOR_CONTRACT_NOT_EXISTS = new ErrorCode(1_012_001_001, "劳动合同管理不存在"); + ErrorCode SALARY_TYPE_NAME_EXISTS = new ErrorCode(1_012_002_001, "类型名称重复!"); + ErrorCode SALARY_TYPE_NOT_EXISTS = new ErrorCode(1_012_002_001, "工资类型不存在"); + } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/SalaryTypeController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/SalaryTypeController.java new file mode 100644 index 00000000..78ceb0cb --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/SalaryTypeController.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.system.controller.admin.hr; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.hr.vo.type.SalaryTypeRespVO; +import cn.iocoder.yudao.module.system.service.hr.SalaryTypeService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 工资类型") +@RestController +@RequestMapping("/system/hr/salary-type") +public class SalaryTypeController { + + @Resource + private SalaryTypeService salaryTypeService; + + @PostMapping("/create") + @Operation(summary = "创建工资类型") + @PreAuthorize("@ss.hasPermission('system:hr:salary-type:create')") + public CommonResult createSalaryType(@RequestParam("name") String name) { + return success(salaryTypeService.createSalaryType(name)); + } + + @PutMapping("/update") + @Operation(summary = "更新工资类型") + @PreAuthorize("@ss.hasPermission('system:hr:salary-type:update')") + public CommonResult updateLogInstance(@RequestParam("id") Long id, + @RequestParam("name") String name) { + salaryTypeService.updateSalaryType(id, name); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新工资类型状态") + @PreAuthorize("@ss.hasPermission('system:hr:salary-type:update')") + public CommonResult updateLogInstance(@RequestParam("id") Long id, + @RequestParam("status") Integer status) { + salaryTypeService.updateSalaryTypeStatus(id, status); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得工资类型") + @Parameter(name = "id", description = "编号", required = true, example = "1") + @PreAuthorize("@ss.hasPermission('system:hr:salary-type:query')") + public CommonResult getSalaryType(@RequestParam("id") Long id) { + + return success(BeanUtils.toBean(salaryTypeService.getSalaryType(id), SalaryTypeRespVO.class)); + } + + @GetMapping("/list") + @Operation(summary = "获得工资类型列表") + @PreAuthorize("@ss.hasPermission('system:hr:salary-type:query')") + public CommonResult> getSalaryTypeList() { + + return success(BeanUtils.toBean(salaryTypeService.getSalaryTypeList(), SalaryTypeRespVO.class)); + } +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/SalaryTypeItemController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/SalaryTypeItemController.java new file mode 100644 index 00000000..a3ba247f --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/SalaryTypeItemController.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.system.controller.admin.hr; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.hr.vo.type.SalaryTypeItemCreateReqVO; +import cn.iocoder.yudao.module.system.controller.admin.hr.vo.type.SalaryTypeRespVO; +import cn.iocoder.yudao.module.system.service.hr.SalaryTypeItemService; +import cn.iocoder.yudao.module.system.service.hr.SalaryTypeService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 工资类型") +@RestController +@RequestMapping("/system/hr/salary-type-item") +public class SalaryTypeItemController { + + @Resource + private SalaryTypeItemService salaryTypeItemService; + + @PostMapping("/create") + @Operation(summary = "创建工资类型配置") + @PreAuthorize("@ss.hasPermission('system:hr:salary-type-item:create')") + public CommonResult createSalaryTypeItem(@Valid @RequestBody SalaryTypeItemCreateReqVO createReqVO) { + return success(salaryTypeItemService.createSalaryTypeItem(createReqVO)); + } +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeItemCreateReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeItemCreateReqVO.java new file mode 100644 index 00000000..1ae15501 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeItemCreateReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.system.controller.admin.hr.vo.type; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 工资配置 Request VO") +@Data +public class SalaryTypeItemCreateReqVO { + + @Schema(description = "类型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "类型编号不能为空") + private Long typeId; + + @Schema(description = "编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "编码不能为空") + private String code; + + @Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "名称不能为空") + private String name; + + @Schema(description = "描述", example = "1") + private String describe; + + @Schema(description = "加减属性 | 1加 2减", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "加减属性不能为空") + private Integer attributes; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeItemRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeItemRespVO.java new file mode 100644 index 00000000..5d9062fd --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeItemRespVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.system.controller.admin.hr.vo.type; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 工资配置 Response VO") +@Data +public class SalaryTypeItemRespVO { + + @Schema(description = "编号") + private Long id; + + @Schema(description = "类型编号") + private Long typeId; + + @Schema(description = "编码") + private String code; + + @Schema(description = "名称") + private String name; + + @Schema(description = "描述") + private String describe; + + @Schema(description = "加减属性 | 1加 2减") + private Integer attributes; + + @Schema(description = "状态 | 0开启 1关闭") + private Integer status; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeRespVO.java new file mode 100644 index 00000000..f9e406c3 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeRespVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.system.controller.admin.hr.vo.type; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 工资类型 Response VO") +@Data +public class SalaryTypeRespVO { + + @Schema(description = "编号") + private Long id; + + @Schema(description = "类型名称") + private String name; + + @Schema(description = "状态 | 0开启 1关闭") + private Integer status; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/hr/SalaryTypeDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/hr/SalaryTypeDO.java new file mode 100644 index 00000000..3e06af9a --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/hr/SalaryTypeDO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.hr; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@TableName(value = "hr_salary_type", autoResultMap = true) +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SalaryTypeDO extends BaseDO { + + /** + * 主键ID,自增 + */ + @TableId + private Long id; + + /** + * 类型名称 + */ + private String name; + + /** + * 状态 | 0开启 1关闭 + */ + private Integer status; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/hr/SalaryTypeItemDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/hr/SalaryTypeItemDO.java new file mode 100644 index 00000000..d45d9265 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/hr/SalaryTypeItemDO.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.hr; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.models.security.SecurityScheme; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@TableName(value = "hr_salary_type_item", autoResultMap = true) +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SalaryTypeItemDO extends BaseDO { + + /** + * 主键ID,自增 + */ + @TableId + private Long id; + + /** + * 工资类型编号 + */ + private Long typeId; + + /** + * 属性code + */ + private String code; + + /** + * 属性名称 + */ + private String name; + + /** + * 描述 + */ + private String describe; + + /** + * 加减属性 | 1加 2减 + */ + private Integer attributes; + + /** + * 状态 | 0开启 1关闭 + */ + private Integer status; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/hr/SalaryTypeItemMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/hr/SalaryTypeItemMapper.java new file mode 100644 index 00000000..c2006fee --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/hr/SalaryTypeItemMapper.java @@ -0,0 +1,9 @@ +package cn.iocoder.yudao.module.system.dal.mysql.hr; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.system.dal.dataobject.hr.SalaryTypeItemDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SalaryTypeItemMapper extends BaseMapperX { +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/hr/SalaryTypeMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/hr/SalaryTypeMapper.java new file mode 100644 index 00000000..510a926e --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/hr/SalaryTypeMapper.java @@ -0,0 +1,9 @@ +package cn.iocoder.yudao.module.system.dal.mysql.hr; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.system.dal.dataobject.hr.SalaryTypeDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SalaryTypeMapper extends BaseMapperX { +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeItemService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeItemService.java new file mode 100644 index 00000000..0dec279a --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeItemService.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.system.service.hr; + +import cn.iocoder.yudao.module.system.controller.admin.hr.vo.type.SalaryTypeItemCreateReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.hr.SalaryTypeItemDO; + +import java.util.List; + +/** + * 工资类型配置 Service 接口 + * + * @author 符溶馨 + */ +public interface SalaryTypeItemService { + + /** + * 创建工资类型配置 + * @param createReqVO 创建信息 + * @return 工资类型配置编号 + */ + Long createSalaryTypeItem(SalaryTypeItemCreateReqVO createReqVO); +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeItemServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeItemServiceImpl.java new file mode 100644 index 00000000..272631d9 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeItemServiceImpl.java @@ -0,0 +1,13 @@ +package cn.iocoder.yudao.module.system.service.hr; + +import cn.iocoder.yudao.module.system.controller.admin.hr.vo.type.SalaryTypeItemCreateReqVO; +import org.springframework.stereotype.Service; + +@Service +public class SalaryTypeItemServiceImpl implements SalaryTypeItemService{ + @Override + public Long createSalaryTypeItem(SalaryTypeItemCreateReqVO createReqVO) { + + return null; + } +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeService.java new file mode 100644 index 00000000..d47d0ae4 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeService.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.system.service.hr; + +import cn.iocoder.yudao.module.system.dal.dataobject.hr.SalaryTypeDO; + +import java.util.List; + +/** + * 工资类型 Service 接口 + * + * @author 符溶馨 + */ +public interface SalaryTypeService { + + /** + * 创建工资类型 + * @param name 类型名称 + * @return 类型编号 + */ + Long createSalaryType(String name); + + /** + * 更新工资类型 + * @param id 类型编号 + * @param name 类型名称 + */ + void updateSalaryType(Long id, String name); + + /** + * 更新工资类型状态 + * @param id 类型编号 + * @param status 状态 + */ + void updateSalaryTypeStatus(Long id, Integer status); + + /** + * 获得工资类型 + * @param id 类型编号 + * @return 工资类型 + */ + SalaryTypeDO getSalaryType(Long id); + + /** + * 获得工资类型列表 + * @return 工资类型列表 + */ + List getSalaryTypeList(); +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeServiceImpl.java new file mode 100644 index 00000000..777da182 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeServiceImpl.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.system.service.hr; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.module.system.dal.dataobject.hr.SalaryTypeDO; +import cn.iocoder.yudao.module.system.dal.mysql.hr.SalaryTypeMapper; +import org.springframework.stereotype.Service; + +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.*; + +@Service +public class SalaryTypeServiceImpl implements SalaryTypeService{ + + @Resource + private SalaryTypeMapper salaryTypeMapper; + + @Override + public Long createSalaryType(String name) { + + // 校验类型名称唯一性 + if (salaryTypeMapper.selectCount(SalaryTypeDO::getName, name) > 0L) { + throw exception(SALARY_TYPE_NAME_EXISTS); + } + + SalaryTypeDO salaryTypeDO = new SalaryTypeDO() + .setName(name) + .setStatus(CommonStatusEnum.ENABLE.getStatus()); + + salaryTypeMapper.insert(salaryTypeDO); + return salaryTypeDO.getId(); + } + + @Override + public void updateSalaryType(Long id, String name) { + + validateTypeExists(id); + + SalaryTypeDO salaryTypeDO = new SalaryTypeDO() + .setId(id) + .setName(name); + + salaryTypeMapper.updateById(salaryTypeDO); + } + + @Override + public void updateSalaryTypeStatus(Long id, Integer status) { + + validateTypeExists(id); + + SalaryTypeDO salaryTypeDO = new SalaryTypeDO() + .setId(id) + .setStatus(status); + + // 同步设置 类型配置状态 + + salaryTypeMapper.updateById(salaryTypeDO); + } + + private void validateTypeExists(Long id) { + if (salaryTypeMapper.selectById(id) == null) { + throw exception(SALARY_TYPE_NOT_EXISTS); + } + } + + @Override + public SalaryTypeDO getSalaryType(Long id) { + return salaryTypeMapper.selectById(id); + } + + @Override + public List getSalaryTypeList() { + return salaryTypeMapper.selectList(); + } +} From ddb864764a8cb71ff6f6ba0b204b0244c9c3f543 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Wed, 16 Oct 2024 19:52:49 +0800 Subject: [PATCH 11/20] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E7=94=9F=E6=97=A5?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E6=9F=A5=E8=AF=A2=E7=9A=84=E6=8E=92=E5=BA=8F?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E5=B0=86=20AdminUserMapper=20=E7=B1=BB?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E7=94=9F=E6=97=A5=E7=BB=9F=E8=AE=A1=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E7=9A=84=E6=8E=92=E5=BA=8F=E5=AD=97=E6=AE=B5=E4=BB=8E?= =?UTF-8?q?=20"birthday=5Fday"=20=E6=9B=B4=E6=94=B9=E4=B8=BA=20"DAY(t.birt?= =?UTF-8?q?hday=5Fday)"=EF=BC=8C=E4=BB=A5=E7=A1=AE=E4=BF=9D=E6=8C=89?= =?UTF-8?q?=E7=85=A7=E7=94=9F=E6=97=A5=E7=9A=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/admin/hr/SalaryTypeItemController.java | 10 ++++------ .../system/dal/dataobject/hr/SalaryTypeItemDO.java | 1 - .../module/system/dal/mysql/user/AdminUserMapper.java | 2 +- .../system/service/hr/SalaryTypeItemService.java | 3 --- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/SalaryTypeItemController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/SalaryTypeItemController.java index a3ba247f..825ccce2 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/SalaryTypeItemController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/SalaryTypeItemController.java @@ -1,20 +1,18 @@ package cn.iocoder.yudao.module.system.controller.admin.hr; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.system.controller.admin.hr.vo.type.SalaryTypeItemCreateReqVO; -import cn.iocoder.yudao.module.system.controller.admin.hr.vo.type.SalaryTypeRespVO; import cn.iocoder.yudao.module.system.service.hr.SalaryTypeItemService; -import cn.iocoder.yudao.module.system.service.hr.SalaryTypeService; import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import javax.validation.Valid; -import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/hr/SalaryTypeItemDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/hr/SalaryTypeItemDO.java index d45d9265..ec5a5cac 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/hr/SalaryTypeItemDO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/hr/SalaryTypeItemDO.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.system.dal.dataobject.hr; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.v3.oas.models.security.SecurityScheme; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java index 78b5b44f..10c9da4a 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java @@ -191,7 +191,7 @@ public interface AdminUserMapper extends BaseMapperX { queryWrapper.ge("DAY(t.birthday_day)", date.getDayOfMonth()); } queryWrapper.groupBy("t.id"); - queryWrapper.orderByAsc("t.birthday_day"); + queryWrapper.orderByAsc("DAY(t.birthday_day)"); return selectJoinPage(pageReqVO, UserBirthdayRespVO.class, queryWrapper); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeItemService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeItemService.java index 0dec279a..19164590 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeItemService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeItemService.java @@ -1,9 +1,6 @@ package cn.iocoder.yudao.module.system.service.hr; import cn.iocoder.yudao.module.system.controller.admin.hr.vo.type.SalaryTypeItemCreateReqVO; -import cn.iocoder.yudao.module.system.dal.dataobject.hr.SalaryTypeItemDO; - -import java.util.List; /** * 工资类型配置 Service 接口 From 9d706927b42031a911f216b6f25c02ab75810e8e Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Mon, 21 Oct 2024 09:16:04 +0800 Subject: [PATCH 12/20] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=8E=B0=E9=87=91?= =?UTF-8?q?=E6=94=AF=E5=87=BA=E3=80=81=E6=8A=A5=E9=94=80=E7=9A=84=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpm/controller/admin/oa/BpmOAImprestController.java | 7 ++++++- .../controller/admin/oa/vo/imprest/BpmOAImprestRespVO.java | 3 +++ .../yudao/module/bpm/dal/mysql/oa/BpmOAImprestMapper.java | 4 ++-- .../yudao/module/bpm/service/oa/BpmOACashServiceImpl.java | 4 ++-- .../module/bpm/service/oa/BpmOAImprestServiceImpl.java | 2 +- .../bpm/service/oa/BpmOAReimbursementServiceImpl.java | 4 +++- 6 files changed, 17 insertions(+), 7 deletions(-) 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 332e97cb..0cff1235 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 @@ -58,7 +58,12 @@ public class BpmOAImprestController { //根据user 查询审批通过并且未报销得表单。 BpmOAImprestDO imprest = imprestService.getImprestByUserId(userId); - return success(BpmOAImprestConvert.INSTANCE.convert(imprest)); + BpmOAImprestRespVO respVO = BpmOAImprestConvert.INSTANCE.convert(imprest); + if (!respVO.getStatus().equals(BpmOAImprestDO.FLAG_FALSE)) { + respVO.setNote("您有一笔备用金报销正在处理中!"); + } + + return success(respVO); } @GetMapping("/getByProcessInstanceId") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/imprest/BpmOAImprestRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/imprest/BpmOAImprestRespVO.java index 3cb4d84b..5591fcc7 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/imprest/BpmOAImprestRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/imprest/BpmOAImprestRespVO.java @@ -48,6 +48,9 @@ public class BpmOAImprestRespVO extends BpmOABaseRespVO { @NotNull(message = "报销状态不能为空") private Integer status; + @Schema(description = "备注") + private String note; + @Schema(description = "上传文件", requiredMode = Schema.RequiredMode.NOT_REQUIRED) private List fileItems; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAImprestMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAImprestMapper.java index 3ee1785d..f47902ec 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAImprestMapper.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAImprestMapper.java @@ -17,10 +17,10 @@ import java.util.List; @Mapper public interface BpmOAImprestMapper extends BaseMapperX { - default BpmOAImprestDO selectByUserId(Long userId, List status){ + default BpmOAImprestDO selectByUserId(Long userId){ return selectOne(new LambdaQueryWrapperX().eq(BpmOAImprestDO::getUserId, userId) .eq(BpmOAImprestDO::getResult, BpmProcessInstanceResultEnum.APPROVE.getResult()) - .notIn(BpmOAImprestDO::getStatus, status)); + .ne(BpmOAImprestDO::getStatus, BpmOAImprestDO.FLAG_TRUE)); } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOACashServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOACashServiceImpl.java index 8efdac84..3cf0daa5 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOACashServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOACashServiceImpl.java @@ -166,6 +166,8 @@ public class BpmOACashServiceImpl extends BpmOABaseService implements BpmOACashS // 获得现金支出业务数据 BpmOACashDO cash = validateLeaveExists(id); + cashMapper.updateById(new BpmOACashDO().setId(id).setResult(result)); + // 获取现金支出明细 List cashItemDOs = getCashItem(id); @@ -283,8 +285,6 @@ public class BpmOACashServiceImpl extends BpmOABaseService implements BpmOACashS ); } } - - cashMapper.updateById(new BpmOACashDO().setId(id).setResult(result)); } private BpmOACashDO validateLeaveExists(Long id) { diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAImprestServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAImprestServiceImpl.java index c661d3c1..cf679694 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAImprestServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAImprestServiceImpl.java @@ -142,7 +142,7 @@ public class BpmOAImprestServiceImpl extends BpmOABaseService implements BpmOAIm public BpmOAImprestDO getImprestByUserId(Long userId) { //根据user 查询审批通过并且未报销得表单。 - return imprestMapper.selectByUserId(userId, Arrays.asList(BpmOAImprestDO.FLAG_TRUE, BpmOAImprestDO.IN_PROGRESS)); + return imprestMapper.selectByUserId(userId); } @Override 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 627b92d1..870690a0 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 @@ -157,6 +157,9 @@ public class BpmOAReimbursementServiceImpl extends BpmOABaseService implements B public void updateReimbursementResult(String processInstanceId, Long id, Integer result) { BpmOAReimbursementDO bpmOAReimbursementDO = validateLeaveExists(id); + + reimbursementMapper.updateById(new BpmOAReimbursementDO().setId(id).setResult(result)); + //审核通过 (最后节点) if (BpmProcessInstanceResultEnum.APPROVE.getResult().equals(result)) { @@ -293,7 +296,6 @@ public class BpmOAReimbursementServiceImpl extends BpmOABaseService implements B } } - reimbursementMapper.updateById(new BpmOAReimbursementDO().setId(id).setResult(result)); } private BpmOAReimbursementDO validateLeaveExists(Long id) { From 77e1a9ed51f0113b03bc0559239c2396d2232c6a Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Tue, 22 Oct 2024 21:33:15 +0800 Subject: [PATCH 13/20] =?UTF-8?q?feat(bpm):=20=E6=96=B0=E5=A2=9E=E8=B0=83?= =?UTF-8?q?=E8=96=AA=E4=BA=BA=E4=B8=8A=E7=BA=A7=E9=A2=86=E5=AF=BC=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E8=A7=84=E5=88=99=E8=84=9A=E6=9C=AC-=20=E5=9C=A8=20Bp?= =?UTF-8?q?mTaskRuleScriptEnum=20=E4=B8=AD=E6=B7=BB=E5=8A=A0=20LEADER=5FX9?= =?UTF-8?q?=20=E6=9E=9A=E4=B8=BE=E9=A1=B9=20-=20=E5=AE=9E=E7=8E=B0=20BpmTa?= =?UTF-8?q?skSalaryAssignLeaderScript=20=E7=B1=BB=EF=BC=8C=E7=94=A8?= =?UTF-8?q?=E4=BA=8E=E8=AE=A1=E7=AE=97=E8=B0=83=E8=96=AA=E4=BA=BA=E4=B8=8A?= =?UTF-8?q?=E7=BA=A7=E9=A2=86=E5=AF=BC=20-=20=E5=9C=A8=20BpmOACashDO=20?= =?UTF-8?q?=E5=92=8C=E7=9B=B8=E5=85=B3=20VO=20=E4=B8=AD=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=20difference=20=E5=AD=97=E6=AE=B5=EF=BC=8C=E7=94=A8=E4=BA=8E?= =?UTF-8?q?=E8=A1=A8=E7=A4=BA=E5=A4=87=E7=94=A8=E9=87=91=E5=B7=AE=E9=A2=9D?= =?UTF-8?q?=20-=20=E4=BC=98=E5=8C=96=20BpmOASalaryAdjustmentServiceImpl=20?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E6=B5=81=E7=A8=8B=E5=8F=91=E8=B5=B7=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../definition/BpmTaskRuleScriptEnum.java | 3 +- .../impl/BpmTaskSalaryAssignLeaderScript.java | 118 ++++++++++++++++++ 2 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskSalaryAssignLeaderScript.java 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 da61c5f9..dccf2c7c 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 @@ -22,7 +22,8 @@ public enum BpmTaskRuleScriptEnum { LEADER_X5(24L, "调岗部门领导"), LEADER_X6(25L, "分配任务的责任人"), LEADER_X7(26L, "入职部门领导"), - LEADER_X8(27L, "调薪部门领导"); + LEADER_X8(27L, "调薪部门领导"), + LEADER_X9(28L, "调薪人上级领导"); /** * 脚本编号 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskSalaryAssignLeaderScript.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskSalaryAssignLeaderScript.java new file mode 100644 index 00000000..48299639 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskSalaryAssignLeaderScript.java @@ -0,0 +1,118 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOASalaryAdjustmentDO; +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; +import cn.iocoder.yudao.module.bpm.service.oa.BpmOASalaryAdjustmentService; +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +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.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static java.util.Collections.emptySet; + +@Component +public class BpmTaskSalaryAssignLeaderScript implements BpmTaskAssignScript { + + @Resource + private DeptApi deptApi; + @Resource + @Lazy // 解决循环依赖 + private BpmOASalaryAdjustmentService salaryAdjustmentService; + + @Resource + @Lazy // 解决循环依赖 + private BpmProcessInstanceService bpmProcessInstanceService; + + @Resource + @Lazy // 解决循环依赖 + private BpmTaskService bpmTaskService ; + + @Resource + private AdminUserApi adminUserApi; + + @Override + public Set calculateTaskCandidateUsers(DelegateExecution execution) { + + // 获得发起人 + ProcessInstance processInstance = bpmProcessInstanceService.getProcessInstance(execution.getProcessInstanceId()); + List bpmTaskRespVOs = bpmTaskService.getTaskListByProcessInstanceId(processInstance.getProcessInstanceId()); + if (CollUtil.isEmpty(bpmTaskRespVOs)) { + return emptySet(); + } + //根据流程实例ID 取到调岗流程表单 + BpmOASalaryAdjustmentDO salaryAdjustmentDO = salaryAdjustmentService.getSalaryAdjustment(Long.valueOf(processInstance.getBusinessKey())); + Long startUserId = salaryAdjustmentDO.getAdjustmentUserId(); + + //获取最后一个Task任务相关数据 + BpmTaskRespVO bpmTaskRespVO = bpmTaskRespVOs.get(0) ; + Long assigneeUserId = bpmTaskRespVO.getAssigneeUser().getId() ; + + // 获得对应 发起人 的部门 + DeptRespDTO dept = getUserDept(startUserId); + if (dept == null) { // 找不到发起人的部门,所以无法使用该规则 + return emptySet(); + } + + int count = 0; + Long parentId = dept.getParentId(); + for (int i = 0; i < dept.getLevel(); i++) { + + if (i == 0) { //第一次查找 判断审批人是否为发起人部门负责人 + if (assigneeUserId.toString().equals(processInstance.getStartUserId()) + && !dept.getLeaderUserId().toString().equals(processInstance.getStartUserId())){ //如果发起人不是所在部门负责人时 + + count = 1; + break; + } + } + + //获得发起人的上级部门 + DeptRespDTO parentDept = deptApi.getDept(parentId).getCheckedData(); + if (parentDept == null) { // 找不到父级部门,所以只好结束寻找。原因是:例如说,级别比较高的人,所在部门层级比较少 + return emptySet(); + } + if (!parentDept.getLeaderUserId().toString().equals(assigneeUserId.toString())){ //如果发起人上级部门负责人不为当前审批人时 + + dept = parentDept; + count = 1; + break; + } + + parentId = parentDept.getParentId(); + } + + if (count == 0){// 找不到父级部门。原因是:人的所属部门配在了最高节点了 + return emptySet(); + } + + return dept.getLeaderUserId() != null ? asSet(dept.getLeaderUserId()) : emptySet(); + } + + @Override + public BpmTaskRuleScriptEnum getEnum() { + return BpmTaskRuleScriptEnum.LEADER_X9; + } + + private DeptRespDTO getUserDept(Long userId) { + AdminUserRespDTO user = adminUserApi.getUser(userId).getCheckedData(); + if (user.getDeptId() == null) { // 找不到部门,所以无法使用该规则 + return null; + } + return deptApi.getDept(user.getDeptId()).getCheckedData(); + } +} From ea8ac0cb2da948fbc0103d008c8cd94252f585f3 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Tue, 22 Oct 2024 21:33:27 +0800 Subject: [PATCH 14/20] =?UTF-8?q?feat(bpm):=20=E6=B7=BB=E5=8A=A0=E5=A4=87?= =?UTF-8?q?=E7=94=A8=E9=87=91=E5=B7=AE=E9=A2=9D=E5=AD=97=E6=AE=B5=E5=B9=B6?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=96=AA=E8=B5=84=E8=B0=83=E6=95=B4=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1-=20=E5=9C=A8=20BpmOACashDO=E3=80=81BpmOACashCreateReq?= =?UTF-8?q?VO=20=E5=92=8C=20BpmOACashRespVO=20=E4=B8=AD=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=A4=87=E7=94=A8=E9=87=91=E5=B7=AE=E9=A2=9D=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=20-=20=E4=BC=98=E5=8C=96=20BpmOASalaryAdjustmentServiceImpl=20?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E7=A9=BA=E5=80=BC=E6=A3=80=E6=9F=A5=E9=80=BB?= =?UTF-8?q?=E8=BE=91=20-=20=E5=88=A0=E9=99=A4=20BpmOACashController=20?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E5=86=97=E4=BD=99=E7=A9=BA=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/bpm/controller/admin/oa/BpmOACashController.java | 2 -- .../controller/admin/oa/vo/cash/BpmOACashCreateReqVO.java | 3 +++ .../bpm/controller/admin/oa/vo/cash/BpmOACashRespVO.java | 3 +++ .../yudao/module/bpm/dal/dataobject/oa/BpmOACashDO.java | 5 +++++ .../bpm/service/oa/BpmOASalaryAdjustmentServiceImpl.java | 4 +--- 5 files changed, 12 insertions(+), 5 deletions(-) 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 976d12d0..a81763f2 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 @@ -58,6 +58,4 @@ public class BpmOACashController { return success(cashService.convertCash(cashDO)); } - - } 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 d726e3df..f129e02a 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 @@ -34,6 +34,9 @@ public class BpmOACashCreateReqVO { @Schema(description = "备用金申请编号") private Long imprestId; + @Schema(description = "备用金差额 = 备用金额 - 报销总金额") + private BigDecimal difference; + @Schema(description = "流程实例编号") private String processInstanceId; 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 b1f5e63d..bb9ac6c2 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 @@ -40,6 +40,9 @@ public class BpmOACashRespVO extends BpmOABaseRespVO { @Schema(description = "备用金申请编号") private Long imprestId; + @Schema(description = "备用金差额 = 备用金额 - 报销总金额") + private BigDecimal difference; + @Schema(description = "备用金金额") private BigDecimal amount; 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 10abe4bb..7b5b9d72 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 @@ -55,6 +55,11 @@ public class BpmOACashDO extends BaseDO { */ private Long imprestId; + /** + * 备用金差额 = 备用金额 - 报销总金额 + */ + private BigDecimal difference; + /** * 用章的结果 * diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOASalaryAdjustmentServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOASalaryAdjustmentServiceImpl.java index 31447f06..cce56e79 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOASalaryAdjustmentServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOASalaryAdjustmentServiceImpl.java @@ -12,8 +12,6 @@ import cn.iocoder.yudao.module.bpm.service.task.BpmHistoryProcessInstanceService import cn.iocoder.yudao.module.infra.api.config.ConfigApi; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; -import io.netty.util.internal.StringUtil; -import org.mapstruct.ap.internal.util.Strings; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -77,7 +75,7 @@ public class BpmOASalaryAdjustmentServiceImpl extends BpmOABaseService implement // 查询配置文件,获取行政部门编号 String hrDeptId = configApi.getConfigKey("system_hr_dept").getCheckedData(); - if (Strings.isNotEmpty(hrDeptId)) { + if (hrDeptId != null && !hrDeptId.isEmpty()) { processInstanceVariables.put("hr_dept", hrDeptId); } // 发起 BPM 流程 From 6a393fa9747822d734d66306a93bbfb408145a1d Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Wed, 23 Oct 2024 14:22:45 +0800 Subject: [PATCH 15/20] =?UTF-8?q?fix(bpm):=20=E4=BC=98=E5=8C=96=E9=A2=84?= =?UTF-8?q?=E6=94=AF=E6=AC=BE=E6=9F=A5=E8=AF=A2=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 增加对用户查询结果为空的处理,返回空响应体以避免错误 - 提高代码健壮性,防止空指针异常 --- .../module/bpm/controller/admin/oa/BpmOAImprestController.java | 3 +++ 1 file changed, 3 insertions(+) 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 0cff1235..3749394f 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 @@ -57,6 +57,9 @@ public class BpmOAImprestController { //根据user 查询审批通过并且未报销得表单。 BpmOAImprestDO imprest = imprestService.getImprestByUserId(userId); + if (imprest == null) { + return success(null); + } BpmOAImprestRespVO respVO = BpmOAImprestConvert.INSTANCE.convert(imprest); if (!respVO.getStatus().equals(BpmOAImprestDO.FLAG_FALSE)) { From 0897be8f7b8b8fc91bf9a056f89879d3089177a0 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Fri, 25 Oct 2024 15:23:06 +0800 Subject: [PATCH 16/20] =?UTF-8?q?refactor(bpm):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=A4=87=E7=94=A8=E9=87=91=E6=8A=A5=E9=94=80=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E5=88=A4=E6=96=AD=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -将状态判断条件从不等于 FLAG_FALSE 改为等于 IN_PROGRESS- 这样可以更准确地处理正在处理中的备用金报销情况 --- .../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 3749394f..3b15a189 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 @@ -62,7 +62,7 @@ public class BpmOAImprestController { } BpmOAImprestRespVO respVO = BpmOAImprestConvert.INSTANCE.convert(imprest); - if (!respVO.getStatus().equals(BpmOAImprestDO.FLAG_FALSE)) { + if (respVO.getStatus().equals(BpmOAImprestDO.IN_PROGRESS)) { respVO.setNote("您有一笔备用金报销正在处理中!"); } From 91bb12863a19e18fc5315b4cbb2effcc24e2f6ad Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Fri, 25 Oct 2024 15:54:03 +0800 Subject: [PATCH 17/20] =?UTF-8?q?feat(system):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E9=80=9A=E8=BF=87=E8=BA=AB=E4=BB=BD=E8=AF=81=E5=8F=B7=E7=A0=81?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E8=8E=B7=E5=8F=96=E7=94=A8=E6=88=B7=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 AdminUserService 接口中添加 getUserListByIdCard 方法 - 在 AdminUserServiceImpl 类中实现 getUserListByIdCard 方法 - 使用 LambdaQueryWrapperX 实现对身份证号码列表的查询 --- .../module/system/service/user/AdminUserService.java | 7 +++++++ .../module/system/service/user/AdminUserServiceImpl.java | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java index 49195db9..77065176 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java @@ -377,4 +377,11 @@ public interface AdminUserService { * @return 用户信息分页 */ PageResult getUserListByBirthday(UserBirthdayPageReqVO pageReqVO); + + /** + * 获得指定身份证号码的用户列表 + * @param idcards 身份证号码列表 + * @return 用户列表 + */ + List getUserListByIdCard(List idcards); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java index c221113f..e1b01403 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java @@ -17,6 +17,7 @@ import cn.iocoder.yudao.framework.common.util.string.DTO.IdCardDO; import cn.iocoder.yudao.framework.common.util.string.StrUtils; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; import cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; import cn.iocoder.yudao.module.infra.api.file.FileApi; import cn.iocoder.yudao.module.system.controller.admin.user.dto.UserPageDTO; @@ -770,4 +771,11 @@ public class AdminUserServiceImpl implements AdminUserService { return userMapper.selectUserPageByBirthday(pageReqVO, deptIds, date); } + + @Override + public List getUserListByIdCard(List idCards) { + + return userMapper.selectList(new LambdaQueryWrapperX() + .inIfPresent(AdminUserDO::getIdcard, idCards)); + } } From 367bbb9f71aa1a6cec015de7001b819dffac55df Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Fri, 25 Oct 2024 16:15:57 +0800 Subject: [PATCH 18/20] =?UTF-8?q?feat(system):=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E5=B7=A5=E8=B5=84=E7=B1=BB=E5=9E=8B=E5=92=8C=E5=B7=A5=E8=B5=84?= =?UTF-8?q?=E6=9D=A1=E7=9B=B8=E5=85=B3=E9=94=99=E8=AF=AF=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增工资类型不存在、工资类型配置不存在等错误码 -增加工资条不存在、导入数据为空等错误处理 - 添加身份证输入错误和工资条已存在的提示 --- .../yudao/module/system/enums/ErrorCodeConstants.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java index 3004218d..53038549 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java @@ -262,6 +262,11 @@ public interface ErrorCodeConstants { // ========== 人事管理相关 1-012-001-001 ========== ErrorCode LABOR_CONTRACT_NOT_EXISTS = new ErrorCode(1_012_001_001, "劳动合同管理不存在"); ErrorCode SALARY_TYPE_NAME_EXISTS = new ErrorCode(1_012_002_001, "类型名称重复!"); - ErrorCode SALARY_TYPE_NOT_EXISTS = new ErrorCode(1_012_002_001, "工资类型不存在"); - + ErrorCode SALARY_TYPE_NOT_EXISTS = new ErrorCode(1_012_002_002, "工资类型不存在"); + ErrorCode SALARY_TYPE_ITEM_CODE_EXISTS = new ErrorCode(1_012_002_003, "code重复!"); + ErrorCode SALARY_TYPE_ITEM_NOT_EXISTS = new ErrorCode(1_012_002_004, "工资类型配置不存在"); + ErrorCode PAYSLIP_NOT_EXISTS = new ErrorCode(1_012_002_005, "工资条不存在"); + ErrorCode PAYSLIP_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_012_002_006, "导入数据不能为空!"); + ErrorCode PAYSLIP_EXISTS = new ErrorCode(1_012_002_007, "所选公司在当前月份已上传工资条!如需修改,请勾选覆盖导入。"); + ErrorCode PAYSLIP_ID_CARD_ERROR = new ErrorCode(1_012_002_008, "【{}】身份证输入有误,请核对后导入!"); } From 7ef255a9f83dec69ce244f02bbfdcc6428765150 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Fri, 25 Oct 2024 16:16:27 +0800 Subject: [PATCH 19/20] =?UTF-8?q?feat(system):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=B7=A5=E8=B5=84=E6=9D=A1=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现了工资条创建、更新、查询、导入、导出等功能 - 添加了工资条相关的数据结构和接口定义 - 实现了工资条数据的持久化和查询 - 添加了工资条导入导出的 Excel 处理逻辑 --- .../admin/hr/PayslipController.java | 201 ++++++++++ .../admin/hr/SalaryTypeController.java | 26 +- .../admin/hr/SalaryTypeItemController.java | 48 ++- .../hr/vo/payslip/PayslipCreateReqVO.java | 48 +++ .../admin/hr/vo/payslip/PayslipDetail.java | 25 ++ .../hr/vo/payslip/PayslipImportExcelVO.java | 86 +++++ .../admin/hr/vo/payslip/PayslipPageReqVO.java | 25 ++ .../admin/hr/vo/payslip/PayslipRespVO.java | 54 +++ .../hr/vo/type/SalaryTypeCreateReqVO.java | 21 + .../hr/vo/type/SalaryTypeItemCreateReqVO.java | 8 +- .../hr/vo/type/SalaryTypeItemRespVO.java | 2 +- .../admin/hr/vo/type/SalaryTypeRespVO.java | 6 + .../hr/vo/type/SalaryTypeUpdateSortVO.java | 15 + .../system/dal/dataobject/hr/PayslipDO.java | 90 +++++ .../dal/dataobject/hr/SalaryTypeDO.java | 10 + .../dal/dataobject/hr/SalaryTypeItemDO.java | 2 +- .../system/dal/mysql/hr/PayslipMapper.java | 50 +++ .../service/hr/SalaryTypeItemService.java | 18 - .../service/hr/SalaryTypeItemServiceImpl.java | 13 - .../service/hr/SalaryTypeServiceImpl.java | 77 ---- .../service/hr/payslip/PayslipService.java | 70 ++++ .../hr/payslip/PayslipServiceImpl.java | 361 ++++++++++++++++++ .../hr/type/SalaryTypeItemService.java | 54 +++ .../hr/type/SalaryTypeItemServiceImpl.java | 105 +++++ .../hr/{ => type}/SalaryTypeService.java | 19 +- .../hr/type/SalaryTypeServiceImpl.java | 110 ++++++ .../resources/mapper/hr/PayslipMapper.xml | 18 + 27 files changed, 1429 insertions(+), 133 deletions(-) create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/PayslipController.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/payslip/PayslipCreateReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/payslip/PayslipDetail.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/payslip/PayslipImportExcelVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/payslip/PayslipPageReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/payslip/PayslipRespVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeCreateReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeUpdateSortVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/hr/PayslipDO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/hr/PayslipMapper.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeItemService.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeItemServiceImpl.java delete mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeServiceImpl.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/payslip/PayslipService.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/payslip/PayslipServiceImpl.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/type/SalaryTypeItemService.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/type/SalaryTypeItemServiceImpl.java rename yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/{ => type}/SalaryTypeService.java (55%) create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/type/SalaryTypeServiceImpl.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/hr/PayslipMapper.xml diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/PayslipController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/PayslipController.java new file mode 100644 index 00000000..10c47dc7 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/PayslipController.java @@ -0,0 +1,201 @@ +package cn.iocoder.yudao.module.system.controller.admin.hr; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import cn.iocoder.yudao.module.infra.api.file.FileApi; +import cn.iocoder.yudao.module.system.controller.admin.hr.vo.payslip.*; +import cn.iocoder.yudao.module.system.service.hr.payslip.PayslipService; +import com.alibaba.excel.EasyExcel; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; + +@Tag(name = "管理后台 - 工资条") +@RestController +@RequestMapping("/system/hr/payslip") +public class PayslipController { + + @Resource + private PayslipService payslipService; + + @Resource + private FileApi fileApi; + + @PostMapping("/create") + @Operation(summary = "创建工资条") + @PreAuthorize("@ss.hasPermission('system:hr:payslip:create')") + public CommonResult createPayslip(@Valid List createReqVO) { + payslipService.createPayslip(createReqVO); + return success(true); + } + + @PutMapping("/issued") + @Operation(summary = "下发工资条") + @PreAuthorize("@ss.hasPermission('system:hr:payslip:update')") + public CommonResult updatePayslip(@RequestBody PayslipPageReqVO updateReqVO) { + payslipService.issuedPayslip(updateReqVO); + return success(true); + } + + @PutMapping("/update") + @Operation(summary = "更新工资条") + @PreAuthorize("@ss.hasPermission('system:hr:payslip:update')") + public CommonResult updatePayslip(@RequestBody PayslipCreateReqVO updateReqVO) { + payslipService.updatePayslip(updateReqVO); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得工资条") + @Parameter(name = "id", description = "编号", required = true, example = "1") + @PreAuthorize("@ss.hasPermission('system:hr:payslip:query')") + public CommonResult getPayslip(@RequestParam("id") Long id) { + + return success(BeanUtils.toBean(payslipService.getPayslip(id), PayslipRespVO.class)); + } + + @PostMapping("/Page") + @Operation(summary = "获得工资条分页") + @Parameter(name = "id", description = "编号", required = true, example = "1") + @PreAuthorize("@ss.hasPermission('system:hr:payslip:query')") + public CommonResult> getPage(@RequestBody PayslipPageReqVO pageReqVO) { + + PageResult pageResult = BeanUtils.toBean(payslipService.getPage(pageReqVO), PayslipRespVO.class); + pageResult.getList().forEach(data -> { + List details = data.getDetails(); + // 设置实发工资 + details.add(new PayslipDetail() + .setCode("salary") + .setName("实发工资") + .setValue(data.getSalary())); + + // 设置开户行 + details.add(new PayslipDetail() + .setCode("bankName") + .setName("开户行") + .setValue(data.getBankName())); + + // 设置银行卡号 + details.add(new PayslipDetail() + .setCode("bankNo") + .setName("卡号") + .setValue(data.getBankNo())); + + // 设置备注 + details.add(new PayslipDetail() + .setCode("remark") + .setName("备注") + .setValue(data.getRemark())); + + if (data.getIsConfirm() != null && data.getIsConfirm() == 1) { + data.setSignURL(fileApi.getUserSignImgPath(data.getUserId()).getData()); + } + + // 设置签名 + details.add(new PayslipDetail() + .setCode("signURL") + .setName("签名") + .setValue(data.getSignURL())); + data.setDetails(details); + }); + return success(pageResult); + } + + @PostMapping("/myPage") + @Operation(summary = "获得当前登录用户的工资条分页") + @Parameter(name = "id", description = "编号", required = true, example = "1") + @PreAuthorize("@ss.hasPermission('system:hr:payslip:query')") + public CommonResult> getMyPage(@RequestBody PayslipPageReqVO pageReqVO) { + + PageResult pageResult = BeanUtils.toBean(payslipService.getMyPage(pageReqVO), PayslipRespVO.class); + pageResult.getList().forEach(data -> { + List details = data.getDetails(); + // 设置实发工资 + details.add(new PayslipDetail() + .setCode("salary") + .setName("实发工资") + .setValue(data.getSalary())); + + // 设置开户行 + details.add(new PayslipDetail() + .setCode("bankName") + .setName("开户行") + .setValue(data.getBankName())); + + // 设置银行卡号 + details.add(new PayslipDetail() + .setCode("bankNo") + .setName("卡号") + .setValue(data.getBankNo())); + + // 设置备注 + details.add(new PayslipDetail() + .setCode("remark") + .setName("备注") + .setValue(data.getRemark())); + + if (data.getIsConfirm() == 1) { + data.setSignURL(fileApi.getUserSignImgPath(data.getUserId()).getData()); + } + + // 设置签名 + details.add(new PayslipDetail() + .setCode("signURL") + .setName("签名") + .setValue(data.getSignURL())); + data.setDetails(details); + }); + return success(pageResult); + } + + @PostMapping("/import") + @Operation(summary = "导入工资条") + @Parameters({ + @Parameter(name = "file", description = "Excel 文件", required = true), + @Parameter(name = "date", description = "日期", required = true), + @Parameter(name = "deptId", description = "公司编号", required = true), + @Parameter(name = "isUpdate", description = "是否允许覆盖", required = true) + }) + @PreAuthorize("@ss.hasPermission('system:hr:payslip:import')") + public CommonResult importExcel(@RequestParam("file") MultipartFile file, + @RequestParam("date") String date, + @RequestParam("deptId") Long deptId, + @RequestParam("isUpdate") Boolean isUpdate) throws Exception { + + List list = EasyExcel.read(file.getInputStream(), PayslipImportExcelVO.class, null) + .headRowNumber(3) + .autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理 + .doReadAllSync(); + // 导入数据 + payslipService.importPayslip(list, date, deptId, isUpdate); + return success(true); + } + + @GetMapping("/export") + @Operation(summary = "导出工资条") + @PreAuthorize("@ss.hasPermission('system:user:export')") + @OperateLog(type = EXPORT) + public void exportList(@Validated PayslipPageReqVO exportReqVO, + HttpServletResponse response) throws IOException { + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + + payslipService.exportList(response, exportReqVO); + } +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/SalaryTypeController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/SalaryTypeController.java index 78ceb0cb..79a5dea1 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/SalaryTypeController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/SalaryTypeController.java @@ -2,8 +2,10 @@ package cn.iocoder.yudao.module.system.controller.admin.hr; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.hr.vo.type.SalaryTypeCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.hr.vo.type.SalaryTypeRespVO; -import cn.iocoder.yudao.module.system.service.hr.SalaryTypeService; +import cn.iocoder.yudao.module.system.controller.admin.hr.vo.type.SalaryTypeUpdateSortVO; +import cn.iocoder.yudao.module.system.service.hr.type.SalaryTypeService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -11,6 +13,7 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; +import javax.validation.Valid; import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -26,28 +29,35 @@ public class SalaryTypeController { @PostMapping("/create") @Operation(summary = "创建工资类型") @PreAuthorize("@ss.hasPermission('system:hr:salary-type:create')") - public CommonResult createSalaryType(@RequestParam("name") String name) { - return success(salaryTypeService.createSalaryType(name)); + public CommonResult createSalaryType(@Valid @RequestBody SalaryTypeCreateReqVO createReqVO) { + return success(salaryTypeService.createSalaryType(createReqVO)); } @PutMapping("/update") @Operation(summary = "更新工资类型") @PreAuthorize("@ss.hasPermission('system:hr:salary-type:update')") - public CommonResult updateLogInstance(@RequestParam("id") Long id, - @RequestParam("name") String name) { - salaryTypeService.updateSalaryType(id, name); + public CommonResult updateSalaryType(@Valid @RequestBody SalaryTypeCreateReqVO updateReqVO) { + salaryTypeService.updateSalaryType(updateReqVO); return success(true); } @PutMapping("/update-status") @Operation(summary = "更新工资类型状态") - @PreAuthorize("@ss.hasPermission('system:hr:salary-type:update')") - public CommonResult updateLogInstance(@RequestParam("id") Long id, + @PreAuthorize("@ss.hasPermission('system:hr:salary-type:update-status')") + public CommonResult updateSalaryTypeStatus(@RequestParam("id") Long id, @RequestParam("status") Integer status) { salaryTypeService.updateSalaryTypeStatus(id, status); return success(true); } + @PutMapping("/update-sort") + @Operation(summary = "更新工资类型排序") + @PreAuthorize("@ss.hasPermission('system:hr:salary-type:update-status')") + public CommonResult updateSort(@RequestBody List updateSortVO) { + salaryTypeService.updateSort(updateSortVO); + return success(true); + } + @GetMapping("/get") @Operation(summary = "获得工资类型") @Parameter(name = "id", description = "编号", required = true, example = "1") diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/SalaryTypeItemController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/SalaryTypeItemController.java index 825ccce2..06d0f99e 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/SalaryTypeItemController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/SalaryTypeItemController.java @@ -1,22 +1,23 @@ package cn.iocoder.yudao.module.system.controller.admin.hr; import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.system.controller.admin.hr.vo.type.SalaryTypeItemCreateReqVO; -import cn.iocoder.yudao.module.system.service.hr.SalaryTypeItemService; +import cn.iocoder.yudao.module.system.controller.admin.hr.vo.type.SalaryTypeItemRespVO; +import cn.iocoder.yudao.module.system.service.hr.type.SalaryTypeItemService; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.validation.Valid; +import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -@Tag(name = "管理后台 - 工资类型") +@Tag(name = "管理后台 - 工资类型配置") @RestController @RequestMapping("/system/hr/salary-type-item") public class SalaryTypeItemController { @@ -30,4 +31,39 @@ public class SalaryTypeItemController { public CommonResult createSalaryTypeItem(@Valid @RequestBody SalaryTypeItemCreateReqVO createReqVO) { return success(salaryTypeItemService.createSalaryTypeItem(createReqVO)); } + + @PutMapping("/update") + @Operation(summary = "更新工资类型配置") + @PreAuthorize("@ss.hasPermission('system:hr:salary-type-item:update')") + public CommonResult updateLogInstance(@Valid @RequestBody SalaryTypeItemCreateReqVO updateReqVO) { + salaryTypeItemService.updateSalaryTypeItem(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新工资类型配置状态") + @PreAuthorize("@ss.hasPermission('system:hr:salary-type-item:update-status')") + public CommonResult updateLogInstance(@RequestParam("id") Long id, + @RequestParam("status") Integer status) { + salaryTypeItemService.updateSalaryTypeItemStatus(id, status); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得工资类型配置") + @Parameter(name = "id", description = "编号", required = true, example = "1") + @PreAuthorize("@ss.hasPermission('system:hr:salary-type-item:query')") + public CommonResult getSalaryType(@RequestParam("id") Long id) { + + return success(BeanUtils.toBean(salaryTypeItemService.getSalaryTypeItem(id), SalaryTypeItemRespVO.class)); + } + + @GetMapping("/listByTypeId") + @Operation(summary = "获得工资类型配置列表") + @Parameter(name = "typeId", description = "类型编号", required = true, example = "1") + @PreAuthorize("@ss.hasPermission('system:hr:salary-type-item:query')") + public CommonResult> getSalaryTypeList(@RequestParam("typeId") Long typeId) { + + return success(BeanUtils.toBean(salaryTypeItemService.getListByTypeId(typeId), SalaryTypeItemRespVO.class)); + } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/payslip/PayslipCreateReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/payslip/PayslipCreateReqVO.java new file mode 100644 index 00000000..cd9efed4 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/payslip/PayslipCreateReqVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.system.controller.admin.hr.vo.payslip; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.util.List; + +@Schema(description = "管理后台 - 工资条创建 Request VO") +@Data +public class PayslipCreateReqVO { + + @Schema(description = "编号", example = "1") + private Long id; + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "用户编号不能为空") + private Long userId; + + @Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "部门编号不能为空") + private Long deptId; + + @Schema(description = "所属公司编号") + private Long companyDeptId; + + @Schema(description = "银行开户名") + private String bankName; + + @Schema(description = "银行账号") + private String bankNo; + + @Schema(description = "工资日期") + private String salaryDate; + + @Schema(description = "实发工资") + private BigDecimal salary; + + @Schema(description = "工资条详情") + private List details; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "是否确认工资单 | 0否 1是", example = "0") + private Integer isConfirm; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/payslip/PayslipDetail.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/payslip/PayslipDetail.java new file mode 100644 index 00000000..11996077 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/payslip/PayslipDetail.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.system.controller.admin.hr.vo.payslip; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "管理后台 - 工资条详情 Response VO") +@Data +public class PayslipDetail { + + @Schema(description = "编码") + private String code; + + @Schema(description = "名称") + private String name; + + @Schema(description = "值") + private Object value; + + /** + * 子数据 + */ + private List children; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/payslip/PayslipImportExcelVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/payslip/PayslipImportExcelVO.java new file mode 100644 index 00000000..3239d537 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/payslip/PayslipImportExcelVO.java @@ -0,0 +1,86 @@ +package cn.iocoder.yudao.module.system.controller.admin.hr.vo.payslip; + +import cn.iocoder.yudao.framework.common.validation.IdCard; +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; + +/** + * 工资条 Excel 导入 VO + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Accessors(chain = false) // 设置 chain = false,避免用户导入有问题 +public class PayslipImportExcelVO { + + @ExcelProperty("姓名") + private String nickname; + + @ExcelProperty("身份证号码") + @IdCard + private String idcard; + + @ExcelProperty("基本工资") + private BigDecimal jbgz; + + @ExcelProperty(value = "防暑降温费") + private BigDecimal fsjwf; + + @ExcelProperty("误餐补助") + private BigDecimal wcbz; + + @ExcelProperty("福利费") + private BigDecimal flf; + + @ExcelProperty(value = "合计", index = 7) + private BigDecimal sum; + + @ExcelProperty(value = "试用期工资", index = 8) + private BigDecimal syqgz; + + @ExcelProperty(value = "应发工资", index = 9) + private BigDecimal yfgz; + + @ExcelProperty("养老") + private BigDecimal ylbx; + + @ExcelProperty("失业") + private BigDecimal sybx; + + @ExcelProperty("医保") + private BigDecimal yb; + + @ExcelProperty("大额医疗") + private BigDecimal deyl; + + @ExcelProperty(value = "代缴合计", index = 14) + private BigDecimal djSum; + + @ExcelProperty(value = "公积金", index = 15) + private BigDecimal gjj; + + @ExcelProperty(value = "个税", index = 16) + private BigDecimal gs; + + @ExcelProperty(value = "实发工资", index = 17) + private BigDecimal salary; + + @ExcelProperty(value = "开户行", index = 18) + private String bankName; + + @ExcelProperty(value = "银行卡号", index = 19) + private String bankNo; + + @ExcelProperty(value = "备注", index = 20) + private String remark; + + @ExcelProperty(value = "签名", index = 21) + private String isConfirm; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/payslip/PayslipPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/payslip/PayslipPageReqVO.java new file mode 100644 index 00000000..efe86940 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/payslip/PayslipPageReqVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.system.controller.admin.hr.vo.payslip; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@Schema(description = "管理后台 - 工资条分页 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class PayslipPageReqVO extends PageParam { + + @Schema(description = "用户账号,模糊匹配", example = "yudao") + private String name; + + @Schema(description = "公司部门编号,同时筛选子部门", example = "1024") + private Long deptId; + + @Schema(description = "薪资日期 | yyyy-MM", example = "2024-10") + private String date; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/payslip/PayslipRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/payslip/PayslipRespVO.java new file mode 100644 index 00000000..a6066456 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/payslip/PayslipRespVO.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.system.controller.admin.hr.vo.payslip; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +@Schema(description = "管理后台 - 工资条 Response VO") +@Data +public class PayslipRespVO { + + @Schema(description = "编号", example = "1") + private Long id; + + @Schema(description = "用户编号", example = "1") + private Long userId; + + @Schema(description = "用户名称", example = "芋道") + private String userName; + + @Schema(description = "部门编号", example = "1") + private Long deptId; + + @Schema(description = "部门名称", example = "芋道源码") + private String deptName; + + @Schema(description = "所属公司编号") + private Long companyDeptId; + + @Schema(description = "银行开户名") + private String bankName; + + @Schema(description = "银行账号") + private String bankNo; + + @Schema(description = "工资日期") + private String salaryDate; + + @Schema(description = "实发工资") + private BigDecimal salary; + + @Schema(description = "工资条详情") + private List details; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "是否确认工资单 | 0否 1是", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Integer isConfirm; + + @Schema(description = "电子签名") + private String signURL; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeCreateReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeCreateReqVO.java new file mode 100644 index 00000000..254f77fa --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeCreateReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.system.controller.admin.hr.vo.type; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 工资类型 Request VO") +@Data +public class SalaryTypeCreateReqVO { + + @Schema(description = "编号", example = "1") + private Long id; + + @Schema(description = "类型名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "类型名称不能为空") + private String name; + + @Schema(description = "类型 | 0应发工资项 1代扣代缴项", example = "1") + private Integer type; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeItemCreateReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeItemCreateReqVO.java index 1ae15501..74c8885a 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeItemCreateReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeItemCreateReqVO.java @@ -9,6 +9,9 @@ import javax.validation.constraints.NotNull; @Data public class SalaryTypeItemCreateReqVO { + @Schema(description = "编号", example = "1") + private Long id; + @Schema(description = "类型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @NotNull(message = "类型编号不能为空") private Long typeId; @@ -22,9 +25,8 @@ public class SalaryTypeItemCreateReqVO { private String name; @Schema(description = "描述", example = "1") - private String describe; + private String itemDescribe; - @Schema(description = "加减属性 | 1加 2减", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @NotNull(message = "加减属性不能为空") + @Schema(description = "加减属性 | 1加 2减", example = "1") private Integer attributes; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeItemRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeItemRespVO.java index 5d9062fd..b3d22b72 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeItemRespVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeItemRespVO.java @@ -20,7 +20,7 @@ public class SalaryTypeItemRespVO { private String name; @Schema(description = "描述") - private String describe; + private String itemDescribe; @Schema(description = "加减属性 | 1加 2减") private Integer attributes; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeRespVO.java index f9e406c3..3e417d2e 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeRespVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeRespVO.java @@ -13,6 +13,12 @@ public class SalaryTypeRespVO { @Schema(description = "类型名称") private String name; + @Schema(description = "类型 | 0应发工资项 1代扣代缴项", example = "1") + private Integer type; + + @Schema(description = "显示顺序", example = "1") + private Integer sort; + @Schema(description = "状态 | 0开启 1关闭") private Integer status; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeUpdateSortVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeUpdateSortVO.java new file mode 100644 index 00000000..d782dd40 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/vo/type/SalaryTypeUpdateSortVO.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.system.controller.admin.hr.vo.type; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 工资类型 Request VO") +@Data +public class SalaryTypeUpdateSortVO { + + @Schema(description = "编号", example = "1") + private Long id; + + @Schema(description = "顺序", example = "1") + private String sort; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/hr/PayslipDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/hr/PayslipDO.java new file mode 100644 index 00000000..7c0d2b8c --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/hr/PayslipDO.java @@ -0,0 +1,90 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.hr; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.system.controller.admin.hr.vo.payslip.PayslipDetail; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.math.BigDecimal; +import java.util.List; + +@TableName(value = "hr_payslip", autoResultMap = true) +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class PayslipDO extends BaseDO { + + /** + * 主键ID,自增 + */ + @TableId + private Long id; + + /** + * 用户编号 + */ + private Long userId; + + /** + * 部门编号 + */ + private Long deptId; + + /** + * 所属公司编号 + */ + private Long companyDeptId; + + /** + * 薪资日期 YYYY-MM + */ + private String salaryDate; + + /** + * 实发工资 + */ + private BigDecimal salary; + + /** + * 开户行 + */ + private String bankName; + + /** + * 银行卡号 + */ + private String bankNo; + + /** + * 详情 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List details; + + /** + * 备注 + */ + private String remark; + + /** + * 是否确认 + */ + private Integer isConfirm; + + /** + * 用户名称 + */ + @TableField(exist = false) + private String userName; + + /** + * 用户部门名称 + */ + @TableField(exist = false) + private String deptName; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/hr/SalaryTypeDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/hr/SalaryTypeDO.java index 3e06af9a..ae7fa05e 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/hr/SalaryTypeDO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/hr/SalaryTypeDO.java @@ -24,6 +24,16 @@ public class SalaryTypeDO extends BaseDO { */ private String name; + /** + * 类型 | 0应发工资项 1代扣代缴项 + */ + private Integer type; + + /** + * 显示顺序 + */ + private Integer sort; + /** * 状态 | 0开启 1关闭 */ diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/hr/SalaryTypeItemDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/hr/SalaryTypeItemDO.java index ec5a5cac..5a4229af 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/hr/SalaryTypeItemDO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/hr/SalaryTypeItemDO.java @@ -37,7 +37,7 @@ public class SalaryTypeItemDO extends BaseDO { /** * 描述 */ - private String describe; + private String itemDescribe; /** * 加减属性 | 1加 2减 diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/hr/PayslipMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/hr/PayslipMapper.java new file mode 100644 index 00000000..37da7701 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/hr/PayslipMapper.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.system.dal.mysql.hr; + +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.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.hr.vo.payslip.PayslipPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; +import cn.iocoder.yudao.module.system.dal.dataobject.hr.PayslipDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.Objects; + +@Mapper +public interface PayslipMapper extends BaseMapperX { + + default PageResult selectPage(PayslipPageReqVO pageReqVO) { + + MPJLambdaWrapperX wrapper = new MPJLambdaWrapperX() + .selectAll(PayslipDO.class) + .selectAs(AdminUserDO::getNickname, PayslipDO::getUserName) + .selectAs(DeptDO::getName, PayslipDO::getDeptName); + wrapper.innerJoin(AdminUserDO.class, on -> on + .eq(AdminUserDO::getId, PayslipDO::getUserId) + .like(Objects.nonNull(pageReqVO.getName()), AdminUserDO::getNickname, pageReqVO.getName())); + wrapper.innerJoin(DeptDO.class, DeptDO::getId, PayslipDO::getDeptId); + wrapper.eq(PayslipDO::getSalaryDate, pageReqVO.getDate()); + wrapper.eqIfPresent(PayslipDO::getCompanyDeptId, pageReqVO.getDeptId()); + + return selectJoinPage(pageReqVO, PayslipDO.class, wrapper); + } + + default PageResult selectMyPage(PayslipPageReqVO pageReqVO, Long loginUserId) { + + MPJLambdaWrapperX wrapper = new MPJLambdaWrapperX() + .selectAll(PayslipDO.class) + .selectAs(AdminUserDO::getNickname, PayslipDO::getUserName) + .selectAs(DeptDO::getName, PayslipDO::getDeptName); + wrapper.innerJoin(AdminUserDO.class, AdminUserDO::getId, PayslipDO::getUserId); + wrapper.innerJoin(DeptDO.class, DeptDO::getId, PayslipDO::getDeptId); + wrapper.eqIfPresent(PayslipDO::getSalaryDate, pageReqVO.getDate()); + wrapper.eq(PayslipDO::getUserId, loginUserId); + wrapper.isNotNull(PayslipDO::getIsConfirm); + + return selectJoinPage(pageReqVO, PayslipDO.class, wrapper); + } + + void deletePayslip(@Param("date") String date, @Param("deptId") Long deptId); +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeItemService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeItemService.java deleted file mode 100644 index 19164590..00000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeItemService.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.iocoder.yudao.module.system.service.hr; - -import cn.iocoder.yudao.module.system.controller.admin.hr.vo.type.SalaryTypeItemCreateReqVO; - -/** - * 工资类型配置 Service 接口 - * - * @author 符溶馨 - */ -public interface SalaryTypeItemService { - - /** - * 创建工资类型配置 - * @param createReqVO 创建信息 - * @return 工资类型配置编号 - */ - Long createSalaryTypeItem(SalaryTypeItemCreateReqVO createReqVO); -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeItemServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeItemServiceImpl.java deleted file mode 100644 index 272631d9..00000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeItemServiceImpl.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.iocoder.yudao.module.system.service.hr; - -import cn.iocoder.yudao.module.system.controller.admin.hr.vo.type.SalaryTypeItemCreateReqVO; -import org.springframework.stereotype.Service; - -@Service -public class SalaryTypeItemServiceImpl implements SalaryTypeItemService{ - @Override - public Long createSalaryTypeItem(SalaryTypeItemCreateReqVO createReqVO) { - - return null; - } -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeServiceImpl.java deleted file mode 100644 index 777da182..00000000 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeServiceImpl.java +++ /dev/null @@ -1,77 +0,0 @@ -package cn.iocoder.yudao.module.system.service.hr; - -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.module.system.dal.dataobject.hr.SalaryTypeDO; -import cn.iocoder.yudao.module.system.dal.mysql.hr.SalaryTypeMapper; -import org.springframework.stereotype.Service; - -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.*; - -@Service -public class SalaryTypeServiceImpl implements SalaryTypeService{ - - @Resource - private SalaryTypeMapper salaryTypeMapper; - - @Override - public Long createSalaryType(String name) { - - // 校验类型名称唯一性 - if (salaryTypeMapper.selectCount(SalaryTypeDO::getName, name) > 0L) { - throw exception(SALARY_TYPE_NAME_EXISTS); - } - - SalaryTypeDO salaryTypeDO = new SalaryTypeDO() - .setName(name) - .setStatus(CommonStatusEnum.ENABLE.getStatus()); - - salaryTypeMapper.insert(salaryTypeDO); - return salaryTypeDO.getId(); - } - - @Override - public void updateSalaryType(Long id, String name) { - - validateTypeExists(id); - - SalaryTypeDO salaryTypeDO = new SalaryTypeDO() - .setId(id) - .setName(name); - - salaryTypeMapper.updateById(salaryTypeDO); - } - - @Override - public void updateSalaryTypeStatus(Long id, Integer status) { - - validateTypeExists(id); - - SalaryTypeDO salaryTypeDO = new SalaryTypeDO() - .setId(id) - .setStatus(status); - - // 同步设置 类型配置状态 - - salaryTypeMapper.updateById(salaryTypeDO); - } - - private void validateTypeExists(Long id) { - if (salaryTypeMapper.selectById(id) == null) { - throw exception(SALARY_TYPE_NOT_EXISTS); - } - } - - @Override - public SalaryTypeDO getSalaryType(Long id) { - return salaryTypeMapper.selectById(id); - } - - @Override - public List getSalaryTypeList() { - return salaryTypeMapper.selectList(); - } -} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/payslip/PayslipService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/payslip/PayslipService.java new file mode 100644 index 00000000..64c110c8 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/payslip/PayslipService.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.system.service.hr.payslip; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.hr.vo.payslip.PayslipCreateReqVO; +import cn.iocoder.yudao.module.system.controller.admin.hr.vo.payslip.PayslipImportExcelVO; +import cn.iocoder.yudao.module.system.controller.admin.hr.vo.payslip.PayslipPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.hr.PayslipDO; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 工资条 Service 接口 + * + * @author 符溶馨 + */ +public interface PayslipService { + + /** + * 批量创建工资条 + * @param createReqVO 创建工资条请求 + */ + void createPayslip(List createReqVO); + + /** + * 更新工资条 + * @param updateReqVO 更新工资条请求 + */ + void updatePayslip(PayslipCreateReqVO updateReqVO); + + /** + * 获取工资条详情 + * @param id 工资条编号 + * @return 工资条详情 + */ + PayslipDO getPayslip(Long id); + + /** + * 获得工资条分页 + * @param pageReqVO 分页信息 + * @return 工资条分页详情 + */ + PageResult getPage(PayslipPageReqVO pageReqVO); + + /** + * 获取当前登录用户的工资条分页 + * @param pageReqVO 分页信息 + * @return 工资条分页详情 + */ + PageResult getMyPage(PayslipPageReqVO pageReqVO); + + /** + * 导入工资条 + * @param list 导入工资条数据 + */ + void importPayslip(List list, String date, Long deptId, Boolean isUpdate); + + /** + * 下发工资条 + * @param updateReqVO 下发条件 + */ + void issuedPayslip(PayslipPageReqVO updateReqVO); + + /** + * 工资条导出 + * @param response 响应 + * @param exportReqVO 工资条列表 + */ + void exportList(HttpServletResponse response, PayslipPageReqVO exportReqVO); +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/payslip/PayslipServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/payslip/PayslipServiceImpl.java new file mode 100644 index 00000000..ab98bd1a --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/payslip/PayslipServiceImpl.java @@ -0,0 +1,361 @@ +package cn.iocoder.yudao.module.system.service.hr.payslip; + +import cn.hutool.core.collection.CollUtil; +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.hr.vo.payslip.*; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; +import cn.iocoder.yudao.module.system.dal.dataobject.hr.PayslipDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.dal.mysql.hr.PayslipMapper; +import cn.iocoder.yudao.module.system.service.attendance.CustomCellStyleHandler; +import cn.iocoder.yudao.module.system.service.dept.DeptService; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.support.ExcelTypeEnum; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +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.convertMap; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + +/** + * 工资条 Service 实现类 + * + * @author 符溶馨 + */ +@Service +public class PayslipServiceImpl implements PayslipService{ + + @Resource + private PayslipMapper payslipMapper; + + @Resource + private DeptService deptService; + + @Resource + private AdminUserService userService; + + @Override + public void createPayslip(List createReqVO) { + + List payslipDOList = BeanUtils.toBean(createReqVO, PayslipDO.class); + payslipMapper.insertBatch(payslipDOList); + } + + @Override + public void updatePayslip(PayslipCreateReqVO updateReqVO) { + + validateIdExists(updateReqVO.getId()); + + PayslipDO updateObj = BeanUtils.toBean(updateReqVO, PayslipDO.class); + payslipMapper.updateById(updateObj); + } + + @Override + public PayslipDO getPayslip(Long id) { + + return payslipMapper.selectById(id); + } + + @Override + public PageResult getPage(PayslipPageReqVO pageReqVO) { + + return payslipMapper.selectPage(pageReqVO); + } + + @Override + public PageResult getMyPage(PayslipPageReqVO pageReqVO) { + + return payslipMapper.selectMyPage(pageReqVO, getLoginUserId()); + } + + @Override + @Transactional(rollbackFor = Exception.class) // 添加事务,异常则回滚所有导入 + public void importPayslip(List importList, String date, Long deptId, Boolean isUpdate) { + + if (CollUtil.isEmpty(importList)) { + throw exception(PAYSLIP_IMPORT_LIST_IS_EMPTY); + } + + // 判断如果选择覆盖, 则删除原有数据重新插入 + if (isUpdate) { + payslipMapper.deletePayslip(date, deptId); + }else { + Long count = payslipMapper.selectCount(new LambdaQueryWrapperX() + .eq(PayslipDO::getSalaryDate, date) + .eqIfPresent(PayslipDO::getCompanyDeptId, deptId)); + + if (count > 0L) { + throw exception(PAYSLIP_EXISTS); + } + } + + List idCards = convertList(importList, PayslipImportExcelVO::getIdcard); + Map userMap = convertMap(userService.getUserListByIdCard(idCards), AdminUserDO::getIdcard); + + List payslipDOList = new ArrayList<>(); + importList.forEach(data -> { + + PayslipDO payslipDO = new PayslipDO(); + try { + payslipDO.setUserId(userMap.get(data.getIdcard()).getId()); + payslipDO.setDeptId(userMap.get(data.getIdcard()).getDeptId()); + } catch (Exception e) { + throw exception(PAYSLIP_ID_CARD_ERROR, data.getNickname()); + } + payslipDO.setCompanyDeptId(deptId); + payslipDO.setSalary(data.getSalary()); + payslipDO.setSalaryDate(date); + payslipDO.setBankName(data.getBankName()); + payslipDO.setBankNo(data.getBankNo()); + payslipDO.setRemark(data.getRemark()); + + /* begin 设置明细数据 */ + List details = new ArrayList<>(); + PayslipDetail detail = new PayslipDetail(); + // 设置类型名称 + detail.setName("月总收入"); + // 设置明细数据 + List detailList = new ArrayList<>(); + // 基本工资 + detailList.add(new PayslipDetail() + .setCode("jbgz") + .setName("基本工资") + .setValue(data.getJbgz())); + // 防暑降温费 + detailList.add(new PayslipDetail() + .setCode("fsjwf") + .setName("防暑降温费") + .setValue(data.getFsjwf())); + // 误餐补助 + detailList.add(new PayslipDetail() + .setCode("wcbz") + .setName("防暑降温费") + .setValue(data.getWcbz())); + // 福利费 + detailList.add(new PayslipDetail() + .setCode("flf") + .setName("福利费") + .setValue(data.getFlf())); + + // 设置大类数据 + detail.setChildren(detailList); + details.add(detail); + + // 设置合计数据 + details.add(new PayslipDetail() + .setCode("sum") + .setName("合计") + .setValue(data.getSum())); + + // 设置试用期工资数据 + details.add(new PayslipDetail() + .setCode("syqgz") + .setName("试用期工资") + .setValue(data.getSyqgz())); + + // 设置试用期工资数据 + details.add(new PayslipDetail() + .setCode("yfgz") + .setName("应发工资") + .setValue(data.getYfgz())); + + // 设置代扣代缴项数据 + detailList = new ArrayList<>(); + detailList.add(new PayslipDetail() + .setCode("ylbx") + .setName("养老") + .setValue(data.getYlbx())); + detailList.add(new PayslipDetail() + .setCode("sybx") + .setName("失业") + .setValue(data.getSybx())); + detailList.add(new PayslipDetail() + .setCode("yb") + .setName("医保") + .setValue(data.getYb())); + detailList.add(new PayslipDetail() + .setCode("deyl") + .setName("大额医疗") + .setValue(data.getDeyl())); + details.add(new PayslipDetail() + .setName("代扣代缴项") + .setChildren(detailList)); + + // 设置代缴合计数据 + details.add(new PayslipDetail() + .setCode("djSum") + .setName("代缴合计") + .setValue(data.getDjSum())); + + // 设置公积金数据 + details.add(new PayslipDetail() + .setCode("gjj") + .setName("公积金") + .setValue(data.getGjj())); + + // 设置个税数据 + details.add(new PayslipDetail() + .setCode("gs") + .setName("个税") + .setValue(data.getGs())); + /* end */ + payslipDO.setDetails(details); + + payslipDOList.add(payslipDO); + }); + + // 批量插入 + payslipMapper.insertBatch(payslipDOList); + } + + @Override + public void issuedPayslip(PayslipPageReqVO updateReqVO) { + + List deptIds = convertList(deptService.getChildDept(updateReqVO.getDeptId()), DeptDO::getId); + + // 更新工资条状态 为待确认中 + payslipMapper.update(new PayslipDO().setIsConfirm(0), new LambdaQueryWrapperX() + .eq(PayslipDO::getSalaryDate, updateReqVO.getDate()) + .inIfPresent(PayslipDO::getDeptId, deptIds) + .isNull(PayslipDO::getIsConfirm)); + } + + @Override + public void exportList(HttpServletResponse response, PayslipPageReqVO exportReqVO) { + + try { + + // 获取工资条列表 + List list = new ArrayList<>(); + if (exportReqVO.getDeptId() != null) { + list = BeanUtils.toBean(getPage(exportReqVO).getList(), PayslipRespVO.class); + }else { + list = BeanUtils.toBean(getMyPage(exportReqVO).getList(), PayslipRespVO.class); + } + + if (CollUtil.isEmpty(list)) { + return; + } + + // 获取用户详情 + List userIds = convertList(list, PayslipRespVO::getUserId); + Map userMap = convertMap(userService.getUserList(userIds), AdminUserDO::getId); + + List> data = new ArrayList<>(); + int count = 1; + for (PayslipRespVO payslipRespVO : list) { + + List row = new ArrayList<>(); + row.add(String.valueOf(count++)); + row.add(payslipRespVO.getUserName()); + row.add(userMap.get(payslipRespVO.getUserId()).getIdcard()); + + Map detailMap = payslipRespVO.getDetails().stream() + .map(item -> { + List children = new ArrayList<>(); + if (item.getChildren() != null) { + children.addAll(item.getChildren()); + }else { + children.add(item); + } + return children.stream().collect(Collectors.toMap(PayslipDetail::getCode, PayslipDetail::getValue)); + }) + .flatMap(map -> map.entrySet().stream()) // 将每个 Map 转换为 Entry 流 + .collect(Collectors.toMap( + Map.Entry::getKey, // 使用 Entry 的 key + Map.Entry::getValue, // 使用 Entry 的 value + (existing, replacement) -> existing // 处理键冲突,保留现有值 + ));; + + row.add(detailMap.get("jbgz").toString()); + row.add(detailMap.get("fsjwf").toString()); + row.add(detailMap.get("wcbz").toString()); + row.add(detailMap.get("flf").toString()); + row.add(detailMap.get("sum").toString()); + row.add(detailMap.get("syqgz").toString()); + row.add(detailMap.get("yfgz").toString()); + row.add(detailMap.get("ylbx").toString()); + row.add(detailMap.get("sybx").toString()); + row.add(detailMap.get("yb").toString()); + row.add(detailMap.get("deyl").toString()); + row.add(detailMap.get("djSum").toString()); + row.add(detailMap.get("gjj").toString()); + row.add(detailMap.get("gs").toString()); + row.add(payslipRespVO.getSalary().toString()); + row.add(payslipRespVO.getBankName()); + row.add(payslipRespVO.getBankNo()); + row.add(payslipRespVO.getRemark()); + row.add(payslipRespVO.getSignURL()); + + data.add(row); + } + + // 获取公司信息 + DeptDO deptDO = deptService.getDept(exportReqVO.getDeptId()); + + String headTitle = deptDO.getName() + exportReqVO.getDate() + "工资条"; + EasyExcel.write(response.getOutputStream()) + .head(getHead(headTitle, list.get(0))) + .autoCloseStream(false) + .excelType(ExcelTypeEnum.XLS) + .registerWriteHandler(new CustomCellStyleHandler()) + .sheet("工资条") + .doWrite(data); + response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("工资条", StandardCharsets.UTF_8.name())); + response.setContentType("application/vnd.ms-excel;charset=UTF-8"); + + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private List> getHead(String headTitle, PayslipRespVO payslipRespVO) { + + List> head = new ArrayList<>(); + head.add(Arrays.asList(headTitle, "序号", "序号")); + head.add(Arrays.asList(headTitle, "姓名", "姓名")); + head.add(Arrays.asList(headTitle, "身份证号码", "身份证号码")); + for (PayslipDetail detail : payslipRespVO.getDetails()) { + + if (detail.getChildren() == null) { + head.add(Arrays.asList(headTitle, detail.getName(), detail.getName())); + }else { + + for (PayslipDetail child : detail.getChildren()) { + + head.add(Arrays.asList(headTitle, detail.getName(), child.getName())); + } + } + } + head.add(Arrays.asList(headTitle, "实发工资", "实发工资")); + head.add(Arrays.asList(headTitle, "开户行", "开户行")); + head.add(Arrays.asList(headTitle, "卡号", "卡号")); + head.add(Arrays.asList(headTitle, "备注", "备注")); + head.add(Arrays.asList(headTitle, "签名", "签名")); + + return head; + } + + private void validateIdExists(Long id) { + if (payslipMapper.selectById(id) == null) { + throw exception(PAYSLIP_NOT_EXISTS); + } + } +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/type/SalaryTypeItemService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/type/SalaryTypeItemService.java new file mode 100644 index 00000000..57201dfd --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/type/SalaryTypeItemService.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.system.service.hr.type; + +import cn.iocoder.yudao.module.system.controller.admin.hr.vo.type.SalaryTypeItemCreateReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.hr.SalaryTypeItemDO; + +import java.util.List; + +/** + * 工资类型配置 Service 接口 + * + * @author 符溶馨 + */ +public interface SalaryTypeItemService { + + /** + * 创建工资类型配置 + * @param createReqVO 创建信息 + * @return 工资类型配置编号 + */ + Long createSalaryTypeItem(SalaryTypeItemCreateReqVO createReqVO); + + /** + * 更新工资类型配置 + * @param updateReqVO 更新信息 + */ + void updateSalaryTypeItem(SalaryTypeItemCreateReqVO updateReqVO); + + /** + * 更新工资类型配置状态 + * @param id 工资类型配置编号 + * @param status 状态值 + */ + void updateSalaryTypeItemStatus(Long id, Integer status); + + /** + * 更新工资类型配置状态 + * @param typeId 工资类型编号 + * @param status 状态值 + */ + void updateStatusByTypeId(Long typeId, Integer status); + + /** + * 获得工资类型配置 + * @param id 工资类型配置编号 + * @return 工资类型配置 + */ + SalaryTypeItemDO getSalaryTypeItem(Long id); + + /** + * 获得指定的工资类型配置 + * @return 工资类型配置列表 + */ + List getListByTypeId(Long typeId); +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/type/SalaryTypeItemServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/type/SalaryTypeItemServiceImpl.java new file mode 100644 index 00000000..b6a9bc93 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/type/SalaryTypeItemServiceImpl.java @@ -0,0 +1,105 @@ +package cn.iocoder.yudao.module.system.service.hr.type; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +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.hr.vo.type.SalaryTypeItemCreateReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.hr.SalaryTypeItemDO; +import cn.iocoder.yudao.module.system.dal.mysql.hr.SalaryTypeItemMapper; +import org.springframework.stereotype.Service; + +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.*; + +@Service +public class SalaryTypeItemServiceImpl implements SalaryTypeItemService{ + + @Resource + private SalaryTypeItemMapper salaryTypeItemMapper; + + @Override + public Long createSalaryTypeItem(SalaryTypeItemCreateReqVO createReqVO) { + + // 校验code的唯一性 + validateTypeCodeExists(null, createReqVO.getCode()); + + SalaryTypeItemDO itemDO = BeanUtils.toBean(createReqVO, SalaryTypeItemDO.class); + itemDO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + + // 插入 + salaryTypeItemMapper.insert(itemDO); + return itemDO.getId(); + } + + @Override + public void updateSalaryTypeItem(SalaryTypeItemCreateReqVO updateReqVO) { + + validateTypeItemExists(updateReqVO.getId()); + // 校验code的唯一性 + validateTypeCodeExists(updateReqVO.getId(), updateReqVO.getCode()); + + SalaryTypeItemDO updateObj = BeanUtils.toBean(updateReqVO, SalaryTypeItemDO.class); + salaryTypeItemMapper.updateById(updateObj); + } + + @Override + public void updateSalaryTypeItemStatus(Long id, Integer status) { + + validateTypeItemExists(id); + + SalaryTypeItemDO itemDO = new SalaryTypeItemDO() + .setId(id) + .setStatus(status); + + salaryTypeItemMapper.updateById(itemDO); + } + + @Override + public void updateStatusByTypeId(Long typeId, Integer status) { + + salaryTypeItemMapper.update(new SalaryTypeItemDO().setStatus(status), new LambdaQueryWrapperX() + .eq(SalaryTypeItemDO::getTypeId, typeId)); + } + + @Override + public SalaryTypeItemDO getSalaryTypeItem(Long id) { + + return salaryTypeItemMapper.selectById(id); + } + + @Override + public List getListByTypeId(Long typeId) { + + return salaryTypeItemMapper.selectList(SalaryTypeItemDO::getTypeId, typeId); + } + + private void validateTypeItemExists(Long id) { + if (salaryTypeItemMapper.selectById(id) == null) { + throw exception(SALARY_TYPE_ITEM_NOT_EXISTS); + } + } + + private void validateTypeCodeExists(Long id, String code) { + + if (StrUtil.isBlank(code)) { + return; + } + + // 校验类型名称唯一性 + SalaryTypeItemDO itemDO = salaryTypeItemMapper.selectOne(SalaryTypeItemDO::getCode, code); + if (itemDO == null) { + return; + } + if (id == null) { + throw exception(SALARY_TYPE_ITEM_CODE_EXISTS); + } + if (!itemDO.getId().equals(id)) { + throw exception(SALARY_TYPE_ITEM_CODE_EXISTS); + } + } +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/type/SalaryTypeService.java similarity index 55% rename from yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeService.java rename to yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/type/SalaryTypeService.java index d47d0ae4..497216bf 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/SalaryTypeService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/type/SalaryTypeService.java @@ -1,5 +1,7 @@ -package cn.iocoder.yudao.module.system.service.hr; +package cn.iocoder.yudao.module.system.service.hr.type; +import cn.iocoder.yudao.module.system.controller.admin.hr.vo.type.SalaryTypeCreateReqVO; +import cn.iocoder.yudao.module.system.controller.admin.hr.vo.type.SalaryTypeUpdateSortVO; import cn.iocoder.yudao.module.system.dal.dataobject.hr.SalaryTypeDO; import java.util.List; @@ -13,17 +15,16 @@ public interface SalaryTypeService { /** * 创建工资类型 - * @param name 类型名称 + * @param createReqVO 创建信息 * @return 类型编号 */ - Long createSalaryType(String name); + Long createSalaryType(SalaryTypeCreateReqVO createReqVO); /** * 更新工资类型 - * @param id 类型编号 - * @param name 类型名称 + * @param updateReqVO 更新信息 */ - void updateSalaryType(Long id, String name); + void updateSalaryType(SalaryTypeCreateReqVO updateReqVO); /** * 更新工资类型状态 @@ -44,4 +45,10 @@ public interface SalaryTypeService { * @return 工资类型列表 */ List getSalaryTypeList(); + + /** + * 更新工资类型排序 + * @param updateSortVO 更新信息 + */ + void updateSort(List updateSortVO); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/type/SalaryTypeServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/type/SalaryTypeServiceImpl.java new file mode 100644 index 00000000..e516de42 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/hr/type/SalaryTypeServiceImpl.java @@ -0,0 +1,110 @@ +package cn.iocoder.yudao.module.system.service.hr.type; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +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.hr.vo.type.SalaryTypeCreateReqVO; +import cn.iocoder.yudao.module.system.controller.admin.hr.vo.type.SalaryTypeUpdateSortVO; +import cn.iocoder.yudao.module.system.dal.dataobject.hr.SalaryTypeDO; +import cn.iocoder.yudao.module.system.dal.mysql.hr.SalaryTypeMapper; +import org.springframework.stereotype.Service; + +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.SALARY_TYPE_NAME_EXISTS; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SALARY_TYPE_NOT_EXISTS; + +@Service +public class SalaryTypeServiceImpl implements SalaryTypeService{ + + @Resource + private SalaryTypeMapper salaryTypeMapper; + + @Resource + private SalaryTypeItemService salaryTypeItemService; + + @Override + public Long createSalaryType(SalaryTypeCreateReqVO createReqVO) { + + // 校验类型名称唯一性 + validateTypeNameExists(null, createReqVO.getName()); + + SalaryTypeDO salaryTypeDO = BeanUtils.toBean(createReqVO, SalaryTypeDO.class) + .setStatus(CommonStatusEnum.ENABLE.getStatus()); + + salaryTypeMapper.insert(salaryTypeDO); + return salaryTypeDO.getId(); + } + + @Override + public void updateSalaryType(SalaryTypeCreateReqVO updateReqVO) { + + validateTypeExists(updateReqVO.getId()); + validateTypeNameExists(updateReqVO.getId(), updateReqVO.getName()); + + SalaryTypeDO salaryTypeDO = BeanUtils.toBean(updateReqVO, SalaryTypeDO.class); + salaryTypeMapper.updateById(salaryTypeDO); + } + + @Override + public void updateSalaryTypeStatus(Long id, Integer status) { + + validateTypeExists(id); + + SalaryTypeDO salaryTypeDO = new SalaryTypeDO() + .setId(id) + .setStatus(status); + + salaryTypeMapper.updateById(salaryTypeDO); + + // 同步更新 类型配置状态 + salaryTypeItemService.updateStatusByTypeId(id, status); + } + + private void validateTypeExists(Long id) { + if (salaryTypeMapper.selectById(id) == null) { + throw exception(SALARY_TYPE_NOT_EXISTS); + } + } + + private void validateTypeNameExists(Long id, String name) { + + if (StrUtil.isBlank(name)) { + return; + } + + // 校验类型名称唯一性 + SalaryTypeDO salaryTypeDO = salaryTypeMapper.selectOne(SalaryTypeDO::getName, name); + if (salaryTypeDO == null) { + return; + } + if (id == null) { + throw exception(SALARY_TYPE_NAME_EXISTS); + } + if (!salaryTypeDO.getId().equals(id)) { + throw exception(SALARY_TYPE_NAME_EXISTS); + } + } + + @Override + public SalaryTypeDO getSalaryType(Long id) { + + return salaryTypeMapper.selectById(id); + } + + @Override + public List getSalaryTypeList() { + + return salaryTypeMapper.selectList(new LambdaQueryWrapperX() + .orderByAsc(SalaryTypeDO::getSort)); + } + + @Override + public void updateSort(List updateSortVO) { + + salaryTypeMapper.updateBatch(BeanUtils.toBean(updateSortVO, SalaryTypeDO.class)); + } +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/hr/PayslipMapper.xml b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/hr/PayslipMapper.xml new file mode 100644 index 00000000..2dd79e8a --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/hr/PayslipMapper.xml @@ -0,0 +1,18 @@ + + + + + + + + delete from hr_payslip + where + salary_date = #{date} + and company_dept_id = #{deptId} + + \ No newline at end of file From e9f1384aee77bdd73063b1ca7d3cc9914b172717 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Fri, 25 Oct 2024 16:30:23 +0800 Subject: [PATCH 20/20] =?UTF-8?q?feat(system):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=B7=A5=E8=B5=84=E6=9D=A1=E8=AF=A6=E6=83=85=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加实发工资、开户行、银行卡号、备注等信息到工资条详情 -增加用户签名图片显示- 优化数据展示结构,提高可读性 --- .../admin/hr/PayslipController.java | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/PayslipController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/PayslipController.java index 10c47dc7..eaa297d0 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/PayslipController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/hr/PayslipController.java @@ -68,7 +68,44 @@ public class PayslipController { @PreAuthorize("@ss.hasPermission('system:hr:payslip:query')") public CommonResult getPayslip(@RequestParam("id") Long id) { - return success(BeanUtils.toBean(payslipService.getPayslip(id), PayslipRespVO.class)); + PayslipRespVO data = BeanUtils.toBean(payslipService.getPayslip(id), PayslipRespVO.class); + List details = data.getDetails(); + // 设置实发工资 + details.add(new PayslipDetail() + .setCode("salary") + .setName("实发工资") + .setValue(data.getSalary())); + + // 设置开户行 + details.add(new PayslipDetail() + .setCode("bankName") + .setName("开户行") + .setValue(data.getBankName())); + + // 设置银行卡号 + details.add(new PayslipDetail() + .setCode("bankNo") + .setName("卡号") + .setValue(data.getBankNo())); + + // 设置备注 + details.add(new PayslipDetail() + .setCode("remark") + .setName("备注") + .setValue(data.getRemark())); + + if (data.getIsConfirm() != null && data.getIsConfirm() == 1) { + data.setSignURL(fileApi.getUserSignImgPath(data.getUserId()).getData()); + } + + // 设置签名 + details.add(new PayslipDetail() + .setCode("signURL") + .setName("签名") + .setValue(data.getSignURL())); + data.setDetails(details); + + return success(data); } @PostMapping("/Page")