Commit 59dfa104613d2fa8705269c19822e12b639cbbc0

Authored by puhui999
2 parents 53badfc3 9fbbce4e

Merge remote-tracking branch 'yudao/develop' into develop

# Conflicts:
#	yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java
Showing 41 changed files with 427 additions and 866 deletions
yudao-framework/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/enums/BpmnModelConstants.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.flowable.core.enums;
  2 +
  3 +/**
  4 + * 流程常量信息
  5 + */
  6 +public interface BpmnModelConstants {
  7 +
  8 + String BPMN_FILE_SUFFIX = ".bpmn";
  9 +
  10 + /**
  11 + * BPMN 中的命名空间
  12 + *
  13 + * 这个东西有可能导致无法切换工作流程的实现
  14 + */
  15 + String NAMESPACE = "http://flowable.org/bpmn";
  16 +
  17 + /**
  18 + * 自定义属性 dataType
  19 + */
  20 + String PROCESS_CUSTOM_DATA_TYPE = "dataType";
  21 +
  22 +}
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceCopyController.java
... ... @@ -49,7 +49,7 @@ public class BpmProcessInstanceCopyController {
49 49 @PostMapping("/create")
50 50 @Operation(summary = "抄送流程")
51 51 @PreAuthorize("@ss.hasPermission('bpm:process-instance-cc:create')")
52   - public CommonResult<Boolean> createProcessInstanceCC(@Valid @RequestBody BpmProcessInstanceCopyCreateReqVO createReqVO) {
  52 + public CommonResult<Boolean> createProcessInstanceCopy(@Valid @RequestBody BpmProcessInstanceCopyCreateReqVO createReqVO) {
53 53 processInstanceCopyService.createProcessInstanceCopy(getLoginUserId(), createReqVO);
54 54 return success(true);
55 55 }
... ... @@ -57,7 +57,7 @@ public class BpmProcessInstanceCopyController {
57 57 @GetMapping("/my-page")
58 58 @Operation(summary = "获得抄送流程分页列表")
59 59 @PreAuthorize("@ss.hasPermission('bpm:process-instance-cc:query')")
60   - public CommonResult<PageResult<BpmProcessInstanceCopyPageItemRespVO>> getProcessInstanceCCPage(
  60 + public CommonResult<PageResult<BpmProcessInstanceCopyPageItemRespVO>> getProcessInstanceCopyPage(
61 61 @Valid BpmProcessInstanceCopyMyPageReqVO pageReqVO) {
62 62 PageResult<BpmProcessInstanceCopyDO> pageResult = processInstanceCopyService.getMyProcessInstanceCopyPage(getLoginUserId(), pageReqVO);
63 63 if (CollUtil.isEmpty(pageResult.getList())) {
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmProcessInstanceCopyVO.java deleted
1   -package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task;
2   -
3   -import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.Data;
5   -
6   -import java.time.LocalDateTime;
7   -
8   -// TODO @kyle:1)明确是 Req 还是 Resp;2)注释可以合并到 swagger 里;3)example 写一下,这样一些 mock 接口平台可以读取 example
9   -/**
10   - * 流程抄送视图对象
11   - */
12   -@Data
13   -public class BpmProcessInstanceCopyVO {
14   -
15   - /**
16   - * 编号
17   - */
18   - @Schema(description = "抄送主键")
19   - private Long id;
20   -
21   - /**
22   - * 发起人Id
23   - */
24   - @Schema(description = "发起人Id")
25   - private Long startUserId;
26   -
27   - @Schema(description = "发起人别名")
28   - private String startUserNickname;
29   -
30   - /**
31   - * 流程主键
32   - */
33   - @Schema(description = "流程实例的主键")
34   - private String processInstanceId;
35   -
36   - @Schema(description = "流程实例的名字")
37   - private String processInstanceName;
38   -
39   - /**
40   - * 任务主键
41   - */
42   - @Schema(description = "发起抄送的任务编号")
43   - private String taskId;
44   -
45   - @Schema(description = "发起抄送的任务名称")
46   - private String taskName;
47   - /**
48   - * 用户主键
49   - */
50   - @Schema(description = "用户编号")
51   - private Long userId;
52   -
53   - @Schema(description = "用户别名")
54   - private Long userNickname;
55   -
56   - @Schema(description = "抄送原因")
57   - private String reason;
58   -
59   - @Schema(description = "抄送人")
60   - private String creator;
61   -
62   - @Schema(description = "抄送时间")
63   - private LocalDateTime createTime;
64   -
65   -}
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/handler/MultiInstanceHandler.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.framework.flowable.core.handler;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.util.ObjectUtil;
  5 +import cn.iocoder.yudao.framework.flowable.core.enums.BpmnModelConstants;
  6 +import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
  7 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  8 +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
  9 +import jakarta.annotation.Resource;
  10 +import lombok.AllArgsConstructor;
  11 +import org.flowable.bpmn.model.FlowElement;
  12 +import org.flowable.bpmn.model.UserTask;
  13 +import org.flowable.engine.delegate.DelegateExecution;
  14 +import org.springframework.stereotype.Component;
  15 +
  16 +import java.util.ArrayList;
  17 +import java.util.LinkedHashSet;
  18 +import java.util.List;
  19 +import java.util.Set;
  20 +import java.util.stream.Collectors;
  21 +
  22 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  23 +
  24 +// TODO @芋艿:bpmn 分配人融合时,需要搞下这块;
  25 +/**
  26 + * 多实例处理类
  27 + */
  28 +@AllArgsConstructor
  29 +@Component("multiInstanceHandler")
  30 +public class MultiInstanceHandler {
  31 +
  32 + @Resource
  33 + private AdminUserApi userApi;
  34 +
  35 + @Resource
  36 + private PermissionApi permissionApi;
  37 +
  38 + /**
  39 + * 流程发起人那种情况不需要处理,
  40 + * 由 flowable 完成
  41 + *
  42 + * @param execution flowable的执行对象
  43 + * @return 用户ID
  44 + */
  45 + public Set<String> getUserIds(DelegateExecution execution) {
  46 + Set<String> candidateUserIds = new LinkedHashSet<>();
  47 + FlowElement flowElement = execution.getCurrentFlowElement();
  48 + if (ObjectUtil.isNotEmpty(flowElement) && flowElement instanceof UserTask userTask) {
  49 + String dataType = userTask.getAttributeValue(BpmnModelConstants.NAMESPACE, BpmnModelConstants.PROCESS_CUSTOM_DATA_TYPE);
  50 + if ("USERS".equals(dataType) && CollUtil.isNotEmpty(userTask.getCandidateUsers())) {
  51 + // 添加候选用户id
  52 + candidateUserIds.addAll(userTask.getCandidateUsers());
  53 + } else if (CollUtil.isNotEmpty(userTask.getCandidateGroups())) {
  54 + // 获取组的ID,角色ID集合或部门ID集合
  55 + List<Long> groups = userTask.getCandidateGroups().stream()
  56 + // 例如部门DEPT100,100才是部门id
  57 + .map(item -> Long.parseLong(item.substring(4)))
  58 + .collect(Collectors.toList());
  59 + List<Long> userIds = new ArrayList<>();
  60 + if ("ROLES".equals(dataType)) {
  61 + // 通过角色id,获取所有用户id集合
  62 + Set<Long> userRoleIdListByRoleIds = permissionApi.getUserRoleIdListByRoleIds(groups);
  63 + userIds = new ArrayList<>(userRoleIdListByRoleIds);
  64 + } else if ("DEPTS".equals(dataType)) {
  65 + // 通过部门id,获取所有用户id集合
  66 + List<AdminUserRespDTO> userListByDeptIds = userApi.getUserListByDeptIds(groups);
  67 + userIds = convertList(userListByDeptIds, AdminUserRespDTO::getId);
  68 + }
  69 + // 添加候选用户id
  70 + userIds.forEach(id -> candidateUserIds.add(String.valueOf(id)));
  71 + }
  72 + }
  73 + return candidateUserIds;
  74 + }
  75 +
  76 +}
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java
... ... @@ -5,8 +5,8 @@ import cn.hutool.core.util.ObjectUtil;
5 5 import cn.hutool.core.util.StrUtil;
6 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 7 import cn.iocoder.yudao.framework.common.util.object.PageUtils;
  8 +import cn.iocoder.yudao.framework.flowable.core.enums.BpmnModelConstants;
8 9 import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils;
9   -import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils;
10 10 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
11 11 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionListReqVO;
12 12 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO;
... ... @@ -17,6 +17,8 @@ import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
17 17 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
18 18 import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmProcessDefinitionExtMapper;
19 19 import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO;
  20 +import jakarta.annotation.Resource;
  21 +import jakarta.validation.Valid;
20 22 import lombok.extern.slf4j.Slf4j;
21 23 import org.flowable.bpmn.converter.BpmnXMLConverter;
22 24 import org.flowable.bpmn.model.BpmnModel;
... ... @@ -29,13 +31,10 @@ import org.flowable.engine.repository.ProcessDefinitionQuery;
29 31 import org.springframework.stereotype.Service;
30 32 import org.springframework.validation.annotation.Validated;
31 33  
32   -import jakarta.annotation.Resource;
33   -import jakarta.validation.Valid;
34 34 import java.util.*;
35 35  
36 36 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
37 37 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
38   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
39 38 import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_DEFINITION_KEY_NOT_MATCH;
40 39 import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_DEFINITION_NAME_NOT_MATCH;
41 40 import static java.util.Collections.emptyList;
... ... @@ -53,8 +52,6 @@ import static java.util.Collections.emptyList;
53 52 @Slf4j
54 53 public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionService {
55 54  
56   - private static final String BPMN_FILE_SUFFIX = ".bpmn";
57   -
58 55 @Resource
59 56 private RepositoryService repositoryService;
60 57  
... ... @@ -125,7 +122,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
125 122 // 创建 Deployment 部署
126 123 Deployment deploy = repositoryService.createDeployment()
127 124 .key(createReqDTO.getKey()).name(createReqDTO.getName()).category(createReqDTO.getCategory())
128   - .addBytes(createReqDTO.getKey() + BPMN_FILE_SUFFIX, createReqDTO.getBpmnBytes())
  125 + .addBytes(createReqDTO.getKey() + BpmnModelConstants.BPMN_FILE_SUFFIX, createReqDTO.getBpmnBytes())
129 126 .tenantId(TenantContextHolder.getTenantIdStr())
130 127 .deploy();
131 128  
... ...
yudao-module-crm/pom.xml
... ... @@ -10,8 +10,6 @@
10 10 <modules>
11 11 <module>yudao-module-crm-api</module>
12 12 <module>yudao-module-crm-biz</module>
13   - <module>yudao-module-bi-biz</module>
14   - <module>yudao-module-bi-api</module>
15 13 </modules>
16 14 <modelVersion>4.0.0</modelVersion>
17 15 <artifactId>yudao-module-crm</artifactId>
... ...
yudao-module-crm/yudao-module-bi-api/pom.xml deleted
1   -<?xml version="1.0" encoding="UTF-8"?>
2   -<project xmlns="http://maven.apache.org/POM/4.0.0"
3   - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4   - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5   - <parent>
6   - <groupId>cn.iocoder.boot</groupId>
7   - <artifactId>yudao-module-crm</artifactId>
8   - <version>${revision}</version>
9   - </parent>
10   - <modelVersion>4.0.0</modelVersion>
11   - <artifactId>yudao-module-bi-api</artifactId>
12   -
13   - <name>${project.artifactId}</name>
14   - <description>
15   - bi 模块 API,暴露给其它模块调用
16   - </description>
17   -
18   - <dependencies>
19   - <dependency>
20   - <groupId>cn.iocoder.boot</groupId>
21   - <artifactId>yudao-module-system-api</artifactId>
22   - <version>${revision}</version>
23   - </dependency>
24   - <dependency>
25   - <groupId>cn.iocoder.boot</groupId>
26   - <artifactId>yudao-module-crm-api</artifactId>
27   - <version>${revision}</version>
28   - </dependency>
29   -
30   - <!-- 业务组件 -->
31   - <dependency>
32   - <groupId>cn.iocoder.boot</groupId>
33   - <artifactId>yudao-spring-boot-starter-biz-operatelog</artifactId>
34   - </dependency>
35   - <dependency>
36   - <groupId>cn.iocoder.boot</groupId>
37   - <artifactId>yudao-spring-boot-starter-biz-ip</artifactId>
38   - </dependency>
39   -
40   - <!-- Web 相关 -->
41   - <dependency>
42   - <groupId>cn.iocoder.boot</groupId>
43   - <artifactId>yudao-spring-boot-starter-web</artifactId>
44   - </dependency>
45   -
46   - <dependency>
47   - <groupId>cn.iocoder.boot</groupId>
48   - <artifactId>yudao-spring-boot-starter-security</artifactId>
49   - </dependency>
50   -
51   - <!-- DB 相关 -->
52   - <dependency>
53   - <groupId>cn.iocoder.boot</groupId>
54   - <artifactId>yudao-spring-boot-starter-mybatis</artifactId>
55   - </dependency>
56   -
57   - <!-- 工具类相关 -->
58   - <dependency>
59   - <groupId>cn.iocoder.boot</groupId>
60   - <artifactId>yudao-spring-boot-starter-excel</artifactId>
61   - </dependency>
62   - <dependency>
63   - <groupId>cn.iocoder.boot</groupId>
64   - <artifactId>yudao-spring-boot-starter-biz-dict</artifactId>
65   - </dependency>
66   -
67   - <!-- Test 测试相关 -->
68   - <dependency>
69   - <groupId>cn.iocoder.boot</groupId>
70   - <artifactId>yudao-spring-boot-starter-test</artifactId>
71   - </dependency>
72   - </dependencies>
73   -</project>
74 0 \ No newline at end of file
yudao-module-crm/yudao-module-bi-api/src/main/java/cn/iocoder/yudao/module/bi/api/package-info.java deleted
1   -package cn.iocoder.yudao.module.bi.api;
2 0 \ No newline at end of file
yudao-module-crm/yudao-module-bi-api/src/main/java/cn/iocoder/yudao/module/bi/enums/package-info.java deleted
1   -package cn.iocoder.yudao.module.bi.enums;
2 0 \ No newline at end of file
yudao-module-crm/yudao-module-bi-biz/pom.xml deleted
1   -<?xml version="1.0" encoding="UTF-8"?>
2   -<project xmlns="http://maven.apache.org/POM/4.0.0"
3   - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4   - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5   - <parent>
6   - <groupId>cn.iocoder.boot</groupId>
7   - <artifactId>yudao-module-crm</artifactId>
8   - <version>${revision}</version>
9   - </parent>
10   - <modelVersion>4.0.0</modelVersion>
11   - <artifactId>yudao-module-bi-biz</artifactId>
12   -
13   - <name>${project.artifactId}</name>
14   - <description>
15   - crm 包下,商业智能(Business Intelligence)。
16   - 例如说:报表、图表、数据分析等等
17   - </description>
18   -
19   - <dependencies>
20   - <dependency>
21   - <groupId>cn.iocoder.boot</groupId>
22   - <artifactId>yudao-module-system-api</artifactId>
23   - <version>${revision}</version>
24   - </dependency>
25   - <dependency>
26   - <groupId>cn.iocoder.boot</groupId>
27   - <artifactId>yudao-module-crm-api</artifactId>
28   - <version>${revision}</version>
29   - </dependency>
30   -
31   - <!-- 业务组件 -->
32   - <dependency>
33   - <groupId>cn.iocoder.boot</groupId>
34   - <artifactId>yudao-spring-boot-starter-biz-operatelog</artifactId>
35   - </dependency>
36   - <dependency>
37   - <groupId>cn.iocoder.boot</groupId>
38   - <artifactId>yudao-spring-boot-starter-biz-ip</artifactId>
39   - </dependency>
40   -
41   - <!-- Web 相关 -->
42   - <dependency>
43   - <groupId>cn.iocoder.boot</groupId>
44   - <artifactId>yudao-spring-boot-starter-web</artifactId>
45   - </dependency>
46   -
47   - <dependency>
48   - <groupId>cn.iocoder.boot</groupId>
49   - <artifactId>yudao-spring-boot-starter-security</artifactId>
50   - </dependency>
51   -
52   - <!-- DB 相关 -->
53   - <dependency>
54   - <groupId>cn.iocoder.boot</groupId>
55   - <artifactId>yudao-spring-boot-starter-mybatis</artifactId>
56   - </dependency>
57   -
58   - <!-- 工具类相关 -->
59   - <dependency>
60   - <groupId>cn.iocoder.boot</groupId>
61   - <artifactId>yudao-spring-boot-starter-excel</artifactId>
62   - </dependency>
63   - <dependency>
64   - <groupId>cn.iocoder.boot</groupId>
65   - <artifactId>yudao-spring-boot-starter-biz-dict</artifactId>
66   - </dependency>
67   -
68   - <!-- Test 测试相关 -->
69   - <dependency>
70   - <groupId>cn.iocoder.boot</groupId>
71   - <artifactId>yudao-spring-boot-starter-test</artifactId>
72   - </dependency>
73   - </dependencies>
74   -</project>
75 0 \ No newline at end of file
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/BiRankingController.java deleted
1   -package cn.iocoder.yudao.module.bi.controller.admin.ranking;
2   -
3   -
4   -import cn.iocoder.yudao.framework.common.pojo.CommonResult;
5   -import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiContractRanKingRespVO;
6   -import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiRankReqVO;
7   -import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiReceivablesRanKingRespVO;
8   -import cn.iocoder.yudao.module.bi.service.ranking.BiRankingService;
9   -import io.swagger.v3.oas.annotations.Operation;
10   -import io.swagger.v3.oas.annotations.tags.Tag;
11   -import jakarta.annotation.Resource;
12   -import org.springframework.security.access.prepost.PreAuthorize;
13   -import org.springframework.validation.annotation.Validated;
14   -import org.springframework.web.bind.annotation.GetMapping;
15   -import org.springframework.web.bind.annotation.RequestMapping;
16   -import org.springframework.web.bind.annotation.RestController;
17   -
18   -import java.util.List;
19   -
20   -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
21   -
22   -// TODO @anhaohao:写了 swagger 注解,不写注释哈
23   -/**
24   - * @author anhaohao
25   - */
26   -@Tag(name = "管理后台 - 排行榜")
27   -@RestController
28   -@RequestMapping("/bi/ranking")
29   -@Validated
30   -public class BiRankingController {
31   -
32   - @Resource
33   - private BiRankingService biRankingService;
34   -
35   - /**
36   - * 合同金额排行榜
37   - */
38   - @GetMapping("/contract-ranking")
39   - @Operation(summary = "合同金额排行榜")
40   - @PreAuthorize("@ss.hasPermission('bi:ranking:query')")
41   - public CommonResult<List<BiContractRanKingRespVO>> contractAmountRanking(BiRankReqVO biRankReqVO) {
42   - return success(biRankingService.contractRanKing(biRankReqVO));
43   - }
44   -
45   - /**
46   - * 回款金额排行榜
47   - */
48   - @GetMapping("/receivables-ranking")
49   - @Operation(summary = "回款金额排行榜")
50   - @PreAuthorize("@ss.hasPermission('bi:ranking:query')")
51   - public CommonResult<List<BiReceivablesRanKingRespVO>> receivablesRanKing(BiRankReqVO biRankReqVO) {
52   - return success(biRankingService.receivablesRanKing(biRankReqVO));
53   - }
54   -
55   -}
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/vo/BiContractRanKingRespVO.java deleted
1   -package cn.iocoder.yudao.module.bi.controller.admin.ranking.vo;
2   -
3   -import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.Data;
5   -
6   -// TODO @anhaohao:VO 类有 swagger 注解,不写注释哈
7   -/**
8   - * 管理后台 - BI 排行榜 Response VO
9   - *
10   - * @author anhaohao
11   - */
12   -@Schema(description = "管理后台 - BI 合同金额排行榜 Response VO")
13   -@Data
14   -public class BiContractRanKingRespVO {
15   -
16   - // TODO @anhaohao:如果一定返回的字段,需要加 requiredMode = Schema.RequiredMode.REQUIRED, 哈
17   - @Schema(description = "金额", example = "1")
18   - private Integer price;
19   -
20   - @Schema(description = "姓名", example = "1")
21   - private String nickname;
22   -
23   - @Schema(description = "部门名称", example = "1")
24   - private String deptName;
25   -
26   -}
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/vo/BiParams.java deleted
1   -package cn.iocoder.yudao.module.bi.controller.admin.ranking.vo;
2   -
3   -import cn.iocoder.yudao.framework.common.pojo.PageParam;
4   -import io.swagger.v3.oas.annotations.media.Schema;
5   -import lombok.Data;
6   -import lombok.EqualsAndHashCode;
7   -
8   -import java.util.List;
9   -
10   -// TODO @anhaohao:这个类的命名,还是保持和其它一致使用 ReqVO 结尾;例如说,CrmStatisticsCommonParamReqVO
11   -/**
12   - * @author anhaohao
13   - * bi参数
14   - */
15   -@EqualsAndHashCode(callSuper = true)
16   -@Schema(description = "bi查询相关参数")
17   -@Data
18   -public class BiParams extends PageParam {
19   -
20   - @Schema(description = "部门ID")
21   - private Long deptId;
22   -
23   - @Schema(description = "用户ID")
24   - private Long userId;
25   -
26   - @Schema(description = "用户IDs")
27   - private List<Long> userIds;
28   -
29   - // TODO @anhaohao:这个字段,可以融合到 startTime、endTime 里去,交给前端计算哈;
30   - @Schema(description = "类型")
31   - private String type;
32   -
33   - // TODO @anhaohao:还是使用 LocalDateTime
34   - @Schema(description = "开始时间")
35   - private String startTime;
36   -
37   - @Schema(description = "结束时间")
38   - private String endTime;
39   -
40   - // TODO @anhaohao:这个字段,是不是直接只基于 deptId 和 userId 来判断即可哈?
41   - @Schema(description = "0 部门 1员工")
42   - private Integer isUser = 1;
43   -
44   -}
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/vo/BiRankReqVO.java deleted
1   -package cn.iocoder.yudao.module.bi.controller.admin.ranking.vo;
2   -
3   -import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.Data;
5   -
6   -/**
7   - * 管理后台 - 排行榜 Request VO
8   - *
9   - * @author anhaohao
10   - */
11   -@Schema(description = "管理后台 - 排行榜 Request VO")
12   -@Data
13   -public class BiRankReqVO {
14   -
15   - @Schema(description = "部门id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
16   - private Long deptId;
17   -
18   - // TODO @anhaohao:这个字段,参考 BiParams 的 type 建议
19   - @Schema(description = "分析类型(1.今天 2.昨天 3.本周 4.上周 5.本月 6.上月 7.本季度 8.上季度 9.本年 10 上年)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
20   - private String type;
21   -
22   -}
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/vo/BiReceivablesRanKingRespVO.java deleted
1   -package cn.iocoder.yudao.module.bi.controller.admin.ranking.vo;
2   -
3   -import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.Data;
5   -
6   -// TODO @anhaohao:参考 BiContractRanKingRespVO 的建议
7   -/**
8   - * 管理后台 - BI 排行榜 Response VO
9   - *
10   - * @author anhaohao
11   - */
12   -@Schema(description = "管理后台 - BI 合同金额排行榜 Response VO")
13   -@Data
14   -public class BiReceivablesRanKingRespVO {
15   -
16   - @Schema(description = "金额", example = "100")
17   - private Integer price;
18   -
19   - @Schema(description = "姓名", example = "张三")
20   - private String nickname;
21   -
22   - @Schema(description = "部门名称", example = "研发部")
23   - private String deptName;
24   -
25   -}
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/package-info.java deleted
1   -/**
2   - * 提供 RESTful API 给前端:
3   - * 1. admin 包:提供给管理后台 yudao-ui-admin 前端项目
4   - * 2. app 包:提供给用户 APP yudao-ui-app 前端项目,它的 Controller 和 VO 都要添加 App 前缀,用于和管理后台进行区分
5   - */
6   -package cn.iocoder.yudao.module.bi.controller;
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/dal/mysql/BiRankingMapper.java deleted
1   -package cn.iocoder.yudao.module.bi.dal.mysql;
2   -
3   -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
4   -import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiContractRanKingRespVO;
5   -import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiReceivablesRanKingRespVO;
6   -import cn.iocoder.yudao.module.bi.util.BiTimeUtil;
7   -import org.apache.ibatis.annotations.Mapper;
8   -
9   -import java.util.List;
10   -
11   -/**
12   - * @author anhaohao
13   - */
14   -@Mapper
15   -public interface BiRankingMapper extends BaseMapperX {
16   - /**
17   - * 合同金额排行榜
18   - *
19   - * @param biTimeEntity 参数
20   - * @return List<BiContractAmountRankingRespVO>
21   - */
22   - List<BiContractRanKingRespVO> contractRanKing(BiTimeUtil.BiTimeEntity biTimeEntity);
23   -
24   - /**
25   - * 回款金额排行榜
26   - *
27   - * @param biTimeEntity 参数
28   - * @return List<BiContractAmountRankingRespVO>
29   - */
30   - List<BiReceivablesRanKingRespVO> receivablesRanKing(BiTimeUtil.BiTimeEntity biTimeEntity);
31   -}
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/framework/package-info.java deleted
1   -/**
2   - * 属于 bi 模块的 framework 封装
3   - *
4   - * @author 芋道源码
5   - */
6   -package cn.iocoder.yudao.module.bi.framework;
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/framework/web/config/BiWebConfiguration.java deleted
1   -package cn.iocoder.yudao.module.bi.framework.web.config;
2   -
3   -import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration;
4   -import org.springdoc.core.models.GroupedOpenApi;
5   -import org.springframework.context.annotation.Bean;
6   -import org.springframework.context.annotation.Configuration;
7   -
8   -/**
9   - * bi 模块的 web 组件的 Configuration
10   - *
11   - * @author 芋道源码
12   - */
13   -@Configuration(proxyBeanMethods = false)
14   -public class BiWebConfiguration {
15   -
16   - /**
17   - * bi 模块的 API 分组
18   - */
19   - @Bean
20   - public GroupedOpenApi biGroupedOpenApi() {
21   - return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("bi");
22   - }
23   -
24   -}
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/framework/web/package-info.java deleted
1   -/**
2   - * bi 模块的 web 配置
3   - */
4   -package cn.iocoder.yudao.module.bi.framework.web;
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/package-info.java deleted
1   -/**
2   - * crm 包下,商业智能(Business Intelligence)。
3   - * 例如说:报表、图表、数据分析等等
4   - * <p>
5   - * 1. Controller URL:以 /bi/ 开头,避免和其它 Module 冲突
6   - *
7   - * TODO @anhaohao:mall 当时独立拆分一个 statistics 模块的原因,是因为 mall 拆分了多个模块,没有模块适合承接统计的能力,所以独立了。
8   - * TODO crm 因为没有拆分,所以可以直接放在 crm 模块下面;这样,我们可以在 controller/admin 和 service 下,新建一个 bi 包,专门放置统计的代码。
9   - */
10   -package cn.iocoder.yudao.module.bi;
11 0 \ No newline at end of file
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/service/ranking/BiRankingService.java deleted
1   -package cn.iocoder.yudao.module.bi.service.ranking;
2   -
3   -import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiContractRanKingRespVO;
4   -import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiRankReqVO;
5   -import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiReceivablesRanKingRespVO;
6   -
7   -import java.util.List;
8   -
9   -/**
10   - * BI 排行榜 Service 接口
11   - *
12   - * @author anhaohao
13   - */
14   -public interface BiRankingService { // TODO @anhaohao:第一个方法,和类要有一个空行
15   - /**
16   - * 合同金额排行榜
17   - *
18   - * @param biRankReqVO 参数
19   - * @return List<BiContractAmountRankingRespVO>
20   - */
21   - List<BiContractRanKingRespVO> contractRanKing(BiRankReqVO biRankReqVO);
22   -
23   - /**
24   - * 回款金额排行榜
25   - *
26   - * @param biRankReqVO 参数
27   - * @return List<BiContractAmountRankingRespVO>
28   - */
29   - List<BiReceivablesRanKingRespVO> receivablesRanKing(BiRankReqVO biRankReqVO);
30   -}
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/service/ranking/BiRankingServiceImpl.java deleted
1   -package cn.iocoder.yudao.module.bi.service.ranking;
2   -
3   -import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiContractRanKingRespVO;
4   -import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiParams;
5   -import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiRankReqVO;
6   -import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiReceivablesRanKingRespVO;
7   -import cn.iocoder.yudao.module.bi.dal.mysql.BiRankingMapper;
8   -import cn.iocoder.yudao.module.bi.util.BiTimeUtil;
9   -import jakarta.annotation.Resource;
10   -import org.springframework.stereotype.Service;
11   -import org.springframework.validation.annotation.Validated;
12   -
13   -import java.util.ArrayList;
14   -import java.util.List;
15   -
16   -/**
17   - * @author anhaohao
18   - */
19   -@Service(value = "biRankService")
20   -@Validated
21   -public class BiRankingServiceImpl implements BiRankingService {
22   -
23   - @Resource
24   - private BiRankingMapper biRankingMapper;
25   -
26   - @Override
27   - public List<BiContractRanKingRespVO> contractRanKing(BiRankReqVO biRankReqVO) {
28   - BiParams biParams = new BiParams();
29   - biParams.setType(biRankReqVO.getType());
30   - biParams.setDeptId(biRankReqVO.getDeptId());
31   - biParams.setIsUser(0);
32   - BiTimeUtil.BiTimeEntity biTimeEntity = BiTimeUtil.analyzeType(biParams);
33   - List<Long> userIds = biTimeEntity.getUserIds();
34   - if (userIds.isEmpty()) {
35   - return new ArrayList<>();
36   - }
37   - return biRankingMapper.contractRanKing(biTimeEntity);
38   - }
39   -
40   - @Override
41   - public List<BiReceivablesRanKingRespVO> receivablesRanKing(BiRankReqVO biRankReqVO) {
42   - BiParams biParams = new BiParams();
43   - biParams.setType(biRankReqVO.getType());
44   - biParams.setDeptId(biRankReqVO.getDeptId());
45   - biParams.setIsUser(0);
46   - BiTimeUtil.BiTimeEntity biTimeEntity = BiTimeUtil.analyzeType(biParams);
47   - List<Long> userIds = biTimeEntity.getUserIds();
48   - if (userIds.isEmpty()) {
49   - return new ArrayList<>();
50   - }
51   - return biRankingMapper.receivablesRanKing(biTimeEntity);
52   - }
53   -}
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/util/BiTimeUtil.java deleted
1   -package cn.iocoder.yudao.module.bi.util;
2   -
3   -import cn.hutool.core.date.DateUnit;
4   -import cn.hutool.core.date.DateUtil;
5   -import cn.hutool.core.util.StrUtil;
6   -import cn.hutool.extra.spring.SpringUtil;
7   -import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
8   -import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiParams;
9   -import cn.iocoder.yudao.module.system.api.dept.DeptApi;
10   -import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
11   -import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
12   -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
13   -import lombok.Data;
14   -import lombok.experimental.Accessors;
15   -
16   -import java.util.ArrayList;
17   -import java.util.Date;
18   -import java.util.List;
19   -
20   -/**
21   - * bi时间工具类
22   - *
23   - * @author anhaohao
24   - */
25   -public class BiTimeUtil {
26   -
27   - public static BiTimeEntity analyzeType(BiParams biParams) {
28   - // 解析时间
29   - BiTimeEntity biTimeEntity = analyzeTime(biParams);
30   - // 解析权限
31   - // TODO @anhaohao:涉及到数据的读取,不放在 Util 里,还是搞会到 Service 哈;
32   - biTimeEntity.setUserIds(analyzeAuth(biParams));
33   - return biTimeEntity;
34   - }
35   -
36   - /**
37   - * 解析权限
38   - *
39   - * @param biParams bi参数
40   - * @return List<Long>
41   - */
42   - public static List<Long> analyzeAuth(BiParams biParams) {
43   - List<Long> userIdList = new ArrayList<>();
44   - Long deptId = biParams.getDeptId();
45   - Long userId = biParams.getUserId();
46   - Integer isUser = biParams.getIsUser();
47   - // 获取部门和用户的api
48   - DeptApi deptApi = SpringUtil.getBean("deptApiImpl");
49   - AdminUserApi adminUserApi = SpringUtil.getBean("adminUserApiImpl");
50   - // 0.部门 1.用户
51   - if (isUser == 0) {
52   - if (deptId == null) {
53   - deptId = adminUserApi.getUser(SecurityFrameworkUtils.getLoginUserId()).getDeptId();
54   - }
55   - List<DeptRespDTO> childDeptList = deptApi.getChildDeptList(deptId);
56   - List<Long> deptIds = new ArrayList<>();
57   - deptIds.add(deptId);
58   - if (childDeptList != null && !childDeptList.isEmpty()) {
59   - for (DeptRespDTO deptRespDTO : childDeptList) {
60   - deptIds.add(deptRespDTO.getId());
61   - }
62   - }
63   - // 获取部门下的用户
64   - adminUserApi.getUserListByDeptIds(deptIds).forEach(adminUserRespDTO -> userIdList.add(adminUserRespDTO.getId()));
65   - } else {
66   - if (userId == null) {
67   - List<AdminUserRespDTO> userListBySubordinate = adminUserApi.getUserListBySubordinate(SecurityFrameworkUtils.getLoginUserId());
68   - userListBySubordinate.forEach(adminUserRespDTO -> userIdList.add(adminUserRespDTO.getId()));
69   - } else {
70   - userIdList.add(userId);
71   - }
72   - }
73   - return userIdList;
74   - }
75   -
76   -
77   - /**
78   - * 解析时间
79   - *
80   - * @param biParams bi参数
81   - * @return BiTimeEntity
82   - */
83   - public static BiTimeEntity analyzeTime(BiParams biParams) {
84   - Date beginDate = DateUtil.date();
85   - Date endDate = DateUtil.date();
86   - int cycleNum = 12;
87   - String sqlDateFormat = "%Y%m";
88   - String dateFormat = "yyyyMM";
89   - String type = biParams.getType();
90   - String startTime = biParams.getStartTime();
91   - String endTime = biParams.getEndTime();
92   - if (StrUtil.isNotEmpty(type)) {
93   - //1.今天 2.昨天 3.本周 4.上周 5.本月 6.上月 7.本季度 8.上季度 9.本年 10 上年
94   - switch (type) {
95   - case "1":
96   - beginDate = DateUtil.beginOfDay(DateUtil.date());
97   - endDate = DateUtil.endOfDay(DateUtil.date());
98   - sqlDateFormat = "%Y%m%d";
99   - dateFormat = "yyyyMMdd";
100   - cycleNum = 1;
101   - break;
102   - case "2":
103   - beginDate = DateUtil.beginOfDay(new Date(System.currentTimeMillis() - 86400000));
104   - endDate = DateUtil.endOfDay(new Date(System.currentTimeMillis() - 86400000));
105   - sqlDateFormat = "%Y%m%d";
106   - dateFormat = "yyyyMMdd";
107   - cycleNum = 1;
108   - break;
109   - case "3":
110   - beginDate = DateUtil.beginOfWeek(DateUtil.date());
111   - endDate = DateUtil.endOfWeek(DateUtil.date());
112   - sqlDateFormat = "%Y%m%d";
113   - dateFormat = "yyyyMMdd";
114   - cycleNum = 7;
115   - break;
116   - case "4":
117   - beginDate = DateUtil.beginOfWeek(DateUtil.offsetWeek(DateUtil.date(), -1));
118   - endDate = DateUtil.endOfWeek(DateUtil.offsetWeek(DateUtil.date(), -1));
119   - sqlDateFormat = "%Y%m%d";
120   - dateFormat = "yyyyMMdd";
121   - cycleNum = 7;
122   - break;
123   - case "5":
124   - beginDate = DateUtil.beginOfMonth(DateUtil.date());
125   - endDate = DateUtil.endOfMonth(DateUtil.date());
126   - sqlDateFormat = "%Y%m%d";
127   - dateFormat = "yyyyMMdd";
128   - cycleNum = (int) DateUtil.between(beginDate, endDate, DateUnit.DAY) + 1;
129   - break;
130   - case "6":
131   - beginDate = DateUtil.beginOfMonth(DateUtil.offsetMonth(DateUtil.date(), -1));
132   - endDate = DateUtil.endOfMonth(DateUtil.offsetMonth(DateUtil.date(), -1));
133   - sqlDateFormat = "%Y%m%d";
134   - dateFormat = "yyyyMMdd";
135   - cycleNum = (int) DateUtil.between(beginDate, endDate, DateUnit.DAY) + 1;
136   - break;
137   - case "7":
138   - beginDate = DateUtil.beginOfQuarter(DateUtil.date());
139   - endDate = DateUtil.endOfQuarter(DateUtil.date());
140   - cycleNum = 3;
141   - break;
142   - case "8":
143   - beginDate = DateUtil.beginOfQuarter(DateUtil.offsetMonth(DateUtil.date(), -3));
144   - endDate = DateUtil.endOfQuarter(DateUtil.offsetMonth(DateUtil.date(), -3));
145   - cycleNum = 3;
146   - break;
147   - case "9":
148   - beginDate = DateUtil.beginOfYear(DateUtil.date());
149   - endDate = DateUtil.endOfYear(DateUtil.date());
150   - break;
151   - case "10":
152   - beginDate = DateUtil.beginOfYear(DateUtil.offsetMonth(DateUtil.date(), -12));
153   - endDate = DateUtil.endOfYear(DateUtil.offsetMonth(DateUtil.date(), -12));
154   - break;
155   - default:
156   - break;
157   - }
158   - } else if (StrUtil.isNotEmpty(startTime) && StrUtil.isNotEmpty(endTime)) {
159   - Date start;
160   - Date end;
161   - if (startTime.length() == 6) {
162   - start = DateUtil.parse(startTime, "yyyyMM");
163   - end = DateUtil.endOfMonth(DateUtil.parse(endTime, "yyyyMM"));
164   - } else {
165   - start = DateUtil.parse(startTime);
166   - end = DateUtil.parse(endTime);
167   - }
168   - Integer startMonth = Integer.valueOf(DateUtil.format(start, "yyyyMM"));
169   - int endMonth = Integer.parseInt(DateUtil.format(end, "yyyyMM"));
170   - if (startMonth.equals(endMonth)) {
171   - sqlDateFormat = "%Y%m%d";
172   - dateFormat = "yyyyMMdd";
173   - long diffDay = DateUtil.between(start, end, DateUnit.DAY);
174   - cycleNum = (int) diffDay + 1;
175   - } else {
176   - sqlDateFormat = "%Y%m";
177   - dateFormat = "yyyyMM";
178   - int diffYear = Integer.parseInt(Integer.toString(endMonth).substring(0, 4)) - Integer.parseInt(startMonth.toString().substring(0, 4));
179   - int diffMonth = endMonth % 100 - startMonth % 100 + 1;
180   - cycleNum = diffYear * 12 + diffMonth;
181   - }
182   - beginDate = start;
183   - endDate = end;
184   - }
185   - Integer beginTime = Integer.valueOf(DateUtil.format(beginDate, dateFormat));
186   - Integer finalTime = Integer.valueOf(DateUtil.format(endDate, dateFormat));
187   - return new BiTimeEntity(sqlDateFormat, dateFormat, beginDate, endDate, cycleNum, beginTime, finalTime, new ArrayList<>());
188   - }
189   -
190   - @Data
191   - @Accessors(chain = true)
192   - public static class BiTimeEntity {
193   - /**
194   - * sql日期格式化
195   - */
196   - private String sqlDateFormat;
197   -
198   - /**
199   - * 日期格式化
200   - */
201   - private String dateFormat;
202   -
203   - /**
204   - * 开始时间
205   - */
206   - private Date beginDate;
207   -
208   - /**
209   - * 结束时间
210   - */
211   - private Date endDate;
212   -
213   - /**
214   - * 周期
215   - */
216   - private Integer cycleNum;
217   -
218   - /**
219   - * 开始时间 字符串格式 如20200101
220   - */
221   - private Integer beginTime;
222   -
223   - /**
224   - * 结束时间 字符串格式 如20200101
225   - */
226   - private Integer finalTime;
227   -
228   - /**
229   - * user列表
230   - */
231   - private List<Long> userIds = new ArrayList<>();
232   - private Integer page;
233   - private Integer limit;
234   -
235   - public BiTimeEntity(String sqlDateFormat, String dateFormat, Date beginDate, Date endDate, Integer cycleNum, Integer beginTime, Integer finalTime, List<Long> userIds) {
236   - this.sqlDateFormat = sqlDateFormat;
237   - this.dateFormat = dateFormat;
238   - this.beginDate = beginDate;
239   - this.endDate = endDate;
240   - this.cycleNum = cycleNum;
241   - this.beginTime = beginTime;
242   - this.finalTime = finalTime;
243   - this.userIds = userIds;
244   - }
245   -
246   - public BiTimeEntity() {
247   - }
248   -
249   - }
250   -}
yudao-module-crm/yudao-module-bi-biz/src/main/resources/mapper/rank/BiRankingMapper.xml deleted
1   -<?xml version="1.0" encoding="UTF-8"?>
2   -<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3   -<mapper namespace="cn.iocoder.yudao.module.bi.dal.mysql.BiRankingMapper">
4   -
5   -
6   - <select id="contractRanKing"
7   - resultType="cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiContractRanKingRespVO">
8   - SELECT IFNULL(SUM(t.price), 0) AS price, su.nickname, t.owner_user_id, dept.name AS deptName
9   - FROM crm_contract t
10   - <!-- TODO @anhaohao:system_users、system_dept 是不是没用到?尽量不连这 2 个表,微服务下会是独立仓库;如果显示需要,可以在 service 读取后拼接; -->
11   - LEFT JOIN system_users AS su ON su.id = t.owner_user_id
12   - LEFT JOIN system_dept AS dept ON dept.id = su.dept_id
13   - WHERE t.deleted = 0
14   - AND t.audit_status = 20
15   - <if test="userIds != null and userIds.size() > 0">
16   - and t.owner_user_id in
17   - <foreach collection="userIds" item="item" open="(" close=")" separator=",">
18   - #{item}
19   - </foreach>
20   - </if>
21   - <!-- TODO @anhaohao:在某个区间的时间,这么做有点浪费性能;一般做法是 beginTime 是开始时间(00:00:00),finalTime 是结束时间(23:59:59),这样实现的; -->
22   - AND DATE_FORMAT(t.order_date,'${sqlDateFormat}') between #{beginTime} and #{finalTime}
23   - GROUP BY t.owner_user_id
24   - ORDER BY price DESC
25   - </select>
26   -
27   - <select id="receivablesRanKing"
28   - resultType="cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiReceivablesRanKingRespVO">
29   - SELECT IFNULL(SUM(t.price), 0) AS price, su.nickname, t.owner_user_id, dept.name AS deptName
30   - FROM crm_receivable t
31   - LEFT JOIN system_users AS su ON su.id = t.owner_user_id
32   - LEFT JOIN system_dept AS dept ON dept.id = su.dept_id
33   - WHERE t.deleted = 0
34   - AND t.audit_status = 20
35   - <if test="userIds != null and userIds.size() > 0">
36   - and t.owner_user_id in
37   - <foreach collection="userIds" item="item" open="(" close=")" separator=",">
38   - #{item}
39   - </foreach>
40   - </if>
41   - AND DATE_FORMAT(t.return_time,'${sqlDateFormat}') between #{beginTime} and #{finalTime}
42   - GROUP BY t.owner_user_id
43   - ORDER BY price DESC
44   - </select>
45   -</mapper>
yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/BiRankingController.http renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/bi/CrmBiRankController.http
1 1 ### 合同金额排行榜
2   -GET {{baseUrl}}/bi/rank/contract-ranKing
  2 +GET {{baseUrl}}/crm/bi-rank/get-contract-price-rank?deptId=100&times[0]=2022-12-12 00:00:00&times[1]=2024-12-12 23:59:59
3 3 Authorization: Bearer {{token}}
4 4 tenant-id: {{adminTenentId}}
5 5  
6 6 ### 回款金额排行榜
7   -GET {{baseUrl}}/bi/rank/receivables-ranKing
  7 +GET {{baseUrl}}/crm/bi-rank/get-receivable-price-rank?deptId=100&times[0]=2022-12-12 00:00:00&times[1]=2024-12-12 23:59:59
8 8 Authorization: Bearer {{token}}
9 9 tenant-id: {{adminTenentId}}
10 10 \ No newline at end of file
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/bi/CrmBiRankController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.bi;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.module.crm.controller.admin.bi.vo.CrmBiRanKRespVO;
  5 +import cn.iocoder.yudao.module.crm.controller.admin.bi.vo.CrmBiRankReqVO;
  6 +import cn.iocoder.yudao.module.crm.service.bi.CrmBiRankingService;
  7 +import io.swagger.v3.oas.annotations.Operation;
  8 +import io.swagger.v3.oas.annotations.tags.Tag;
  9 +import jakarta.annotation.Resource;
  10 +import jakarta.validation.Valid;
  11 +import org.springframework.security.access.prepost.PreAuthorize;
  12 +import org.springframework.validation.annotation.Validated;
  13 +import org.springframework.web.bind.annotation.GetMapping;
  14 +import org.springframework.web.bind.annotation.RequestMapping;
  15 +import org.springframework.web.bind.annotation.RestController;
  16 +
  17 +import java.util.List;
  18 +
  19 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  20 +
  21 +
  22 +@Tag(name = "管理后台 - CRM BI 排行榜")
  23 +@RestController
  24 +@RequestMapping("/crm/bi-rank")
  25 +@Validated
  26 +public class CrmBiRankController {
  27 +
  28 + @Resource
  29 + private CrmBiRankingService rankingService;
  30 +
  31 + @GetMapping("/get-contract-price-rank")
  32 + @Operation(summary = "获得合同金额排行榜")
  33 + @PreAuthorize("@ss.hasPermission('crm:bi-rank:query')")
  34 + public CommonResult<List<CrmBiRanKRespVO>> getContractPriceRank(@Valid CrmBiRankReqVO rankingReqVO) {
  35 + return success(rankingService.getContractPriceRank(rankingReqVO));
  36 + }
  37 +
  38 + @GetMapping("/get-receivable-price-rank")
  39 + @Operation(summary = "获得回款金额排行榜")
  40 + @PreAuthorize("@ss.hasPermission('crm:bi-rank:query')")
  41 + public CommonResult<List<CrmBiRanKRespVO>> getReceivablePriceRank(@Valid CrmBiRankReqVO rankingReqVO) {
  42 + return success(rankingService.getReceivablePriceRank(rankingReqVO));
  43 + }
  44 +
  45 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/bi/vo/CrmBiRanKRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.bi.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +
  7 +@Schema(description = "管理后台 - CRM BI 排行榜 Response VO")
  8 +@Data
  9 +public class CrmBiRanKRespVO {
  10 +
  11 + @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  12 + private Long ownerUserId;
  13 +
  14 + @Schema(description = "姓名", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  15 + private String nickname;
  16 +
  17 + @Schema(description = "部门名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  18 + private String deptName;
  19 +
  20 + /**
  21 + * 数量是个特别“抽象”的概念,在不同排行下,代表不同含义
  22 + *
  23 + * 1. 金额:合同金额排行、回款金额排行
  24 + * 2. 个数:签约合同排行、产品销量排行、产品销量排行、新增客户数排行、新增联系人排行、跟进次数排行、跟进客户数排行
  25 + */
  26 + @Schema(description = "数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  27 + private Integer count;
  28 +
  29 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/bi/vo/CrmBiRankReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.controller.admin.bi.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.NotEmpty;
  5 +import jakarta.validation.constraints.NotNull;
  6 +import lombok.Data;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +
  9 +import java.time.LocalDateTime;
  10 +import java.util.List;
  11 +
  12 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  13 +
  14 +@Schema(description = "管理后台 - CRM BI 排行榜 Request VO")
  15 +@Data
  16 +public class CrmBiRankReqVO {
  17 +
  18 + @Schema(description = "部门 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  19 + @NotNull(message = "部门 id 不能为空")
  20 + private Long deptId;
  21 +
  22 + /**
  23 + * userIds 目前不用前端传递,目前是方便后端通过 deptId 读取编号后,设置回来
  24 + *
  25 + * 后续,可能会支持选择部分用户进行查询
  26 + */
  27 + @Schema(description = "负责人用户 id 集合", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2")
  28 + private List<Long> userIds;
  29 +
  30 + @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.REQUIRED)
  31 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  32 + @NotEmpty(message = "时间范围不能为空")
  33 + private LocalDateTime[] times;
  34 +
  35 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java
... ... @@ -28,6 +28,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
28 28 import jakarta.annotation.Resource;
29 29 import jakarta.servlet.http.HttpServletResponse;
30 30 import jakarta.validation.Valid;
  31 +import org.springframework.context.annotation.Lazy;
31 32 import org.springframework.security.access.prepost.PreAuthorize;
32 33 import org.springframework.validation.annotation.Validated;
33 34 import org.springframework.web.bind.annotation.*;
... ... @@ -55,6 +56,7 @@ public class CrmReceivablePlanController {
55 56 @Resource
56 57 private CrmReceivableService receivableService;
57 58 @Resource
  59 + @Lazy
58 60 private CrmContractService contractService;
59 61 @Resource
60 62 private CrmCustomerService customerService;
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/bi/CrmBiRankingMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.dal.mysql.bi;
  2 +
  3 +import cn.iocoder.yudao.module.crm.controller.admin.bi.vo.CrmBiRanKRespVO;
  4 +import cn.iocoder.yudao.module.crm.controller.admin.bi.vo.CrmBiRankReqVO;
  5 +import org.apache.ibatis.annotations.Mapper;
  6 +
  7 +import java.util.List;
  8 +
  9 +/**
  10 + * CRM BI 排行榜 Mapper
  11 + *
  12 + * @author anhaohao
  13 + */
  14 +@Mapper
  15 +public interface CrmBiRankingMapper {
  16 +
  17 + /**
  18 + * 查询合同金额排行榜
  19 + *
  20 + * @param rankReqVO 参数
  21 + * @return 合同金额排行榜
  22 + */
  23 + List<CrmBiRanKRespVO> selectContractPriceRank(CrmBiRankReqVO rankReqVO);
  24 +
  25 + /**
  26 + * 查询回款金额排行榜
  27 + *
  28 + * @param rankReqVO 参数
  29 + * @return 回款金额排行榜
  30 + */
  31 + List<CrmBiRanKRespVO> selectReceivablePriceRank(CrmBiRankReqVO rankReqVO);
  32 +
  33 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/bi/CrmBiRankingService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.service.bi;
  2 +
  3 +
  4 +import cn.iocoder.yudao.module.crm.controller.admin.bi.vo.CrmBiRanKRespVO;
  5 +import cn.iocoder.yudao.module.crm.controller.admin.bi.vo.CrmBiRankReqVO;
  6 +
  7 +import java.util.List;
  8 +
  9 +/**
  10 + * CRM BI 排行榜 Service 接口
  11 + *
  12 + * @author anhaohao
  13 + */
  14 +public interface CrmBiRankingService {
  15 +
  16 + /**
  17 + * 获得合同金额排行榜
  18 + *
  19 + * @param rankReqVO 排行参数
  20 + * @return 合同金额排行榜
  21 + */
  22 + List<CrmBiRanKRespVO> getContractPriceRank(CrmBiRankReqVO rankReqVO);
  23 +
  24 + /**
  25 + * 获得回款金额排行榜
  26 + *
  27 + * @param rankReqVO 排行参数
  28 + * @return 回款金额排行榜
  29 + */
  30 + List<CrmBiRanKRespVO> getReceivablePriceRank(CrmBiRankReqVO rankReqVO);
  31 +
  32 +}
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/bi/CrmBiRankingServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.crm.service.bi;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  5 +import cn.iocoder.yudao.module.crm.controller.admin.bi.vo.CrmBiRanKRespVO;
  6 +import cn.iocoder.yudao.module.crm.controller.admin.bi.vo.CrmBiRankReqVO;
  7 +import cn.iocoder.yudao.module.crm.dal.mysql.bi.CrmBiRankingMapper;
  8 +import cn.iocoder.yudao.module.system.api.dept.DeptApi;
  9 +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
  10 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  11 +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
  12 +import jakarta.annotation.Resource;
  13 +import org.springframework.stereotype.Service;
  14 +import org.springframework.validation.annotation.Validated;
  15 +
  16 +import java.util.Collections;
  17 +import java.util.Comparator;
  18 +import java.util.List;
  19 +import java.util.Map;
  20 +import java.util.function.Function;
  21 +
  22 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  23 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  24 +
  25 +/**
  26 + * CRM BI 排行榜 Service 实现类
  27 + *
  28 + * @author anhaohao
  29 + */
  30 +@Service
  31 +@Validated
  32 +public class CrmBiRankingServiceImpl implements CrmBiRankingService {
  33 +
  34 + @Resource
  35 + private CrmBiRankingMapper biRankingMapper;
  36 +
  37 + @Resource
  38 + private AdminUserApi adminUserApi;
  39 + @Resource
  40 + private DeptApi deptApi;
  41 +
  42 + @Override
  43 + public List<CrmBiRanKRespVO> getContractPriceRank(CrmBiRankReqVO rankReqVO) {
  44 + return getRank(rankReqVO, biRankingMapper::selectContractPriceRank);
  45 + }
  46 +
  47 + @Override
  48 + public List<CrmBiRanKRespVO> getReceivablePriceRank(CrmBiRankReqVO rankReqVO) {
  49 + return getRank(rankReqVO, biRankingMapper::selectReceivablePriceRank);
  50 + }
  51 +
  52 + /**
  53 + * 获得排行版数据
  54 + *
  55 + * @param rankReqVO 参数
  56 + * @param rankFunction 排行榜方法
  57 + * @return 排行版数据
  58 + */
  59 + private List<CrmBiRanKRespVO> getRank(CrmBiRankReqVO rankReqVO, Function<CrmBiRankReqVO, List<CrmBiRanKRespVO>> rankFunction) {
  60 + // 1. 获得用户编号数组
  61 + rankReqVO.setUserIds(getUserIds(rankReqVO.getDeptId()));
  62 + if (CollUtil.isEmpty(rankReqVO.getUserIds())) {
  63 + return Collections.emptyList();
  64 + }
  65 + // 2. 获得排行数据
  66 + List<CrmBiRanKRespVO> ranks = rankFunction.apply(rankReqVO);
  67 + if (CollUtil.isEmpty(ranks)) {
  68 + return Collections.emptyList();
  69 + }
  70 + ranks.sort(Comparator.comparing(CrmBiRanKRespVO::getCount).reversed());
  71 + // 3. 拼接用户信息
  72 + appendUserInfo(ranks);
  73 + return ranks;
  74 + }
  75 +
  76 + /**
  77 + * 拼接用户信息(昵称、部门)
  78 + *
  79 + * @param ranks 排行榜数据
  80 + */
  81 + private void appendUserInfo(List<CrmBiRanKRespVO> ranks) {
  82 + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertSet(ranks, CrmBiRanKRespVO::getOwnerUserId));
  83 + Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
  84 + ranks.forEach(rank -> MapUtils.findAndThen(userMap, rank.getOwnerUserId(), user -> {
  85 + rank.setNickname(user.getNickname());
  86 + MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> rank.setDeptName(dept.getName()));
  87 + }));
  88 + }
  89 +
  90 + /**
  91 + * 获得部门下的用户编号数组,包括子部门的
  92 + *
  93 + * @param deptId 部门编号
  94 + * @return 用户编号数组
  95 + */
  96 + public List<Long> getUserIds(Long deptId) {
  97 + // 1. 获得部门列表
  98 + List<Long> deptIds = convertList(deptApi.getChildDeptList(deptId), DeptRespDTO::getId);
  99 + deptIds.add(deptId);
  100 + // 2. 获得用户编号
  101 + return convertList(adminUserApi.getUserListByDeptIds(deptIds), AdminUserRespDTO::getId);
  102 + }
  103 +
  104 +}
0 105 \ No newline at end of file
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java
... ... @@ -57,7 +57,7 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
57 57 @Resource
58 58 private CrmBusinessProductService businessProductService;
59 59 @Resource
60   - @Lazy
  60 + @Lazy // 延迟加载,避免循环依赖
61 61 private CrmContractService contractService;
62 62 @Resource
63 63 private CrmPermissionService permissionService;
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java
... ... @@ -24,6 +24,7 @@ import com.mzt.logapi.context.LogRecordContext;
24 24 import com.mzt.logapi.service.impl.DiffParseFunction;
25 25 import com.mzt.logapi.starter.annotation.LogRecord;
26 26 import jakarta.annotation.Resource;
  27 +import org.springframework.context.annotation.Lazy;
27 28 import org.springframework.stereotype.Service;
28 29 import org.springframework.validation.annotation.Validated;
29 30  
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java
... ... @@ -27,6 +27,7 @@ import com.mzt.logapi.context.LogRecordContext;
27 27 import com.mzt.logapi.service.impl.DiffParseFunction;
28 28 import com.mzt.logapi.starter.annotation.LogRecord;
29 29 import jakarta.annotation.Resource;
  30 +import org.springframework.context.annotation.Lazy;
30 31 import org.springframework.stereotype.Service;
31 32 import org.springframework.validation.annotation.Validated;
32 33  
... ...
yudao-module-crm/yudao-module-crm-biz/src/main/resources/mapper/bi/CrmBiRankingMapper.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +<mapper namespace="cn.iocoder.yudao.module.crm.dal.mysql.bi.CrmBiRankingMapper">
  4 +
  5 + <select id="selectContractPriceRank"
  6 + resultType="cn.iocoder.yudao.module.crm.controller.admin.bi.vo.CrmBiRanKRespVO">
  7 + SELECT IFNULL(SUM(price), 0) AS count, owner_user_id
  8 + FROM crm_contract
  9 + WHERE deleted = 0
  10 + AND audit_status = 20
  11 + and owner_user_id in
  12 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  13 + #{userId}
  14 + </foreach>
  15 + AND order_date between #{times[0],javaType=java.time.LocalDateTime} and #{times[1],javaType=java.time.LocalDateTime}
  16 + GROUP BY owner_user_id
  17 + </select>
  18 +
  19 + <select id="selectReceivablePriceRank"
  20 + resultType="cn.iocoder.yudao.module.crm.controller.admin.bi.vo.CrmBiRanKRespVO">
  21 + SELECT IFNULL(SUM(price), 0) AS count, owner_user_id
  22 + FROM crm_receivable
  23 + WHERE deleted = 0
  24 + AND audit_status = 20
  25 + and owner_user_id in
  26 + <foreach collection="userIds" item="userId" open="(" close=")" separator=",">
  27 + #{userId}
  28 + </foreach>
  29 + AND return_time between #{times[0],javaType=java.time.LocalDateTime} and #{times[1],javaType=java.time.LocalDateTime}
  30 + GROUP BY owner_user_id
  31 + </select>
  32 +
  33 +</mapper>
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApiImpl.java
... ... @@ -20,7 +20,6 @@ import java.util.List;
20 20 public class DeptApiImpl implements DeptApi {
21 21  
22 22 @Resource
23   - @Lazy // 延迟加载,解决相互依赖的问题
24 23 private DeptService deptService;
25 24  
26 25 @Override
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java
... ... @@ -44,6 +44,9 @@ public class AuthPermissionInfoRespVO {
44 44 @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.jpg")
45 45 private String avatar;
46 46  
  47 + @Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
  48 + private Long deptId;
  49 +
47 50 }
48 51  
49 52 @Schema(description = "管理后台 - 登录用户的菜单信息 Response VO")
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/auth/AuthConvert.java
1 1 package cn.iocoder.yudao.module.system.convert.auth;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
4 5 import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
5 6 import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
6 7 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
... ... @@ -29,7 +30,7 @@ public interface AuthConvert {
29 30  
30 31 default AuthPermissionInfoRespVO convert(AdminUserDO user, List<RoleDO> roleList, List<MenuDO> menuList) {
31 32 return AuthPermissionInfoRespVO.builder()
32   - .user(AuthPermissionInfoRespVO.UserVO.builder().id(user.getId()).nickname(user.getNickname()).avatar(user.getAvatar()).build())
  33 + .user(BeanUtils.toBean(user, AuthPermissionInfoRespVO.UserVO.class))
33 34 .roles(convertSet(roleList, RoleDO::getCode))
34 35 // 权限标识信息
35 36 .permissions(convertSet(menuList, MenuDO::getPermission))
... ...
yudao-server/pom.xml
... ... @@ -93,11 +93,6 @@
93 93 <artifactId>yudao-module-crm-biz</artifactId>
94 94 <version>${revision}</version>
95 95 </dependency>
96   - <dependency>
97   - <groupId>cn.iocoder.boot</groupId>
98   - <artifactId>yudao-module-bi-biz</artifactId>
99   - <version>${revision}</version>
100   - </dependency>
101 96  
102 97 <!-- ERP 相关模块。默认注释,保证编译速度 -->
103 98 <dependency>
... ...