修改统计数据显示问题
This commit is contained in:
parent
61d640da2b
commit
a5264f2ab8
|
|
@ -63,4 +63,7 @@ public class CustomerStatisticsData implements Serializable {
|
|||
|
||||
private int sortNo;
|
||||
|
||||
//是否是隐藏数据
|
||||
private Boolean hiddenFlag = false;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,17 +41,53 @@ public class DepartmentStatisticsData implements Serializable {
|
|||
//非及时单占比(当日)
|
||||
private BigDecimal dailyNonTimelyOrderRatio;
|
||||
|
||||
/* //即时单
|
||||
//即时单
|
||||
private Integer dailyTimelyCount;
|
||||
//非即时单
|
||||
private Integer dailyNonTimelyCount;*/
|
||||
private Integer dailyNonTimelyCount;
|
||||
|
||||
//管理员分配(当日)
|
||||
private Integer managerAccepted;
|
||||
/**
|
||||
* 部门路径(如:苏州曼普/销售部/一组 或 苏州曼普/销售部/一组/盛宇婷)
|
||||
*/
|
||||
|
||||
//新增:家长出单率(当日)
|
||||
private BigDecimal dailyParentOrderRate;
|
||||
//新增:学生出单率(当日)
|
||||
private BigDecimal dailyStudentOrderRate;
|
||||
|
||||
//如果是四级的 默认是个人 前端显示时也是默认显示个人
|
||||
private Boolean personFlag;
|
||||
|
||||
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分配"
|
||||
* */
|
||||
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;
|
||||
}
|
||||
|
||||
// 提取组级别路径和员工级别路径
|
||||
// 例如:苏州曼普/销售部/二组/盛宇婷
|
||||
// 组级别:苏州曼普/销售部/二组
|
||||
// 员工级别:苏州曼普/销售部/二组/盛宇婷
|
||||
// 先计算所有条件,避免重复判断
|
||||
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("/");
|
||||
|
||||
// 处理组级别统计(前3级)
|
||||
if (pathParts.length >= 3) {
|
||||
String groupPath = pathParts[0] + "/" + pathParts[1] + "/" + pathParts[2];
|
||||
processDepartmentRecord(data, targetDate, accumulator.getDepartmentStats(groupPath));
|
||||
// 构建各级路径并累加统计(只遍历一次,条件已预先计算)
|
||||
StringBuilder pathBuilder = new StringBuilder();
|
||||
for (int i = 0; i < pathParts.length; i++) {
|
||||
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 (isSourceMatch) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理员工级别统计(完整路径)
|
||||
if (pathParts.length >= 4) {
|
||||
processDepartmentRecord(data, targetDate, accumulator.getDepartmentStats(departmentPath));
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否还有下一页
|
||||
|
|
@ -530,38 +566,72 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
}
|
||||
|
||||
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()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
//由于可能是多个逗号拼成的多个日期 任意一个日期符合都可以
|
||||
// 由于可能是多个逗号拼成的多个日期,任意一个日期符合都可以
|
||||
String[] dates = orderDate.trim().split(",");
|
||||
// 解析订单日期:2.3 -> [2, 3]
|
||||
String[] parts = dates[dates.length - 1].trim().split("[.\\-/]");
|
||||
if (parts.length < 2) {
|
||||
return false;
|
||||
}
|
||||
String lastDateStr = dates[dates.length - 1].trim();
|
||||
|
||||
int orderMonth = Integer.parseInt(parts[0].trim());
|
||||
int orderDay = Integer.parseInt(parts[1].trim());
|
||||
|
||||
// 构建成交日期(基于addTime的年份)
|
||||
Calendar orderCal = Calendar.getInstance();
|
||||
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.MINUTE, 0);
|
||||
orderCal.set(Calendar.SECOND, 0);
|
||||
orderCal.set(Calendar.MILLISECOND, 0);
|
||||
|
||||
// 跨年处理:如果成交日期早于添加日期,年份+1
|
||||
if (orderCal.getTime().before(curDate)) {
|
||||
orderCal.add(Calendar.YEAR, 1);
|
||||
boolean parsed = false;
|
||||
|
||||
// 格式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);
|
||||
}
|
||||
parsed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!parsed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 标准化目标日期(清除时分秒)
|
||||
|
|
@ -572,15 +642,11 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
targetCal.set(Calendar.SECOND, 0);
|
||||
targetCal.set(Calendar.MILLISECOND, 0);
|
||||
|
||||
boolean b = orderCal.getTimeInMillis() == targetCal.getTimeInMillis();
|
||||
if (b) {
|
||||
return true;
|
||||
}
|
||||
return orderCal.getTimeInMillis() == targetCal.getTimeInMillis();
|
||||
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean matchOrderCompleted(CustomerExportData data,Date curDate) {
|
||||
|
|
@ -591,6 +657,16 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
}
|
||||
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 存在订单未完成 但是有标签的场景
|
||||
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("学生")) {
|
||||
stats.setStudentCount(stats.getStudentCount() + 1);
|
||||
|
||||
stats.setStudentOrderCount(stats.getStudentOrderCount() + 1);
|
||||
|
||||
// 新增:N组学生出单率统计(当日)
|
||||
stats.setStudentDailyCount(stats.getStudentDailyCount() + 1);
|
||||
if (matchesQValue(data, date) && isTimelyOrder(data)) {
|
||||
stats.setStudentDailyOrderCount(stats.getStudentDailyOrderCount() + 1);
|
||||
}
|
||||
|
||||
} else {
|
||||
stats.setUnknownAttrCount(stats.getUnknownAttrCount() + 1);
|
||||
}
|
||||
|
|
@ -773,10 +861,12 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
// 4. 及时单占比
|
||||
String timelyRate = calculateRate(stats.getTimelyOrderCount(), stats.getCustomerCount());
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "及时单占比(当日)", groupName, timelyRate,(10*sortNo++));
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "及时单数量(当日)", groupName, String.valueOf(stats.getTimelyOrderCount()),(10*sortNo++),true);
|
||||
|
||||
// 5. 非及时单占比
|
||||
String nonTimelyRate = calculateRate(stats.getNonTimelyOrderCount(), stats.getCustomerCount());
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "非及时单占比(当日)", groupName, nonTimelyRate,(10*sortNo++));
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "非及时单数量(当日)", groupName, String.valueOf(stats.getNonTimelyOrderCount()),(10*sortNo++),true);
|
||||
|
||||
// 6. 客户属性数量
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "客户属性数量(当日)", groupName, String.valueOf(stats.getTotalCustomerAttr()),(10*sortNo++));
|
||||
|
|
@ -784,14 +874,17 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
// 7. 家长占比
|
||||
String parentRate = calculateRate(stats.getParentCount(), stats.getTotalCustomerAttr());
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "家长占比(当日)", groupName, parentRate,(10*sortNo++));
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "家长数量(当日)", groupName, String.valueOf(stats.getParentCount()),(10*sortNo++),true);
|
||||
|
||||
// 8. 学生占比
|
||||
String studentRate = calculateRate(stats.getStudentCount(), stats.getTotalCustomerAttr());
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "学生占比(当日)", groupName, studentRate,(10*sortNo++));
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "学生数量(当日)", groupName, String.valueOf(stats.getStudentCount()),(10*sortNo++),true);
|
||||
|
||||
// 9. 未知占比
|
||||
String unknownRate = calculateRate(stats.getUnknownAttrCount(), stats.getTotalCustomerAttr());
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "未知占比(当日)", groupName, unknownRate,(10*sortNo++));
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "未知数量(当日)", groupName, String.valueOf(stats.getUnknownAttrCount()),(10*sortNo++),true);
|
||||
|
||||
// 10. 意向度数量
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "意向度数量(当日)", groupName, String.valueOf(stats.getTotalIntention()),(10*sortNo++));
|
||||
|
|
@ -799,18 +892,22 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
// 11. 主动报价占比
|
||||
String activeQuoteRate = calculateRate(stats.getActiveQuoteCount(), stats.getTotalIntention());
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "主动报价占比(当日)", groupName, activeQuoteRate,(10*sortNo++));
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "主动报价数量(当日)", groupName, String.valueOf(stats.getActiveQuoteCount()),(10*sortNo++),true);
|
||||
|
||||
// 12. 被动报价占比
|
||||
String passiveQuoteRate = calculateRate(stats.getPassiveQuoteCount(), stats.getTotalIntention());
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "被动报价占比(当日)", groupName, passiveQuoteRate,(10*sortNo++));
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "被动报价数量(当日)", groupName, String.valueOf(stats.getPassiveQuoteCount()),(10*sortNo++),true);
|
||||
|
||||
// 13. 未开口报价占比
|
||||
String noQuoteRate = calculateRate(stats.getNoQuoteCount(), stats.getTotalIntention());
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "未开口报价占比(当日)", groupName, noQuoteRate,(10*sortNo++));
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "未开口报价数量(当日)", groupName, String.valueOf(stats.getNoQuoteCount()),(10*sortNo++),true);
|
||||
|
||||
// 14. 已删除报价占比
|
||||
String deletedQuoteRate = calculateRate(stats.getDeletedQuoteCount(), stats.getTotalIntention());
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "已删除报价占比(当日)", groupName, deletedQuoteRate,(10*sortNo++));
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "已删除数量(当日)", groupName, String.valueOf(stats.getDeletedQuoteCount()),(10*sortNo++),true);
|
||||
|
||||
// 15. 年级数量
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "年级数量(当日)", groupName, String.valueOf(stats.getTotalGrade()),(10*sortNo++));
|
||||
|
|
@ -818,23 +915,37 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
// 16. 小学占比
|
||||
String primaryRate = calculateRate(stats.getPrimaryCount(), stats.getTotalGrade());
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "小学占比(当日)", groupName, primaryRate,(10*sortNo++));
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "小学数量(当日)", groupName, String.valueOf(stats.getPrimaryCount()),(10*sortNo++),true);
|
||||
|
||||
// 17. 初中占比
|
||||
String middleRate = calculateRate(stats.getMiddleCount(), stats.getTotalGrade());
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "初中占比(当日)", groupName, middleRate,(10*sortNo++));
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "初中数量(当日)", groupName, String.valueOf(stats.getMiddleCount()),(10*sortNo++),true);
|
||||
|
||||
// 18. 高中占比
|
||||
String highRate = calculateRate(stats.getHighCount(), stats.getTotalGrade());
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "高中占比(当日)", groupName, highRate,(10*sortNo++));
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "高中数量(当日)", groupName, String.valueOf(stats.getHighCount()),(10*sortNo++),true);
|
||||
|
||||
// 19. 家长出单占比
|
||||
String parentOrderRate = calculateRate(stats.getParentOrderCount(), stats.getParentCount());
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "家长出单占比(当日)", groupName, parentOrderRate,(10*sortNo++));
|
||||
setIndicatorValue(corpId,indicatorMap,curDate, "家长出单数量(当日)", groupName, String.valueOf(stats.getParentOrderCount()),(10*sortNo++),true);
|
||||
|
||||
// 20. 学生出单占比
|
||||
String studentOrderRate = calculateRate(stats.getStudentOrderCount(), stats.getStudentCount());
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置指标值到对应的 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 对象
|
||||
|
|
@ -947,6 +1082,22 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
if(matchesSource(data)) {
|
||||
// 2. 总承接数(当日)- 排除"由管理员XXX分配"
|
||||
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 {
|
||||
// 由管理员XXX分配"
|
||||
stats.setManagerAcceptCount(stats.getManagerAcceptCount() + 1);
|
||||
|
|
@ -975,6 +1126,25 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
vo.setDepartmentPath(departmentPath);
|
||||
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. 总承接数(当日)
|
||||
vo.setDailyTotalAccepted(stats.getTotalAcceptCount());
|
||||
|
|
@ -990,12 +1160,26 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
|
||||
// 4. 及时单占比(当日)
|
||||
BigDecimal timelyRate = calculateRateBigDecimal(stats.getTimelyOrderCount(), stats.getTotalOrderCount());
|
||||
vo.setDailyTimelyCount(stats.getTimelyOrderCount());
|
||||
vo.setDailyTimelyOrderRatio(timelyRate);
|
||||
|
||||
// 5. 非及时单占比(当日)
|
||||
BigDecimal nonTimelyRate = calculateRateBigDecimal(stats.getNonTimelyOrderCount(), stats.getTotalOrderCount());
|
||||
vo.setDailyNonTimelyCount(stats.getNonTimelyOrderCount());
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -142,6 +142,27 @@ public class StatisticsAccumulator {
|
|||
*/
|
||||
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
|
||||
);
|
||||
|
||||
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,
|
||||
@Param("endDate") Date endDate,
|
||||
@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 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 endDate 结束日期
|
||||
* @param departmentPath 部门路径
|
||||
* @param dataType 数据类型
|
||||
* @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列表(用于导出)
|
||||
* @param startDate 开始日期
|
||||
* @param endDate 结束日期
|
||||
* @param departmentPath 部门路径
|
||||
* @param dataType 数据类型
|
||||
* @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查询部门统计数据
|
||||
|
|
@ -59,5 +61,5 @@ public interface IDepartmentStatisticsDataService {
|
|||
*/
|
||||
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.service.ICustomerStatisticsDataService;
|
||||
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.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
|
@ -12,8 +14,15 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
import java.lang.reflect.Field;
|
||||
import java.math.BigDecimal;
|
||||
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.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 客户统计数据Service业务层处理
|
||||
|
|
@ -21,6 +30,8 @@ import java.util.List;
|
|||
@Service
|
||||
public class CustomerStatisticsDataServiceImpl implements ICustomerStatisticsDataService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(CustomerStatisticsDataServiceImpl.class);
|
||||
|
||||
@Autowired
|
||||
private CustomerStatisticsDataMapper customerStatisticsDataMapper;
|
||||
|
||||
|
|
@ -94,7 +105,7 @@ public class CustomerStatisticsDataServiceImpl implements ICustomerStatisticsDat
|
|||
|
||||
@Override
|
||||
@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 {
|
||||
// 1. 查询该日期的所有记录
|
||||
LambdaQueryWrapper<CustomerStatisticsData> queryWrapper = new LambdaQueryWrapper<>();
|
||||
|
|
@ -112,32 +123,50 @@ public class CustomerStatisticsDataServiceImpl implements ICustomerStatisticsDat
|
|||
CustomerStatisticsData danTiaoCostData = findByIndicatorName(dataList, "单条成本(当日)");
|
||||
CustomerStatisticsData chengDanCostData = findByIndicatorName(dataList, "成单成本(当日)");
|
||||
|
||||
// 3. 更新总成本
|
||||
setFieldValue(totalCostData, titleAttr, totalCost.toString());
|
||||
// 3. 根据type类型处理成本更新
|
||||
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);
|
||||
|
||||
// 4. 获取进粉数和成单数
|
||||
// 5. 获取进粉数和成单数
|
||||
String jinFenShuStr = getFieldValue(jinFenShuData, titleAttr);
|
||||
String chengDanShuStr = getFieldValue(chengDanShuData, titleAttr);
|
||||
|
||||
// 5. 计算并更新单条成本
|
||||
if (jinFenShuStr != null && !jinFenShuStr.trim().isEmpty()) {
|
||||
BigDecimal jinFenShu = new BigDecimal(jinFenShuStr);
|
||||
if (jinFenShu.compareTo(BigDecimal.ZERO) > 0) {
|
||||
BigDecimal danTiaoCost = totalCost.divide(jinFenShu, 2, RoundingMode.HALF_UP);
|
||||
setFieldValue(danTiaoCostData, titleAttr, danTiaoCost.toString());
|
||||
customerStatisticsDataMapper.updateById(danTiaoCostData);
|
||||
} else {
|
||||
setFieldValue(danTiaoCostData, titleAttr, "0");
|
||||
customerStatisticsDataMapper.updateById(danTiaoCostData);
|
||||
// 6. 计算并更新单条成本(仅在非single模式下更新)
|
||||
if (!"single".equals(type)) {
|
||||
if (jinFenShuStr != null && !jinFenShuStr.trim().isEmpty()) {
|
||||
BigDecimal jinFenShu = new BigDecimal(jinFenShuStr);
|
||||
if (jinFenShu.compareTo(BigDecimal.ZERO) > 0) {
|
||||
BigDecimal danTiaoCost = actualTotalCost.divide(jinFenShu, 2, RoundingMode.HALF_UP);
|
||||
setFieldValue(danTiaoCostData, titleAttr, danTiaoCost.toString());
|
||||
customerStatisticsDataMapper.updateById(danTiaoCostData);
|
||||
} else {
|
||||
setFieldValue(danTiaoCostData, titleAttr, "0");
|
||||
customerStatisticsDataMapper.updateById(danTiaoCostData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 6. 计算并更新成单成本
|
||||
// 7. 计算并更新成单成本
|
||||
if (chengDanShuStr != null && !chengDanShuStr.trim().isEmpty()) {
|
||||
BigDecimal chengDanShu = new BigDecimal(chengDanShuStr);
|
||||
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());
|
||||
customerStatisticsDataMapper.updateById(chengDanCostData);
|
||||
} 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) {
|
||||
try {
|
||||
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,11 +26,15 @@ public class DepartmentStatisticsDataServiceImpl implements IDepartmentStatistic
|
|||
* @param startDate 开始日期
|
||||
* @param endDate 结束日期
|
||||
* @param departmentPath 部门路径
|
||||
* @param dataType 数据类型
|
||||
* @return 部门统计数据列表
|
||||
*/
|
||||
@Override
|
||||
public List<DepartmentStatisticsData> selectDepartmentStatisticsDataList(String corpId,Date startDate, Date endDate, String departmentPath) {
|
||||
return departmentStatisticsDataMapper.selectDepartmentStatisticsDataList(corpId,startDate, endDate, 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -38,11 +42,15 @@ public class DepartmentStatisticsDataServiceImpl implements IDepartmentStatistic
|
|||
* @param startDate 开始日期
|
||||
* @param endDate 结束日期
|
||||
* @param departmentPath 部门路径
|
||||
* @param dataType 数据类型
|
||||
* @return 部门统计数据VO列表
|
||||
*/
|
||||
@Override
|
||||
public List<DepartmentStatisticsDataVO> selectDepartmentStatisticsDataVOList(String corpId,Date startDate, Date endDate, String departmentPath) {
|
||||
return departmentStatisticsDataMapper.selectDepartmentStatisticsDataVOList(corpId,startDate, endDate, 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -90,7 +98,7 @@ public class DepartmentStatisticsDataServiceImpl implements IDepartmentStatistic
|
|||
}
|
||||
|
||||
@Override
|
||||
public Map<String, BigDecimal> getSummary(String corpId,Date startDate, Date endDate, String departmentPath) {
|
||||
return departmentStatisticsDataMapper.getSummary(corpId,startDate,endDate,departmentPath);
|
||||
public Map<String, BigDecimal> getSummary(String corpId, Date startDate, Date endDate, String departmentPath, String dataType) {
|
||||
return departmentStatisticsDataMapper.getSummary(corpId, startDate, endDate, departmentPath);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
package com.ruoyi.excel.wecom.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.alibaba.excel.annotation.format.DateTimeFormat;
|
||||
import com.alibaba.excel.annotation.write.style.ColumnWidth;
|
||||
import com.ruoyi.common.annotation.Excel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 流量看板数据VO
|
||||
|
|
@ -21,10 +19,9 @@ public class CustomerStatisticsDataVO implements Serializable {
|
|||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ExcelProperty("统计日期")
|
||||
@Excel(name ="日期",dateFormat = "yyyy-MM-dd")
|
||||
@DateTimeFormat("yyyy-MM-dd")
|
||||
@Excel(name ="日期")
|
||||
@ColumnWidth(20)
|
||||
private Date curDate;
|
||||
private String curDate;
|
||||
|
||||
@ExcelProperty("重要指标")
|
||||
@Excel(name ="重要指标")
|
||||
|
|
@ -85,4 +82,14 @@ public class CustomerStatisticsDataVO implements Serializable {
|
|||
@Excel(name ="AE组(G1组)")
|
||||
@ColumnWidth(15)
|
||||
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 ="非及时单占比(当日")
|
||||
@ColumnWidth(15)
|
||||
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
|
||||
<where>
|
||||
corp_id = #{corpId}
|
||||
corp_id = #{corpId} and hidden_flag = false
|
||||
<if test="startDate != null">
|
||||
AND cur_date >= #{startDate}
|
||||
</if>
|
||||
|
|
@ -48,4 +48,54 @@
|
|||
ORDER BY cur_date DESC,sort_no
|
||||
</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>
|
||||
|
|
|
|||
|
|
@ -52,6 +52,16 @@
|
|||
daily_conversion_rate as dailyConversionRate,
|
||||
daily_timely_order_ratio as dailyTimelyOrderRatio,
|
||||
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
|
||||
FROM department_statistics_data
|
||||
<where>
|
||||
|
|
@ -76,9 +86,29 @@
|
|||
daily_total_accepted as dailyTotalAccepted,
|
||||
daily_total_orders as dailyTotalOrders,
|
||||
daily_conversion_rate as dailyConversionRate,
|
||||
daily_timely_order_ratio as dailyTimelyOrderRatio,
|
||||
daily_non_timely_order_ratio as dailyNonTimelyOrderRatio,
|
||||
sort_no as sortNo
|
||||
daily_timely_order_ratio as dailyTimelyOrderRatio,
|
||||
daily_non_timely_order_ratio as dailyNonTimelyOrderRatio,
|
||||
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
|
||||
<where>
|
||||
corp_id = #{corpId}
|
||||
|
|
@ -100,7 +130,7 @@
|
|||
sum(ifnull(daily_total_accepted,0)+ifnull(manager_accepted,0)) as totalIns
|
||||
from department_statistics_data
|
||||
<where>
|
||||
corp_id = #{corpId}
|
||||
corp_id = #{corpId} and person_flag = true
|
||||
<if test="startDate != null">
|
||||
AND stat_date >= #{startDate}
|
||||
</if>
|
||||
|
|
@ -113,4 +143,112 @@
|
|||
</where>
|
||||
</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>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import com.ruoyi.common.core.page.TableDataInfo;
|
|||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.CorpContextHolder;
|
||||
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.vo.CustomerStatisticsDataVO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
|
@ -36,14 +35,30 @@ public class CustomerStatisticsDataController extends BaseController {
|
|||
@PreAuthorize("@ss.hasPermi('wecom:customerStatistics:list')")
|
||||
@GetMapping("/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 = "endDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate,
|
||||
@RequestParam(value = "indicatorName", required = false) String indicatorName) {
|
||||
String corpId = CorpContextHolder.getCurrentCorpId();
|
||||
|
||||
startPage();
|
||||
List<CustomerStatisticsData> list = customerStatisticsDataService.selectCustomerStatisticsDataList(corpId,startDate, endDate, indicatorName);
|
||||
return getDataTable(list);
|
||||
List<CustomerStatisticsDataVO> list;
|
||||
if ("week".equals(dataType)) {
|
||||
list = customerStatisticsDataService.selectByWeekAggregation(corpId, year, week, indicatorName);
|
||||
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)
|
||||
@PostMapping("/export")
|
||||
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 = "endDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate,
|
||||
@RequestParam(value = "indicatorName", required = false) String indicatorName) {
|
||||
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);
|
||||
util.exportExcel(response, list, "流量看板数据");
|
||||
util.exportExcel(response, dataList, "流量看板数据");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -80,10 +109,11 @@ public class CustomerStatisticsDataController extends BaseController {
|
|||
@Log(title = "客户统计数据", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
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) {
|
||||
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 java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
|
@ -40,11 +42,19 @@ public class DepartmentStatisticsDataController extends BaseController {
|
|||
public TableDataInfo list(
|
||||
@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 = "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();
|
||||
|
||||
Date[] dateRange = calculateDateRange(dataType, year, week, month, startDate, endDate);
|
||||
startDate = dateRange[0];
|
||||
endDate = dateRange[1];
|
||||
|
||||
startPage();
|
||||
List<DepartmentStatisticsData> list = departmentStatisticsDataService.selectDepartmentStatisticsDataList(corpId,startDate, endDate, departmentPath);
|
||||
List<DepartmentStatisticsData> list = departmentStatisticsDataService.selectDepartmentStatisticsDataList(corpId, startDate, endDate, departmentPath, dataType);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
|
|
@ -57,10 +67,18 @@ public class DepartmentStatisticsDataController extends BaseController {
|
|||
public void export(HttpServletResponse response,
|
||||
@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 = "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();
|
||||
|
||||
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);
|
||||
util.exportExcel(response, list, "销售看板数据");
|
||||
}
|
||||
|
|
@ -83,10 +101,21 @@ public class DepartmentStatisticsDataController extends BaseController {
|
|||
public AjaxResult summary(
|
||||
@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 = "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();
|
||||
|
||||
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 totalIns = map.get("totalIns");
|
||||
if(totalOrders == null) {
|
||||
|
|
@ -104,4 +133,60 @@ public class DepartmentStatisticsDataController extends BaseController {
|
|||
}
|
||||
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({
|
||||
url: '/wecom/customerStatistics',
|
||||
method: 'put',
|
||||
params: {
|
||||
curDate: date,
|
||||
totalCost: cost,
|
||||
cost: cost,
|
||||
type: type,
|
||||
attr: attr
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,7 +1,52 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<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
|
||||
v-model="queryParams.startDate"
|
||||
type="date"
|
||||
|
|
@ -10,7 +55,7 @@
|
|||
clearable
|
||||
/>
|
||||
</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
|
||||
v-model="queryParams.endDate"
|
||||
type="date"
|
||||
|
|
@ -49,22 +94,32 @@
|
|||
|
||||
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
|
||||
<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">
|
||||
<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>
|
||||
</el-table-column>
|
||||
<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">
|
||||
<template slot-scope="scope">
|
||||
<el-input-number
|
||||
v-if="scope.row.indicatorName === '总成本(当日)'"
|
||||
v-if="canEditCost(scope.row)"
|
||||
v-model="scope.row.ntfGroup"
|
||||
size="mini"
|
||||
:controls="false"
|
||||
style="width: 100%"
|
||||
@blur="handleUpdateCost(scope.row.curDate,scope.row.ntfGroup,'ntfGroup')"
|
||||
@keyup.enter.native="handleUpdateCost(scope.row.curDate,scope.row.ntfGroup,'ntfGroup')"
|
||||
@keyup.enter.native="handleUpdateCost(scope.row,scope.row.ntfGroup,'ntfGroup')"
|
||||
/>
|
||||
<span v-else>{{ scope.row.ntfGroup }}</span>
|
||||
</template>
|
||||
|
|
@ -72,13 +127,12 @@
|
|||
<el-table-column label="O组(公司孵化)" align="center" prop="ofhGroup" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-input-number
|
||||
v-if="scope.row.indicatorName === '总成本(当日)'"
|
||||
v-if="canEditCost(scope.row)"
|
||||
v-model="scope.row.ofhGroup"
|
||||
size="mini"
|
||||
:controls="false"
|
||||
style="width: 100%"
|
||||
@blur="handleUpdateCost(scope.row.curDate,scope.row.ofhGroup,'ofhGroup')"
|
||||
@keyup.enter.native="handleUpdateCost(scope.row.curDate,scope.row.ofhGroup,'ofhGroup')"
|
||||
@keyup.enter.native="handleUpdateCost(scope.row,scope.row.ofhGroup,'ofhGroup')"
|
||||
/>
|
||||
<span v-else>{{ scope.row.ofhGroup }}</span>
|
||||
</template>
|
||||
|
|
@ -86,13 +140,12 @@
|
|||
<el-table-column label="P组(商务)" align="center" prop="pswGroup" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-input-number
|
||||
v-if="scope.row.indicatorName === '总成本(当日)'"
|
||||
v-if="canEditCost(scope.row)"
|
||||
v-model="scope.row.pswGroup"
|
||||
size="mini"
|
||||
:controls="false"
|
||||
style="width: 100%"
|
||||
@blur="handleUpdateCost(scope.row.curDate,scope.row.pswGroup,'pswGroup')"
|
||||
@keyup.enter.native="handleUpdateCost(scope.row.curDate,scope.row.pswGroup,'pswGroup')"
|
||||
@keyup.enter.native="handleUpdateCost(scope.row,scope.row.pswGroup,'pswGroup')"
|
||||
/>
|
||||
<span v-else>{{ scope.row.pswGroup }}</span>
|
||||
</template>
|
||||
|
|
@ -100,13 +153,12 @@
|
|||
<el-table-column label="W组(A1组)" align="center" prop="wa1Group" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-input-number
|
||||
v-if="scope.row.indicatorName === '总成本(当日)'"
|
||||
v-if="canEditCost(scope.row)"
|
||||
v-model="scope.row.wa1Group"
|
||||
size="mini"
|
||||
:controls="false"
|
||||
style="width: 100%"
|
||||
@blur="handleUpdateCost(scope.row.curDate,scope.row.wa1Group,'wa1Group')"
|
||||
@keyup.enter.native="handleUpdateCost(scope.row.curDate,scope.row.wa1Group,'wa1Group')"
|
||||
@keyup.enter.native="handleUpdateCost(scope.row,scope.row.wa1Group,'wa1Group')"
|
||||
/>
|
||||
<span v-else>{{ scope.row.wa1Group }}</span>
|
||||
</template>
|
||||
|
|
@ -114,13 +166,12 @@
|
|||
<el-table-column label="X组(B1组)" align="center" prop="xb1Group" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-input-number
|
||||
v-if="scope.row.indicatorName === '总成本(当日)'"
|
||||
v-if="canEditCost(scope.row)"
|
||||
v-model="scope.row.xb1Group"
|
||||
size="mini"
|
||||
:controls="false"
|
||||
style="width: 100%"
|
||||
@blur="handleUpdateCost(scope.row.curDate,scope.row.xb1Group,'xb1Group')"
|
||||
@keyup.enter.native="handleUpdateCost(scope.row.curDate,scope.row.xb1Group,'xb1Group')"
|
||||
@keyup.enter.native="handleUpdateCost(scope.row,scope.row.xb1Group,'xb1Group')"
|
||||
/>
|
||||
<span v-else>{{ scope.row.xb1Group }}</span>
|
||||
</template>
|
||||
|
|
@ -128,13 +179,12 @@
|
|||
<el-table-column label="Y组(C1组)" align="center" prop="yc1Group" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-input-number
|
||||
v-if="scope.row.indicatorName === '总成本(当日)'"
|
||||
v-if="canEditCost(scope.row)"
|
||||
v-model="scope.row.yc1Group"
|
||||
size="mini"
|
||||
:controls="false"
|
||||
style="width: 100%"
|
||||
@blur="handleUpdateCost(scope.row.curDate,scope.row.yc1Group,'yc1Group')"
|
||||
@keyup.enter.native="handleUpdateCost(scope.row.curDate,scope.row.yc1Group,'yc1Group')"
|
||||
@keyup.enter.native="handleUpdateCost(scope.row,scope.row.yc1Group,'yc1Group')"
|
||||
/>
|
||||
<span v-else>{{ scope.row.yc1Group }}</span>
|
||||
</template>
|
||||
|
|
@ -142,13 +192,12 @@
|
|||
<el-table-column label="Z组(D1组)" align="center" prop="zd1Group" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-input-number
|
||||
v-if="scope.row.indicatorName === '总成本(当日)'"
|
||||
v-if="canEditCost(scope.row)"
|
||||
v-model="scope.row.zd1Group"
|
||||
size="mini"
|
||||
:controls="false"
|
||||
style="width: 100%"
|
||||
@blur="handleUpdateCost(scope.row.curDate,scope.row.zd1Group,'zd1Group')"
|
||||
@keyup.enter.native="handleUpdateCost(scope.row.curDate,scope.row.zd1Group,'zd1Group')"
|
||||
@keyup.enter.native="handleUpdateCost(scope.row,scope.row.zd1Group,'zd1Group')"
|
||||
/>
|
||||
<span v-else>{{ scope.row.zd1Group }}</span>
|
||||
</template>
|
||||
|
|
@ -156,13 +205,12 @@
|
|||
<el-table-column label="AA组(E1组)" align="center" prop="aaGroup" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-input-number
|
||||
v-if="scope.row.indicatorName === '总成本(当日)'"
|
||||
v-if="canEditCost(scope.row)"
|
||||
v-model="scope.row.aaGroup"
|
||||
size="mini"
|
||||
:controls="false"
|
||||
style="width: 100%"
|
||||
@blur="handleUpdateCost(scope.row.curDate,scope.row.aaGroup,'aaGroup')"
|
||||
@keyup.enter.native="handleUpdateCost(scope.row.curDate,scope.row.aaGroup,'aaGroup')"
|
||||
@keyup.enter.native="handleUpdateCost(scope.row,scope.row.aaGroup,'aaGroup')"
|
||||
/>
|
||||
<span v-else>{{ scope.row.aaGroup }}</span>
|
||||
</template>
|
||||
|
|
@ -170,13 +218,12 @@
|
|||
<el-table-column label="AC组(自然流)" align="center" prop="acGroup" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-input-number
|
||||
v-if="scope.row.indicatorName === '总成本(当日)'"
|
||||
v-if="canEditCost(scope.row)"
|
||||
v-model="scope.row.acGroup"
|
||||
size="mini"
|
||||
:controls="false"
|
||||
style="width: 100%"
|
||||
@blur="handleUpdateCost(scope.row.curDate,scope.row.acGroup,'acGroup')"
|
||||
@keyup.enter.native="handleUpdateCost(scope.row.curDate,scope.row.acGroup,'acGroup')"
|
||||
@keyup.enter.native="handleUpdateCost(scope.row,scope.row.acGroup,'acGroup')"
|
||||
/>
|
||||
<span v-else>{{ scope.row.acGroup }}</span>
|
||||
</template>
|
||||
|
|
@ -184,13 +231,12 @@
|
|||
<el-table-column label="AD组(F1组)" align="center" prop="adGroup" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-input-number
|
||||
v-if="scope.row.indicatorName === '总成本(当日)'"
|
||||
v-if="canEditCost(scope.row)"
|
||||
v-model="scope.row.adGroup"
|
||||
size="mini"
|
||||
:controls="false"
|
||||
style="width: 100%"
|
||||
@blur="handleUpdateCost(scope.row.curDate,scope.row.adGroup,'adGroup')"
|
||||
@keyup.enter.native="handleUpdateCost(scope.row.curDate,scope.row.adGroup,'adGroup')"
|
||||
@keyup.enter.native="handleUpdateCost(scope.row,scope.row.adGroup,'adGroup')"
|
||||
/>
|
||||
<span v-else>{{ scope.row.adGroup }}</span>
|
||||
</template>
|
||||
|
|
@ -198,13 +244,12 @@
|
|||
<el-table-column label="AE组(G1组)" align="center" prop="aeGroup" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-input-number
|
||||
v-if="scope.row.indicatorName === '总成本(当日)'"
|
||||
v-if="canEditCost(scope.row)"
|
||||
v-model="scope.row.aeGroup"
|
||||
size="mini"
|
||||
:controls="false"
|
||||
style="width: 100%"
|
||||
@blur="handleUpdateCost(scope.row.curDate,scope.row.aeGroup,'aeGroup')"
|
||||
@keyup.enter.native="handleUpdateCost(scope.row.curDate,scope.row.aeGroup,'aeGroup')"
|
||||
@keyup.enter.native="handleUpdateCost(scope.row,scope.row.aeGroup,'aeGroup')"
|
||||
/>
|
||||
<span v-else>{{ scope.row.aeGroup }}</span>
|
||||
</template>
|
||||
|
|
@ -228,35 +273,70 @@ export default {
|
|||
name: "CustomerStatistics",
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 选中数组
|
||||
ids: [],
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 客户统计数据表格数据
|
||||
dataList: [],
|
||||
// 查询参数
|
||||
weekDateRange: '',
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
dataType: undefined,
|
||||
year: undefined,
|
||||
week: undefined,
|
||||
yearMonth: undefined,
|
||||
startDate: undefined,
|
||||
endDate: undefined,
|
||||
indicatorName: undefined
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'queryParams.week'(newVal) {
|
||||
this.updateWeekDateRange()
|
||||
},
|
||||
'queryParams.year'(newVal) {
|
||||
this.updateWeekDateRange()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
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() {
|
||||
this.loading = true
|
||||
console.log('=== 开始请求数据 ===')
|
||||
|
|
@ -274,7 +354,7 @@ export default {
|
|||
console.log('第一条数据的 aaGroup:', response.rows[0].aaGroup)
|
||||
console.log('第一条数据的 nGroup:', response.rows[0].nGroup)
|
||||
} else {
|
||||
console.warn('⚠️ rows 为空或不存在')
|
||||
console.warn('rows 为空或不存在')
|
||||
}
|
||||
|
||||
this.dataList = response.rows
|
||||
|
|
@ -290,23 +370,28 @@ export default {
|
|||
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() {
|
||||
this.queryParams.pageNum = 1
|
||||
this.getList()
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm")
|
||||
this.handleDataTypeChange()
|
||||
this.handleQuery()
|
||||
},
|
||||
// 多选框选中数据
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.id)
|
||||
this.single = selection.length !== 1
|
||||
this.multiple = !selection.length
|
||||
},
|
||||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
const formattedDate = this.parseTime(new Date(), '{y}-{m}-{d}');
|
||||
|
||||
|
|
@ -314,9 +399,7 @@ export default {
|
|||
...this.queryParams
|
||||
}, `流量看板数据_${formattedDate}.xlsx`)
|
||||
},
|
||||
/** 处理成本更新 */
|
||||
handleUpdateCost(date, cost, attr) {
|
||||
// 校验 cost 是否为有效数字
|
||||
handleUpdateCost(row, cost, attr) {
|
||||
if (cost === '' || cost === null || cost === undefined) {
|
||||
this.$modal.msgWarning("请输入成本金额");
|
||||
return;
|
||||
|
|
@ -328,18 +411,30 @@ export default {
|
|||
return;
|
||||
}
|
||||
|
||||
// 可选: 校验是否为负数
|
||||
if (numCost < 0) {
|
||||
this.$modal.msgWarning("成本金额不能为负数");
|
||||
return;
|
||||
}
|
||||
|
||||
const formattedDate = this.parseTime(date, '{y}-{m}-{d}');
|
||||
updateCustomerStatistics(formattedDate, numCost, attr).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.getList();
|
||||
const indicatorName = row.indicatorName;
|
||||
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.getList();
|
||||
}).catch(() => {
|
||||
this.getList();
|
||||
});
|
||||
}).catch(() => {
|
||||
this.getList(); // 失败时刷新数据以还原修改
|
||||
this.getList();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,19 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<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
|
||||
v-model="queryParams.startDate"
|
||||
type="date"
|
||||
|
|
@ -10,7 +22,7 @@
|
|||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="结束日期" prop="endDate">
|
||||
<el-form-item label="结束日期" prop="endDate" v-if="showDateRange">
|
||||
<el-date-picker
|
||||
v-model="queryParams.endDate"
|
||||
type="date"
|
||||
|
|
@ -19,6 +31,50 @@
|
|||
clearable
|
||||
/>
|
||||
</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-input
|
||||
v-model="queryParams.departmentPath"
|
||||
|
|
@ -70,7 +126,7 @@
|
|||
|
||||
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
|
||||
<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">
|
||||
<span>{{ parseTime(scope.row.statDate, '{y}-{m}-{d}') }}</span>
|
||||
</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="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="dailyParentOrderRate" width="180" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="学生成单率" align="center" prop="dailyStudentOrderRate" width="180" :show-overflow-tooltip="true" />
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
|
|
@ -126,23 +184,140 @@ export default {
|
|||
pageSize: 10,
|
||||
startDate: 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() {
|
||||
this.initYearOptions()
|
||||
this.initWeekOptions()
|
||||
this.getList()
|
||||
},
|
||||
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() {
|
||||
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.total = response.total
|
||||
this.loading = false
|
||||
})
|
||||
getDepartmentStatisticsSummary(this.queryParams).then(response => {
|
||||
getDepartmentStatisticsSummary(params).then(response => {
|
||||
this.summaryData = response.data
|
||||
})
|
||||
},
|
||||
|
|
@ -154,6 +329,12 @@ export default {
|
|||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
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()
|
||||
},
|
||||
// 多选框选中数据
|
||||
|
|
@ -166,8 +347,17 @@ export default {
|
|||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
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.queryParams
|
||||
...params
|
||||
}, `销售看板数据_${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