|
@@ -0,0 +1,1321 @@
|
|
|
|
+package com.pig4cloud.pig.statistics.service.impl;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
|
+import com.pig4cloud.pig.statistics.api.dto.user.*;
|
|
|
|
+import com.pig4cloud.pig.statistics.api.vo.user.*;
|
|
|
|
+import com.pig4cloud.pig.statistics.service.UserAnalyseService;
|
|
|
|
+import lombok.AllArgsConstructor;
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
|
+
|
|
|
|
+import java.math.BigDecimal;
|
|
|
|
+import java.math.RoundingMode;
|
|
|
|
+import java.time.DayOfWeek;
|
|
|
|
+import java.time.LocalDate;
|
|
|
|
+import java.time.LocalDateTime;
|
|
|
|
+import java.time.LocalTime;
|
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
|
+import java.time.temporal.ChronoUnit;
|
|
|
|
+import java.util.ArrayList;
|
|
|
|
+import java.util.Arrays;
|
|
|
|
+import java.util.List;
|
|
|
|
+import java.util.Random;
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * @author: lwh
|
|
|
|
+ * @date: 2025-08-06
|
|
|
|
+ * @description: 用户分析Service实现类
|
|
|
|
+ */
|
|
|
|
+@Slf4j
|
|
|
|
+@Service
|
|
|
|
+@AllArgsConstructor
|
|
|
|
+public class UserAnalyseServiceImpl implements UserAnalyseService {
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 获取新增趋势
|
|
|
|
+ * @param reqDto 请求参数
|
|
|
|
+ * @return GetNewUserTrendVO
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ public GetNewUserTrendVO getNewUserTrend(GetNewUserTrendDTO reqDto) {
|
|
|
|
+ GetNewUserTrendVO result = new GetNewUserTrendVO();
|
|
|
|
+ List<String> dates = new ArrayList<>();
|
|
|
|
+ String timeUnit = reqDto.getTimeUnit();
|
|
|
|
+ LocalDate fromDate = reqDto.getFromDate();
|
|
|
|
+ LocalDate toDate = reqDto.getToDate();
|
|
|
|
+
|
|
|
|
+ // 生成日期列表
|
|
|
|
+ switch (timeUnit) {
|
|
|
|
+ case "hour":
|
|
|
|
+ DateTimeFormatter hourFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:00");
|
|
|
|
+ LocalDateTime hourStart = fromDate.atStartOfDay();
|
|
|
|
+ LocalDateTime hourEnd = toDate.atTime(23, 0);
|
|
|
|
+ while (!hourStart.isAfter(hourEnd)) {
|
|
|
|
+ dates.add(hourStart.format(hourFormatter));
|
|
|
|
+ hourStart = hourStart.plusHours(1);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ case "day":
|
|
|
|
+ DateTimeFormatter dayFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
|
+ LocalDate dayStart = fromDate;
|
|
|
|
+ while (!dayStart.isAfter(toDate)) {
|
|
|
|
+ dates.add(dayStart.format(dayFormatter));
|
|
|
|
+ dayStart = dayStart.plusDays(1);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ case "week":
|
|
|
|
+ DateTimeFormatter weekFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
|
+ // 计算起始日期后的第一个周日
|
|
|
|
+ LocalDate currentWeek = fromDate;
|
|
|
|
+ DayOfWeek dayOfWeek = currentWeek.getDayOfWeek();
|
|
|
|
+ int daysToSunday = 7 - dayOfWeek.getValue(); // 周日的DayOfWeek值为7
|
|
|
|
+ LocalDate firstSunday = currentWeek.plusDays(daysToSunday);
|
|
|
|
+
|
|
|
|
+ while (!firstSunday.isAfter(toDate)) {
|
|
|
|
+ dates.add(firstSunday.format(weekFormatter));
|
|
|
|
+ firstSunday = firstSunday.plusWeeks(1);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ case "month":
|
|
|
|
+ DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
|
+ // 计算范围内的每月1号
|
|
|
|
+ LocalDate currentMonthFirstDay = LocalDate.of(fromDate.getYear(), fromDate.getMonth(), 1);
|
|
|
|
+ // 如果当月1号在起始日期之前,则取下个月1号
|
|
|
|
+ if (currentMonthFirstDay.isBefore(fromDate)) {
|
|
|
|
+ currentMonthFirstDay = currentMonthFirstDay.plusMonths(1);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ while (!currentMonthFirstDay.isAfter(toDate)) {
|
|
|
|
+ dates.add(currentMonthFirstDay.format(monthFormatter));
|
|
|
|
+ currentMonthFirstDay = currentMonthFirstDay.plusMonths(1);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ // 默认按天处理
|
|
|
|
+ DateTimeFormatter defaultFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
|
+ LocalDate defaultStart = fromDate;
|
|
|
|
+ while (!defaultStart.isAfter(toDate)) {
|
|
|
|
+ dates.add(defaultStart.format(defaultFormatter));
|
|
|
|
+ defaultStart = defaultStart.plusDays(1);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 生成items数据
|
|
|
|
+ List<TrendBaseVO> items = new ArrayList<>();
|
|
|
|
+ List<String> versions = reqDto.getVersion();
|
|
|
|
+ // 若未指定版本,使用默认版本列表
|
|
|
|
+ if (versions == null || versions.isEmpty()) {
|
|
|
|
+ versions = Arrays.asList("1.0", "5.1");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Random random = new Random();
|
|
|
|
+ for (String version : versions) {
|
|
|
|
+ TrendBaseVO trend = new TrendBaseVO();
|
|
|
|
+ trend.setName("新增用户");
|
|
|
|
+ trend.setVersion(version);
|
|
|
|
+ trend.setKey("newUser");
|
|
|
|
+
|
|
|
|
+ // 生成与日期数量匹配的随机数据
|
|
|
|
+ List<Integer> data = new ArrayList<>(dates.size());
|
|
|
|
+ for (int i = 0; i < dates.size(); i++) {
|
|
|
|
+ // 生成100-1000之间的随机数,模拟用户数量
|
|
|
|
+ data.add(random.nextInt(901) + 100);
|
|
|
|
+ }
|
|
|
|
+ trend.setData(data);
|
|
|
|
+ items.add(trend);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ result.setDates(dates);
|
|
|
|
+ result.setItems(items);
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 分页查询新增趋势详情
|
|
|
|
+ * @param reqDto 请求参数
|
|
|
|
+ * @return Page
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ public Page<PageNewUserTrendDetailVO> pageNewUserTrendDetail(PageNewUserTrendDetailDTO reqDto) {
|
|
|
|
+ // 创建分页对象
|
|
|
|
+ Page<PageNewUserTrendDetailVO> page = new Page<>(reqDto.getCurrent(), reqDto.getSize());
|
|
|
|
+ List<PageNewUserTrendDetailVO> result = new ArrayList<>();
|
|
|
|
+ List<String> timeLabels = new ArrayList<>();
|
|
|
|
+ String timeUnit = reqDto.getTimeUnit();
|
|
|
|
+ LocalDate startDate = reqDto.getFromDate();
|
|
|
|
+ LocalDate endDate = reqDto.getToDate();
|
|
|
|
+ Random random = new Random();
|
|
|
|
+
|
|
|
|
+ // 1. 根据时间单位生成对应的时间标签列表
|
|
|
|
+ switch (timeUnit) {
|
|
|
|
+ case "hour":
|
|
|
|
+ // 按小时生成:2025-08-05 23:00
|
|
|
|
+ LocalDateTime startHour = startDate.atStartOfDay();
|
|
|
|
+ LocalDateTime endHour = endDate.atTime(23, 0);
|
|
|
|
+ LocalDateTime currentHour = startHour;
|
|
|
|
+ DateTimeFormatter hourFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
|
|
|
|
+
|
|
|
|
+ while (!currentHour.isAfter(endHour)) {
|
|
|
|
+ timeLabels.add(currentHour.format(hourFormatter));
|
|
|
|
+ currentHour = currentHour.plusHours(1);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case "day":
|
|
|
|
+ // 按天生成:2025-08-03
|
|
|
|
+ LocalDate currentDay = startDate;
|
|
|
|
+ DateTimeFormatter dayFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
|
+
|
|
|
|
+ while (!currentDay.isAfter(endDate)) {
|
|
|
|
+ timeLabels.add(currentDay.format(dayFormatter));
|
|
|
|
+ currentDay = currentDay.plusDays(1);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case "week":
|
|
|
|
+ // 按周生成:2025/07/27~2025/08/02
|
|
|
|
+ LocalDate currentWeekStart = startDate;
|
|
|
|
+ DateTimeFormatter weekFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
|
|
|
|
+
|
|
|
|
+ while (!currentWeekStart.isAfter(endDate)) {
|
|
|
|
+ LocalDate currentWeekEnd = currentWeekStart.plusDays(6);
|
|
|
|
+ if (currentWeekEnd.isAfter(endDate)) {
|
|
|
|
+ currentWeekEnd = endDate;
|
|
|
|
+ }
|
|
|
|
+ timeLabels.add(currentWeekStart.format(weekFormatter) + "~" + currentWeekEnd.format(weekFormatter));
|
|
|
|
+ currentWeekStart = currentWeekStart.plusWeeks(1);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case "month":
|
|
|
|
+ // 按月生成:2025/07/01~2025/07/31
|
|
|
|
+ LocalDate currentMonthStart = startDate;
|
|
|
|
+ DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
|
|
|
|
+
|
|
|
|
+ while (!currentMonthStart.isAfter(endDate)) {
|
|
|
|
+ LocalDate currentMonthEnd = currentMonthStart.plusMonths(1).minusDays(1);
|
|
|
|
+ if (currentMonthEnd.isAfter(endDate)) {
|
|
|
|
+ currentMonthEnd = endDate;
|
|
|
|
+ }
|
|
|
|
+ timeLabels.add(currentMonthStart.withDayOfMonth(1).format(monthFormatter) + "~" + currentMonthEnd.format(monthFormatter));
|
|
|
|
+ currentMonthStart = currentMonthStart.plusMonths(1);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ default:
|
|
|
|
+ throw new IllegalArgumentException("不支持的时间单位: " + timeUnit);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 2. 计算总记录数并设置到分页对象
|
|
|
|
+ long total = timeLabels.size();
|
|
|
|
+ page.setTotal(total);
|
|
|
|
+
|
|
|
|
+ // 3. 计算分页范围
|
|
|
|
+ long startIndex = (reqDto.getCurrent() - 1) * reqDto.getSize();
|
|
|
|
+ long endIndex = Math.min(startIndex + reqDto.getSize(), total);
|
|
|
|
+
|
|
|
|
+ // 4. 生成当前页的模拟数据
|
|
|
|
+ if (startIndex < total) {
|
|
|
|
+ double baseRate = 0.05; // 基础占比基数(5%)
|
|
|
|
+
|
|
|
|
+ for (long i = startIndex; i < endIndex; i++) {
|
|
|
|
+ PageNewUserTrendDetailVO vo = new PageNewUserTrendDetailVO();
|
|
|
|
+ vo.setDate(timeLabels.get((int) i));
|
|
|
|
+
|
|
|
|
+ // 生成新增用户数(随时间增长并带有随机波动)
|
|
|
|
+ int baseUsers = 100 + (int) (i * 5);
|
|
|
|
+ int randomUsers = random.nextInt(60) - 20; // 随机波动(-20至39)
|
|
|
|
+ vo.setNewUser(Math.max(10, baseUsers + randomUsers));
|
|
|
|
+
|
|
|
|
+ // 生成新增用户占比(保留两位小数)
|
|
|
|
+ double rateFluctuation = (random.nextDouble() - 0.5) * 0.03;
|
|
|
|
+ double userRate = baseRate + rateFluctuation;
|
|
|
|
+ vo.setNewUserRate(Math.round(userRate * 100) / 100.0);
|
|
|
|
+
|
|
|
|
+ result.add(vo);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 5. 设置分页数据并返回
|
|
|
|
+ page.setRecords(result);
|
|
|
|
+ return page;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 查询次日留存率
|
|
|
|
+ * @param reqDto 获取次日留存率入参
|
|
|
|
+ * @return GetNewUserRetentionVO
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ public GetNewUserRetentionVO getNewUserRetention(GetNewUserRetentionDTO reqDto) {
|
|
|
|
+ GetNewUserRetentionVO vo = new GetNewUserRetentionVO();
|
|
|
|
+ List<String> dates = new ArrayList<>();
|
|
|
|
+ List<Double> counts = new ArrayList<>();
|
|
|
|
+
|
|
|
|
+ // 计算日期范围并生成模拟数据
|
|
|
|
+ LocalDate start = reqDto.getFromDate();
|
|
|
|
+ LocalDate end = reqDto.getToDate();
|
|
|
|
+ long days = ChronoUnit.DAYS.between(start, end) + 1;
|
|
|
|
+
|
|
|
|
+ Random random = new Random();
|
|
|
|
+ for (int i = 0; i < days; i++) {
|
|
|
|
+ dates.add(start.plusDays(i).toString());
|
|
|
|
+ // 生成5%-30%之间的留存率,保留两位小数
|
|
|
|
+ double rate = 5 + random.nextDouble() * 25;
|
|
|
|
+ // 使用BigDecimal处理小数位数
|
|
|
|
+ BigDecimal bd = new BigDecimal(rate).setScale(2, RoundingMode.HALF_UP);
|
|
|
|
+ counts.add(bd.doubleValue());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ vo.setDates(dates);
|
|
|
|
+ vo.setRetention(counts);
|
|
|
|
+ return vo;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 分页查询次日留存率详情
|
|
|
|
+ * @param reqDto 分页查询次日留存率详情入参
|
|
|
|
+ * @return Page
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ public Page<PageRetentionDetailVO> pageNewUserRetentionDetail(PageRetentionDetailDTO reqDto) {
|
|
|
|
+ // 创建分页对象
|
|
|
|
+ Page<PageRetentionDetailVO> page = new Page<>(reqDto.getCurrent(), reqDto.getSize());
|
|
|
|
+ List<PageRetentionDetailVO> result = new ArrayList<>();
|
|
|
|
+
|
|
|
|
+ // 1. 生成日期列表(根据时间范围)
|
|
|
|
+ List<String> dates = new ArrayList<>();
|
|
|
|
+ LocalDate currentDate = reqDto.getFromDate();
|
|
|
|
+ LocalDate endDate = reqDto.getToDate();
|
|
|
|
+
|
|
|
|
+ // 格式化日期的工具
|
|
|
|
+ DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
|
+
|
|
|
|
+ // 生成从开始日期到结束日期的所有日期
|
|
|
|
+ while (!currentDate.isAfter(endDate)) {
|
|
|
|
+ dates.add(currentDate.format(dateFormatter));
|
|
|
|
+ currentDate = currentDate.plusDays(1);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 2. 设置总记录数
|
|
|
|
+ long total = dates.size();
|
|
|
|
+ page.setTotal(total);
|
|
|
|
+
|
|
|
|
+ // 3. 计算分页范围
|
|
|
|
+ long startIndex = (reqDto.getCurrent() - 1) * reqDto.getSize();
|
|
|
|
+ long endIndex = Math.min(startIndex + reqDto.getSize(), total);
|
|
|
|
+
|
|
|
|
+ // 4. 生成当前页的模拟数据
|
|
|
|
+ if (startIndex < total) {
|
|
|
|
+ Random random = new Random();
|
|
|
|
+
|
|
|
|
+ for (long i = startIndex; i < endIndex; i++) {
|
|
|
|
+ PageRetentionDetailVO vo = new PageRetentionDetailVO();
|
|
|
|
+
|
|
|
|
+ // 设置日期
|
|
|
|
+ vo.setDate(dates.get((int) i));
|
|
|
|
+
|
|
|
|
+ // 生成留存率(5%-30%之间的随机数,保留两位小数)
|
|
|
|
+ double baseRate = 5 + random.nextDouble() * 25; // 5% ~ 30%
|
|
|
|
+ // 使用四舍五入保留两位小数
|
|
|
|
+ double retention = Math.round(baseRate * 100) / 100.0;
|
|
|
|
+ vo.setRetention(retention);
|
|
|
|
+
|
|
|
|
+ result.add(vo);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 5. 设置分页数据
|
|
|
|
+ page.setRecords(result);
|
|
|
|
+ return page;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /************************************** 活跃用户 *****************************************
|
|
|
|
+ * 查询活跃趋势
|
|
|
|
+ * @param reqDto 查询活跃趋势入参
|
|
|
|
+ * @return GetNewUserTrendVO
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ public GetNewUserTrendVO getActiveTrend(UserAnalyseQueryBaseDTO reqDto) {
|
|
|
|
+ GetNewUserTrendVO result = new GetNewUserTrendVO();
|
|
|
|
+ List<String> dates = new ArrayList<>();
|
|
|
|
+ String timeUnit = reqDto.getTimeUnit();
|
|
|
|
+ LocalDate fromDate = reqDto.getFromDate();
|
|
|
|
+ LocalDate toDate = reqDto.getToDate();
|
|
|
|
+
|
|
|
|
+ // 生成日期列表
|
|
|
|
+ switch (timeUnit) {
|
|
|
|
+ case "hour":
|
|
|
|
+ DateTimeFormatter hourFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:00");
|
|
|
|
+ LocalDateTime hourStart = fromDate.atStartOfDay();
|
|
|
|
+ LocalDateTime hourEnd = toDate.atTime(23, 0);
|
|
|
|
+ while (!hourStart.isAfter(hourEnd)) {
|
|
|
|
+ dates.add(hourStart.format(hourFormatter));
|
|
|
|
+ hourStart = hourStart.plusHours(1);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ case "day":
|
|
|
|
+ DateTimeFormatter dayFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
|
+ LocalDate dayStart = fromDate;
|
|
|
|
+ while (!dayStart.isAfter(toDate)) {
|
|
|
|
+ dates.add(dayStart.format(dayFormatter));
|
|
|
|
+ dayStart = dayStart.plusDays(1);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ case "week":
|
|
|
|
+ DateTimeFormatter weekFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
|
+ // 计算起始日期后的第一个周日
|
|
|
|
+ LocalDate currentWeek = fromDate;
|
|
|
|
+ DayOfWeek dayOfWeek = currentWeek.getDayOfWeek();
|
|
|
|
+ int daysToSunday = 7 - dayOfWeek.getValue(); // 周日的DayOfWeek值为7
|
|
|
|
+ LocalDate firstSunday = currentWeek.plusDays(daysToSunday);
|
|
|
|
+
|
|
|
|
+ while (!firstSunday.isAfter(toDate)) {
|
|
|
|
+ dates.add(firstSunday.format(weekFormatter));
|
|
|
|
+ firstSunday = firstSunday.plusWeeks(1);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ case "month":
|
|
|
|
+ DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
|
+ // 计算范围内的每月1号
|
|
|
|
+ LocalDate currentMonthFirstDay = LocalDate.of(fromDate.getYear(), fromDate.getMonth(), 1);
|
|
|
|
+ // 如果当月1号在起始日期之前,则取下个月1号
|
|
|
|
+ if (currentMonthFirstDay.isBefore(fromDate)) {
|
|
|
|
+ currentMonthFirstDay = currentMonthFirstDay.plusMonths(1);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ while (!currentMonthFirstDay.isAfter(toDate)) {
|
|
|
|
+ dates.add(currentMonthFirstDay.format(monthFormatter));
|
|
|
|
+ currentMonthFirstDay = currentMonthFirstDay.plusMonths(1);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ // 默认按天处理
|
|
|
|
+ DateTimeFormatter defaultFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
|
+ LocalDate defaultStart = fromDate;
|
|
|
|
+ while (!defaultStart.isAfter(toDate)) {
|
|
|
|
+ dates.add(defaultStart.format(defaultFormatter));
|
|
|
|
+ defaultStart = defaultStart.plusDays(1);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 生成items数据
|
|
|
|
+ List<TrendBaseVO> items = new ArrayList<>();
|
|
|
|
+ List<String> versions = reqDto.getVersion();
|
|
|
|
+ // 若未指定版本,使用默认版本列表
|
|
|
|
+ if (versions == null || versions.isEmpty()) {
|
|
|
|
+ versions = Arrays.asList("1.0", "5.1");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Random random = new Random();
|
|
|
|
+ for (String version : versions) {
|
|
|
|
+ TrendBaseVO trend = new TrendBaseVO();
|
|
|
|
+ trend.setName("活跃用户");
|
|
|
|
+ trend.setVersion(version);
|
|
|
|
+ trend.setKey("activeUser");
|
|
|
|
+
|
|
|
|
+ // 生成与日期数量匹配的随机数据
|
|
|
|
+ List<Integer> data = new ArrayList<>(dates.size());
|
|
|
|
+ for (int i = 0; i < dates.size(); i++) {
|
|
|
|
+ // 生成100-1000之间的随机数,模拟用户数量
|
|
|
|
+ data.add(random.nextInt(901) + 100);
|
|
|
|
+ }
|
|
|
|
+ trend.setData(data);
|
|
|
|
+ items.add(trend);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ result.setDates(dates);
|
|
|
|
+ result.setItems(items);
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 查询活跃构成
|
|
|
|
+ * @param reqDto 查询活跃构成入参
|
|
|
|
+ * @return GetActiveComposeVO
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ public GetActiveUserBaseVO getActiveCompose(UserAnalyseQueryBaseDTO reqDto) {
|
|
|
|
+ // 创建返回对象
|
|
|
|
+ GetActiveUserBaseVO result = new GetActiveUserBaseVO();
|
|
|
|
+ Random random = new Random();
|
|
|
|
+
|
|
|
|
+ // 1. 生成日期列表
|
|
|
|
+ List<String> dates = new ArrayList<>();
|
|
|
|
+ LocalDate startDate = reqDto.getFromDate();
|
|
|
|
+ LocalDate endDate = reqDto.getToDate();
|
|
|
|
+ LocalDateTime currentDateTime = LocalDateTime.of(startDate, LocalTime.MIN);
|
|
|
|
+ LocalDateTime endDateTime = LocalDateTime.of(endDate, LocalTime.MAX);
|
|
|
|
+
|
|
|
|
+ // 根据时间单位生成对应日期
|
|
|
|
+ while (!currentDateTime.isAfter(endDateTime)) {
|
|
|
|
+ String dateStr;
|
|
|
|
+ switch (reqDto.getTimeUnit()) {
|
|
|
|
+ case "hour":
|
|
|
|
+ dateStr = currentDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
|
|
|
|
+ currentDateTime = currentDateTime.plusHours(1);
|
|
|
|
+ break;
|
|
|
|
+ case "day":
|
|
|
|
+ dateStr = currentDateTime.toLocalDate().format(DateTimeFormatter.ISO_LOCAL_DATE);
|
|
|
|
+ currentDateTime = currentDateTime.plusDays(1);
|
|
|
|
+ break;
|
|
|
|
+ case "week":
|
|
|
|
+ LocalDate weekStart = currentDateTime.toLocalDate();
|
|
|
|
+ LocalDate weekEnd = weekStart.plusDays(6);
|
|
|
|
+ if (weekEnd.isAfter(endDate)) {
|
|
|
|
+ weekEnd = endDate;
|
|
|
|
+ }
|
|
|
|
+ dateStr = weekStart.format(DateTimeFormatter.ISO_LOCAL_DATE) + "~" +
|
|
|
|
+ weekEnd.format(DateTimeFormatter.ISO_LOCAL_DATE);
|
|
|
|
+ currentDateTime = currentDateTime.plusWeeks(1);
|
|
|
|
+ break;
|
|
|
|
+ case "month":
|
|
|
|
+ LocalDate monthStart = currentDateTime.toLocalDate();
|
|
|
|
+ LocalDate monthEnd = monthStart.plusMonths(1).minusDays(1);
|
|
|
|
+ if (monthEnd.isAfter(endDate)) {
|
|
|
|
+ monthEnd = endDate;
|
|
|
|
+ }
|
|
|
|
+ dateStr = monthStart.withDayOfMonth(1).format(DateTimeFormatter.ISO_LOCAL_DATE) + "~" +
|
|
|
|
+ monthEnd.format(DateTimeFormatter.ISO_LOCAL_DATE);
|
|
|
|
+ currentDateTime = currentDateTime.plusMonths(1);
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ dateStr = currentDateTime.toLocalDate().format(DateTimeFormatter.ISO_LOCAL_DATE);
|
|
|
|
+ currentDateTime = currentDateTime.plusDays(1);
|
|
|
|
+ }
|
|
|
|
+ dates.add(dateStr);
|
|
|
|
+ }
|
|
|
|
+ result.setDates(dates);
|
|
|
|
+
|
|
|
|
+ // 2. 生成各项数据(调整为Double类型列表)
|
|
|
|
+ List<ActiveUserComposeVO> items = new ArrayList<>();
|
|
|
|
+ int dataSize = dates.size();
|
|
|
|
+
|
|
|
|
+ // 活跃用户数据(整数转为Double)
|
|
|
|
+ ActiveUserComposeVO activeUser = new ActiveUserComposeVO();
|
|
|
|
+ activeUser.setName("活跃用户");
|
|
|
|
+ List<Double> activeData = new ArrayList<>();
|
|
|
|
+ for (int i = 0; i < dataSize; i++) {
|
|
|
|
+ int value = 30000 + random.nextInt(5000) + (i * 50);
|
|
|
|
+ activeData.add((double) value); // 整数转Double
|
|
|
|
+ }
|
|
|
|
+ activeUser.setData(activeData);
|
|
|
|
+ items.add(activeUser);
|
|
|
|
+
|
|
|
|
+ // 新增用户数据(整数转为Double)
|
|
|
|
+ ActiveUserComposeVO newUser = new ActiveUserComposeVO();
|
|
|
|
+ newUser.setName("新增用户");
|
|
|
|
+ List<Double> newUserData = new ArrayList<>();
|
|
|
|
+ for (int i = 0; i < dataSize; i++) {
|
|
|
|
+ int value = activeData.get(i).intValue() - 100 - random.nextInt(300);
|
|
|
|
+ newUserData.add((double) value); // 整数转Double
|
|
|
|
+ }
|
|
|
|
+ newUser.setData(newUserData);
|
|
|
|
+ items.add(newUser);
|
|
|
|
+
|
|
|
|
+ // 新增用户占比数据(保持Double类型)
|
|
|
|
+ ActiveUserComposeVO newUserRate = new ActiveUserComposeVO();
|
|
|
|
+ newUserRate.setName("新增用户占比");
|
|
|
|
+ List<Double> rateData = new ArrayList<>();
|
|
|
|
+ for (int i = 0; i < dataSize; i++) {
|
|
|
|
+ double rate = (newUserData.get(i) / activeData.get(i)) * 100;
|
|
|
|
+ rateData.add(Math.round(rate * 100) / 100.0); // 保留两位小数
|
|
|
|
+ }
|
|
|
|
+ newUserRate.setData(rateData);
|
|
|
|
+ items.add(newUserRate);
|
|
|
|
+
|
|
|
|
+ // 老用户数据(计算后转为Double)
|
|
|
|
+ ActiveUserComposeVO oldUser = new ActiveUserComposeVO();
|
|
|
|
+ oldUser.setName("老用户");
|
|
|
|
+ List<Double> oldUserData = new ArrayList<>();
|
|
|
|
+ for (int i = 0; i < dataSize; i++) {
|
|
|
|
+ double value = activeData.get(i) - newUserData.get(i);
|
|
|
|
+ oldUserData.add(value); // 直接为Double类型
|
|
|
|
+ }
|
|
|
|
+ oldUser.setData(oldUserData);
|
|
|
|
+ items.add(oldUser);
|
|
|
|
+
|
|
|
|
+ result.setItems(items);
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 获取活跃粘度
|
|
|
|
+ * @param reqDto 获取活跃粘度入参
|
|
|
|
+ * @return GetActiveUserBaseVO
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ public GetActiveUserBaseVO getActiveViscosity(UserAnalyseQueryBaseDTO reqDto) {
|
|
|
|
+ GetActiveUserBaseVO result = new GetActiveUserBaseVO();
|
|
|
|
+
|
|
|
|
+ // 构建日期列表(可根据 reqDto 的 fromDate 和 toDate 动态生成,此处为示例固定日期)
|
|
|
|
+ List<String> dates = Arrays.asList(
|
|
|
|
+ "2025-07-29", "2025-07-30", "2025-07-31",
|
|
|
|
+ "2025-08-01", "2025-08-02", "2025-08-03",
|
|
|
|
+ "2025-08-04", "2025-08-05"
|
|
|
|
+ );
|
|
|
|
+ result.setDates(dates);
|
|
|
|
+
|
|
|
|
+ // 构建活跃用户组成数据
|
|
|
|
+ List<ActiveUserComposeVO> items = new ArrayList<>();
|
|
|
|
+
|
|
|
|
+ // 日活数据
|
|
|
|
+ ActiveUserComposeVO activeUserItem = new ActiveUserComposeVO();
|
|
|
|
+ activeUserItem.setName("日活");
|
|
|
|
+ activeUserItem.setData(Arrays.asList(1523.0, 1489.0, 1602.0, 1576.0, 987.0, 923.0, 1756.0, 1632.0));
|
|
|
|
+ items.add(activeUserItem);
|
|
|
|
+
|
|
|
|
+ // 过去7日活跃用户数据
|
|
|
|
+ ActiveUserComposeVO wauItem = new ActiveUserComposeVO();
|
|
|
|
+ wauItem.setName("过去7日活跃用户");
|
|
|
|
+ wauItem.setData(Arrays.asList(8234.0, 8156.0, 8321.0, 8289.0, 8356.0, 8412.0, 8531.0, 8498.0));
|
|
|
|
+ items.add(wauItem);
|
|
|
|
+
|
|
|
|
+ // DAU/过去7日活跃用户比率
|
|
|
|
+ ActiveUserComposeVO wauRateItem = new ActiveUserComposeVO();
|
|
|
|
+ wauRateItem.setName("DAU/过去7日活跃用户");
|
|
|
|
+ wauRateItem.setData(Arrays.asList(18.5, 18.25, 19.25, 19.01, 11.81, 10.97, 20.58, 19.21));
|
|
|
|
+ items.add(wauRateItem);
|
|
|
|
+
|
|
|
|
+ // 过去30日活跃用户数据
|
|
|
|
+ ActiveUserComposeVO mauItem = new ActiveUserComposeVO();
|
|
|
|
+ mauItem.setName("过去30日活跃用户");
|
|
|
|
+ mauItem.setData(Arrays.asList(35621.0, 35489.0, 35723.0, 35698.0, 34987.0, 34215.0, 35123.0, 36012.0));
|
|
|
|
+ items.add(mauItem);
|
|
|
|
+
|
|
|
|
+ // DAU/过去30日活跃用户比率
|
|
|
|
+ ActiveUserComposeVO mauRateItem = new ActiveUserComposeVO();
|
|
|
|
+ mauRateItem.setName("DAU/过去30日活跃用户");
|
|
|
|
+ mauRateItem.setData(Arrays.asList(4.28, 4.19, 4.48, 4.42, 2.82, 2.70, 5.00, 4.53));
|
|
|
|
+ items.add(mauRateItem);
|
|
|
|
+
|
|
|
|
+ result.setItems(items);
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 获取周活跃率
|
|
|
|
+ * @param reqDto 获取周活跃率入参
|
|
|
|
+ * @return GetActiveUserBaseVO
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ public GetActiveUserBaseVO getActiveWeekrate(UserAnalyseQueryBaseDTO reqDto) {
|
|
|
|
+ GetActiveUserBaseVO result = new GetActiveUserBaseVO();
|
|
|
|
+ Random random = new Random();
|
|
|
|
+ DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
|
+
|
|
|
|
+ // 1. 生成周日期列表(每周一)
|
|
|
|
+ List<String> dates = new ArrayList<>();
|
|
|
|
+ LocalDate currentDate = reqDto.getFromDate();
|
|
|
|
+ // 调整到当周周一
|
|
|
|
+ currentDate = currentDate.minusDays(currentDate.getDayOfWeek().getValue() - 1);
|
|
|
|
+
|
|
|
|
+ while (!currentDate.isAfter(reqDto.getToDate())) {
|
|
|
|
+ dates.add(currentDate.format(dateFormatter));
|
|
|
|
+ currentDate = currentDate.plusWeeks(1);
|
|
|
|
+ }
|
|
|
|
+ result.setDates(dates);
|
|
|
|
+ int dataSize = dates.size();
|
|
|
|
+
|
|
|
|
+ // 2. 生成周累积用户数据(240万起,每周递增0.2%-0.4%)
|
|
|
|
+ List<Double> weekTotalUserList = new ArrayList<>();
|
|
|
|
+ double baseTotal = 2400000;
|
|
|
|
+ for (int i = 0; i < dataSize; i++) {
|
|
|
|
+ baseTotal += baseTotal * (0.002 + random.nextDouble() * 0.002);
|
|
|
|
+ // 四舍五入取整(内部实现四舍五入逻辑)
|
|
|
|
+ weekTotalUserList.add((double) Math.round(baseTotal));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 3. 生成周活跃用户数据(周累积的0.28%-0.33%)
|
|
|
|
+ List<Double> weekActiveUserList = new ArrayList<>();
|
|
|
|
+ for (double total : weekTotalUserList) {
|
|
|
|
+ double active = total * (0.0028 + random.nextDouble() * 0.0005);
|
|
|
|
+ weekActiveUserList.add((double) Math.round(active)); // 四舍五入取整
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 4. 生成周活跃用户率(保留两位小数)
|
|
|
|
+ List<Double> weekActiveRateList = new ArrayList<>();
|
|
|
|
+ for (int i = 0; i < dataSize; i++) {
|
|
|
|
+ double rate = (weekActiveUserList.get(i) / weekTotalUserList.get(i)) * 100;
|
|
|
|
+ // 四舍五入保留两位小数:先乘100取整再除以100
|
|
|
|
+ weekActiveRateList.add(Math.round(rate * 100) / 100.0);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 5. 组装返回数据
|
|
|
|
+ List<ActiveUserComposeVO> items = new ArrayList<>();
|
|
|
|
+
|
|
|
|
+ // 周累积用户
|
|
|
|
+ ActiveUserComposeVO totalItem = new ActiveUserComposeVO();
|
|
|
|
+ totalItem.setName("周累积用户");
|
|
|
|
+ totalItem.setData(weekTotalUserList);
|
|
|
|
+ items.add(totalItem);
|
|
|
|
+
|
|
|
|
+ // 周活跃用户
|
|
|
|
+ ActiveUserComposeVO activeItem = new ActiveUserComposeVO();
|
|
|
|
+ activeItem.setName("周活跃用户");
|
|
|
|
+ activeItem.setData(weekActiveUserList);
|
|
|
|
+ items.add(activeItem);
|
|
|
|
+
|
|
|
|
+ // 周活跃用户率
|
|
|
|
+ ActiveUserComposeVO rateItem = new ActiveUserComposeVO();
|
|
|
|
+ rateItem.setName("周活跃用户率");
|
|
|
|
+ rateItem.setData(weekActiveRateList);
|
|
|
|
+ items.add(rateItem);
|
|
|
|
+
|
|
|
|
+ result.setItems(items);
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 获取月活跃率
|
|
|
|
+ * @param reqDto 获取月活跃率入参
|
|
|
|
+ * @return GetActiveUserBaseVO
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ public GetActiveUserBaseVO getActiveMonthrate(UserAnalyseQueryBaseDTO reqDto) {
|
|
|
|
+ // 创建返回对象
|
|
|
|
+ GetActiveUserBaseVO result = new GetActiveUserBaseVO();
|
|
|
|
+ Random random = new Random();
|
|
|
|
+ DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
|
+
|
|
|
|
+ // 1. 生成月日期列表(每月1日)
|
|
|
|
+ List<String> dates = new ArrayList<>();
|
|
|
|
+ LocalDate currentDate = reqDto.getFromDate();
|
|
|
|
+
|
|
|
|
+ // 调整到当月1日
|
|
|
|
+ currentDate = currentDate.withDayOfMonth(1);
|
|
|
|
+
|
|
|
|
+ // 按月生成日期直到结束日期
|
|
|
|
+ while (!currentDate.isAfter(reqDto.getToDate())) {
|
|
|
|
+ dates.add(currentDate.format(dateFormatter));
|
|
|
|
+ currentDate = currentDate.plusMonths(1);
|
|
|
|
+ }
|
|
|
|
+ result.setDates(dates);
|
|
|
|
+ int dataSize = dates.size();
|
|
|
|
+
|
|
|
|
+ // 2. 生成月累积用户数据(基础值250万,每月递增约1.2%-1.8%)
|
|
|
|
+ List<Double> monthTotalUserList = new ArrayList<>();
|
|
|
|
+ double baseTotal = 2500000; // 基础用户量
|
|
|
|
+ for (int i = 0; i < dataSize; i++) {
|
|
|
|
+ // 每月增加1.2%-1.8%的随机增长
|
|
|
|
+ double growth = baseTotal * (0.012 + random.nextDouble() * 0.006);
|
|
|
|
+ baseTotal += growth;
|
|
|
|
+ monthTotalUserList.add((double) Math.round(baseTotal)); // 取整数
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 3. 生成月活跃用户数据(月累积用户的1.2%-1.4%)
|
|
|
|
+ List<Double> monthActiveUserList = new ArrayList<>();
|
|
|
|
+ for (double total : monthTotalUserList) {
|
|
|
|
+ double activeRate = 0.012 + random.nextDouble() * 0.002; // 1.2% - 1.4%
|
|
|
|
+ monthActiveUserList.add((double) Math.round(total * activeRate)); // 取整数
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 4. 生成月活跃用户率(月活跃/月累积,保留两位小数)
|
|
|
|
+ List<Double> monthActiveRateList = new ArrayList<>();
|
|
|
|
+ for (int i = 0; i < dataSize; i++) {
|
|
|
|
+ double rate = (monthActiveUserList.get(i) / monthTotalUserList.get(i)) * 100;
|
|
|
|
+ monthActiveRateList.add(Math.round(rate * 100) / 100.0); // 保留两位小数
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 5. 组装items数据
|
|
|
|
+ List<ActiveUserComposeVO> items = new ArrayList<>();
|
|
|
|
+
|
|
|
|
+ // 月累积用户
|
|
|
|
+ ActiveUserComposeVO totalUserItem = new ActiveUserComposeVO();
|
|
|
|
+ totalUserItem.setName("月累积用户");
|
|
|
|
+ totalUserItem.setData(monthTotalUserList);
|
|
|
|
+ items.add(totalUserItem);
|
|
|
|
+
|
|
|
|
+ // 月活跃用户
|
|
|
|
+ ActiveUserComposeVO activeUserItem = new ActiveUserComposeVO();
|
|
|
|
+ activeUserItem.setName("月活跃用户");
|
|
|
|
+ activeUserItem.setData(monthActiveUserList);
|
|
|
|
+ items.add(activeUserItem);
|
|
|
|
+
|
|
|
|
+ // 月活跃用户率
|
|
|
|
+ ActiveUserComposeVO rateItem = new ActiveUserComposeVO();
|
|
|
|
+ rateItem.setName("月活跃用户率");
|
|
|
|
+ rateItem.setData(monthActiveRateList);
|
|
|
|
+ items.add(rateItem);
|
|
|
|
+
|
|
|
|
+ result.setItems(items);
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 分页查询活跃详情
|
|
|
|
+ * @param reqDto 分页查询活跃详情入参
|
|
|
|
+ * @return Page
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ public Page pageActiveDetail(PageActiveDetailDTO reqDto) {
|
|
|
|
+ Page<PageActiveDetailVO> page = new Page<>(reqDto.getCurrent(), reqDto.getSize());
|
|
|
|
+ List<PageActiveDetailVO> result = new ArrayList<>();
|
|
|
|
+ String timeUnit = reqDto.getTimeUnit();
|
|
|
|
+ LocalDate fromDate = reqDto.getFromDate();
|
|
|
|
+ LocalDate toDate = reqDto.getToDate();
|
|
|
|
+
|
|
|
|
+ // 根据时间单位生成对应模拟数据
|
|
|
|
+ if ("day".equals(timeUnit)) {
|
|
|
|
+ // 生成按天的模拟数据
|
|
|
|
+ LocalDate currentDate = fromDate;
|
|
|
|
+ while (!currentDate.isAfter(toDate) && result.size() < reqDto.getSize()) {
|
|
|
|
+ PageActiveDetailVO vo = new PageActiveDetailVO();
|
|
|
|
+ vo.setDate(currentDate.toString());
|
|
|
|
+ vo.setActiveUser(1300 + new Random().nextInt(200));
|
|
|
|
+ vo.setMauRate(3.5 + new Random().nextDouble() * 1.5);
|
|
|
|
+ vo.setWauRate(15 + new Random().nextDouble() * 5);
|
|
|
|
+ vo.setNewUserRate(96 + new Random().nextDouble() * 2);
|
|
|
|
+ result.add(vo);
|
|
|
|
+ currentDate = currentDate.plusDays(1);
|
|
|
|
+ }
|
|
|
|
+ } else if ("week".equals(timeUnit)) {
|
|
|
|
+ // 生成按周的模拟数据
|
|
|
|
+ LocalDate currentDate = fromDate;
|
|
|
|
+ while (!currentDate.isAfter(toDate) && result.size() < reqDto.getSize()) {
|
|
|
|
+ LocalDate endOfWeek = currentDate.plusDays(6);
|
|
|
|
+ if (endOfWeek.isAfter(toDate)) {
|
|
|
|
+ endOfWeek = toDate;
|
|
|
|
+ }
|
|
|
|
+ PageActiveDetailVO vo = new PageActiveDetailVO();
|
|
|
|
+ vo.setDate(String.format("%s~%s",
|
|
|
|
+ currentDate.format(DateTimeFormatter.ofPattern("yyyy/MM/dd")),
|
|
|
|
+ endOfWeek.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"))));
|
|
|
|
+ vo.setActiveUser(7500 + new Random().nextInt(500));
|
|
|
|
+ vo.setWeekActiveUserRate(0.25 + new Random().nextDouble() * 0.1);
|
|
|
|
+ vo.setNewUserRate(98.5 + new Random().nextDouble() * 0.5);
|
|
|
|
+ result.add(vo);
|
|
|
|
+ currentDate = currentDate.plusWeeks(1);
|
|
|
|
+ }
|
|
|
|
+ } else if ("month".equals(timeUnit)) {
|
|
|
|
+ // 生成按月的模拟数据
|
|
|
|
+ LocalDate currentDate = fromDate;
|
|
|
|
+ while (!currentDate.isAfter(toDate) && result.size() < reqDto.getSize()) {
|
|
|
|
+ LocalDate endOfMonth = currentDate.plusMonths(1).minusDays(1);
|
|
|
|
+ if (endOfMonth.isAfter(toDate)) {
|
|
|
|
+ endOfMonth = toDate;
|
|
|
|
+ }
|
|
|
|
+ PageActiveDetailVO vo = new PageActiveDetailVO();
|
|
|
|
+ vo.setDate(String.format("%s~%s",
|
|
|
|
+ currentDate.format(DateTimeFormatter.ofPattern("yyyy/MM/dd")),
|
|
|
|
+ endOfMonth.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"))));
|
|
|
|
+ vo.setActiveUser(30000 + new Random().nextInt(5000));
|
|
|
|
+ vo.setNewUserRate(99.4 + new Random().nextDouble() * 0.2);
|
|
|
|
+ vo.setMonthActiveUserRate(1.2 + new Random().nextDouble() * 0.2);
|
|
|
|
+ result.add(vo);
|
|
|
|
+ currentDate = currentDate.plusMonths(1);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ page.setRecords(result);
|
|
|
|
+ // 模拟总条数,实际场景应根据查询条件计算
|
|
|
|
+ page.setTotal(result.size() > 0 ? 100 : 0);
|
|
|
|
+ return page;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /************************************** 启动次数 *****************************************
|
|
|
|
+ * 查询启动次数趋势
|
|
|
|
+ * @param reqDto 查询启动次数趋势入参
|
|
|
|
+ * @return GetNewUserTrendVO
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ public GetNewUserTrendVO getLaunchTrend(UserAnalyseQueryBaseDTO reqDto) {
|
|
|
|
+ GetNewUserTrendVO result = new GetNewUserTrendVO();
|
|
|
|
+ List<String> dates = new ArrayList<>();
|
|
|
|
+ String timeUnit = reqDto.getTimeUnit();
|
|
|
|
+ LocalDate fromDate = reqDto.getFromDate();
|
|
|
|
+ LocalDate toDate = reqDto.getToDate();
|
|
|
|
+
|
|
|
|
+ // 生成日期列表
|
|
|
|
+ switch (timeUnit) {
|
|
|
|
+ case "hour":
|
|
|
|
+ DateTimeFormatter hourFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:00");
|
|
|
|
+ LocalDateTime hourStart = fromDate.atStartOfDay();
|
|
|
|
+ LocalDateTime hourEnd = toDate.atTime(23, 0);
|
|
|
|
+ while (!hourStart.isAfter(hourEnd)) {
|
|
|
|
+ dates.add(hourStart.format(hourFormatter));
|
|
|
|
+ hourStart = hourStart.plusHours(1);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ case "day":
|
|
|
|
+ DateTimeFormatter dayFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
|
+ LocalDate dayStart = fromDate;
|
|
|
|
+ while (!dayStart.isAfter(toDate)) {
|
|
|
|
+ dates.add(dayStart.format(dayFormatter));
|
|
|
|
+ dayStart = dayStart.plusDays(1);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ case "week":
|
|
|
|
+ DateTimeFormatter weekFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
|
+ // 计算起始日期后的第一个周日
|
|
|
|
+ LocalDate currentWeek = fromDate;
|
|
|
|
+ DayOfWeek dayOfWeek = currentWeek.getDayOfWeek();
|
|
|
|
+ int daysToSunday = 7 - dayOfWeek.getValue(); // 周日的DayOfWeek值为7
|
|
|
|
+ LocalDate firstSunday = currentWeek.plusDays(daysToSunday);
|
|
|
|
+
|
|
|
|
+ while (!firstSunday.isAfter(toDate)) {
|
|
|
|
+ dates.add(firstSunday.format(weekFormatter));
|
|
|
|
+ firstSunday = firstSunday.plusWeeks(1);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ case "month":
|
|
|
|
+ DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
|
+ // 计算范围内的每月1号
|
|
|
|
+ LocalDate currentMonthFirstDay = LocalDate.of(fromDate.getYear(), fromDate.getMonth(), 1);
|
|
|
|
+ // 如果当月1号在起始日期之前,则取下个月1号
|
|
|
|
+ if (currentMonthFirstDay.isBefore(fromDate)) {
|
|
|
|
+ currentMonthFirstDay = currentMonthFirstDay.plusMonths(1);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ while (!currentMonthFirstDay.isAfter(toDate)) {
|
|
|
|
+ dates.add(currentMonthFirstDay.format(monthFormatter));
|
|
|
|
+ currentMonthFirstDay = currentMonthFirstDay.plusMonths(1);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ // 默认按天处理
|
|
|
|
+ DateTimeFormatter defaultFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
|
+ LocalDate defaultStart = fromDate;
|
|
|
|
+ while (!defaultStart.isAfter(toDate)) {
|
|
|
|
+ dates.add(defaultStart.format(defaultFormatter));
|
|
|
|
+ defaultStart = defaultStart.plusDays(1);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 生成items数据
|
|
|
|
+ List<TrendBaseVO> items = new ArrayList<>();
|
|
|
|
+ List<String> versions = reqDto.getVersion();
|
|
|
|
+ // 若未指定版本,使用默认版本列表
|
|
|
|
+ if (versions == null || versions.isEmpty()) {
|
|
|
|
+ versions = Arrays.asList("1.0", "5.1");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Random random = new Random();
|
|
|
|
+ for (String version : versions) {
|
|
|
|
+ TrendBaseVO trend = new TrendBaseVO();
|
|
|
|
+ trend.setName("启动次数");
|
|
|
|
+ trend.setVersion(version);
|
|
|
|
+ trend.setKey("launch");
|
|
|
|
+
|
|
|
|
+ // 生成与日期数量匹配的随机数据
|
|
|
|
+ List<Integer> data = new ArrayList<>(dates.size());
|
|
|
|
+ for (int i = 0; i < dates.size(); i++) {
|
|
|
|
+ // 生成100-1000之间的随机数,模拟用户数量
|
|
|
|
+ data.add(random.nextInt(901) + 100);
|
|
|
|
+ }
|
|
|
|
+ trend.setData(data);
|
|
|
|
+ items.add(trend);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ result.setDates(dates);
|
|
|
|
+ result.setItems(items);
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+ /**
|
|
|
|
+ * 分页查询启动次数详情
|
|
|
|
+ * @param reqDto 分页查询启动次数详情入参
|
|
|
|
+ * @return Page
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ public Page<PageLaunchDetailVO> pageLaunchDetail(PageActiveDetailDTO reqDto) {
|
|
|
|
+ // 初始化分页对象
|
|
|
|
+ Page<PageLaunchDetailVO> page = new Page<>(reqDto.getCurrent(), reqDto.getSize());
|
|
|
|
+ List<PageLaunchDetailVO> result = new ArrayList<>();
|
|
|
|
+ Random random = new Random();
|
|
|
|
+
|
|
|
|
+ // 日期格式化器
|
|
|
|
+ DateTimeFormatter hourFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:00");
|
|
|
|
+ DateTimeFormatter dayFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
|
+ DateTimeFormatter weekMonthFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
|
|
|
|
+
|
|
|
|
+ // 获取入参参数
|
|
|
|
+ String timeUnit = reqDto.getTimeUnit();
|
|
|
|
+ LocalDate fromDate = reqDto.getFromDate();
|
|
|
|
+ LocalDate toDate = reqDto.getToDate();
|
|
|
|
+
|
|
|
|
+ // 根据时间单位生成模拟数据
|
|
|
|
+ switch (timeUnit) {
|
|
|
|
+ case "hour":
|
|
|
|
+ LocalDateTime currentHour = LocalDateTime.of(fromDate, LocalTime.MIN);
|
|
|
|
+ LocalDateTime endHour = LocalDateTime.of(toDate, LocalTime.MAX);
|
|
|
|
+ while (!currentHour.isAfter(endHour)) {
|
|
|
|
+ PageLaunchDetailVO vo = new PageLaunchDetailVO();
|
|
|
|
+ vo.setDate(currentHour.format(hourFormatter));
|
|
|
|
+ // 保留两位小数:生成0-100的随机数后四舍五入保留两位
|
|
|
|
+ double hourRate = random.nextDouble() * 100;
|
|
|
|
+ vo.setLaunchRate(Math.round(hourRate * 100) / 100.0);
|
|
|
|
+ vo.setLaunch(random.nextInt(10000));
|
|
|
|
+ result.add(vo);
|
|
|
|
+ currentHour = currentHour.plusHours(1);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case "day":
|
|
|
|
+ LocalDate currentDay = fromDate;
|
|
|
|
+ while (!currentDay.isAfter(toDate)) {
|
|
|
|
+ PageLaunchDetailVO vo = new PageLaunchDetailVO();
|
|
|
|
+ vo.setDate(currentDay.format(dayFormatter));
|
|
|
|
+ // 保留两位小数
|
|
|
|
+ double dayRate = random.nextDouble() * 100;
|
|
|
|
+ vo.setLaunchRate(Math.round(dayRate * 100) / 100.0);
|
|
|
|
+ vo.setLaunch(random.nextInt(40000) + 929);
|
|
|
|
+ result.add(vo);
|
|
|
|
+ currentDay = currentDay.plusDays(1);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case "week":
|
|
|
|
+ LocalDate weekStart = fromDate.minusDays(fromDate.getDayOfWeek().getValue() - 1);
|
|
|
|
+ while (!weekStart.isAfter(toDate)) {
|
|
|
|
+ LocalDate weekEnd = weekStart.plusDays(6);
|
|
|
|
+ if (weekEnd.isAfter(toDate)) {
|
|
|
|
+ weekEnd = toDate;
|
|
|
|
+ }
|
|
|
|
+ PageLaunchDetailVO vo = new PageLaunchDetailVO();
|
|
|
|
+ vo.setDate(weekStart.format(weekMonthFormatter) + "~" + weekEnd.format(weekMonthFormatter));
|
|
|
|
+ // 保留两位小数
|
|
|
|
+ double weekRate = random.nextDouble() * 50;
|
|
|
|
+ vo.setLaunchRate(Math.round(weekRate * 100) / 100.0);
|
|
|
|
+ vo.setLaunch(random.nextInt(10000) + 298);
|
|
|
|
+ result.add(vo);
|
|
|
|
+ weekStart = weekEnd.plusDays(1);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case "month":
|
|
|
|
+ LocalDate monthStart = fromDate.withDayOfMonth(1);
|
|
|
|
+ while (!monthStart.isAfter(toDate)) {
|
|
|
|
+ LocalDate monthEnd = monthStart.plusMonths(1).minusDays(1);
|
|
|
|
+ if (monthEnd.isAfter(toDate)) {
|
|
|
|
+ monthEnd = toDate;
|
|
|
|
+ }
|
|
|
|
+ PageLaunchDetailVO vo = new PageLaunchDetailVO();
|
|
|
|
+ vo.setDate(monthStart.format(weekMonthFormatter) + "~" + monthEnd.format(weekMonthFormatter));
|
|
|
|
+ // 保留两位小数
|
|
|
|
+ double monthRate = random.nextDouble() * 60;
|
|
|
|
+ vo.setLaunchRate(Math.round(monthRate * 100) / 100.0);
|
|
|
|
+ vo.setLaunch(random.nextInt(30000) + 3955);
|
|
|
|
+ result.add(vo);
|
|
|
|
+ monthStart = monthEnd.plusDays(1);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 处理分页
|
|
|
|
+ int total = result.size();
|
|
|
|
+ int fromIndex = (int) ((reqDto.getCurrent() - 1) * reqDto.getSize());
|
|
|
|
+ int toIndex = Math.min(fromIndex + (int) reqDto.getSize(), total);
|
|
|
|
+ if (fromIndex >= 0 && fromIndex < total) {
|
|
|
|
+ result = result.subList(fromIndex, toIndex);
|
|
|
|
+ } else {
|
|
|
|
+ result = new ArrayList<>();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ page.setRecords(result);
|
|
|
|
+ page.setTotal(total);
|
|
|
|
+ return page;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /************************************** 版本分布 *****************************************
|
|
|
|
+ * 分页查询全部版本详情
|
|
|
|
+ * @param reqDto 分页查询全部版本详情入参
|
|
|
|
+ * @return Page
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ public Page<PageAllVersionDetailVO> pageAllVersionDetail(PageAllVersionDetailDTO reqDto) {
|
|
|
|
+ // 初始化分页对象
|
|
|
|
+ Page<PageAllVersionDetailVO> page = new Page<>(reqDto.getCurrent(), reqDto.getSize());
|
|
|
|
+ List<PageAllVersionDetailVO> result = new ArrayList<>();
|
|
|
|
+ Random random = new Random();
|
|
|
|
+
|
|
|
|
+ // 模拟版本列表(可根据实际业务版本调整)
|
|
|
|
+ List<String> versions = new ArrayList<>();
|
|
|
|
+ versions.add("1.0");
|
|
|
|
+ versions.add("2.5");
|
|
|
|
+ versions.add("3.2.1");
|
|
|
|
+ versions.add("4.0");
|
|
|
|
+ versions.add("5.1");
|
|
|
|
+ versions.add("6.0.2");
|
|
|
|
+ versions.add("6.3.0");
|
|
|
|
+ versions.add("7.1.0");
|
|
|
|
+
|
|
|
|
+ // 生成总数据(超出分页范围,用于模拟分页效果)
|
|
|
|
+ int totalDataSize = 20; // 模拟20条总数据
|
|
|
|
+ for (int i = 0; i < totalDataSize; i++) {
|
|
|
|
+ PageAllVersionDetailVO vo = new PageAllVersionDetailVO();
|
|
|
|
+ String version = versions.get(random.nextInt(versions.size()));
|
|
|
|
+
|
|
|
|
+ // 基础用户量(根据版本新旧设置不同量级)
|
|
|
|
+ int baseTotalUser;
|
|
|
|
+ if (version.startsWith("1.") || version.startsWith("2.")) {
|
|
|
|
+ baseTotalUser = 500000 + random.nextInt(500000); // 老版本用户量较大
|
|
|
|
+ } else if (version.startsWith("6.") || version.startsWith("7.")) {
|
|
|
|
+ baseTotalUser = 10000 + random.nextInt(50000); // 新版本用户量较小
|
|
|
|
+ } else {
|
|
|
|
+ baseTotalUser = 100000 + random.nextInt(400000); // 中间版本
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 活跃用户(总用户的0.01%-0.1%)
|
|
|
|
+ int activeUser = (int) (baseTotalUser * (0.0001 + random.nextDouble() * 0.0009));
|
|
|
|
+ activeUser = Math.max(activeUser, 1); // 确保至少1个活跃用户
|
|
|
|
+
|
|
|
|
+ // 新用户(活跃用户的80%-120%)
|
|
|
|
+ int newUser = (int) (activeUser * (0.8 + random.nextDouble() * 0.4));
|
|
|
|
+
|
|
|
|
+ // 升级用户(新用户的0%-5%)
|
|
|
|
+ int upgradeUser = (int) (newUser * random.nextDouble() * 0.05);
|
|
|
|
+
|
|
|
|
+ // 启动次数(活跃用户的50-200倍)
|
|
|
|
+ int launch = activeUser * (50 + random.nextInt(151));
|
|
|
|
+
|
|
|
|
+ // 活跃用户率(2%-60%,保留两位小数)
|
|
|
|
+ double activeUserRate = Math.round((2 + random.nextDouble() * 58) * 100) / 100.0;
|
|
|
|
+
|
|
|
|
+ // 总用户占比(1%-60%,保留两位小数)
|
|
|
|
+ double totalUserRate = Math.round((1 + random.nextDouble() * 59) * 100) / 100.0;
|
|
|
|
+
|
|
|
|
+ // 设置属性
|
|
|
|
+ vo.setVersion(version);
|
|
|
|
+ vo.setTotalUser(baseTotalUser);
|
|
|
|
+ vo.setActiveUser(activeUser);
|
|
|
|
+ vo.setNewUser(newUser);
|
|
|
|
+ vo.setUpgradeUser(upgradeUser);
|
|
|
|
+ vo.setLaunch(launch);
|
|
|
|
+ vo.setActiveUserRate(activeUserRate);
|
|
|
|
+ vo.setTotalUserRate(totalUserRate);
|
|
|
|
+
|
|
|
|
+ result.add(vo);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 处理分页逻辑
|
|
|
|
+ int total = result.size();
|
|
|
|
+ int fromIndex = (int) ((reqDto.getCurrent() - 1) * reqDto.getSize());
|
|
|
|
+ int toIndex = Math.min(fromIndex + (int) reqDto.getSize(), total);
|
|
|
|
+
|
|
|
|
+ if (fromIndex >= 0 && fromIndex < total) {
|
|
|
|
+ result = result.subList(fromIndex, toIndex);
|
|
|
|
+ } else {
|
|
|
|
+ result = new ArrayList<>();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ page.setRecords(result);
|
|
|
|
+ page.setTotal(total);
|
|
|
|
+ return page;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 分页查询单版本详情
|
|
|
|
+ * @param reqDto 入参
|
|
|
|
+ * @return Page
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ public Page<PageSingleVersionDetailVO> pageSingleVersionDetail(PageSingleVersionDetailDTO reqDto) {
|
|
|
|
+ // 初始化分页对象
|
|
|
|
+ Page<PageSingleVersionDetailVO> page = new Page<>(reqDto.getCurrent(), reqDto.getSize());
|
|
|
|
+ List<PageSingleVersionDetailVO> result = new ArrayList<>();
|
|
|
|
+ Random random = new Random();
|
|
|
|
+
|
|
|
|
+ // 获取入参中的时间范围和版本信息
|
|
|
|
+ LocalDate fromDate = reqDto.getFromDate();
|
|
|
|
+ LocalDate toDate = reqDto.getToDate();
|
|
|
|
+ String version = reqDto.getVersion().get(0); // 假设DTO中有获取版本的方法
|
|
|
|
+
|
|
|
|
+ // 日期格式化器
|
|
|
|
+ DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
|
+
|
|
|
|
+ // 生成时间范围内的所有日期数据
|
|
|
|
+ LocalDate currentDate = fromDate;
|
|
|
|
+ while (!currentDate.isAfter(toDate)) {
|
|
|
|
+ PageSingleVersionDetailVO vo = new PageSingleVersionDetailVO();
|
|
|
|
+
|
|
|
|
+ // 设置日期
|
|
|
|
+ vo.setDate(currentDate.format(dateFormatter));
|
|
|
|
+
|
|
|
|
+ // 基础用户数(10-50之间随机)
|
|
|
|
+ int baseUser = 10 + random.nextInt(41);
|
|
|
|
+
|
|
|
|
+ // 活跃用户
|
|
|
|
+ vo.setActiveUser(baseUser);
|
|
|
|
+
|
|
|
|
+ // 新用户(80%-100%的活跃用户)
|
|
|
|
+ int newUser = (int) (baseUser * (0.8 + random.nextDouble() * 0.2));
|
|
|
|
+ vo.setNewUser(newUser);
|
|
|
|
+
|
|
|
|
+ // 升级用户(0-5之间随机,且不超过活跃用户)
|
|
|
|
+ int upgradeUser = random.nextInt(Math.min(6, baseUser + 1));
|
|
|
|
+ vo.setUpgradeUser(upgradeUser);
|
|
|
|
+
|
|
|
|
+ // 启动次数(活跃用户的1-3倍)
|
|
|
|
+ int launch = baseUser * (1 + random.nextInt(3));
|
|
|
|
+ vo.setLaunch(launch);
|
|
|
|
+
|
|
|
|
+ result.add(vo);
|
|
|
|
+ currentDate = currentDate.plusDays(1);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 处理分页逻辑
|
|
|
|
+ int total = result.size();
|
|
|
|
+ int fromIndex = (int) ((reqDto.getCurrent() - 1) * reqDto.getSize());
|
|
|
|
+ int toIndex = Math.min(fromIndex + (int) reqDto.getSize(), total);
|
|
|
|
+
|
|
|
|
+ if (fromIndex >= 0 && fromIndex < total) {
|
|
|
|
+ result = result.subList(fromIndex, toIndex);
|
|
|
|
+ } else {
|
|
|
|
+ result = new ArrayList<>();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ page.setRecords(result);
|
|
|
|
+ page.setTotal(total);
|
|
|
|
+ return page;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 查询版本用户来源
|
|
|
|
+ * @param reqDto 入参
|
|
|
|
+ * @return GetVersionDistributionVO
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ public List<GetVersionDistributionVO> getVersionDistribution(GetVersionDistributionDTO reqDto) {
|
|
|
|
+ List<GetVersionDistributionVO> result = new ArrayList<>();
|
|
|
|
+
|
|
|
|
+ // 根据不同类型模拟不同来源数据
|
|
|
|
+ if ("upgradeChannel".equals(reqDto.getType())) {
|
|
|
|
+ GetVersionDistributionVO vo1 = new GetVersionDistributionVO();
|
|
|
|
+ vo1.setName("应用宝");
|
|
|
|
+ vo1.setValue(120);
|
|
|
|
+ result.add(vo1);
|
|
|
|
+
|
|
|
|
+ GetVersionDistributionVO vo2 = new GetVersionDistributionVO();
|
|
|
|
+ vo2.setName("华为应用市场");
|
|
|
|
+ vo2.setValue(95);
|
|
|
|
+ result.add(vo2);
|
|
|
|
+
|
|
|
|
+ GetVersionDistributionVO vo3 = new GetVersionDistributionVO();
|
|
|
|
+ vo3.setName("小米应用商店");
|
|
|
|
+ vo3.setValue(80);
|
|
|
|
+ result.add(vo3);
|
|
|
|
+
|
|
|
|
+ GetVersionDistributionVO vo4 = new GetVersionDistributionVO();
|
|
|
|
+ vo4.setName("苹果App Store");
|
|
|
|
+ vo4.setValue(75);
|
|
|
|
+ result.add(vo4);
|
|
|
|
+
|
|
|
|
+ GetVersionDistributionVO vo5 = new GetVersionDistributionVO();
|
|
|
|
+ vo5.setName("百度手机助手");
|
|
|
|
+ vo5.setValue(40);
|
|
|
|
+ result.add(vo5);
|
|
|
|
+ } else {
|
|
|
|
+ // 其他类型的默认模拟数据
|
|
|
|
+ GetVersionDistributionVO vo1 = new GetVersionDistributionVO();
|
|
|
|
+ vo1.setName("未知渠道1");
|
|
|
|
+ vo1.setValue(50);
|
|
|
|
+ result.add(vo1);
|
|
|
|
+
|
|
|
|
+ GetVersionDistributionVO vo2 = new GetVersionDistributionVO();
|
|
|
|
+ vo2.setName("未知渠道2");
|
|
|
|
+ vo2.setValue(30);
|
|
|
|
+ result.add(vo2);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 分页查询版本用户来源详情
|
|
|
|
+ * @param reqDto 入参
|
|
|
|
+ * @return Page<PageVersionDistributionDetailVO>
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ public Page<PageVersionDistributionDetailVO> pageVersionDistributionDetail(PageVersionDistributionDetailDTO reqDto) {
|
|
|
|
+ Page<PageVersionDistributionDetailVO> page = new Page<>(reqDto.getCurrent(), reqDto.getSize());
|
|
|
|
+ List<PageVersionDistributionDetailVO> result = new ArrayList<>();
|
|
|
|
+ Random random = new Random();
|
|
|
|
+ String type = reqDto.getType();
|
|
|
|
+
|
|
|
|
+ // 根据类型生成15条数据
|
|
|
|
+ if ("upgradeChannel".equals(type)) {
|
|
|
|
+ // 升级渠道类型
|
|
|
|
+ String[] channelNames = {
|
|
|
|
+ "应用宝", "华为应用市场", "小米应用商店", "苹果App Store", "百度手机助手",
|
|
|
|
+ "360手机助手", "vivo应用商店", "OPPO软件商店", "腾讯应用宝", "豌豆荚",
|
|
|
|
+ "三星应用商店", "魅族应用市场", "谷歌Play商店", "应用汇", "机锋市场"
|
|
|
|
+ };
|
|
|
|
+ for (String name : channelNames) {
|
|
|
|
+ PageVersionDistributionDetailVO vo = new PageVersionDistributionDetailVO();
|
|
|
|
+ vo.setName(name);
|
|
|
|
+ // 生成10-200之间的随机整数value
|
|
|
|
+ int value = 10 + random.nextInt(191);
|
|
|
|
+ vo.setValue(value);
|
|
|
|
+ // 生成0.1-30.0之间的随机数并保留两位小数
|
|
|
|
+ double rate = Math.round((0.1 + random.nextDouble() * 29.9) * 100) / 100.0;
|
|
|
|
+ vo.setRate(rate);
|
|
|
|
+ result.add(vo);
|
|
|
|
+ }
|
|
|
|
+ } else if ("upgradeVersion".equals(type)) {
|
|
|
|
+ // 升级版本类型
|
|
|
|
+ String[] versionNames = {
|
|
|
|
+ "1.0.0→2.0.0", "1.1.0→2.0.0", "1.2.0→2.0.0", "1.3.0→2.0.0", "1.4.0→2.0.0",
|
|
|
|
+ "1.5.0→2.0.0", "1.6.0→2.0.0", "1.7.0→2.0.0", "1.8.0→2.0.0", "1.9.0→2.0.0",
|
|
|
|
+ "2.0.0→2.1.0", "2.0.0→2.2.0", "2.0.0→3.0.0", "2.1.0→3.0.0", "2.2.0→3.0.0"
|
|
|
|
+ };
|
|
|
|
+ for (String name : versionNames) {
|
|
|
|
+ PageVersionDistributionDetailVO vo = new PageVersionDistributionDetailVO();
|
|
|
|
+ vo.setName(name);
|
|
|
|
+ // 生成50-500之间的随机整数value
|
|
|
|
+ int value = 50 + random.nextInt(451);
|
|
|
|
+ vo.setValue(value);
|
|
|
|
+ // 生成5.0-60.0之间的随机数并保留两位小数
|
|
|
|
+ double rate = Math.round((5.0 + random.nextDouble() * 55.0) * 100) / 100.0;
|
|
|
|
+ vo.setRate(rate);
|
|
|
|
+ result.add(vo);
|
|
|
|
+ }
|
|
|
|
+ } else if ("newUserChannel".equals(type)) {
|
|
|
|
+ // 新用户渠道类型
|
|
|
|
+ String[] newUserNames = {
|
|
|
|
+ "应用市场推广", "社交媒体分享", "官网下载", "朋友推荐", "搜索引擎",
|
|
|
|
+ "信息流广告", "短视频推广", "直播带货", "线下活动", "合作引流",
|
|
|
|
+ "短信邀请", "二维码扫描", "公众号文章", "小程序跳转", "地推活动"
|
|
|
|
+ };
|
|
|
|
+ for (String name : newUserNames) {
|
|
|
|
+ PageVersionDistributionDetailVO vo = new PageVersionDistributionDetailVO();
|
|
|
|
+ vo.setName(name);
|
|
|
|
+ // 生成100-1000之间的随机整数value
|
|
|
|
+ int value = 100 + random.nextInt(901);
|
|
|
|
+ vo.setValue(value);
|
|
|
|
+ // 生成1.0-40.0之间的随机数并保留两位小数
|
|
|
|
+ double rate = Math.round((1.0 + random.nextDouble() * 39.0) * 100) / 100.0;
|
|
|
|
+ vo.setRate(rate);
|
|
|
|
+ result.add(vo);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ // 其他类型默认数据
|
|
|
|
+ for (int i = 1; i <= 15; i++) {
|
|
|
|
+ PageVersionDistributionDetailVO vo = new PageVersionDistributionDetailVO();
|
|
|
|
+ vo.setName("未知类型" + i);
|
|
|
|
+ vo.setValue(20 + random.nextInt(181));
|
|
|
|
+ vo.setRate(Math.round((0.5 + random.nextDouble() * 20.0) * 100) / 100.0);
|
|
|
|
+ result.add(vo);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 处理分页逻辑
|
|
|
|
+ long current = reqDto.getCurrent();
|
|
|
|
+ long size = reqDto.getSize();
|
|
|
|
+ long total = result.size();
|
|
|
|
+ int start = (int) ((current - 1) * size);
|
|
|
|
+ int end = (int) Math.min(start + size, total);
|
|
|
|
+
|
|
|
|
+ if (start < result.size() && start >= 0) {
|
|
|
|
+ result = result.subList(start, end);
|
|
|
|
+ } else {
|
|
|
|
+ result = new ArrayList<>();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ page.setRecords(result);
|
|
|
|
+ page.setTotal(total);
|
|
|
|
+ return page;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|