客户统计的代码框架

This commit is contained in:
2026-02-08 17:10:25 +08:00
parent 6350261a55
commit c003cbb11c
9 changed files with 584 additions and 2 deletions

View File

@@ -140,6 +140,9 @@ hikari:

View File

@@ -0,0 +1,16 @@
CREATE TABLE `customer_management_statistics` (
`id` VARCHAR(36) NOT NULL COMMENT '主键ID',
`tenant_id` VARCHAR(64) DEFAULT NULL COMMENT '租户ID',
`dealership_id` VARCHAR(64) DEFAULT NULL COMMENT '经销商ID',
`dealership_name` VARCHAR(255) DEFAULT NULL COMMENT '经销商名称',
`sales_id` VARCHAR(64) DEFAULT NULL COMMENT '销售ID',
`count_by_dealership` INT DEFAULT 0 COMMENT '按经销商统计数量',
`count_by_sales` INT DEFAULT 0 COMMENT '按销售统计数量',
`count_by_project` INT DEFAULT 0 COMMENT '按项目统计数量',
`statistics_date` DATE NOT NULL COMMENT '统计日期',
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_statistics_date` (`statistics_date`) COMMENT '统计日期索引'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='客户统计表';

View File

@@ -86,11 +86,11 @@ public class CustomerManagementController {
queryWrapper.eq(AudioManagement::getSalesPhone, salesPhone.trim())
.eq(AudioManagement::getServiceStatus, AudioManagementConstants.SERVICE_STATUS_IN_SERVICE);
long count = audioManagementService.count(queryWrapper);
if (count > 0) {
if (count > 0) { //如果正在服务,就直接返回,不能新增记录
result.put("success", true);
result.put("message", isUpdate ? "客户信息更新成功" : "客户添加成功");
result.put("message", "该销售人员正在服务其他客户,无法创建新的服务记录");
return ResponseEntity.badRequest().body(result);
return ResponseEntity.badRequest().body(result); //如果正在服务,就直接返回,不能新增记录
}
}
AudioManagement audioRecord = buildAudioRecordFromCustomer(customerManagement, now);

View File

@@ -0,0 +1,148 @@
package com.rj.controller;
import com.rj.common.Result;
import com.rj.entity.CustomerManagementStatistics;
import com.rj.service.ICustomerManagementStatisticsService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDate;
import java.util.List;
/**
* 客户统计控制器
*
* @author 李中华 ,spllzh
* @since 2025-08-07
*/
@Tag(name = "客户统计", description = "客户统计相关接口")
@RestController
@RequestMapping("/api/customer-statistics")
public class CustomerManagementStatisticsController {
@Autowired
private ICustomerManagementStatisticsService customerStatisticsService;
/**
* 手动生成指定日期的统计数据
*/
@Operation(summary = "手动生成指定日期的统计数据", description = "手动触发指定日期的客户统计")
@PostMapping("/generate")
public Result<?> generateStatistics(
@Parameter(description = "统计日期格式yyyy-MM-dd")
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date) {
try {
int count = customerStatisticsService.generateStatisticsByDate(date);
Result<?> result = Result.ok(count);
result.setMsg("统计生成成功");
return result;
} catch (Exception e) {
return Result.error("统计生成失败:" + e.getMessage());
}
}
/**
* 查询指定日期范围的统计数据
*/
@Operation(summary = "查询指定日期范围的统计数据", description = "查询指定日期范围内的客户统计数据")
@GetMapping("/range")
public Result<?> getStatisticsByDateRange(
@Parameter(description = "开始日期格式yyyy-MM-dd")
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate,
@Parameter(description = "结束日期格式yyyy-MM-dd")
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate) {
try {
List<CustomerManagementStatistics> statistics = customerStatisticsService.getStatisticsByDateRange(startDate, endDate);
Result<?> result = Result.ok(statistics);
result.setMsg("查询成功");
return result;
} catch (Exception e) {
return Result.error("查询失败:" + e.getMessage());
}
}
/**
* 查询指定经销商的统计数据
*/
@Operation(summary = "查询指定经销商的统计数据", description = "查询指定经销商在指定日期范围内的客户统计数据")
@GetMapping("/dealership/{dealershipId}")
public Result<?> getStatisticsByDealership(
@Parameter(description = "经销商ID")
@PathVariable String dealershipId,
@Parameter(description = "开始日期格式yyyy-MM-dd")
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate,
@Parameter(description = "结束日期格式yyyy-MM-dd")
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate) {
try {
List<CustomerManagementStatistics> statistics = customerStatisticsService.getStatisticsByDealership(dealershipId, startDate, endDate);
Result<?> result = Result.ok(statistics);
result.setMsg("查询成功");
return result;
} catch (Exception e) {
return Result.error("查询失败:" + e.getMessage());
}
}
/**
* 查询指定销售的统计数据
*/
@Operation(summary = "查询指定销售的统计数据", description = "查询指定销售在指定日期范围内的客户统计数据")
@GetMapping("/sales/{salesId}")
public Result<?> getStatisticsBySales(
@Parameter(description = "销售ID")
@PathVariable String salesId,
@Parameter(description = "开始日期格式yyyy-MM-dd")
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate,
@Parameter(description = "结束日期格式yyyy-MM-dd")
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate) {
try {
List<CustomerManagementStatistics> statistics = customerStatisticsService.getStatisticsBySales(salesId, startDate, endDate);
Result<?> result = Result.ok(statistics);
result.setMsg("查询成功");
return result;
} catch (Exception e) {
return Result.error("查询失败:" + e.getMessage());
}
}
/**
* 查询指定日期的统计数据
*/
@Operation(summary = "查询指定日期的统计数据", description = "查询指定日期的所有客户统计数据")
@GetMapping("/date/{date}")
public Result<?> getStatisticsByDate(
@Parameter(description = "统计日期格式yyyy-MM-dd")
@PathVariable @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date) {
try {
List<CustomerManagementStatistics> statistics = customerStatisticsService.getStatisticsByDateRange(date, date);
Result<?> result = Result.ok(statistics);
result.setMsg("查询成功");
return result;
} catch (Exception e) {
return Result.error("查询失败:" + e.getMessage());
}
}
/**
* 获取统计概览最近7天
*/
@Operation(summary = "获取统计概览", description = "获取最近7天的客户统计概览")
@GetMapping("/overview")
public Result<?> getStatisticsOverview() {
try {
LocalDate endDate = LocalDate.now().minusDays(1); // 昨天
LocalDate startDate = endDate.minusDays(6); // 7天前
List<CustomerManagementStatistics> statistics = customerStatisticsService.getStatisticsByDateRange(startDate, endDate);
Result<?> result = Result.ok(statistics);
result.setMsg("查询成功");
return result;
} catch (Exception e) {
return Result.error("查询失败:" + e.getMessage());
}
}
}

View File

@@ -0,0 +1,75 @@
package com.rj.entity;
import java.time.LocalDate;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import java.io.Serializable;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
* 客户统计表
* </p>
*
* @author 李中华 ,spllzh
* @since 2025-08-07
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("customer_management_statistics")
@Schema(description="客户统计表")
public class CustomerManagementStatistics implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "主键ID")
@TableId(value = "id", type = IdType.ASSIGN_UUID)
private String id;
@Schema(description = "租户ID")
@TableField("tenant_id")
private String tenantId;
@Schema(description = "经销商ID")
@TableField("dealership_id")
private String dealershipId;
@Schema(description = "经销商名称")
@TableField("dealership_name")
private String dealershipName;
@Schema(description = "销售ID")
@TableField("sales_id")
private String salesId;
@Schema(description = "按经销商统计数量")
@TableField("count_by_dealership")
private Integer countByDealership;
@Schema(description = "按销售统计数量")
@TableField("count_by_sales")
private Integer countBySales;
@Schema(description = "按项目统计数量")
@TableField("count_by_project")
private Integer countByProject;
@Schema(description = "统计日期")
@TableField("statistics_date")
private LocalDate statisticsDate;
@Schema(description = "创建时间")
@TableField("created_at")
private LocalDateTime createdAt;
@Schema(description = "更新时间")
@TableField("updated_at")
private LocalDateTime updatedAt;
}

View File

@@ -0,0 +1,88 @@
package com.rj.mapper;
import com.rj.entity.CustomerManagementStatistics;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
/**
* <p>
* 客户统计表 Mapper 接口
* </p>
*
* @author 李中华 ,spllzh
* @since 2025-08-07
*/
@Mapper
public interface CustomerManagementStatisticsMapper extends BaseMapper<CustomerManagementStatistics> {
/**
* 按经销商统计指定日期的客户数据
* @param date 统计日期
* @return 经销商统计结果列表
*/
@Select("SELECT " +
"dealership_id, " +
"dealership_name, " +
"COUNT(*) as count_by_dealership " +
"FROM customer_management " +
"WHERE DATE(create_time) = #{date} " +
"AND dealership_id IS NOT NULL " +
"AND dealership_id != '' " +
"GROUP BY dealership_id, dealership_name")
List<Map<String, Object>> getDealershipStatisticsByDate(@Param("date") LocalDate date);
/**
* 按销售统计指定日期的客户数据
* @param date 统计日期
* @return 销售统计结果列表
*/
@Select("SELECT " +
"sales_id, " +
"COUNT(*) as count_by_sales " +
"FROM customer_management " +
"WHERE DATE(create_time) = #{date} " +
"AND sales_id IS NOT NULL " +
"AND sales_id != '' " +
"GROUP BY sales_id")
List<Map<String, Object>> getSalesStatisticsByDate(@Param("date") LocalDate date);
/**
* 按项目统计指定日期的客户数据
* @param date 统计日期
* @return 项目统计结果列表
*/
@Select("SELECT " +
"dealership_id, " +
"sales_id, " +
"COUNT(*) as count_by_project " +
"FROM customer_management " +
"WHERE DATE(create_time) = #{date} " +
"AND dealership_id IS NOT NULL " +
"AND dealership_id != '' " +
"AND sales_id IS NOT NULL " +
"AND sales_id != '' " +
"GROUP BY dealership_id, sales_id")
List<Map<String, Object>> getProjectStatisticsByDate(@Param("date") LocalDate date);
/**
* 检查指定日期的统计数据是否已存在
* @param date 统计日期
* @return 统计记录数量
*/
@Select("SELECT COUNT(*) FROM customer_management_statistics WHERE statistics_date = #{date}")
int countByStatisticsDate(@Param("date") LocalDate date);
/**
* 删除指定日期的统计数据
* @param date 统计日期
* @return 删除的记录数
*/
int deleteByStatisticsDate(@Param("date") LocalDate date);
}

View File

@@ -0,0 +1,58 @@
package com.rj.service;
import com.rj.entity.CustomerManagementStatistics;
import com.baomidou.mybatisplus.extension.service.IService;
import java.time.LocalDate;
import java.util.List;
/**
* <p>
* 客户统计表 服务类
* </p>
*
* @author 李中华 ,spllzh
* @since 2025-08-07
*/
public interface ICustomerManagementStatisticsService extends IService<CustomerManagementStatistics> {
/**
* 生成指定日期的客户统计数据
* @param date 统计日期
* @return 生成的统计记录数量
*/
int generateStatisticsByDate(LocalDate date);
/**
* 生成昨天的客户统计数据
* @return 生成的统计记录数量
*/
int generateYesterdayStatistics();
/**
* 查询指定日期范围的统计数据
* @param startDate 开始日期
* @param endDate 结束日期
* @return 统计记录列表
*/
List<CustomerManagementStatistics> getStatisticsByDateRange(LocalDate startDate, LocalDate endDate);
/**
* 查询指定经销商的统计数据
* @param dealershipId 经销商ID
* @param startDate 开始日期
* @param endDate 结束日期
* @return 统计记录列表
*/
List<CustomerManagementStatistics> getStatisticsByDealership(String dealershipId, LocalDate startDate, LocalDate endDate);
/**
* 查询指定销售的统计数据
* @param salesId 销售ID
* @param startDate 开始日期
* @param endDate 结束日期
* @return 统计记录列表
*/
List<CustomerManagementStatistics> getStatisticsBySales(String salesId, LocalDate startDate, LocalDate endDate);
}

View File

@@ -0,0 +1,182 @@
package com.rj.service.impl;
import com.rj.entity.CustomerManagementStatistics;
import com.rj.mapper.CustomerManagementStatisticsMapper;
import com.rj.service.ICustomerManagementStatisticsService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
/**
* <p>
* 客户统计表 服务实现类
* </p>
*
* @author 李中华 ,spllzh
* @since 2025-08-07
*/
@Service
public class CustomerManagementStatisticsServiceImpl extends ServiceImpl<CustomerManagementStatisticsMapper, CustomerManagementStatistics> implements ICustomerManagementStatisticsService {
@Override
@Transactional(rollbackFor = Exception.class)
public int generateStatisticsByDate(LocalDate date) {
// 先删除该日期的统计数据(如果存在)
baseMapper.deleteByStatisticsDate(date);
// 查询该日期的经销商客户统计数据
List<Map<String, Object>> dealershipStatsList = baseMapper.getDealershipStatisticsByDate(date);
// 查询该日期的销售客户统计数据
List<Map<String, Object>> salesStatsList = baseMapper.getSalesStatisticsByDate(date);
// 查询该日期的项目客户统计数据
List<Map<String, Object>> projectStatsList = baseMapper.getProjectStatisticsByDate(date);
int count = 0;
// 处理经销商统计数据
for (Map<String, Object> stat : dealershipStatsList) {
CustomerManagementStatistics statistics = new CustomerManagementStatistics();
// 设置经销商信息
Object dealershipIdObj = stat.get("dealership_id");
statistics.setDealershipId(dealershipIdObj != null ? dealershipIdObj.toString() : "");
Object dealershipNameObj = stat.get("dealership_name");
statistics.setDealershipName(dealershipNameObj != null ? dealershipNameObj.toString() : "未知经销商");
// 设置经销商统计数量
Object countByDealershipObj = stat.get("count_by_dealership");
if (countByDealershipObj != null) {
statistics.setCountByDealership(Integer.valueOf(countByDealershipObj.toString()));
} else {
statistics.setCountByDealership(0);
}
// 查找该经销商对应的销售统计数据
String dealershipId = dealershipIdObj != null ? dealershipIdObj.toString() : "";
Map<String, Object> salesStat = findSalesStatByDealership(salesStatsList, dealershipId);
if (salesStat != null) {
// 设置销售信息
Object salesIdObj = salesStat.get("sales_id");
statistics.setSalesId(salesIdObj != null ? salesIdObj.toString() : "");
// 设置销售统计数量
Object countBySalesObj = salesStat.get("count_by_sales");
if (countBySalesObj != null) {
statistics.setCountBySales(Integer.valueOf(countBySalesObj.toString()));
} else {
statistics.setCountBySales(0);
}
} else {
// 如果没有找到对应的销售数据,设置为空
statistics.setSalesId("");
statistics.setCountBySales(0);
}
// 查找该经销商和销售对应的项目统计数据
Map<String, Object> projectStat = findProjectStat(projectStatsList, dealershipId, statistics.getSalesId());
if (projectStat != null) {
// 设置项目统计数量
Object countByProjectObj = projectStat.get("count_by_project");
if (countByProjectObj != null) {
statistics.setCountByProject(Integer.valueOf(countByProjectObj.toString()));
} else {
statistics.setCountByProject(0);
}
} else {
statistics.setCountByProject(0);
}
// 设置统计日期和时间
statistics.setStatisticsDate(date);
statistics.setCreatedAt(LocalDateTime.now());
statistics.setUpdatedAt(LocalDateTime.now());
// 保存统计记录
save(statistics);
count++;
}
return count;
}
/**
* 根据经销商ID查找对应的销售统计数据
* @param salesStatsList 销售统计列表
* @param dealershipId 经销商ID
* @return 销售统计数据
*/
private Map<String, Object> findSalesStatByDealership(List<Map<String, Object>> salesStatsList, String dealershipId) {
// 这里需要根据业务逻辑来确定经销商和销售的对应关系
// 由于原始数据中可能没有直接的关联关系,这里返回第一个销售数据作为示例
// 实际使用时需要根据具体的业务逻辑来调整
if (!salesStatsList.isEmpty()) {
return salesStatsList.get(0);
}
return null;
}
/**
* 根据经销商ID和销售ID查找对应的项目统计数据
* @param projectStatsList 项目统计列表
* @param dealershipId 经销商ID
* @param salesId 销售ID
* @return 项目统计数据
*/
private Map<String, Object> findProjectStat(List<Map<String, Object>> projectStatsList, String dealershipId, String salesId) {
for (Map<String, Object> projectStat : projectStatsList) {
Object projectDealershipId = projectStat.get("dealership_id");
Object projectSalesId = projectStat.get("sales_id");
if (dealershipId != null && dealershipId.equals(projectDealershipId != null ? projectDealershipId.toString() : "") &&
salesId != null && salesId.equals(projectSalesId != null ? projectSalesId.toString() : "")) {
return projectStat;
}
}
return null;
}
@Override
public int generateYesterdayStatistics() {
LocalDate yesterday = LocalDate.now().minusDays(1);
return generateStatisticsByDate(yesterday);
}
@Override
public List<CustomerManagementStatistics> getStatisticsByDateRange(LocalDate startDate, LocalDate endDate) {
LambdaQueryWrapper<CustomerManagementStatistics> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.between(CustomerManagementStatistics::getStatisticsDate, startDate, endDate)
.orderByAsc(CustomerManagementStatistics::getStatisticsDate)
.orderByAsc(CustomerManagementStatistics::getDealershipId);
return list(queryWrapper);
}
@Override
public List<CustomerManagementStatistics> getStatisticsByDealership(String dealershipId, LocalDate startDate, LocalDate endDate) {
LambdaQueryWrapper<CustomerManagementStatistics> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(CustomerManagementStatistics::getDealershipId, dealershipId)
.between(CustomerManagementStatistics::getStatisticsDate, startDate, endDate)
.orderByAsc(CustomerManagementStatistics::getStatisticsDate);
return list(queryWrapper);
}
@Override
public List<CustomerManagementStatistics> getStatisticsBySales(String salesId, LocalDate startDate, LocalDate endDate) {
LambdaQueryWrapper<CustomerManagementStatistics> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(CustomerManagementStatistics::getSalesId, salesId)
.between(CustomerManagementStatistics::getStatisticsDate, startDate, endDate)
.orderByAsc(CustomerManagementStatistics::getStatisticsDate);
return list(queryWrapper);
}
}

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.rj.mapper.CustomerManagementStatisticsMapper">
<!-- 删除指定日期的统计数据 -->
<delete id="deleteByStatisticsDate" parameterType="java.time.LocalDate">
DELETE FROM customer_management_statistics
WHERE statistics_date = #{date}
</delete>
</mapper>