录音统计

This commit is contained in:
spllzh
2025-08-16 06:13:09 +08:00
parent 45548df6bd
commit b3d28112a7
10 changed files with 1182 additions and 0 deletions

View File

@@ -0,0 +1,173 @@
package com.rj.controller;
import com.rj.common.Result;
import com.rj.entity.AudioManagementStatistics;
import com.rj.scheduler.AudioStatisticsScheduler;
import com.rj.service.IAudioManagementStatisticsService;
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/audio-statistics")
public class AudioStatisticsController {
@Autowired
private IAudioManagementStatisticsService audioStatisticsService;
@Autowired
private AudioStatisticsScheduler audioStatisticsScheduler;
/**
* 手动生成指定日期的统计数据
*/
@Operation(summary = "手动生成指定日期的统计数据", description = "手动触发指定日期的门店录音统计")
@PostMapping("/generate")
public Result generateStatistics(
@Parameter(description = "统计日期,格式:yyyy-MM-dd")
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date) {
try {
int count = audioStatisticsScheduler.manualGenerateStatistics(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<AudioManagementStatistics> statistics = audioStatisticsService.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 Long 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<AudioManagementStatistics> statistics = audioStatisticsService.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<AudioManagementStatistics> statistics = audioStatisticsService.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("/project/{projectId}")
public Result getStatisticsByProject(
@Parameter(description = "项目ID")
@PathVariable String projectId,
@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<AudioManagementStatistics> statistics = audioStatisticsService.getStatisticsByProject(projectId, 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<AudioManagementStatistics> statistics = audioStatisticsService.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<AudioManagementStatistics> statistics = audioStatisticsService.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,107 @@
package com.rj.entity;
import java.math.BigDecimal;
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("audio_management_statistics")
@Schema(description="门店录音统计表")
public class AudioManagementStatistics implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "主键ID")
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@Schema(description = "门店ID")
@TableField("dealership_id")
private Long dealershipId;
@Schema(description = "门店名称")
@TableField("dealership_name")
private String dealershipName;
@Schema(description = "门店录音总时长(秒)")
@TableField("dealership_total_duration")
private Long dealershipTotalDuration;
@Schema(description = "门店录音数量")
@TableField("dealership_recording_count")
private Integer dealershipRecordingCount;
@Schema(description = "门店录音平均时长(秒)")
@TableField("dealership_avg_duration")
private BigDecimal dealershipAvgDuration;
@Schema(description = "销售人员ID")
@TableField("sales_id")
private String salesId;
@Schema(description = "销售人员姓名")
@TableField("sales_name")
private String salesName;
@Schema(description = "销售人员录音总时长(秒)")
@TableField("sales_total_duration")
private Long salesTotalDuration;
@Schema(description = "销售人员录音数量")
@TableField("sales_recording_count")
private Integer salesRecordingCount;
@Schema(description = "销售人员录音平均时长(秒)")
@TableField("sales_avg_duration")
private BigDecimal salesAvgDuration;
@Schema(description = "项目ID")
@TableField("project_id")
private String projectId;
@Schema(description = "项目名称")
@TableField("project_name")
private String projectName;
@Schema(description = "项目录音总时长(秒)")
@TableField("project_total_duration")
private Long projectTotalDuration;
@Schema(description = "项目录音数量")
@TableField("project_recording_count")
private Integer projectRecordingCount;
@Schema(description = "项目录音平均时长(秒)")
@TableField("project_avg_duration")
private BigDecimal projectAvgDuration;
@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,215 @@
package com.rj.example;
import com.rj.entity.AudioManagementStatistics;
import com.rj.scheduler.AudioStatisticsScheduler;
import com.rj.service.IAudioManagementStatisticsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.LocalDate;
import java.util.List;
/**
* 门店录音统计功能使用示例
*
* @author 李中华 ,spllzh
* @since 2025-08-07
*/
@Component
public class AudioStatisticsExample {
@Autowired
private IAudioManagementStatisticsService audioStatisticsService;
@Autowired
private AudioStatisticsScheduler audioStatisticsScheduler;
/**
* 示例1:手动生成指定日期的统计数据
*/
public void exampleGenerateStatistics() {
System.out.println("=== 示例1:手动生成指定日期的统计数据 ===");
// 生成昨天的统计数据
LocalDate yesterday = LocalDate.now().minusDays(1);
int count = audioStatisticsScheduler.manualGenerateStatistics(yesterday);
System.out.println("生成统计记录数: " + count);
System.out.println("统计日期: " + yesterday);
}
/**
* 示例2:查询最近7天的统计数据
*/
public void exampleQueryRecentStatistics() {
System.out.println("=== 示例2:查询最近7天的统计数据 ===");
LocalDate endDate = LocalDate.now().minusDays(1); // 昨天
LocalDate startDate = endDate.minusDays(6); // 7天前
List<AudioManagementStatistics> statistics = audioStatisticsService.getStatisticsByDateRange(startDate, endDate);
System.out.println("查询到统计记录数: " + statistics.size());
System.out.println("查询日期范围: " + startDate + " 到 " + endDate);
// 打印统计信息
for (AudioManagementStatistics stat : statistics) {
System.out.println("门店: " + stat.getDealershipName() +
", 日期: " + stat.getStatisticsDate() +
", 录音数量: " + stat.getDealershipRecordingCount() +
", 总时长: " + stat.getDealershipTotalDuration() + "秒" +
", 平均时长: " + stat.getDealershipAvgDuration() + "秒");
}
}
/**
* 示例3:查询指定门店的统计数据
*/
public void exampleQueryDealershipStatistics() {
System.out.println("=== 示例3:查询指定门店的统计数据 ===");
Long dealershipId = 1L; // 假设门店ID为1
LocalDate startDate = LocalDate.now().minusDays(30); // 最近30天
LocalDate endDate = LocalDate.now().minusDays(1);
List<AudioManagementStatistics> statistics = audioStatisticsService.getStatisticsByDealership(dealershipId, startDate, endDate);
System.out.println("门店ID: " + dealershipId);
System.out.println("查询到统计记录数: " + statistics.size());
// 计算该门店的总统计
long totalDuration = 0;
int totalCount = 0;
for (AudioManagementStatistics stat : statistics) {
totalDuration += stat.getDealershipTotalDuration();
totalCount += stat.getDealershipRecordingCount();
}
System.out.println("门店总录音时长: " + totalDuration + "秒");
System.out.println("门店总录音数量: " + totalCount);
if (totalCount > 0) {
System.out.println("门店平均录音时长: " + (totalDuration / totalCount) + "秒");
}
}
/**
* 示例4:查询指定销售人员的统计数据
*/
public void exampleQuerySalesStatistics() {
System.out.println("=== 示例4:查询指定销售人员的统计数据 ===");
String salesId = "sales001"; // 假设销售人员ID
LocalDate startDate = LocalDate.now().minusDays(30); // 最近30天
LocalDate endDate = LocalDate.now().minusDays(1);
List<AudioManagementStatistics> statistics = audioStatisticsService.getStatisticsBySales(salesId, startDate, endDate);
System.out.println("销售人员ID: " + salesId);
System.out.println("查询到统计记录数: " + statistics.size());
// 计算该销售人员的总统计
long totalDuration = 0;
int totalCount = 0;
for (AudioManagementStatistics stat : statistics) {
totalDuration += stat.getSalesTotalDuration();
totalCount += stat.getSalesRecordingCount();
}
System.out.println("销售人员总录音时长: " + totalDuration + "秒");
System.out.println("销售人员总录音数量: " + totalCount);
if (totalCount > 0) {
System.out.println("销售人员平均录音时长: " + (totalDuration / totalCount) + "秒");
}
}
/**
* 示例5:查询指定项目的统计数据
*/
public void exampleQueryProjectStatistics() {
System.out.println("=== 示例5:查询指定项目的统计数据 ===");
String projectId = "project001"; // 假设项目ID
LocalDate startDate = LocalDate.now().minusDays(30); // 最近30天
LocalDate endDate = LocalDate.now().minusDays(1);
List<AudioManagementStatistics> statistics = audioStatisticsService.getStatisticsByProject(projectId, startDate, endDate);
System.out.println("项目ID: " + projectId);
System.out.println("查询到统计记录数: " + statistics.size());
// 计算该项目的总统计
long totalDuration = 0;
int totalCount = 0;
for (AudioManagementStatistics stat : statistics) {
totalDuration += stat.getProjectTotalDuration();
totalCount += stat.getProjectRecordingCount();
}
System.out.println("项目总录音时长: " + totalDuration + "秒");
System.out.println("项目总录音数量: " + totalCount);
if (totalCount > 0) {
System.out.println("项目平均录音时长: " + (totalDuration / totalCount) + "秒");
}
}
/**
* 示例6:批量生成历史统计数据
*/
public void exampleBatchGenerateStatistics() {
System.out.println("=== 示例6:批量生成历史统计数据 ===");
// 生成最近30天的统计数据
LocalDate endDate = LocalDate.now().minusDays(1);
LocalDate startDate = endDate.minusDays(29);
int totalCount = 0;
for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
try {
int count = audioStatisticsScheduler.manualGenerateStatistics(date);
totalCount += count;
System.out.println("日期 " + date + " 生成统计记录数: " + count);
} catch (Exception e) {
System.err.println("日期 " + date + " 统计失败: " + e.getMessage());
}
}
System.out.println("批量生成完成,总记录数: " + totalCount);
}
/**
* 运行所有示例
*/
public void runAllExamples() {
System.out.println("开始运行门店录音统计功能示例...");
System.out.println();
try {
exampleGenerateStatistics();
System.out.println();
exampleQueryRecentStatistics();
System.out.println();
exampleQueryDealershipStatistics();
System.out.println();
exampleQuerySalesStatistics();
System.out.println();
exampleQueryProjectStatistics();
System.out.println();
exampleBatchGenerateStatistics();
System.out.println();
} catch (Exception e) {
System.err.println("示例运行失败: " + e.getMessage());
e.printStackTrace();
}
System.out.println("示例运行完成!");
}
}

View File

@@ -0,0 +1,92 @@
package com.rj.mapper;
import com.rj.entity.AudioManagementStatistics;
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 AudioManagementStatisticsMapper extends BaseMapper<AudioManagementStatistics> {
/**
* 按门店统计指定日期的录音数据
* @param date 统计日期
* @return 门店统计结果列表
*/
@Select("SELECT " +
"dealership_id, " +
"dealership_name, " +
"SUM(duration * 60) as total_duration_seconds, " +
"COUNT(*) as recording_count, " +
"AVG(duration * 60) as avg_duration_seconds " +
"FROM audio_management " +
"WHERE DATE(recording_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, " +
"sales_name, " +
"SUM(duration * 60) as total_duration_seconds, " +
"COUNT(*) as recording_count, " +
"AVG(duration * 60) as avg_duration_seconds " +
"FROM audio_management " +
"WHERE DATE(recording_time) = #{date} " +
"AND sales_id IS NOT NULL " +
"AND sales_id != '' " +
"GROUP BY sales_id, sales_name")
List<Map<String, Object>> getSalesStatisticsByDate(@Param("date") LocalDate date);
/**
* 按项目统计指定日期的录音数据
* @param date 统计日期
* @return 项目统计结果列表
*/
@Select("SELECT " +
"project_id, " +
"project_name, " +
"SUM(duration * 60) as total_duration_seconds, " +
"COUNT(*) as recording_count, " +
"AVG(duration * 60) as avg_duration_seconds " +
"FROM audio_management " +
"WHERE DATE(recording_time) = #{date} " +
"AND project_id IS NOT NULL " +
"AND project_id != '' " +
"GROUP BY project_id, project_name")
List<Map<String, Object>> getProjectStatisticsByDate(@Param("date") LocalDate date);
/**
* 检查指定日期的统计数据是否已存在
* @param date 统计日期
* @return 统计记录数量
*/
@Select("SELECT COUNT(*) FROM audio_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.scheduler;
import com.rj.service.IAudioManagementStatisticsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDate;
/**
* 门店录音统计定时任务
*
* @author 李中华 ,spllzh
* @since 2025-08-07
*/
@Slf4j
@Component
public class AudioStatisticsScheduler {
@Autowired
private IAudioManagementStatisticsService audioStatisticsService;
/**
* 每天凌晨2点执行门店录音统计
* 统计昨天的录音数据
*/
@Scheduled(cron = "0 0 2 * * ?")
public void generateDailyAudioStatistics() {
try {
log.info("开始执行门店录音统计任务...");
LocalDate yesterday = LocalDate.now().minusDays(1);
int count = audioStatisticsService.generateStatisticsByDate(yesterday);
log.info("门店录音统计任务执行完成,统计日期:{},生成记录数:{}", yesterday, count);
} catch (Exception e) {
log.error("门店录音统计任务执行失败", e);
}
}
/**
* 手动触发统计任务(用于测试或补录数据)
* @param date 要统计的日期
* @return 生成的记录数
*/
public int manualGenerateStatistics(LocalDate date) {
try {
log.info("手动执行门店录音统计任务,统计日期:{}", date);
int count = audioStatisticsService.generateStatisticsByDate(date);
log.info("手动门店录音统计任务执行完成,统计日期:{},生成记录数:{}", date, count);
return count;
} catch (Exception e) {
log.error("手动门店录音统计任务执行失败,统计日期:{}", date, e);
throw e;
}
}
}

View File

@@ -0,0 +1,66 @@
package com.rj.service;
import com.rj.entity.AudioManagementStatistics;
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 IAudioManagementStatisticsService extends IService<AudioManagementStatistics> {
/**
* 生成指定日期的门店录音统计数据
* @param date 统计日期
* @return 生成的统计记录数量
*/
int generateStatisticsByDate(LocalDate date);
/**
* 生成昨天的门店录音统计数据
* @return 生成的统计记录数量
*/
int generateYesterdayStatistics();
/**
* 查询指定日期范围的统计数据
* @param startDate 开始日期
* @param endDate 结束日期
* @return 统计记录列表
*/
List<AudioManagementStatistics> getStatisticsByDateRange(LocalDate startDate, LocalDate endDate);
/**
* 查询指定门店的统计数据
* @param dealershipId 门店ID
* @param startDate 开始日期
* @param endDate 结束日期
* @return 统计记录列表
*/
List<AudioManagementStatistics> getStatisticsByDealership(Long dealershipId, LocalDate startDate, LocalDate endDate);
/**
* 查询指定销售人员的统计数据
* @param salesId 销售人员ID
* @param startDate 开始日期
* @param endDate 结束日期
* @return 统计记录列表
*/
List<AudioManagementStatistics> getStatisticsBySales(String salesId, LocalDate startDate, LocalDate endDate);
/**
* 查询指定项目的统计数据
* @param projectId 项目ID
* @param startDate 开始日期
* @param endDate 结束日期
* @return 统计记录列表
*/
List<AudioManagementStatistics> getStatisticsByProject(String projectId, LocalDate startDate, LocalDate endDate);
}

View File

@@ -0,0 +1,264 @@
package com.rj.service.impl;
import com.rj.entity.AudioManagementStatistics;
import com.rj.mapper.AudioManagementStatisticsMapper;
import com.rj.service.IAudioManagementStatisticsService;
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.math.BigDecimal;
import java.math.RoundingMode;
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 AudioManagementStatisticsServiceImpl extends ServiceImpl<AudioManagementStatisticsMapper, AudioManagementStatistics> implements IAudioManagementStatisticsService {
@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) {
AudioManagementStatistics statistics = new AudioManagementStatistics();
// 设置门店信息
Object dealershipIdObj = stat.get("dealership_id");
if (dealershipIdObj != null) {
try {
statistics.setDealershipId(Long.valueOf(dealershipIdObj.toString()));
} catch (NumberFormatException e) {
// 如果dealership_id是UUID格式,使用hashCode作为ID
statistics.setDealershipId((long) dealershipIdObj.toString().hashCode());
}
} else {
statistics.setDealershipId(0L);
}
Object dealershipNameObj = stat.get("dealership_name");
statistics.setDealershipName(dealershipNameObj != null ? dealershipNameObj.toString() : "未知门店");
// 设置门店录音统计数据
Object totalDurationObj = stat.get("total_duration_seconds");
if (totalDurationObj != null) {
statistics.setDealershipTotalDuration(Long.valueOf(totalDurationObj.toString()));
} else {
statistics.setDealershipTotalDuration(0L);
}
Object recordingCountObj = stat.get("recording_count");
if (recordingCountObj != null) {
statistics.setDealershipRecordingCount(Integer.valueOf(recordingCountObj.toString()));
} else {
statistics.setDealershipRecordingCount(0);
}
// 计算门店平均时长
if (statistics.getDealershipRecordingCount() > 0 && statistics.getDealershipTotalDuration() > 0) {
BigDecimal avgDuration = BigDecimal.valueOf(statistics.getDealershipTotalDuration())
.divide(BigDecimal.valueOf(statistics.getDealershipRecordingCount()), 2, RoundingMode.HALF_UP);
statistics.setDealershipAvgDuration(avgDuration);
} else {
statistics.setDealershipAvgDuration(BigDecimal.ZERO);
}
// 查找该门店对应的销售人员统计数据
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 salesNameObj = salesStat.get("sales_name");
statistics.setSalesName(salesNameObj != null ? salesNameObj.toString() : "未知销售");
// 设置销售人员录音统计数据
Object salesTotalDurationObj = salesStat.get("total_duration_seconds");
if (salesTotalDurationObj != null) {
statistics.setSalesTotalDuration(Long.valueOf(salesTotalDurationObj.toString()));
} else {
statistics.setSalesTotalDuration(0L);
}
Object salesRecordingCountObj = salesStat.get("recording_count");
if (salesRecordingCountObj != null) {
statistics.setSalesRecordingCount(Integer.valueOf(salesRecordingCountObj.toString()));
} else {
statistics.setSalesRecordingCount(0);
}
// 计算销售人员平均时长
if (statistics.getSalesRecordingCount() > 0 && statistics.getSalesTotalDuration() > 0) {
BigDecimal salesAvgDuration = BigDecimal.valueOf(statistics.getSalesTotalDuration())
.divide(BigDecimal.valueOf(statistics.getSalesRecordingCount()), 2, RoundingMode.HALF_UP);
statistics.setSalesAvgDuration(salesAvgDuration);
} else {
statistics.setSalesAvgDuration(BigDecimal.ZERO);
}
} else {
// 如果没有找到对应的销售人员数据,设置为空
statistics.setSalesId("");
statistics.setSalesName("");
statistics.setSalesTotalDuration(0L);
statistics.setSalesRecordingCount(0);
statistics.setSalesAvgDuration(BigDecimal.ZERO);
}
// 查找该门店对应的项目统计数据
String dealershipIdForProject = dealershipIdObj != null ? dealershipIdObj.toString() : "";
Map<String, Object> projectStat = findProjectStatByDealership(projectStatsList, dealershipIdForProject);
if (projectStat != null) {
// 设置项目信息
Object projectIdObj = projectStat.get("project_id");
statistics.setProjectId(projectIdObj != null ? projectIdObj.toString() : "");
Object projectNameObj = projectStat.get("project_name");
statistics.setProjectName(projectNameObj != null ? projectNameObj.toString() : "未知项目");
// 设置项目录音统计数据
Object projectTotalDurationObj = projectStat.get("total_duration_seconds");
if (projectTotalDurationObj != null) {
statistics.setProjectTotalDuration(Long.valueOf(projectTotalDurationObj.toString()));
} else {
statistics.setProjectTotalDuration(0L);
}
Object projectRecordingCountObj = projectStat.get("recording_count");
if (projectRecordingCountObj != null) {
statistics.setProjectRecordingCount(Integer.valueOf(projectRecordingCountObj.toString()));
} else {
statistics.setProjectRecordingCount(0);
}
// 计算项目平均时长
if (statistics.getProjectRecordingCount() > 0 && statistics.getProjectTotalDuration() > 0) {
BigDecimal projectAvgDuration = BigDecimal.valueOf(statistics.getProjectTotalDuration())
.divide(BigDecimal.valueOf(statistics.getProjectRecordingCount()), 2, RoundingMode.HALF_UP);
statistics.setProjectAvgDuration(projectAvgDuration);
} else {
statistics.setProjectAvgDuration(BigDecimal.ZERO);
}
} else {
// 如果没有找到对应的项目数据,设置为空
statistics.setProjectId("");
statistics.setProjectName("");
statistics.setProjectTotalDuration(0L);
statistics.setProjectRecordingCount(0);
statistics.setProjectAvgDuration(BigDecimal.ZERO);
}
// 设置统计日期和时间
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查找对应的项目统计数据
* @param projectStatsList 项目统计列表
* @param dealershipId 门店ID
* @return 项目统计数据
*/
private Map<String, Object> findProjectStatByDealership(List<Map<String, Object>> projectStatsList, String dealershipId) {
// 这里需要根据业务逻辑来确定门店和项目的对应关系
// 由于原始数据中可能没有直接的关联关系,这里返回第一个项目数据作为示例
// 实际使用时需要根据具体的业务逻辑来调整
if (!projectStatsList.isEmpty()) {
return projectStatsList.get(0);
}
return null;
}
@Override
public int generateYesterdayStatistics() {
LocalDate yesterday = LocalDate.now().minusDays(1);
return generateStatisticsByDate(yesterday);
}
@Override
public List<AudioManagementStatistics> getStatisticsByDateRange(LocalDate startDate, LocalDate endDate) {
LambdaQueryWrapper<AudioManagementStatistics> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.between(AudioManagementStatistics::getStatisticsDate, startDate, endDate)
.orderByAsc(AudioManagementStatistics::getStatisticsDate)
.orderByAsc(AudioManagementStatistics::getDealershipId);
return list(queryWrapper);
}
@Override
public List<AudioManagementStatistics> getStatisticsByDealership(Long dealershipId, LocalDate startDate, LocalDate endDate) {
LambdaQueryWrapper<AudioManagementStatistics> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(AudioManagementStatistics::getDealershipId, dealershipId)
.between(AudioManagementStatistics::getStatisticsDate, startDate, endDate)
.orderByAsc(AudioManagementStatistics::getStatisticsDate);
return list(queryWrapper);
}
@Override
public List<AudioManagementStatistics> getStatisticsBySales(String salesId, LocalDate startDate, LocalDate endDate) {
LambdaQueryWrapper<AudioManagementStatistics> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(AudioManagementStatistics::getSalesId, salesId)
.between(AudioManagementStatistics::getStatisticsDate, startDate, endDate)
.orderByAsc(AudioManagementStatistics::getStatisticsDate);
return list(queryWrapper);
}
@Override
public List<AudioManagementStatistics> getStatisticsByProject(String projectId, LocalDate startDate, LocalDate endDate) {
LambdaQueryWrapper<AudioManagementStatistics> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(AudioManagementStatistics::getProjectId, projectId)
.between(AudioManagementStatistics::getStatisticsDate, startDate, endDate)
.orderByAsc(AudioManagementStatistics::getStatisticsDate);
return list(queryWrapper);
}
}

View File

@@ -0,0 +1,11 @@
<?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.AudioManagementStatisticsMapper">
<!-- 删除指定日期的统计数据 -->
<delete id="deleteByStatisticsDate" parameterType="java.time.LocalDate">
DELETE FROM audio_management_statistics
WHERE statistics_date = #{date}
</delete>
</mapper>

View File

@@ -0,0 +1,73 @@
-- 用于存储门店录音相关数据, 基础的原始数据,可以用于统计分析
CREATE TABLE `audio_management` (
`id` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '主键,UUID',
`recording_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '录音名称',
`recording_time` datetime NULL DEFAULT NULL COMMENT '录音时间',
`info_card_description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '信息卡',
`sales_id` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '所属销售ID',
`sales_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '所属销售名称',
`duration` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '录音时长(分钟)',
`customer_id` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '客户ID',
`customer_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '客户姓名',
`customer_phone` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '客户手机号',
`upload_time` datetime NULL DEFAULT NULL COMMENT '上传时间',
`intention_level` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '意向级别(高意向, 中意向 , 低意向)',
`dealership_id` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '所属门店ID',
`dealership_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '所属门店名称',
`project_id` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '所属项目ID',
`project_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '所属项目名称',
`script_model` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '话术模型',
`upload_status` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '上传状态',
`sync_status` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '同步状态',
`is_merged` tinyint(1) NULL DEFAULT 0 COMMENT '是否合并(0否1是)',
`remarks` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '录音备注',
`company_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '公司类型',
`edit_status` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '编辑状态',
`edit_time` datetime NULL DEFAULT NULL COMMENT '编辑时间',
`info_card_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '信息卡类型(如意向车型、购买情况、来访目的、试驾结果、付款方式、试驾专员等)',
`info_card_value` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '信息卡内容',
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '录音管理表,含信息卡字段' ROW_FORMAT = Dynamic;
-- 用于存储门店录音相关的统计数据
CREATE TABLE `audio_management_statistics` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`dealership_id` bigint(20) NOT NULL COMMENT '门店ID',
`dealership_name` varchar(100) NOT NULL COMMENT '门店名称',
-- 门店录音总时长相关字段
`dealership_total_duration` bigint(20) NOT NULL DEFAULT 0 COMMENT '门店录音总时长(秒)',
`dealership_recording_count` int(11) NOT NULL DEFAULT 0 COMMENT '门店录音数量',
`dealership_avg_duration` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '门店录音平均时长(秒)',
-- 个人录音相关字段
`personal_total_duration` bigint(20) NOT NULL DEFAULT 0 COMMENT '个人录音总时长(秒)',
`personal_recording_count` int(11) NOT NULL DEFAULT 0 COMMENT '个人录音数量',
`personal_avg_duration` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '个人录音平均时长(秒)',
-- 项目录音相关字段
`project_recording_count` int(11) NOT NULL DEFAULT 0 COMMENT '项目录音总数',
`project_avg_duration` decimal(10,2) NOT NULL DEFAULT 0.00 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 '统计日期索引',
KEY `idx_dealership_id` (`dealership_id`) COMMENT '门店ID索引',
KEY `idx_created_at` (`created_at`) COMMENT '创建时间索引'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='门店录音统计表';

View File

@@ -0,0 +1,123 @@
package com.rj.service;
import com.rj.entity.AudioManagementStatistics;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import java.time.LocalDate;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
/**
* 门店录音统计服务测试类
*
* @author 李中华 ,spllzh
* @since 2025-08-07
*/
@SpringBootTest
@ActiveProfiles("test")
public class AudioManagementStatisticsServiceTest {
@Autowired
private IAudioManagementStatisticsService audioStatisticsService;
@Test
public void testGenerateStatisticsByDate() {
// 测试生成指定日期的统计数据
LocalDate testDate = LocalDate.now().minusDays(1);
int count = audioStatisticsService.generateStatisticsByDate(testDate);
assertTrue(count >= 0, "统计记录数应该大于等于0");
System.out.println("生成统计记录数: " + count);
}
@Test
public void testGenerateYesterdayStatistics() {
// 测试生成昨天的统计数据
int count = audioStatisticsService.generateYesterdayStatistics();
assertTrue(count >= 0, "统计记录数应该大于等于0");
System.out.println("生成昨天统计记录数: " + count);
}
@Test
public void testGetStatisticsByDateRange() {
// 测试查询日期范围的统计数据
LocalDate startDate = LocalDate.now().minusDays(7);
LocalDate endDate = LocalDate.now().minusDays(1);
List<AudioManagementStatistics> statistics = audioStatisticsService.getStatisticsByDateRange(startDate, endDate);
assertNotNull(statistics, "统计列表不应该为null");
System.out.println("查询到统计记录数: " + statistics.size());
// 打印统计信息
for (AudioManagementStatistics stat : statistics) {
System.out.println("门店: " + stat.getDealershipName() +
", 日期: " + stat.getStatisticsDate() +
", 录音数量: " + stat.getDealershipRecordingCount() +
", 总时长: " + stat.getDealershipTotalDuration() + "秒" +
", 平均时长: " + stat.getDealershipAvgDuration() + "秒");
}
}
@Test
public void testGetStatisticsByDealership() {
// 测试查询指定门店的统计数据
Long dealershipId = 1L; // 假设门店ID为1
LocalDate startDate = LocalDate.now().minusDays(7);
LocalDate endDate = LocalDate.now().minusDays(1);
List<AudioManagementStatistics> statistics = audioStatisticsService.getStatisticsByDealership(dealershipId, startDate, endDate);
assertNotNull(statistics, "统计列表不应该为null");
System.out.println("查询到门店统计记录数: " + statistics.size());
}
@Test
public void testGetStatisticsBySales() {
// 测试查询指定销售人员的统计数据
String salesId = "sales001"; // 假设销售人员ID
LocalDate startDate = LocalDate.now().minusDays(30); // 最近30天
LocalDate endDate = LocalDate.now().minusDays(1);
List<AudioManagementStatistics> statistics = audioStatisticsService.getStatisticsBySales(salesId, startDate, endDate);
assertNotNull(statistics, "统计列表不应该为null");
System.out.println("查询到销售人员统计记录数: " + statistics.size());
// 打印销售人员统计信息
for (AudioManagementStatistics stat : statistics) {
System.out.println("销售人员: " + stat.getSalesName() +
", 日期: " + stat.getStatisticsDate() +
", 录音数量: " + stat.getSalesRecordingCount() +
", 总时长: " + stat.getSalesTotalDuration() + "秒" +
", 平均时长: " + stat.getSalesAvgDuration() + "秒");
}
}
@Test
public void testGetStatisticsByProject() {
// 测试查询指定项目的统计数据
String projectId = "project001"; // 假设项目ID
LocalDate startDate = LocalDate.now().minusDays(30); // 最近30天
LocalDate endDate = LocalDate.now().minusDays(1);
List<AudioManagementStatistics> statistics = audioStatisticsService.getStatisticsByProject(projectId, startDate, endDate);
assertNotNull(statistics, "统计列表不应该为null");
System.out.println("查询到项目统计记录数: " + statistics.size());
// 打印项目统计信息
for (AudioManagementStatistics stat : statistics) {
System.out.println("项目: " + stat.getProjectName() +
", 日期: " + stat.getStatisticsDate() +
", 录音数量: " + stat.getProjectRecordingCount() +
", 总时长: " + stat.getProjectTotalDuration() + "秒" +
", 平均时长: " + stat.getProjectAvgDuration() + "秒");
}
}
}