Преглед на файлове

update: 活跃详情、新增用户、留存率相关逻辑调整

lwh преди 4 седмици
родител
ревизия
ac2c9c2be7

+ 1 - 1
pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/component/PigResourceServerConfiguration.java

@@ -79,7 +79,7 @@ public class PigResourceServerConfiguration {
 			.toArray(new PathPatternRequestMatcher[] {});
 
 		http.authorizeHttpRequests(authorizeRequests -> authorizeRequests.requestMatchers(permitMatchers)
-			.permitAll().requestMatchers("/uninstall/*").permitAll()
+			.permitAll()
 			.anyRequest()
 			.authenticated())
 			.oauth2ResourceServer(

+ 10 - 3
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/dto/user/PageNewUserTrendDetailDTO.java → pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/dto/user/PageUserAnalyseDTO.java

@@ -18,11 +18,18 @@ import java.util.List;
  */
 @Data
 @Schema(description = "获取新增趋势详情入参")
-public class PageNewUserTrendDetailDTO implements Serializable {
+public class PageUserAnalyseDTO implements Serializable {
 
 	@Serial
 	private static final long serialVersionUID = 1L;
 
+	/**
+	 * 应用ID
+	 */
+	@NotBlank(message = "应用ID不能为空")
+	@Schema(description = "应用ID", example = "Fqs2CL9CUn7U1AqilSFXgb")
+	private String appId;
+
 	/**
 	 * 渠道
 	 */
@@ -59,12 +66,12 @@ public class PageNewUserTrendDetailDTO implements Serializable {
 	/**
 	 * 每页显示条数,默认 10
 	 */
-	@Schema(description = "每页显示条数")
+	@Schema(description = "每页显示条数", example = "10")
 	private long size = 10;
 
 	/**
 	 * 当前页
 	 */
-	@Schema(description = "当前页")
+	@Schema(description = "当前页",example = "1")
 	private long current = 1;
 }

+ 1 - 1
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/dto/user/UserAnalyseQueryBaseDTO.java

@@ -26,7 +26,7 @@ public class UserAnalyseQueryBaseDTO implements Serializable {
 	 * 应用ID
 	 */
 	@NotBlank(message = "应用ID不能为空")
-	@Schema(description = "应用ID", example = "FoigtBxJrmOi9nirwkjpsJ")
+	@Schema(description = "应用ID", example = "Fqs2CL9CUn7U1AqilSFXgb")
 	private String appId;
 
 	/**

+ 5 - 5
pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/controller/UserAnalyseController.java

@@ -42,7 +42,7 @@ public class UserAnalyseController {
 
 	@PostMapping("/new/detail")
 	@Operation(summary = "分页查询新增趋势详情")
-	public R<Page<PageNewUserTrendDetailVO>> pageNewUserTrendDetail(@Valid @RequestBody PageNewUserTrendDetailDTO reqDto) {
+	public R<Page<PageNewUserTrendDetailVO>> pageNewUserTrendDetail(@Valid @RequestBody PageUserAnalyseDTO reqDto) {
 		Page<PageNewUserTrendDetailVO> result = userAnalyseService.pageNewUserTrendDetail(reqDto);
 		return R.ok(result);
 	}
@@ -55,13 +55,13 @@ public class UserAnalyseController {
 
 	@PostMapping("/new/retention")
 	@Operation(summary = "查询次日留存率")
-	public R<GetNewUserRetentionVO> getNewUserRetention(@Valid @RequestBody GetNewUserRetentionDTO reqDto) {
+	public R<GetNewUserRetentionVO> getNewUserRetention(@Valid @RequestBody UserAnalyseQueryBaseDTO reqDto) {
 		GetNewUserRetentionVO result = userAnalyseService.getNewUserRetention(reqDto);
 		return R.ok(result);
 	}
 	@PostMapping("/retention/detail")
 	@Operation(summary = "分页查询次日留存率详情")
-	public R<Page<PageRetentionDetailVO>> pageNewUserRetentionDetail(@Valid @RequestBody PageRetentionDetailDTO reqDto) {
+	public R<Page<PageRetentionDetailVO>> pageNewUserRetentionDetail(@Valid @RequestBody PageUserAnalyseDTO reqDto) {
 		Page<PageRetentionDetailVO> result = userAnalyseService.pageNewUserRetentionDetail(reqDto);
 		return R.ok(result);
 	}
@@ -111,7 +111,7 @@ public class UserAnalyseController {
 
 	@PostMapping("/active/detail")
 	@Operation(summary = "分页查询活跃详情")
-	public R<Page<PageActiveDetailVO>> pageActiveDetail(@Valid @RequestBody PageActiveDetailDTO reqDto) {
+	public R<Page<PageActiveDetailVO>> pageActiveDetail(@Valid @RequestBody PageUserAnalyseDTO reqDto) {
 		Page<PageActiveDetailVO> result = userAnalyseService.pageActiveDetail(reqDto);
 		return R.ok(result);
 	}
@@ -132,7 +132,7 @@ public class UserAnalyseController {
 
 	@PostMapping("/launch/detail")
 	@Operation(summary = "分页查询启动次数详情")
-	public R<Page<PageLaunchDetailVO>> pageLaunchDetail(@Valid @RequestBody PageActiveDetailDTO reqDto) {
+	public R<Page<PageLaunchDetailVO>> pageLaunchDetail(@Valid @RequestBody PageUserAnalyseDTO reqDto) {
 		Page<PageLaunchDetailVO> result = userAnalyseService.pageLaunchDetail(reqDto);
 		return R.ok(result);
 	}

+ 5 - 5
pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/service/UserAnalyseService.java

@@ -28,21 +28,21 @@ public interface UserAnalyseService {
 	 * @param reqDto 请求参数
 	 * @return Page
 	 */
-	Page<PageNewUserTrendDetailVO> pageNewUserTrendDetail(@Valid PageNewUserTrendDetailDTO reqDto);
+	Page<PageNewUserTrendDetailVO> pageNewUserTrendDetail(@Valid PageUserAnalyseDTO reqDto);
 
 	/**
 	 * 查询次日留存率
 	 * @param reqDto 查询次日留存率入参
 	 * @return GetNewUserRetentionVO
 	 */
-	GetNewUserRetentionVO getNewUserRetention(@Valid GetNewUserRetentionDTO reqDto);
+	GetNewUserRetentionVO getNewUserRetention(@Valid UserAnalyseQueryBaseDTO reqDto);
 
 	/**
 	 * 分页查询次日留存率详情
 	 * @param reqDto 分页查询次日留存率详情入参
 	 * @return Page
 	 */
-	Page<PageRetentionDetailVO> pageNewUserRetentionDetail(@Valid PageRetentionDetailDTO reqDto);
+	Page<PageRetentionDetailVO> pageNewUserRetentionDetail(@Valid PageUserAnalyseDTO reqDto);
 
 
 	/************************************** 活跃用户 *****************************************
@@ -86,7 +86,7 @@ public interface UserAnalyseService {
 	 * @param reqDto 入参
 	 * @return Page
 	 */
-	Page<PageActiveDetailVO> pageActiveDetail(@Valid PageActiveDetailDTO reqDto);
+	Page<PageActiveDetailVO> pageActiveDetail(@Valid PageUserAnalyseDTO reqDto);
 
 	/************************************** 启动次数 *****************************************
 	 * 查询启动次数趋势
@@ -100,7 +100,7 @@ public interface UserAnalyseService {
 	 * @param reqDto 入参
 	 * @return Page
 	 */
-	Page<PageLaunchDetailVO> pageLaunchDetail(@Valid PageActiveDetailDTO reqDto);
+	Page<PageLaunchDetailVO> pageLaunchDetail(@Valid PageUserAnalyseDTO reqDto);
 
 	/************************************** 版本分布 *****************************************
 	 * 分页查询全部版本详情

+ 280 - 95
pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/service/impl/UserAnalyseServiceImpl.java

@@ -25,7 +25,6 @@ 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.format.DateTimeParseException;
 import java.time.temporal.ChronoUnit;
@@ -65,6 +64,41 @@ public class UserAnalyseServiceImpl implements UserAnalyseService {
 		List<String> dates = generateTimeAxis(reqDto.getFromDate(), reqDto.getToDate(), reqDto.getTimeUnit());
 		result.setDates(dates);
 
+		// 2. 处理版本列表(为空时按null处理)
+		List<String> versions = reqDto.getVersion();
+		List<String> processVersions = (versions == null || versions.isEmpty())
+				? Collections.singletonList(null)
+				: versions.stream().filter(v -> v != null && !v.isEmpty()).toList();
+
+		// 3. 处理每个版本的数据
+		List<TrendBaseVO> voList = processVersions.stream()
+				.map(version -> {
+					TrendBaseVO trend = new TrendBaseVO();
+					trend.setName("新增用户");
+					trend.setVersion(version == null ? "All" : version);
+					trend.setKey("newUser");
+
+					// 计算每个时间点的活跃用户数
+					List<Long> counts = dates.stream()
+							.map(date -> {
+								LocalDateTime startTime = getStartTime(date, reqDto.getTimeUnit());
+								LocalDateTime endTime = getEndTime(date, reqDto.getTimeUnit());
+								return statNewUserCount(startTime, endTime, reqDto.getAppId(), version, reqDto.getChannel());
+							})
+							.collect(Collectors.toList());
+					trend.setData(counts);
+					return trend;
+				})
+				.toList();
+		result.setItems(voList);
+		return result;
+	}
+	public GetNewUserTrendVO getNewUserTrend2(UserAnalyseQueryBaseDTO reqDto) {
+		GetNewUserTrendVO result = new GetNewUserTrendVO();
+		// 1. 生成时间轴
+		List<String> dates = generateTimeAxis(reqDto.getFromDate(), reqDto.getToDate(), reqDto.getTimeUnit());
+		result.setDates(dates);
+
 		// 2. 处理版本列表(为空时按"All"处理)
 		List<String> versions = reqDto.getVersion();
 		List<String> processVersions = (versions == null || versions.isEmpty())
@@ -99,7 +133,58 @@ public class UserAnalyseServiceImpl implements UserAnalyseService {
 	 * @return Page
 	 */
 	@Override
-	public Page<PageNewUserTrendDetailVO> pageNewUserTrendDetail(PageNewUserTrendDetailDTO reqDto) {
+	public Page<PageNewUserTrendDetailVO> pageNewUserTrendDetail(PageUserAnalyseDTO reqDto) {
+		// 初始化分页对象并计算总条数
+		Page<PageNewUserTrendDetailVO> page = new Page<>(reqDto.getCurrent(), reqDto.getSize());
+		page.setTotal(calculateTotalCount(reqDto.getFromDate(), reqDto.getToDate(), reqDto.getTimeUnit()));
+		// 生成当前页时间轴
+		List<String> dates = generatePageTimeAxis(reqDto.getFromDate(), reqDto.getToDate(),
+				reqDto.getTimeUnit(), reqDto.getCurrent(), reqDto.getSize());
+		if (dates.isEmpty()) {
+			return page; // 无数据直接返回
+		}
+
+		// 获取渠道和版本
+		List<String> channel = reqDto.getChannel();
+		String version = null;
+		if (reqDto.getVersion() != null && !reqDto.getVersion().isEmpty()){
+			version = reqDto.getVersion().get(0);
+		}
+
+		// 查询结果
+		List<PageNewUserTrendDetailVO> items = new ArrayList<>(dates.size());
+		for (String date : dates) {
+			// 获取时间范围
+			LocalDateTime startTime = getStartTime(date, reqDto.getTimeUnit());
+			LocalDateTime endTime = getEndTime(date, reqDto.getTimeUnit());
+			// 查询新增用户数
+			BigDecimal newUser = BigDecimal.valueOf(statNewUserCount(startTime, endTime, reqDto.getAppId(), version, channel));
+			// 查询活跃用户数
+			BigDecimal activeUser = BigDecimal.valueOf(statActiveUserCount(startTime, endTime, reqDto.getAppId(), version, channel));
+			// 计算新用户占比
+			BigDecimal newRate = newUser.compareTo(BigDecimal.ZERO) == 0 || activeUser.compareTo(BigDecimal.ZERO) == 0
+					? BigDecimal.ZERO
+					: newUser.divide(activeUser, 4, RoundingMode.HALF_UP);
+
+			// 构建返回对象
+			PageNewUserTrendDetailVO detail = new PageNewUserTrendDetailVO();
+			// 定义日期格式
+			DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
+			// 处理日期显示
+			boolean isRangeType = "week".equals(reqDto.getTimeUnit()) || "month".equals(reqDto.getTimeUnit());
+			String displayDate = isRangeType && startTime != null && endTime != null
+					? startTime.toLocalDate().format(dateFormatter) + "~" + endTime.minusDays(1).toLocalDate().format(dateFormatter)
+					: date;
+			detail.setDate(displayDate);
+			detail.setNewUser(newUser.intValue());
+			detail.setNewUserRate(newRate);
+			items.add( detail);
+		}
+		// 返回结果
+		page.setRecords(items);
+		return page;
+	}
+	public Page<PageNewUserTrendDetailVO> pageNewUserTrendDetail2(PageUserAnalyseDTO reqDto) {
 		// 1. 初始化分页对象并计算总条数
 		Page<PageNewUserTrendDetailVO> page = new Page<>(reqDto.getCurrent(), reqDto.getSize());
 		page.setTotal(calculateTotalCount(reqDto.getFromDate(), reqDto.getToDate(), reqDto.getTimeUnit()));
@@ -172,7 +257,53 @@ public class UserAnalyseServiceImpl implements UserAnalyseService {
 	 * @return GetNewUserRetentionVO
 	 */
 	@Override
-	public GetNewUserRetentionVO getNewUserRetention(GetNewUserRetentionDTO reqDto) {
+	public GetNewUserRetentionVO getNewUserRetention(UserAnalyseQueryBaseDTO reqDto) {
+		// 校验时间粒度
+		if (!"day".equals(reqDto.getTimeUnit())){
+			throw new BusinessException("时间粒度只能为日");
+		}
+		// 生成时间轴
+		GetNewUserRetentionVO result = new GetNewUserRetentionVO();
+		List<String> dates = generateTimeAxis(reqDto.getFromDate(), reqDto.getToDate(), reqDto.getTimeUnit());
+		ArrayList<BigDecimal> retentions = new ArrayList<>();
+		// 获取版本和渠道
+		String version = null;
+		if (reqDto.getVersion() != null && !reqDto.getVersion().isEmpty()){
+			version = reqDto.getVersion().get(0);
+		}
+		List<String> channel = reqDto.getChannel();
+		// 变量时间轴
+		for (String date : dates) {
+			// 获取时间范围
+			LocalDateTime startTime = getStartTime(date, reqDto.getTimeUnit());
+			LocalDateTime endTime = getEndTime(date, reqDto.getTimeUnit());
+			if (startTime == null || endTime == null){
+				throw new BusinessException("获取时间范围错误");
+			}
+			// 留存率:今日新增的用户在明天活跃用户中有多少
+			// 查询今日新增用户
+			List<String> newUserIds = getNewUserIdList(startTime, endTime, reqDto.getAppId(), version, channel);
+			// 查询明天活跃用户有多少
+			List<String> activeUserIds = getActiveUserIdList(startTime.plusDays(1), endTime.plusDays(1), reqDto.getAppId(), version, channel);
+			// 计算留存率
+			Set<String> activeUserSet = new HashSet<>(activeUserIds);
+			Set<String> newUserSet = new HashSet<>(newUserIds);
+			//保留在活跃用户集合中的新增用户
+			activeUserSet.retainAll(newUserSet);
+			BigDecimal activeCount = BigDecimal.valueOf(activeUserSet.size());
+			BigDecimal newUserCount = BigDecimal.valueOf(newUserIds.size());
+			// 留存率
+			BigDecimal retention = newUserCount.compareTo(BigDecimal.ZERO) == 0 || activeCount.compareTo(BigDecimal.ZERO) == 0
+					? BigDecimal.ZERO
+					: activeCount.divide(newUserCount, 4, RoundingMode.HALF_UP);
+			retentions.add( retention);
+		}
+		result.setDates(dates);
+		result.setRetentions(retentions);
+		return result;
+	}
+
+	public GetNewUserRetentionVO getNewUserRetention2(GetNewUserRetentionDTO reqDto) {
 		String timeUnit = "day";
 		GetNewUserRetentionVO result = new GetNewUserRetentionVO();
 		List<String> dates = generateTimeAxis(reqDto.getFromDate(), reqDto.getToDate(), timeUnit);
@@ -215,7 +346,59 @@ public class UserAnalyseServiceImpl implements UserAnalyseService {
 	 * @return Page
 	 */
 	@Override
-	public Page<PageRetentionDetailVO> pageNewUserRetentionDetail(PageRetentionDetailDTO reqDto) {
+	public Page<PageRetentionDetailVO> pageNewUserRetentionDetail(PageUserAnalyseDTO reqDto) {
+		// 初始化分页对象并计算总条数
+		Page<PageRetentionDetailVO> page = new Page<>(reqDto.getCurrent(), reqDto.getSize());
+		page.setTotal(calculateTotalCount(reqDto.getFromDate(), reqDto.getToDate(), reqDto.getTimeUnit()));
+		// 生成当前页时间轴
+		List<String> dates = generatePageTimeAxis(reqDto.getFromDate(), reqDto.getToDate(),
+				reqDto.getTimeUnit(), reqDto.getCurrent(), reqDto.getSize());
+		if (dates.isEmpty()) {
+			return page; // 无数据直接返回
+		}
+		// 获取渠道和版本
+		List<String> channel = reqDto.getChannel();
+		String version = null;
+		if (reqDto.getVersion() != null && !reqDto.getVersion().isEmpty()){
+			version = reqDto.getVersion().get(0);
+		}
+		// 查询结果
+		List<PageRetentionDetailVO> result = new ArrayList<>();
+		// 遍历时间轴
+		for (String date : dates) {
+			// 获取时间范围
+			LocalDateTime startTime = getStartTime(date, reqDto.getTimeUnit());
+			LocalDateTime endTime = getEndTime(date, reqDto.getTimeUnit());
+			if (startTime == null || endTime == null){
+				throw new BusinessException("获取时间范围错误");
+			}
+			// 留存率:今日新增的用户在明天活跃用户中有多少
+			// 查询今日新增用户
+			List<String> newUserIds = getNewUserIdList(startTime, endTime, reqDto.getAppId(), version, channel);
+			// 查询明天活跃用户有多少
+			List<String> activeUserIds = getActiveUserIdList(startTime.plusDays(1), endTime.plusDays(1), reqDto.getAppId(), version, channel);
+			// 计算留存率
+			Set<String> activeUserSet = new HashSet<>(activeUserIds);
+			Set<String> newUserSet = new HashSet<>(newUserIds);
+			//保留在活跃用户集合中的新增用户
+			activeUserSet.retainAll(newUserSet);
+			BigDecimal activeCount = BigDecimal.valueOf(activeUserSet.size());
+			BigDecimal newUserCount = BigDecimal.valueOf(newUserIds.size());
+			// 留存率
+			BigDecimal retention = newUserCount.compareTo(BigDecimal.ZERO) == 0 || activeCount.compareTo(BigDecimal.ZERO) == 0
+					? BigDecimal.ZERO
+					: activeCount.divide(newUserCount, 4, RoundingMode.HALF_UP);
+			// 组装结果
+			PageRetentionDetailVO detail = new PageRetentionDetailVO();
+			detail.setDate(date);
+			detail.setRetention( retention);
+			result.add( detail);
+		}
+		// 返回结果
+		page.setRecords(result);
+		return page;
+	}
+	public Page<PageRetentionDetailVO> pageNewUserRetentionDetail2(PageUserAnalyseDTO reqDto) {
 		// 1. 初始化分页对象并设置总条数
 		final String timeUnit = "day";
 		Page<PageRetentionDetailVO> page = new Page<>(reqDto.getCurrent(), reqDto.getSize());
@@ -301,7 +484,7 @@ public class UserAnalyseServiceImpl implements UserAnalyseService {
 				.map(version -> {
 					TrendBaseVO trend = new TrendBaseVO();
 					trend.setName("活跃用户");
-					trend.setVersion(version);
+					trend.setVersion(version == null ? "All" : version);
 					trend.setKey("activeUser");
 
 					// 计算每个时间点的活跃用户数
@@ -743,7 +926,91 @@ public class UserAnalyseServiceImpl implements UserAnalyseService {
 	 * @return Page
 	 */
 	@Override
-	public Page<PageActiveDetailVO> pageActiveDetail(PageActiveDetailDTO reqDto) {
+	public Page<PageActiveDetailVO> pageActiveDetail(PageUserAnalyseDTO reqDto) {
+		// 1. 初始化分页对象并计算总条数
+		Page<PageActiveDetailVO> page = new Page<>(reqDto.getCurrent(), reqDto.getSize());
+		page.setTotal(calculateTotalCount(reqDto.getFromDate(), reqDto.getToDate(), reqDto.getTimeUnit()));
+
+		// 2. 生成当前页时间轴
+		List<String> dates = generatePageTimeAxis(reqDto.getFromDate(), reqDto.getToDate(),
+				reqDto.getTimeUnit(), reqDto.getCurrent(), reqDto.getSize());
+		if (dates.isEmpty()) {
+			return page; // 无数据直接返回
+		}
+		// 获取渠道和版本
+		List<String> channel = reqDto.getChannel();
+		String version = null;
+		if (reqDto.getVersion() != null && !reqDto.getVersion().isEmpty()){
+			version = reqDto.getVersion().get(0);
+		}
+		// 查询结果
+		List<PageActiveDetailVO> result = new ArrayList<>();
+		for (String date : dates) {
+			// 获取时间范围
+			LocalDateTime startTime = getStartTime(date, reqDto.getTimeUnit());
+			LocalDateTime endTime = getEndTime(date, reqDto.getTimeUnit());
+			// 查询活跃用户数量
+			BigDecimal activeCount = BigDecimal.valueOf(statActiveUserCount(startTime, endTime, reqDto.getAppId(), version, channel));
+			// 查询活跃用户中的新增用户数
+			BigDecimal newCount = BigDecimal.valueOf(getActiveNewUserCount(startTime, endTime, reqDto.getAppId(), version, channel));
+			// 计算新增用户占比
+			BigDecimal newUserRate = activeCount.compareTo(BigDecimal.ZERO) == 0 || newCount.compareTo(BigDecimal.ZERO) == 0 ?
+					BigDecimal.ZERO :
+					newCount.divide(activeCount, 4, RoundingMode.HALF_UP);
+			// 构建返回对象
+			PageActiveDetailVO detail = new PageActiveDetailVO();
+			if("day".equals(reqDto.getTimeUnit())){
+				LocalDateTime sevenDaysAgo = startTime.minusDays(7);
+				LocalDateTime thirtyDaysAgo = startTime.minusDays(30);
+				// 查询过去7天活跃用户数量
+				BigDecimal sevenCount = BigDecimal.valueOf(statActiveUserCount(sevenDaysAgo, startTime, reqDto.getAppId(), version, channel));
+				// 查询过去30天活跃用户数量
+				BigDecimal thirtyCount = BigDecimal.valueOf(statActiveUserCount(thirtyDaysAgo, startTime, reqDto.getAppId(), version, channel));
+
+				// 计算用户周活跃率
+				BigDecimal wauRate = sevenCount.compareTo(BigDecimal.ZERO) != 0 && activeCount.compareTo(BigDecimal.ZERO) != 0
+						? activeCount.divide(sevenCount, 4, RoundingMode.HALF_UP)
+						: BigDecimal.ZERO;
+				// 计算用户月活跃率
+				BigDecimal mauRate = thirtyCount.compareTo(BigDecimal.ZERO) != 0 && activeCount.compareTo(BigDecimal.ZERO) != 0
+						? activeCount.divide(thirtyCount, 4, RoundingMode.HALF_UP)
+						: BigDecimal.ZERO;
+				// 组装结果
+				detail.setWauRate(wauRate);
+				detail.setMauRate(mauRate);
+			} else if("week".equals(reqDto.getTimeUnit()) || "month".equals(reqDto.getTimeUnit())){
+				// 查询累计用户数
+				BigDecimal totalUser = BigDecimal.valueOf(statNewUserCount(null, endTime, reqDto.getAppId(), null, null));
+				// 查询活跃用户数
+				BigDecimal activeUser = BigDecimal.valueOf(statActiveUserCount(startTime, endTime, reqDto.getAppId(), null, null));
+				// 计算活跃率
+				BigDecimal rate = totalUser.compareTo(BigDecimal.ZERO) != 0 && activeUser.compareTo(BigDecimal.ZERO) != 0
+						? activeUser.divide(totalUser, 4, RoundingMode.HALF_UP)
+						: BigDecimal.ZERO;
+				if ("week".equals(reqDto.getTimeUnit())) {
+					detail.setWeekActiveUserRate(rate);
+				}else {
+					detail.setMonthActiveUserRate(rate);
+				}
+
+			}
+			// 定义日期格式
+			DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
+			// 处理日期显示
+			boolean isRangeType = "week".equals(reqDto.getTimeUnit()) || "month".equals(reqDto.getTimeUnit());
+			String displayDate = isRangeType && startTime != null && endTime != null
+					? startTime.toLocalDate().format(dateFormatter) + "~" + endTime.minusDays(1).toLocalDate().format(dateFormatter)
+					: date;
+			detail.setDate(displayDate);
+			detail.setActiveUser(activeCount.intValue());
+			detail.setNewUserRate(newUserRate);
+			result.add(detail);
+		}
+		// 返回结果
+		page.setRecords( result);
+		return page;
+	}
+	public Page<PageActiveDetailVO> pageActiveDetail2(PageUserAnalyseDTO reqDto) {
 		// 活跃构成:活跃用户中新增用户的占比比例
 		// 活跃粘度:DAU/过去7日活跃用户,DAU/过去30日活跃用户
 		// 过去7日活跃用户:过去7日(不含今日)的活跃用户数(去重)
@@ -896,90 +1163,7 @@ public class UserAnalyseServiceImpl implements UserAnalyseService {
 		page.setRecords( result);
 		return page;
 	}
-//	public Page<PageActiveDetailVO> pageActiveDetail(PageActiveDetailDTO reqDto) {
-//		// 1. 初始化分页对象并计算总条数
-//		Page<PageActiveDetailVO> page = new Page<>(reqDto.getCurrent(), reqDto.getSize());
-//		page.setTotal(calculateTotalCount(reqDto.getFromDate(), reqDto.getToDate(), reqDto.getTimeUnit()));
-//
-//		// 2. 生成当前页时间轴
-//		List<String> dates = generatePageTimeAxis(reqDto.getFromDate(), reqDto.getToDate(),
-//				reqDto.getTimeUnit(), reqDto.getCurrent(), reqDto.getSize());
-//		if (dates.isEmpty()) {
-//			return page; // 无数据直接返回
-//		}
-//		// 获取渠道和版本
-//		List<String> channel = reqDto.getChannel();
-//		String version = null;
-//		if (reqDto.getVersion() != null && !reqDto.getVersion().isEmpty()){
-//			version = reqDto.getVersion().get(0);
-//		}
-//		// 查询结果
-//		List<PageActiveDetailVO> result = new ArrayList<>();
-//		for (String date : dates) {
-//			PageActiveDetailVO detail = new PageActiveDetailVO();
-//			LocalDateTime startTime = getStartTime(date, reqDto.getTimeUnit());
-//			LocalDateTime endTime = getEndTime(date, reqDto.getTimeUnit());
-//
-//			// 查询活跃用户数量
-//			BigDecimal activeCount = BigDecimal.valueOf(statActiveUserCount(startTime, endTime, reqDto.getAppId(), version, reqDto.getChannel()));
-//			// 查询活跃用户中的新增用户数
-//			BigDecimal newCount = BigDecimal.valueOf(getActiveNewUserCount(startTime, endTime, reqDto.getAppId(), version, reqDto.getChannel()));
-//			// 计算新增用户占比
-//			BigDecimal newUserRate = activeCount.compareTo(BigDecimal.ZERO) == 0 || newCount.compareTo(BigDecimal.ZERO) == 0 ?
-//					BigDecimal.ZERO :
-//					newCount.divide(activeCount, 4, RoundingMode.HALF_UP);
-//
-//			if("day".equals(reqDto.getTimeUnit())){
-//				LocalDateTime sevenDaysAgo = startTime.minusDays(7);
-//				LocalDateTime thirtyDaysAgo = startTime.minusDays(30);
-//				// 查询过去7天活跃用户数量
-//				BigDecimal sevenCount = BigDecimal.valueOf(statActiveUserCount(sevenDaysAgo, startTime, reqDto.getAppId(), version, reqDto.getChannel()));
-//				// 查询过去30天活跃用户数量
-//				BigDecimal thirtyCount = BigDecimal.valueOf(statActiveUserCount(thirtyDaysAgo, startTime, reqDto.getAppId(), version, reqDto.getChannel()));
-//
-//				// 计算用户周活跃率
-//				BigDecimal wauRate = sevenCount.compareTo(BigDecimal.ZERO) != 0 && activeCount.compareTo(BigDecimal.ZERO) != 0
-//						? activeCount.divide(sevenCount, 4, RoundingMode.HALF_UP)
-//						: BigDecimal.ZERO;
-//
-//				// 计算
-//			}
-//
-//
-//
-//			// 过去30日活跃用户
-//			List<MktStatUserAnalysis> thirtyDaysUser = userAnalysisMapper.selectList(Wrappers.<MktStatUserAnalysis>lambdaQuery()
-//					.ge(MktStatUserAnalysis::getStatDate, thirtyDaysAgo)
-//					.lt(MktStatUserAnalysis::getStatDate, startTime)
-//					.in(channel!=null && !channel.isEmpty(),MktStatUserAnalysis::getChannel, channel)
-//					.eq("All".equals(version),MktStatUserAnalysis::getVersion, version)
-//					.select(MktStatUserAnalysis::getNewUser, MktStatUserAnalysis::getActiveUser)
-//			);
-//			BigDecimal thirtyDaysActiveUser = BigDecimal.valueOf(thirtyDaysUser.stream()
-//					.mapToInt(MktStatUserAnalysis::getActiveUser)
-//					.sum());
-//			BigDecimal thirtyDaysNewUser = BigDecimal.valueOf(thirtyDaysUser.stream()
-//					.mapToInt(MktStatUserAnalysis::getNewUser)
-//					.sum());
-//			BigDecimal mauRate = thirtyDaysActiveUser.compareTo(BigDecimal.ZERO) != 0 && thirtyDaysNewUser.compareTo(BigDecimal.ZERO) != 0
-//					? thirtyDaysNewUser.divide(thirtyDaysActiveUser, 4, RoundingMode.HALF_UP)
-//					: BigDecimal.ZERO;
-//
-//
-//			detail.setDate(date);
-//			detail.setActiveUser(activeUser.intValue());
-//			detail.setNewUserRate(newUserRate);
-//			detail.setWauRate(wauRate);
-//			detail.setMauRate(mauRate);
-//			result.add(detail);
-//
-//
-//		}
-//
-//
-//
-//		return page;
-//	}
+
 
 	/************************************** 启动次数 *****************************************
 	 * 查询启动次数趋势
@@ -1008,11 +1192,12 @@ public class UserAnalyseServiceImpl implements UserAnalyseService {
 					trend.setKey("launch");
 
 					// 计算每个时间点的启动次数
-					List<Integer> counts = dates.stream()
+					List<Long> counts = dates.stream()
 							.map(date -> calculateNewUserCount(date, version, reqDto.getChannel(), reqDto.getTimeUnit(), "launch"))
+							.map(Integer::longValue)
 							.collect(Collectors.toList());
 
-//					trend.setData(counts);
+					trend.setData(counts);
 					return trend;
 				})
 				.collect(Collectors.toList());
@@ -1026,7 +1211,7 @@ public class UserAnalyseServiceImpl implements UserAnalyseService {
 	 * @return Page
 	 */
 	@Override
-	public Page<PageLaunchDetailVO> pageLaunchDetail(PageActiveDetailDTO reqDto) {
+	public Page<PageLaunchDetailVO> pageLaunchDetail(PageUserAnalyseDTO reqDto) {
 		// 1. 初始化分页对象并计算总条数
 		Page<PageLaunchDetailVO> page = new Page<>(reqDto.getCurrent(), reqDto.getSize());
 		page.setTotal(calculateTotalCount(reqDto.getFromDate(), reqDto.getToDate(), reqDto.getTimeUnit()));
@@ -1725,7 +1910,7 @@ public class UserAnalyseServiceImpl implements UserAnalyseService {
 	}
 
 	/**
-	 * 查询指定时间范围内的活跃用户Id列表(去重)
+	 * 查询指定时间范围内的活跃用户Id列表
 	 */
 	private List<String> getNewUserIdList(LocalDateTime startTime, LocalDateTime endTime, String appId, String version, List<String> channels){
 
@@ -1743,7 +1928,7 @@ public class UserAnalyseServiceImpl implements UserAnalyseService {
 		if (version != null && !version.isEmpty()){
 			queryWrapper.eq(MktStatNewUser::getVersion, version);
 		}
-		// 4. 统计新增用户数,不用去重
+		// 4. 统计新增用户数
 		List<MktStatNewUser> newUsers = newUserMapper.selectList(queryWrapper);
 		return newUsers.stream().map(MktStatNewUser::getUserId).toList();
 	}