|
@@ -17,6 +17,7 @@ import org.springframework.stereotype.Service;
|
|
|
|
|
|
import java.time.DayOfWeek;
|
|
|
import java.time.LocalDate;
|
|
|
+import java.time.ZoneId;
|
|
|
import java.time.temporal.TemporalAdjusters;
|
|
|
import java.util.*;
|
|
|
import java.util.stream.Collectors;
|
|
@@ -32,70 +33,76 @@ public class UninstallAnalyseServiceImpl implements UninstallAnalyseService {
|
|
|
|
|
|
private static final Random random = new Random();
|
|
|
|
|
|
- @Autowired
|
|
|
- private MktTrendSummaryMapper mktTrendSummaryMapper;
|
|
|
- @Autowired
|
|
|
- private MktDeviceTimeMapper mktDeviceTimeMapper;
|
|
|
- @Autowired
|
|
|
- private MktDeviceCountMapper mktDeviceCountMapper;
|
|
|
- @Autowired
|
|
|
- private MktDeviceInterfereMapper mktDeviceInterfereMapper;
|
|
|
- @Autowired
|
|
|
- private MktDeviceActionMapper mktDeviceActionMapper;
|
|
|
-
|
|
|
- @Override
|
|
|
- public UninstallTrendVO getUninstallTrend(GetUninstallTrendDTO dto) {
|
|
|
- LocalDate startDate, endDate;
|
|
|
- String timeUnit = dto.getTimeUnit() == null ? "week" : dto.getTimeUnit();
|
|
|
- LocalDate now = LocalDate.now();
|
|
|
- if ("week".equalsIgnoreCase(timeUnit)) {
|
|
|
- if (now.getDayOfWeek().getValue() < DayOfWeek.THURSDAY.getValue()) {
|
|
|
- startDate = now.minusWeeks(2).with(DayOfWeek.MONDAY);
|
|
|
- endDate = now.minusWeeks(2).with(DayOfWeek.SUNDAY);
|
|
|
- } else {
|
|
|
- startDate = now.minusWeeks(1).with(DayOfWeek.MONDAY);
|
|
|
- endDate = now.minusWeeks(1).with(DayOfWeek.SUNDAY);
|
|
|
- }
|
|
|
- } else if ("month".equalsIgnoreCase(timeUnit)) {
|
|
|
- if (now.getDayOfMonth() < 4) {
|
|
|
- LocalDate lastMonth = now.minusMonths(2);
|
|
|
- startDate = lastMonth.withDayOfMonth(1);
|
|
|
- endDate = lastMonth.with(TemporalAdjusters.lastDayOfMonth());
|
|
|
- } else {
|
|
|
- LocalDate lastMonth = now.minusMonths(1);
|
|
|
- startDate = lastMonth.withDayOfMonth(1);
|
|
|
- endDate = lastMonth.with(TemporalAdjusters.lastDayOfMonth());
|
|
|
- }
|
|
|
- } else {
|
|
|
- startDate = now;
|
|
|
- endDate = now;
|
|
|
- }
|
|
|
- // 支持前端传参覆盖
|
|
|
- if (!StringUtils.isEmpty(dto.getStartDate())) {
|
|
|
- startDate = LocalDate.parse(dto.getStartDate());
|
|
|
- }
|
|
|
- if (!StringUtils.isEmpty(dto.getEndDate())) {
|
|
|
- endDate = LocalDate.parse(dto.getEndDate());
|
|
|
- }
|
|
|
- QueryWrapper<MktTrendSummary> wrapper = new QueryWrapper<>();
|
|
|
- wrapper.between("stat_date", startDate, endDate);
|
|
|
- if (!StringUtils.isEmpty(dto.getAppId())) {
|
|
|
- wrapper.eq("app_id", dto.getAppId());
|
|
|
- }
|
|
|
- if (!StringUtils.isEmpty(dto.getChannel())) {
|
|
|
- wrapper.eq("channel", dto.getChannel());
|
|
|
- }
|
|
|
- if (!StringUtils.isEmpty(dto.getVersion())) {
|
|
|
- wrapper.eq("app_version", dto.getVersion());
|
|
|
- }
|
|
|
- wrapper.eq("stat_cycle", timeUnit);
|
|
|
- List<MktTrendSummary> list = mktTrendSummaryMapper.selectList(wrapper);
|
|
|
+ @Autowired
|
|
|
+ private MktTrendSummaryMapper mktTrendSummaryMapper;
|
|
|
+ @Autowired
|
|
|
+ private MktDeviceTimeMapper mktDeviceTimeMapper;
|
|
|
+ @Autowired
|
|
|
+ private MktDeviceCountMapper mktDeviceCountMapper;
|
|
|
+ @Autowired
|
|
|
+ private MktDeviceInterfereMapper mktDeviceInterfereMapper;
|
|
|
+ @Autowired
|
|
|
+ private MktDeviceActionMapper mktDeviceActionMapper;
|
|
|
+ @Autowired
|
|
|
+ private MktPortraitMapper mktPortraitMapper;
|
|
|
+ @Autowired
|
|
|
+ private MktInstallUninstallRatioMapper mktInstallUninstallRatioMapper;
|
|
|
+ @Autowired
|
|
|
+ private MktPredictMapper mktPredictMapper;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public UninstallTrendVO getUninstallTrend(GetUninstallTrendDTO dto) {
|
|
|
+ LocalDate startDate, endDate;
|
|
|
+ String timeUnit = dto.getTimeUnit() == null ? "week" : dto.getTimeUnit();
|
|
|
+ LocalDate now = LocalDate.now();
|
|
|
+ if ("week".equalsIgnoreCase(timeUnit)) {
|
|
|
+ if (now.getDayOfWeek().getValue() < DayOfWeek.THURSDAY.getValue()) {
|
|
|
+ startDate = now.minusWeeks(2).with(DayOfWeek.MONDAY);
|
|
|
+ endDate = now.minusWeeks(2).with(DayOfWeek.SUNDAY);
|
|
|
+ } else {
|
|
|
+ startDate = now.minusWeeks(1).with(DayOfWeek.MONDAY);
|
|
|
+ endDate = now.minusWeeks(1).with(DayOfWeek.SUNDAY);
|
|
|
+ }
|
|
|
+ } else if ("month".equalsIgnoreCase(timeUnit)) {
|
|
|
+ if (now.getDayOfMonth() < 4) {
|
|
|
+ LocalDate lastMonth = now.minusMonths(2);
|
|
|
+ startDate = lastMonth.withDayOfMonth(1);
|
|
|
+ endDate = lastMonth.with(TemporalAdjusters.lastDayOfMonth());
|
|
|
+ } else {
|
|
|
+ LocalDate lastMonth = now.minusMonths(1);
|
|
|
+ startDate = lastMonth.withDayOfMonth(1);
|
|
|
+ endDate = lastMonth.with(TemporalAdjusters.lastDayOfMonth());
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ startDate = now;
|
|
|
+ endDate = now;
|
|
|
+ }
|
|
|
+ // 支持前端传参覆盖
|
|
|
+ if (!StringUtils.isEmpty(dto.getStartDate())) {
|
|
|
+ startDate = LocalDate.parse(dto.getStartDate());
|
|
|
+ }
|
|
|
+ if (!StringUtils.isEmpty(dto.getEndDate())) {
|
|
|
+ endDate = LocalDate.parse(dto.getEndDate());
|
|
|
+ }
|
|
|
+ QueryWrapper<MktTrendSummary> wrapper = new QueryWrapper<>();
|
|
|
+ wrapper.between("stat_date", startDate, endDate);
|
|
|
+ if (!StringUtils.isEmpty(dto.getAppId())) {
|
|
|
+ wrapper.eq("app_id", dto.getAppId());
|
|
|
+ }
|
|
|
+ if (!StringUtils.isEmpty(dto.getChannel())) {
|
|
|
+ wrapper.eq("channel", dto.getChannel());
|
|
|
+ }
|
|
|
+ if (!StringUtils.isEmpty(dto.getVersion())) {
|
|
|
+ wrapper.eq("app_version", dto.getVersion());
|
|
|
+ }
|
|
|
+ wrapper.eq("stat_cycle", timeUnit);
|
|
|
+ List<MktTrendSummary> list = mktTrendSummaryMapper.selectList(wrapper);
|
|
|
|
|
|
UninstallTrendVO vo = new UninstallTrendVO();
|
|
|
|
|
|
- int uninstallCount = 0, recallCount = 0;
|
|
|
+ int uninstallCount = 0, recallCount = 0;
|
|
|
Double uninstallRate = 0.0, recallRate = 0.0;
|
|
|
- if (list != null && !list.isEmpty()) {
|
|
|
+ if (list != null && !list.isEmpty()) {
|
|
|
for (MktTrendSummary summary : list) {
|
|
|
if (summary.getTrendType() != null) {
|
|
|
// 卸载
|
|
@@ -110,42 +117,46 @@ public class UninstallAnalyseServiceImpl implements UninstallAnalyseService {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
+ }
|
|
|
vo.setStartDate(String.valueOf(startDate));
|
|
|
vo.setEndDate(String.valueOf(endDate));
|
|
|
- vo.setUninstallCounts(uninstallCount);
|
|
|
- vo.setRecallCounts(recallCount);
|
|
|
+ vo.setUninstallCounts(uninstallCount);
|
|
|
+ vo.setRecallCounts(recallCount);
|
|
|
vo.setUninstallRates(uninstallRate);
|
|
|
vo.setRecallRates(recallRate);
|
|
|
|
|
|
- return vo;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Page<UninstallTrendDtlVO> getUninstallTrendDetail(GetUninstallTrendDetailDTO dto) {
|
|
|
- // 分页参数
|
|
|
- int pageNum = dto.getPageNum() == null ? 1 : dto.getPageNum();
|
|
|
- int pageSize = dto.getPageSize() == null ? 10 : dto.getPageSize();
|
|
|
-
|
|
|
- String timeUnit = StringUtils.isEmpty(dto.getTimeUnit()) ? "week" : dto.getTimeUnit();
|
|
|
- QueryWrapper<MktTrendSummary> wrapper = new QueryWrapper<>();
|
|
|
-
|
|
|
- if (!StringUtils.isEmpty(dto.getAppId())) {
|
|
|
- wrapper.eq("app_id", dto.getAppId());
|
|
|
- }
|
|
|
- if (!StringUtils.isEmpty(dto.getChannel())) {
|
|
|
- wrapper.eq("channel", dto.getChannel());
|
|
|
- }
|
|
|
- if (!StringUtils.isEmpty(dto.getVersion())) {
|
|
|
- wrapper.eq("app_version", dto.getVersion());
|
|
|
- }
|
|
|
- wrapper.eq("stat_cycle", timeUnit);
|
|
|
-
|
|
|
- List<MktTrendSummary> list = mktTrendSummaryMapper.selectList(wrapper);
|
|
|
- log.info("查询结果数量: {}", list.size());
|
|
|
-
|
|
|
- // 使用Stream API优化分组和统计逻辑
|
|
|
- List<UninstallTrendDtlVO> voList = new ArrayList<>(list.stream()
|
|
|
+ return vo;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Page<UninstallTrendDtlVO> getUninstallTrendDetail(GetUninstallTrendDetailDTO dto) {
|
|
|
+ // 分页参数
|
|
|
+ int pageNum = dto.getPageNum() == null ? 1 : dto.getPageNum();
|
|
|
+ int pageSize = dto.getPageSize() == null ? 10 : dto.getPageSize();
|
|
|
+
|
|
|
+ String timeUnit = StringUtils.isEmpty(dto.getTimeUnit()) ? "week" : dto.getTimeUnit();
|
|
|
+ QueryWrapper<MktTrendSummary> wrapper = new QueryWrapper<>();
|
|
|
+
|
|
|
+ if (!StringUtils.isEmpty(dto.getAppId())) {
|
|
|
+ wrapper.eq("app_id", dto.getAppId());
|
|
|
+ }
|
|
|
+ if (!StringUtils.isEmpty(dto.getChannel())) {
|
|
|
+ wrapper.eq("channel", dto.getChannel());
|
|
|
+ }
|
|
|
+ if (!StringUtils.isEmpty(dto.getVersion())) {
|
|
|
+ wrapper.eq("app_version", dto.getVersion());
|
|
|
+ }
|
|
|
+ wrapper.eq("stat_cycle", timeUnit);
|
|
|
+
|
|
|
+ if (!StringUtils.isEmpty(dto.getStartDate()) && !StringUtils.isEmpty(dto.getEndDate())) {
|
|
|
+ wrapper.between("stat_date", dto.getStartDate(), dto.getEndDate());
|
|
|
+ }
|
|
|
+
|
|
|
+ List<MktTrendSummary> list = mktTrendSummaryMapper.selectList(wrapper);
|
|
|
+ log.info("查询结果数量: {}", list.size());
|
|
|
+
|
|
|
+ // 使用Stream API优化分组和统计逻辑
|
|
|
+ List<UninstallTrendDtlVO> voList = new ArrayList<>(list.stream()
|
|
|
.collect(Collectors.groupingBy(
|
|
|
summary -> getCycleKey(summary.getStatDate(), timeUnit),
|
|
|
TreeMap::new,
|
|
@@ -155,61 +166,61 @@ public class UninstallAnalyseServiceImpl implements UninstallAnalyseService {
|
|
|
)
|
|
|
))
|
|
|
.values());
|
|
|
-
|
|
|
- log.info("分页参数: pageNum={}, pageSize={}, voList.size={}", pageNum, pageSize, voList.size());
|
|
|
-
|
|
|
- // 使用PageUtils工具类处理分页
|
|
|
- return PageUtils.buildPage(voList, pageNum, pageSize);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 获取周期分组key
|
|
|
- */
|
|
|
- private String getCycleKey(Date statDate, String timeUnit) {
|
|
|
- LocalDate date = statDate.toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDate();
|
|
|
- if ("week".equalsIgnoreCase(timeUnit)) {
|
|
|
- return date.with(DayOfWeek.MONDAY).toString();
|
|
|
- } else if ("month".equalsIgnoreCase(timeUnit)) {
|
|
|
- return date.withDayOfMonth(1).toString();
|
|
|
- } else {
|
|
|
- return date.toString();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 构建卸载趋势明细VO
|
|
|
- */
|
|
|
- private UninstallTrendDtlVO buildUninstallTrendDtlVO(List<MktTrendSummary> summaries, String timeUnit) {
|
|
|
- LocalDate start = LocalDate.parse(getCycleKey(summaries.get(0).getStatDate(), timeUnit));
|
|
|
- LocalDate end;
|
|
|
-
|
|
|
- if ("week".equalsIgnoreCase(timeUnit)) {
|
|
|
- end = start.with(DayOfWeek.SUNDAY);
|
|
|
- } else if ("month".equalsIgnoreCase(timeUnit)) {
|
|
|
- end = start.with(TemporalAdjusters.lastDayOfMonth());
|
|
|
- } else {
|
|
|
- end = start;
|
|
|
- }
|
|
|
-
|
|
|
- // 使用Stream API统计数据
|
|
|
- int uninstallCount = summaries.stream()
|
|
|
- .filter(summary -> summary.getTrendType() != null && summary.getTrendType() == 0)
|
|
|
- .mapToInt(MktTrendSummary::getCount)
|
|
|
- .sum();
|
|
|
-
|
|
|
- int recallCount = summaries.stream()
|
|
|
- .filter(summary -> summary.getTrendType() != null && summary.getTrendType() == 1)
|
|
|
- .mapToInt(MktTrendSummary::getCount)
|
|
|
- .sum();
|
|
|
-
|
|
|
- UninstallTrendDtlVO vo = new UninstallTrendDtlVO();
|
|
|
- vo.setStartDate(start.toString());
|
|
|
- vo.setEndDate(end.toString());
|
|
|
- vo.setUninstallCounts(uninstallCount);
|
|
|
- vo.setRecallCounts(recallCount);
|
|
|
-
|
|
|
- return vo;
|
|
|
- }
|
|
|
+
|
|
|
+ log.info("分页参数: pageNum={}, pageSize={}, voList.size={}", pageNum, pageSize, voList.size());
|
|
|
+
|
|
|
+ // 使用PageUtils工具类处理分页
|
|
|
+ return PageUtils.buildPage(voList, pageNum, pageSize);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取周期分组key
|
|
|
+ */
|
|
|
+ private String getCycleKey(java.util.Date statDate, String timeUnit) {
|
|
|
+ LocalDate date = statDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
|
|
|
+ if ("week".equalsIgnoreCase(timeUnit)) {
|
|
|
+ return date.with(DayOfWeek.MONDAY).toString();
|
|
|
+ } else if ("month".equalsIgnoreCase(timeUnit)) {
|
|
|
+ return date.withDayOfMonth(1).toString();
|
|
|
+ } else {
|
|
|
+ return date.toString();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建卸载趋势明细VO
|
|
|
+ */
|
|
|
+ private UninstallTrendDtlVO buildUninstallTrendDtlVO(List<MktTrendSummary> summaries, String timeUnit) {
|
|
|
+ LocalDate start = LocalDate.parse(getCycleKey(summaries.get(0).getStatDate(), timeUnit));
|
|
|
+ LocalDate end;
|
|
|
+
|
|
|
+ if ("week".equalsIgnoreCase(timeUnit)) {
|
|
|
+ end = start.with(DayOfWeek.SUNDAY);
|
|
|
+ } else if ("month".equalsIgnoreCase(timeUnit)) {
|
|
|
+ end = start.with(TemporalAdjusters.lastDayOfMonth());
|
|
|
+ } else {
|
|
|
+ end = start;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 使用Stream API统计数据
|
|
|
+ int uninstallCount = summaries.stream()
|
|
|
+ .filter(summary -> summary.getTrendType() != null && summary.getTrendType() == 0)
|
|
|
+ .mapToInt(MktTrendSummary::getCount)
|
|
|
+ .sum();
|
|
|
+
|
|
|
+ int recallCount = summaries.stream()
|
|
|
+ .filter(summary -> summary.getTrendType() != null && summary.getTrendType() == 1)
|
|
|
+ .mapToInt(MktTrendSummary::getCount)
|
|
|
+ .sum();
|
|
|
+
|
|
|
+ UninstallTrendDtlVO vo = new UninstallTrendDtlVO();
|
|
|
+ vo.setStartDate(start.toString());
|
|
|
+ vo.setEndDate(end.toString());
|
|
|
+ vo.setUninstallCounts(uninstallCount);
|
|
|
+ vo.setRecallCounts(recallCount);
|
|
|
+
|
|
|
+ return vo;
|
|
|
+ }
|
|
|
|
|
|
@Override
|
|
|
public UninstallInsightVO getUninstallDeviceActive(GetUninstallInsightDTO dto) {
|
|
@@ -227,7 +238,7 @@ public class UninstallAnalyseServiceImpl implements UninstallAnalyseService {
|
|
|
if (!StringUtils.isEmpty(dto.getAppId())) wrapper.eq("app_id", dto.getAppId());
|
|
|
if (!StringUtils.isEmpty(dto.getChannel())) wrapper.eq("channel", dto.getChannel());
|
|
|
if (!StringUtils.isEmpty(dto.getVersion())) wrapper.eq("app_version", dto.getVersion());
|
|
|
-
|
|
|
+
|
|
|
List<MktDeviceTime> list = mktDeviceTimeMapper.selectList(wrapper);
|
|
|
List<InstallStockVO> voList = new ArrayList<>();
|
|
|
for (MktDeviceTime entity : list) {
|
|
@@ -288,8 +299,16 @@ public class UninstallAnalyseServiceImpl implements UninstallAnalyseService {
|
|
|
|
|
|
@Override
|
|
|
public UninstallBeforeVO uninstallBefore(GetUninstallInsightDTO dto) {
|
|
|
+
|
|
|
+ Map<String, LocalDate> timeRangeMap = new HashMap<>();
|
|
|
+ if (!StringUtils.isEmpty(dto.getCycle())) {
|
|
|
+ timeRangeMap = getTimeRangeMap(dto.getCycle());
|
|
|
+ }
|
|
|
// 1. 卸载时间差分布
|
|
|
QueryWrapper<MktDeviceTime> timeWrapper = new QueryWrapper<>();
|
|
|
+ if (timeRangeMap.get("startDate") != null && timeRangeMap.get("endDate") != null) {
|
|
|
+ timeWrapper.between("stat_date", timeRangeMap.get("startDate"), timeRangeMap.get("endDate"));
|
|
|
+ }
|
|
|
timeWrapper.eq("type", dto.getType());
|
|
|
if (!StringUtils.isEmpty(dto.getAppId())) timeWrapper.eq("app_id", dto.getAppId());
|
|
|
if (!StringUtils.isEmpty(dto.getChannel())) timeWrapper.eq("channel", dto.getChannel());
|
|
@@ -307,6 +326,7 @@ public class UninstallAnalyseServiceImpl implements UninstallAnalyseService {
|
|
|
// 2. 卸载前7天使用次数分布
|
|
|
QueryWrapper<MktDeviceCount> countWrapper = new QueryWrapper<>();
|
|
|
countWrapper.eq("type", dto.getType());
|
|
|
+ countWrapper.between("stat_date", timeRangeMap.get("startDate"), timeRangeMap.get("endDate"));
|
|
|
if (!StringUtils.isEmpty(dto.getAppId())) countWrapper.eq("app_id", dto.getAppId());
|
|
|
if (!StringUtils.isEmpty(dto.getChannel())) countWrapper.eq("channel", dto.getChannel());
|
|
|
if (!StringUtils.isEmpty(dto.getVersion())) countWrapper.eq("app_version", dto.getVersion());
|
|
@@ -338,13 +358,19 @@ public class UninstallAnalyseServiceImpl implements UninstallAnalyseService {
|
|
|
public UninstallBeforeInterfereVO uninstallInterfere(GetUninstallInsightDTO dto) {
|
|
|
|
|
|
UninstallBeforeInterfereVO result = new UninstallBeforeInterfereVO();
|
|
|
+
|
|
|
+ Map<String, LocalDate> timeRangeMap = new HashMap<>();
|
|
|
+ if (!StringUtils.isEmpty(dto.getCycle())) {
|
|
|
+ timeRangeMap = getTimeRangeMap(dto.getCycle());
|
|
|
+ }
|
|
|
ConfigItem configValue = null;
|
|
|
- if (!StringUtils.isEmpty(dto.getType())){
|
|
|
+ if (!StringUtils.isEmpty(dto.getType())) {
|
|
|
configValue = ConfigUtils.getConfigValue("Interfere_type", dto.getType());
|
|
|
}
|
|
|
List<Map<String, Integer>> value = new ArrayList<>();
|
|
|
// 3. 卸载前干扰指标
|
|
|
QueryWrapper<MktDeviceInterfere> interfereWrapper = new QueryWrapper<>();
|
|
|
+ interfereWrapper.between("stat_date", timeRangeMap.get("startDate"), timeRangeMap.get("endDate"));
|
|
|
interfereWrapper.eq("interfere_type", dto.getType());
|
|
|
if (!StringUtils.isEmpty(dto.getAppId())) interfereWrapper.eq("app_id", dto.getAppId());
|
|
|
if (!StringUtils.isEmpty(dto.getChannel())) interfereWrapper.eq("channel", dto.getChannel());
|
|
@@ -359,7 +385,7 @@ public class UninstallAnalyseServiceImpl implements UninstallAnalyseService {
|
|
|
}
|
|
|
if (configValue != null) {
|
|
|
result.setType(configValue.getLabel());
|
|
|
- }else {
|
|
|
+ } else {
|
|
|
result.setType("");
|
|
|
}
|
|
|
result.setValue(value);
|
|
@@ -375,13 +401,20 @@ public class UninstallAnalyseServiceImpl implements UninstallAnalyseService {
|
|
|
public UninstallBeforeActionVO uninstallAction(GetUninstallInsightDTO dto) {
|
|
|
|
|
|
UninstallBeforeActionVO result = new UninstallBeforeActionVO();
|
|
|
+
|
|
|
+ Map<String, LocalDate> timeRangeMap = new HashMap<>();
|
|
|
+ if (!StringUtils.isEmpty(dto.getCycle())) {
|
|
|
+ timeRangeMap = getTimeRangeMap(dto.getCycle());
|
|
|
+ }
|
|
|
+
|
|
|
ConfigItem configValue = null;
|
|
|
- if (!StringUtils.isEmpty(dto.getType())){
|
|
|
+ if (!StringUtils.isEmpty(dto.getType())) {
|
|
|
configValue = ConfigUtils.getConfigValue("Action_type", dto.getType());
|
|
|
}
|
|
|
// 4. 卸载前行为还原
|
|
|
QueryWrapper<MktDeviceAction> actionWrapper = new QueryWrapper<>();
|
|
|
- actionWrapper.eq("actionType", dto.getType());
|
|
|
+ actionWrapper.between("stat_date", timeRangeMap.get("startDate"), timeRangeMap.get("endDate"));
|
|
|
+ actionWrapper.eq("action_type", dto.getType());
|
|
|
if (!StringUtils.isEmpty(dto.getAppId())) actionWrapper.eq("app_id", dto.getAppId());
|
|
|
if (!StringUtils.isEmpty(dto.getChannel())) actionWrapper.eq("channel", dto.getChannel());
|
|
|
if (!StringUtils.isEmpty(dto.getVersion())) actionWrapper.eq("app_version", dto.getVersion());
|
|
@@ -398,7 +431,7 @@ public class UninstallAnalyseServiceImpl implements UninstallAnalyseService {
|
|
|
|
|
|
if (configValue != null) {
|
|
|
result.setActionType(configValue.getLabel());
|
|
|
- }else {
|
|
|
+ } else {
|
|
|
result.setActionType("");
|
|
|
}
|
|
|
|
|
@@ -430,7 +463,7 @@ public class UninstallAnalyseServiceImpl implements UninstallAnalyseService {
|
|
|
Map<String, List<Map<String, Integer>>> sysMap = new LinkedHashMap<>();
|
|
|
for (MktDeviceTime entity : list) {
|
|
|
sysMap.computeIfAbsent(entity.getTimeRange(), k -> new ArrayList<>())
|
|
|
- .add(Collections.singletonMap(entity.getAppVersion(), entity.getDeviceCount()));
|
|
|
+ .add(Collections.singletonMap(entity.getAppVersion(), entity.getDeviceCount()));
|
|
|
}
|
|
|
List<UninstallSYSOV> result = new ArrayList<>();
|
|
|
for (Map.Entry<String, List<Map<String, Integer>>> entry : sysMap.entrySet()) {
|
|
@@ -445,104 +478,248 @@ public class UninstallAnalyseServiceImpl implements UninstallAnalyseService {
|
|
|
@Override
|
|
|
public UninstallPortraitOV getUninstallPortrait(UninstallPortraitDTO dto) {
|
|
|
UninstallPortraitOV vo = new UninstallPortraitOV();
|
|
|
- // 1. 卸载数量
|
|
|
+
|
|
|
+ QueryWrapper<MktPortrait> wrapper = new QueryWrapper<>();
|
|
|
+
|
|
|
+ if (!StringUtils.isEmpty(dto.getTimeUnit())) {
|
|
|
+ wrapper.eq("stat_cycle", dto.getTimeUnit());
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!StringUtils.isEmpty(dto.getAppId())) {
|
|
|
+ wrapper.eq("app_id", dto.getAppId());
|
|
|
+ }
|
|
|
+ if (!StringUtils.isEmpty(dto.getChannel())) {
|
|
|
+ wrapper.eq("channel", dto.getChannel());
|
|
|
+ }
|
|
|
+ if (!StringUtils.isEmpty(dto.getVersion())) {
|
|
|
+ wrapper.eq("app_version", dto.getVersion());
|
|
|
+ }
|
|
|
+
|
|
|
+ LocalDate startDate, endDate;
|
|
|
+ if (!StringUtils.isEmpty(dto.getStartDate())) {
|
|
|
+ startDate = LocalDate.parse(dto.getStartDate());
|
|
|
+ } else {
|
|
|
+ // 默认当周第一天
|
|
|
+ LocalDate now = LocalDate.now();
|
|
|
+ startDate = now.with(DayOfWeek.MONDAY);
|
|
|
+ }
|
|
|
+
|
|
|
+ if ("week".equalsIgnoreCase(dto.getTimeUnit())) {
|
|
|
+ endDate = startDate.with(DayOfWeek.SUNDAY);
|
|
|
+ } else if ("month".equalsIgnoreCase(dto.getTimeUnit())) {
|
|
|
+ endDate = startDate.with(TemporalAdjusters.lastDayOfMonth());
|
|
|
+ } else {
|
|
|
+ endDate = startDate.with(DayOfWeek.SUNDAY);
|
|
|
+ }
|
|
|
+
|
|
|
+ wrapper.between("stat_date", startDate, endDate);
|
|
|
+
|
|
|
+ List<MktPortrait> portraitList = mktPortraitMapper.selectList(wrapper);
|
|
|
+
|
|
|
+ // 1. 卸载数量统计
|
|
|
UninstallPortraitSumOV sum = new UninstallPortraitSumOV();
|
|
|
sum.setTimeUnit(dto.getTimeUnit() == null ? "week" : dto.getTimeUnit());
|
|
|
- sum.setCount(1000 + random.nextInt(1000));
|
|
|
+
|
|
|
+ int totalCount = portraitList.stream()
|
|
|
+ .filter(p -> p.getStatus() != null)
|
|
|
+ .mapToInt(p -> p.getPhaseCount() != null ? p.getPhaseCount() : 0)
|
|
|
+ .sum();
|
|
|
+ sum.setCount(totalCount);
|
|
|
vo.setUninstallCount(sum);
|
|
|
- // 2. 用户特征情况
|
|
|
+
|
|
|
+ // 2. 用户特征情况(易卸载和不易卸载特征)
|
|
|
List<UninstallPortraitCharacterVO> charList = new ArrayList<>();
|
|
|
- String[] easyNames = {"专科", "便捷生活_智能生活", "社交通讯_同城本地社区", "影音娱乐_乐器", "教育_考公务员"};
|
|
|
- String[] hardNames = {"25-29岁", "三线城市", "普通消费", "商务办公_CRM营销工具", "影音娱乐_在线音乐"};
|
|
|
- for (String name : easyNames) {
|
|
|
+
|
|
|
+ List<MktPortrait> easyFeatures = portraitList.stream()
|
|
|
+ .filter(p -> p.getStatus() != null && p.getStatus() == 0)
|
|
|
+ .toList();
|
|
|
+
|
|
|
+ for (MktPortrait feature : easyFeatures) {
|
|
|
UninstallPortraitCharacterVO c = new UninstallPortraitCharacterVO();
|
|
|
- c.setName(name);
|
|
|
- c.setTgi(String.valueOf(80 + random.nextInt(40)));
|
|
|
- c.setPercent(String.valueOf(10 + random.nextInt(20)));
|
|
|
+ c.setName(feature.getFeatureName());
|
|
|
+ c.setTgi(feature.getTgi());
|
|
|
+ c.setPercent(feature.getPercent());
|
|
|
c.setStatus(0);
|
|
|
charList.add(c);
|
|
|
}
|
|
|
- for (String name : hardNames) {
|
|
|
+
|
|
|
+ List<MktPortrait> hardFeatures = portraitList.stream()
|
|
|
+ .filter(p -> p.getStatus() != null && p.getStatus() == 1)
|
|
|
+ .toList();
|
|
|
+
|
|
|
+ for (MktPortrait feature : hardFeatures) {
|
|
|
UninstallPortraitCharacterVO c = new UninstallPortraitCharacterVO();
|
|
|
- c.setName(name);
|
|
|
- c.setTgi(String.valueOf(80 + random.nextInt(40)));
|
|
|
- c.setPercent(String.valueOf(10 + random.nextInt(20)));
|
|
|
+ c.setName(feature.getFeatureName());
|
|
|
+ c.setTgi(feature.getTgi());
|
|
|
+ c.setPercent(feature.getPercent());
|
|
|
c.setStatus(1);
|
|
|
charList.add(c);
|
|
|
}
|
|
|
+
|
|
|
vo.setUninstallPortraitCharactList(charList);
|
|
|
- // 3. 卸载阶段
|
|
|
- String[] phases = {"未使用", "使用1次", "使用2次", "使用3次", "使用4次", "使用5次", "6次以上"};
|
|
|
+
|
|
|
+ // 3. 卸载阶段统计
|
|
|
List<UninstallPortraitPhaseVO> phaseList = new ArrayList<>();
|
|
|
- int total = 1000 + random.nextInt(1000);
|
|
|
- double percentSum = 0;
|
|
|
- int countSum = 0;
|
|
|
- double[] raw = new double[phases.length];
|
|
|
- double sumPhase = 0;
|
|
|
- for (int i = 0; i < phases.length; i++) {
|
|
|
- raw[i] = 10 + random.nextDouble() * 90;
|
|
|
- sumPhase += raw[i];
|
|
|
- }
|
|
|
- for (int i = 0; i < phases.length; i++) {
|
|
|
- UninstallPortraitPhaseVO p = new UninstallPortraitPhaseVO();
|
|
|
- p.setPhase(phases[i]);
|
|
|
- if (i < phases.length - 1) {
|
|
|
- p.setRate(Math.round(raw[i] / sumPhase * 10000.0) / 100.0);
|
|
|
- percentSum += p.getRate();
|
|
|
- p.setCount((int)Math.round(p.getRate() / 100 * total));
|
|
|
- countSum += p.getCount();
|
|
|
- } else {
|
|
|
- p.setRate(Math.round((100.0 - percentSum) * 100.0) / 100.0);
|
|
|
- p.setCount(total - countSum);
|
|
|
+
|
|
|
+ Map<String, List<MktPortrait>> phaseGroups = portraitList.stream()
|
|
|
+ .filter(p -> !StringUtils.isEmpty(p.getPhase()))
|
|
|
+ .collect(Collectors.groupingBy(MktPortrait::getPhase));
|
|
|
+
|
|
|
+ for (Map.Entry<String, List<MktPortrait>> entry : phaseGroups.entrySet()) {
|
|
|
+ String phase = entry.getKey();
|
|
|
+ ConfigItem phaseConfig = ConfigUtils.getConfigValue("Phase_type", phase);
|
|
|
+ List<MktPortrait> phaseData = entry.getValue();
|
|
|
+
|
|
|
+ // 计算该阶段的总数量和占比
|
|
|
+ int phaseCount = phaseData.stream()
|
|
|
+ .mapToInt(p -> p.getPhaseCount() != null ? p.getPhaseCount() : 0)
|
|
|
+ .sum();
|
|
|
+
|
|
|
+ double phaseRate = 0.0;
|
|
|
+ if (totalCount > 0) {
|
|
|
+ phaseRate = Math.round((double) phaseCount / totalCount * 10000.0) / 100.0;
|
|
|
}
|
|
|
+
|
|
|
+ UninstallPortraitPhaseVO p = new UninstallPortraitPhaseVO();
|
|
|
+ p.setPhase(!StringUtils.isEmpty(phaseConfig.getLabel()) ? phaseConfig.getLabel() : "");
|
|
|
+ p.setCount(phaseCount);
|
|
|
+ p.setRate(phaseRate);
|
|
|
phaseList.add(p);
|
|
|
}
|
|
|
+
|
|
|
vo.setUninstallPortraitPhaseList(phaseList);
|
|
|
+
|
|
|
return vo;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public UninstallPredictVO getUninstallPredict(UninstallPredictDTO dto) {
|
|
|
- UninstallPredictVO vo = new UninstallPredictVO();
|
|
|
- // 预测时间为一周最后一天
|
|
|
- LocalDate start = LocalDate.now();
|
|
|
- LocalDate predictTime = start.plusDays(6);
|
|
|
- vo.setPredictTime(predictTime.toString());
|
|
|
- vo.setUninstallCount(100 + random.nextInt(200));
|
|
|
- vo.setRecallCount(10 + random.nextInt(50));
|
|
|
- return vo;
|
|
|
+ public List<UninstallPredictVO> getUninstallPredict(UninstallPredictDTO dto) {
|
|
|
+ QueryWrapper<MktPredict> wrapper = new QueryWrapper<>();
|
|
|
+
|
|
|
+ if (dto.getType() != null) {
|
|
|
+ wrapper.eq("type", dto.getType());
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!StringUtils.isEmpty(dto.getCycle())) {
|
|
|
+ wrapper.eq("stat_cycle", dto.getCycle());
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!StringUtils.isEmpty(dto.getAppId())) {
|
|
|
+ wrapper.eq("app_id", dto.getAppId());
|
|
|
+ }
|
|
|
+ if (!StringUtils.isEmpty(dto.getChannel())) {
|
|
|
+ wrapper.eq("channel", dto.getChannel());
|
|
|
+ }
|
|
|
+ if (!StringUtils.isEmpty(dto.getVersion())) {
|
|
|
+ wrapper.eq("app_version", dto.getVersion());
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!StringUtils.isEmpty(dto.getStartDate()) && !StringUtils.isEmpty(dto.getEndDate())) {
|
|
|
+ wrapper.between("stat_date", dto.getStartDate(), dto.getEndDate());
|
|
|
+ }
|
|
|
+
|
|
|
+ List<MktPredict> predictList = mktPredictMapper.selectList(wrapper);
|
|
|
+
|
|
|
+ List<UninstallPredictVO> result = new ArrayList<>();
|
|
|
+
|
|
|
+ if (predictList != null && !predictList.isEmpty()) {
|
|
|
+ for (MktPredict entity : predictList) {
|
|
|
+ UninstallPredictVO vo = new UninstallPredictVO();
|
|
|
+
|
|
|
+ if (entity.getPredictTime() != null) {
|
|
|
+ vo.setPredictTime(entity.getPredictTime().toString());
|
|
|
+ } else {
|
|
|
+ LocalDate predictTime = LocalDate.now().with(DayOfWeek.MONDAY);
|
|
|
+ vo.setPredictTime(predictTime.toString());
|
|
|
+ }
|
|
|
+
|
|
|
+ vo.setUninstallCount(entity.getUninstallCount() != null ? entity.getUninstallCount() : 0);
|
|
|
+
|
|
|
+ if (entity.getType() != null && entity.getType() == 1) {
|
|
|
+ vo.setRecallCount(entity.getUninstallCount() != null ? entity.getUninstallCount() : 0);
|
|
|
+ } else {
|
|
|
+ vo.setRecallCount(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ result.add(vo);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public List<InstallUninstallRatioVO> getInstallUninstallRatio(InstallUninstallRatioDTO dto) {
|
|
|
- List<InstallUninstallRatioVO> list = new ArrayList<>();
|
|
|
- String[] types = {"当前应用", "移动视频", "医疗服务"};
|
|
|
- LocalDate start = LocalDate.now();
|
|
|
- for (String type : types) {
|
|
|
+ QueryWrapper<MktInstallUninstallRatio> wrapper = new QueryWrapper<>();
|
|
|
+
|
|
|
+ if (!StringUtils.isEmpty(dto.getCycle())) {
|
|
|
+ wrapper.eq("stat_cycle", dto.getCycle());
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!StringUtils.isEmpty(dto.getAppId())) {
|
|
|
+ wrapper.eq("app_id", dto.getAppId());
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!StringUtils.isEmpty(dto.getChannel())) {
|
|
|
+ wrapper.eq("channel", dto.getChannel());
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!StringUtils.isEmpty(dto.getVersion())) {
|
|
|
+ wrapper.eq("app_version", dto.getVersion());
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (!StringUtils.isEmpty(dto.getStartDate()) && !StringUtils.isEmpty(dto.getEndDate())) {
|
|
|
+ wrapper.between("stat_date", dto.getStartDate(), dto.getEndDate());
|
|
|
+ }
|
|
|
+
|
|
|
+ List<MktInstallUninstallRatio> ratioList = mktInstallUninstallRatioMapper.selectList(wrapper);
|
|
|
+
|
|
|
+ // 按日期分组,每个日期对应多个行业-占比
|
|
|
+ Map<Date, List<MktInstallUninstallRatio>> dateGroups = ratioList.stream()
|
|
|
+ .collect(Collectors.groupingBy(MktInstallUninstallRatio::getStatDate));
|
|
|
+
|
|
|
+ List<InstallUninstallRatioVO> result = new ArrayList<>();
|
|
|
+ for (Map.Entry<Date, List<MktInstallUninstallRatio>> entry : dateGroups.entrySet()) {
|
|
|
+ Date date = entry.getKey();
|
|
|
+ List<MktInstallUninstallRatio> dateData = entry.getValue();
|
|
|
+
|
|
|
InstallUninstallRatioVO vo = new InstallUninstallRatioVO();
|
|
|
- vo.setDate(java.sql.Date.valueOf(start));
|
|
|
- vo.setType(type);
|
|
|
- vo.setRate(Math.round((10 + random.nextDouble() * 90) * 100.0) / 100.0);
|
|
|
- list.add(vo);
|
|
|
+ vo.setDate(date);
|
|
|
+
|
|
|
+ // 构建该日期下的所有行业-占比数据
|
|
|
+ List<Map<String, Double>> typeList = new ArrayList<>();
|
|
|
+ for (MktInstallUninstallRatio entity : dateData) {
|
|
|
+ Map<String, Double> typeMap = new HashMap<>();
|
|
|
+
|
|
|
+ // 获取行业类型标签
|
|
|
+ String industryLabel = "未知类型";
|
|
|
+ if (entity.getIndustryType() != null) {
|
|
|
+ ConfigItem configValue = ConfigUtils.getConfigValue("Industry_type", String.valueOf(entity.getIndustryType()));
|
|
|
+ industryLabel = configValue != null ? configValue.getLabel() : "未知类型";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置占比
|
|
|
+ Double rate = entity.getRate() != null ? entity.getRate() : 0.0;
|
|
|
+ typeMap.put(industryLabel, rate);
|
|
|
+ typeList.add(typeMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ vo.setType(typeList);
|
|
|
+ result.add(vo);
|
|
|
}
|
|
|
- return list;
|
|
|
+
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public List<InstallUninstallRatioVO> getInstallUninstallRatioDetail(InstallUninstallRatioDTO dto) {
|
|
|
- List<InstallUninstallRatioVO> list = new ArrayList<>();
|
|
|
- String[] types = {"当前应用", "移动视频", "医疗服务"};
|
|
|
- LocalDate start = LocalDate.now();
|
|
|
- for (int i = 0; i < 7; i++) {
|
|
|
- LocalDate date = start.plusDays(i);
|
|
|
- for (String type : types) {
|
|
|
- InstallUninstallRatioVO vo = new InstallUninstallRatioVO();
|
|
|
- vo.setDate(java.sql.Date.valueOf(date));
|
|
|
- vo.setType(type);
|
|
|
- vo.setRate(Math.round((10 + random.nextDouble() * 90) * 100.0) / 100.0);
|
|
|
- list.add(vo);
|
|
|
- }
|
|
|
- }
|
|
|
- return list;
|
|
|
+ public Page<InstallUninstallRatioVO> getInstallUninstallRatioDetail(InstallUninstallRatioDTO dto) {
|
|
|
+ // 分页参数
|
|
|
+ int pageNum = dto.getPageNum() == null ? 1 : dto.getPageNum();
|
|
|
+ int pageSize = dto.getPageSize() == null ? 10 : dto.getPageSize();
|
|
|
+
|
|
|
+ List<InstallUninstallRatioVO> allData = getInstallUninstallRatio(dto);
|
|
|
+
|
|
|
+ // 使用PageUtils工具类处理分页
|
|
|
+ return PageUtils.buildPage(allData, pageNum, pageSize);
|
|
|
}
|
|
|
}
|