Files
smartDriveEE/src/main/java/com/rj/scheduler/CustomerProfileMockInsertDataScheduler.java

543 lines
24 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.rj.scheduler;
import com.rj.entity.CustomerProfileAnalysis;
import com.rj.service.biz.impl.CustomerProfileAnalysisServiceImpl;
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.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ThreadLocalRandom;
/**
* 客户画像分析数据定时生成器
* 每天凌晨2:30插入模拟的客户画像分析数据
*
* Author: 李中华 wx: spllzh email(qq): 28668817@qq.com
* Date: 2025/1/3
*/
@Slf4j
@Component
public class CustomerProfileMockInsertDataScheduler {
// @Autowired
// private ICustomerProfileAnalysisService customerProfileAnalysisService;
@Autowired
CustomerProfileAnalysisServiceImpl customerProfileAnalysisService;;
// 项目数据 - 来自适配准真实.sql的project_management JSON
private static final String[][] PROJECTS = {
{"1957424785875087363", "奔驰C级销售项目"},
{"1957424785875087364", "奥迪A4L项目"},
{"1957424785875087365", "宝马3系项目"},
{"1957424785875087366", "雷克萨斯RX项目"},
{"1957424785875087367", "保时捷911项目"},
{"1957424785875087368", "威兹曼GT项目"}
};
// 销售顾问数据 - 来自适配准真实.sql的sales_management JSON
private static final String[][] SALES_PEOPLE = {
{"1957424800000000001", "张明"},
{"1957424800000000002", "李华"},
{"1957424800000000003", "王强"},
{"1957424800000000004", "刘芳"},
{"1957424800000000005", "陈军"},
{"1957424800000000006", "赵敏"},
{"1957424800000000007", "孙丽"},
{"1957424800000000008", "周涛"}
};
// 经销商门店数据 - 来自适配准真实.sql的经销商门店JSON
private static final String[][] DEALERSHIPS = {
{"华南区", "1957424710587330562", "广州奔驰4S店"},
{"华北区", "1957424711560409089", "北京奥迪4S店"},
{"华南区","1957424714953601026", "上海宝马4S店"},
{"华南区","1957424739267981313", "深圳雷克萨斯4S店"},
{"西南区","1957424740000000001", "成都保时捷4S店"},
{"西南区","1957424740000000017", "昆明威兹曼4S店"}
};
// 大区数据 - 确保数据分布均衡
private static final String[] BIG_AREAS = {
"华北区", "华东区", "华南区", "华中区", "西南区", "西北区", "东北区"
};
// 单向开口率数据 - 来自适配准真实.sql的单向开口率JSON
private static final String[][] OPENING_RATES = {
{"1957424800000000001", "沃尔沃M90续航亮点"},
{"1957424800000000002", "lexus RX350智能互联"},
{"1957424800000000003", "别克品牌主张"},
{"1957424800000000004", "lexusRX470刹车问题"}
};
// 客户姓名库
private static final String[] CUSTOMER_NAMES = {
"王小明", "李小红", "张伟", "刘敏", "陈强", "杨丽", "赵刚", "黄娟",
"周杰", "吴芳", "徐磊", "孙静", "马超", "朱琳", "胡军", "郭娜",
"何涛", "罗雪", "高飞", "梁梅", "宋波", "唐丽", "韩强", "冯敏",
"邓伟", "曹静", "彭军", "蒋娜", "薛涛", "方丽", "石强", "顾敏"
};
// 客户电话前缀
private static final String[] PHONE_PREFIXES = {
"138", "139", "150", "151", "152", "158", "159", "188", "189"
};
// 购买类型
private static final String[] PURCHASE_TYPES = {"新购", "置换", "增购"};
// 付款方式
private static final String[] PAYMENT_WAYS = {"贷款", "全款", "分期"};
// 竞品品牌
private static final String[] COMPETITOR_BRANDS = {"奔驰", "宝马", "奥迪", "雷克萨斯", "保时捷", "威兹曼"};
// 购车用途
private static final String[] VEHICLE_USAGES = {"家用", "商用", "代步"};
// 实际驾驶人
private static final String[] PRIMARY_DRIVERS = {"本人", "家人", "其他"};
// 教育水平
private static final String[] EDUCATION_LEVELS = {"高中", "大专", "本科", "硕士", "博士"};
// 家庭结构
private static final String[] FAMILY_COMPOSITIONS = {"单身", "已婚无子女", "已婚有子女", "离异"};
// 职业
private static final String[] JOB_TITLES = {"教师", "工程师", "医生", "律师", "销售", "经理", "公务员", "自由职业"};
// 企业性质
private static final String[] COMPANY_TYPES = {"民营企业", "国企", "外企", "事业单位", "政府机关"};
// 所属行业
private static final String[] INDUSTRY_SECTORS = {"教育", "互联网", "金融", "制造业", "医疗", "房地产", "零售", "服务业"};
// 兴趣点
private static final String[] INTEREST_FOCUSES = {"智能驾驶", "油耗", "空间", "外观", "内饰", "动力", "安全", "环保"};
// 顾虑点
private static final String[] CONCERN_POINTS = {"保养成本", "保值率", "维修费用", "保险费用", "充电便利性", "续航里程"};
// 情感倾向
private static final String[] EMOTION_TENDENCIES = {"积极", "中性", "消极"};
/**
* 每天凌晨2:30执行客户画像数据生成任务
*/
@Scheduled(cron = "0 30 2 * * ?")
public void generateDailyCustomerProfileData() {
try {
log.info("开始执行客户画像数据生成任务...");
// 生成今天的数据
LocalDateTime today = LocalDateTime.now().minusDays(0);
int todayCount = generateCustomerProfileDataForDate(today);
// 生成昨天的数据
LocalDateTime yesterday = LocalDateTime.now().minusDays(1);
int count = generateCustomerProfileDataForDate(yesterday);
// 生成前天天的数据
LocalDateTime yesterday2 = LocalDateTime.now().minusDays(2);
int count2 = generateCustomerProfileDataForDate(yesterday2);
log.info("客户画像数据生成任务执行完成,生成日期:{},生成记录数:{}",
yesterday.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")), count);
log.info("客户画像数据生成任务执行完成,生成日期:{},生成记录数:{}",
today.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")), todayCount);
} catch (Exception e) {
log.error("客户画像数据生成任务执行失败", e);
}
}
/**
* 为指定日期生成客户画像数据
*
* @param date 要生成数据的日期
* @return 生成的记录数
*/
public int generateCustomerProfileDataForDate(LocalDateTime date) {
try {
log.info("开始为日期 {} 生成客户画像数据", date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
// 每天生成20-50条记录确保数据分布均匀
int recordCount = ThreadLocalRandom.current().nextInt(30, 50);
int successCount = 0;
for (int i = 0; i < recordCount; i++) {
try {
CustomerProfileAnalysis analysis = createRandomCustomerProfileAnalysis(date);
boolean result = customerProfileAnalysisService.save(analysis);
if (result) {
successCount++;
log.debug("成功生成第{}条客户画像数据 - 客户:{},门店:{},项目:{}",
i + 1, analysis.getClientName(), analysis.getDealerName(), analysis.getProjectName());
} else {
log.warn("保存第{}条客户画像数据失败", i + 1);
}
} catch (Exception e) {
log.error("生成第{}条客户画像数据失败", i + 1, e);
}
}
log.info("为日期 {} 生成客户画像数据完成,成功生成记录数:{}",
date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")), successCount);
return successCount;
} catch (Exception e) {
log.error("为日期 {} 生成客户画像数据失败", date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")), e);
throw e;
}
}
/**
* 创建随机的客户画像分析数据
*
* @param baseDate 基础日期
* @return 客户画像分析对象
*/
private CustomerProfileAnalysis createRandomCustomerProfileAnalysis(LocalDateTime baseDate) {
CustomerProfileAnalysis analysis = new CustomerProfileAnalysis();
ThreadLocalRandom random = ThreadLocalRandom.current();
// 基础字段
analysis.setProfileAnalysisRecordId("AI_" + System.currentTimeMillis() + "_" + random.nextInt(1000, 9999));
analysis.setAnalysisSceneType(random.nextInt(1, 5)); // 1-4随机
analysis.setRelatedBusinessId("BIZ_" + System.currentTimeMillis() + "_" + random.nextInt(1000, 9999));
// 随机选择经销商、项目、销售顾问、开口率,确保分布均匀
String[] dealership = DEALERSHIPS[random.nextInt(DEALERSHIPS.length)];
String[] project = PROJECTS[random.nextInt(PROJECTS.length)];
String[] salesPerson = SALES_PEOPLE[random.nextInt(SALES_PEOPLE.length)];
String[] openingRate = OPENING_RATES[random.nextInt(OPENING_RATES.length)];
// 设置经销商信息
analysis.setBigArea(dealership[0]);
analysis.setDealerCode(dealership[1]);
analysis.setDealerName(dealership[2]);
// 设置项目信息
analysis.setProjectId(project[0]);
analysis.setProjectName(project[1]);
// 设置销售顾问信息
analysis.setSalesPersonId(salesPerson[0]);
analysis.setSalesPersonName(salesPerson[1]);
// 生成唯一ID
long timestamp = System.currentTimeMillis();
int randomSuffix = random.nextInt(1000, 9999);
analysis.setOpportunityId("OPP_" + timestamp + "_" + randomSuffix);
analysis.setClientId("CLIENT_" + timestamp + "_" + randomSuffix);
// 客户信息
analysis.setClientName(CUSTOMER_NAMES[random.nextInt(CUSTOMER_NAMES.length)]);
analysis.setClientPhone(generateRandomPhone());
// 沟通时间 - 在基础日期的随机时间
LocalDateTime interactionTime = baseDate
.withHour(random.nextInt(9, 18)) // 9-17点
.withMinute(random.nextInt(0, 60))
.withSecond(random.nextInt(0, 60));
analysis.setInteractionDate(interactionTime);
// 客户画像信息字段
analysis.setPurchaseDate(String.valueOf(random.nextInt(1, 91))); // 1-90天
analysis.setPurchaseType(PURCHASE_TYPES[random.nextInt(PURCHASE_TYPES.length)]);
analysis.setPaymentWay(PAYMENT_WAYS[random.nextInt(PAYMENT_WAYS.length)]);
analysis.setCompetitorBrand(COMPETITOR_BRANDS[random.nextInt(COMPETITOR_BRANDS.length)]);
analysis.setVehicleUsage(VEHICLE_USAGES[random.nextInt(VEHICLE_USAGES.length)]);
analysis.setPrimaryDriver(PRIMARY_DRIVERS[random.nextInt(PRIMARY_DRIVERS.length)]);
// 预算范围
int budgetMin = random.nextInt(20, 100);
int budgetMax = budgetMin + random.nextInt(10, 50);
analysis.setBudgetRange(budgetMin + "-" + budgetMax + "");
// 教育水平
analysis.setEducationLevel(EDUCATION_LEVELS[random.nextInt(EDUCATION_LEVELS.length)]);
// 家庭结构
analysis.setFamilyComposition(FAMILY_COMPOSITIONS[random.nextInt(FAMILY_COMPOSITIONS.length)]);
// 月收入
int incomeMin = random.nextInt(5, 30);
int incomeMax = incomeMin + random.nextInt(5, 20);
analysis.setMonthlyIncome(incomeMin + "-" + incomeMax + "");
// 职业信息
analysis.setJobTitle(JOB_TITLES[random.nextInt(JOB_TITLES.length)]);
analysis.setCompanyType(COMPANY_TYPES[random.nextInt(COMPANY_TYPES.length)]);
analysis.setIndustrySector(INDUSTRY_SECTORS[random.nextInt(INDUSTRY_SECTORS.length)]);
// 兴趣和顾虑
analysis.setInterestFocus(INTEREST_FOCUSES[random.nextInt(INTEREST_FOCUSES.length)]);
analysis.setConcernPoint(CONCERN_POINTS[random.nextInt(CONCERN_POINTS.length)]);
analysis.setPurchaseQualification(random.nextBoolean() ? "" : "");
// 其他信息 - 利用新字段生成更详细的备注
analysis.setNotes(String.format("客户在%s门店咨询%s项目销售顾问%s接待关注点%s购车意向明确",
dealership[1], project[1], salesPerson[1], openingRate[1]));
analysis.setCurrentBrand(COMPETITOR_BRANDS[random.nextInt(COMPETITOR_BRANDS.length)]);
analysis.setHomeAddress(generateRandomAddress());
analysis.setFamilySize(String.valueOf(random.nextInt(1, 6))); // 1-5人
analysis.setHobby("运动、旅游、音乐");
// 实体情感分析字段 - 随机生成情感倾向
generateEntityEmotions(analysis, random);
// 系统字段
LocalDateTime now = LocalDateTime.now();
analysis.setCreatedAt(now);
analysis.setUpdatedAt(now);
analysis.setRecordVersion(0);
analysis.setIsDeleted(0);
analysis.setCreateSqlby("sched"); // 限制在8个字符以内
analysis.setUpdateSqlby("sched"); // 限制在8个字符以内
// 数据验证
validateCustomerProfileAnalysis(analysis);
// 调试日志 - 输出生成的数据信息
log.debug("生成客户画像数据完成 - ID: {}, 客户: {}, 门店: {}, 项目: {}, 销售顾问: {}",
analysis.getId(), analysis.getClientName(), analysis.getDealerName(),
analysis.getProjectName(), analysis.getSalesPersonName());
return analysis;
}
/**
* 生成实体情感分析数据
*/
private void generateEntityEmotions(CustomerProfileAnalysis analysis, ThreadLocalRandom random) {
String[] emotions = EMOTION_TENDENCIES;
String[] reasons = {"客户对此方面表示满意", "客户对此方面持中性态度", "客户对此方面存在疑虑"};
// 品牌情感
int brandEmotion = random.nextInt(emotions.length);
analysis.setEntityBrand(emotions[brandEmotion]);
analysis.setEntityBrandReason(reasons[brandEmotion]);
// 外观设计情感
int designEmotion = random.nextInt(emotions.length);
analysis.setEntityDesign(emotions[designEmotion]);
analysis.setEntityDesignReason(reasons[designEmotion]);
// 颜色情感
int colorEmotion = random.nextInt(emotions.length);
analysis.setEntityColor(emotions[colorEmotion]);
analysis.setEntityColorReason(reasons[colorEmotion]);
// 尺寸情感
int sizeEmotion = random.nextInt(emotions.length);
analysis.setEntitySize(emotions[sizeEmotion]);
analysis.setEntitySizeReason(reasons[sizeEmotion]);
// 空间情感
int spaceEmotion = random.nextInt(emotions.length);
analysis.setEntitySpace(emotions[spaceEmotion]);
analysis.setEntitySpaceReason(reasons[spaceEmotion]);
// 内饰情感
int interiorEmotion = random.nextInt(emotions.length);
analysis.setEntityInterior(emotions[interiorEmotion]);
analysis.setEntityInteriorReason(reasons[interiorEmotion]);
// 音响情感
int audioEmotion = random.nextInt(emotions.length);
analysis.setEntityAudio(emotions[audioEmotion]);
analysis.setEntityAudioReason(reasons[audioEmotion]);
// 车机情感
int ivinfoEmotion = random.nextInt(emotions.length);
analysis.setEntityIvinfo(emotions[ivinfoEmotion]);
analysis.setEntityIvinfoReason(reasons[ivinfoEmotion]);
// 智驾情感
int fsdEmotion = random.nextInt(emotions.length);
analysis.setEntityFsd(emotions[fsdEmotion]);
analysis.setEntityFsdReason(reasons[fsdEmotion]);
// 续航情感
int mileageEmotion = random.nextInt(emotions.length);
analysis.setEntityMileage(emotions[mileageEmotion]);
analysis.setEntityMileageReason(reasons[mileageEmotion]);
// 安全情感
int safetyEmotion = random.nextInt(emotions.length);
analysis.setEntitySafety(emotions[safetyEmotion]);
analysis.setEntitySafetyReason(reasons[safetyEmotion]);
// 环保情感
int ecoEmotion = random.nextInt(emotions.length);
analysis.setEntityEco(emotions[ecoEmotion]);
analysis.setEntityEcoReason(reasons[ecoEmotion]);
// 绿牌/路权情感
int liscenseEmotion = random.nextInt(emotions.length);
analysis.setEntityLiscense(emotions[liscenseEmotion]);
analysis.setEntityLiscenseReason(reasons[liscenseEmotion]);
// 价格情感
int priceEmotion = random.nextInt(emotions.length);
analysis.setEntityPrice(emotions[priceEmotion]);
analysis.setEntityPriceReason(reasons[priceEmotion]);
// 购车权益情感
int benefitEmotion = random.nextInt(emotions.length);
analysis.setEntityBenefit(emotions[benefitEmotion]);
analysis.setEntityBenefitReason(reasons[benefitEmotion]);
// 用车成本情感
int costEmotion = random.nextInt(emotions.length);
analysis.setEntityCost(emotions[costEmotion]);
analysis.setEntityCostReason(reasons[costEmotion]);
// 性价比情感
int valueEmotion = random.nextInt(emotions.length);
analysis.setEntityValue(emotions[valueEmotion]);
analysis.setEntityValueReason(reasons[valueEmotion]);
// 动力情感
int powerEmotion = random.nextInt(emotions.length);
analysis.setEntityPower(emotions[powerEmotion]);
analysis.setEntityPowerReason(reasons[powerEmotion]);
// 操控情感
int controlEmotion = random.nextInt(emotions.length);
analysis.setEntityControl(emotions[controlEmotion]);
analysis.setEntityControlReason(reasons[controlEmotion]);
// 置换政策情感
int tradeinEmotion = random.nextInt(emotions.length);
analysis.setEntityTradein(emotions[tradeinEmotion]);
analysis.setEntityTradeinReason(reasons[tradeinEmotion]);
// 金融方案情感
int financeEmotion = random.nextInt(emotions.length);
analysis.setEntityFinance(emotions[financeEmotion]);
analysis.setEntityFinanceReason(reasons[financeEmotion]);
// 质保情感
int warrantyEmotion = random.nextInt(emotions.length);
analysis.setEntityWarranty(emotions[warrantyEmotion]);
analysis.setEntityWarrantyReason(reasons[warrantyEmotion]);
// 交付时间情感
int deliveryEmotion = random.nextInt(emotions.length);
analysis.setEntityDelivery(emotions[deliveryEmotion]);
analysis.setEntityDeliveryReason(reasons[deliveryEmotion]);
}
/**
* 验证客户画像分析数据的完整性
*
* @param analysis 客户画像分析对象
*/
private void validateCustomerProfileAnalysis(CustomerProfileAnalysis analysis) {
if (analysis == null) {
throw new IllegalArgumentException("客户画像分析对象不能为空");
}
// 验证必填字段
if (analysis.getProfileAnalysisRecordId() == null || analysis.getProfileAnalysisRecordId().trim().isEmpty()) {
throw new IllegalArgumentException("AI分析记录ID不能为空");
}
if (analysis.getDealerCode() == null || analysis.getDealerCode().trim().isEmpty()) {
throw new IllegalArgumentException("经销商编码不能为空");
}
if (analysis.getDealerName() == null || analysis.getDealerName().trim().isEmpty()) {
throw new IllegalArgumentException("经销商门店名称不能为空");
}
if (analysis.getProjectId() == null || analysis.getProjectId().trim().isEmpty()) {
throw new IllegalArgumentException("项目ID不能为空");
}
if (analysis.getProjectName() == null || analysis.getProjectName().trim().isEmpty()) {
throw new IllegalArgumentException("项目名称不能为空");
}
if (analysis.getSalesPersonId() == null || analysis.getSalesPersonId().trim().isEmpty()) {
throw new IllegalArgumentException("销售顾问ID不能为空");
}
if (analysis.getSalesPersonName() == null || analysis.getSalesPersonName().trim().isEmpty()) {
throw new IllegalArgumentException("销售顾问姓名不能为空");
}
if (analysis.getClientName() == null || analysis.getClientName().trim().isEmpty()) {
throw new IllegalArgumentException("客户姓名不能为空");
}
if (analysis.getClientPhone() == null || analysis.getClientPhone().trim().isEmpty()) {
throw new IllegalArgumentException("客户电话不能为空");
}
if (analysis.getInteractionDate() == null) {
throw new IllegalArgumentException("沟通时间不能为空");
}
log.debug("客户画像分析数据验证通过 - 客户:{},门店:{},项目:{},销售顾问:{}",
analysis.getClientName(), analysis.getDealerName(),
analysis.getProjectName(), analysis.getSalesPersonName());
}
/**
* 生成随机手机号
*/
private String generateRandomPhone() {
ThreadLocalRandom random = ThreadLocalRandom.current();
String prefix = PHONE_PREFIXES[random.nextInt(PHONE_PREFIXES.length)];
StringBuilder phone = new StringBuilder(prefix);
for (int i = 0; i < 8; i++) {
phone.append(random.nextInt(0, 10));
}
return phone.toString();
}
/**
* 生成随机地址
*/
private String generateRandomAddress() {
String[] cities = {"北京市", "上海市", "广州市", "深圳市", "成都市", "杭州市", "南京市", "武汉市"};
String[] districts = {"朝阳区", "海淀区", "西城区", "东城区", "丰台区", "石景山区", "通州区", "昌平区"};
ThreadLocalRandom random = ThreadLocalRandom.current();
String city = cities[random.nextInt(cities.length)];
String district = districts[random.nextInt(districts.length)];
String street = "某某街道" + random.nextInt(1, 100) + "";
return city + district + street;
}
/**
* 手动触发数据生成任务(用于测试或补录数据)
*
* @param date 要生成数据的日期
* @return 生成的记录数
*/
public int manualGenerateData(LocalDateTime date) {
try {
log.info("手动执行客户画像数据生成任务,生成日期:{}", date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
int count = generateCustomerProfileDataForDate(date);
log.info("手动客户画像数据生成任务执行完成,生成日期:{},生成记录数:{}",
date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")), count);
return count;
} catch (Exception e) {
log.error("手动客户画像数据生成任务执行失败,生成日期:{}", date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")), e);
throw e;
}
}
}