receivablesRanKing(BiTimeUtil.BiTimeEntity biTimeEntity);
+}
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/framework/package-info.java b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/framework/package-info.java
new file mode 100644
index 000000000..8b004cf8c
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/framework/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * 属于 bi 模块的 framework 封装
+ *
+ * @author 芋道源码
+ */
+package cn.iocoder.yudao.module.bi.framework;
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/framework/web/config/BiWebConfiguration.java b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/framework/web/config/BiWebConfiguration.java
new file mode 100644
index 000000000..ad10cdccd
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/framework/web/config/BiWebConfiguration.java
@@ -0,0 +1,24 @@
+package cn.iocoder.yudao.module.bi.framework.web.config;
+
+import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration;
+import org.springdoc.core.models.GroupedOpenApi;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * bi 模块的 web 组件的 Configuration
+ *
+ * @author 芋道源码
+ */
+@Configuration(proxyBeanMethods = false)
+public class BiWebConfiguration {
+
+ /**
+ * bi 模块的 API 分组
+ */
+ @Bean
+ public GroupedOpenApi biGroupedOpenApi() {
+ return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("bi");
+ }
+
+}
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/framework/web/package-info.java b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/framework/web/package-info.java
new file mode 100644
index 000000000..e17abbb1c
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/framework/web/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * bi 模块的 web 配置
+ */
+package cn.iocoder.yudao.module.bi.framework.web;
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/package-info.java b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/package-info.java
new file mode 100644
index 000000000..b45b8458d
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/package-info.java
@@ -0,0 +1,7 @@
+/**
+ * crm 包下,商业智能(Business Intelligence)。
+ * 例如说:报表、图表、数据分析等等
+ *
+ * 1. Controller URL:以 /bi/ 开头,避免和其它 Module 冲突
+ */
+package cn.iocoder.yudao.module.bi;
\ No newline at end of file
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/service/ranking/BiRankingService.java b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/service/ranking/BiRankingService.java
new file mode 100644
index 000000000..98f1346de
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/service/ranking/BiRankingService.java
@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.bi.service.ranking;
+
+import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiContractRanKingRespVO;
+import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiRankReqVO;
+import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiReceivablesRanKingRespVO;
+
+import java.util.List;
+
+/**
+ * BI 排行榜 Service 接口
+ *
+ * @author anhaohao
+ */
+public interface BiRankingService {
+ /**
+ * 合同金额排行榜
+ *
+ * @param biRankReqVO 参数
+ * @return List
+ */
+ List contractRanKing(BiRankReqVO biRankReqVO);
+
+ /**
+ * 回款金额排行榜
+ *
+ * @param biRankReqVO 参数
+ * @return List
+ */
+ List receivablesRanKing(BiRankReqVO biRankReqVO);
+}
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/service/ranking/BiRankingServiceImpl.java b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/service/ranking/BiRankingServiceImpl.java
new file mode 100644
index 000000000..1ed468547
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/service/ranking/BiRankingServiceImpl.java
@@ -0,0 +1,53 @@
+package cn.iocoder.yudao.module.bi.service.ranking;
+
+import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiContractRanKingRespVO;
+import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiParams;
+import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiRankReqVO;
+import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiReceivablesRanKingRespVO;
+import cn.iocoder.yudao.module.bi.dal.mysql.BiRankingMapper;
+import cn.iocoder.yudao.module.bi.util.BiTimeUtil;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author anhaohao
+ */
+@Service(value = "biRankService")
+@Validated
+public class BiRankingServiceImpl implements BiRankingService {
+
+ @Resource
+ private BiRankingMapper biRankingMapper;
+
+ @Override
+ public List contractRanKing(BiRankReqVO biRankReqVO) {
+ BiParams biParams = new BiParams();
+ biParams.setType(biRankReqVO.getType());
+ biParams.setDeptId(biRankReqVO.getDeptId());
+ biParams.setIsUser(0);
+ BiTimeUtil.BiTimeEntity biTimeEntity = BiTimeUtil.analyzeType(biParams);
+ List userIds = biTimeEntity.getUserIds();
+ if (userIds.isEmpty()) {
+ return new ArrayList<>();
+ }
+ return biRankingMapper.contractRanKing(biTimeEntity);
+ }
+
+ @Override
+ public List receivablesRanKing(BiRankReqVO biRankReqVO) {
+ BiParams biParams = new BiParams();
+ biParams.setType(biRankReqVO.getType());
+ biParams.setDeptId(biRankReqVO.getDeptId());
+ biParams.setIsUser(0);
+ BiTimeUtil.BiTimeEntity biTimeEntity = BiTimeUtil.analyzeType(biParams);
+ List userIds = biTimeEntity.getUserIds();
+ if (userIds.isEmpty()) {
+ return new ArrayList<>();
+ }
+ return biRankingMapper.receivablesRanKing(biTimeEntity);
+ }
+}
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/util/BiTimeUtil.java b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/util/BiTimeUtil.java
new file mode 100644
index 000000000..b1b68aea2
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/util/BiTimeUtil.java
@@ -0,0 +1,249 @@
+package cn.iocoder.yudao.module.bi.util;
+
+import cn.hutool.core.date.DateUnit;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
+import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiParams;
+import cn.iocoder.yudao.module.system.api.dept.DeptApi;
+import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * bi时间工具类
+ *
+ * @author anhaohao
+ */
+public class BiTimeUtil {
+
+ public static BiTimeEntity analyzeType(BiParams biParams) {
+ // 解析时间
+ BiTimeEntity biTimeEntity = analyzeTime(biParams);
+ // 解析权限
+ biTimeEntity.setUserIds(analyzeAuth(biParams));
+ return biTimeEntity;
+ }
+
+ /**
+ * 解析权限
+ *
+ * @param biParams bi参数
+ * @return List
+ */
+ public static List analyzeAuth(BiParams biParams) {
+ List userIdList = new ArrayList<>();
+ Long deptId = biParams.getDeptId();
+ Long userId = biParams.getUserId();
+ Integer isUser = biParams.getIsUser();
+ // 获取部门和用户的api
+ DeptApi deptApi = SpringUtil.getBean("deptApiImpl");
+ AdminUserApi adminUserApi = SpringUtil.getBean("adminUserApiImpl");
+ // 0.部门 1.用户
+ if (isUser == 0) {
+ if (deptId == null) {
+ deptId = adminUserApi.getUser(SecurityFrameworkUtils.getLoginUserId()).getDeptId();
+ }
+ List childDeptList = deptApi.getChildDeptList(deptId);
+ List deptIds = new ArrayList<>();
+ deptIds.add(deptId);
+ if (childDeptList != null && !childDeptList.isEmpty()) {
+ for (DeptRespDTO deptRespDTO : childDeptList) {
+ deptIds.add(deptRespDTO.getId());
+ }
+ }
+ // 获取部门下的用户
+ adminUserApi.getUserListByDeptIds(deptIds).forEach(adminUserRespDTO -> userIdList.add(adminUserRespDTO.getId()));
+ } else {
+ if (userId == null) {
+ List userListBySubordinate = adminUserApi.getUserListBySubordinate(SecurityFrameworkUtils.getLoginUserId());
+ userListBySubordinate.forEach(adminUserRespDTO -> userIdList.add(adminUserRespDTO.getId()));
+ } else {
+ userIdList.add(userId);
+ }
+ }
+ return userIdList;
+ }
+
+
+ /**
+ * 解析时间
+ *
+ * @param biParams bi参数
+ * @return BiTimeEntity
+ */
+ public static BiTimeEntity analyzeTime(BiParams biParams) {
+ Date beginDate = DateUtil.date();
+ Date endDate = DateUtil.date();
+ int cycleNum = 12;
+ String sqlDateFormat = "%Y%m";
+ String dateFormat = "yyyyMM";
+ String type = biParams.getType();
+ String startTime = biParams.getStartTime();
+ String endTime = biParams.getEndTime();
+ if (StrUtil.isNotEmpty(type)) {
+ //1.今天 2.昨天 3.本周 4.上周 5.本月 6.上月 7.本季度 8.上季度 9.本年 10 上年
+ switch (type) {
+ case "1":
+ beginDate = DateUtil.beginOfDay(DateUtil.date());
+ endDate = DateUtil.endOfDay(DateUtil.date());
+ sqlDateFormat = "%Y%m%d";
+ dateFormat = "yyyyMMdd";
+ cycleNum = 1;
+ break;
+ case "2":
+ beginDate = DateUtil.beginOfDay(new Date(System.currentTimeMillis() - 86400000));
+ endDate = DateUtil.endOfDay(new Date(System.currentTimeMillis() - 86400000));
+ sqlDateFormat = "%Y%m%d";
+ dateFormat = "yyyyMMdd";
+ cycleNum = 1;
+ break;
+ case "3":
+ beginDate = DateUtil.beginOfWeek(DateUtil.date());
+ endDate = DateUtil.endOfWeek(DateUtil.date());
+ sqlDateFormat = "%Y%m%d";
+ dateFormat = "yyyyMMdd";
+ cycleNum = 7;
+ break;
+ case "4":
+ beginDate = DateUtil.beginOfWeek(DateUtil.offsetWeek(DateUtil.date(), -1));
+ endDate = DateUtil.endOfWeek(DateUtil.offsetWeek(DateUtil.date(), -1));
+ sqlDateFormat = "%Y%m%d";
+ dateFormat = "yyyyMMdd";
+ cycleNum = 7;
+ break;
+ case "5":
+ beginDate = DateUtil.beginOfMonth(DateUtil.date());
+ endDate = DateUtil.endOfMonth(DateUtil.date());
+ sqlDateFormat = "%Y%m%d";
+ dateFormat = "yyyyMMdd";
+ cycleNum = (int) DateUtil.between(beginDate, endDate, DateUnit.DAY) + 1;
+ break;
+ case "6":
+ beginDate = DateUtil.beginOfMonth(DateUtil.offsetMonth(DateUtil.date(), -1));
+ endDate = DateUtil.endOfMonth(DateUtil.offsetMonth(DateUtil.date(), -1));
+ sqlDateFormat = "%Y%m%d";
+ dateFormat = "yyyyMMdd";
+ cycleNum = (int) DateUtil.between(beginDate, endDate, DateUnit.DAY) + 1;
+ break;
+ case "7":
+ beginDate = DateUtil.beginOfQuarter(DateUtil.date());
+ endDate = DateUtil.endOfQuarter(DateUtil.date());
+ cycleNum = 3;
+ break;
+ case "8":
+ beginDate = DateUtil.beginOfQuarter(DateUtil.offsetMonth(DateUtil.date(), -3));
+ endDate = DateUtil.endOfQuarter(DateUtil.offsetMonth(DateUtil.date(), -3));
+ cycleNum = 3;
+ break;
+ case "9":
+ beginDate = DateUtil.beginOfYear(DateUtil.date());
+ endDate = DateUtil.endOfYear(DateUtil.date());
+ break;
+ case "10":
+ beginDate = DateUtil.beginOfYear(DateUtil.offsetMonth(DateUtil.date(), -12));
+ endDate = DateUtil.endOfYear(DateUtil.offsetMonth(DateUtil.date(), -12));
+ break;
+ default:
+ break;
+ }
+ } else if (StrUtil.isNotEmpty(startTime) && StrUtil.isNotEmpty(endTime)) {
+ Date start;
+ Date end;
+ if (startTime.length() == 6) {
+ start = DateUtil.parse(startTime, "yyyyMM");
+ end = DateUtil.endOfMonth(DateUtil.parse(endTime, "yyyyMM"));
+ } else {
+ start = DateUtil.parse(startTime);
+ end = DateUtil.parse(endTime);
+ }
+ Integer startMonth = Integer.valueOf(DateUtil.format(start, "yyyyMM"));
+ int endMonth = Integer.parseInt(DateUtil.format(end, "yyyyMM"));
+ if (startMonth.equals(endMonth)) {
+ sqlDateFormat = "%Y%m%d";
+ dateFormat = "yyyyMMdd";
+ long diffDay = DateUtil.between(start, end, DateUnit.DAY);
+ cycleNum = (int) diffDay + 1;
+ } else {
+ sqlDateFormat = "%Y%m";
+ dateFormat = "yyyyMM";
+ int diffYear = Integer.parseInt(Integer.toString(endMonth).substring(0, 4)) - Integer.parseInt(startMonth.toString().substring(0, 4));
+ int diffMonth = endMonth % 100 - startMonth % 100 + 1;
+ cycleNum = diffYear * 12 + diffMonth;
+ }
+ beginDate = start;
+ endDate = end;
+ }
+ Integer beginTime = Integer.valueOf(DateUtil.format(beginDate, dateFormat));
+ Integer finalTime = Integer.valueOf(DateUtil.format(endDate, dateFormat));
+ return new BiTimeEntity(sqlDateFormat, dateFormat, beginDate, endDate, cycleNum, beginTime, finalTime, new ArrayList<>());
+ }
+
+ @Data
+ @Accessors(chain = true)
+ public static class BiTimeEntity {
+ /**
+ * sql日期格式化
+ */
+ private String sqlDateFormat;
+
+ /**
+ * 日期格式化
+ */
+ private String dateFormat;
+
+ /**
+ * 开始时间
+ */
+ private Date beginDate;
+
+ /**
+ * 结束时间
+ */
+ private Date endDate;
+
+ /**
+ * 周期
+ */
+ private Integer cycleNum;
+
+ /**
+ * 开始时间 字符串格式 如20200101
+ */
+ private Integer beginTime;
+
+ /**
+ * 结束时间 字符串格式 如20200101
+ */
+ private Integer finalTime;
+
+ /**
+ * user列表
+ */
+ private List userIds = new ArrayList<>();
+ private Integer page;
+ private Integer limit;
+
+ public BiTimeEntity(String sqlDateFormat, String dateFormat, Date beginDate, Date endDate, Integer cycleNum, Integer beginTime, Integer finalTime, List userIds) {
+ this.sqlDateFormat = sqlDateFormat;
+ this.dateFormat = dateFormat;
+ this.beginDate = beginDate;
+ this.endDate = endDate;
+ this.cycleNum = cycleNum;
+ this.beginTime = beginTime;
+ this.finalTime = finalTime;
+ this.userIds = userIds;
+ }
+
+ public BiTimeEntity() {
+ }
+
+ }
+}
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/resources/mapper/rank/BiRankingMapper.xml b/yudao-module-crm/yudao-module-bi-biz/src/main/resources/mapper/rank/BiRankingMapper.xml
new file mode 100644
index 000000000..9bee4fbaf
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/resources/mapper/rank/BiRankingMapper.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApi.java
index f8059fbb7..bdc3ba59b 100644
--- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApi.java
+++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApi.java
@@ -50,4 +50,12 @@ public interface DeptApi {
return CollectionUtils.convertMap(list, DeptRespDTO::getId);
}
+ /**
+ * 获得指定部门的所有子部门
+ *
+ * @param id 部门编号
+ * @return 子部门列表
+ */
+ List getChildDeptList(Long id);
+
}
diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApiImpl.java
index 76685cf31..00d79ceaa 100644
--- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApiImpl.java
+++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApiImpl.java
@@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
+import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
@@ -19,6 +20,7 @@ import java.util.List;
public class DeptApiImpl implements DeptApi {
@Resource
+ @Lazy // 延迟加载,解决相互依赖的问题
private DeptService deptService;
@Override
@@ -38,4 +40,11 @@ public class DeptApiImpl implements DeptApi {
deptService.validateDeptList(ids);
}
+ @Override
+ public List getChildDeptList(Long id) {
+ List childDeptList = deptService.getChildDeptList(id);
+ return BeanUtils.toBean(childDeptList, DeptRespDTO.class);
+ }
+
+
}
diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml
index 85b284c3c..3caebe16c 100644
--- a/yudao-server/pom.xml
+++ b/yudao-server/pom.xml
@@ -97,6 +97,11 @@
yudao-module-crm-biz
${revision}
+
+ cn.iocoder.boot
+ yudao-module-bi-biz
+ ${revision}
+
From 65d7f8c4ab8086480709201816f9747885a7e022 Mon Sep 17 00:00:00 2001
From: anhaohao <1036606149@qq.com>
Date: Sun, 28 Jan 2024 20:06:56 +0800
Subject: [PATCH 2/3] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9ACRM=20=E5=95=86?=
=?UTF-8?q?=E4=B8=9A=E6=99=BA=E8=83=BD=EF=BC=8C=E5=90=88=E5=90=8C=E9=87=91?=
=?UTF-8?q?=E9=A2=9D=E6=8E=92=E8=A1=8C=E6=A6=9C=E5=92=8C=E5=9B=9E=E6=AC=BE?=
=?UTF-8?q?=E9=87=91=E9=A2=9D=E6=8E=92=E8=A1=8C=E6=A6=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
yudao-module-crm/pom.xml | 3 +
yudao-module-crm/yudao-module-bi-api/pom.xml | 73 +++++
.../yudao/module/bi/api/package-info.java | 1 +
.../yudao/module/bi/enums/package-info.java | 1 +
yudao-module-crm/yudao-module-bi-biz/pom.xml | 74 ++++++
.../admin/ranking/BiRankingController.http | 10 +
.../admin/ranking/BiRankingController.java | 53 ++++
.../ranking/vo/BiContractRanKingRespVO.java | 24 ++
.../controller/admin/ranking/vo/BiParams.java | 41 +++
.../admin/ranking/vo/BiRankReqVO.java | 20 ++
.../vo/BiReceivablesRanKingRespVO.java | 23 ++
.../module/bi/controller/package-info.java | 6 +
.../module/bi/dal/mysql/BiRankingMapper.java | 31 +++
.../module/bi/framework/package-info.java | 6 +
.../web/config/BiWebConfiguration.java | 24 ++
.../module/bi/framework/web/package-info.java | 4 +
.../iocoder/yudao/module/bi/package-info.java | 7 +
.../bi/service/ranking/BiRankingService.java | 30 +++
.../service/ranking/BiRankingServiceImpl.java | 53 ++++
.../yudao/module/bi/util/BiTimeUtil.java | 249 ++++++++++++++++++
.../resources/mapper/rank/BiRankingMapper.xml | 42 +++
.../yudao/module/system/api/dept/DeptApi.java | 8 +
.../module/system/api/dept/DeptApiImpl.java | 9 +
yudao-server/pom.xml | 5 +
24 files changed, 797 insertions(+)
create mode 100644 yudao-module-crm/yudao-module-bi-api/pom.xml
create mode 100644 yudao-module-crm/yudao-module-bi-api/src/main/java/cn/iocoder/yudao/module/bi/api/package-info.java
create mode 100644 yudao-module-crm/yudao-module-bi-api/src/main/java/cn/iocoder/yudao/module/bi/enums/package-info.java
create mode 100644 yudao-module-crm/yudao-module-bi-biz/pom.xml
create mode 100644 yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/BiRankingController.http
create mode 100644 yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/BiRankingController.java
create mode 100644 yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/vo/BiContractRanKingRespVO.java
create mode 100644 yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/vo/BiParams.java
create mode 100644 yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/vo/BiRankReqVO.java
create mode 100644 yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/vo/BiReceivablesRanKingRespVO.java
create mode 100644 yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/package-info.java
create mode 100644 yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/dal/mysql/BiRankingMapper.java
create mode 100644 yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/framework/package-info.java
create mode 100644 yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/framework/web/config/BiWebConfiguration.java
create mode 100644 yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/framework/web/package-info.java
create mode 100644 yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/package-info.java
create mode 100644 yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/service/ranking/BiRankingService.java
create mode 100644 yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/service/ranking/BiRankingServiceImpl.java
create mode 100644 yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/util/BiTimeUtil.java
create mode 100644 yudao-module-crm/yudao-module-bi-biz/src/main/resources/mapper/rank/BiRankingMapper.xml
diff --git a/yudao-module-crm/pom.xml b/yudao-module-crm/pom.xml
index 2a7b748c3..c281c7bfa 100644
--- a/yudao-module-crm/pom.xml
+++ b/yudao-module-crm/pom.xml
@@ -10,6 +10,8 @@
yudao-module-crm-api
yudao-module-crm-biz
+ yudao-module-bi-biz
+ yudao-module-bi-api
4.0.0
yudao-module-crm
@@ -20,6 +22,7 @@
crm 包下,客户关系管理(Customer Relationship Management)。
例如说:客户、联系人、商机、合同、回款等等
+ 商业智能 BI 模块,包括:报表、图表、数据大屏等等
diff --git a/yudao-module-crm/yudao-module-bi-api/pom.xml b/yudao-module-crm/yudao-module-bi-api/pom.xml
new file mode 100644
index 000000000..aa21b85f9
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-api/pom.xml
@@ -0,0 +1,73 @@
+
+
+
+ cn.iocoder.boot
+ yudao-module-crm
+ ${revision}
+
+ 4.0.0
+ yudao-module-bi-api
+
+ ${project.artifactId}
+
+ bi 模块 API,暴露给其它模块调用
+
+
+
+
+ cn.iocoder.boot
+ yudao-module-system-api
+ ${revision}
+
+
+ cn.iocoder.boot
+ yudao-module-crm-api
+ ${revision}
+
+
+
+
+ cn.iocoder.boot
+ yudao-spring-boot-starter-biz-operatelog
+
+
+ cn.iocoder.boot
+ yudao-spring-boot-starter-biz-ip
+
+
+
+
+ cn.iocoder.boot
+ yudao-spring-boot-starter-web
+
+
+
+ cn.iocoder.boot
+ yudao-spring-boot-starter-security
+
+
+
+
+ cn.iocoder.boot
+ yudao-spring-boot-starter-mybatis
+
+
+
+
+ cn.iocoder.boot
+ yudao-spring-boot-starter-excel
+
+
+ cn.iocoder.boot
+ yudao-spring-boot-starter-biz-dict
+
+
+
+
+ cn.iocoder.boot
+ yudao-spring-boot-starter-test
+
+
+
\ No newline at end of file
diff --git a/yudao-module-crm/yudao-module-bi-api/src/main/java/cn/iocoder/yudao/module/bi/api/package-info.java b/yudao-module-crm/yudao-module-bi-api/src/main/java/cn/iocoder/yudao/module/bi/api/package-info.java
new file mode 100644
index 000000000..77e7d2290
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-api/src/main/java/cn/iocoder/yudao/module/bi/api/package-info.java
@@ -0,0 +1 @@
+package cn.iocoder.yudao.module.bi.api;
\ No newline at end of file
diff --git a/yudao-module-crm/yudao-module-bi-api/src/main/java/cn/iocoder/yudao/module/bi/enums/package-info.java b/yudao-module-crm/yudao-module-bi-api/src/main/java/cn/iocoder/yudao/module/bi/enums/package-info.java
new file mode 100644
index 000000000..eb4c1e428
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-api/src/main/java/cn/iocoder/yudao/module/bi/enums/package-info.java
@@ -0,0 +1 @@
+package cn.iocoder.yudao.module.bi.enums;
\ No newline at end of file
diff --git a/yudao-module-crm/yudao-module-bi-biz/pom.xml b/yudao-module-crm/yudao-module-bi-biz/pom.xml
new file mode 100644
index 000000000..92c8e2f9f
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/pom.xml
@@ -0,0 +1,74 @@
+
+
+
+ cn.iocoder.boot
+ yudao-module-crm
+ ${revision}
+
+ 4.0.0
+ yudao-module-bi-biz
+
+ ${project.artifactId}
+
+ crm 包下,商业智能(Business Intelligence)。
+ 例如说:报表、图表、数据分析等等
+
+
+
+
+ cn.iocoder.boot
+ yudao-module-system-api
+ ${revision}
+
+
+ cn.iocoder.boot
+ yudao-module-crm-api
+ ${revision}
+
+
+
+
+ cn.iocoder.boot
+ yudao-spring-boot-starter-biz-operatelog
+
+
+ cn.iocoder.boot
+ yudao-spring-boot-starter-biz-ip
+
+
+
+
+ cn.iocoder.boot
+ yudao-spring-boot-starter-web
+
+
+
+ cn.iocoder.boot
+ yudao-spring-boot-starter-security
+
+
+
+
+ cn.iocoder.boot
+ yudao-spring-boot-starter-mybatis
+
+
+
+
+ cn.iocoder.boot
+ yudao-spring-boot-starter-excel
+
+
+ cn.iocoder.boot
+ yudao-spring-boot-starter-biz-dict
+
+
+
+
+ cn.iocoder.boot
+ yudao-spring-boot-starter-test
+
+
+
\ No newline at end of file
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/BiRankingController.http b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/BiRankingController.http
new file mode 100644
index 000000000..50ab7ec2b
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/BiRankingController.http
@@ -0,0 +1,10 @@
+### 合同金额排行榜
+GET {{baseUrl}}/bi/rank/contract-ranKing
+Authorization: Bearer {{token}}
+tenant-id: {{adminTenentId}}
+
+
+### 回款金额排行榜
+GET {{baseUrl}}/bi/rank/receivables-ranKing
+Authorization: Bearer {{token}}
+tenant-id: {{adminTenentId}}
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/BiRankingController.java b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/BiRankingController.java
new file mode 100644
index 000000000..2d81ae80d
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/BiRankingController.java
@@ -0,0 +1,53 @@
+package cn.iocoder.yudao.module.bi.controller.admin.ranking;
+
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiContractRanKingRespVO;
+import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiRankReqVO;
+import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiReceivablesRanKingRespVO;
+import cn.iocoder.yudao.module.bi.service.ranking.BiRankingService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+/**
+ * @author anhaohao
+ */
+@Tag(name = "管理后台 - 排行榜")
+@RestController
+@RequestMapping("/bi/ranking")
+@Validated
+public class BiRankingController {
+
+ @Resource
+ private BiRankingService biRankingService;
+
+ /**
+ * 合同金额排行榜
+ */
+ @GetMapping("/contract-ranking")
+ @Operation(summary = "合同金额排行榜")
+ @PreAuthorize("@ss.hasPermission('bi:ranking:query')")
+ public CommonResult> contractAmountRanking(BiRankReqVO biRankReqVO) {
+ return success(biRankingService.contractRanKing(biRankReqVO));
+ }
+
+ /**
+ * 回款金额排行榜
+ */
+ @GetMapping("/receivables-ranking")
+ @Operation(summary = "回款金额排行榜")
+ @PreAuthorize("@ss.hasPermission('bi:ranking:query')")
+ public CommonResult> receivablesRanKing(BiRankReqVO biRankReqVO) {
+ return success(biRankingService.receivablesRanKing(biRankReqVO));
+ }
+}
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/vo/BiContractRanKingRespVO.java b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/vo/BiContractRanKingRespVO.java
new file mode 100644
index 000000000..777996b90
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/vo/BiContractRanKingRespVO.java
@@ -0,0 +1,24 @@
+package cn.iocoder.yudao.module.bi.controller.admin.ranking.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * 管理后台 - BI 排行榜 Response VO
+ *
+ * @author anhaohao
+ */
+@Schema(description = "管理后台 - BI 合同金额排行榜 Response VO")
+@Data
+public class BiContractRanKingRespVO {
+
+ @Schema(description = "金额", example = "1")
+ private Integer price;
+
+ @Schema(description = "姓名", example = "1")
+ private String nickname;
+
+
+ @Schema(description = "部门名称", example = "1")
+ private String deptName;
+}
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/vo/BiParams.java b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/vo/BiParams.java
new file mode 100644
index 000000000..5cce4c6cb
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/vo/BiParams.java
@@ -0,0 +1,41 @@
+package cn.iocoder.yudao.module.bi.controller.admin.ranking.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.List;
+
+/**
+ * @author anhaohao
+ * bi参数
+ */
+@EqualsAndHashCode(callSuper = true)
+@Schema(description = "bi查询相关参数")
+@Data
+public class BiParams extends PageParam {
+
+ @Schema(description = "部门ID")
+ private Long deptId;
+
+ @Schema(description = "用户ID")
+ private Long userId;
+
+ @Schema(description = "用户IDs")
+ private List userIds;
+
+ @Schema(description = "类型")
+ private String type;
+
+ @Schema(description = "开始时间")
+ private String startTime;
+
+ @Schema(description = "结束时间")
+ private String endTime;
+
+ @Schema(description = "0 部门 1员工")
+ private Integer isUser = 1;
+
+
+}
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/vo/BiRankReqVO.java b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/vo/BiRankReqVO.java
new file mode 100644
index 000000000..1569ba88d
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/vo/BiRankReqVO.java
@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.bi.controller.admin.ranking.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * 管理后台 - 排行榜 Request VO
+ *
+ * @author anhaohao
+ */
+@Schema(description = "管理后台 - 排行榜 Request VO")
+@Data
+public class BiRankReqVO {
+
+ @Schema(description = "部门id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Long deptId;
+
+ @Schema(description = "分析类型(1.今天 2.昨天 3.本周 4.上周 5.本月 6.上月 7.本季度 8.上季度 9.本年 10 上年)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private String type;
+}
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/vo/BiReceivablesRanKingRespVO.java b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/vo/BiReceivablesRanKingRespVO.java
new file mode 100644
index 000000000..32b49231f
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/admin/ranking/vo/BiReceivablesRanKingRespVO.java
@@ -0,0 +1,23 @@
+package cn.iocoder.yudao.module.bi.controller.admin.ranking.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * 管理后台 - BI 排行榜 Response VO
+ *
+ * @author anhaohao
+ */
+@Schema(description = "管理后台 - BI 合同金额排行榜 Response VO")
+@Data
+public class BiReceivablesRanKingRespVO {
+
+ @Schema(description = "金额", example = "100")
+ private Integer price;
+
+ @Schema(description = "姓名", example = "张三")
+ private String nickname;
+
+ @Schema(description = "部门名称", example = "研发部")
+ private String deptName;
+}
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/package-info.java b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/package-info.java
new file mode 100644
index 000000000..052f6238f
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/controller/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * 提供 RESTful API 给前端:
+ * 1. admin 包:提供给管理后台 yudao-ui-admin 前端项目
+ * 2. app 包:提供给用户 APP yudao-ui-app 前端项目,它的 Controller 和 VO 都要添加 App 前缀,用于和管理后台进行区分
+ */
+package cn.iocoder.yudao.module.bi.controller;
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/dal/mysql/BiRankingMapper.java b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/dal/mysql/BiRankingMapper.java
new file mode 100644
index 000000000..e37184031
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/dal/mysql/BiRankingMapper.java
@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.module.bi.dal.mysql;
+
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiContractRanKingRespVO;
+import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiReceivablesRanKingRespVO;
+import cn.iocoder.yudao.module.bi.util.BiTimeUtil;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * @author anhaohao
+ */
+@Mapper
+public interface BiRankingMapper extends BaseMapperX {
+ /**
+ * 合同金额排行榜
+ *
+ * @param biTimeEntity 参数
+ * @return List
+ */
+ List contractRanKing(BiTimeUtil.BiTimeEntity biTimeEntity);
+
+ /**
+ * 回款金额排行榜
+ *
+ * @param biTimeEntity 参数
+ * @return List
+ */
+ List receivablesRanKing(BiTimeUtil.BiTimeEntity biTimeEntity);
+}
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/framework/package-info.java b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/framework/package-info.java
new file mode 100644
index 000000000..8b004cf8c
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/framework/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * 属于 bi 模块的 framework 封装
+ *
+ * @author 芋道源码
+ */
+package cn.iocoder.yudao.module.bi.framework;
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/framework/web/config/BiWebConfiguration.java b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/framework/web/config/BiWebConfiguration.java
new file mode 100644
index 000000000..ad10cdccd
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/framework/web/config/BiWebConfiguration.java
@@ -0,0 +1,24 @@
+package cn.iocoder.yudao.module.bi.framework.web.config;
+
+import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration;
+import org.springdoc.core.models.GroupedOpenApi;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * bi 模块的 web 组件的 Configuration
+ *
+ * @author 芋道源码
+ */
+@Configuration(proxyBeanMethods = false)
+public class BiWebConfiguration {
+
+ /**
+ * bi 模块的 API 分组
+ */
+ @Bean
+ public GroupedOpenApi biGroupedOpenApi() {
+ return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("bi");
+ }
+
+}
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/framework/web/package-info.java b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/framework/web/package-info.java
new file mode 100644
index 000000000..e17abbb1c
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/framework/web/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * bi 模块的 web 配置
+ */
+package cn.iocoder.yudao.module.bi.framework.web;
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/package-info.java b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/package-info.java
new file mode 100644
index 000000000..b45b8458d
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/package-info.java
@@ -0,0 +1,7 @@
+/**
+ * crm 包下,商业智能(Business Intelligence)。
+ * 例如说:报表、图表、数据分析等等
+ *
+ * 1. Controller URL:以 /bi/ 开头,避免和其它 Module 冲突
+ */
+package cn.iocoder.yudao.module.bi;
\ No newline at end of file
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/service/ranking/BiRankingService.java b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/service/ranking/BiRankingService.java
new file mode 100644
index 000000000..98f1346de
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/service/ranking/BiRankingService.java
@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.bi.service.ranking;
+
+import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiContractRanKingRespVO;
+import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiRankReqVO;
+import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiReceivablesRanKingRespVO;
+
+import java.util.List;
+
+/**
+ * BI 排行榜 Service 接口
+ *
+ * @author anhaohao
+ */
+public interface BiRankingService {
+ /**
+ * 合同金额排行榜
+ *
+ * @param biRankReqVO 参数
+ * @return List
+ */
+ List contractRanKing(BiRankReqVO biRankReqVO);
+
+ /**
+ * 回款金额排行榜
+ *
+ * @param biRankReqVO 参数
+ * @return List
+ */
+ List receivablesRanKing(BiRankReqVO biRankReqVO);
+}
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/service/ranking/BiRankingServiceImpl.java b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/service/ranking/BiRankingServiceImpl.java
new file mode 100644
index 000000000..1ed468547
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/service/ranking/BiRankingServiceImpl.java
@@ -0,0 +1,53 @@
+package cn.iocoder.yudao.module.bi.service.ranking;
+
+import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiContractRanKingRespVO;
+import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiParams;
+import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiRankReqVO;
+import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiReceivablesRanKingRespVO;
+import cn.iocoder.yudao.module.bi.dal.mysql.BiRankingMapper;
+import cn.iocoder.yudao.module.bi.util.BiTimeUtil;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author anhaohao
+ */
+@Service(value = "biRankService")
+@Validated
+public class BiRankingServiceImpl implements BiRankingService {
+
+ @Resource
+ private BiRankingMapper biRankingMapper;
+
+ @Override
+ public List contractRanKing(BiRankReqVO biRankReqVO) {
+ BiParams biParams = new BiParams();
+ biParams.setType(biRankReqVO.getType());
+ biParams.setDeptId(biRankReqVO.getDeptId());
+ biParams.setIsUser(0);
+ BiTimeUtil.BiTimeEntity biTimeEntity = BiTimeUtil.analyzeType(biParams);
+ List userIds = biTimeEntity.getUserIds();
+ if (userIds.isEmpty()) {
+ return new ArrayList<>();
+ }
+ return biRankingMapper.contractRanKing(biTimeEntity);
+ }
+
+ @Override
+ public List receivablesRanKing(BiRankReqVO biRankReqVO) {
+ BiParams biParams = new BiParams();
+ biParams.setType(biRankReqVO.getType());
+ biParams.setDeptId(biRankReqVO.getDeptId());
+ biParams.setIsUser(0);
+ BiTimeUtil.BiTimeEntity biTimeEntity = BiTimeUtil.analyzeType(biParams);
+ List userIds = biTimeEntity.getUserIds();
+ if (userIds.isEmpty()) {
+ return new ArrayList<>();
+ }
+ return biRankingMapper.receivablesRanKing(biTimeEntity);
+ }
+}
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/util/BiTimeUtil.java b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/util/BiTimeUtil.java
new file mode 100644
index 000000000..b1b68aea2
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/java/cn/iocoder/yudao/module/bi/util/BiTimeUtil.java
@@ -0,0 +1,249 @@
+package cn.iocoder.yudao.module.bi.util;
+
+import cn.hutool.core.date.DateUnit;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
+import cn.iocoder.yudao.module.bi.controller.admin.ranking.vo.BiParams;
+import cn.iocoder.yudao.module.system.api.dept.DeptApi;
+import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * bi时间工具类
+ *
+ * @author anhaohao
+ */
+public class BiTimeUtil {
+
+ public static BiTimeEntity analyzeType(BiParams biParams) {
+ // 解析时间
+ BiTimeEntity biTimeEntity = analyzeTime(biParams);
+ // 解析权限
+ biTimeEntity.setUserIds(analyzeAuth(biParams));
+ return biTimeEntity;
+ }
+
+ /**
+ * 解析权限
+ *
+ * @param biParams bi参数
+ * @return List
+ */
+ public static List analyzeAuth(BiParams biParams) {
+ List userIdList = new ArrayList<>();
+ Long deptId = biParams.getDeptId();
+ Long userId = biParams.getUserId();
+ Integer isUser = biParams.getIsUser();
+ // 获取部门和用户的api
+ DeptApi deptApi = SpringUtil.getBean("deptApiImpl");
+ AdminUserApi adminUserApi = SpringUtil.getBean("adminUserApiImpl");
+ // 0.部门 1.用户
+ if (isUser == 0) {
+ if (deptId == null) {
+ deptId = adminUserApi.getUser(SecurityFrameworkUtils.getLoginUserId()).getDeptId();
+ }
+ List childDeptList = deptApi.getChildDeptList(deptId);
+ List deptIds = new ArrayList<>();
+ deptIds.add(deptId);
+ if (childDeptList != null && !childDeptList.isEmpty()) {
+ for (DeptRespDTO deptRespDTO : childDeptList) {
+ deptIds.add(deptRespDTO.getId());
+ }
+ }
+ // 获取部门下的用户
+ adminUserApi.getUserListByDeptIds(deptIds).forEach(adminUserRespDTO -> userIdList.add(adminUserRespDTO.getId()));
+ } else {
+ if (userId == null) {
+ List userListBySubordinate = adminUserApi.getUserListBySubordinate(SecurityFrameworkUtils.getLoginUserId());
+ userListBySubordinate.forEach(adminUserRespDTO -> userIdList.add(adminUserRespDTO.getId()));
+ } else {
+ userIdList.add(userId);
+ }
+ }
+ return userIdList;
+ }
+
+
+ /**
+ * 解析时间
+ *
+ * @param biParams bi参数
+ * @return BiTimeEntity
+ */
+ public static BiTimeEntity analyzeTime(BiParams biParams) {
+ Date beginDate = DateUtil.date();
+ Date endDate = DateUtil.date();
+ int cycleNum = 12;
+ String sqlDateFormat = "%Y%m";
+ String dateFormat = "yyyyMM";
+ String type = biParams.getType();
+ String startTime = biParams.getStartTime();
+ String endTime = biParams.getEndTime();
+ if (StrUtil.isNotEmpty(type)) {
+ //1.今天 2.昨天 3.本周 4.上周 5.本月 6.上月 7.本季度 8.上季度 9.本年 10 上年
+ switch (type) {
+ case "1":
+ beginDate = DateUtil.beginOfDay(DateUtil.date());
+ endDate = DateUtil.endOfDay(DateUtil.date());
+ sqlDateFormat = "%Y%m%d";
+ dateFormat = "yyyyMMdd";
+ cycleNum = 1;
+ break;
+ case "2":
+ beginDate = DateUtil.beginOfDay(new Date(System.currentTimeMillis() - 86400000));
+ endDate = DateUtil.endOfDay(new Date(System.currentTimeMillis() - 86400000));
+ sqlDateFormat = "%Y%m%d";
+ dateFormat = "yyyyMMdd";
+ cycleNum = 1;
+ break;
+ case "3":
+ beginDate = DateUtil.beginOfWeek(DateUtil.date());
+ endDate = DateUtil.endOfWeek(DateUtil.date());
+ sqlDateFormat = "%Y%m%d";
+ dateFormat = "yyyyMMdd";
+ cycleNum = 7;
+ break;
+ case "4":
+ beginDate = DateUtil.beginOfWeek(DateUtil.offsetWeek(DateUtil.date(), -1));
+ endDate = DateUtil.endOfWeek(DateUtil.offsetWeek(DateUtil.date(), -1));
+ sqlDateFormat = "%Y%m%d";
+ dateFormat = "yyyyMMdd";
+ cycleNum = 7;
+ break;
+ case "5":
+ beginDate = DateUtil.beginOfMonth(DateUtil.date());
+ endDate = DateUtil.endOfMonth(DateUtil.date());
+ sqlDateFormat = "%Y%m%d";
+ dateFormat = "yyyyMMdd";
+ cycleNum = (int) DateUtil.between(beginDate, endDate, DateUnit.DAY) + 1;
+ break;
+ case "6":
+ beginDate = DateUtil.beginOfMonth(DateUtil.offsetMonth(DateUtil.date(), -1));
+ endDate = DateUtil.endOfMonth(DateUtil.offsetMonth(DateUtil.date(), -1));
+ sqlDateFormat = "%Y%m%d";
+ dateFormat = "yyyyMMdd";
+ cycleNum = (int) DateUtil.between(beginDate, endDate, DateUnit.DAY) + 1;
+ break;
+ case "7":
+ beginDate = DateUtil.beginOfQuarter(DateUtil.date());
+ endDate = DateUtil.endOfQuarter(DateUtil.date());
+ cycleNum = 3;
+ break;
+ case "8":
+ beginDate = DateUtil.beginOfQuarter(DateUtil.offsetMonth(DateUtil.date(), -3));
+ endDate = DateUtil.endOfQuarter(DateUtil.offsetMonth(DateUtil.date(), -3));
+ cycleNum = 3;
+ break;
+ case "9":
+ beginDate = DateUtil.beginOfYear(DateUtil.date());
+ endDate = DateUtil.endOfYear(DateUtil.date());
+ break;
+ case "10":
+ beginDate = DateUtil.beginOfYear(DateUtil.offsetMonth(DateUtil.date(), -12));
+ endDate = DateUtil.endOfYear(DateUtil.offsetMonth(DateUtil.date(), -12));
+ break;
+ default:
+ break;
+ }
+ } else if (StrUtil.isNotEmpty(startTime) && StrUtil.isNotEmpty(endTime)) {
+ Date start;
+ Date end;
+ if (startTime.length() == 6) {
+ start = DateUtil.parse(startTime, "yyyyMM");
+ end = DateUtil.endOfMonth(DateUtil.parse(endTime, "yyyyMM"));
+ } else {
+ start = DateUtil.parse(startTime);
+ end = DateUtil.parse(endTime);
+ }
+ Integer startMonth = Integer.valueOf(DateUtil.format(start, "yyyyMM"));
+ int endMonth = Integer.parseInt(DateUtil.format(end, "yyyyMM"));
+ if (startMonth.equals(endMonth)) {
+ sqlDateFormat = "%Y%m%d";
+ dateFormat = "yyyyMMdd";
+ long diffDay = DateUtil.between(start, end, DateUnit.DAY);
+ cycleNum = (int) diffDay + 1;
+ } else {
+ sqlDateFormat = "%Y%m";
+ dateFormat = "yyyyMM";
+ int diffYear = Integer.parseInt(Integer.toString(endMonth).substring(0, 4)) - Integer.parseInt(startMonth.toString().substring(0, 4));
+ int diffMonth = endMonth % 100 - startMonth % 100 + 1;
+ cycleNum = diffYear * 12 + diffMonth;
+ }
+ beginDate = start;
+ endDate = end;
+ }
+ Integer beginTime = Integer.valueOf(DateUtil.format(beginDate, dateFormat));
+ Integer finalTime = Integer.valueOf(DateUtil.format(endDate, dateFormat));
+ return new BiTimeEntity(sqlDateFormat, dateFormat, beginDate, endDate, cycleNum, beginTime, finalTime, new ArrayList<>());
+ }
+
+ @Data
+ @Accessors(chain = true)
+ public static class BiTimeEntity {
+ /**
+ * sql日期格式化
+ */
+ private String sqlDateFormat;
+
+ /**
+ * 日期格式化
+ */
+ private String dateFormat;
+
+ /**
+ * 开始时间
+ */
+ private Date beginDate;
+
+ /**
+ * 结束时间
+ */
+ private Date endDate;
+
+ /**
+ * 周期
+ */
+ private Integer cycleNum;
+
+ /**
+ * 开始时间 字符串格式 如20200101
+ */
+ private Integer beginTime;
+
+ /**
+ * 结束时间 字符串格式 如20200101
+ */
+ private Integer finalTime;
+
+ /**
+ * user列表
+ */
+ private List userIds = new ArrayList<>();
+ private Integer page;
+ private Integer limit;
+
+ public BiTimeEntity(String sqlDateFormat, String dateFormat, Date beginDate, Date endDate, Integer cycleNum, Integer beginTime, Integer finalTime, List userIds) {
+ this.sqlDateFormat = sqlDateFormat;
+ this.dateFormat = dateFormat;
+ this.beginDate = beginDate;
+ this.endDate = endDate;
+ this.cycleNum = cycleNum;
+ this.beginTime = beginTime;
+ this.finalTime = finalTime;
+ this.userIds = userIds;
+ }
+
+ public BiTimeEntity() {
+ }
+
+ }
+}
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/resources/mapper/rank/BiRankingMapper.xml b/yudao-module-crm/yudao-module-bi-biz/src/main/resources/mapper/rank/BiRankingMapper.xml
new file mode 100644
index 000000000..9bee4fbaf
--- /dev/null
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/resources/mapper/rank/BiRankingMapper.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApi.java
index f8059fbb7..bdc3ba59b 100644
--- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApi.java
+++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApi.java
@@ -50,4 +50,12 @@ public interface DeptApi {
return CollectionUtils.convertMap(list, DeptRespDTO::getId);
}
+ /**
+ * 获得指定部门的所有子部门
+ *
+ * @param id 部门编号
+ * @return 子部门列表
+ */
+ List getChildDeptList(Long id);
+
}
diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApiImpl.java
index 76685cf31..00d79ceaa 100644
--- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApiImpl.java
+++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApiImpl.java
@@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
+import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
@@ -19,6 +20,7 @@ import java.util.List;
public class DeptApiImpl implements DeptApi {
@Resource
+ @Lazy // 延迟加载,解决相互依赖的问题
private DeptService deptService;
@Override
@@ -38,4 +40,11 @@ public class DeptApiImpl implements DeptApi {
deptService.validateDeptList(ids);
}
+ @Override
+ public List getChildDeptList(Long id) {
+ List childDeptList = deptService.getChildDeptList(id);
+ return BeanUtils.toBean(childDeptList, DeptRespDTO.class);
+ }
+
+
}
diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml
index 85b284c3c..3caebe16c 100644
--- a/yudao-server/pom.xml
+++ b/yudao-server/pom.xml
@@ -97,6 +97,11 @@
yudao-module-crm-biz
${revision}
+
+ cn.iocoder.boot
+ yudao-module-bi-biz
+ ${revision}
+
From bfed37af6f65f691c6a2e6cca36284c29d792978 Mon Sep 17 00:00:00 2001
From: anhaohao <1036606149@qq.com>
Date: Sun, 28 Jan 2024 21:47:52 +0800
Subject: [PATCH 3/3] =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=9ACRM=20=E5=95=86?=
=?UTF-8?q?=E4=B8=9A=E6=99=BA=E8=83=BD=EF=BC=8C=E5=9B=9E=E6=AC=BE=E9=87=91?=
=?UTF-8?q?=E9=A2=9D=E6=8E=92=E8=A1=8C=E6=A6=9C=E6=97=B6=E9=97=B4=E5=AD=97?=
=?UTF-8?q?=E6=AE=B5=20bug?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/main/resources/mapper/rank/BiRankingMapper.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/yudao-module-crm/yudao-module-bi-biz/src/main/resources/mapper/rank/BiRankingMapper.xml b/yudao-module-crm/yudao-module-bi-biz/src/main/resources/mapper/rank/BiRankingMapper.xml
index 9bee4fbaf..ed12ded42 100644
--- a/yudao-module-crm/yudao-module-bi-biz/src/main/resources/mapper/rank/BiRankingMapper.xml
+++ b/yudao-module-crm/yudao-module-bi-biz/src/main/resources/mapper/rank/BiRankingMapper.xml
@@ -35,7 +35,7 @@
#{item}
- AND DATE_FORMAT(t.order_date,'${sqlDateFormat}') between #{beginTime} and #{finalTime}
+ AND DATE_FORMAT(t.return_time,'${sqlDateFormat}') between #{beginTime} and #{finalTime}
GROUP BY t.owner_user_id
ORDER BY price DESC