修改统计数据显示问题
This commit is contained in:
parent
61d640da2b
commit
a5264f2ab8
|
|
@ -63,4 +63,7 @@ public class CustomerStatisticsData implements Serializable {
|
||||||
|
|
||||||
private int sortNo;
|
private int sortNo;
|
||||||
|
|
||||||
|
//是否是隐藏数据
|
||||||
|
private Boolean hiddenFlag = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,17 +41,53 @@ public class DepartmentStatisticsData implements Serializable {
|
||||||
//非及时单占比(当日)
|
//非及时单占比(当日)
|
||||||
private BigDecimal dailyNonTimelyOrderRatio;
|
private BigDecimal dailyNonTimelyOrderRatio;
|
||||||
|
|
||||||
/* //即时单
|
//即时单
|
||||||
private Integer dailyTimelyCount;
|
private Integer dailyTimelyCount;
|
||||||
//非即时单
|
//非即时单
|
||||||
private Integer dailyNonTimelyCount;*/
|
private Integer dailyNonTimelyCount;
|
||||||
|
|
||||||
//管理员分配(当日)
|
//管理员分配(当日)
|
||||||
private Integer managerAccepted;
|
private Integer managerAccepted;
|
||||||
/**
|
|
||||||
* 部门路径(如:苏州曼普/销售部/一组 或 苏州曼普/销售部/一组/盛宇婷)
|
//新增:家长出单率(当日)
|
||||||
*/
|
private BigDecimal dailyParentOrderRate;
|
||||||
|
//新增:学生出单率(当日)
|
||||||
|
private BigDecimal dailyStudentOrderRate;
|
||||||
|
|
||||||
|
//如果是四级的 默认是个人 前端显示时也是默认显示个人
|
||||||
|
private Boolean personFlag;
|
||||||
|
|
||||||
private String departmentPath;
|
private String departmentPath;
|
||||||
|
//公司名称
|
||||||
|
private String corpName;
|
||||||
|
//部门名称
|
||||||
|
private String departmentName;
|
||||||
|
//组名称
|
||||||
|
private String groupName;
|
||||||
|
//个人名称
|
||||||
|
private String personName;
|
||||||
|
|
||||||
|
|
||||||
|
// ========== 新增:家长/学生出单率统计(当日) ==========
|
||||||
|
/**
|
||||||
|
* 家长出单数(当日成交)- 满足Q列=当日 AND T列=已成交及时单9元+
|
||||||
|
*/
|
||||||
|
private int parentDailyOrderCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 家长总数(当日进粉)- 用于出单率分母
|
||||||
|
*/
|
||||||
|
private int parentDailyCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 学生出单数(当日成交)- 满足Q列=当日 AND T列=已成交及时单9元+
|
||||||
|
*/
|
||||||
|
private int studentDailyOrderCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 学生总数(当日进粉)- 用于出单率分母
|
||||||
|
*/
|
||||||
|
private int studentDailyCount = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建时间
|
* 创建时间
|
||||||
|
|
|
||||||
|
|
@ -55,5 +55,26 @@ public class DepartmentStatisticsAccumulator {
|
||||||
* "由管理员XXX分配"
|
* "由管理员XXX分配"
|
||||||
* */
|
* */
|
||||||
private int managerAcceptCount = 0;
|
private int managerAcceptCount = 0;
|
||||||
|
|
||||||
|
// ========== 新增:家长/学生出单率统计(当日) ==========
|
||||||
|
/**
|
||||||
|
* 家长出单数(当日成交)- 满足Q列=当日 AND T列=已成交及时单9元+
|
||||||
|
*/
|
||||||
|
private int parentDailyOrderCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 家长总数(当日进粉)- 用于出单率分母
|
||||||
|
*/
|
||||||
|
private int parentDailyCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 学生出单数(当日成交)- 满足Q列=当日 AND T列=已成交及时单9元+
|
||||||
|
*/
|
||||||
|
private int studentDailyOrderCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 学生总数(当日进粉)- 用于出单率分母
|
||||||
|
*/
|
||||||
|
private int studentDailyCount = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -451,22 +451,58 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提取组级别路径和员工级别路径
|
// 先计算所有条件,避免重复判断
|
||||||
// 例如:苏州曼普/销售部/二组/盛宇婷
|
boolean isQValueMatch = matchesQValue(data, targetDate);
|
||||||
// 组级别:苏州曼普/销售部/二组
|
boolean isDateMatch = matchesDate(data, targetDate);
|
||||||
// 员工级别:苏州曼普/销售部/二组/盛宇婷
|
boolean isSourceMatch = matchesSource(data);
|
||||||
|
boolean isTimelyOrder = isTimelyOrder(data);
|
||||||
|
String customerAttr = data.getTagGroup6();
|
||||||
|
boolean isParent = customerAttr != null && !customerAttr.trim().isEmpty() && customerAttr.contains("家长");
|
||||||
|
boolean isStudent = customerAttr != null && !customerAttr.trim().isEmpty() && customerAttr.contains("学生");
|
||||||
|
|
||||||
|
// 提取各级路径
|
||||||
String[] pathParts = departmentPath.split("/");
|
String[] pathParts = departmentPath.split("/");
|
||||||
|
|
||||||
// 处理组级别统计(前3级)
|
// 构建各级路径并累加统计(只遍历一次,条件已预先计算)
|
||||||
if (pathParts.length >= 3) {
|
StringBuilder pathBuilder = new StringBuilder();
|
||||||
String groupPath = pathParts[0] + "/" + pathParts[1] + "/" + pathParts[2];
|
for (int i = 0; i < pathParts.length; i++) {
|
||||||
processDepartmentRecord(data, targetDate, accumulator.getDepartmentStats(groupPath));
|
if (i > 0) {
|
||||||
|
pathBuilder.append("/");
|
||||||
|
}
|
||||||
|
pathBuilder.append(pathParts[i]);
|
||||||
|
String currentPath = pathBuilder.toString();
|
||||||
|
DepartmentStatisticsAccumulator.DepartmentStats stats = accumulator.getDepartmentStats(currentPath);
|
||||||
|
|
||||||
|
// 累加统计(条件已预先计算,直接使用)
|
||||||
|
if (isQValueMatch) {
|
||||||
|
stats.setTotalOrderCount(stats.getTotalOrderCount() + 1);
|
||||||
|
if (isTimelyOrder) {
|
||||||
|
stats.setTimelyOrderCount(stats.getTimelyOrderCount() + 1);
|
||||||
|
} else {
|
||||||
|
stats.setNonTimelyOrderCount(stats.getNonTimelyOrderCount() + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理员工级别统计(完整路径)
|
if (isDateMatch) {
|
||||||
if (pathParts.length >= 4) {
|
if (isSourceMatch) {
|
||||||
processDepartmentRecord(data, targetDate, accumulator.getDepartmentStats(departmentPath));
|
stats.setTotalAcceptCount(stats.getTotalAcceptCount() + 1);
|
||||||
|
if (isParent) {
|
||||||
|
stats.setParentDailyCount(stats.getParentDailyCount() + 1);
|
||||||
|
if (isQValueMatch && isTimelyOrder) {
|
||||||
|
stats.setParentDailyOrderCount(stats.getParentDailyOrderCount() + 1);
|
||||||
}
|
}
|
||||||
|
} else if (isStudent) {
|
||||||
|
stats.setStudentDailyCount(stats.getStudentDailyCount() + 1);
|
||||||
|
if (isQValueMatch && isTimelyOrder) {
|
||||||
|
stats.setStudentDailyOrderCount(stats.getStudentDailyOrderCount() + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stats.setManagerAcceptCount(stats.getManagerAcceptCount() + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否还有下一页
|
// 检查是否还有下一页
|
||||||
|
|
@ -530,39 +566,73 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean matchesQValue(CustomerExportData data,Date curDate) {
|
private boolean matchesQValue(CustomerExportData data,Date curDate) {
|
||||||
String orderDate = data.getTagGroup4(); // Q列:成交日期,格式:2.3
|
String orderDate = data.getTagGroup4(); // Q列:成交日期
|
||||||
|
|
||||||
// 基础校验
|
// 支持多种格式:
|
||||||
|
// 1. 2026/2/24周二 或 2026/2/24 周一
|
||||||
|
// 2. 1.7-小雅初中公众号K 或 1.7
|
||||||
|
// 3. 2.3
|
||||||
if (orderDate == null || orderDate.trim().isEmpty()) {
|
if (orderDate == null || orderDate.trim().isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//由于可能是多个逗号拼成的多个日期 任意一个日期符合都可以
|
// 由于可能是多个逗号拼成的多个日期,任意一个日期符合都可以
|
||||||
String[] dates = orderDate.trim().split(",");
|
String[] dates = orderDate.trim().split(",");
|
||||||
// 解析订单日期:2.3 -> [2, 3]
|
String lastDateStr = dates[dates.length - 1].trim();
|
||||||
String[] parts = dates[dates.length - 1].trim().split("[.\\-/]");
|
|
||||||
if (parts.length < 2) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int orderMonth = Integer.parseInt(parts[0].trim());
|
|
||||||
int orderDay = Integer.parseInt(parts[1].trim());
|
|
||||||
|
|
||||||
// 构建成交日期(基于addTime的年份)
|
|
||||||
Calendar orderCal = Calendar.getInstance();
|
Calendar orderCal = Calendar.getInstance();
|
||||||
orderCal.setTime(curDate);
|
orderCal.setTime(curDate);
|
||||||
orderCal.set(Calendar.MONTH, orderMonth - 1);
|
|
||||||
orderCal.set(Calendar.DAY_OF_MONTH, orderDay);
|
|
||||||
orderCal.set(Calendar.HOUR_OF_DAY, 0);
|
orderCal.set(Calendar.HOUR_OF_DAY, 0);
|
||||||
orderCal.set(Calendar.MINUTE, 0);
|
orderCal.set(Calendar.MINUTE, 0);
|
||||||
orderCal.set(Calendar.SECOND, 0);
|
orderCal.set(Calendar.SECOND, 0);
|
||||||
orderCal.set(Calendar.MILLISECOND, 0);
|
orderCal.set(Calendar.MILLISECOND, 0);
|
||||||
|
|
||||||
// 跨年处理:如果成交日期早于添加日期,年份+1
|
boolean parsed = false;
|
||||||
if (orderCal.getTime().before(curDate)) {
|
|
||||||
|
// 格式1: 2026/2/24周二 或 2026/2/24 周一 (完整日期格式)
|
||||||
|
// 正则匹配: 年份/月份/日期
|
||||||
|
java.util.regex.Pattern fullDatePattern = java.util.regex.Pattern.compile("(\\d{4})[/\\-](\\d{1,2})[/\\-](\\d{1,2})");
|
||||||
|
java.util.regex.Matcher fullDateMatcher = fullDatePattern.matcher(lastDateStr);
|
||||||
|
if (fullDateMatcher.find()) {
|
||||||
|
int year = Integer.parseInt(fullDateMatcher.group(1));
|
||||||
|
int month = Integer.parseInt(fullDateMatcher.group(2));
|
||||||
|
int day = Integer.parseInt(fullDateMatcher.group(3));
|
||||||
|
orderCal.set(Calendar.YEAR, year);
|
||||||
|
orderCal.set(Calendar.MONTH, month - 1);
|
||||||
|
orderCal.set(Calendar.DAY_OF_MONTH, day);
|
||||||
|
parsed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式2和3: 1.7-小雅初中公众号K 或 2.3 (月.日格式)
|
||||||
|
if (!parsed) {
|
||||||
|
// 提取开头的月.日格式,忽略后面的文字
|
||||||
|
java.util.regex.Pattern monthDayPattern = java.util.regex.Pattern.compile("^(\\d{1,2})[.\\-/](\\d{1,2})");
|
||||||
|
java.util.regex.Matcher monthDayMatcher = monthDayPattern.matcher(lastDateStr);
|
||||||
|
if (monthDayMatcher.find()) {
|
||||||
|
int month = Integer.parseInt(monthDayMatcher.group(1));
|
||||||
|
int day = Integer.parseInt(monthDayMatcher.group(2));
|
||||||
|
orderCal.set(Calendar.MONTH, month - 1);
|
||||||
|
orderCal.set(Calendar.DAY_OF_MONTH, day);
|
||||||
|
// 跨年处理:如果成交日期早于当前日期,年份+1
|
||||||
|
Calendar tempCal = Calendar.getInstance();
|
||||||
|
tempCal.setTime(curDate);
|
||||||
|
tempCal.set(Calendar.MONTH, month - 1);
|
||||||
|
tempCal.set(Calendar.DAY_OF_MONTH, day);
|
||||||
|
tempCal.set(Calendar.HOUR_OF_DAY, 0);
|
||||||
|
tempCal.set(Calendar.MINUTE, 0);
|
||||||
|
tempCal.set(Calendar.SECOND, 0);
|
||||||
|
tempCal.set(Calendar.MILLISECOND, 0);
|
||||||
|
if (tempCal.getTime().before(curDate)) {
|
||||||
orderCal.add(Calendar.YEAR, 1);
|
orderCal.add(Calendar.YEAR, 1);
|
||||||
}
|
}
|
||||||
|
parsed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parsed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// 标准化目标日期(清除时分秒)
|
// 标准化目标日期(清除时分秒)
|
||||||
Calendar targetCal = Calendar.getInstance();
|
Calendar targetCal = Calendar.getInstance();
|
||||||
|
|
@ -572,15 +642,11 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
targetCal.set(Calendar.SECOND, 0);
|
targetCal.set(Calendar.SECOND, 0);
|
||||||
targetCal.set(Calendar.MILLISECOND, 0);
|
targetCal.set(Calendar.MILLISECOND, 0);
|
||||||
|
|
||||||
boolean b = orderCal.getTimeInMillis() == targetCal.getTimeInMillis();
|
return orderCal.getTimeInMillis() == targetCal.getTimeInMillis();
|
||||||
if (b) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean matchOrderCompleted(CustomerExportData data,Date curDate) {
|
private boolean matchOrderCompleted(CustomerExportData data,Date curDate) {
|
||||||
|
|
@ -591,6 +657,16 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isTimelyOrder(CustomerExportData data) {
|
||||||
|
String orderStatus = data.getTagGroup7();
|
||||||
|
if (orderStatus == null || orderStatus.trim().isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String[] split = orderStatus.split(",");
|
||||||
|
String statusInfo = split[split.length - 1];
|
||||||
|
return statusInfo.contains("已成交及时单9元+");
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 处理单条数据记录,累加到所有相关组的统计中
|
* 处理单条数据记录,累加到所有相关组的统计中
|
||||||
*/
|
*/
|
||||||
|
|
@ -674,11 +750,23 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
//todo 存在订单未完成 但是有标签的场景
|
//todo 存在订单未完成 但是有标签的场景
|
||||||
stats.setParentOrderCount(stats.getParentOrderCount() + 1);
|
stats.setParentOrderCount(stats.getParentOrderCount() + 1);
|
||||||
|
|
||||||
|
// 新增:出单率统计(当日)
|
||||||
|
stats.setParentDailyCount(stats.getParentDailyCount() + 1);
|
||||||
|
if (matchesQValue(data, date) && isTimelyOrder(data)) {
|
||||||
|
stats.setParentDailyOrderCount(stats.getParentDailyOrderCount() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
} else if (customerAttr.contains("学生")) {
|
} else if (customerAttr.contains("学生")) {
|
||||||
stats.setStudentCount(stats.getStudentCount() + 1);
|
stats.setStudentCount(stats.getStudentCount() + 1);
|
||||||
|
|
||||||
stats.setStudentOrderCount(stats.getStudentOrderCount() + 1);
|
stats.setStudentOrderCount(stats.getStudentOrderCount() + 1);
|
||||||
|
|
||||||
|
// 新增:N组学生出单率统计(当日)
|
||||||
|
stats.setStudentDailyCount(stats.getStudentDailyCount() + 1);
|
||||||
|
if (matchesQValue(data, date) && isTimelyOrder(data)) {
|
||||||
|
stats.setStudentDailyOrderCount(stats.getStudentDailyOrderCount() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
stats.setUnknownAttrCount(stats.getUnknownAttrCount() + 1);
|
stats.setUnknownAttrCount(stats.getUnknownAttrCount() + 1);
|
||||||
}
|
}
|
||||||
|
|
@ -773,10 +861,12 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
// 4. 及时单占比
|
// 4. 及时单占比
|
||||||
String timelyRate = calculateRate(stats.getTimelyOrderCount(), stats.getCustomerCount());
|
String timelyRate = calculateRate(stats.getTimelyOrderCount(), stats.getCustomerCount());
|
||||||
setIndicatorValue(corpId,indicatorMap,curDate, "及时单占比(当日)", groupName, timelyRate,(10*sortNo++));
|
setIndicatorValue(corpId,indicatorMap,curDate, "及时单占比(当日)", groupName, timelyRate,(10*sortNo++));
|
||||||
|
setIndicatorValue(corpId,indicatorMap,curDate, "及时单数量(当日)", groupName, String.valueOf(stats.getTimelyOrderCount()),(10*sortNo++),true);
|
||||||
|
|
||||||
// 5. 非及时单占比
|
// 5. 非及时单占比
|
||||||
String nonTimelyRate = calculateRate(stats.getNonTimelyOrderCount(), stats.getCustomerCount());
|
String nonTimelyRate = calculateRate(stats.getNonTimelyOrderCount(), stats.getCustomerCount());
|
||||||
setIndicatorValue(corpId,indicatorMap,curDate, "非及时单占比(当日)", groupName, nonTimelyRate,(10*sortNo++));
|
setIndicatorValue(corpId,indicatorMap,curDate, "非及时单占比(当日)", groupName, nonTimelyRate,(10*sortNo++));
|
||||||
|
setIndicatorValue(corpId,indicatorMap,curDate, "非及时单数量(当日)", groupName, String.valueOf(stats.getNonTimelyOrderCount()),(10*sortNo++),true);
|
||||||
|
|
||||||
// 6. 客户属性数量
|
// 6. 客户属性数量
|
||||||
setIndicatorValue(corpId,indicatorMap,curDate, "客户属性数量(当日)", groupName, String.valueOf(stats.getTotalCustomerAttr()),(10*sortNo++));
|
setIndicatorValue(corpId,indicatorMap,curDate, "客户属性数量(当日)", groupName, String.valueOf(stats.getTotalCustomerAttr()),(10*sortNo++));
|
||||||
|
|
@ -784,14 +874,17 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
// 7. 家长占比
|
// 7. 家长占比
|
||||||
String parentRate = calculateRate(stats.getParentCount(), stats.getTotalCustomerAttr());
|
String parentRate = calculateRate(stats.getParentCount(), stats.getTotalCustomerAttr());
|
||||||
setIndicatorValue(corpId,indicatorMap,curDate, "家长占比(当日)", groupName, parentRate,(10*sortNo++));
|
setIndicatorValue(corpId,indicatorMap,curDate, "家长占比(当日)", groupName, parentRate,(10*sortNo++));
|
||||||
|
setIndicatorValue(corpId,indicatorMap,curDate, "家长数量(当日)", groupName, String.valueOf(stats.getParentCount()),(10*sortNo++),true);
|
||||||
|
|
||||||
// 8. 学生占比
|
// 8. 学生占比
|
||||||
String studentRate = calculateRate(stats.getStudentCount(), stats.getTotalCustomerAttr());
|
String studentRate = calculateRate(stats.getStudentCount(), stats.getTotalCustomerAttr());
|
||||||
setIndicatorValue(corpId,indicatorMap,curDate, "学生占比(当日)", groupName, studentRate,(10*sortNo++));
|
setIndicatorValue(corpId,indicatorMap,curDate, "学生占比(当日)", groupName, studentRate,(10*sortNo++));
|
||||||
|
setIndicatorValue(corpId,indicatorMap,curDate, "学生数量(当日)", groupName, String.valueOf(stats.getStudentCount()),(10*sortNo++),true);
|
||||||
|
|
||||||
// 9. 未知占比
|
// 9. 未知占比
|
||||||
String unknownRate = calculateRate(stats.getUnknownAttrCount(), stats.getTotalCustomerAttr());
|
String unknownRate = calculateRate(stats.getUnknownAttrCount(), stats.getTotalCustomerAttr());
|
||||||
setIndicatorValue(corpId,indicatorMap,curDate, "未知占比(当日)", groupName, unknownRate,(10*sortNo++));
|
setIndicatorValue(corpId,indicatorMap,curDate, "未知占比(当日)", groupName, unknownRate,(10*sortNo++));
|
||||||
|
setIndicatorValue(corpId,indicatorMap,curDate, "未知数量(当日)", groupName, String.valueOf(stats.getUnknownAttrCount()),(10*sortNo++),true);
|
||||||
|
|
||||||
// 10. 意向度数量
|
// 10. 意向度数量
|
||||||
setIndicatorValue(corpId,indicatorMap,curDate, "意向度数量(当日)", groupName, String.valueOf(stats.getTotalIntention()),(10*sortNo++));
|
setIndicatorValue(corpId,indicatorMap,curDate, "意向度数量(当日)", groupName, String.valueOf(stats.getTotalIntention()),(10*sortNo++));
|
||||||
|
|
@ -799,18 +892,22 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
// 11. 主动报价占比
|
// 11. 主动报价占比
|
||||||
String activeQuoteRate = calculateRate(stats.getActiveQuoteCount(), stats.getTotalIntention());
|
String activeQuoteRate = calculateRate(stats.getActiveQuoteCount(), stats.getTotalIntention());
|
||||||
setIndicatorValue(corpId,indicatorMap,curDate, "主动报价占比(当日)", groupName, activeQuoteRate,(10*sortNo++));
|
setIndicatorValue(corpId,indicatorMap,curDate, "主动报价占比(当日)", groupName, activeQuoteRate,(10*sortNo++));
|
||||||
|
setIndicatorValue(corpId,indicatorMap,curDate, "主动报价数量(当日)", groupName, String.valueOf(stats.getActiveQuoteCount()),(10*sortNo++),true);
|
||||||
|
|
||||||
// 12. 被动报价占比
|
// 12. 被动报价占比
|
||||||
String passiveQuoteRate = calculateRate(stats.getPassiveQuoteCount(), stats.getTotalIntention());
|
String passiveQuoteRate = calculateRate(stats.getPassiveQuoteCount(), stats.getTotalIntention());
|
||||||
setIndicatorValue(corpId,indicatorMap,curDate, "被动报价占比(当日)", groupName, passiveQuoteRate,(10*sortNo++));
|
setIndicatorValue(corpId,indicatorMap,curDate, "被动报价占比(当日)", groupName, passiveQuoteRate,(10*sortNo++));
|
||||||
|
setIndicatorValue(corpId,indicatorMap,curDate, "被动报价数量(当日)", groupName, String.valueOf(stats.getPassiveQuoteCount()),(10*sortNo++),true);
|
||||||
|
|
||||||
// 13. 未开口报价占比
|
// 13. 未开口报价占比
|
||||||
String noQuoteRate = calculateRate(stats.getNoQuoteCount(), stats.getTotalIntention());
|
String noQuoteRate = calculateRate(stats.getNoQuoteCount(), stats.getTotalIntention());
|
||||||
setIndicatorValue(corpId,indicatorMap,curDate, "未开口报价占比(当日)", groupName, noQuoteRate,(10*sortNo++));
|
setIndicatorValue(corpId,indicatorMap,curDate, "未开口报价占比(当日)", groupName, noQuoteRate,(10*sortNo++));
|
||||||
|
setIndicatorValue(corpId,indicatorMap,curDate, "未开口报价数量(当日)", groupName, String.valueOf(stats.getNoQuoteCount()),(10*sortNo++),true);
|
||||||
|
|
||||||
// 14. 已删除报价占比
|
// 14. 已删除报价占比
|
||||||
String deletedQuoteRate = calculateRate(stats.getDeletedQuoteCount(), stats.getTotalIntention());
|
String deletedQuoteRate = calculateRate(stats.getDeletedQuoteCount(), stats.getTotalIntention());
|
||||||
setIndicatorValue(corpId,indicatorMap,curDate, "已删除报价占比(当日)", groupName, deletedQuoteRate,(10*sortNo++));
|
setIndicatorValue(corpId,indicatorMap,curDate, "已删除报价占比(当日)", groupName, deletedQuoteRate,(10*sortNo++));
|
||||||
|
setIndicatorValue(corpId,indicatorMap,curDate, "已删除数量(当日)", groupName, String.valueOf(stats.getDeletedQuoteCount()),(10*sortNo++),true);
|
||||||
|
|
||||||
// 15. 年级数量
|
// 15. 年级数量
|
||||||
setIndicatorValue(corpId,indicatorMap,curDate, "年级数量(当日)", groupName, String.valueOf(stats.getTotalGrade()),(10*sortNo++));
|
setIndicatorValue(corpId,indicatorMap,curDate, "年级数量(当日)", groupName, String.valueOf(stats.getTotalGrade()),(10*sortNo++));
|
||||||
|
|
@ -818,23 +915,37 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
// 16. 小学占比
|
// 16. 小学占比
|
||||||
String primaryRate = calculateRate(stats.getPrimaryCount(), stats.getTotalGrade());
|
String primaryRate = calculateRate(stats.getPrimaryCount(), stats.getTotalGrade());
|
||||||
setIndicatorValue(corpId,indicatorMap,curDate, "小学占比(当日)", groupName, primaryRate,(10*sortNo++));
|
setIndicatorValue(corpId,indicatorMap,curDate, "小学占比(当日)", groupName, primaryRate,(10*sortNo++));
|
||||||
|
setIndicatorValue(corpId,indicatorMap,curDate, "小学数量(当日)", groupName, String.valueOf(stats.getPrimaryCount()),(10*sortNo++),true);
|
||||||
|
|
||||||
// 17. 初中占比
|
// 17. 初中占比
|
||||||
String middleRate = calculateRate(stats.getMiddleCount(), stats.getTotalGrade());
|
String middleRate = calculateRate(stats.getMiddleCount(), stats.getTotalGrade());
|
||||||
setIndicatorValue(corpId,indicatorMap,curDate, "初中占比(当日)", groupName, middleRate,(10*sortNo++));
|
setIndicatorValue(corpId,indicatorMap,curDate, "初中占比(当日)", groupName, middleRate,(10*sortNo++));
|
||||||
|
setIndicatorValue(corpId,indicatorMap,curDate, "初中数量(当日)", groupName, String.valueOf(stats.getMiddleCount()),(10*sortNo++),true);
|
||||||
|
|
||||||
// 18. 高中占比
|
// 18. 高中占比
|
||||||
String highRate = calculateRate(stats.getHighCount(), stats.getTotalGrade());
|
String highRate = calculateRate(stats.getHighCount(), stats.getTotalGrade());
|
||||||
setIndicatorValue(corpId,indicatorMap,curDate, "高中占比(当日)", groupName, highRate,(10*sortNo++));
|
setIndicatorValue(corpId,indicatorMap,curDate, "高中占比(当日)", groupName, highRate,(10*sortNo++));
|
||||||
|
setIndicatorValue(corpId,indicatorMap,curDate, "高中数量(当日)", groupName, String.valueOf(stats.getHighCount()),(10*sortNo++),true);
|
||||||
|
|
||||||
// 19. 家长出单占比
|
// 19. 家长出单占比
|
||||||
String parentOrderRate = calculateRate(stats.getParentOrderCount(), stats.getParentCount());
|
String parentOrderRate = calculateRate(stats.getParentOrderCount(), stats.getParentCount());
|
||||||
setIndicatorValue(corpId,indicatorMap,curDate, "家长出单占比(当日)", groupName, parentOrderRate,(10*sortNo++));
|
setIndicatorValue(corpId,indicatorMap,curDate, "家长出单占比(当日)", groupName, parentOrderRate,(10*sortNo++));
|
||||||
|
setIndicatorValue(corpId,indicatorMap,curDate, "家长出单数量(当日)", groupName, String.valueOf(stats.getParentOrderCount()),(10*sortNo++),true);
|
||||||
|
|
||||||
// 20. 学生出单占比
|
// 20. 学生出单占比
|
||||||
String studentOrderRate = calculateRate(stats.getStudentOrderCount(), stats.getStudentCount());
|
String studentOrderRate = calculateRate(stats.getStudentOrderCount(), stats.getStudentCount());
|
||||||
setIndicatorValue(corpId,indicatorMap,curDate, "学生出单占比(当日)", groupName, studentOrderRate,(10*sortNo++));
|
setIndicatorValue(corpId,indicatorMap,curDate, "学生出单占比(当日)", groupName, studentOrderRate,(10*sortNo++));
|
||||||
|
setIndicatorValue(corpId,indicatorMap,curDate, "学生出单数量(当日)", groupName, String.valueOf(stats.getStudentOrderCount()),(10*sortNo++),true);
|
||||||
|
|
||||||
|
// 21. 家长出单率(当日)
|
||||||
|
String parentDailyOrderRate = calculateRate(stats.getParentDailyOrderCount(), stats.getParentDailyCount());
|
||||||
|
setIndicatorValue(corpId,indicatorMap,curDate, "家长出单率(当日)", groupName, parentDailyOrderRate,(10*sortNo++));
|
||||||
|
setIndicatorValue(corpId,indicatorMap,curDate, "家长即时单数量(当日)", groupName, String.valueOf(stats.getParentDailyOrderCount()),(10*sortNo++),true);
|
||||||
|
|
||||||
|
// 22. 学生出单率(当日)
|
||||||
|
String studentDailyOrderRate = calculateRate(stats.getStudentDailyOrderCount(), stats.getStudentDailyCount());
|
||||||
|
setIndicatorValue(corpId,indicatorMap,curDate, "学生出单率(当日)", groupName, studentDailyOrderRate,(10*sortNo++));
|
||||||
|
setIndicatorValue(corpId,indicatorMap,curDate, "学生即时单数量(当日)", groupName, String.valueOf(stats.getStudentDailyOrderCount()),(10*sortNo++),true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -865,6 +976,30 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
setGroupValue(vo, groupName, value);
|
setGroupValue(vo, groupName, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置指标值到对应的 CustomerStatisticsData 对象
|
||||||
|
* @param indicatorMap 指标映射表
|
||||||
|
* @param indicatorName 指标名称(不带组名前缀)
|
||||||
|
* @param groupName 组名
|
||||||
|
* @param value 指标值
|
||||||
|
*/
|
||||||
|
private void setIndicatorValue(String corpId, Map<String, CustomerStatisticsData> indicatorMap, Date curDate,
|
||||||
|
String indicatorName, String groupName, String value, int sortNo, Boolean hiddenFlag) {
|
||||||
|
// 获取或创建该指标对应的 CustomerStatisticsData 对象
|
||||||
|
CustomerStatisticsData vo = indicatorMap.computeIfAbsent(indicatorName, k -> {
|
||||||
|
CustomerStatisticsData newVo = new CustomerStatisticsData();
|
||||||
|
newVo.setIndicatorName(indicatorName);
|
||||||
|
newVo.setCurDate(curDate);
|
||||||
|
newVo.setSortNo(sortNo);
|
||||||
|
newVo.setCorpId(corpId);
|
||||||
|
newVo.setHiddenFlag(hiddenFlag);
|
||||||
|
return newVo;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 根据组名设置对应的字段值
|
||||||
|
setGroupValue(vo, groupName, value);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据组名设置对应字段的值
|
* 根据组名设置对应字段的值
|
||||||
* @param vo CustomerStatisticsData 对象
|
* @param vo CustomerStatisticsData 对象
|
||||||
|
|
@ -947,6 +1082,22 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
if(matchesSource(data)) {
|
if(matchesSource(data)) {
|
||||||
// 2. 总承接数(当日)- 排除"由管理员XXX分配"
|
// 2. 总承接数(当日)- 排除"由管理员XXX分配"
|
||||||
stats.setTotalAcceptCount(stats.getTotalAcceptCount() + 1);
|
stats.setTotalAcceptCount(stats.getTotalAcceptCount() + 1);
|
||||||
|
|
||||||
|
// 新增:家长/学生出单率统计
|
||||||
|
String customerAttr = data.getTagGroup6();
|
||||||
|
if (customerAttr != null && !customerAttr.trim().isEmpty()) {
|
||||||
|
if (customerAttr.contains("家长")) {
|
||||||
|
stats.setParentDailyCount(stats.getParentDailyCount() + 1);
|
||||||
|
if (matchesQValue(data, targetDate) && isTimelyOrder(data)) {
|
||||||
|
stats.setParentDailyOrderCount(stats.getParentDailyOrderCount() + 1);
|
||||||
|
}
|
||||||
|
} else if (customerAttr.contains("学生")) {
|
||||||
|
stats.setStudentDailyCount(stats.getStudentDailyCount() + 1);
|
||||||
|
if (matchesQValue(data, targetDate) && isTimelyOrder(data)) {
|
||||||
|
stats.setStudentDailyOrderCount(stats.getStudentDailyOrderCount() + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// 由管理员XXX分配"
|
// 由管理员XXX分配"
|
||||||
stats.setManagerAcceptCount(stats.getManagerAcceptCount() + 1);
|
stats.setManagerAcceptCount(stats.getManagerAcceptCount() + 1);
|
||||||
|
|
@ -975,6 +1126,25 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
vo.setDepartmentPath(departmentPath);
|
vo.setDepartmentPath(departmentPath);
|
||||||
vo.setCorpId(corpId);
|
vo.setCorpId(corpId);
|
||||||
|
|
||||||
|
// 解析路径,设置各级名称
|
||||||
|
// 路径格式:苏州曼普/销售部/二组/盛宇婷
|
||||||
|
String[] pathParts = departmentPath.split("/");
|
||||||
|
if (pathParts.length >= 1) {
|
||||||
|
vo.setCorpName(pathParts[0]);
|
||||||
|
}
|
||||||
|
if (pathParts.length >= 2) {
|
||||||
|
vo.setDepartmentName(pathParts[1]);
|
||||||
|
}
|
||||||
|
if (pathParts.length >= 3) {
|
||||||
|
vo.setGroupName(pathParts[2]);
|
||||||
|
}
|
||||||
|
if (pathParts.length >= 4) {
|
||||||
|
vo.setPersonName(pathParts[3]);
|
||||||
|
vo.setPersonFlag(true);
|
||||||
|
} else {
|
||||||
|
vo.setPersonFlag(false);
|
||||||
|
}
|
||||||
|
|
||||||
// 设置各项指标
|
// 设置各项指标
|
||||||
// 1. 总承接数(当日)
|
// 1. 总承接数(当日)
|
||||||
vo.setDailyTotalAccepted(stats.getTotalAcceptCount());
|
vo.setDailyTotalAccepted(stats.getTotalAcceptCount());
|
||||||
|
|
@ -990,12 +1160,26 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
// 4. 及时单占比(当日)
|
// 4. 及时单占比(当日)
|
||||||
BigDecimal timelyRate = calculateRateBigDecimal(stats.getTimelyOrderCount(), stats.getTotalOrderCount());
|
BigDecimal timelyRate = calculateRateBigDecimal(stats.getTimelyOrderCount(), stats.getTotalOrderCount());
|
||||||
|
vo.setDailyTimelyCount(stats.getTimelyOrderCount());
|
||||||
vo.setDailyTimelyOrderRatio(timelyRate);
|
vo.setDailyTimelyOrderRatio(timelyRate);
|
||||||
|
|
||||||
// 5. 非及时单占比(当日)
|
// 5. 非及时单占比(当日)
|
||||||
BigDecimal nonTimelyRate = calculateRateBigDecimal(stats.getNonTimelyOrderCount(), stats.getTotalOrderCount());
|
BigDecimal nonTimelyRate = calculateRateBigDecimal(stats.getNonTimelyOrderCount(), stats.getTotalOrderCount());
|
||||||
|
vo.setDailyNonTimelyCount(stats.getNonTimelyOrderCount());
|
||||||
vo.setDailyNonTimelyOrderRatio(nonTimelyRate);
|
vo.setDailyNonTimelyOrderRatio(nonTimelyRate);
|
||||||
|
|
||||||
|
// 6. 家长出单率(当日)
|
||||||
|
BigDecimal parentOrderRate = calculateRateBigDecimal(stats.getParentDailyOrderCount(), stats.getParentDailyCount());
|
||||||
|
vo.setParentDailyOrderCount(stats.getParentDailyOrderCount());
|
||||||
|
vo.setParentDailyCount(stats.getParentDailyCount());
|
||||||
|
vo.setDailyParentOrderRate(parentOrderRate);
|
||||||
|
|
||||||
|
// 7. 学生出单率(当日)
|
||||||
|
BigDecimal studentOrderRate = calculateRateBigDecimal(stats.getStudentDailyOrderCount(), stats.getStudentDailyCount());
|
||||||
|
vo.setStudentDailyOrderCount(stats.getStudentDailyOrderCount());
|
||||||
|
vo.setStudentDailyCount(stats.getStudentDailyCount());
|
||||||
|
vo.setDailyStudentOrderRate(studentOrderRate);
|
||||||
|
|
||||||
results.add(vo);
|
results.add(vo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,27 @@ public class StatisticsAccumulator {
|
||||||
*/
|
*/
|
||||||
private int studentOrderCount = 0;
|
private int studentOrderCount = 0;
|
||||||
|
|
||||||
|
// ========== 新增:家长/学生出单率统计(当日) ==========
|
||||||
|
/**
|
||||||
|
* 家长出单数(当日成交)- 满足Q列=当日 AND T列=已成交及时单9元+
|
||||||
|
*/
|
||||||
|
private int parentDailyOrderCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 家长总数(当日进粉)- 用于出单率分母
|
||||||
|
*/
|
||||||
|
private int parentDailyCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 学生出单数(当日成交)- 满足Q列=当日 AND T列=已成交及时单9元+
|
||||||
|
*/
|
||||||
|
private int studentDailyOrderCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 学生总数(当日进粉)- 用于出单率分母
|
||||||
|
*/
|
||||||
|
private int studentDailyCount = 0;
|
||||||
|
|
||||||
// ========== 成本数据 ==========
|
// ========== 成本数据 ==========
|
||||||
/**
|
/**
|
||||||
* 总成本(手工填写)
|
* 总成本(手工填写)
|
||||||
|
|
|
||||||
|
|
@ -46,5 +46,23 @@ public interface CustomerStatisticsDataMapper extends BaseMapper<CustomerStatist
|
||||||
@Param("indicatorName") String indicatorName
|
@Param("indicatorName") String indicatorName
|
||||||
);
|
);
|
||||||
|
|
||||||
|
List<CustomerStatisticsData> selectDailyDataByWeek(
|
||||||
|
@Param("corpId") String corpId,
|
||||||
|
@Param("year") Integer year,
|
||||||
|
@Param("week") Integer week,
|
||||||
|
@Param("indicatorName") String indicatorName
|
||||||
|
);
|
||||||
|
|
||||||
|
List<CustomerStatisticsData> selectDailyDataByMonth(
|
||||||
|
@Param("corpId") String corpId,
|
||||||
|
@Param("yearMonth") String yearMonth,
|
||||||
|
@Param("indicatorName") String indicatorName
|
||||||
|
);
|
||||||
|
|
||||||
|
List<CustomerStatisticsData> selectAllDailyData(
|
||||||
|
@Param("corpId") String corpId,
|
||||||
|
@Param("indicatorName") String indicatorName
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,4 +83,32 @@ public interface DepartmentStatisticsDataMapper extends BaseMapper<DepartmentSta
|
||||||
Map<String, BigDecimal> getSummary(@Param("corpId") String corpId,@Param("startDate") Date startDate,
|
Map<String, BigDecimal> getSummary(@Param("corpId") String corpId,@Param("startDate") Date startDate,
|
||||||
@Param("endDate") Date endDate,
|
@Param("endDate") Date endDate,
|
||||||
@Param("departmentPath") String departmentPath);
|
@Param("departmentPath") String departmentPath);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询部门统计数据聚合列表(按部门路径聚合)
|
||||||
|
* @param startDate 开始日期
|
||||||
|
* @param endDate 结束日期
|
||||||
|
* @param departmentPath 部门路径(可选)
|
||||||
|
* @return 部门统计数据聚合列表
|
||||||
|
*/
|
||||||
|
List<DepartmentStatisticsData> selectDepartmentStatisticsDataAggregatedList(
|
||||||
|
@Param("corpId") String corpId,
|
||||||
|
@Param("startDate") Date startDate,
|
||||||
|
@Param("endDate") Date endDate,
|
||||||
|
@Param("departmentPath") String departmentPath
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询部门统计数据VO聚合列表(用于导出)
|
||||||
|
* @param startDate 开始日期
|
||||||
|
* @param endDate 结束日期
|
||||||
|
* @param departmentPath 部门路径(可选)
|
||||||
|
* @return 部门统计数据VO聚合列表
|
||||||
|
*/
|
||||||
|
List<DepartmentStatisticsDataVO> selectDepartmentStatisticsDataVOAggregatedList(
|
||||||
|
@Param("corpId") String corpId,
|
||||||
|
@Param("startDate") Date startDate,
|
||||||
|
@Param("endDate") Date endDate,
|
||||||
|
@Param("departmentPath") String departmentPath
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,5 +58,11 @@ public interface ICustomerStatisticsDataService {
|
||||||
*/
|
*/
|
||||||
int deleteCustomerStatisticsDataByIds(Long[] ids);
|
int deleteCustomerStatisticsDataByIds(Long[] ids);
|
||||||
|
|
||||||
int updateCost(String corpId,Date curDate, BigDecimal totalCost, String titleAttr);
|
int updateCost(String corpId,Date curDate, BigDecimal totalCost, String type,String titleAttr);
|
||||||
|
|
||||||
|
List<CustomerStatisticsDataVO> selectByWeekAggregation(String corpId, Integer year, Integer week, String indicatorName);
|
||||||
|
|
||||||
|
List<CustomerStatisticsDataVO> selectByMonthAggregation(String corpId, String yearMonth, String indicatorName);
|
||||||
|
|
||||||
|
List<CustomerStatisticsDataVO> selectAllAggregation(String corpId, String indicatorName);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,18 +18,20 @@ public interface IDepartmentStatisticsDataService {
|
||||||
* @param startDate 开始日期
|
* @param startDate 开始日期
|
||||||
* @param endDate 结束日期
|
* @param endDate 结束日期
|
||||||
* @param departmentPath 部门路径
|
* @param departmentPath 部门路径
|
||||||
|
* @param dataType 数据类型
|
||||||
* @return 部门统计数据列表
|
* @return 部门统计数据列表
|
||||||
*/
|
*/
|
||||||
List<DepartmentStatisticsData> selectDepartmentStatisticsDataList(String corpId,Date startDate, Date endDate, String departmentPath);
|
List<DepartmentStatisticsData> selectDepartmentStatisticsDataList(String corpId, Date startDate, Date endDate, String departmentPath, String dataType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询部门统计数据VO列表(用于导出)
|
* 查询部门统计数据VO列表(用于导出)
|
||||||
* @param startDate 开始日期
|
* @param startDate 开始日期
|
||||||
* @param endDate 结束日期
|
* @param endDate 结束日期
|
||||||
* @param departmentPath 部门路径
|
* @param departmentPath 部门路径
|
||||||
|
* @param dataType 数据类型
|
||||||
* @return 部门统计数据VO列表
|
* @return 部门统计数据VO列表
|
||||||
*/
|
*/
|
||||||
List<DepartmentStatisticsDataVO> selectDepartmentStatisticsDataVOList(String corpId,Date startDate, Date endDate, String departmentPath);
|
List<DepartmentStatisticsDataVO> selectDepartmentStatisticsDataVOList(String corpId, Date startDate, Date endDate, String departmentPath, String dataType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据ID查询部门统计数据
|
* 根据ID查询部门统计数据
|
||||||
|
|
@ -59,5 +61,5 @@ public interface IDepartmentStatisticsDataService {
|
||||||
*/
|
*/
|
||||||
int deleteDepartmentStatisticsDataByIds(Long[] ids);
|
int deleteDepartmentStatisticsDataByIds(Long[] ids);
|
||||||
|
|
||||||
Map<String, BigDecimal> getSummary(String corpId,Date startDate, Date endDate, String departmentPath);
|
Map<String, BigDecimal> getSummary(String corpId, Date startDate, Date endDate, String departmentPath, String dataType);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ import com.ruoyi.excel.wecom.domain.CustomerStatisticsData;
|
||||||
import com.ruoyi.excel.wecom.mapper.CustomerStatisticsDataMapper;
|
import com.ruoyi.excel.wecom.mapper.CustomerStatisticsDataMapper;
|
||||||
import com.ruoyi.excel.wecom.service.ICustomerStatisticsDataService;
|
import com.ruoyi.excel.wecom.service.ICustomerStatisticsDataService;
|
||||||
import com.ruoyi.excel.wecom.vo.CustomerStatisticsDataVO;
|
import com.ruoyi.excel.wecom.vo.CustomerStatisticsDataVO;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
@ -12,8 +14,15 @@ import org.springframework.transaction.annotation.Transactional;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
|
import java.time.DayOfWeek;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.temporal.WeekFields;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 客户统计数据Service业务层处理
|
* 客户统计数据Service业务层处理
|
||||||
|
|
@ -21,6 +30,8 @@ import java.util.List;
|
||||||
@Service
|
@Service
|
||||||
public class CustomerStatisticsDataServiceImpl implements ICustomerStatisticsDataService {
|
public class CustomerStatisticsDataServiceImpl implements ICustomerStatisticsDataService {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(CustomerStatisticsDataServiceImpl.class);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private CustomerStatisticsDataMapper customerStatisticsDataMapper;
|
private CustomerStatisticsDataMapper customerStatisticsDataMapper;
|
||||||
|
|
||||||
|
|
@ -94,7 +105,7 @@ public class CustomerStatisticsDataServiceImpl implements ICustomerStatisticsDat
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public int updateCost(String corpId,Date curDate, BigDecimal totalCost, String titleAttr) {
|
public int updateCost(String corpId,Date curDate, BigDecimal totalCost, String type,String titleAttr) {
|
||||||
try {
|
try {
|
||||||
// 1. 查询该日期的所有记录
|
// 1. 查询该日期的所有记录
|
||||||
LambdaQueryWrapper<CustomerStatisticsData> queryWrapper = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<CustomerStatisticsData> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
|
@ -112,19 +123,36 @@ public class CustomerStatisticsDataServiceImpl implements ICustomerStatisticsDat
|
||||||
CustomerStatisticsData danTiaoCostData = findByIndicatorName(dataList, "单条成本(当日)");
|
CustomerStatisticsData danTiaoCostData = findByIndicatorName(dataList, "单条成本(当日)");
|
||||||
CustomerStatisticsData chengDanCostData = findByIndicatorName(dataList, "成单成本(当日)");
|
CustomerStatisticsData chengDanCostData = findByIndicatorName(dataList, "成单成本(当日)");
|
||||||
|
|
||||||
// 3. 更新总成本
|
// 3. 根据type类型处理成本更新
|
||||||
setFieldValue(totalCostData, titleAttr, totalCost.toString());
|
BigDecimal actualTotalCost;
|
||||||
|
if ("single".equals(type)) {
|
||||||
|
String jinFenShuStr = getFieldValue(jinFenShuData, titleAttr);
|
||||||
|
if (jinFenShuStr != null && !jinFenShuStr.trim().isEmpty()) {
|
||||||
|
BigDecimal jinFenShu = new BigDecimal(jinFenShuStr);
|
||||||
|
actualTotalCost = totalCost.multiply(jinFenShu).setScale(2, RoundingMode.HALF_UP);
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("进粉数为空,无法计算总成本");
|
||||||
|
}
|
||||||
|
setFieldValue(danTiaoCostData, titleAttr, totalCost.toString());
|
||||||
|
customerStatisticsDataMapper.updateById(danTiaoCostData);
|
||||||
|
} else {
|
||||||
|
actualTotalCost = totalCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 更新总成本
|
||||||
|
setFieldValue(totalCostData, titleAttr, actualTotalCost.toString());
|
||||||
customerStatisticsDataMapper.updateById(totalCostData);
|
customerStatisticsDataMapper.updateById(totalCostData);
|
||||||
|
|
||||||
// 4. 获取进粉数和成单数
|
// 5. 获取进粉数和成单数
|
||||||
String jinFenShuStr = getFieldValue(jinFenShuData, titleAttr);
|
String jinFenShuStr = getFieldValue(jinFenShuData, titleAttr);
|
||||||
String chengDanShuStr = getFieldValue(chengDanShuData, titleAttr);
|
String chengDanShuStr = getFieldValue(chengDanShuData, titleAttr);
|
||||||
|
|
||||||
// 5. 计算并更新单条成本
|
// 6. 计算并更新单条成本(仅在非single模式下更新)
|
||||||
|
if (!"single".equals(type)) {
|
||||||
if (jinFenShuStr != null && !jinFenShuStr.trim().isEmpty()) {
|
if (jinFenShuStr != null && !jinFenShuStr.trim().isEmpty()) {
|
||||||
BigDecimal jinFenShu = new BigDecimal(jinFenShuStr);
|
BigDecimal jinFenShu = new BigDecimal(jinFenShuStr);
|
||||||
if (jinFenShu.compareTo(BigDecimal.ZERO) > 0) {
|
if (jinFenShu.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
BigDecimal danTiaoCost = totalCost.divide(jinFenShu, 2, RoundingMode.HALF_UP);
|
BigDecimal danTiaoCost = actualTotalCost.divide(jinFenShu, 2, RoundingMode.HALF_UP);
|
||||||
setFieldValue(danTiaoCostData, titleAttr, danTiaoCost.toString());
|
setFieldValue(danTiaoCostData, titleAttr, danTiaoCost.toString());
|
||||||
customerStatisticsDataMapper.updateById(danTiaoCostData);
|
customerStatisticsDataMapper.updateById(danTiaoCostData);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -132,12 +160,13 @@ public class CustomerStatisticsDataServiceImpl implements ICustomerStatisticsDat
|
||||||
customerStatisticsDataMapper.updateById(danTiaoCostData);
|
customerStatisticsDataMapper.updateById(danTiaoCostData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 6. 计算并更新成单成本
|
// 7. 计算并更新成单成本
|
||||||
if (chengDanShuStr != null && !chengDanShuStr.trim().isEmpty()) {
|
if (chengDanShuStr != null && !chengDanShuStr.trim().isEmpty()) {
|
||||||
BigDecimal chengDanShu = new BigDecimal(chengDanShuStr);
|
BigDecimal chengDanShu = new BigDecimal(chengDanShuStr);
|
||||||
if (chengDanShu.compareTo(BigDecimal.ZERO) > 0) {
|
if (chengDanShu.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
BigDecimal chengDanCost = totalCost.divide(chengDanShu, 2, RoundingMode.HALF_UP);
|
BigDecimal chengDanCost = actualTotalCost.divide(chengDanShu, 2, RoundingMode.HALF_UP);
|
||||||
setFieldValue(chengDanCostData, titleAttr, chengDanCost.toString());
|
setFieldValue(chengDanCostData, titleAttr, chengDanCost.toString());
|
||||||
customerStatisticsDataMapper.updateById(chengDanCostData);
|
customerStatisticsDataMapper.updateById(chengDanCostData);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -178,9 +207,32 @@ public class CustomerStatisticsDataServiceImpl implements ICustomerStatisticsDat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动态获取字段值
|
||||||
|
*/
|
||||||
|
private String getFieldValue(CustomerStatisticsDataVO data, String fieldName) {
|
||||||
|
try {
|
||||||
|
Field field = CustomerStatisticsDataVO.class.getDeclaredField(fieldName);
|
||||||
|
field.setAccessible(true);
|
||||||
|
Object value = field.get(data);
|
||||||
|
return value != null ? value.toString() : null;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("获取字段值失败: " + fieldName, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 动态设置字段值
|
* 动态设置字段值
|
||||||
*/
|
*/
|
||||||
|
private void setFieldValue(CustomerStatisticsDataVO data, String fieldName, String value) {
|
||||||
|
try {
|
||||||
|
Field field = CustomerStatisticsDataVO.class.getDeclaredField(fieldName);
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(data, value);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("设置字段值失败: " + fieldName, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void setFieldValue(CustomerStatisticsData data, String fieldName, String value) {
|
private void setFieldValue(CustomerStatisticsData data, String fieldName, String value) {
|
||||||
try {
|
try {
|
||||||
Field field = CustomerStatisticsData.class.getDeclaredField(fieldName);
|
Field field = CustomerStatisticsData.class.getDeclaredField(fieldName);
|
||||||
|
|
@ -191,4 +243,684 @@ public class CustomerStatisticsDataServiceImpl implements ICustomerStatisticsDat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CustomerStatisticsDataVO> selectByWeekAggregation(String corpId, Integer year, Integer week, String indicatorName) {
|
||||||
|
List<CustomerStatisticsData> dailyDataList = customerStatisticsDataMapper.selectDailyDataByWeek(corpId, year, week, indicatorName);
|
||||||
|
return aggregateDataList(dailyDataList, year, week, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CustomerStatisticsDataVO> selectByMonthAggregation(String corpId, String yearMonth, String indicatorName) {
|
||||||
|
log.info("按月聚合查询 - corpId: {}, yearMonth: {}, indicatorName: {}", corpId, yearMonth, indicatorName);
|
||||||
|
List<CustomerStatisticsData> dailyDataList = customerStatisticsDataMapper.selectDailyDataByMonth(corpId, yearMonth, indicatorName);
|
||||||
|
log.info("查询到 {} 条原始数据", dailyDataList != null ? dailyDataList.size() : 0);
|
||||||
|
if (dailyDataList != null && !dailyDataList.isEmpty()) {
|
||||||
|
log.info("第一条数据: indicatorName={}, ntfGroup={}, ofhGroup={}",
|
||||||
|
dailyDataList.get(0).getIndicatorName(),
|
||||||
|
dailyDataList.get(0).getNtfGroup(),
|
||||||
|
dailyDataList.get(0).getOfhGroup());
|
||||||
|
}
|
||||||
|
return aggregateDataList(dailyDataList, null, null, yearMonth);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CustomerStatisticsDataVO> selectAllAggregation(String corpId, String indicatorName) {
|
||||||
|
List<CustomerStatisticsData> dailyDataList = customerStatisticsDataMapper.selectAllDailyData(corpId, indicatorName);
|
||||||
|
return aggregateAllData(dailyDataList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<CustomerStatisticsDataVO> aggregateAllData(List<CustomerStatisticsData> dailyDataList) {
|
||||||
|
if (dailyDataList == null || dailyDataList.isEmpty()) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, List<CustomerStatisticsData>> groupByIndicator = dailyDataList.stream()
|
||||||
|
.collect(Collectors.groupingBy(CustomerStatisticsData::getIndicatorName));
|
||||||
|
|
||||||
|
List<CustomerStatisticsDataVO> allAggregatedList = new ArrayList<>();
|
||||||
|
Map<String, CustomerStatisticsDataVO> indicatorMap = new java.util.HashMap<>();
|
||||||
|
Map<String, Boolean> hiddenFlagMap = new java.util.HashMap<>();
|
||||||
|
|
||||||
|
for (List<CustomerStatisticsData> indicatorDataList : groupByIndicator.values()) {
|
||||||
|
CustomerStatisticsData firstData = indicatorDataList.get(0);
|
||||||
|
String indicatorName = firstData.getIndicatorName();
|
||||||
|
|
||||||
|
CustomerStatisticsDataVO aggregated = new CustomerStatisticsDataVO();
|
||||||
|
aggregated.setIndicatorName(indicatorName);
|
||||||
|
aggregated.setSortNo(firstData.getSortNo());
|
||||||
|
|
||||||
|
hiddenFlagMap.put(indicatorName, firstData.getHiddenFlag());
|
||||||
|
|
||||||
|
String[] groupFields = {"ntfGroup", "ofhGroup", "pswGroup", "wa1Group", "xb1Group",
|
||||||
|
"yc1Group", "zd1Group", "aaGroup", "acGroup", "adGroup", "aeGroup"};
|
||||||
|
|
||||||
|
boolean isPercentIndicator = indicatorName.contains("占比") || indicatorName.contains("转化率");
|
||||||
|
boolean isDerivedCostIndicator = indicatorName.equals("单条成本(当日)") || indicatorName.equals("成单成本(当日)");
|
||||||
|
|
||||||
|
if (!isPercentIndicator && !isDerivedCostIndicator) {
|
||||||
|
for (String field : groupFields) {
|
||||||
|
BigDecimal sum = BigDecimal.ZERO;
|
||||||
|
boolean hasValue = false;
|
||||||
|
for (CustomerStatisticsData data : indicatorDataList) {
|
||||||
|
String value = getFieldValue(data, field);
|
||||||
|
if (value != null && !value.trim().isEmpty()) {
|
||||||
|
String cleanValue = value.replace("%", "").trim();
|
||||||
|
if (cleanValue.equals("需手工填写")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (cleanValue.matches("-?\\d+(\\.\\d+)?")) {
|
||||||
|
try {
|
||||||
|
sum = sum.add(new BigDecimal(cleanValue));
|
||||||
|
hasValue = true;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasValue) {
|
||||||
|
setFieldValue(aggregated, field, sum.setScale(2, RoundingMode.HALF_UP).toString());
|
||||||
|
} else if (indicatorName.equals("总成本(当日)")) {
|
||||||
|
setFieldValue(aggregated, field, "0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allAggregatedList.add(aggregated);
|
||||||
|
indicatorMap.put(indicatorName, aggregated);
|
||||||
|
}
|
||||||
|
|
||||||
|
recalculateCostIndicators(indicatorMap);
|
||||||
|
|
||||||
|
List<CustomerStatisticsDataVO> result = new ArrayList<>();
|
||||||
|
for (CustomerStatisticsDataVO vo : allAggregatedList) {
|
||||||
|
Boolean hidden = hiddenFlagMap.get(vo.getIndicatorName());
|
||||||
|
if (!Boolean.TRUE.equals(hidden)) {
|
||||||
|
result.add(vo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.sort((a, b) -> Integer.compare(a.getSortNo(), b.getSortNo()));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<CustomerStatisticsDataVO> aggregateDataList(List<CustomerStatisticsData> dailyDataList, Integer year, Integer week, String yearMonth) {
|
||||||
|
if (dailyDataList == null || dailyDataList.isEmpty()) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, List<CustomerStatisticsData>> groupByIndicator = dailyDataList.stream()
|
||||||
|
.collect(Collectors.groupingBy(CustomerStatisticsData::getIndicatorName));
|
||||||
|
|
||||||
|
List<CustomerStatisticsDataVO> allAggregatedList = new ArrayList<>();
|
||||||
|
Map<String, CustomerStatisticsDataVO> indicatorMap = new java.util.HashMap<>();
|
||||||
|
Map<String, Boolean> hiddenFlagMap = new java.util.HashMap<>();
|
||||||
|
|
||||||
|
for (List<CustomerStatisticsData> indicatorDataList : groupByIndicator.values()) {
|
||||||
|
CustomerStatisticsData firstData = indicatorDataList.get(0);
|
||||||
|
String indicatorName = firstData.getIndicatorName();
|
||||||
|
|
||||||
|
CustomerStatisticsDataVO aggregated = aggregateIndicatorData(indicatorDataList, year, week, yearMonth);
|
||||||
|
allAggregatedList.add(aggregated);
|
||||||
|
indicatorMap.put(indicatorName, aggregated);
|
||||||
|
hiddenFlagMap.put(indicatorName, firstData.getHiddenFlag());
|
||||||
|
}
|
||||||
|
|
||||||
|
recalculateCostIndicators(indicatorMap);
|
||||||
|
|
||||||
|
List<CustomerStatisticsDataVO> result = new ArrayList<>();
|
||||||
|
for (CustomerStatisticsDataVO vo : allAggregatedList) {
|
||||||
|
Boolean hidden = hiddenFlagMap.get(vo.getIndicatorName());
|
||||||
|
if (!Boolean.TRUE.equals(hidden)) {
|
||||||
|
result.add(vo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.sort((a, b) -> Integer.compare(a.getSortNo(), b.getSortNo()));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CustomerStatisticsDataVO aggregateIndicatorData(List<CustomerStatisticsData> dailyList, Integer year, Integer week, String yearMonth) {
|
||||||
|
CustomerStatisticsDataVO result = new CustomerStatisticsDataVO();
|
||||||
|
String indicatorName = dailyList.get(0).getIndicatorName();
|
||||||
|
result.setIndicatorName(indicatorName);
|
||||||
|
result.setSortNo(dailyList.get(0).getSortNo());
|
||||||
|
|
||||||
|
log.info("聚合指标: {}, 数据条数: {}", indicatorName, dailyList.size());
|
||||||
|
|
||||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||||
|
|
||||||
|
if (year != null && week != null) {
|
||||||
|
result.setYearWeek(year + "年第" + week + "周");
|
||||||
|
WeekFields weekFields = WeekFields.of(DayOfWeek.MONDAY, 4);
|
||||||
|
LocalDate startDate = LocalDate.of(year, 1, 1)
|
||||||
|
.with(weekFields.weekOfYear(), week)
|
||||||
|
.with(DayOfWeek.MONDAY);
|
||||||
|
LocalDate endDate = startDate.plusDays(6);
|
||||||
|
result.setDateRange(startDate.format(formatter) + " 至 " + endDate.format(formatter));
|
||||||
|
} else if (yearMonth != null) {
|
||||||
|
result.setYearMonth(yearMonth.substring(0, 4) + "年" + yearMonth.substring(5) + "月");
|
||||||
|
LocalDate startDate = LocalDate.parse(yearMonth + "-01", DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
||||||
|
LocalDate endDate = startDate.withDayOfMonth(startDate.lengthOfMonth());
|
||||||
|
result.setDateRange(startDate.format(formatter) + " 至 " + endDate.format(formatter));
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] groupFields = {"ntfGroup", "ofhGroup", "pswGroup", "wa1Group", "xb1Group",
|
||||||
|
"yc1Group", "zd1Group", "aaGroup", "acGroup", "adGroup", "aeGroup"};
|
||||||
|
|
||||||
|
boolean isPercentIndicator = indicatorName.contains("占比") || indicatorName.contains("转化率");
|
||||||
|
boolean isDerivedCostIndicator = indicatorName.equals("单条成本(当日)") || indicatorName.equals("成单成本(当日)");
|
||||||
|
|
||||||
|
if (isPercentIndicator) {
|
||||||
|
log.info("指标 {} 是占比指标,跳过聚合", indicatorName);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDerivedCostIndicator) {
|
||||||
|
log.info("指标 {} 是派生成本指标,跳过聚合", indicatorName);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String field : groupFields) {
|
||||||
|
BigDecimal sum = BigDecimal.ZERO;
|
||||||
|
boolean hasValue = false;
|
||||||
|
for (CustomerStatisticsData data : dailyList) {
|
||||||
|
String value = getFieldValue(data, field);
|
||||||
|
if (value != null && !value.trim().isEmpty()) {
|
||||||
|
String cleanValue = value.replace("%", "").trim();
|
||||||
|
if (indicatorName.equals("总成本(当日)") && !cleanValue.equals("需手工填写")) {
|
||||||
|
log.info("总成本数据 - curDate: {}, 字段: {}, 原始值: {}, 清理后: {}",
|
||||||
|
data.getCurDate(), field, value, cleanValue);
|
||||||
|
}
|
||||||
|
if (cleanValue.equals("需手工填写")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (cleanValue.matches("-?\\d+(\\.\\d+)?")) {
|
||||||
|
try {
|
||||||
|
sum = sum.add(new BigDecimal(cleanValue));
|
||||||
|
hasValue = true;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasValue) {
|
||||||
|
setFieldValue(result, field, sum.setScale(2, RoundingMode.HALF_UP).toString());
|
||||||
|
log.info("指标 {} 字段 {} 最终聚合值: {}", indicatorName, field, sum.setScale(2, RoundingMode.HALF_UP));
|
||||||
|
} else if (indicatorName.equals("总成本(当日)")) {
|
||||||
|
setFieldValue(result, field, "0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void recalculateCostIndicators(Map<String, CustomerStatisticsDataVO> indicatorMap) {
|
||||||
|
CustomerStatisticsDataVO totalCostData = indicatorMap.get("总成本(当日)");
|
||||||
|
CustomerStatisticsDataVO jinFenShuData = indicatorMap.get("进粉数(当日)");
|
||||||
|
CustomerStatisticsDataVO chengDanShuData = indicatorMap.get("成单数(当日)");
|
||||||
|
CustomerStatisticsDataVO danTiaoCostData = indicatorMap.get("单条成本(当日)");
|
||||||
|
CustomerStatisticsDataVO chengDanCostData = indicatorMap.get("成单成本(当日)");
|
||||||
|
CustomerStatisticsDataVO zhuanHuaLvData = indicatorMap.get("转化率(当日)");
|
||||||
|
CustomerStatisticsDataVO jiShiDanZhanBiData = indicatorMap.get("及时单占比(当日)");
|
||||||
|
CustomerStatisticsDataVO feiJiShiDanZhanBiData = indicatorMap.get("非及时单占比(当日)");
|
||||||
|
CustomerStatisticsDataVO jiaZhangZhanBiData = indicatorMap.get("家长占比(当日)");
|
||||||
|
CustomerStatisticsDataVO keHuShuXingData = indicatorMap.get("客户属性数量(当日)");
|
||||||
|
CustomerStatisticsDataVO xueShengZhanBiData = indicatorMap.get("学生占比(当日)");
|
||||||
|
CustomerStatisticsDataVO weiZhiZhanBiData = indicatorMap.get("未知占比(当日)");
|
||||||
|
CustomerStatisticsDataVO zhuDongBaoJiaZhanBiData = indicatorMap.get("主动报价占比(当日)");
|
||||||
|
CustomerStatisticsDataVO beiDongBaoJiaZhanBiData = indicatorMap.get("被动报价占比(当日)");
|
||||||
|
CustomerStatisticsDataVO weiKaiKouBaoJiaZhanBiData = indicatorMap.get("未开口报价占比(当日)");
|
||||||
|
CustomerStatisticsDataVO yiShanChuBaoJiaZhanBiData = indicatorMap.get("已删除报价占比(当日)");
|
||||||
|
CustomerStatisticsDataVO xiaoXueZhanBiData = indicatorMap.get("小学占比(当日)");
|
||||||
|
CustomerStatisticsDataVO chuZhongZhanBiData = indicatorMap.get("初中占比(当日)");
|
||||||
|
CustomerStatisticsDataVO gaoZhongZhanBiData = indicatorMap.get("高中占比(当日)");
|
||||||
|
CustomerStatisticsDataVO jiaZhangChuDanZhanBiData = indicatorMap.get("家长出单占比(当日)");
|
||||||
|
CustomerStatisticsDataVO xueShengChuDanZhanBiData = indicatorMap.get("学生出单占比(当日)");
|
||||||
|
|
||||||
|
CustomerStatisticsDataVO yiXiangDuShuLiangData = indicatorMap.get("意向度数量(当日)");
|
||||||
|
CustomerStatisticsDataVO nianJiShuLiangData = indicatorMap.get("年级数量(当日)");
|
||||||
|
|
||||||
|
CustomerStatisticsDataVO jiShiDanShuLiangData = indicatorMap.get("及时单数量(当日)");
|
||||||
|
CustomerStatisticsDataVO feiJiShiDanShuLiangData = indicatorMap.get("非及时单数量(当日)");
|
||||||
|
CustomerStatisticsDataVO jiaZhangShuLiangData = indicatorMap.get("家长数量(当日)");
|
||||||
|
CustomerStatisticsDataVO xueShengShuLiangData = indicatorMap.get("学生数量(当日)");
|
||||||
|
CustomerStatisticsDataVO weiZhiShuLiangData = indicatorMap.get("未知数量(当日)");
|
||||||
|
CustomerStatisticsDataVO zhuDongBaoJiaShuLiangData = indicatorMap.get("主动报价数量(当日)");
|
||||||
|
CustomerStatisticsDataVO beiDongBaoJiaShuLiangData = indicatorMap.get("被动报价数量(当日)");
|
||||||
|
CustomerStatisticsDataVO weiKaiKouBaoJiaShuLiangData = indicatorMap.get("未开口报价数量(当日)");
|
||||||
|
CustomerStatisticsDataVO yiShanChuShuLiangData = indicatorMap.get("已删除数量(当日)");
|
||||||
|
CustomerStatisticsDataVO xiaoXueShuLiangData = indicatorMap.get("小学数量(当日)");
|
||||||
|
CustomerStatisticsDataVO chuZhongShuLiangData = indicatorMap.get("初中数量(当日)");
|
||||||
|
CustomerStatisticsDataVO gaoZhongShuLiangData = indicatorMap.get("高中数量(当日)");
|
||||||
|
CustomerStatisticsDataVO jiaZhangChuDanShuLiangData = indicatorMap.get("家长出单数量(当日)");
|
||||||
|
CustomerStatisticsDataVO xueShengChuDanShuLiangData = indicatorMap.get("学生出单数量(当日)");
|
||||||
|
|
||||||
|
String[] groupFields = {"ntfGroup", "ofhGroup", "pswGroup", "wa1Group", "xb1Group",
|
||||||
|
"yc1Group", "zd1Group", "aaGroup", "acGroup", "adGroup", "aeGroup"};
|
||||||
|
|
||||||
|
log.info("开始计算派生指标 - totalCostData: {}, jinFenShuData: {}, chengDanShuData: {}, danTiaoCostData: {}, chengDanCostData: {}",
|
||||||
|
totalCostData != null, jinFenShuData != null, chengDanShuData != null, danTiaoCostData != null, chengDanCostData != null);
|
||||||
|
|
||||||
|
if (totalCostData != null) {
|
||||||
|
log.info("总成本数据: ntfGroup={}, ofhGroup={}", totalCostData.getNtfGroup(), totalCostData.getOfhGroup());
|
||||||
|
}
|
||||||
|
if (jinFenShuData != null) {
|
||||||
|
log.info("进粉数数据: ntfGroup={}, ofhGroup={}", jinFenShuData.getNtfGroup(), jinFenShuData.getOfhGroup());
|
||||||
|
}
|
||||||
|
if (chengDanShuData != null) {
|
||||||
|
log.info("成单数数据: ntfGroup={}, ofhGroup={}", chengDanShuData.getNtfGroup(), chengDanShuData.getOfhGroup());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (danTiaoCostData != null && totalCostData != null && jinFenShuData != null) {
|
||||||
|
for (String field : groupFields) {
|
||||||
|
String totalCostStr = getFieldValue(totalCostData, field);
|
||||||
|
String jinFenShuStr = getFieldValue(jinFenShuData, field);
|
||||||
|
log.debug("计算单条成本 - 字段: {}, 总成本: {}, 进粉数: {}", field, totalCostStr, jinFenShuStr);
|
||||||
|
if (totalCostStr != null && jinFenShuStr != null) {
|
||||||
|
try {
|
||||||
|
BigDecimal totalCost = parseCostValue(totalCostStr);
|
||||||
|
BigDecimal jinFenShu = new BigDecimal(jinFenShuStr);
|
||||||
|
log.info("计算单条成本 - 字段: {}, 总成本: {}, 进粉数: {}", field, totalCost, jinFenShu);
|
||||||
|
if (jinFenShu.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
BigDecimal danTiaoCost = totalCost.divide(jinFenShu, 2, RoundingMode.HALF_UP);
|
||||||
|
setFieldValue(danTiaoCostData, field, danTiaoCost.toString());
|
||||||
|
log.info("单条成本计算结果 - 字段: {}, 值: {}", field, danTiaoCost);
|
||||||
|
} else {
|
||||||
|
setFieldValue(danTiaoCostData, field, "0");
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.warn("计算单条成本失败 - 字段: {}, 错误: {}", field, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chengDanCostData != null && totalCostData != null && chengDanShuData != null) {
|
||||||
|
for (String field : groupFields) {
|
||||||
|
String totalCostStr = getFieldValue(totalCostData, field);
|
||||||
|
String chengDanShuStr = getFieldValue(chengDanShuData, field);
|
||||||
|
log.debug("计算成单成本 - 字段: {}, 总成本: {}, 成单数: {}", field, totalCostStr, chengDanShuStr);
|
||||||
|
if (totalCostStr != null && chengDanShuStr != null) {
|
||||||
|
try {
|
||||||
|
BigDecimal totalCost = parseCostValue(totalCostStr);
|
||||||
|
BigDecimal chengDanShu = new BigDecimal(chengDanShuStr);
|
||||||
|
log.info("计算成单成本 - 字段: {}, 总成本: {}, 成单数: {}", field, totalCost, chengDanShu);
|
||||||
|
if (chengDanShu.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
BigDecimal chengDanCost = totalCost.divide(chengDanShu, 2, RoundingMode.HALF_UP);
|
||||||
|
setFieldValue(chengDanCostData, field, chengDanCost.toString());
|
||||||
|
log.info("成单成本计算结果 - 字段: {}, 值: {}", field, chengDanCost);
|
||||||
|
} else {
|
||||||
|
setFieldValue(chengDanCostData, field, "0");
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.warn("计算成单成本失败 - 字段: {}, 错误: {}", field, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zhuanHuaLvData != null && chengDanShuData != null && jinFenShuData != null) {
|
||||||
|
for (String field : groupFields) {
|
||||||
|
String chengDanShuStr = getFieldValue(chengDanShuData, field);
|
||||||
|
String jinFenShuStr = getFieldValue(jinFenShuData, field);
|
||||||
|
if (chengDanShuStr != null && jinFenShuStr != null) {
|
||||||
|
try {
|
||||||
|
BigDecimal chengDanShu = new BigDecimal(chengDanShuStr);
|
||||||
|
BigDecimal jinFenShu = new BigDecimal(jinFenShuStr);
|
||||||
|
if (jinFenShu.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
BigDecimal zhuanHuaLv = chengDanShu.divide(jinFenShu, 4, RoundingMode.HALF_UP)
|
||||||
|
.multiply(new BigDecimal("100"))
|
||||||
|
.setScale(2, RoundingMode.HALF_UP);
|
||||||
|
setFieldValue(zhuanHuaLvData, field, zhuanHuaLv + "%");
|
||||||
|
} else {
|
||||||
|
setFieldValue(zhuanHuaLvData, field, "0%");
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jiShiDanZhanBiData != null && jiShiDanShuLiangData != null && jinFenShuData != null) {
|
||||||
|
for (String field : groupFields) {
|
||||||
|
String jiShiDanStr = getFieldValue(jiShiDanShuLiangData, field);
|
||||||
|
String jinFenShuStr = getFieldValue(jinFenShuData, field);
|
||||||
|
if (jiShiDanStr != null && jinFenShuStr != null) {
|
||||||
|
try {
|
||||||
|
BigDecimal jiShiDan = new BigDecimal(jiShiDanStr);
|
||||||
|
BigDecimal jinFenShu = new BigDecimal(jinFenShuStr);
|
||||||
|
if (jinFenShu.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
BigDecimal zhanBi = jiShiDan.divide(jinFenShu, 4, RoundingMode.HALF_UP)
|
||||||
|
.multiply(new BigDecimal("100"))
|
||||||
|
.setScale(2, RoundingMode.HALF_UP);
|
||||||
|
setFieldValue(jiShiDanZhanBiData, field, zhanBi + "%");
|
||||||
|
} else {
|
||||||
|
setFieldValue(jiShiDanZhanBiData, field, "0%");
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (feiJiShiDanZhanBiData != null && feiJiShiDanShuLiangData != null && jinFenShuData != null) {
|
||||||
|
for (String field : groupFields) {
|
||||||
|
String feiJiShiDanStr = getFieldValue(feiJiShiDanShuLiangData, field);
|
||||||
|
String jinFenShuStr = getFieldValue(jinFenShuData, field);
|
||||||
|
if (feiJiShiDanStr != null && jinFenShuStr != null) {
|
||||||
|
try {
|
||||||
|
BigDecimal feiJiShiDan = new BigDecimal(feiJiShiDanStr);
|
||||||
|
BigDecimal jinFenShu = new BigDecimal(jinFenShuStr);
|
||||||
|
if (jinFenShu.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
BigDecimal zhanBi = feiJiShiDan.divide(jinFenShu, 4, RoundingMode.HALF_UP)
|
||||||
|
.multiply(new BigDecimal("100"))
|
||||||
|
.setScale(2, RoundingMode.HALF_UP);
|
||||||
|
setFieldValue(feiJiShiDanZhanBiData, field, zhanBi + "%");
|
||||||
|
} else {
|
||||||
|
setFieldValue(feiJiShiDanZhanBiData, field, "0%");
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keHuShuXingData != null && jiaZhangShuLiangData != null && xueShengShuLiangData != null && weiZhiShuLiangData != null) {
|
||||||
|
for (String field : groupFields) {
|
||||||
|
String jiaZhangStr = getFieldValue(jiaZhangShuLiangData, field);
|
||||||
|
String xueShengStr = getFieldValue(xueShengShuLiangData, field);
|
||||||
|
String weiZhiStr = getFieldValue(weiZhiShuLiangData, field);
|
||||||
|
try {
|
||||||
|
BigDecimal jiaZhang = jiaZhangStr != null ? new BigDecimal(jiaZhangStr) : BigDecimal.ZERO;
|
||||||
|
BigDecimal xueSheng = xueShengStr != null ? new BigDecimal(xueShengStr) : BigDecimal.ZERO;
|
||||||
|
BigDecimal weiZhi = weiZhiStr != null ? new BigDecimal(weiZhiStr) : BigDecimal.ZERO;
|
||||||
|
BigDecimal total = jiaZhang.add(xueSheng).add(weiZhi);
|
||||||
|
setFieldValue(keHuShuXingData, field, total.setScale(0, RoundingMode.HALF_UP).toString());
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jiaZhangZhanBiData != null && jiaZhangShuLiangData != null && keHuShuXingData != null) {
|
||||||
|
for (String field : groupFields) {
|
||||||
|
String jiaZhangStr = getFieldValue(jiaZhangShuLiangData, field);
|
||||||
|
String keHuShuXingStr = getFieldValue(keHuShuXingData, field);
|
||||||
|
if (jiaZhangStr != null && keHuShuXingStr != null) {
|
||||||
|
try {
|
||||||
|
BigDecimal jiaZhang = new BigDecimal(jiaZhangStr);
|
||||||
|
BigDecimal keHuShuXing = new BigDecimal(keHuShuXingStr);
|
||||||
|
if (keHuShuXing.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
BigDecimal zhanBi = jiaZhang.divide(keHuShuXing, 4, RoundingMode.HALF_UP)
|
||||||
|
.multiply(new BigDecimal("100"))
|
||||||
|
.setScale(2, RoundingMode.HALF_UP);
|
||||||
|
setFieldValue(jiaZhangZhanBiData, field, zhanBi + "%");
|
||||||
|
} else {
|
||||||
|
setFieldValue(jiaZhangZhanBiData, field, "0%");
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xueShengZhanBiData != null && xueShengShuLiangData != null && keHuShuXingData != null) {
|
||||||
|
for (String field : groupFields) {
|
||||||
|
String xueShengStr = getFieldValue(xueShengShuLiangData, field);
|
||||||
|
String keHuShuXingStr = getFieldValue(keHuShuXingData, field);
|
||||||
|
if (xueShengStr != null && keHuShuXingStr != null) {
|
||||||
|
try {
|
||||||
|
BigDecimal xueSheng = new BigDecimal(xueShengStr);
|
||||||
|
BigDecimal keHuShuXing = new BigDecimal(keHuShuXingStr);
|
||||||
|
if (keHuShuXing.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
BigDecimal zhanBi = xueSheng.divide(keHuShuXing, 4, RoundingMode.HALF_UP)
|
||||||
|
.multiply(new BigDecimal("100"))
|
||||||
|
.setScale(2, RoundingMode.HALF_UP);
|
||||||
|
setFieldValue(xueShengZhanBiData, field, zhanBi + "%");
|
||||||
|
} else {
|
||||||
|
setFieldValue(xueShengZhanBiData, field, "0%");
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weiZhiZhanBiData != null && weiZhiShuLiangData != null && keHuShuXingData != null) {
|
||||||
|
for (String field : groupFields) {
|
||||||
|
String weiZhiStr = getFieldValue(weiZhiShuLiangData, field);
|
||||||
|
String keHuShuXingStr = getFieldValue(keHuShuXingData, field);
|
||||||
|
if (weiZhiStr != null && keHuShuXingStr != null) {
|
||||||
|
try {
|
||||||
|
BigDecimal weiZhi = new BigDecimal(weiZhiStr);
|
||||||
|
BigDecimal keHuShuXing = new BigDecimal(keHuShuXingStr);
|
||||||
|
if (keHuShuXing.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
BigDecimal zhanBi = weiZhi.divide(keHuShuXing, 4, RoundingMode.HALF_UP)
|
||||||
|
.multiply(new BigDecimal("100"))
|
||||||
|
.setScale(2, RoundingMode.HALF_UP);
|
||||||
|
setFieldValue(weiZhiZhanBiData, field, zhanBi + "%");
|
||||||
|
} else {
|
||||||
|
setFieldValue(weiZhiZhanBiData, field, "0%");
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zhuDongBaoJiaZhanBiData != null && zhuDongBaoJiaShuLiangData != null && yiXiangDuShuLiangData != null) {
|
||||||
|
for (String field : groupFields) {
|
||||||
|
String zhuDongStr = getFieldValue(zhuDongBaoJiaShuLiangData, field);
|
||||||
|
String yiXiangDuStr = getFieldValue(yiXiangDuShuLiangData, field);
|
||||||
|
if (zhuDongStr != null && yiXiangDuStr != null) {
|
||||||
|
try {
|
||||||
|
BigDecimal zhuDong = new BigDecimal(zhuDongStr);
|
||||||
|
BigDecimal yiXiangDu = new BigDecimal(yiXiangDuStr);
|
||||||
|
if (yiXiangDu.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
BigDecimal zhanBi = zhuDong.divide(yiXiangDu, 4, RoundingMode.HALF_UP)
|
||||||
|
.multiply(new BigDecimal("100"))
|
||||||
|
.setScale(2, RoundingMode.HALF_UP);
|
||||||
|
setFieldValue(zhuDongBaoJiaZhanBiData, field, zhanBi + "%");
|
||||||
|
} else {
|
||||||
|
setFieldValue(zhuDongBaoJiaZhanBiData, field, "0%");
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (beiDongBaoJiaZhanBiData != null && beiDongBaoJiaShuLiangData != null && yiXiangDuShuLiangData != null) {
|
||||||
|
for (String field : groupFields) {
|
||||||
|
String beiDongStr = getFieldValue(beiDongBaoJiaShuLiangData, field);
|
||||||
|
String yiXiangDuStr = getFieldValue(yiXiangDuShuLiangData, field);
|
||||||
|
if (beiDongStr != null && yiXiangDuStr != null) {
|
||||||
|
try {
|
||||||
|
BigDecimal beiDong = new BigDecimal(beiDongStr);
|
||||||
|
BigDecimal yiXiangDu = new BigDecimal(yiXiangDuStr);
|
||||||
|
if (yiXiangDu.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
BigDecimal zhanBi = beiDong.divide(yiXiangDu, 4, RoundingMode.HALF_UP)
|
||||||
|
.multiply(new BigDecimal("100"))
|
||||||
|
.setScale(2, RoundingMode.HALF_UP);
|
||||||
|
setFieldValue(beiDongBaoJiaZhanBiData, field, zhanBi + "%");
|
||||||
|
} else {
|
||||||
|
setFieldValue(beiDongBaoJiaZhanBiData, field, "0%");
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weiKaiKouBaoJiaZhanBiData != null && weiKaiKouBaoJiaShuLiangData != null && yiXiangDuShuLiangData != null) {
|
||||||
|
for (String field : groupFields) {
|
||||||
|
String weiKaiKouStr = getFieldValue(weiKaiKouBaoJiaShuLiangData, field);
|
||||||
|
String yiXiangDuStr = getFieldValue(yiXiangDuShuLiangData, field);
|
||||||
|
if (weiKaiKouStr != null && yiXiangDuStr != null) {
|
||||||
|
try {
|
||||||
|
BigDecimal weiKaiKou = new BigDecimal(weiKaiKouStr);
|
||||||
|
BigDecimal yiXiangDu = new BigDecimal(yiXiangDuStr);
|
||||||
|
if (yiXiangDu.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
BigDecimal zhanBi = weiKaiKou.divide(yiXiangDu, 4, RoundingMode.HALF_UP)
|
||||||
|
.multiply(new BigDecimal("100"))
|
||||||
|
.setScale(2, RoundingMode.HALF_UP);
|
||||||
|
setFieldValue(weiKaiKouBaoJiaZhanBiData, field, zhanBi + "%");
|
||||||
|
} else {
|
||||||
|
setFieldValue(weiKaiKouBaoJiaZhanBiData, field, "0%");
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (yiShanChuBaoJiaZhanBiData != null && yiShanChuShuLiangData != null && yiXiangDuShuLiangData != null) {
|
||||||
|
for (String field : groupFields) {
|
||||||
|
String yiShanChuStr = getFieldValue(yiShanChuShuLiangData, field);
|
||||||
|
String yiXiangDuStr = getFieldValue(yiXiangDuShuLiangData, field);
|
||||||
|
if (yiShanChuStr != null && yiXiangDuStr != null) {
|
||||||
|
try {
|
||||||
|
BigDecimal yiShanChu = new BigDecimal(yiShanChuStr);
|
||||||
|
BigDecimal yiXiangDu = new BigDecimal(yiXiangDuStr);
|
||||||
|
if (yiXiangDu.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
BigDecimal zhanBi = yiShanChu.divide(yiXiangDu, 4, RoundingMode.HALF_UP)
|
||||||
|
.multiply(new BigDecimal("100"))
|
||||||
|
.setScale(2, RoundingMode.HALF_UP);
|
||||||
|
setFieldValue(yiShanChuBaoJiaZhanBiData, field, zhanBi + "%");
|
||||||
|
} else {
|
||||||
|
setFieldValue(yiShanChuBaoJiaZhanBiData, field, "0%");
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xiaoXueZhanBiData != null && xiaoXueShuLiangData != null && nianJiShuLiangData != null) {
|
||||||
|
for (String field : groupFields) {
|
||||||
|
String xiaoXueStr = getFieldValue(xiaoXueShuLiangData, field);
|
||||||
|
String nianJiStr = getFieldValue(nianJiShuLiangData, field);
|
||||||
|
if (xiaoXueStr != null && nianJiStr != null) {
|
||||||
|
try {
|
||||||
|
BigDecimal xiaoXue = new BigDecimal(xiaoXueStr);
|
||||||
|
BigDecimal nianJi = new BigDecimal(nianJiStr);
|
||||||
|
if (nianJi.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
BigDecimal zhanBi = xiaoXue.divide(nianJi, 4, RoundingMode.HALF_UP)
|
||||||
|
.multiply(new BigDecimal("100"))
|
||||||
|
.setScale(2, RoundingMode.HALF_UP);
|
||||||
|
setFieldValue(xiaoXueZhanBiData, field, zhanBi + "%");
|
||||||
|
} else {
|
||||||
|
setFieldValue(xiaoXueZhanBiData, field, "0%");
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chuZhongZhanBiData != null && chuZhongShuLiangData != null && nianJiShuLiangData != null) {
|
||||||
|
for (String field : groupFields) {
|
||||||
|
String chuZhongStr = getFieldValue(chuZhongShuLiangData, field);
|
||||||
|
String nianJiStr = getFieldValue(nianJiShuLiangData, field);
|
||||||
|
if (chuZhongStr != null && nianJiStr != null) {
|
||||||
|
try {
|
||||||
|
BigDecimal chuZhong = new BigDecimal(chuZhongStr);
|
||||||
|
BigDecimal nianJi = new BigDecimal(nianJiStr);
|
||||||
|
if (nianJi.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
BigDecimal zhanBi = chuZhong.divide(nianJi, 4, RoundingMode.HALF_UP)
|
||||||
|
.multiply(new BigDecimal("100"))
|
||||||
|
.setScale(2, RoundingMode.HALF_UP);
|
||||||
|
setFieldValue(chuZhongZhanBiData, field, zhanBi + "%");
|
||||||
|
} else {
|
||||||
|
setFieldValue(chuZhongZhanBiData, field, "0%");
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gaoZhongZhanBiData != null && gaoZhongShuLiangData != null && nianJiShuLiangData != null) {
|
||||||
|
for (String field : groupFields) {
|
||||||
|
String gaoZhongStr = getFieldValue(gaoZhongShuLiangData, field);
|
||||||
|
String nianJiStr = getFieldValue(nianJiShuLiangData, field);
|
||||||
|
if (gaoZhongStr != null && nianJiStr != null) {
|
||||||
|
try {
|
||||||
|
BigDecimal gaoZhong = new BigDecimal(gaoZhongStr);
|
||||||
|
BigDecimal nianJi = new BigDecimal(nianJiStr);
|
||||||
|
if (nianJi.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
BigDecimal zhanBi = gaoZhong.divide(nianJi, 4, RoundingMode.HALF_UP)
|
||||||
|
.multiply(new BigDecimal("100"))
|
||||||
|
.setScale(2, RoundingMode.HALF_UP);
|
||||||
|
setFieldValue(gaoZhongZhanBiData, field, zhanBi + "%");
|
||||||
|
} else {
|
||||||
|
setFieldValue(gaoZhongZhanBiData, field, "0%");
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jiaZhangChuDanZhanBiData != null && jiaZhangChuDanShuLiangData != null && jiaZhangShuLiangData != null) {
|
||||||
|
for (String field : groupFields) {
|
||||||
|
String jiaZhangChuDanStr = getFieldValue(jiaZhangChuDanShuLiangData, field);
|
||||||
|
String jiaZhangStr = getFieldValue(jiaZhangShuLiangData, field);
|
||||||
|
if (jiaZhangChuDanStr != null && jiaZhangStr != null) {
|
||||||
|
try {
|
||||||
|
BigDecimal jiaZhangChuDan = new BigDecimal(jiaZhangChuDanStr);
|
||||||
|
BigDecimal jiaZhang = new BigDecimal(jiaZhangStr);
|
||||||
|
if (jiaZhang.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
BigDecimal zhanBi = jiaZhangChuDan.divide(jiaZhang, 4, RoundingMode.HALF_UP)
|
||||||
|
.multiply(new BigDecimal("100"))
|
||||||
|
.setScale(2, RoundingMode.HALF_UP);
|
||||||
|
setFieldValue(jiaZhangChuDanZhanBiData, field, zhanBi + "%");
|
||||||
|
} else {
|
||||||
|
setFieldValue(jiaZhangChuDanZhanBiData, field, "0%");
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xueShengChuDanZhanBiData != null && xueShengChuDanShuLiangData != null && xueShengShuLiangData != null) {
|
||||||
|
for (String field : groupFields) {
|
||||||
|
String xueShengChuDanStr = getFieldValue(xueShengChuDanShuLiangData, field);
|
||||||
|
String xueShengStr = getFieldValue(xueShengShuLiangData, field);
|
||||||
|
if (xueShengChuDanStr != null && xueShengStr != null) {
|
||||||
|
try {
|
||||||
|
BigDecimal xueShengChuDan = new BigDecimal(xueShengChuDanStr);
|
||||||
|
BigDecimal xueSheng = new BigDecimal(xueShengStr);
|
||||||
|
if (xueSheng.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
BigDecimal zhanBi = xueShengChuDan.divide(xueSheng, 4, RoundingMode.HALF_UP)
|
||||||
|
.multiply(new BigDecimal("100"))
|
||||||
|
.setScale(2, RoundingMode.HALF_UP);
|
||||||
|
setFieldValue(xueShengChuDanZhanBiData, field, zhanBi + "%");
|
||||||
|
} else {
|
||||||
|
setFieldValue(xueShengChuDanZhanBiData, field, "0%");
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal parseCostValue(String value) {
|
||||||
|
if (value == null || value.trim().isEmpty()) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
String cleanValue = value.trim();
|
||||||
|
if (cleanValue.equals("需手工填写") || !cleanValue.matches("-?\\d+(\\.\\d+)?")) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return new BigDecimal(cleanValue);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,14 @@ public class DepartmentStatisticsDataServiceImpl implements IDepartmentStatistic
|
||||||
* @param startDate 开始日期
|
* @param startDate 开始日期
|
||||||
* @param endDate 结束日期
|
* @param endDate 结束日期
|
||||||
* @param departmentPath 部门路径
|
* @param departmentPath 部门路径
|
||||||
|
* @param dataType 数据类型
|
||||||
* @return 部门统计数据列表
|
* @return 部门统计数据列表
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<DepartmentStatisticsData> selectDepartmentStatisticsDataList(String corpId,Date startDate, Date endDate, String departmentPath) {
|
public List<DepartmentStatisticsData> selectDepartmentStatisticsDataList(String corpId, Date startDate, Date endDate, String departmentPath, String dataType) {
|
||||||
|
if ("week".equals(dataType) || "month".equals(dataType)) {
|
||||||
|
return departmentStatisticsDataMapper.selectDepartmentStatisticsDataAggregatedList(corpId, startDate, endDate, departmentPath);
|
||||||
|
}
|
||||||
return departmentStatisticsDataMapper.selectDepartmentStatisticsDataList(corpId, startDate, endDate, departmentPath);
|
return departmentStatisticsDataMapper.selectDepartmentStatisticsDataList(corpId, startDate, endDate, departmentPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -38,10 +42,14 @@ public class DepartmentStatisticsDataServiceImpl implements IDepartmentStatistic
|
||||||
* @param startDate 开始日期
|
* @param startDate 开始日期
|
||||||
* @param endDate 结束日期
|
* @param endDate 结束日期
|
||||||
* @param departmentPath 部门路径
|
* @param departmentPath 部门路径
|
||||||
|
* @param dataType 数据类型
|
||||||
* @return 部门统计数据VO列表
|
* @return 部门统计数据VO列表
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<DepartmentStatisticsDataVO> selectDepartmentStatisticsDataVOList(String corpId,Date startDate, Date endDate, String departmentPath) {
|
public List<DepartmentStatisticsDataVO> selectDepartmentStatisticsDataVOList(String corpId, Date startDate, Date endDate, String departmentPath, String dataType) {
|
||||||
|
if ("week".equals(dataType) || "month".equals(dataType)) {
|
||||||
|
return departmentStatisticsDataMapper.selectDepartmentStatisticsDataVOAggregatedList(corpId, startDate, endDate, departmentPath);
|
||||||
|
}
|
||||||
return departmentStatisticsDataMapper.selectDepartmentStatisticsDataVOList(corpId, startDate, endDate, departmentPath);
|
return departmentStatisticsDataMapper.selectDepartmentStatisticsDataVOList(corpId, startDate, endDate, departmentPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,7 +98,7 @@ public class DepartmentStatisticsDataServiceImpl implements IDepartmentStatistic
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, BigDecimal> getSummary(String corpId,Date startDate, Date endDate, String departmentPath) {
|
public Map<String, BigDecimal> getSummary(String corpId, Date startDate, Date endDate, String departmentPath, String dataType) {
|
||||||
return departmentStatisticsDataMapper.getSummary(corpId, startDate, endDate, departmentPath);
|
return departmentStatisticsDataMapper.getSummary(corpId, startDate, endDate, departmentPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,12 @@
|
||||||
package com.ruoyi.excel.wecom.vo;
|
package com.ruoyi.excel.wecom.vo;
|
||||||
|
|
||||||
import com.alibaba.excel.annotation.ExcelProperty;
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
import com.alibaba.excel.annotation.format.DateTimeFormat;
|
|
||||||
import com.alibaba.excel.annotation.write.style.ColumnWidth;
|
import com.alibaba.excel.annotation.write.style.ColumnWidth;
|
||||||
import com.ruoyi.common.annotation.Excel;
|
import com.ruoyi.common.annotation.Excel;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流量看板数据VO
|
* 流量看板数据VO
|
||||||
|
|
@ -21,10 +19,9 @@ public class CustomerStatisticsDataVO implements Serializable {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@ExcelProperty("统计日期")
|
@ExcelProperty("统计日期")
|
||||||
@Excel(name ="日期",dateFormat = "yyyy-MM-dd")
|
@Excel(name ="日期")
|
||||||
@DateTimeFormat("yyyy-MM-dd")
|
|
||||||
@ColumnWidth(20)
|
@ColumnWidth(20)
|
||||||
private Date curDate;
|
private String curDate;
|
||||||
|
|
||||||
@ExcelProperty("重要指标")
|
@ExcelProperty("重要指标")
|
||||||
@Excel(name ="重要指标")
|
@Excel(name ="重要指标")
|
||||||
|
|
@ -85,4 +82,14 @@ public class CustomerStatisticsDataVO implements Serializable {
|
||||||
@Excel(name ="AE组(G1组)")
|
@Excel(name ="AE组(G1组)")
|
||||||
@ColumnWidth(15)
|
@ColumnWidth(15)
|
||||||
private String aeGroup;
|
private String aeGroup;
|
||||||
|
|
||||||
|
|
||||||
|
private String yearWeek;
|
||||||
|
|
||||||
|
private String yearMonth;
|
||||||
|
|
||||||
|
private String dateRange;
|
||||||
|
|
||||||
|
private Integer sortNo;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,4 +53,14 @@ public class DepartmentStatisticsDataVO implements Serializable {
|
||||||
@Excel(name ="非及时单占比(当日")
|
@Excel(name ="非及时单占比(当日")
|
||||||
@ColumnWidth(15)
|
@ColumnWidth(15)
|
||||||
private BigDecimal dailyNonTimelyOrderRatio;
|
private BigDecimal dailyNonTimelyOrderRatio;
|
||||||
|
|
||||||
|
@ExcelProperty("家长成单率(当日")
|
||||||
|
@Excel(name ="家长成单率(当日")
|
||||||
|
@ColumnWidth(15)
|
||||||
|
private BigDecimal dailyParentOrderRate;
|
||||||
|
|
||||||
|
@ExcelProperty("学生成单率(当日")
|
||||||
|
@Excel(name ="学生成单率(当日")
|
||||||
|
@ColumnWidth(15)
|
||||||
|
private BigDecimal dailyStudentOrderRate;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
*
|
*
|
||||||
FROM customer_statistics_data
|
FROM customer_statistics_data
|
||||||
<where>
|
<where>
|
||||||
corp_id = #{corpId}
|
corp_id = #{corpId} and hidden_flag = false
|
||||||
<if test="startDate != null">
|
<if test="startDate != null">
|
||||||
AND cur_date >= #{startDate}
|
AND cur_date >= #{startDate}
|
||||||
</if>
|
</if>
|
||||||
|
|
@ -48,4 +48,54 @@
|
||||||
ORDER BY cur_date DESC,sort_no
|
ORDER BY cur_date DESC,sort_no
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectDailyDataByWeek" resultType="com.ruoyi.excel.wecom.domain.CustomerStatisticsData">
|
||||||
|
SELECT * FROM customer_statistics_data
|
||||||
|
<where>
|
||||||
|
corp_id = #{corpId}
|
||||||
|
AND YEAR(cur_date) = #{year}
|
||||||
|
AND WEEK(cur_date, 1) = #{week}
|
||||||
|
<if test="indicatorName != null and indicatorName != ''">
|
||||||
|
AND indicator_name LIKE CONCAT('%', #{indicatorName}, '%')
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
ORDER BY cur_date, sort_no
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectDailyDataByMonth" resultType="com.ruoyi.excel.wecom.domain.CustomerStatisticsData">
|
||||||
|
SELECT * FROM customer_statistics_data
|
||||||
|
<where>
|
||||||
|
corp_id = #{corpId}
|
||||||
|
AND DATE_FORMAT(cur_date, '%Y-%m') = #{yearMonth}
|
||||||
|
<if test="indicatorName != null and indicatorName != ''">
|
||||||
|
AND indicator_name LIKE CONCAT('%', #{indicatorName}, '%')
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
ORDER BY cur_date, sort_no
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 调试查询:检查indicator_name是否有隐藏字符 -->
|
||||||
|
<select id="selectDebugIndicatorName" resultType="java.util.Map">
|
||||||
|
SELECT id, cur_date,
|
||||||
|
CONCAT('[', indicator_name, ']') as name_with_brackets,
|
||||||
|
LENGTH(indicator_name) as name_length
|
||||||
|
FROM customer_statistics_data
|
||||||
|
WHERE corp_id = #{corpId}
|
||||||
|
AND DATE_FORMAT(cur_date, '%Y-%m') = #{yearMonth}
|
||||||
|
<if test="indicatorName != null and indicatorName != ''">
|
||||||
|
AND indicator_name LIKE CONCAT('%', #{indicatorName}, '%')
|
||||||
|
</if>
|
||||||
|
ORDER BY cur_date
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectAllDailyData" resultType="com.ruoyi.excel.wecom.domain.CustomerStatisticsData">
|
||||||
|
SELECT * FROM customer_statistics_data
|
||||||
|
<where>
|
||||||
|
corp_id = #{corpId}
|
||||||
|
<if test="indicatorName != null and indicatorName != ''">
|
||||||
|
AND indicator_name LIKE CONCAT('%', #{indicatorName}, '%')
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
ORDER BY cur_date, sort_no
|
||||||
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,16 @@
|
||||||
daily_conversion_rate as dailyConversionRate,
|
daily_conversion_rate as dailyConversionRate,
|
||||||
daily_timely_order_ratio as dailyTimelyOrderRatio,
|
daily_timely_order_ratio as dailyTimelyOrderRatio,
|
||||||
daily_non_timely_order_ratio as dailyNonTimelyOrderRatio,
|
daily_non_timely_order_ratio as dailyNonTimelyOrderRatio,
|
||||||
|
CASE
|
||||||
|
WHEN parent_daily_count > 0
|
||||||
|
THEN ROUND(parent_daily_order_count * 100.0 / parent_daily_count, 2)
|
||||||
|
ELSE 0
|
||||||
|
END as dailyParentOrderRate,
|
||||||
|
CASE
|
||||||
|
WHEN student_daily_count > 0
|
||||||
|
THEN ROUND(student_daily_order_count * 100.0 / student_daily_count, 2)
|
||||||
|
ELSE 0
|
||||||
|
END as dailyStudentOrderRate,
|
||||||
sort_no as sortNo
|
sort_no as sortNo
|
||||||
FROM department_statistics_data
|
FROM department_statistics_data
|
||||||
<where>
|
<where>
|
||||||
|
|
@ -78,7 +88,27 @@
|
||||||
daily_conversion_rate as dailyConversionRate,
|
daily_conversion_rate as dailyConversionRate,
|
||||||
daily_timely_order_ratio as dailyTimelyOrderRatio,
|
daily_timely_order_ratio as dailyTimelyOrderRatio,
|
||||||
daily_non_timely_order_ratio as dailyNonTimelyOrderRatio,
|
daily_non_timely_order_ratio as dailyNonTimelyOrderRatio,
|
||||||
sort_no as sortNo
|
daily_timely_count as dailyTimelyCount,
|
||||||
|
daily_non_timely_count as dailyNonTimelyCount,
|
||||||
|
parent_daily_order_count as parentDailyOrderCount,
|
||||||
|
parent_daily_count as parentDailyCount,
|
||||||
|
student_daily_order_count as studentDailyOrderCount,
|
||||||
|
student_daily_count as studentDailyCount,
|
||||||
|
CASE
|
||||||
|
WHEN parent_daily_count > 0
|
||||||
|
THEN ROUND(parent_daily_order_count * 100.0 / parent_daily_count, 2)
|
||||||
|
ELSE 0
|
||||||
|
END as dailyParentOrderRate,
|
||||||
|
CASE
|
||||||
|
WHEN student_daily_count > 0
|
||||||
|
THEN ROUND(student_daily_order_count * 100.0 / student_daily_count, 2)
|
||||||
|
ELSE 0
|
||||||
|
END as dailyStudentOrderRate,
|
||||||
|
person_flag as personFlag,
|
||||||
|
corp_name as corpName,
|
||||||
|
department_name as departmentName,
|
||||||
|
group_name as groupName,
|
||||||
|
person_name as personName
|
||||||
FROM department_statistics_data
|
FROM department_statistics_data
|
||||||
<where>
|
<where>
|
||||||
corp_id = #{corpId}
|
corp_id = #{corpId}
|
||||||
|
|
@ -100,7 +130,7 @@
|
||||||
sum(ifnull(daily_total_accepted,0)+ifnull(manager_accepted,0)) as totalIns
|
sum(ifnull(daily_total_accepted,0)+ifnull(manager_accepted,0)) as totalIns
|
||||||
from department_statistics_data
|
from department_statistics_data
|
||||||
<where>
|
<where>
|
||||||
corp_id = #{corpId}
|
corp_id = #{corpId} and person_flag = true
|
||||||
<if test="startDate != null">
|
<if test="startDate != null">
|
||||||
AND stat_date >= #{startDate}
|
AND stat_date >= #{startDate}
|
||||||
</if>
|
</if>
|
||||||
|
|
@ -113,4 +143,112 @@
|
||||||
</where>
|
</where>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectDepartmentStatisticsDataAggregatedList"
|
||||||
|
resultType="com.ruoyi.excel.wecom.domain.DepartmentStatisticsData">
|
||||||
|
SELECT
|
||||||
|
department_path as departmentPath,
|
||||||
|
SUM(daily_total_accepted) as dailyTotalAccepted,
|
||||||
|
SUM(daily_total_orders) as dailyTotalOrders,
|
||||||
|
CASE
|
||||||
|
WHEN SUM(daily_total_accepted) > 0
|
||||||
|
THEN ROUND(SUM(daily_total_orders) * 100.0 / SUM(daily_total_accepted), 2)
|
||||||
|
ELSE 0
|
||||||
|
END as dailyConversionRate,
|
||||||
|
CASE
|
||||||
|
WHEN SUM(daily_total_orders) > 0
|
||||||
|
THEN ROUND(SUM(IFNULL(daily_timely_count, 0)) * 100.0 / SUM(daily_total_orders), 2)
|
||||||
|
ELSE 0
|
||||||
|
END as dailyTimelyOrderRatio,
|
||||||
|
CASE
|
||||||
|
WHEN SUM(daily_total_orders) > 0
|
||||||
|
THEN ROUND(SUM(IFNULL(daily_non_timely_count, 0)) * 100.0 / SUM(daily_total_orders), 2)
|
||||||
|
ELSE 0
|
||||||
|
END as dailyNonTimelyOrderRatio,
|
||||||
|
SUM(IFNULL(daily_timely_count, 0)) as dailyTimelyCount,
|
||||||
|
SUM(IFNULL(daily_non_timely_count, 0)) as dailyNonTimelyCount,
|
||||||
|
SUM(IFNULL(parent_daily_order_count, 0)) as parentDailyOrderCount,
|
||||||
|
SUM(IFNULL(parent_daily_count, 0)) as parentDailyCount,
|
||||||
|
SUM(IFNULL(student_daily_order_count, 0)) as studentDailyOrderCount,
|
||||||
|
SUM(IFNULL(student_daily_count, 0)) as studentDailyCount,
|
||||||
|
CASE
|
||||||
|
WHEN SUM(IFNULL(parent_daily_count, 0)) > 0
|
||||||
|
THEN ROUND(SUM(IFNULL(parent_daily_order_count, 0)) * 100.0 / SUM(IFNULL(parent_daily_count, 0)), 2)
|
||||||
|
ELSE 0
|
||||||
|
END as dailyParentOrderRate,
|
||||||
|
CASE
|
||||||
|
WHEN SUM(IFNULL(student_daily_count, 0)) > 0
|
||||||
|
THEN ROUND(SUM(IFNULL(student_daily_order_count, 0)) * 100.0 / SUM(IFNULL(student_daily_count, 0)), 2)
|
||||||
|
ELSE 0
|
||||||
|
END as dailyStudentOrderRate,
|
||||||
|
person_flag as personFlag,
|
||||||
|
corp_name as corpName,
|
||||||
|
department_name as departmentName,
|
||||||
|
group_name as groupName,
|
||||||
|
person_name as personName,
|
||||||
|
MIN(sort_no) as sortNo
|
||||||
|
FROM department_statistics_data
|
||||||
|
<where>
|
||||||
|
corp_id = #{corpId}
|
||||||
|
<if test="startDate != null">
|
||||||
|
AND stat_date >= #{startDate}
|
||||||
|
</if>
|
||||||
|
<if test="endDate != null">
|
||||||
|
AND stat_date <= #{endDate}
|
||||||
|
</if>
|
||||||
|
<if test="departmentPath != null and departmentPath != ''">
|
||||||
|
AND department_path LIKE CONCAT(#{departmentPath}, '%')
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
GROUP BY department_path, person_flag, corp_name, department_name, group_name, person_name
|
||||||
|
ORDER BY department_path, sortNo
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectDepartmentStatisticsDataVOAggregatedList" resultType="com.ruoyi.excel.wecom.vo.DepartmentStatisticsDataVO">
|
||||||
|
SELECT
|
||||||
|
department_path as departmentPath,
|
||||||
|
SUM(daily_total_accepted) as dailyTotalAccepted,
|
||||||
|
SUM(daily_total_orders) as dailyTotalOrders,
|
||||||
|
CASE
|
||||||
|
WHEN SUM(daily_total_accepted) > 0
|
||||||
|
THEN ROUND(SUM(daily_total_orders) * 100.0 / SUM(daily_total_accepted), 2)
|
||||||
|
ELSE 0
|
||||||
|
END as dailyConversionRate,
|
||||||
|
CASE
|
||||||
|
WHEN SUM(daily_total_orders) > 0
|
||||||
|
THEN ROUND(SUM(IFNULL(daily_timely_count, 0)) * 100.0 / SUM(daily_total_orders), 2)
|
||||||
|
ELSE 0
|
||||||
|
END as dailyTimelyOrderRatio,
|
||||||
|
CASE
|
||||||
|
WHEN SUM(daily_total_orders) > 0
|
||||||
|
THEN ROUND(SUM(IFNULL(daily_non_timely_count, 0)) * 100.0 / SUM(daily_total_orders), 2)
|
||||||
|
ELSE 0
|
||||||
|
END as dailyNonTimelyOrderRatio,
|
||||||
|
CASE
|
||||||
|
WHEN SUM(IFNULL(parent_daily_count, 0)) > 0
|
||||||
|
THEN ROUND(SUM(IFNULL(parent_daily_order_count, 0)) * 100.0 / SUM(IFNULL(parent_daily_count, 0)), 2)
|
||||||
|
ELSE 0
|
||||||
|
END as dailyParentOrderRate,
|
||||||
|
CASE
|
||||||
|
WHEN SUM(IFNULL(student_daily_count, 0)) > 0
|
||||||
|
THEN ROUND(SUM(IFNULL(student_daily_order_count, 0)) * 100.0 / SUM(IFNULL(student_daily_count, 0)), 2)
|
||||||
|
ELSE 0
|
||||||
|
END as dailyStudentOrderRate,
|
||||||
|
MIN(sort_no) as sortNo
|
||||||
|
FROM department_statistics_data
|
||||||
|
<where>
|
||||||
|
corp_id = #{corpId}
|
||||||
|
<if test="startDate != null">
|
||||||
|
AND stat_date >= #{startDate}
|
||||||
|
</if>
|
||||||
|
<if test="endDate != null">
|
||||||
|
AND stat_date <= #{endDate}
|
||||||
|
</if>
|
||||||
|
<if test="departmentPath != null and departmentPath != ''">
|
||||||
|
AND department_path LIKE CONCAT(#{departmentPath}, '%')
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
GROUP BY department_path
|
||||||
|
ORDER BY department_path, sortNo
|
||||||
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import com.ruoyi.common.core.page.TableDataInfo;
|
||||||
import com.ruoyi.common.enums.BusinessType;
|
import com.ruoyi.common.enums.BusinessType;
|
||||||
import com.ruoyi.common.utils.CorpContextHolder;
|
import com.ruoyi.common.utils.CorpContextHolder;
|
||||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||||
import com.ruoyi.excel.wecom.domain.CustomerStatisticsData;
|
|
||||||
import com.ruoyi.excel.wecom.service.ICustomerStatisticsDataService;
|
import com.ruoyi.excel.wecom.service.ICustomerStatisticsDataService;
|
||||||
import com.ruoyi.excel.wecom.vo.CustomerStatisticsDataVO;
|
import com.ruoyi.excel.wecom.vo.CustomerStatisticsDataVO;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
@ -36,14 +35,30 @@ public class CustomerStatisticsDataController extends BaseController {
|
||||||
@PreAuthorize("@ss.hasPermi('wecom:customerStatistics:list')")
|
@PreAuthorize("@ss.hasPermi('wecom:customerStatistics:list')")
|
||||||
@GetMapping("/list")
|
@GetMapping("/list")
|
||||||
public TableDataInfo list(
|
public TableDataInfo list(
|
||||||
|
@RequestParam(value = "dataType", required = false) String dataType,
|
||||||
|
@RequestParam(value = "year", required = false) Integer year,
|
||||||
|
@RequestParam(value = "week", required = false) Integer week,
|
||||||
|
@RequestParam(value = "yearMonth", required = false) String yearMonth,
|
||||||
@RequestParam(value = "startDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate,
|
@RequestParam(value = "startDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate,
|
||||||
@RequestParam(value = "endDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate,
|
@RequestParam(value = "endDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate,
|
||||||
@RequestParam(value = "indicatorName", required = false) String indicatorName) {
|
@RequestParam(value = "indicatorName", required = false) String indicatorName) {
|
||||||
String corpId = CorpContextHolder.getCurrentCorpId();
|
String corpId = CorpContextHolder.getCurrentCorpId();
|
||||||
|
|
||||||
startPage();
|
List<CustomerStatisticsDataVO> list;
|
||||||
List<CustomerStatisticsData> list = customerStatisticsDataService.selectCustomerStatisticsDataList(corpId,startDate, endDate, indicatorName);
|
if ("week".equals(dataType)) {
|
||||||
|
list = customerStatisticsDataService.selectByWeekAggregation(corpId, year, week, indicatorName);
|
||||||
return getDataTable(list);
|
return getDataTable(list);
|
||||||
|
} else if ("month".equals(dataType)) {
|
||||||
|
list = customerStatisticsDataService.selectByMonthAggregation(corpId, yearMonth, indicatorName);
|
||||||
|
return getDataTable(list);
|
||||||
|
} else if ("all".equals(dataType)) {
|
||||||
|
list = customerStatisticsDataService.selectAllAggregation(corpId, indicatorName);
|
||||||
|
return getDataTable(list);
|
||||||
|
} else {
|
||||||
|
startPage();
|
||||||
|
list = customerStatisticsDataService.selectCustomerStatisticsDataVOList(corpId, startDate, endDate, indicatorName);
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -53,14 +68,28 @@ public class CustomerStatisticsDataController extends BaseController {
|
||||||
@Log(title = "客户统计数据", businessType = BusinessType.EXPORT)
|
@Log(title = "客户统计数据", businessType = BusinessType.EXPORT)
|
||||||
@PostMapping("/export")
|
@PostMapping("/export")
|
||||||
public void export(HttpServletResponse response,
|
public void export(HttpServletResponse response,
|
||||||
|
@RequestParam(value = "dataType", required = false) String dataType,
|
||||||
|
@RequestParam(value = "year", required = false) Integer year,
|
||||||
|
@RequestParam(value = "week", required = false) Integer week,
|
||||||
|
@RequestParam(value = "yearMonth", required = false) String yearMonth,
|
||||||
@RequestParam(value = "startDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate,
|
@RequestParam(value = "startDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate,
|
||||||
@RequestParam(value = "endDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate,
|
@RequestParam(value = "endDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate,
|
||||||
@RequestParam(value = "indicatorName", required = false) String indicatorName) {
|
@RequestParam(value = "indicatorName", required = false) String indicatorName) {
|
||||||
String corpId = CorpContextHolder.getCurrentCorpId();
|
String corpId = CorpContextHolder.getCurrentCorpId();
|
||||||
|
|
||||||
List<CustomerStatisticsDataVO> list = customerStatisticsDataService.selectCustomerStatisticsDataVOList(corpId,startDate, endDate, indicatorName);
|
List<CustomerStatisticsDataVO> dataList;
|
||||||
|
if ("week".equals(dataType)) {
|
||||||
|
dataList = customerStatisticsDataService.selectByWeekAggregation(corpId, year, week, indicatorName);
|
||||||
|
} else if ("month".equals(dataType)) {
|
||||||
|
dataList = customerStatisticsDataService.selectByMonthAggregation(corpId, yearMonth, indicatorName);
|
||||||
|
} else if ("all".equals(dataType)) {
|
||||||
|
dataList = customerStatisticsDataService.selectAllAggregation(corpId, indicatorName);
|
||||||
|
} else {
|
||||||
|
dataList = customerStatisticsDataService.selectCustomerStatisticsDataVOList(corpId, startDate, endDate, indicatorName);
|
||||||
|
}
|
||||||
|
|
||||||
ExcelUtil<CustomerStatisticsDataVO> util = new ExcelUtil<>(CustomerStatisticsDataVO.class);
|
ExcelUtil<CustomerStatisticsDataVO> util = new ExcelUtil<>(CustomerStatisticsDataVO.class);
|
||||||
util.exportExcel(response, list, "流量看板数据");
|
util.exportExcel(response, dataList, "流量看板数据");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -80,10 +109,11 @@ public class CustomerStatisticsDataController extends BaseController {
|
||||||
@Log(title = "客户统计数据", businessType = BusinessType.UPDATE)
|
@Log(title = "客户统计数据", businessType = BusinessType.UPDATE)
|
||||||
@PutMapping
|
@PutMapping
|
||||||
public AjaxResult edit(@RequestParam(value = "curDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date curDate,
|
public AjaxResult edit(@RequestParam(value = "curDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date curDate,
|
||||||
@RequestParam(value = "totalCost")BigDecimal totalCost,
|
@RequestParam(value = "cost")BigDecimal cost,
|
||||||
|
@RequestParam(value = "type")String type,
|
||||||
@RequestParam(value = "attr")String attr) {
|
@RequestParam(value = "attr")String attr) {
|
||||||
String corpId = CorpContextHolder.getCurrentCorpId();
|
String corpId = CorpContextHolder.getCurrentCorpId();
|
||||||
return toAjax(customerStatisticsDataService.updateCost(corpId,curDate,totalCost,attr));
|
return toAjax(customerStatisticsDataService.updateCost(corpId,curDate,cost,type,attr));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,9 @@ import org.springframework.web.bind.annotation.*;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
@ -40,11 +42,19 @@ public class DepartmentStatisticsDataController extends BaseController {
|
||||||
public TableDataInfo list(
|
public TableDataInfo list(
|
||||||
@RequestParam(value = "startDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate,
|
@RequestParam(value = "startDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate,
|
||||||
@RequestParam(value = "endDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate,
|
@RequestParam(value = "endDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate,
|
||||||
@RequestParam(value = "departmentPath", required = false) String departmentPath) {
|
@RequestParam(value = "departmentPath", required = false) String departmentPath,
|
||||||
|
@RequestParam(value = "dataType", required = false) String dataType,
|
||||||
|
@RequestParam(value = "year", required = false) Integer year,
|
||||||
|
@RequestParam(value = "week", required = false) Integer week,
|
||||||
|
@RequestParam(value = "month", required = false) Integer month) {
|
||||||
String corpId = CorpContextHolder.getCurrentCorpId();
|
String corpId = CorpContextHolder.getCurrentCorpId();
|
||||||
|
|
||||||
|
Date[] dateRange = calculateDateRange(dataType, year, week, month, startDate, endDate);
|
||||||
|
startDate = dateRange[0];
|
||||||
|
endDate = dateRange[1];
|
||||||
|
|
||||||
startPage();
|
startPage();
|
||||||
List<DepartmentStatisticsData> list = departmentStatisticsDataService.selectDepartmentStatisticsDataList(corpId,startDate, endDate, departmentPath);
|
List<DepartmentStatisticsData> list = departmentStatisticsDataService.selectDepartmentStatisticsDataList(corpId, startDate, endDate, departmentPath, dataType);
|
||||||
return getDataTable(list);
|
return getDataTable(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,10 +67,18 @@ public class DepartmentStatisticsDataController extends BaseController {
|
||||||
public void export(HttpServletResponse response,
|
public void export(HttpServletResponse response,
|
||||||
@RequestParam(value = "startDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate,
|
@RequestParam(value = "startDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate,
|
||||||
@RequestParam(value = "endDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate,
|
@RequestParam(value = "endDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate,
|
||||||
@RequestParam(value = "departmentPath", required = false) String departmentPath) {
|
@RequestParam(value = "departmentPath", required = false) String departmentPath,
|
||||||
|
@RequestParam(value = "dataType", required = false) String dataType,
|
||||||
|
@RequestParam(value = "year", required = false) Integer year,
|
||||||
|
@RequestParam(value = "week", required = false) Integer week,
|
||||||
|
@RequestParam(value = "month", required = false) Integer month) {
|
||||||
String corpId = CorpContextHolder.getCurrentCorpId();
|
String corpId = CorpContextHolder.getCurrentCorpId();
|
||||||
|
|
||||||
List<DepartmentStatisticsDataVO> list = departmentStatisticsDataService.selectDepartmentStatisticsDataVOList(corpId,startDate, endDate, departmentPath);
|
Date[] dateRange = calculateDateRange(dataType, year, week, month, startDate, endDate);
|
||||||
|
startDate = dateRange[0];
|
||||||
|
endDate = dateRange[1];
|
||||||
|
|
||||||
|
List<DepartmentStatisticsDataVO> list = departmentStatisticsDataService.selectDepartmentStatisticsDataVOList(corpId, startDate, endDate, departmentPath, dataType);
|
||||||
ExcelUtil<DepartmentStatisticsDataVO> util = new ExcelUtil<>(DepartmentStatisticsDataVO.class);
|
ExcelUtil<DepartmentStatisticsDataVO> util = new ExcelUtil<>(DepartmentStatisticsDataVO.class);
|
||||||
util.exportExcel(response, list, "销售看板数据");
|
util.exportExcel(response, list, "销售看板数据");
|
||||||
}
|
}
|
||||||
|
|
@ -83,10 +101,21 @@ public class DepartmentStatisticsDataController extends BaseController {
|
||||||
public AjaxResult summary(
|
public AjaxResult summary(
|
||||||
@RequestParam(value = "startDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate,
|
@RequestParam(value = "startDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate,
|
||||||
@RequestParam(value = "endDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate,
|
@RequestParam(value = "endDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate,
|
||||||
@RequestParam(value = "departmentPath", required = false) String departmentPath) {
|
@RequestParam(value = "departmentPath", required = false) String departmentPath,
|
||||||
|
@RequestParam(value = "dataType", required = false) String dataType,
|
||||||
|
@RequestParam(value = "year", required = false) Integer year,
|
||||||
|
@RequestParam(value = "week", required = false) Integer week,
|
||||||
|
@RequestParam(value = "month", required = false) Integer month) {
|
||||||
String corpId = CorpContextHolder.getCurrentCorpId();
|
String corpId = CorpContextHolder.getCurrentCorpId();
|
||||||
|
|
||||||
Map<String, BigDecimal> map = departmentStatisticsDataService.getSummary(corpId,startDate, endDate, departmentPath);
|
Date[] dateRange = calculateDateRange(dataType, year, week, month, startDate, endDate);
|
||||||
|
startDate = dateRange[0];
|
||||||
|
endDate = dateRange[1];
|
||||||
|
|
||||||
|
Map<String, BigDecimal> map = departmentStatisticsDataService.getSummary(corpId, startDate, endDate, departmentPath, dataType);
|
||||||
|
if(map == null) {
|
||||||
|
return success(new HashMap<>());
|
||||||
|
}
|
||||||
BigDecimal totalOrders = map.get("totalOrders");
|
BigDecimal totalOrders = map.get("totalOrders");
|
||||||
BigDecimal totalIns = map.get("totalIns");
|
BigDecimal totalIns = map.get("totalIns");
|
||||||
if(totalOrders == null) {
|
if(totalOrders == null) {
|
||||||
|
|
@ -104,4 +133,60 @@ public class DepartmentStatisticsDataController extends BaseController {
|
||||||
}
|
}
|
||||||
return success(map);
|
return success(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据数据类型计算日期范围
|
||||||
|
* @param dataType 数据类型:week/month/all
|
||||||
|
* @param year 年份
|
||||||
|
* @param week 周数(1-53)
|
||||||
|
* @param month 月份(1-12)
|
||||||
|
* @param startDate 原始开始日期
|
||||||
|
* @param endDate 原始结束日期
|
||||||
|
* @return 日期数组[startDate, endDate]
|
||||||
|
*/
|
||||||
|
private Date[] calculateDateRange(String dataType, Integer year, Integer week, Integer month, Date startDate, Date endDate) {
|
||||||
|
if (dataType == null || dataType.isEmpty()) {
|
||||||
|
return new Date[]{startDate, endDate};
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("all".equals(dataType)) {
|
||||||
|
return new Date[]{null, null};
|
||||||
|
}
|
||||||
|
|
||||||
|
Calendar cal = Calendar.getInstance();
|
||||||
|
|
||||||
|
if ("week".equals(dataType) && year != null && week != null) {
|
||||||
|
cal.set(Calendar.YEAR, year);
|
||||||
|
cal.set(Calendar.WEEK_OF_YEAR, week);
|
||||||
|
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
|
||||||
|
cal.set(Calendar.HOUR_OF_DAY, 0);
|
||||||
|
cal.set(Calendar.MINUTE, 0);
|
||||||
|
cal.set(Calendar.SECOND, 0);
|
||||||
|
cal.set(Calendar.MILLISECOND, 0);
|
||||||
|
startDate = cal.getTime();
|
||||||
|
|
||||||
|
cal.add(Calendar.DAY_OF_MONTH, 6);
|
||||||
|
endDate = cal.getTime();
|
||||||
|
|
||||||
|
return new Date[]{startDate, endDate};
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("month".equals(dataType) && year != null && month != null) {
|
||||||
|
cal.set(Calendar.YEAR, year);
|
||||||
|
cal.set(Calendar.MONTH, month - 1);
|
||||||
|
cal.set(Calendar.DAY_OF_MONTH, 1);
|
||||||
|
cal.set(Calendar.HOUR_OF_DAY, 0);
|
||||||
|
cal.set(Calendar.MINUTE, 0);
|
||||||
|
cal.set(Calendar.SECOND, 0);
|
||||||
|
cal.set(Calendar.MILLISECOND, 0);
|
||||||
|
startDate = cal.getTime();
|
||||||
|
|
||||||
|
cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
|
||||||
|
endDate = cal.getTime();
|
||||||
|
|
||||||
|
return new Date[]{startDate, endDate};
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Date[]{startDate, endDate};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,13 +27,14 @@ export function addCustomerStatistics(data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改客户统计数据
|
// 修改客户统计数据
|
||||||
export function updateCustomerStatistics(date,cost,attr) {
|
export function updateCustomerStatistics(date,cost,attr,type) {
|
||||||
return request({
|
return request({
|
||||||
url: '/wecom/customerStatistics',
|
url: '/wecom/customerStatistics',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
params: {
|
params: {
|
||||||
curDate: date,
|
curDate: date,
|
||||||
totalCost: cost,
|
cost: cost,
|
||||||
|
type: type,
|
||||||
attr: attr
|
attr: attr
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,52 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80px">
|
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80px">
|
||||||
<el-form-item label="开始日期" prop="startDate">
|
<el-form-item label="数据类型" prop="dataType">
|
||||||
|
<el-select
|
||||||
|
v-model="queryParams.dataType"
|
||||||
|
placeholder="请选择数据类型"
|
||||||
|
clearable
|
||||||
|
@change="handleDataTypeChange"
|
||||||
|
>
|
||||||
|
<el-option label="按天查询" value="day" />
|
||||||
|
<el-option label="自然周叠加数据" value="week" />
|
||||||
|
<el-option label="自然月叠加数据" value="month" />
|
||||||
|
<el-option label="所有数据" value="all" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item v-if="queryParams.dataType === 'week'" label="年份" prop="year">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="queryParams.year"
|
||||||
|
type="year"
|
||||||
|
placeholder="选择年份"
|
||||||
|
value-format="yyyy"
|
||||||
|
style="width: 120px"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item v-if="queryParams.dataType === 'week'" label="周数" prop="week">
|
||||||
|
<el-select
|
||||||
|
v-model="queryParams.week"
|
||||||
|
placeholder="选择周数"
|
||||||
|
clearable
|
||||||
|
style="width: 120px"
|
||||||
|
>
|
||||||
|
<el-option v-for="i in 53" :key="i" :label="'第' + i + '周'" :value="i" />
|
||||||
|
</el-select>
|
||||||
|
<span v-if="weekDateRange" style="margin-left: 10px; color: #909399; font-size: 12px;">{{ weekDateRange }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item v-if="queryParams.dataType === 'month'" label="年月" prop="yearMonth">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="queryParams.yearMonth"
|
||||||
|
type="month"
|
||||||
|
placeholder="选择年月"
|
||||||
|
value-format="yyyy-MM"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item v-if="queryParams.dataType === 'day' || !queryParams.dataType" label="开始日期" prop="startDate">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-model="queryParams.startDate"
|
v-model="queryParams.startDate"
|
||||||
type="date"
|
type="date"
|
||||||
|
|
@ -10,7 +55,7 @@
|
||||||
clearable
|
clearable
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="结束日期" prop="endDate">
|
<el-form-item v-if="queryParams.dataType === 'day' || !queryParams.dataType" label="结束日期" prop="endDate">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-model="queryParams.endDate"
|
v-model="queryParams.endDate"
|
||||||
type="date"
|
type="date"
|
||||||
|
|
@ -49,22 +94,32 @@
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="日期" align="center" prop="curDate" width="120">
|
<el-table-column label="日期" align="center" width="180">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<span>{{ parseTime(scope.row.curDate, '{y}-{m}-{d}') }}</span>
|
<div v-if="queryParams.dataType === 'week'">
|
||||||
|
<div>{{ scope.row.yearWeek }}</div>
|
||||||
|
<div style="color: #909399; font-size: 12px;">{{ scope.row.dateRange }}</div>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="queryParams.dataType === 'month'">
|
||||||
|
<div>{{ scope.row.yearMonth }}</div>
|
||||||
|
<div style="color: #909399; font-size: 12px;">{{ scope.row.dateRange }}</div>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="queryParams.dataType === 'all'">
|
||||||
|
<span>全部数据</span>
|
||||||
|
</div>
|
||||||
|
<span v-else>{{ parseTime(scope.row.curDate, '{y}-{m}-{d}') }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="重要指标" align="center" prop="indicatorName" width="180" :show-overflow-tooltip="true" />
|
<el-table-column label="重要指标" align="center" prop="indicatorName" width="180" :show-overflow-tooltip="true" />
|
||||||
<el-table-column label="N组(投放)" align="center" prop="ntfGroup" width="100">
|
<el-table-column label="N组(投放)" align="center" prop="ntfGroup" width="100">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
v-if="scope.row.indicatorName === '总成本(当日)'"
|
v-if="canEditCost(scope.row)"
|
||||||
v-model="scope.row.ntfGroup"
|
v-model="scope.row.ntfGroup"
|
||||||
size="mini"
|
size="mini"
|
||||||
:controls="false"
|
:controls="false"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@blur="handleUpdateCost(scope.row.curDate,scope.row.ntfGroup,'ntfGroup')"
|
@keyup.enter.native="handleUpdateCost(scope.row,scope.row.ntfGroup,'ntfGroup')"
|
||||||
@keyup.enter.native="handleUpdateCost(scope.row.curDate,scope.row.ntfGroup,'ntfGroup')"
|
|
||||||
/>
|
/>
|
||||||
<span v-else>{{ scope.row.ntfGroup }}</span>
|
<span v-else>{{ scope.row.ntfGroup }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -72,13 +127,12 @@
|
||||||
<el-table-column label="O组(公司孵化)" align="center" prop="ofhGroup" width="120">
|
<el-table-column label="O组(公司孵化)" align="center" prop="ofhGroup" width="120">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
v-if="scope.row.indicatorName === '总成本(当日)'"
|
v-if="canEditCost(scope.row)"
|
||||||
v-model="scope.row.ofhGroup"
|
v-model="scope.row.ofhGroup"
|
||||||
size="mini"
|
size="mini"
|
||||||
:controls="false"
|
:controls="false"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@blur="handleUpdateCost(scope.row.curDate,scope.row.ofhGroup,'ofhGroup')"
|
@keyup.enter.native="handleUpdateCost(scope.row,scope.row.ofhGroup,'ofhGroup')"
|
||||||
@keyup.enter.native="handleUpdateCost(scope.row.curDate,scope.row.ofhGroup,'ofhGroup')"
|
|
||||||
/>
|
/>
|
||||||
<span v-else>{{ scope.row.ofhGroup }}</span>
|
<span v-else>{{ scope.row.ofhGroup }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -86,13 +140,12 @@
|
||||||
<el-table-column label="P组(商务)" align="center" prop="pswGroup" width="120">
|
<el-table-column label="P组(商务)" align="center" prop="pswGroup" width="120">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
v-if="scope.row.indicatorName === '总成本(当日)'"
|
v-if="canEditCost(scope.row)"
|
||||||
v-model="scope.row.pswGroup"
|
v-model="scope.row.pswGroup"
|
||||||
size="mini"
|
size="mini"
|
||||||
:controls="false"
|
:controls="false"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@blur="handleUpdateCost(scope.row.curDate,scope.row.pswGroup,'pswGroup')"
|
@keyup.enter.native="handleUpdateCost(scope.row,scope.row.pswGroup,'pswGroup')"
|
||||||
@keyup.enter.native="handleUpdateCost(scope.row.curDate,scope.row.pswGroup,'pswGroup')"
|
|
||||||
/>
|
/>
|
||||||
<span v-else>{{ scope.row.pswGroup }}</span>
|
<span v-else>{{ scope.row.pswGroup }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -100,13 +153,12 @@
|
||||||
<el-table-column label="W组(A1组)" align="center" prop="wa1Group" width="120">
|
<el-table-column label="W组(A1组)" align="center" prop="wa1Group" width="120">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
v-if="scope.row.indicatorName === '总成本(当日)'"
|
v-if="canEditCost(scope.row)"
|
||||||
v-model="scope.row.wa1Group"
|
v-model="scope.row.wa1Group"
|
||||||
size="mini"
|
size="mini"
|
||||||
:controls="false"
|
:controls="false"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@blur="handleUpdateCost(scope.row.curDate,scope.row.wa1Group,'wa1Group')"
|
@keyup.enter.native="handleUpdateCost(scope.row,scope.row.wa1Group,'wa1Group')"
|
||||||
@keyup.enter.native="handleUpdateCost(scope.row.curDate,scope.row.wa1Group,'wa1Group')"
|
|
||||||
/>
|
/>
|
||||||
<span v-else>{{ scope.row.wa1Group }}</span>
|
<span v-else>{{ scope.row.wa1Group }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -114,13 +166,12 @@
|
||||||
<el-table-column label="X组(B1组)" align="center" prop="xb1Group" width="120">
|
<el-table-column label="X组(B1组)" align="center" prop="xb1Group" width="120">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
v-if="scope.row.indicatorName === '总成本(当日)'"
|
v-if="canEditCost(scope.row)"
|
||||||
v-model="scope.row.xb1Group"
|
v-model="scope.row.xb1Group"
|
||||||
size="mini"
|
size="mini"
|
||||||
:controls="false"
|
:controls="false"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@blur="handleUpdateCost(scope.row.curDate,scope.row.xb1Group,'xb1Group')"
|
@keyup.enter.native="handleUpdateCost(scope.row,scope.row.xb1Group,'xb1Group')"
|
||||||
@keyup.enter.native="handleUpdateCost(scope.row.curDate,scope.row.xb1Group,'xb1Group')"
|
|
||||||
/>
|
/>
|
||||||
<span v-else>{{ scope.row.xb1Group }}</span>
|
<span v-else>{{ scope.row.xb1Group }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -128,13 +179,12 @@
|
||||||
<el-table-column label="Y组(C1组)" align="center" prop="yc1Group" width="120">
|
<el-table-column label="Y组(C1组)" align="center" prop="yc1Group" width="120">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
v-if="scope.row.indicatorName === '总成本(当日)'"
|
v-if="canEditCost(scope.row)"
|
||||||
v-model="scope.row.yc1Group"
|
v-model="scope.row.yc1Group"
|
||||||
size="mini"
|
size="mini"
|
||||||
:controls="false"
|
:controls="false"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@blur="handleUpdateCost(scope.row.curDate,scope.row.yc1Group,'yc1Group')"
|
@keyup.enter.native="handleUpdateCost(scope.row,scope.row.yc1Group,'yc1Group')"
|
||||||
@keyup.enter.native="handleUpdateCost(scope.row.curDate,scope.row.yc1Group,'yc1Group')"
|
|
||||||
/>
|
/>
|
||||||
<span v-else>{{ scope.row.yc1Group }}</span>
|
<span v-else>{{ scope.row.yc1Group }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -142,13 +192,12 @@
|
||||||
<el-table-column label="Z组(D1组)" align="center" prop="zd1Group" width="120">
|
<el-table-column label="Z组(D1组)" align="center" prop="zd1Group" width="120">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
v-if="scope.row.indicatorName === '总成本(当日)'"
|
v-if="canEditCost(scope.row)"
|
||||||
v-model="scope.row.zd1Group"
|
v-model="scope.row.zd1Group"
|
||||||
size="mini"
|
size="mini"
|
||||||
:controls="false"
|
:controls="false"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@blur="handleUpdateCost(scope.row.curDate,scope.row.zd1Group,'zd1Group')"
|
@keyup.enter.native="handleUpdateCost(scope.row,scope.row.zd1Group,'zd1Group')"
|
||||||
@keyup.enter.native="handleUpdateCost(scope.row.curDate,scope.row.zd1Group,'zd1Group')"
|
|
||||||
/>
|
/>
|
||||||
<span v-else>{{ scope.row.zd1Group }}</span>
|
<span v-else>{{ scope.row.zd1Group }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -156,13 +205,12 @@
|
||||||
<el-table-column label="AA组(E1组)" align="center" prop="aaGroup" width="120">
|
<el-table-column label="AA组(E1组)" align="center" prop="aaGroup" width="120">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
v-if="scope.row.indicatorName === '总成本(当日)'"
|
v-if="canEditCost(scope.row)"
|
||||||
v-model="scope.row.aaGroup"
|
v-model="scope.row.aaGroup"
|
||||||
size="mini"
|
size="mini"
|
||||||
:controls="false"
|
:controls="false"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@blur="handleUpdateCost(scope.row.curDate,scope.row.aaGroup,'aaGroup')"
|
@keyup.enter.native="handleUpdateCost(scope.row,scope.row.aaGroup,'aaGroup')"
|
||||||
@keyup.enter.native="handleUpdateCost(scope.row.curDate,scope.row.aaGroup,'aaGroup')"
|
|
||||||
/>
|
/>
|
||||||
<span v-else>{{ scope.row.aaGroup }}</span>
|
<span v-else>{{ scope.row.aaGroup }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -170,13 +218,12 @@
|
||||||
<el-table-column label="AC组(自然流)" align="center" prop="acGroup" width="120">
|
<el-table-column label="AC组(自然流)" align="center" prop="acGroup" width="120">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
v-if="scope.row.indicatorName === '总成本(当日)'"
|
v-if="canEditCost(scope.row)"
|
||||||
v-model="scope.row.acGroup"
|
v-model="scope.row.acGroup"
|
||||||
size="mini"
|
size="mini"
|
||||||
:controls="false"
|
:controls="false"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@blur="handleUpdateCost(scope.row.curDate,scope.row.acGroup,'acGroup')"
|
@keyup.enter.native="handleUpdateCost(scope.row,scope.row.acGroup,'acGroup')"
|
||||||
@keyup.enter.native="handleUpdateCost(scope.row.curDate,scope.row.acGroup,'acGroup')"
|
|
||||||
/>
|
/>
|
||||||
<span v-else>{{ scope.row.acGroup }}</span>
|
<span v-else>{{ scope.row.acGroup }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -184,13 +231,12 @@
|
||||||
<el-table-column label="AD组(F1组)" align="center" prop="adGroup" width="120">
|
<el-table-column label="AD组(F1组)" align="center" prop="adGroup" width="120">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
v-if="scope.row.indicatorName === '总成本(当日)'"
|
v-if="canEditCost(scope.row)"
|
||||||
v-model="scope.row.adGroup"
|
v-model="scope.row.adGroup"
|
||||||
size="mini"
|
size="mini"
|
||||||
:controls="false"
|
:controls="false"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@blur="handleUpdateCost(scope.row.curDate,scope.row.adGroup,'adGroup')"
|
@keyup.enter.native="handleUpdateCost(scope.row,scope.row.adGroup,'adGroup')"
|
||||||
@keyup.enter.native="handleUpdateCost(scope.row.curDate,scope.row.adGroup,'adGroup')"
|
|
||||||
/>
|
/>
|
||||||
<span v-else>{{ scope.row.adGroup }}</span>
|
<span v-else>{{ scope.row.adGroup }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -198,13 +244,12 @@
|
||||||
<el-table-column label="AE组(G1组)" align="center" prop="aeGroup" width="120">
|
<el-table-column label="AE组(G1组)" align="center" prop="aeGroup" width="120">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
v-if="scope.row.indicatorName === '总成本(当日)'"
|
v-if="canEditCost(scope.row)"
|
||||||
v-model="scope.row.aeGroup"
|
v-model="scope.row.aeGroup"
|
||||||
size="mini"
|
size="mini"
|
||||||
:controls="false"
|
:controls="false"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@blur="handleUpdateCost(scope.row.curDate,scope.row.aeGroup,'aeGroup')"
|
@keyup.enter.native="handleUpdateCost(scope.row,scope.row.aeGroup,'aeGroup')"
|
||||||
@keyup.enter.native="handleUpdateCost(scope.row.curDate,scope.row.aeGroup,'aeGroup')"
|
|
||||||
/>
|
/>
|
||||||
<span v-else>{{ scope.row.aeGroup }}</span>
|
<span v-else>{{ scope.row.aeGroup }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -228,35 +273,70 @@ export default {
|
||||||
name: "CustomerStatistics",
|
name: "CustomerStatistics",
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
// 遮罩层
|
|
||||||
loading: true,
|
loading: true,
|
||||||
// 选中数组
|
|
||||||
ids: [],
|
ids: [],
|
||||||
// 非单个禁用
|
|
||||||
single: true,
|
single: true,
|
||||||
// 非多个禁用
|
|
||||||
multiple: true,
|
multiple: true,
|
||||||
// 显示搜索条件
|
|
||||||
showSearch: true,
|
showSearch: true,
|
||||||
// 总条数
|
|
||||||
total: 0,
|
total: 0,
|
||||||
// 客户统计数据表格数据
|
|
||||||
dataList: [],
|
dataList: [],
|
||||||
// 查询参数
|
weekDateRange: '',
|
||||||
queryParams: {
|
queryParams: {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
|
dataType: undefined,
|
||||||
|
year: undefined,
|
||||||
|
week: undefined,
|
||||||
|
yearMonth: undefined,
|
||||||
startDate: undefined,
|
startDate: undefined,
|
||||||
endDate: undefined,
|
endDate: undefined,
|
||||||
indicatorName: undefined
|
indicatorName: undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
'queryParams.week'(newVal) {
|
||||||
|
this.updateWeekDateRange()
|
||||||
|
},
|
||||||
|
'queryParams.year'(newVal) {
|
||||||
|
this.updateWeekDateRange()
|
||||||
|
}
|
||||||
|
},
|
||||||
created() {
|
created() {
|
||||||
this.getList()
|
this.getList()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/** 查询客户统计数据列表 */
|
updateWeekDateRange() {
|
||||||
|
if (this.queryParams.year && this.queryParams.week) {
|
||||||
|
const year = parseInt(this.queryParams.year)
|
||||||
|
const week = this.queryParams.week
|
||||||
|
const startDate = this.getWeekStartDate(year, week)
|
||||||
|
const endDate = new Date(startDate)
|
||||||
|
endDate.setDate(endDate.getDate() + 6)
|
||||||
|
this.weekDateRange = this.formatDate(startDate) + ' 至 ' + this.formatDate(endDate)
|
||||||
|
} else {
|
||||||
|
this.weekDateRange = ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getWeekStartDate(year, week) {
|
||||||
|
const date = new Date(year, 0, 1)
|
||||||
|
const dayOfWeek = date.getDay()
|
||||||
|
const daysToMonday = dayOfWeek === 0 ? -6 : 1 - dayOfWeek
|
||||||
|
date.setDate(date.getDate() + daysToMonday)
|
||||||
|
date.setDate(date.getDate() + (week - 1) * 7)
|
||||||
|
return date
|
||||||
|
},
|
||||||
|
formatDate(date) {
|
||||||
|
const year = date.getFullYear()
|
||||||
|
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(date.getDate()).padStart(2, '0')
|
||||||
|
return year + '-' + month + '-' + day
|
||||||
|
},
|
||||||
|
canEditCost(row) {
|
||||||
|
const isCostIndicator = row.indicatorName === '总成本(当日)' || row.indicatorName === '单条成本(当日)'
|
||||||
|
const isDayMode = this.queryParams.dataType === 'day' || !this.queryParams.dataType
|
||||||
|
return isCostIndicator && isDayMode
|
||||||
|
},
|
||||||
getList() {
|
getList() {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
console.log('=== 开始请求数据 ===')
|
console.log('=== 开始请求数据 ===')
|
||||||
|
|
@ -274,7 +354,7 @@ export default {
|
||||||
console.log('第一条数据的 aaGroup:', response.rows[0].aaGroup)
|
console.log('第一条数据的 aaGroup:', response.rows[0].aaGroup)
|
||||||
console.log('第一条数据的 nGroup:', response.rows[0].nGroup)
|
console.log('第一条数据的 nGroup:', response.rows[0].nGroup)
|
||||||
} else {
|
} else {
|
||||||
console.warn('⚠️ rows 为空或不存在')
|
console.warn('rows 为空或不存在')
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dataList = response.rows
|
this.dataList = response.rows
|
||||||
|
|
@ -290,23 +370,28 @@ export default {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
/** 搜索按钮操作 */
|
handleDataTypeChange() {
|
||||||
|
this.queryParams.year = undefined
|
||||||
|
this.queryParams.week = undefined
|
||||||
|
this.queryParams.yearMonth = undefined
|
||||||
|
this.queryParams.startDate = undefined
|
||||||
|
this.queryParams.endDate = undefined
|
||||||
|
this.weekDateRange = ''
|
||||||
|
},
|
||||||
handleQuery() {
|
handleQuery() {
|
||||||
this.queryParams.pageNum = 1
|
this.queryParams.pageNum = 1
|
||||||
this.getList()
|
this.getList()
|
||||||
},
|
},
|
||||||
/** 重置按钮操作 */
|
|
||||||
resetQuery() {
|
resetQuery() {
|
||||||
this.resetForm("queryForm")
|
this.resetForm("queryForm")
|
||||||
|
this.handleDataTypeChange()
|
||||||
this.handleQuery()
|
this.handleQuery()
|
||||||
},
|
},
|
||||||
// 多选框选中数据
|
|
||||||
handleSelectionChange(selection) {
|
handleSelectionChange(selection) {
|
||||||
this.ids = selection.map(item => item.id)
|
this.ids = selection.map(item => item.id)
|
||||||
this.single = selection.length !== 1
|
this.single = selection.length !== 1
|
||||||
this.multiple = !selection.length
|
this.multiple = !selection.length
|
||||||
},
|
},
|
||||||
/** 导出按钮操作 */
|
|
||||||
handleExport() {
|
handleExport() {
|
||||||
const formattedDate = this.parseTime(new Date(), '{y}-{m}-{d}');
|
const formattedDate = this.parseTime(new Date(), '{y}-{m}-{d}');
|
||||||
|
|
||||||
|
|
@ -314,9 +399,7 @@ export default {
|
||||||
...this.queryParams
|
...this.queryParams
|
||||||
}, `流量看板数据_${formattedDate}.xlsx`)
|
}, `流量看板数据_${formattedDate}.xlsx`)
|
||||||
},
|
},
|
||||||
/** 处理成本更新 */
|
handleUpdateCost(row, cost, attr) {
|
||||||
handleUpdateCost(date, cost, attr) {
|
|
||||||
// 校验 cost 是否为有效数字
|
|
||||||
if (cost === '' || cost === null || cost === undefined) {
|
if (cost === '' || cost === null || cost === undefined) {
|
||||||
this.$modal.msgWarning("请输入成本金额");
|
this.$modal.msgWarning("请输入成本金额");
|
||||||
return;
|
return;
|
||||||
|
|
@ -328,18 +411,30 @@ export default {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 可选: 校验是否为负数
|
|
||||||
if (numCost < 0) {
|
if (numCost < 0) {
|
||||||
this.$modal.msgWarning("成本金额不能为负数");
|
this.$modal.msgWarning("成本金额不能为负数");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const formattedDate = this.parseTime(date, '{y}-{m}-{d}');
|
const indicatorName = row.indicatorName;
|
||||||
updateCustomerStatistics(formattedDate, numCost, attr).then(response => {
|
const type = indicatorName === '单条成本(当日)' ? 'single' : 'total';
|
||||||
|
const costTypeName = indicatorName === '单条成本(当日)' ? '单条成本' : '总成本';
|
||||||
|
let formattedDate = row.curDate;
|
||||||
|
if (row.curDate instanceof Date) {
|
||||||
|
formattedDate = this.parseTime(row.curDate, '{y}-{m}-{d}');
|
||||||
|
} else if (typeof row.curDate === 'string' && row.curDate.length > 10) {
|
||||||
|
formattedDate = row.curDate.substring(0, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$modal.confirm(`确认修改${formattedDate}的${costTypeName}为 ${numCost}?`).then(() => {
|
||||||
|
updateCustomerStatistics(formattedDate, numCost, attr, type).then(response => {
|
||||||
this.$modal.msgSuccess("修改成功");
|
this.$modal.msgSuccess("修改成功");
|
||||||
this.getList();
|
this.getList();
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
this.getList(); // 失败时刷新数据以还原修改
|
this.getList();
|
||||||
|
});
|
||||||
|
}).catch(() => {
|
||||||
|
this.getList();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,19 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80px">
|
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80px">
|
||||||
<el-form-item label="开始日期" prop="startDate">
|
<el-form-item label="数据类型" prop="dataType">
|
||||||
|
<el-select
|
||||||
|
v-model="queryParams.dataType"
|
||||||
|
placeholder="请选择数据类型"
|
||||||
|
@change="handleDataTypeChange"
|
||||||
|
>
|
||||||
|
<el-option label="按天查询" value="day" />
|
||||||
|
<el-option label="自然周叠加数据" value="week" />
|
||||||
|
<el-option label="自然月叠加数据" value="month" />
|
||||||
|
<el-option label="所有数据" value="all" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="开始日期" prop="startDate" v-if="showDateRange">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-model="queryParams.startDate"
|
v-model="queryParams.startDate"
|
||||||
type="date"
|
type="date"
|
||||||
|
|
@ -10,7 +22,7 @@
|
||||||
clearable
|
clearable
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="结束日期" prop="endDate">
|
<el-form-item label="结束日期" prop="endDate" v-if="showDateRange">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-model="queryParams.endDate"
|
v-model="queryParams.endDate"
|
||||||
type="date"
|
type="date"
|
||||||
|
|
@ -19,6 +31,50 @@
|
||||||
clearable
|
clearable
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="年份" prop="year" v-if="showYearSelect">
|
||||||
|
<el-select
|
||||||
|
v-model="queryParams.year"
|
||||||
|
placeholder="选择年份"
|
||||||
|
clearable
|
||||||
|
@change="updateWeekDateRange"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in yearOptions"
|
||||||
|
:key="item"
|
||||||
|
:label="item + '年'"
|
||||||
|
:value="item"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="周数" prop="week" v-if="showWeekSelect">
|
||||||
|
<el-select
|
||||||
|
v-model="queryParams.week"
|
||||||
|
placeholder="选择周数"
|
||||||
|
clearable
|
||||||
|
@change="updateWeekDateRange"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in weekOptions"
|
||||||
|
:key="item"
|
||||||
|
:label="item + '周'"
|
||||||
|
:value="item"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="showWeekDateRange && weekDateRange">
|
||||||
|
<el-tag type="info" size="medium">
|
||||||
|
{{ weekDateRange }}
|
||||||
|
</el-tag>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="年月" prop="yearMonth" v-if="showMonthSelect">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="queryParams.yearMonth"
|
||||||
|
type="month"
|
||||||
|
placeholder="选择年月"
|
||||||
|
value-format="yyyy-MM"
|
||||||
|
@change="handleYearMonthChange"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="部门路径" prop="departmentPath">
|
<el-form-item label="部门路径" prop="departmentPath">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="queryParams.departmentPath"
|
v-model="queryParams.departmentPath"
|
||||||
|
|
@ -70,7 +126,7 @@
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="日期" align="center" prop="statDate" width="120">
|
<el-table-column label="日期" align="center" prop="statDate" width="120" v-if="showStatDate">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<span>{{ parseTime(scope.row.statDate, '{y}-{m}-{d}') }}</span>
|
<span>{{ parseTime(scope.row.statDate, '{y}-{m}-{d}') }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -81,6 +137,8 @@
|
||||||
<el-table-column label="当日转化率" align="center" prop="dailyConversionRate" width="180" :show-overflow-tooltip="true" />
|
<el-table-column label="当日转化率" align="center" prop="dailyConversionRate" width="180" :show-overflow-tooltip="true" />
|
||||||
<el-table-column label="当日及时单占比" align="center" prop="dailyTimelyOrderRatio" width="180" :show-overflow-tooltip="true" />
|
<el-table-column label="当日及时单占比" align="center" prop="dailyTimelyOrderRatio" width="180" :show-overflow-tooltip="true" />
|
||||||
<el-table-column label="当日非及时单占比" align="center" prop="dailyNonTimelyOrderRatio" width="180" :show-overflow-tooltip="true" />
|
<el-table-column label="当日非及时单占比" align="center" prop="dailyNonTimelyOrderRatio" width="180" :show-overflow-tooltip="true" />
|
||||||
|
<el-table-column label="家长成单率" align="center" prop="dailyParentOrderRate" width="180" :show-overflow-tooltip="true" />
|
||||||
|
<el-table-column label="学生成单率" align="center" prop="dailyStudentOrderRate" width="180" :show-overflow-tooltip="true" />
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<pagination
|
<pagination
|
||||||
|
|
@ -126,23 +184,140 @@ export default {
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
startDate: undefined,
|
startDate: undefined,
|
||||||
endDate: undefined,
|
endDate: undefined,
|
||||||
departmentPath: undefined
|
departmentPath: undefined,
|
||||||
|
dataType: 'day',
|
||||||
|
year: undefined,
|
||||||
|
week: undefined,
|
||||||
|
month: undefined,
|
||||||
|
yearMonth: undefined
|
||||||
|
},
|
||||||
|
// 年份选项
|
||||||
|
yearOptions: [],
|
||||||
|
// 周数选项(1-53)
|
||||||
|
weekOptions: [],
|
||||||
|
// 周日期范围显示
|
||||||
|
weekDateRange: ''
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 是否显示日期范围选择器
|
||||||
|
showDateRange() {
|
||||||
|
return this.queryParams.dataType === 'day'
|
||||||
|
},
|
||||||
|
// 是否显示年份选择器
|
||||||
|
showYearSelect() {
|
||||||
|
return this.queryParams.dataType === 'week'
|
||||||
|
},
|
||||||
|
// 是否显示周数选择器
|
||||||
|
showWeekSelect() {
|
||||||
|
return this.queryParams.dataType === 'week'
|
||||||
|
},
|
||||||
|
// 是否显示周日期范围
|
||||||
|
showWeekDateRange() {
|
||||||
|
return this.queryParams.dataType === 'week'
|
||||||
|
},
|
||||||
|
// 是否显示年月选择器
|
||||||
|
showMonthSelect() {
|
||||||
|
return this.queryParams.dataType === 'month'
|
||||||
|
},
|
||||||
|
// 是否显示日期列
|
||||||
|
showStatDate() {
|
||||||
|
return this.queryParams.dataType === 'day'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
this.initYearOptions()
|
||||||
|
this.initWeekOptions()
|
||||||
this.getList()
|
this.getList()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
// 初始化年份选项
|
||||||
|
initYearOptions() {
|
||||||
|
const currentYear = new Date().getFullYear()
|
||||||
|
const years = []
|
||||||
|
for (let i = currentYear; i >= currentYear - 5; i--) {
|
||||||
|
years.push(i)
|
||||||
|
}
|
||||||
|
this.yearOptions = years
|
||||||
|
},
|
||||||
|
// 初始化周数选项(1-53)
|
||||||
|
initWeekOptions() {
|
||||||
|
const weeks = []
|
||||||
|
for (let i = 1; i <= 53; i++) {
|
||||||
|
weeks.push(i)
|
||||||
|
}
|
||||||
|
this.weekOptions = weeks
|
||||||
|
},
|
||||||
|
// 数据类型变更处理
|
||||||
|
handleDataTypeChange(val) {
|
||||||
|
this.queryParams.year = undefined
|
||||||
|
this.queryParams.week = undefined
|
||||||
|
this.queryParams.month = undefined
|
||||||
|
this.queryParams.yearMonth = undefined
|
||||||
|
this.queryParams.startDate = undefined
|
||||||
|
this.queryParams.endDate = undefined
|
||||||
|
this.weekDateRange = ''
|
||||||
|
},
|
||||||
|
// 更新周日期范围显示
|
||||||
|
updateWeekDateRange() {
|
||||||
|
if (this.queryParams.year && this.queryParams.week) {
|
||||||
|
const dateRange = this.getWeekDateRange(this.queryParams.year, this.queryParams.week)
|
||||||
|
this.weekDateRange = `${dateRange.startDate} 至 ${dateRange.endDate}`
|
||||||
|
} else {
|
||||||
|
this.weekDateRange = ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 根据年份和周数计算日期范围
|
||||||
|
getWeekDateRange(year, week) {
|
||||||
|
const firstDayOfYear = new Date(year, 0, 1)
|
||||||
|
const daysOffset = (week - 1) * 7
|
||||||
|
let firstDayOfWeek = new Date(firstDayOfYear)
|
||||||
|
firstDayOfWeek.setDate(firstDayOfYear.getDate() + daysOffset)
|
||||||
|
const dayOfWeek = firstDayOfWeek.getDay()
|
||||||
|
const diff = dayOfWeek === 0 ? -6 : 1 - dayOfWeek
|
||||||
|
firstDayOfWeek.setDate(firstDayOfWeek.getDate() + diff)
|
||||||
|
const lastDayOfWeek = new Date(firstDayOfWeek)
|
||||||
|
lastDayOfWeek.setDate(firstDayOfWeek.getDate() + 6)
|
||||||
|
const formatDate = (date) => {
|
||||||
|
const y = date.getFullYear()
|
||||||
|
const m = String(date.getMonth() + 1).padStart(2, '0')
|
||||||
|
const d = String(date.getDate()).padStart(2, '0')
|
||||||
|
return `${y}-${m}-${d}`
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
startDate: formatDate(firstDayOfWeek),
|
||||||
|
endDate: formatDate(lastDayOfWeek)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 年月变更处理
|
||||||
|
handleYearMonthChange(val) {
|
||||||
|
if (val) {
|
||||||
|
const [year, month] = val.split('-')
|
||||||
|
this.queryParams.year = parseInt(year)
|
||||||
|
this.queryParams.month = parseInt(month)
|
||||||
|
} else {
|
||||||
|
this.queryParams.year = undefined
|
||||||
|
this.queryParams.month = undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
/** 查询部门统计数据列表 */
|
/** 查询部门统计数据列表 */
|
||||||
getList() {
|
getList() {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
listDepartmentStatistics(this.queryParams).then(response => {
|
const params = { ...this.queryParams }
|
||||||
|
if (params.dataType === 'day') {
|
||||||
|
params.dataType = undefined
|
||||||
|
}
|
||||||
|
if (params.dataType === 'month' && params.yearMonth) {
|
||||||
|
const [year, month] = params.yearMonth.split('-')
|
||||||
|
params.year = parseInt(year)
|
||||||
|
params.month = parseInt(month)
|
||||||
|
}
|
||||||
|
listDepartmentStatistics(params).then(response => {
|
||||||
this.dataList = response.rows
|
this.dataList = response.rows
|
||||||
this.total = response.total
|
this.total = response.total
|
||||||
this.loading = false
|
this.loading = false
|
||||||
})
|
})
|
||||||
getDepartmentStatisticsSummary(this.queryParams).then(response => {
|
getDepartmentStatisticsSummary(params).then(response => {
|
||||||
this.summaryData = response.data
|
this.summaryData = response.data
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
@ -154,6 +329,12 @@ export default {
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
resetQuery() {
|
resetQuery() {
|
||||||
this.resetForm("queryForm")
|
this.resetForm("queryForm")
|
||||||
|
this.queryParams.dataType = 'day'
|
||||||
|
this.queryParams.year = undefined
|
||||||
|
this.queryParams.week = undefined
|
||||||
|
this.queryParams.month = undefined
|
||||||
|
this.queryParams.yearMonth = undefined
|
||||||
|
this.weekDateRange = ''
|
||||||
this.handleQuery()
|
this.handleQuery()
|
||||||
},
|
},
|
||||||
// 多选框选中数据
|
// 多选框选中数据
|
||||||
|
|
@ -166,8 +347,17 @@ export default {
|
||||||
/** 导出按钮操作 */
|
/** 导出按钮操作 */
|
||||||
handleExport() {
|
handleExport() {
|
||||||
const formattedDate = this.parseTime(new Date(), '{y}-{m}-{d}');
|
const formattedDate = this.parseTime(new Date(), '{y}-{m}-{d}');
|
||||||
|
const params = { ...this.queryParams }
|
||||||
|
if (params.dataType === 'day') {
|
||||||
|
params.dataType = undefined
|
||||||
|
}
|
||||||
|
if (params.dataType === 'month' && params.yearMonth) {
|
||||||
|
const [year, month] = params.yearMonth.split('-')
|
||||||
|
params.year = parseInt(year)
|
||||||
|
params.month = parseInt(month)
|
||||||
|
}
|
||||||
this.download('/wecom/departmentStatistics/export', {
|
this.download('/wecom/departmentStatistics/export', {
|
||||||
...this.queryParams
|
...params
|
||||||
}, `销售看板数据_${formattedDate}.xlsx`)
|
}, `销售看板数据_${formattedDate}.xlsx`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
-- 部门统计表新增字段
|
||||||
|
-- 执行时间: 2026-03-02
|
||||||
|
|
||||||
|
-- 新增家长出单率(当日)
|
||||||
|
ALTER TABLE department_statistics_data
|
||||||
|
ADD COLUMN daily_parent_order_rate DECIMAL(10,2) DEFAULT NULL COMMENT '家长出单率(当日)';
|
||||||
|
|
||||||
|
-- 新增学生出单率(当日)
|
||||||
|
ALTER TABLE department_statistics_data
|
||||||
|
ADD COLUMN daily_student_order_rate DECIMAL(10,2) DEFAULT NULL COMMENT '学生出单率(当日)';
|
||||||
|
|
||||||
|
-- 新增是否个人标识
|
||||||
|
ALTER TABLE department_statistics_data
|
||||||
|
ADD COLUMN person_flag TINYINT(1) DEFAULT 0 COMMENT '是否个人标识(0-否,1-是)';
|
||||||
|
|
||||||
|
-- 新增公司名称
|
||||||
|
ALTER TABLE department_statistics_data
|
||||||
|
ADD COLUMN corp_name VARCHAR(100) DEFAULT NULL COMMENT '公司名称';
|
||||||
|
|
||||||
|
-- 新增部门名称
|
||||||
|
ALTER TABLE department_statistics_data
|
||||||
|
ADD COLUMN department_name VARCHAR(100) DEFAULT NULL COMMENT '部门名称';
|
||||||
|
|
||||||
|
-- 新增组名称
|
||||||
|
ALTER TABLE department_statistics_data
|
||||||
|
ADD COLUMN group_name VARCHAR(100) DEFAULT NULL COMMENT '组名称';
|
||||||
|
|
||||||
|
-- 新增个人名称
|
||||||
|
ALTER TABLE department_statistics_data
|
||||||
|
ADD COLUMN person_name VARCHAR(100) DEFAULT NULL COMMENT '个人名称';
|
||||||
Loading…
Reference in New Issue