Skip to content

Commit

Permalink
Merge branch 'master-jdk17' of https://gitee.com/zhijiantianya/ruoyi-…
Browse files Browse the repository at this point in the history
…vue-pro

# Conflicts:
#	yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceServiceImpl.java
#	yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageUserController.java
#	yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserService.java
#	yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserServiceImpl.java
#	yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/AppSocialUserController.java
#	yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialUserApi.java
#	yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientService.java
  • Loading branch information
YunaiV committed Jul 13, 2024
2 parents d349557 + 41afea6 commit ce1940e
Show file tree
Hide file tree
Showing 60 changed files with 1,828 additions and 163 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ public void run(ApplicationArguments args) {
if (isNotPresent("cn.iocoder.yudao.module.pay.framework.pay.config.PayConfiguration")) {
System.out.println("[支付系统 yudao-module-pay - 已禁用][参考 https://doc.iocoder.cn/pay/build/ 开启]");
}
// AI 大模型
if (isNotPresent("cn.iocoder.yudao.module.ai.framework.web.config.AiWebConfiguration")) {
System.out.println("[AI 大模型 yudao-module-ai - 已禁用][参考 https://doc.iocoder.cn/ai/build/ 开启]");
}
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* 属于 ai 模块的 framework 封装
*
* @author 芋道源码
*/
package cn.iocoder.yudao.module.crm.framework;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.ai.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;

/**
* ai 模块的 web 组件的 Configuration
*
* @author 芋道源码
*/
@Configuration(proxyBeanMethods = false)
public class AiWebConfiguration {

/**
* ai 模块的 API 分组
*/
@Bean
public GroupedOpenApi aiGroupedOpenApi() {
return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("ai");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* crm 模块的 web 拓展封装
*/
package cn.iocoder.yudao.module.crm.framework.web;
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ public class CrmStatisticsPerformanceReqVO {
@Schema(description = "负责人用户 id 集合", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2")
private List<Long> userIds;

// TODO @scholar:应该传递的是 int year;年份
@Schema(description = "时间范围", requiredMode = Schema.RequiredMode.REQUIRED)
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@NotEmpty(message = "时间范围不能为空")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package cn.iocoder.yudao.module.crm.service.statistics;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjUtil;
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceRespVO;
Expand All @@ -11,17 +9,20 @@
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 jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;

/**
* CRM 员工业绩分析 Service 实现类
Expand All @@ -42,10 +43,6 @@ public class CrmStatisticsPerformanceServiceImpl implements CrmStatisticsPerform

@Override
public List<CrmStatisticsPerformanceRespVO> getContractCountPerformance(CrmStatisticsPerformanceReqVO performanceReqVO) {
// TODO @scholar:可以把下面这个注释,你理解后,重新整理下,写到 getPerformance 里;
// 比如说,2024 年的合同数据,是不是 2022-12 到 2024-12-31,每个月的统计呢?
// 理解之后,我们可以数据 group by 年-月,20222-12 到 2024-12-31 的,然后内存在聚合出 CrmStatisticsPerformanceRespVO 这样
// 这样,我们就可以减少数据库的计算量,提升性能;同时 SQL 也会很简单,开发者理解起来也简单哈;
return getPerformance(performanceReqVO, performanceMapper::selectContractCountPerformance);
}

Expand All @@ -59,99 +56,45 @@ public List<CrmStatisticsPerformanceRespVO> getReceivablePricePerformance(CrmSta
return getPerformance(performanceReqVO, performanceMapper::selectReceivablePricePerformance);
}

// TODO @scholar:代码注释,应该有 3 个变量哈;
/**
* 获得员工业绩数据
*
* 1. 获得今年 + 去年的数据
* 2. 遍历今年的月份,逐个拼接去年的月份数据
*
* @param performanceReqVO 参数
* @param performanceFunction 员工业绩统计方法
* @return 员工业绩数据
*/
// TODO @scholar:下面一行的变量,超过一行了,阅读不美观;可以考虑每一行一个变量;
private List<CrmStatisticsPerformanceRespVO> getPerformance(CrmStatisticsPerformanceReqVO performanceReqVO, Function<CrmStatisticsPerformanceReqVO,
List<CrmStatisticsPerformanceRespVO>> performanceFunction) {

// TODO @scholar:没使用到的变量,建议删除;
List<CrmStatisticsPerformanceRespVO> performanceRespVOList;
private List<CrmStatisticsPerformanceRespVO> getPerformance(CrmStatisticsPerformanceReqVO performanceReqVO,
Function<CrmStatisticsPerformanceReqVO, List<CrmStatisticsPerformanceRespVO>> performanceFunction) {

// 1. 获得用户编号数组
final List<Long> userIds = getUserIds(performanceReqVO);
List<Long> userIds = getUserIds(performanceReqVO);
if (CollUtil.isEmpty(userIds)) {
return Collections.emptyList();
}
performanceReqVO.setUserIds(userIds);
// TODO @scholar:1. 和 2. 之间,可以考虑换一行;保证每一块逻辑的间隔;
// 2. 获得业绩数据
// TODO @scholar:复数变量,建议使用 s 或者 list 结果;这里用 performanceList 好列;
List<CrmStatisticsPerformanceRespVO> performance = performanceFunction.apply(performanceReqVO);

// 获取查询的年份
// TODO @scholar:逻辑可以简化一下;
// TODO 1)把 performance 转换成 map;key 是 time,value 是 count
// TODO 2)当前年,遍历 1-12 月份,去 map 拿到 count;接着月份 -1,去 map 拿 count;再年份 -1,拿 count
String currentYear = LocalDateTimeUtil.format(performanceReqVO.getTimes()[0],"yyyy");

// 构造查询当年和前一年,每年12个月的年月组合
List<String> allMonths = new ArrayList<>();
for (int year = Integer.parseInt(currentYear)-1; year <= Integer.parseInt(currentYear); year++) {
for (int month = 1; month <= 12; month++) {
allMonths.add(String.format("%d%02d", year, month));
}
}

List<CrmStatisticsPerformanceRespVO> computedList = new ArrayList<>();
List<CrmStatisticsPerformanceRespVO> respVOList = new ArrayList<>();

// 生成computedList基础数据
// 构造完整的2*12个月的数据,如果某月数据缺失,需要补上0,一年12个月不能有缺失
for (String month : allMonths) {
CrmStatisticsPerformanceRespVO foundData = performance.stream()
.filter(data -> data.getTime().equals(month))
.findFirst()
.orElse(null);

if (foundData != null) {
computedList.add(foundData);
} else {
CrmStatisticsPerformanceRespVO missingData = new CrmStatisticsPerformanceRespVO();
missingData.setTime(month);
missingData.setCurrentMonthCount(BigDecimal.ZERO);
missingData.setLastMonthCount(BigDecimal.ZERO);
missingData.setLastYearCount(BigDecimal.ZERO);
computedList.add(missingData);
}
}
//根据查询年份和前一年的数据,计算查询年份的同比环比数据
for (CrmStatisticsPerformanceRespVO currentData : computedList) {
String currentMonth = currentData.getTime();

// 根据当年和前一年的月销售数据,计算currentYear的完整数据
if (currentMonth.startsWith(currentYear)) {
// 计算 LastMonthCount
int currentIndex = computedList.indexOf(currentData);
if (currentIndex > 0) {
CrmStatisticsPerformanceRespVO lastMonthData = computedList.get(currentIndex - 1);
currentData.setLastMonthCount(lastMonthData.getCurrentMonthCount());
} else {
currentData.setLastMonthCount(BigDecimal.ZERO); // 第一个月的 LastMonthCount 设为0
}

// 计算 LastYearCount
String lastYearMonth = String.valueOf(Integer.parseInt(currentMonth) - 100);
CrmStatisticsPerformanceRespVO lastYearData = computedList.stream()
.filter(data -> data.getTime().equals(lastYearMonth))
.findFirst()
.orElse(null);

if (lastYearData != null) {
currentData.setLastYearCount(lastYearData.getCurrentMonthCount());
} else {
currentData.setLastYearCount(BigDecimal.ZERO); // 如果去年同月数据不存在,设为0
}
respVOList.add(currentData);//给前端只需要返回查询当年的数据,不需要前一年数据
}
// 2. 获得业绩数据
int year = performanceReqVO.getTimes()[0].getYear(); // 获取查询的年份
performanceReqVO.getTimes()[0] = performanceReqVO.getTimes()[0].minusYears(1);
List<CrmStatisticsPerformanceRespVO> performanceList = performanceFunction.apply(performanceReqVO);
Map<String, BigDecimal> performanceMap = convertMap(performanceList, CrmStatisticsPerformanceRespVO::getTime,
CrmStatisticsPerformanceRespVO::getCurrentMonthCount);

// 3. 组装数据返回
List<CrmStatisticsPerformanceRespVO> result = new ArrayList<>();
for (int month = 1; month <= 12; month++) {
String currentMonth = String.format("%d%02d", year, month);
String lastMonth = month == 1 ? String.format("%d%02d", year - 1, 12) : String.format("%d%02d", year, month - 1);
String lastYear = String.format("%d%02d", year - 1, month);
result.add(new CrmStatisticsPerformanceRespVO().setTime(currentMonth)
.setCurrentMonthCount(performanceMap.getOrDefault(currentMonth, BigDecimal.ZERO))
.setLastMonthCount(performanceMap.getOrDefault(lastMonth, BigDecimal.ZERO))
.setLastYearCount(performanceMap.getOrDefault(lastYear, BigDecimal.ZERO)));
}
return respVOList;
return result;
}

/**
Expand All @@ -163,7 +106,7 @@ private List<CrmStatisticsPerformanceRespVO> getPerformance(CrmStatisticsPerform
private List<Long> getUserIds(CrmStatisticsPerformanceReqVO reqVO) {
// 情况一:选中某个用户
if (ObjUtil.isNotNull(reqVO.getUserId())) {
return ListUtil.of(reqVO.getUserId());
return List.of(reqVO.getUserId());
}
// 情况二:选中某个部门
// 2.1 获得部门列表
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,51 +9,47 @@
COUNT(1) AS currentMonthCount
FROM crm_contract
WHERE deleted = 0
<!-- TODO @scholar:20 改成静态类引入 -->
AND audit_status = 20
AND audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status}
AND owner_user_id in
<foreach collection="userIds" item="userId" open="(" close=")" separator=",">
#{userId}
</foreach>
<!-- TODO @scholar:CrmStatisticsPerformanceReqVO 传递 year,然后 java 代码里,转换出 times;这样,order_time 使用范围查询,避免使用函数 -->
AND (DATE_FORMAT(order_date, '%Y') = DATE_FORMAT(#{times[0],javaType=java.time.LocalDateTime}, '%Y')
or DATE_FORMAT(order_date, '%Y') = DATE_FORMAT(#{times[0],javaType=java.time.LocalDateTime}, '%Y') - 1)
AND order_date between #{times[0],javaType=java.time.LocalDateTime} and
#{times[1],javaType=java.time.LocalDateTime}
GROUP BY time
</select>

<!-- TODO @scholar:参考上面,调整下这个 SQL 的排版、和代码建议哈 -->
<select id="selectContractPricePerformance"
resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceRespVO">
SELECT
DATE_FORMAT(order_date, '%Y%m') AS time,
IFNULL(SUM(total_price), 0) AS currentMonthCount
FROM crm_contract
DATE_FORMAT(order_date, '%Y%m') AS time,
IFNULL(SUM(total_price), 0) AS currentMonthCount
FROM crm_contract
WHERE deleted = 0
AND audit_status = 20
AND audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status}
AND owner_user_id in
<foreach collection="userIds" item="userId" open="(" close=")" separator=",">
#{userId}
</foreach>
AND (DATE_FORMAT(order_date, '%Y') = DATE_FORMAT(#{times[0],javaType=java.time.LocalDateTime},'%Y')
or DATE_FORMAT(order_date, '%Y') = DATE_FORMAT(#{times[0],javaType=java.time.LocalDateTime},'%Y')-1)
<foreach collection="userIds" item="userId" open="(" close=")" separator=",">
#{userId}
</foreach>
AND order_date between #{times[0],javaType=java.time.LocalDateTime} and
#{times[1],javaType=java.time.LocalDateTime}
GROUP BY time
</select>

<!-- TODO @scholar:参考上面,调整下这个 SQL 的排版、和代码建议哈 -->
<select id="selectReceivablePricePerformance"
resultType="cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceRespVO">
SELECT
DATE_FORMAT(return_time, '%Y%m') AS time,
IFNULL(SUM(price), 0) AS currentMonthCount
FROM crm_receivable
DATE_FORMAT(return_time, '%Y%m') AS time,
IFNULL(SUM(price), 0) AS currentMonthCount
FROM crm_receivable
WHERE deleted = 0
AND audit_status = 20
AND audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status}
AND owner_user_id in
<foreach collection="userIds" item="userId" open="(" close=")" separator=",">
#{userId}
</foreach>
AND (DATE_FORMAT(return_time, '%Y') = DATE_FORMAT(#{times[0],javaType=java.time.LocalDateTime},'%Y')
or DATE_FORMAT(return_time, '%Y') = DATE_FORMAT(#{times[0],javaType=java.time.LocalDateTime},'%Y')-1)
<foreach collection="userIds" item="userId" open="(" close=")" separator=",">
#{userId}
</foreach>
AND return_time between #{times[0],javaType=java.time.LocalDateTime} and
#{times[1],javaType=java.time.LocalDateTime}
GROUP BY time
</select>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,10 @@ public interface ErrorCodeConstants {
ErrorCode DIY_PAGE_NOT_EXISTS = new ErrorCode(1_013_018_000, "装修页面不存在");
ErrorCode DIY_PAGE_NAME_USED = new ErrorCode(1_013_018_001, "装修页面名称({})已经被使用");

// ========== 客服会话 1-013-019-000 ==========
ErrorCode KEFU_CONVERSATION_NOT_EXISTS = new ErrorCode(1_013_019_000, "客服会话不存在");

// ========== 客服消息 1-013-020-000 ==========
ErrorCode KEFU_MESSAGE_NOT_EXISTS = new ErrorCode(1_013_020_000, "客服消息不存在");

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package cn.iocoder.yudao.module.promotion.enums;

/**
* Promotion 的 WebSocket 消息类型枚举类
*
* @author HUIHUI
*/
public interface WebSocketMessageTypeConstants {

// ======================= mall 客服 =======================

String KEFU_MESSAGE_TYPE = "kefu_message_type"; // 客服消息类型
String KEFU_MESSAGE_ADMIN_READ = "kefu_message_read_status_change"; // 客服消息管理员已读

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package cn.iocoder.yudao.module.promotion.enums.kehu;

import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;

import java.util.Arrays;

/**
* 客服消息的类型枚举
*
* @author HUIHUI
*/
@AllArgsConstructor
@Getter
public enum KeFuMessageContentTypeEnum implements IntArrayValuable {

TEXT(1, "文本消息"),
IMAGE(2, "图片消息"),
VOICE(3, "语音消息"),
VIDEO(4, "视频消息"),
SYSTEM(5, "系统消息"),

// ========== 商城特殊消息 ==========
PRODUCT(10, "商品消息"),
ORDER(11, "订单消息");

private static final int[] ARRAYS = Arrays.stream(values()).mapToInt(KeFuMessageContentTypeEnum::getType).toArray();

/**
* 类型
*/
private final Integer type;

/**
* 名称
*/
private final String name;

@Override
public int[] array() {
return ARRAYS;
}

}
Loading

0 comments on commit ce1940e

Please sign in to comment.