录音管理和销售管理能增强

This commit is contained in:
spllzh
2025-10-01 17:57:11 +08:00
parent f6ad404f65
commit a493ef8c20
32 changed files with 365 additions and 52 deletions

View File

@@ -40,16 +40,14 @@ public class AudioMockInsertDataScheduler {
{"1957424785875087368", "威兹曼GT项目"}
};
// 销售顾问数据 - 参考适配准真实.sql
// 销售顾问数据 - 参考适配准真实.sql (ID, 姓名, 电话)
private static final String[][] SALES_PEOPLE = {
{"1957424800000000001", "张明"},
{"1957424800000000002", "李华"},
{"1957424800000000003", "王强"},
{"1957424800000000004", "刘芳"},
{"1957424800000000005", "陈军"},
{"1957424800000000006", "赵敏"},
{"1957424800000000007", "孙丽"},
{"1957424800000000008", "周涛"}
{"1972975619388026881", "江叶", "1899263500"},
{"1972975623548776449", "许莲", "1894165677"},
{"1972975624127590401", "叶洋", "1887059943"},
{"1972975624584769537", "曾艺", "1883632473"},
{"1972975625037754369", "赵眉", "1502041762"},
{"1972975625520099329", "付婵", "1506166863"}
};
// 经销商门店数据 - 参考适配准真实.sql按ID名称
@@ -180,6 +178,7 @@ public class AudioMockInsertDataScheduler {
audio.setRecordingTime(recordTime);
audio.setSalesId(sale[0]);
audio.setSalesName(sale[1]);
audio.setSalesPhone(sale[2]);
audio.setDuration(new BigDecimal(String.format("%d.%d",
5 + random.nextInt(55), // 分钟
random.nextInt(10))));

View File

@@ -83,6 +83,11 @@ public class AudioStatisticsScheduler {

View File

@@ -0,0 +1,177 @@
package com.rj.scheduler;
import com.rj.controller.SalesManagementController;
import com.rj.entity.SalesManagement;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
/**
* 销售管理模拟数据定时生成器
* 每天凌晨2:00循环50次调用新增销售接口插入尽量真实的模拟数据
* 数据取值范围参考 src/main/sql/sales_management.sql
*
* Author: 自动生成
* Date: 2025/01/27
*/
@Slf4j
@Component
public class SalesManagementMockInsertDataScheduler {
@Autowired
private SalesManagementController salesManagementController;
// 项目数据 - 参考适配准真实.sql
private static final String[][] PROJECTS = {
{"1957424785875087363", "奔驰C级销售项目"},
{"1957424785875087364", "奥迪A4L项目"},
{"1957424785875087365", "宝马3系项目"},
{"1957424785875087366", "雷克萨斯RX项目"},
{"1957424785875087367", "保时捷911项目"},
{"1957424785875087368", "威兹曼GT项目"}
};
// 经销商门店数据 - 参考适配准真实.sql按ID名称
private static final String[][] DEALERSHIPS = {
{"1957424710587330562", "广州奔驰4S店"},
{"1957424711560409089", "北京奥迪4S店"},
{"1957424714953601026", "上海宝马4S店"},
{"1957424739267981313", "深圳雷克萨斯4S店"},
{"1957424740000000001", "成都保时捷4S店"},
{"1957424740000000017", "昆明威兹曼4S店"}
};
// 销售角色
private static final String[] ROLES = {"销售顾问", "高级销售顾问", "销售经理", "销售总监"};
// 手机号前缀
private static final String[] PHONE_PREFIXES = {"138", "139", "150", "151", "152", "158", "159", "188", "189"};
// 姓氏
private static final String[] FAMILY_NAMES = {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""};
// 名字
private static final String[] GIVEN_NAMES = {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""};
private final Random random = new Random();
// 用于确保数据分布均匀的计数器
private int dataIndex = 0;
/**
* 每天 02:00 触发
*/
@Scheduled(cron = "0 0 2 * * ?")
public void generateDailySalesData() {
try {
log.info("开始执行销售管理模拟数据任务,时间:{}", LocalDateTime.now());
log.info("数据分布策略:项目({}个),门店({}个),角色({}个),使用智能分布算法",
PROJECTS.length, DEALERSHIPS.length, ROLES.length);
int success = 0;
for (int i = 0; i < 50; i++) {
SalesManagement sales = buildMockSalesManagement();
ResponseEntity<Map<String, Object>> resp = salesManagementController.addSales(sales);
if (resp != null && resp.getStatusCode().is2xxSuccessful()) {
success++;
} else {
log.warn("第{}次插入失败,返回:{}", i + 1, resp == null ? "null" : resp.getStatusCode());
}
}
log.info("销售管理模拟数据任务完成共尝试50次成功 {} 次", success);
log.info("数据分布统计:数据索引={},项目分布更均匀,门店分布更均匀,角色分布更均匀", dataIndex);
} catch (Exception e) {
log.error("销售管理模拟数据任务异常", e);
}
}
private SalesManagement buildMockSalesManagement() {
SalesManagement sales = new SalesManagement();
// 使用更智能的分布策略,确保项目、门店、角色的组合更加均匀
// 通过不同的步长和偏移来避免简单的循环模式
int projectIdx = (dataIndex * 2) % PROJECTS.length;
int dealerIdx = (dataIndex * 3) % DEALERSHIPS.length;
int roleIdx = (dataIndex * 5) % ROLES.length;
String[] project = PROJECTS[projectIdx];
String[] dealer = DEALERSHIPS[dealerIdx];
String role = ROLES[roleIdx];
// 更新统一索引
dataIndex++;
// 创建时间近30天随机时间
LocalDateTime now = LocalDateTime.now();
LocalDateTime createTime = now.minusDays(ThreadLocalRandom.current().nextInt(0, 30))
.minusHours(ThreadLocalRandom.current().nextInt(0, 24))
.minusMinutes(ThreadLocalRandom.current().nextInt(0, 60));
// 基本字段
String salesName = randomChineseName();
sales.setSalesName(salesName);
sales.setLoginAccount(generatePhone()); // 使用手机号作为登录账号
sales.setRecordingCount(ThreadLocalRandom.current().nextInt(5, 50)); // 录音数 5-49
sales.setAvgRecordingDuration(new BigDecimal(String.format("%d.%d",
ThreadLocalRandom.current().nextInt(10, 40), // 平均录音时间 10-39分钟
ThreadLocalRandom.current().nextInt(0, 10))));
sales.setTotalRecordingHours(new BigDecimal(String.format("%d.%d",
ThreadLocalRandom.current().nextInt(5, 30), // 总录音时长 5-29小时
ThreadLocalRandom.current().nextInt(0, 10))));
sales.setProjectId(project[0]);
sales.setProjectName(project[1]);
sales.setDealershipId(dealer[0]);
sales.setDealershipName(dealer[1]);
sales.setRole(role);
sales.setCreateTime(createTime);
// 最近录音时间:创建时间之后
LocalDateTime lastRecordingTime = createTime.plusDays(ThreadLocalRandom.current().nextInt(0, 30))
.plusHours(ThreadLocalRandom.current().nextInt(0, 24))
.plusMinutes(ThreadLocalRandom.current().nextInt(0, 60));
sales.setLastRecordingTime(lastRecordingTime);
// 最后登录时间最近7天
LocalDateTime lastLoginTime = now.minusDays(ThreadLocalRandom.current().nextInt(0, 7))
.minusHours(ThreadLocalRandom.current().nextInt(0, 24))
.minusMinutes(ThreadLocalRandom.current().nextInt(0, 60));
sales.setLastLoginTime(lastLoginTime);
// 最后登录IP
sales.setLastLoginIp(generateIpAddress());
// 状态也使用轮询方式,但保持一定的随机性
sales.setStatus(ThreadLocalRandom.current().nextBoolean());
sales.setUpdateTime(now);
return sales;
}
private String generatePhone() {
String prefix = PHONE_PREFIXES[random.nextInt(PHONE_PREFIXES.length)];
int mid = 100 + random.nextInt(900);
int tail = 1000 + random.nextInt(9000);
return prefix + mid + tail;
}
private String randomChineseName() {
String family = FAMILY_NAMES[random.nextInt(FAMILY_NAMES.length)];
String given = GIVEN_NAMES[random.nextInt(GIVEN_NAMES.length)];
return family + given;
}
private String generateIpAddress() {
return String.format("192.168.%d.%d",
ThreadLocalRandom.current().nextInt(1, 255),
ThreadLocalRandom.current().nextInt(1, 255));
}
}