From 7495611493b4a5291a720c7740dbcd78ec897324 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Fri, 16 Aug 2024 22:49:13 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E6=92=A4=E9=94=80=E7=9B=91=E6=8E=A7?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/admin/hik/HikController.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/zn-module-smartfactory/zn-module-smartfactory-biz/src/main/java/cn/iocoder/yudao/module/smartfactory/controller/admin/hik/HikController.java b/zn-module-smartfactory/zn-module-smartfactory-biz/src/main/java/cn/iocoder/yudao/module/smartfactory/controller/admin/hik/HikController.java index f8f8da5a..fab768b7 100644 --- a/zn-module-smartfactory/zn-module-smartfactory-biz/src/main/java/cn/iocoder/yudao/module/smartfactory/controller/admin/hik/HikController.java +++ b/zn-module-smartfactory/zn-module-smartfactory-biz/src/main/java/cn/iocoder/yudao/module/smartfactory/controller/admin/hik/HikController.java @@ -7,12 +7,12 @@ import cn.iocoder.yudao.module.smartfactory.controller.admin.hik.vo.CameraReplay import cn.iocoder.yudao.module.smartfactory.service.hik.HikService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; +import javax.annotation.security.PermitAll; /** * 工厂管理-工厂列表 @@ -29,8 +29,8 @@ public class HikController { @GetMapping("/getCameraUrl") @Operation(summary = "视频播放->查询播放地址") - @PreAuthorize("@ss.hasPermission('smartfactory:camera:view')") -// @PermitAll +// @PreAuthorize("@ss.hasPermission('smartfactory:camera:view')") + @PermitAll public CommonResult getCameraUrl(String cameraCode) { String url = hikService.getPreviewUrlsApi(cameraCode, 0); return CommonResult.success(url); @@ -38,7 +38,7 @@ public class HikController { @GetMapping("/m-getCameraUrl") @Operation(summary = "视频播放->查询播放地址(微信用)") - @PreAuthorize("@ss.hasPermission('smartfactory:camera:view')") +// @PreAuthorize("@ss.hasPermission('smartfactory:camera:view')") public CommonResult getMCameraUrl(String cameraCode) { String url = hikService.getPreviewUrlsApiHttps(cameraCode); @@ -48,8 +48,8 @@ public class HikController { @GetMapping("/replayUrl") @Operation(summary = "视频播放->回放流") - @PreAuthorize("@ss.hasPermission('smartfactory:camera:view')") -// @PermitAll +// @PreAuthorize("@ss.hasPermission('smartfactory:camera:view')") + @PermitAll public CommonResult getReplayUrl(CameraReplayDTO cameraReplayDTO) { JSONObject replayUrl = hikService.getReplayUrl(cameraReplayDTO); return CommonResult.success(replayUrl); @@ -57,8 +57,8 @@ public class HikController { @GetMapping("/operate") @Operation(summary = "视频->云台操作") - @PreAuthorize("@ss.hasPermission('smartfactory:camera:view')") -// @PermitAll +// @PreAuthorize("@ss.hasPermission('smartfactory:camera:view')") + @PermitAll public CommonResult operate(CameraOperateDTO dto) { String msg = hikService.operateCamera(dto); From 8db27dd8d9e3ee5d9b201952f2cf8c836610c389 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Fri, 16 Aug 2024 23:15:15 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=A4=A7=E5=B1=8F=20=E5=8F=AA=E6=9F=A5=E8=AF=A2=E5=B7=A5?= =?UTF-8?q?=E5=8E=82=20=E5=8E=BB=E9=99=A4=E5=AD=90=E5=85=AC=E5=8F=B8?= =?UTF-8?q?=E3=80=81=E6=80=BB=E5=85=AC=E5=8F=B8=E6=9F=A5=E8=AF=A2=20?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=20=E5=B7=A5=E5=8E=82=E7=9B=91=E6=8E=A7?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E6=9F=A5=E8=AF=A2=E5=BC=80=E5=90=AF=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E4=B8=94=E5=9C=A8=E5=A4=A7=E5=B1=8F=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E7=9A=84=20=E6=91=84=E5=83=8F=E5=A4=B4=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dal/mysql/device/cameradevice/CameraDeviceMapper.java | 7 +++++++ .../device/cameradevice/CameraDeviceServiceImpl.java | 2 +- .../service/factoryinfo/FactoryInfoServiceImpl.java | 4 ++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/zn-module-smartfactory/zn-module-smartfactory-biz/src/main/java/cn/iocoder/yudao/module/smartfactory/dal/mysql/device/cameradevice/CameraDeviceMapper.java b/zn-module-smartfactory/zn-module-smartfactory-biz/src/main/java/cn/iocoder/yudao/module/smartfactory/dal/mysql/device/cameradevice/CameraDeviceMapper.java index 1e3262e7..e49ef702 100644 --- a/zn-module-smartfactory/zn-module-smartfactory-biz/src/main/java/cn/iocoder/yudao/module/smartfactory/dal/mysql/device/cameradevice/CameraDeviceMapper.java +++ b/zn-module-smartfactory/zn-module-smartfactory-biz/src/main/java/cn/iocoder/yudao/module/smartfactory/dal/mysql/device/cameradevice/CameraDeviceMapper.java @@ -34,4 +34,11 @@ public interface CameraDeviceMapper extends BaseMapperX { .inIfPresent(CameraDeviceDO::getFactoryId, factoryIds) .eq(CameraDeviceDO::getStatus, CommonStatusEnum.ENABLE.getStatus())); } + + default List selectListCameraByFactoryId(Long factoryId) { + return selectList(new LambdaQueryWrapperX() + .eq(CameraDeviceDO::getFactoryId, factoryId) + .eq(CameraDeviceDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) + .eq(CameraDeviceDO::getIsShow, 1)); + } } \ No newline at end of file diff --git a/zn-module-smartfactory/zn-module-smartfactory-biz/src/main/java/cn/iocoder/yudao/module/smartfactory/service/device/cameradevice/CameraDeviceServiceImpl.java b/zn-module-smartfactory/zn-module-smartfactory-biz/src/main/java/cn/iocoder/yudao/module/smartfactory/service/device/cameradevice/CameraDeviceServiceImpl.java index e22010f1..42bc563f 100644 --- a/zn-module-smartfactory/zn-module-smartfactory-biz/src/main/java/cn/iocoder/yudao/module/smartfactory/service/device/cameradevice/CameraDeviceServiceImpl.java +++ b/zn-module-smartfactory/zn-module-smartfactory-biz/src/main/java/cn/iocoder/yudao/module/smartfactory/service/device/cameradevice/CameraDeviceServiceImpl.java @@ -73,7 +73,7 @@ public class CameraDeviceServiceImpl implements CameraDeviceService { @Override public List getListCameraByFactoryId(Long factoryId) { - return cameraDeviceMapper.selectList(CameraDeviceDO::getFactoryId, factoryId); + return cameraDeviceMapper.selectListCameraByFactoryId(factoryId); } @Override diff --git a/zn-module-smartfactory/zn-module-smartfactory-biz/src/main/java/cn/iocoder/yudao/module/smartfactory/service/factoryinfo/FactoryInfoServiceImpl.java b/zn-module-smartfactory/zn-module-smartfactory-biz/src/main/java/cn/iocoder/yudao/module/smartfactory/service/factoryinfo/FactoryInfoServiceImpl.java index 9e2e245e..8f5ed3d8 100644 --- a/zn-module-smartfactory/zn-module-smartfactory-biz/src/main/java/cn/iocoder/yudao/module/smartfactory/service/factoryinfo/FactoryInfoServiceImpl.java +++ b/zn-module-smartfactory/zn-module-smartfactory-biz/src/main/java/cn/iocoder/yudao/module/smartfactory/service/factoryinfo/FactoryInfoServiceImpl.java @@ -164,8 +164,8 @@ public class FactoryInfoServiceImpl implements FactoryInfoService { Area area = AreaUtils.getArea(Integer.valueOf(code)); List vos = new ArrayList<>(); LambdaQueryWrapperX lambdaQueryWrapperX = new LambdaQueryWrapperX(); - //去除中鼐总部 - lambdaQueryWrapperX.ne(FactoryInfoDO::getId, 1L); + // 只查询 type为工厂类型的 工厂信息 + lambdaQueryWrapperX.eq(FactoryInfoDO::getType, 3L); //去除关闭状态工厂 lambdaQueryWrapperX.eq(FactoryInfoDO::getStatus, CommonStatusEnum.ENABLE.getStatus()); From 21f034d94c43b3323193a23671823c14f1d80d7a Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Sun, 18 Aug 2024 15:39:53 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=8E=B0=E9=87=91?= =?UTF-8?q?=E6=94=AF=E5=87=BA=EF=BC=8C=20=E8=BF=BD=E5=8A=A0=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E6=98=8E=E7=BB=86=E5=8A=9F=E8=83=BD=20=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E6=8A=A5=E9=94=80=E6=B5=81=E7=A8=8B=E6=89=93=E5=8D=B0?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=8C=20=E6=A0=B9=E6=8D=AE=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E6=96=87=E4=BB=B6=E5=88=A4=E6=96=AD=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E8=BF=87=E6=BB=A4=20=E5=A4=96=E8=81=98=E4=BA=BA=E5=91=98?= =?UTF-8?q?=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/oa/BpmOACashController.java | 25 ++++++- .../oa/vo/cash/BpmOACashCreateReqVO.java | 36 ++-------- .../admin/oa/vo/cash/BpmOACashRespVO.java | 36 ++-------- .../bpm/controller/admin/oa/vo/cash/Cash.java | 51 ++++++++++++++ .../oa/vo/print/BpmOACashPrintDataRespVO.java | 43 ++++++++++++ .../BpmProcessInstancePrintDataRespVO.java | 5 +- .../bpm/convert/oa/BpmOACashConvert.java | 44 ++++++++++++ .../bpm/dal/dataobject/oa/BpmOACashDO.java | 37 ---------- .../dal/dataobject/oa/BpmOACashItemDO.java | 70 +++++++++++++++++++ .../bpm/dal/mysql/oa/BpmOACashItemMapper.java | 15 ++++ .../rpc/config/RpcConfiguration.java | 4 +- .../bpm/service/oa/BpmOACashService.java | 9 +++ .../bpm/service/oa/BpmOACashServiceImpl.java | 58 ++++++++++++--- .../task/BpmProcessInstanceServiceImpl.java | 2 +- .../yudao/module/system/api/bank/BankApi.java | 23 ++++++ .../system/api/bank/dto/BankRespDTO.java | 21 ++++++ .../module/system/api/user/AdminUserApi.java | 5 ++ .../module/system/api/bank/BankApiImpl.java | 28 ++++++++ .../system/api/user/AdminUserApiImpl.java | 8 +++ .../dal/dataobject/user/AdminUserDO.java | 7 ++ .../system/service/user/AdminUserService.java | 6 ++ .../service/user/AdminUserServiceImpl.java | 6 ++ 22 files changed, 427 insertions(+), 112 deletions(-) create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/cash/Cash.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/print/BpmOACashPrintDataRespVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOACashItemDO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOACashItemMapper.java create mode 100644 yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/bank/BankApi.java create mode 100644 yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/bank/dto/BankRespDTO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/bank/BankApiImpl.java diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOACashController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOACashController.java index b0b6191c..080b37a3 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOACashController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOACashController.java @@ -5,7 +5,12 @@ import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.cash.BpmOACashCreateRe import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.cash.BpmOACashRespVO; import cn.iocoder.yudao.module.bpm.convert.oa.BpmOACashConvert; 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.service.oa.BpmOACashService; +import cn.iocoder.yudao.module.system.api.bank.BankApi; +import cn.iocoder.yudao.module.system.api.bank.dto.BankRespDTO; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -14,8 +19,11 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.validation.Valid; +import java.util.List; +import java.util.Map; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; /** @@ -33,6 +41,12 @@ public class BpmOACashController { @Resource private BpmOACashService cashService; + @Resource + private DeptApi deptApi; + + @Resource + private BankApi bankApi; + @PostMapping("/create") @Operation(summary = "创建请求申请") public CommonResult createCash(@Valid @RequestBody BpmOACashCreateReqVO createReqVO) { @@ -47,6 +61,15 @@ public class BpmOACashController { BpmOACashDO cash = cashService.getCash(id); - return success(BpmOACashConvert.INSTANCE.convert(cash)); + // 获取明细数据 + List cashItemDOs = cashService.getCashItem(cash.getId()); + + //获取部门信息map + Map deptMap = deptApi.getDeptMap(convertSet(cashItemDOs, BpmOACashItemDO::getDeptId)); + + // 获取银行卡信息 + BankRespDTO bankRespDTO = bankApi.getBank(cash.getBankId()).getCheckedData(); + + return success(BpmOACashConvert.INSTANCE.convert1(cash, cashItemDOs, deptMap, bankRespDTO)); } } 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 c96bf868..c48d84d5 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 @@ -5,15 +5,11 @@ 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.time.LocalDate; import java.util.List; -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; - /** * 现金支出 创建 Request VO * @@ -25,35 +21,15 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @ToString(callSuper = true) public class BpmOACashCreateReqVO { - @Schema(description = "申请事由", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "申请事由不能为空") - private String reason; - - @Schema(description = "费用类型 | 字典值参照bpm_oa_cash_type", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "费用类型不能为空") - private Integer type; - - @Schema(description = "费用产生部门", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "费用产生部门不能为空") - private Long deptId; - - @Schema(description = "采购申请编号") - private Long procureId; - - @Schema(description = "支出金额", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "申请金额不能为空") - private BigDecimal totalMoney; - - @Schema(description = "申请日期", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "申请日期不能为空") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) - private LocalDate applicationDate; - @Schema(description = "收款人信息") private Long bankId; - @Schema(description = "备注说明", requiredMode = Schema.RequiredMode.NOT_REQUIRED) - private String notes; + @Schema(description = "现金支出明细") + private List cashItem; + + @Schema(description = "报销总金额", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "报销总金额不能为空") + private BigDecimal totalMoney; @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/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 6ce053d9..d1aba2c2 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 @@ -6,15 +6,10 @@ 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.time.LocalDate; import java.util.List; -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; - /** * @author 符溶馨 */ @@ -24,28 +19,8 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @ToString(callSuper = true) public class BpmOACashRespVO extends BpmOABaseRespVO { - @Schema(description = "申请事由", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "申请事由不能为空") - private String reason; - - @Schema(description = "费用类型 | 字典值参照bpm_oa_cash_type", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "费用类型不能为空") - private Integer type; - - @Schema(description = "部门名称") - private String deptName; - - @Schema(description = "采购申请编号") - private Long procureId; - - @Schema(description = "支出金额", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "申请金额不能为空") - private BigDecimal totalMoney; - - @Schema(description = "申请日期", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "申请日期不能为空") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) - private LocalDate applicationDate; + @Schema(description = "收款人信息编号") + private Long bankId; @Schema(description = "收款人名称") private String payeeName; @@ -56,8 +31,11 @@ public class BpmOACashRespVO extends BpmOABaseRespVO { @Schema(description = "开户行名称") private String bankName; - @Schema(description = "备注说明", requiredMode = Schema.RequiredMode.NOT_REQUIRED) - private String notes; + @Schema(description = "现金支出明细") + private List cashItem; + + @Schema(description = "报销总金额") + private BigDecimal totalMoney; @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/cash/Cash.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/cash/Cash.java new file mode 100644 index 00000000..06a80b81 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/cash/Cash.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.cash; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDate; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; + +/** + * 功能描述 现金支出项目明细 + */ +@Data +public class Cash { + + @Schema(description = "id") + private Long id; + + @Schema(description = "申请事由", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "申请事由不能为空") + private String reason; + + @Schema(description = "费用类型 | 字典值参照bpm_oa_cash_type", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "费用类型不能为空") + private Integer type; + + @Schema(description = "费用产生部门", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "费用产生部门不能为空") + private Long deptId; + + @Schema(description = "费用产生部门名称") + private String deptName; + + @Schema(description = "采购申请编号") + private Long procureId; + + @Schema(description = "支出金额", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "申请金额不能为空") + private BigDecimal totalMoney; + + @Schema(description = "申请日期", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "申请日期不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + private LocalDate applicationDate; + + @Schema(description = "备注") + private String notes; +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/print/BpmOACashPrintDataRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/print/BpmOACashPrintDataRespVO.java new file mode 100644 index 00000000..ae3025a2 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/print/BpmOACashPrintDataRespVO.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print; + +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOABaseRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.cash.BpmOACashRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.List; + +@Schema(description = "管理后台 - 现金支出打印数回数据 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmOACashPrintDataRespVO extends BpmOABaseRespVO { + + @Schema(description = "现金支出业务数据", requiredMode = Schema.RequiredMode.REQUIRED) + private BpmOACashRespVO bpmOACashRespVO ; + + @Schema(description = "流程审批节点信息【包含人员签名地址】", requiredMode = Schema.RequiredMode.REQUIRED) + List processTasks ; + + /** + * 抄送用户信息 + */ + private List ccUsers; + + @Schema(description = "抄送用户信息") + @Data + public static class CCUser { + + @Schema(description = "抄送用户编号", example = "146,128") + private Long ccUserId; + + @Schema(description = "抄送用户名称", example = "张三") + private String ccUserName; + + @Schema(description = "抄送用户部门名称", example = "研发部") + private String ccDeptName; + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/print/BpmProcessInstancePrintDataRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/print/BpmProcessInstancePrintDataRespVO.java index 718b481e..1f130cd9 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/print/BpmProcessInstancePrintDataRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/print/BpmProcessInstancePrintDataRespVO.java @@ -1,12 +1,9 @@ package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print; -import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.BpmOAReimbursementRespVO; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.ToString; -import javax.validation.constraints.NotEmpty; - @Schema(description = "管理后台 - 流程打印响应数据 Item Response VO") @Data @ToString(callSuper = true) @@ -21,4 +18,6 @@ public class BpmProcessInstancePrintDataRespVO { @Schema(description = "报销业务打印数据", requiredMode = Schema.RequiredMode.REQUIRED) private BpmOAReimbursementPrintDataRespVO bpmOAReimbursementPrintDataRespVO ; + @Schema(description = "现金支出业务打印数据", requiredMode = Schema.RequiredMode.REQUIRED) + private BpmOACashPrintDataRespVO bpmOACashPrintDataRespVO; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/oa/BpmOACashConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/oa/BpmOACashConvert.java index bbfa6b12..f4677292 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/oa/BpmOACashConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/oa/BpmOACashConvert.java @@ -1,11 +1,20 @@ package cn.iocoder.yudao.module.bpm.convert.oa; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.cash.BpmOACashCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.cash.BpmOACashRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.cash.Cash; 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.system.api.bank.dto.BankRespDTO; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; +import java.util.List; +import java.util.Map; + /** * 现金支出 Convert * @@ -19,4 +28,39 @@ public interface BpmOACashConvert { BpmOACashDO convert(BpmOACashCreateReqVO bean); BpmOACashRespVO convert(BpmOACashDO bean); + + default BpmOACashRespVO convert1(BpmOACashDO cashDO, List cashItemDOs, + Map deptMap, BankRespDTO bankRespDTO) { + + BpmOACashRespVO respVO = BeanUtils.toBean(cashDO, BpmOACashRespVO.class); + + List cashItems = BeanUtils.toBean(cashItemDOs, Cash.class); + if (deptMap != null) { + + cashItems = convertList(cashItems, deptMap); + } + + if (bankRespDTO != null) { + respVO.setBankNo(bankRespDTO.getBankNo()); + respVO.setBankName(bankRespDTO.getBankName()); + respVO.setPayeeName(bankRespDTO.getNickname()); + } + + respVO.setCashItem(cashItems); + return respVO; + } + + default List convertList(List list, Map deptMap) { + + return CollectionUtils.convertList(list, cash -> convert(cash, deptMap.get(cash.getDeptId()))); + } + + default Cash convert(Cash cashItem, DeptRespDTO dept) { + + if (dept != null) { + cashItem.setDeptName(dept.getName()); + } + + return cashItem; + } } 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 8a1a2683..23a0620c 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 @@ -9,8 +9,6 @@ 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; /** @@ -40,47 +38,12 @@ public class BpmOACashDO extends BaseDO { */ private Long userId; - /** - * 申请理由 - */ - private String reason; - - /** - * 费用类型 字典值参照 BPM_OA_REIMBURSEMENT_TYPE - */ - private Integer type; - - /** - * 费用产生部门 - */ - private Long deptId; - - /** - * 采购申请 业务编号 - */ - private Long procureId; - - /** - * 现金支出金额 - */ - private BigDecimal totalMoney; - - /** - * 申请日期 - */ - private LocalDate applicationDate; - /** * 收款人信息 * system_bank 编号 */ private Long bankId; - /** - * 备注说明 - */ - private String notes; - /** * 用章的结果 * diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOACashItemDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOACashItemDO.java new file mode 100644 index 00000000..2c237154 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOACashItemDO.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.oa; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDate; + +/** + * OA 现金支出明细 DO + * + * @author 符溶馨 + */ +@TableName(value ="bpm_oa_cash_item", autoResultMap = true) +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmOACashItemDO extends BaseDO { + + /** + * 出差表单主键 + */ + @TableId + private Long id; + + /** + * 现金支出业务编号 + */ + private Long cashId; + + /** + * 申请理由 + */ + private String reason; + + /** + * 费用类型 字典值参照 BPM_OA_REIMBURSEMENT_TYPE + */ + private Integer type; + + /** + * 费用产生部门 + */ + private Long deptId; + + /** + * 采购申请 业务编号 + */ + private Long procureId; + + /** + * 现金支出金额 + */ + private BigDecimal totalMoney; + + /** + * 申请日期 + */ + private LocalDate applicationDate; + + /** + * 备注 + */ + private String notes; +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOACashItemMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOACashItemMapper.java new file mode 100644 index 00000000..f0132bb4 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOACashItemMapper.java @@ -0,0 +1,15 @@ +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.BpmOACashItemDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 现金支出 Mapper + * + * @author 符溶馨 + + */ +@Mapper +public interface BpmOACashItemMapper extends BaseMapperX { +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/config/RpcConfiguration.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/config/RpcConfiguration.java index 3aaeea2a..f2432fab 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/config/RpcConfiguration.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/config/RpcConfiguration.java @@ -1,7 +1,9 @@ package cn.iocoder.yudao.module.bpm.framework.rpc.config; +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.attendance.AttendanceApi; +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.PostApi; import cn.iocoder.yudao.module.system.api.dict.DictDataApi; @@ -17,7 +19,7 @@ import org.springframework.context.annotation.Configuration; @Configuration(proxyBeanMethods = false) @EnableFeignClients(clients = {FileApi.class, RoleApi.class, DeptApi.class, PostApi.class, AdminUserApi.class, SmsSendApi.class, DictDataApi.class, NotifyMessageSendApi.class, - SubscribeMessageSendApi.class, SocialClientApi.class, UsersExtApi.class, AttendanceApi.class + SubscribeMessageSendApi.class, SocialClientApi.class, UsersExtApi.class, AttendanceApi.class, BankApi.class, ConfigApi.class }) public class RpcConfiguration { } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOACashService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOACashService.java index 0e7acc5b..abbc0fa8 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOACashService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOACashService.java @@ -2,8 +2,10 @@ package cn.iocoder.yudao.module.bpm.service.oa; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.cash.BpmOACashCreateReqVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOACashDO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOACashItemDO; import javax.validation.Valid; +import java.util.List; public interface BpmOACashService { @@ -31,4 +33,11 @@ public interface BpmOACashService { * @return 现金支出申请 */ BpmOACashDO getCash(Long id); + + /** + * 获得指定得现金支出明细 + * @param cashId 现金支出 编号 + * @return 明细 + */ + List getCashItem(Long cashId); } 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 5c0cefcf..e1f5c142 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 @@ -1,5 +1,7 @@ package cn.iocoder.yudao.module.bpm.service.oa; +import cn.hutool.core.collection.CollectionUtil; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 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; @@ -7,7 +9,9 @@ import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.procure.BpmOAProcureLi import cn.iocoder.yudao.module.bpm.controller.admin.upload.UploadUserFile; import cn.iocoder.yudao.module.bpm.convert.oa.BpmOACashConvert; 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.mysql.oa.BpmOACashItemMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOACashMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; @@ -18,7 +22,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; -import java.util.Collections; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -44,6 +48,9 @@ public class BpmOACashServiceImpl extends BpmOABaseService implements BpmOACashS @Resource private BpmOACashMapper cashMapper; + @Resource + private BpmOACashItemMapper cashItemMapper; + @Resource private BpmProcessInstanceApi processInstanceApi; @@ -62,6 +69,11 @@ public class BpmOACashServiceImpl extends BpmOABaseService implements BpmOACashS .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); cashMapper.insert(cash) ; + // 批量插入现金支出明细数据 + List bpmOACashItemDOS = BeanUtils.toBean(createReqVO.getCashItem(), BpmOACashItemDO.class); + bpmOACashItemDOS.forEach(item -> item.setCashId(cash.getId())); + cashItemMapper.insertBatch(bpmOACashItemDOS); + // 发起 BPM 流程 Map processInstanceVariables = new HashMap<>(); String processInstanceId = processInstanceApi.createProcessInstance(userId, @@ -71,14 +83,21 @@ public class BpmOACashServiceImpl extends BpmOABaseService implements BpmOACashS // 将工作流的编号,更新到 OA 现金支出单中 cashMapper.updateById(new BpmOACashDO().setId(cash.getId()).setProcessInstanceId(processInstanceId)); - //报销类别为 采购费时 - if (cash.getType() == 4) { + List procureIds = new ArrayList<>(); + for (BpmOACashItemDO cashItemDO : bpmOACashItemDOS) { + //报销类别为 采购费时 + if (cashItemDO.getType() == 4) { + procureIds.add(cashItemDO.getProcureId()); + } + } + + if (!CollectionUtil.isEmpty(procureIds)) { //所有关联的采购申请改为 进行中状态 bpmOAProcureService.updatePayFlagByIds( new BpmOAProcureListEditReqVO() .setPayFlag(BpmOAProcureDO.IN_PROGRESS) - .setProcureIds(Collections.singletonList(cash.getProcureId())) + .setProcureIds(procureIds) ); } @@ -95,6 +114,11 @@ public class BpmOACashServiceImpl extends BpmOABaseService implements BpmOACashS public void updateCashResult(String processInstanceId, Long id, Integer result) { validateLeaveExists(id); + + // 获取现金支出明细 + List cashItemDOs = getCashItem(id); + + List procureIds = new ArrayList<>(); //审核通过 (最后节点) if (BpmProcessInstanceResultEnum.APPROVE.getResult().equals(result)) { @@ -103,16 +127,20 @@ public class BpmOACashServiceImpl extends BpmOABaseService implements BpmOACashS if (instance.isEnded()) { //判断是否有采购报销 - BpmOACashDO cash = getCash(id); + for (BpmOACashItemDO cashItemDO : cashItemDOs) { + if (cashItemDO.getType() == 4) { + procureIds.add(cashItemDO.getProcureId()); + } + } //报销类别为 采购费时 - if (cash.getType() == 4) { + if (!CollectionUtil.isEmpty(procureIds)) { //所有关联的采购申请改为 已支付状态 bpmOAProcureService.updatePayFlagByIds( new BpmOAProcureListEditReqVO() .setPayFlag(BpmOAProcureDO.FLAG_TRUE) - .setProcureIds(Collections.singletonList(cash.getProcureId())) + .setProcureIds(procureIds) ); } } @@ -126,16 +154,20 @@ public class BpmOACashServiceImpl extends BpmOABaseService implements BpmOACashS || BpmProcessInstanceResultEnum.BACK.getResult().equals(result)) { //判断是否有采购报销 - BpmOACashDO cash = getCash(id); + for (BpmOACashItemDO cashItemDO : cashItemDOs) { + if (cashItemDO.getType() == 4) { + procureIds.add(cashItemDO.getProcureId()); + } + } //报销类别为 采购费时 - if (cash.getType() == 4) { + if (!CollectionUtil.isEmpty(procureIds)) { //所有关联的采购申请改为 未支付状态 bpmOAProcureService.updatePayFlagByIds( new BpmOAProcureListEditReqVO() .setPayFlag(BpmOAProcureDO.FLAG_FALSE) - .setProcureIds(Collections.singletonList(cash.getProcureId())) + .setProcureIds(procureIds) ); } } @@ -154,4 +186,10 @@ public class BpmOACashServiceImpl extends BpmOABaseService implements BpmOACashS return cashMapper.selectById(id); } + + @Override + public List getCashItem(Long cashId) { + + return cashItemMapper.selectList(BpmOACashItemDO::getCashId, cashId); + } } 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 2e09c961..1d055a8f 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java @@ -1 +1 @@ -package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmOAReimbursementPrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.BpmOAReimbursementRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskApproveReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAImprestDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReimbursementDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmConstants; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAImprestService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAProcureServiceImpl; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAReimbursementService; import cn.iocoder.yudao.module.infra.api.file.FileApi; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.permission.PermissionApi; import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.lang.reflect.Field; import java.text.DecimalFormat; import java.time.LocalDateTime; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 *

* ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. *

* HistoricProcessInstance & ProcessInstance 的关系: * 1. *

* 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private TaskService engineTaskService; @Resource private BpmTaskAssignRuleMapper taskRuleMapper; @Resource private BpmUserGroupService userGroupService; @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource @Lazy // 解决循环依赖 private BpmMessageService messageService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); // 获得 User Map Map userMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, userMap); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())).getCheckedData(); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()).getCheckedData(); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); } @Override public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); Map processVariables = runtimeService.getVariables(instance.getProcessInstanceId()); String reason = (String) processVariables.get("approve_reason"); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessInstanceId(id) .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置当前用户 FlowableUtils.setAuthenticatedUserId(userId); // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(variables)); /** 创建流程后,添加抄送人 End add by yj 2024.1.4 */ processCCToUsers(definition, instance); /** 通过自己发起的流程 */ // approveSelfTask(instance.getId()) ; return instance.getId(); } private void approveSelfTask(String processInstanceId) { List tasks = engineTaskService.createTaskQuery().processInstanceId(processInstanceId).list(); if (tasks != null && tasks.size() > 0) { Task task = tasks.get(0); String assigneeId = task.getAssignee(); //如果当前登陆用户是审批人,那么自动审批通过 if (assigneeId.equals(SecurityFrameworkUtils.getLoginUserId().toString())) { BpmTaskApproveReqVO reqVO = new BpmTaskApproveReqVO(); reqVO.setId(task.getId()); reqVO.setReason(BpmConstants.AUTO_APPRAVAL); taskService.approveTask(getLoginUserId(), reqVO); } } } /** * 获得抄送我的流程实例的分页 * * @param userId 用户编号 * @param pageReqVO 分页请求 * @return 流程实例的分页 */ public PageResult getMyCCProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectCCPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, null); } public List getProcessInstancesGroupByModelName(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); return processInstanceExtMapper.getProcessInstancesGroupByModelName(pageReqVO); } public List getProcessInstancesGroupByResultStatus(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); return processInstanceExtMapper.getProcessInstancesGroupByResultStatus(pageReqVO); } public PageResult getStatisticsProcessInstancePage(@Valid BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectStatisticePage(pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); //获得 审批人 User Map Map assigneeUserMap = adminUserApi.getUserMap(longIds); //获得 发起人 User Map List bpieDOs = pageResult.getList(); longIds = new ArrayList<>(); for (BpmProcessInstanceExtDO bpieDO : bpieDOs) { longIds.add(bpieDO.getStartUserId()); } Map startUserMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertStatisticsPage(pageResult, taskMap, assigneeUserMap, startUserMap); } @Resource PermissionApi permissionApi; /** * 根据数据权限,查询关联操作的用户IDS * * @param pageReqVO * @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); for (BpmTaskAssignRuleDO rule : rules) { String key = rule.getTaskDefinitionKey(); //任务名称 Integer type = rule.getType(); if (!key.isEmpty() && key.equals(BpmConstants.CC_NAME) && type == 40) { StringBuffer str = new StringBuffer(); Set options = rule.getOptions(); List list = new ArrayList(options); for (Long groupId : list) { //需要根据这个groupId,查询这个组中的用户id BpmUserGroupDO userGroup = userGroupService.getUserGroup(groupId); Set userIds = userGroup.getMemberUserIds(); List userIdList = new ArrayList(userIds); for (Long user_id : userIdList) { str.append("[").append(user_id).append("]"); } } //流程是采购计划时 if (definition.getKey().equals(BpmOAProcureServiceImpl.PROCESS_KEY)) { AdminUserRespDTO userRespDTO = adminUserApi.getUser(Long.valueOf(instance.getStartUserId())).getCheckedData(); DeptRespDTO deptRespDTO = deptApi.getDept(userRespDTO.getDeptId()).getCheckedData(); //发起人部门为 生产部及以下时 if (deptRespDTO.getFlag().contains("130")) { //添加 供应部抄送 BpmUserGroupDO userGroup = userGroupService.getUserGroup(121L); Set userIds = userGroup.getMemberUserIds(); List userIdList = new ArrayList(userIds); for (Long user_id : userIdList) { str.append("[").append(user_id).append("]"); } } } String ccids = str.toString(); //根据processDefinitionId 将ccids保存到bpm_process_instance_ext中的ccids字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessDefinitionId(processDefinitionId) .setCcids(ccids).setProcessInstanceId(instance.getProcessInstanceId()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); break; } } } @Resource private BpmTaskExtMapper taskExtMapper; @Override public List getUserProcessTpo10(BpmProcessInstanceStatisticsReqVO pageReqVO) { //按审核人分组查询,统计已完成流程数量及平均耗时间 List respVOS = processInstanceExtMapper.getUserProcessTpo10(pageReqVO); if (respVOS == null || respVOS.size() == 0) { return null; } List idList = respVOS.stream() .map(BpmProcessFinishStatisticsRespVO::getUserId) .collect(Collectors.toList()); //根据userId,查询UserMap Map userMap = adminUserApi.getUserMap(idList); Long[] idsArray = new Long[userMap.size()]; // 使用 map 的 keySet() 方法获取键集合 Set keys = userMap.keySet(); // 遍历键集合,将每个键添加到数组中 int index = 0; for (Long key : keys) { idsArray[index++] = key; } pageReqVO.setUserIds(idsArray); //按审核人分组查询,未审批完成的流程数量 List bpmTaskExtDOs = processInstanceExtMapper.selectUnfinishProcessCount(pageReqVO); //按审核人分组查询,未完成的记录数 Map unFinfishCountCountMap = new HashMap<>(); for (BpmProcessFinishStatisticsRespVO item : bpmTaskExtDOs) { unFinfishCountCountMap.put(item.getUserId(), item.getUnFinfishCount()); } respVOS.forEach(respVO -> respVO.setName(userMap.get(respVO.getUserId()).getNickname())); respVOS.forEach(respVO -> respVO.setUnFinfishCount(unFinfishCountCountMap.get(respVO.getUserId()))); //获取排行榜第一记录的耗时,作为基础数据 double num = Double.parseDouble(respVOS.get(0).getUserTime()); // 先将字符串转换为双精度浮点数 int baseNumber = (int) num; // 再通过类型转换操作符将其转换为整数 DecimalFormat df = new DecimalFormat("#.00"); respVOS.forEach(respVO -> { //格式化流程完成率 float finfishCount = (float) respVO.getFinfishCount(); float unFinfishCount = respVO.getUnFinfishCount() == null ? 0 : respVO.getUnFinfishCount(); float all = finfishCount + unFinfishCount; float result = finfishCount / all; float rate = result * 100; respVO.setCompletionRate(df.format(rate) + "%"); double dValue = Double.parseDouble(respVO.getUserTime()); // 将字符串转换为double类型 int roundedValue = (int) Math.round(dValue); // 使用Math.round()进行四舍五入,并转换为int类型 respVO.setUserTime(roundedValue + ""); //格式化进度百度比, 参照最高的数据进行百分比显示 double percentage = ((int) Double.parseDouble(respVO.getUserTime()) / (double) baseNumber) * 100; respVO.setPercentage((int) Math.round(percentage)); //设置未完成 respVO.setUnFinfishCount(Integer.valueOf((int) unFinfishCount)); }); return respVOS; } @Override public BpmProcessInstanceExtDO getProcessInstanceDO(String id) { return processInstanceExtMapper.selectByProcessInstanceId(id); } @Resource private FileApi fileApi; @Resource @Lazy // 解决循环依赖 private BpmOAReimbursementService reimbursementService; @Resource @Lazy // 解决循环依赖 private BpmOAImprestService imprestService; @Override public BpmProcessInstancePrintDataRespVO getOAReportPrintData(BpmProcessInstancePrintDataReqVO reqVO) { BpmProcessInstancePrintDataRespVO bpmProcessInstancePrintDataRespVO = new BpmProcessInstancePrintDataRespVO(); String key = reqVO.getKey(); //流程标识 String processInstanceId = reqVO.getId(); //流程实例ID bpmProcessInstancePrintDataRespVO.setId(processInstanceId); bpmProcessInstancePrintDataRespVO.setKey(key); BpmProcessInstanceRespVO bpmProcessInstance = getProcessInstanceVO(processInstanceId); Long businessKey = Long.valueOf(bpmProcessInstance.getBusinessKey()); //流程业务表-主键ID if ("oa_reimbursement".equals(key)) { //报销流程 BpmOAReimbursementDO reimbursement = reimbursementService.getReimbursement(businessKey); BpmOAReimbursementRespVO bpmOAReimbursementRespVO = reimbursementService.convert(reimbursement); //报销业务数据 List taskRespVOList = taskService.getTaskListByProcessInstanceId(processInstanceId); //报销审核人数据 //给User添加签名地址 taskRespVOList.forEach(taskRespVO -> taskRespVO.getAssigneeUser().setSignURL( fileApi.getUserSignImgPath( taskRespVO.getAssigneeUser().getId() ).getData() ) ); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprestByReimbursementId(reimbursement.getId()); if (bpmOAImprestDO != null) { //设置备用金 金额 bpmOAReimbursementRespVO.setAmount(bpmOAImprestDO.getAmount()); } //获取流程抄送用户编号 BpmProcessInstanceExtDO processInstanceExtDO = getProcessInstanceDO(processInstanceId); //获取流程抄送用户信息 List ccUserIds = new ArrayList<>(); if (processInstanceExtDO.getCcids() != null && !processInstanceExtDO.getCcids().isEmpty()) { Pattern pattern = Pattern.compile("\\[(\\d+)]"); Matcher matcher = pattern.matcher(processInstanceExtDO.getCcids()); while (matcher.find()) { ccUserIds.add(Long.parseLong(matcher.group(1))); } } List userRespDTOS = adminUserApi.getUserList(ccUserIds).getCheckedData(); //获取抄送用户部门信息 Map deptMapDTO = deptApi.getDeptMap(convertSet(userRespDTOS, AdminUserRespDTO::getDeptId)); //拼接数据 List ccUsers = userRespDTOS.stream().map(user -> { BpmOAReimbursementPrintDataRespVO.CCUser cc = new BpmOAReimbursementPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOAReimbursementPrintDataRespVO reimbursementPrintData = new BpmOAReimbursementPrintDataRespVO(); reimbursementPrintData.setBpmOAReimbursementRespVO(bpmOAReimbursementRespVO); reimbursementPrintData.setProcessTasks(taskRespVOList); reimbursementPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOAReimbursementPrintDataRespVO(reimbursementPrintData); } return bpmProcessInstancePrintDataRespVO; } } \ No newline at end of file +package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.cash.BpmOACashRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmOAReimbursementPrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.BpmOAReimbursementRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskApproveReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; import cn.iocoder.yudao.module.bpm.convert.oa.BpmOACashConvert; 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.BpmOACashItemDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAImprestDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReimbursementDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmConstants; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.bpm.service.oa.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.bank.dto.BankRespDTO; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.permission.PermissionApi; import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.lang.reflect.Field; import java.text.DecimalFormat; import java.time.LocalDateTime; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 *

* ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. *

* HistoricProcessInstance & ProcessInstance 的关系: * 1. *

* 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private TaskService engineTaskService; @Resource private BpmTaskAssignRuleMapper taskRuleMapper; @Resource private BpmUserGroupService userGroupService; @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource @Lazy // 解决循环依赖 private BpmMessageService messageService; @Resource private ConfigApi configApi; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); // 获得 User Map Map userMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, userMap); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())).getCheckedData(); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()).getCheckedData(); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); } @Override public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); Map processVariables = runtimeService.getVariables(instance.getProcessInstanceId()); String reason = (String) processVariables.get("approve_reason"); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessInstanceId(id) .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置当前用户 FlowableUtils.setAuthenticatedUserId(userId); // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(variables)); /** 创建流程后,添加抄送人 End add by yj 2024.1.4 */ processCCToUsers(definition, instance); /** 通过自己发起的流程 */ // approveSelfTask(instance.getId()) ; return instance.getId(); } private void approveSelfTask(String processInstanceId) { List tasks = engineTaskService.createTaskQuery().processInstanceId(processInstanceId).list(); if (tasks != null && tasks.size() > 0) { Task task = tasks.get(0); String assigneeId = task.getAssignee(); //如果当前登陆用户是审批人,那么自动审批通过 if (assigneeId.equals(SecurityFrameworkUtils.getLoginUserId().toString())) { BpmTaskApproveReqVO reqVO = new BpmTaskApproveReqVO(); reqVO.setId(task.getId()); reqVO.setReason(BpmConstants.AUTO_APPRAVAL); taskService.approveTask(getLoginUserId(), reqVO); } } } /** * 获得抄送我的流程实例的分页 * * @param userId 用户编号 * @param pageReqVO 分页请求 * @return 流程实例的分页 */ public PageResult getMyCCProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectCCPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, null); } public List getProcessInstancesGroupByModelName(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); return processInstanceExtMapper.getProcessInstancesGroupByModelName(pageReqVO); } public List getProcessInstancesGroupByResultStatus(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); return processInstanceExtMapper.getProcessInstancesGroupByResultStatus(pageReqVO); } public PageResult getStatisticsProcessInstancePage(@Valid BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectStatisticePage(pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); //获得 审批人 User Map Map assigneeUserMap = adminUserApi.getUserMap(longIds); //获得 发起人 User Map List bpieDOs = pageResult.getList(); longIds = new ArrayList<>(); for (BpmProcessInstanceExtDO bpieDO : bpieDOs) { longIds.add(bpieDO.getStartUserId()); } Map startUserMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertStatisticsPage(pageResult, taskMap, assigneeUserMap, startUserMap); } @Resource PermissionApi permissionApi; /** * 根据数据权限,查询关联操作的用户IDS * * @param pageReqVO * @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); for (BpmTaskAssignRuleDO rule : rules) { String key = rule.getTaskDefinitionKey(); //任务名称 Integer type = rule.getType(); if (!key.isEmpty() && key.equals(BpmConstants.CC_NAME) && type == 40) { StringBuffer str = new StringBuffer(); Set options = rule.getOptions(); List list = new ArrayList(options); for (Long groupId : list) { //需要根据这个groupId,查询这个组中的用户id BpmUserGroupDO userGroup = userGroupService.getUserGroup(groupId); Set userIds = userGroup.getMemberUserIds(); List userIdList = new ArrayList(userIds); for (Long user_id : userIdList) { str.append("[").append(user_id).append("]"); } } //流程是采购计划时 if (definition.getKey().equals(BpmOAProcureServiceImpl.PROCESS_KEY)) { AdminUserRespDTO userRespDTO = adminUserApi.getUser(Long.valueOf(instance.getStartUserId())).getCheckedData(); DeptRespDTO deptRespDTO = deptApi.getDept(userRespDTO.getDeptId()).getCheckedData(); //发起人部门为 生产部及以下时 if (deptRespDTO.getFlag().contains("130")) { //添加 供应部抄送 BpmUserGroupDO userGroup = userGroupService.getUserGroup(121L); Set userIds = userGroup.getMemberUserIds(); List userIdList = new ArrayList(userIds); for (Long user_id : userIdList) { str.append("[").append(user_id).append("]"); } } } String ccids = str.toString(); //根据processDefinitionId 将ccids保存到bpm_process_instance_ext中的ccids字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessDefinitionId(processDefinitionId) .setCcids(ccids).setProcessInstanceId(instance.getProcessInstanceId()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); break; } } } @Resource private BpmTaskExtMapper taskExtMapper; @Override public List getUserProcessTpo10(BpmProcessInstanceStatisticsReqVO pageReqVO) { //按审核人分组查询,统计已完成流程数量及平均耗时间 List respVOS = processInstanceExtMapper.getUserProcessTpo10(pageReqVO); if (respVOS == null || respVOS.size() == 0) { return null; } List idList = respVOS.stream() .map(BpmProcessFinishStatisticsRespVO::getUserId) .collect(Collectors.toList()); //根据userId,查询UserMap Map userMap = adminUserApi.getUserMap(idList); Long[] idsArray = new Long[userMap.size()]; // 使用 map 的 keySet() 方法获取键集合 Set keys = userMap.keySet(); // 遍历键集合,将每个键添加到数组中 int index = 0; for (Long key : keys) { idsArray[index++] = key; } pageReqVO.setUserIds(idsArray); //按审核人分组查询,未审批完成的流程数量 List bpmTaskExtDOs = processInstanceExtMapper.selectUnfinishProcessCount(pageReqVO); //按审核人分组查询,未完成的记录数 Map unFinfishCountCountMap = new HashMap<>(); for (BpmProcessFinishStatisticsRespVO item : bpmTaskExtDOs) { unFinfishCountCountMap.put(item.getUserId(), item.getUnFinfishCount()); } respVOS.forEach(respVO -> respVO.setName(userMap.get(respVO.getUserId()).getNickname())); respVOS.forEach(respVO -> respVO.setUnFinfishCount(unFinfishCountCountMap.get(respVO.getUserId()))); //获取排行榜第一记录的耗时,作为基础数据 double num = Double.parseDouble(respVOS.get(0).getUserTime()); // 先将字符串转换为双精度浮点数 int baseNumber = (int) num; // 再通过类型转换操作符将其转换为整数 DecimalFormat df = new DecimalFormat("#.00"); respVOS.forEach(respVO -> { //格式化流程完成率 float finfishCount = (float) respVO.getFinfishCount(); float unFinfishCount = respVO.getUnFinfishCount() == null ? 0 : respVO.getUnFinfishCount(); float all = finfishCount + unFinfishCount; float result = finfishCount / all; float rate = result * 100; respVO.setCompletionRate(df.format(rate) + "%"); double dValue = Double.parseDouble(respVO.getUserTime()); // 将字符串转换为double类型 int roundedValue = (int) Math.round(dValue); // 使用Math.round()进行四舍五入,并转换为int类型 respVO.setUserTime(roundedValue + ""); //格式化进度百度比, 参照最高的数据进行百分比显示 double percentage = ((int) Double.parseDouble(respVO.getUserTime()) / (double) baseNumber) * 100; respVO.setPercentage((int) Math.round(percentage)); //设置未完成 respVO.setUnFinfishCount(Integer.valueOf((int) unFinfishCount)); }); return respVOS; } @Override public BpmProcessInstanceExtDO getProcessInstanceDO(String id) { return processInstanceExtMapper.selectByProcessInstanceId(id); } @Resource private FileApi fileApi; @Resource 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() ) ); if ("oa_reimbursement".equals(key)) { //报销流程 BpmOAReimbursementDO reimbursement = reimbursementService.getReimbursement(businessKey); BpmOAReimbursementRespVO bpmOAReimbursementRespVO = reimbursementService.convert(reimbursement); //报销业务数据 //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprestByReimbursementId(reimbursement.getId()); if (bpmOAImprestDO != null) { //设置备用金 金额 bpmOAReimbursementRespVO.setAmount(bpmOAImprestDO.getAmount()); } //获取流程抄送用户编号 BpmProcessInstanceExtDO processInstanceExtDO = getProcessInstanceDO(processInstanceId); //获取流程抄送用户信息 List ccUserIds = new ArrayList<>(); if (processInstanceExtDO.getCcids() != null && !processInstanceExtDO.getCcids().isEmpty()) { Pattern pattern = Pattern.compile("\\[(\\d+)]"); Matcher matcher = pattern.matcher(processInstanceExtDO.getCcids()); while (matcher.find()) { ccUserIds.add(Long.parseLong(matcher.group(1))); } // 移除 外勤人员信息 ccUserIds.removeAll(userIds); } List userRespDTOS = adminUserApi.getUserList(ccUserIds).getCheckedData(); //获取抄送用户部门信息 Map deptMapDTO = deptApi.getDeptMap(convertSet(userRespDTOS, AdminUserRespDTO::getDeptId)); //拼接数据 List ccUsers = userRespDTOS.stream().map(user -> { BpmOAReimbursementPrintDataRespVO.CCUser cc = new BpmOAReimbursementPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOAReimbursementPrintDataRespVO reimbursementPrintData = new BpmOAReimbursementPrintDataRespVO(); reimbursementPrintData.setBpmOAReimbursementRespVO(bpmOAReimbursementRespVO); reimbursementPrintData.setProcessTasks(taskRespVOList); reimbursementPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOAReimbursementPrintDataRespVO(reimbursementPrintData); } if ("oa_cash".equals(key)) { BpmOACashDO cashDO = cashService.getCash(businessKey); // 获取明细数据 List cashItemDOs = cashService.getCashItem(cashDO.getId()); //获取部门信息map Map deptMap = deptApi.getDeptMap(convertSet(cashItemDOs, BpmOACashItemDO::getDeptId)); // 获取银行卡信息 BankRespDTO bankRespDTO = bankApi.getBank(cashDO.getBankId()).getCheckedData(); BpmOACashRespVO cashRespVO = BpmOACashConvert.INSTANCE.convert1(cashDO, cashItemDOs, deptMap, bankRespDTO); } return bpmProcessInstancePrintDataRespVO; } } \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/bank/BankApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/bank/BankApi.java new file mode 100644 index 00000000..134f471c --- /dev/null +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/bank/BankApi.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.system.api.bank; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.system.api.bank.dto.BankRespDTO; +import cn.iocoder.yudao.module.system.enums.ApiConstants; +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.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - 银行卡") +public interface BankApi { + + String PREFIX = ApiConstants.PREFIX + "/bank"; + + @GetMapping(PREFIX + "/get") + @Operation(summary = "获得银行卡信息") + @Parameter(name = "bankId", description = "编号", example = "1", required = true) + CommonResult getBank(@RequestParam("bankId") Long bankId); +} diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/bank/dto/BankRespDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/bank/dto/BankRespDTO.java new file mode 100644 index 00000000..1048dd77 --- /dev/null +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/bank/dto/BankRespDTO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.system.api.bank.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "RPC 服务 - 银行卡 Response DTO") +@Data +public class BankRespDTO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED) + private Long id; + + @Schema(description = "银行卡号", requiredMode = Schema.RequiredMode.REQUIRED) + private String bankNo; + + @Schema(description = "银行卡用户名称", requiredMode = Schema.RequiredMode.REQUIRED) + private String nickname; + + @Schema(description = "开户行信息", requiredMode = Schema.RequiredMode.REQUIRED) + private String bankName; +} diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApi.java index 76a52806..0522e79c 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApi.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApi.java @@ -70,4 +70,9 @@ public interface AdminUserApi { @PostMapping(PREFIX + "/create") @Operation(summary = "创建用户") CommonResult createUser(@RequestBody UserSaveRespDTO saveRespDTO); + + @GetMapping(PREFIX + "/getUserIdsByUserNature") + @Operation(summary = "获取所有用户性质为外勤的用户") + @Parameter(name = "userNature", description = "用户性质", example = "3", required = true) + CommonResult> getUserIdsByUserNature(@RequestParam("userNature") Integer userNature); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/bank/BankApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/bank/BankApiImpl.java new file mode 100644 index 00000000..ba3bc667 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/bank/BankApiImpl.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.system.api.bank; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.api.bank.dto.BankRespDTO; +import cn.iocoder.yudao.module.system.dal.dataobject.bank.BankDO; +import cn.iocoder.yudao.module.system.service.bank.UserBankService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class BankApiImpl implements BankApi{ + + @Resource + private UserBankService userBankService; + + @Override + public CommonResult getBank(Long bankId) { + + BankDO bankDO = userBankService.getBank(bankId); + return success(BeanUtils.toBean(bankDO, BankRespDTO.class)); + } +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApiImpl.java index 0f2daf35..03ce5075 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApiImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApiImpl.java @@ -17,6 +17,7 @@ import java.util.List; import java.util.Set; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; @RestController // 提供 RESTful API 接口,给 Feign 调用 @Validated @@ -69,4 +70,11 @@ public class AdminUserApiImpl implements AdminUserApi { return success(userService.createUser(BeanUtils.toBean(saveRespDTO, UserSaveReqVO.class))); } + @Override + public CommonResult> getUserIdsByUserNature(Integer userNature) { + + List userDOS = userService.getListByNature(userNature); + return success(convertList(userDOS, AdminUserDO::getId)); + } + } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/user/AdminUserDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/user/AdminUserDO.java index a232c734..98aef7de 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/user/AdminUserDO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/user/AdminUserDO.java @@ -108,6 +108,13 @@ public class AdminUserDO extends TenantBaseDO { * 1:公司用户 2:工厂用户 */ private Integer userType; + + /** + * 用户性质 + * 3:正式 4:外勤 + */ + private Integer userNature; + /** * 最后登录IP */ 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 3884d257..87132535 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 @@ -317,4 +317,10 @@ public interface AdminUserService { */ IPage getAllUserListByGroupIds(UserPageDTO dto); + /** + * 获取指令性质得用户列表 + * @param userNature 用户性质 + * @return 用户列表 + */ + List getListByNature(Integer userNature); } 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 6f091c19..b4afa310 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 @@ -624,4 +624,10 @@ public class AdminUserServiceImpl implements AdminUserService { return userMapper.getAllUserListByGroupIds(MyBatisUtils.buildPage(dto), dto); } + @Override + public List getListByNature(Integer userNature) { + + return userMapper.selectList(AdminUserDO::getUserNature, userNature); + } + } From 5de1bac1d9b090ab3a7b2d0dfcdab3ad1286e24e Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Sun, 18 Aug 2024 15:52:44 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=8E=B0=E9=87=91?= =?UTF-8?q?=E6=94=AF=E5=87=BA=EF=BC=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/bpm/dal/dataobject/oa/BpmOACashDO.java | 6 ++++++ .../yudao/module/bpm/service/oa/BpmOACashServiceImpl.java | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) 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 23a0620c..7aa48038 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 @@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import lombok.*; +import java.math.BigDecimal; import java.util.List; /** @@ -44,6 +45,11 @@ public class BpmOACashDO extends BaseDO { */ private Long bankId; + /** + * 支出总金额 + */ + private BigDecimal totalMoney; + /** * 用章的结果 * 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 7dd6166d..37a6c3d4 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 @@ -118,6 +118,9 @@ public class BpmOACashServiceImpl extends BpmOABaseService implements BpmOACashS validateLeaveExists(id); + // 获得现金支出业务数据 + BpmOACashDO cash = getCash(id); + // 获取现金支出明细 List cashItemDOs = getCashItem(id); @@ -130,11 +133,13 @@ public class BpmOACashServiceImpl extends BpmOABaseService implements BpmOACashS if (instance.isEnded()) { //判断是否有采购报销 + StringBuilder reason = new StringBuilder(); for (BpmOACashItemDO cashItemDO : cashItemDOs) { if (cashItemDO.getType() == 4) { procureIds.add(cashItemDO.getProcureId()); } + reason.append(cashItemDO.getReason()).append(","); } //报销类别为 采购费时 if (!CollectionUtil.isEmpty(procureIds)) { @@ -151,7 +156,7 @@ public class BpmOACashServiceImpl extends BpmOABaseService implements BpmOACashS financialPaymentService.save(new FinancialPaymentDO() .setUserId(cash.getUserId()) .setProcessInstanceId(cash.getProcessInstanceId()) - .setReason(cash.getReason()) + .setReason(reason.toString()) .setObjectId(id) .setType(1) .setStatus(0) From 5bd4c332ab297a1499edff0d777caaf8dc386326 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Sun, 18 Aug 2024 17:13:43 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=8E=B0=E9=87=91?= =?UTF-8?q?=E6=94=AF=E5=87=BA=20=E6=89=93=E5=8D=B0=E5=8A=9F=E8=83=BD=20?= =?UTF-8?q?=E7=A7=BB=E9=99=A4=20=E5=A4=87=E7=94=A8=E9=87=91DO=E4=B8=AD=20d?= =?UTF-8?q?ept=5Fid=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/oa/vo/print/BpmOACashPrintDataRespVO.java | 2 +- .../yudao/module/bpm/dal/dataobject/oa/BpmOAImprestDO.java | 5 ----- .../bpm/service/task/BpmProcessInstanceServiceImpl.java | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/print/BpmOACashPrintDataRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/print/BpmOACashPrintDataRespVO.java index ae3025a2..3b46d8f6 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/print/BpmOACashPrintDataRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/print/BpmOACashPrintDataRespVO.java @@ -25,7 +25,7 @@ public class BpmOACashPrintDataRespVO extends BpmOABaseRespVO { /** * 抄送用户信息 */ - private List ccUsers; + private List ccUsers; @Schema(description = "抄送用户信息") @Data 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 1d16e262..b15971bc 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 @@ -49,11 +49,6 @@ public class BpmOAImprestDO extends BaseDO { */ private Long userId; - /** - * 部门id - */ - private Long deptId; - /** * 费用类型 */ 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 1d055a8f..c4013542 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java @@ -1 +1 @@ -package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.cash.BpmOACashRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmOAReimbursementPrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.BpmOAReimbursementRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskApproveReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; import cn.iocoder.yudao.module.bpm.convert.oa.BpmOACashConvert; 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.BpmOACashItemDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAImprestDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReimbursementDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmConstants; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.bpm.service.oa.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.bank.dto.BankRespDTO; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.permission.PermissionApi; import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.lang.reflect.Field; import java.text.DecimalFormat; import java.time.LocalDateTime; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 *

* ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. *

* HistoricProcessInstance & ProcessInstance 的关系: * 1. *

* 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private TaskService engineTaskService; @Resource private BpmTaskAssignRuleMapper taskRuleMapper; @Resource private BpmUserGroupService userGroupService; @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource @Lazy // 解决循环依赖 private BpmMessageService messageService; @Resource private ConfigApi configApi; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); // 获得 User Map Map userMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, userMap); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())).getCheckedData(); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()).getCheckedData(); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); } @Override public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); Map processVariables = runtimeService.getVariables(instance.getProcessInstanceId()); String reason = (String) processVariables.get("approve_reason"); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessInstanceId(id) .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置当前用户 FlowableUtils.setAuthenticatedUserId(userId); // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(variables)); /** 创建流程后,添加抄送人 End add by yj 2024.1.4 */ processCCToUsers(definition, instance); /** 通过自己发起的流程 */ // approveSelfTask(instance.getId()) ; return instance.getId(); } private void approveSelfTask(String processInstanceId) { List tasks = engineTaskService.createTaskQuery().processInstanceId(processInstanceId).list(); if (tasks != null && tasks.size() > 0) { Task task = tasks.get(0); String assigneeId = task.getAssignee(); //如果当前登陆用户是审批人,那么自动审批通过 if (assigneeId.equals(SecurityFrameworkUtils.getLoginUserId().toString())) { BpmTaskApproveReqVO reqVO = new BpmTaskApproveReqVO(); reqVO.setId(task.getId()); reqVO.setReason(BpmConstants.AUTO_APPRAVAL); taskService.approveTask(getLoginUserId(), reqVO); } } } /** * 获得抄送我的流程实例的分页 * * @param userId 用户编号 * @param pageReqVO 分页请求 * @return 流程实例的分页 */ public PageResult getMyCCProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectCCPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, null); } public List getProcessInstancesGroupByModelName(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); return processInstanceExtMapper.getProcessInstancesGroupByModelName(pageReqVO); } public List getProcessInstancesGroupByResultStatus(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); return processInstanceExtMapper.getProcessInstancesGroupByResultStatus(pageReqVO); } public PageResult getStatisticsProcessInstancePage(@Valid BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectStatisticePage(pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); //获得 审批人 User Map Map assigneeUserMap = adminUserApi.getUserMap(longIds); //获得 发起人 User Map List bpieDOs = pageResult.getList(); longIds = new ArrayList<>(); for (BpmProcessInstanceExtDO bpieDO : bpieDOs) { longIds.add(bpieDO.getStartUserId()); } Map startUserMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertStatisticsPage(pageResult, taskMap, assigneeUserMap, startUserMap); } @Resource PermissionApi permissionApi; /** * 根据数据权限,查询关联操作的用户IDS * * @param pageReqVO * @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); for (BpmTaskAssignRuleDO rule : rules) { String key = rule.getTaskDefinitionKey(); //任务名称 Integer type = rule.getType(); if (!key.isEmpty() && key.equals(BpmConstants.CC_NAME) && type == 40) { StringBuffer str = new StringBuffer(); Set options = rule.getOptions(); List list = new ArrayList(options); for (Long groupId : list) { //需要根据这个groupId,查询这个组中的用户id BpmUserGroupDO userGroup = userGroupService.getUserGroup(groupId); Set userIds = userGroup.getMemberUserIds(); List userIdList = new ArrayList(userIds); for (Long user_id : userIdList) { str.append("[").append(user_id).append("]"); } } //流程是采购计划时 if (definition.getKey().equals(BpmOAProcureServiceImpl.PROCESS_KEY)) { AdminUserRespDTO userRespDTO = adminUserApi.getUser(Long.valueOf(instance.getStartUserId())).getCheckedData(); DeptRespDTO deptRespDTO = deptApi.getDept(userRespDTO.getDeptId()).getCheckedData(); //发起人部门为 生产部及以下时 if (deptRespDTO.getFlag().contains("130")) { //添加 供应部抄送 BpmUserGroupDO userGroup = userGroupService.getUserGroup(121L); Set userIds = userGroup.getMemberUserIds(); List userIdList = new ArrayList(userIds); for (Long user_id : userIdList) { str.append("[").append(user_id).append("]"); } } } String ccids = str.toString(); //根据processDefinitionId 将ccids保存到bpm_process_instance_ext中的ccids字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessDefinitionId(processDefinitionId) .setCcids(ccids).setProcessInstanceId(instance.getProcessInstanceId()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); break; } } } @Resource private BpmTaskExtMapper taskExtMapper; @Override public List getUserProcessTpo10(BpmProcessInstanceStatisticsReqVO pageReqVO) { //按审核人分组查询,统计已完成流程数量及平均耗时间 List respVOS = processInstanceExtMapper.getUserProcessTpo10(pageReqVO); if (respVOS == null || respVOS.size() == 0) { return null; } List idList = respVOS.stream() .map(BpmProcessFinishStatisticsRespVO::getUserId) .collect(Collectors.toList()); //根据userId,查询UserMap Map userMap = adminUserApi.getUserMap(idList); Long[] idsArray = new Long[userMap.size()]; // 使用 map 的 keySet() 方法获取键集合 Set keys = userMap.keySet(); // 遍历键集合,将每个键添加到数组中 int index = 0; for (Long key : keys) { idsArray[index++] = key; } pageReqVO.setUserIds(idsArray); //按审核人分组查询,未审批完成的流程数量 List bpmTaskExtDOs = processInstanceExtMapper.selectUnfinishProcessCount(pageReqVO); //按审核人分组查询,未完成的记录数 Map unFinfishCountCountMap = new HashMap<>(); for (BpmProcessFinishStatisticsRespVO item : bpmTaskExtDOs) { unFinfishCountCountMap.put(item.getUserId(), item.getUnFinfishCount()); } respVOS.forEach(respVO -> respVO.setName(userMap.get(respVO.getUserId()).getNickname())); respVOS.forEach(respVO -> respVO.setUnFinfishCount(unFinfishCountCountMap.get(respVO.getUserId()))); //获取排行榜第一记录的耗时,作为基础数据 double num = Double.parseDouble(respVOS.get(0).getUserTime()); // 先将字符串转换为双精度浮点数 int baseNumber = (int) num; // 再通过类型转换操作符将其转换为整数 DecimalFormat df = new DecimalFormat("#.00"); respVOS.forEach(respVO -> { //格式化流程完成率 float finfishCount = (float) respVO.getFinfishCount(); float unFinfishCount = respVO.getUnFinfishCount() == null ? 0 : respVO.getUnFinfishCount(); float all = finfishCount + unFinfishCount; float result = finfishCount / all; float rate = result * 100; respVO.setCompletionRate(df.format(rate) + "%"); double dValue = Double.parseDouble(respVO.getUserTime()); // 将字符串转换为double类型 int roundedValue = (int) Math.round(dValue); // 使用Math.round()进行四舍五入,并转换为int类型 respVO.setUserTime(roundedValue + ""); //格式化进度百度比, 参照最高的数据进行百分比显示 double percentage = ((int) Double.parseDouble(respVO.getUserTime()) / (double) baseNumber) * 100; respVO.setPercentage((int) Math.round(percentage)); //设置未完成 respVO.setUnFinfishCount(Integer.valueOf((int) unFinfishCount)); }); return respVOS; } @Override public BpmProcessInstanceExtDO getProcessInstanceDO(String id) { return processInstanceExtMapper.selectByProcessInstanceId(id); } @Resource private FileApi fileApi; @Resource 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() ) ); if ("oa_reimbursement".equals(key)) { //报销流程 BpmOAReimbursementDO reimbursement = reimbursementService.getReimbursement(businessKey); BpmOAReimbursementRespVO bpmOAReimbursementRespVO = reimbursementService.convert(reimbursement); //报销业务数据 //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprestByReimbursementId(reimbursement.getId()); if (bpmOAImprestDO != null) { //设置备用金 金额 bpmOAReimbursementRespVO.setAmount(bpmOAImprestDO.getAmount()); } //获取流程抄送用户编号 BpmProcessInstanceExtDO processInstanceExtDO = getProcessInstanceDO(processInstanceId); //获取流程抄送用户信息 List ccUserIds = new ArrayList<>(); if (processInstanceExtDO.getCcids() != null && !processInstanceExtDO.getCcids().isEmpty()) { Pattern pattern = Pattern.compile("\\[(\\d+)]"); Matcher matcher = pattern.matcher(processInstanceExtDO.getCcids()); while (matcher.find()) { ccUserIds.add(Long.parseLong(matcher.group(1))); } // 移除 外勤人员信息 ccUserIds.removeAll(userIds); } List userRespDTOS = adminUserApi.getUserList(ccUserIds).getCheckedData(); //获取抄送用户部门信息 Map deptMapDTO = deptApi.getDeptMap(convertSet(userRespDTOS, AdminUserRespDTO::getDeptId)); //拼接数据 List ccUsers = userRespDTOS.stream().map(user -> { BpmOAReimbursementPrintDataRespVO.CCUser cc = new BpmOAReimbursementPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOAReimbursementPrintDataRespVO reimbursementPrintData = new BpmOAReimbursementPrintDataRespVO(); reimbursementPrintData.setBpmOAReimbursementRespVO(bpmOAReimbursementRespVO); reimbursementPrintData.setProcessTasks(taskRespVOList); reimbursementPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOAReimbursementPrintDataRespVO(reimbursementPrintData); } if ("oa_cash".equals(key)) { BpmOACashDO cashDO = cashService.getCash(businessKey); // 获取明细数据 List cashItemDOs = cashService.getCashItem(cashDO.getId()); //获取部门信息map Map deptMap = deptApi.getDeptMap(convertSet(cashItemDOs, BpmOACashItemDO::getDeptId)); // 获取银行卡信息 BankRespDTO bankRespDTO = bankApi.getBank(cashDO.getBankId()).getCheckedData(); BpmOACashRespVO cashRespVO = BpmOACashConvert.INSTANCE.convert1(cashDO, cashItemDOs, deptMap, bankRespDTO); } return bpmProcessInstancePrintDataRespVO; } } \ No newline at end of file +package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.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.oa.BpmOACashConvert; 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.BpmOACashItemDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAImprestDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReimbursementDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmConstants; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.bpm.service.oa.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.bank.dto.BankRespDTO; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.permission.PermissionApi; import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.lang.reflect.Field; import java.text.DecimalFormat; import java.time.LocalDateTime; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 *

* ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. *

* HistoricProcessInstance & ProcessInstance 的关系: * 1. *

* 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private TaskService engineTaskService; @Resource private BpmTaskAssignRuleMapper taskRuleMapper; @Resource private BpmUserGroupService userGroupService; @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource @Lazy // 解决循环依赖 private BpmMessageService messageService; @Resource private ConfigApi configApi; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); // 获得 User Map Map userMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, userMap); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())).getCheckedData(); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()).getCheckedData(); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); } @Override public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); Map processVariables = runtimeService.getVariables(instance.getProcessInstanceId()); String reason = (String) processVariables.get("approve_reason"); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessInstanceId(id) .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置当前用户 FlowableUtils.setAuthenticatedUserId(userId); // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(variables)); /** 创建流程后,添加抄送人 End add by yj 2024.1.4 */ processCCToUsers(definition, instance); /** 通过自己发起的流程 */ // approveSelfTask(instance.getId()) ; return instance.getId(); } private void approveSelfTask(String processInstanceId) { List tasks = engineTaskService.createTaskQuery().processInstanceId(processInstanceId).list(); if (tasks != null && tasks.size() > 0) { Task task = tasks.get(0); String assigneeId = task.getAssignee(); //如果当前登陆用户是审批人,那么自动审批通过 if (assigneeId.equals(SecurityFrameworkUtils.getLoginUserId().toString())) { BpmTaskApproveReqVO reqVO = new BpmTaskApproveReqVO(); reqVO.setId(task.getId()); reqVO.setReason(BpmConstants.AUTO_APPRAVAL); taskService.approveTask(getLoginUserId(), reqVO); } } } /** * 获得抄送我的流程实例的分页 * * @param userId 用户编号 * @param pageReqVO 分页请求 * @return 流程实例的分页 */ public PageResult getMyCCProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectCCPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, null); } public List getProcessInstancesGroupByModelName(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); return processInstanceExtMapper.getProcessInstancesGroupByModelName(pageReqVO); } public List getProcessInstancesGroupByResultStatus(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); return processInstanceExtMapper.getProcessInstancesGroupByResultStatus(pageReqVO); } public PageResult getStatisticsProcessInstancePage(@Valid BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectStatisticePage(pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); //获得 审批人 User Map Map assigneeUserMap = adminUserApi.getUserMap(longIds); //获得 发起人 User Map List bpieDOs = pageResult.getList(); longIds = new ArrayList<>(); for (BpmProcessInstanceExtDO bpieDO : bpieDOs) { longIds.add(bpieDO.getStartUserId()); } Map startUserMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertStatisticsPage(pageResult, taskMap, assigneeUserMap, startUserMap); } @Resource PermissionApi permissionApi; /** * 根据数据权限,查询关联操作的用户IDS * * @param pageReqVO * @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); for (BpmTaskAssignRuleDO rule : rules) { String key = rule.getTaskDefinitionKey(); //任务名称 Integer type = rule.getType(); if (!key.isEmpty() && key.equals(BpmConstants.CC_NAME) && type == 40) { StringBuffer str = new StringBuffer(); Set options = rule.getOptions(); List list = new ArrayList(options); for (Long groupId : list) { //需要根据这个groupId,查询这个组中的用户id BpmUserGroupDO userGroup = userGroupService.getUserGroup(groupId); Set userIds = userGroup.getMemberUserIds(); List userIdList = new ArrayList(userIds); for (Long user_id : userIdList) { str.append("[").append(user_id).append("]"); } } //流程是采购计划时 if (definition.getKey().equals(BpmOAProcureServiceImpl.PROCESS_KEY)) { AdminUserRespDTO userRespDTO = adminUserApi.getUser(Long.valueOf(instance.getStartUserId())).getCheckedData(); DeptRespDTO deptRespDTO = deptApi.getDept(userRespDTO.getDeptId()).getCheckedData(); //发起人部门为 生产部及以下时 if (deptRespDTO.getFlag().contains("130")) { //添加 供应部抄送 BpmUserGroupDO userGroup = userGroupService.getUserGroup(121L); Set userIds = userGroup.getMemberUserIds(); List userIdList = new ArrayList(userIds); for (Long user_id : userIdList) { str.append("[").append(user_id).append("]"); } } } String ccids = str.toString(); //根据processDefinitionId 将ccids保存到bpm_process_instance_ext中的ccids字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessDefinitionId(processDefinitionId) .setCcids(ccids).setProcessInstanceId(instance.getProcessInstanceId()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); break; } } } @Resource private BpmTaskExtMapper taskExtMapper; @Override public List getUserProcessTpo10(BpmProcessInstanceStatisticsReqVO pageReqVO) { //按审核人分组查询,统计已完成流程数量及平均耗时间 List respVOS = processInstanceExtMapper.getUserProcessTpo10(pageReqVO); if (respVOS == null || respVOS.size() == 0) { return null; } List idList = respVOS.stream() .map(BpmProcessFinishStatisticsRespVO::getUserId) .collect(Collectors.toList()); //根据userId,查询UserMap Map userMap = adminUserApi.getUserMap(idList); Long[] idsArray = new Long[userMap.size()]; // 使用 map 的 keySet() 方法获取键集合 Set keys = userMap.keySet(); // 遍历键集合,将每个键添加到数组中 int index = 0; for (Long key : keys) { idsArray[index++] = key; } pageReqVO.setUserIds(idsArray); //按审核人分组查询,未审批完成的流程数量 List bpmTaskExtDOs = processInstanceExtMapper.selectUnfinishProcessCount(pageReqVO); //按审核人分组查询,未完成的记录数 Map unFinfishCountCountMap = new HashMap<>(); for (BpmProcessFinishStatisticsRespVO item : bpmTaskExtDOs) { unFinfishCountCountMap.put(item.getUserId(), item.getUnFinfishCount()); } respVOS.forEach(respVO -> respVO.setName(userMap.get(respVO.getUserId()).getNickname())); respVOS.forEach(respVO -> respVO.setUnFinfishCount(unFinfishCountCountMap.get(respVO.getUserId()))); //获取排行榜第一记录的耗时,作为基础数据 double num = Double.parseDouble(respVOS.get(0).getUserTime()); // 先将字符串转换为双精度浮点数 int baseNumber = (int) num; // 再通过类型转换操作符将其转换为整数 DecimalFormat df = new DecimalFormat("#.00"); respVOS.forEach(respVO -> { //格式化流程完成率 float finfishCount = (float) respVO.getFinfishCount(); float unFinfishCount = respVO.getUnFinfishCount() == null ? 0 : respVO.getUnFinfishCount(); float all = finfishCount + unFinfishCount; float result = finfishCount / all; float rate = result * 100; respVO.setCompletionRate(df.format(rate) + "%"); double dValue = Double.parseDouble(respVO.getUserTime()); // 将字符串转换为double类型 int roundedValue = (int) Math.round(dValue); // 使用Math.round()进行四舍五入,并转换为int类型 respVO.setUserTime(roundedValue + ""); //格式化进度百度比, 参照最高的数据进行百分比显示 double percentage = ((int) Double.parseDouble(respVO.getUserTime()) / (double) baseNumber) * 100; respVO.setPercentage((int) Math.round(percentage)); //设置未完成 respVO.setUnFinfishCount(Integer.valueOf((int) unFinfishCount)); }); return respVOS; } @Override public BpmProcessInstanceExtDO getProcessInstanceDO(String id) { return processInstanceExtMapper.selectByProcessInstanceId(id); } @Resource private FileApi fileApi; @Resource 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); //报销业务数据 //备用金信息查询 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); // 获取明细数据 List cashItemDOs = cashService.getCashItem(cashDO.getId()); //获取部门信息map Map deptMap = deptApi.getDeptMap(convertSet(cashItemDOs, BpmOACashItemDO::getDeptId)); // 获取银行卡信息 BankRespDTO bankRespDTO = bankApi.getBank(cashDO.getBankId()).getCheckedData(); BpmOACashRespVO cashRespVO = BpmOACashConvert.INSTANCE.convert1(cashDO, cashItemDOs, deptMap, bankRespDTO); // 设置抄送人信息 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; } } \ No newline at end of file