Quellcode durchsuchen

update: 新增用户、活跃用户、新增活跃粘度相关

lwh vor 1 Monat
Ursprung
Commit
89dd8665ad

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

@@ -22,6 +22,13 @@ public class UserAnalyseQueryBaseDTO implements Serializable {
 	@Serial
 	private static final long serialVersionUID = 1L;
 
+	/**
+	 * 应用ID
+	 */
+	@NotBlank(message = "应用ID不能为空")
+	@Schema(description = "应用ID", example = "FoigtBxJrmOi9nirwkjpsJ")
+	private String appId;
+
 	/**
 	 * 渠道
 	 */

+ 96 - 0
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/user/MktStatActiveUser.java

@@ -0,0 +1,96 @@
+package com.pig4cloud.pig.statistics.api.entity.user;
+
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.time.LocalDateTime;
+
+/**
+ * @author: lwh
+ * @date: 2025-08-15
+ * @description: 营销统计-活跃用户
+ */
+@Data
+@Schema(description = "活跃用户")
+@EqualsAndHashCode(callSuper = true)
+public class MktStatActiveUser extends Model<MktStatActiveUser> {
+
+	/**
+	 * id
+	 */
+	@TableId(value = "id")
+	private Long id;
+
+	/**
+	 * 用户ID
+	 */
+	@Schema(description = "用户ID")
+	private String userId;
+
+	/**
+	 * 应用ID
+	 */
+	@Schema(description = "应用ID")
+	private String appId;
+
+	/**
+	 * 渠道
+	 */
+	@Schema(description = "渠道")
+	private String channel;
+
+	/**
+	 * 版本
+	 */
+	@Schema(description = "版本")
+	private String version;
+
+	/**
+	 * 统计时间
+	 */
+	@Schema(description = "统计时间")
+	private LocalDateTime statDate;
+
+	/**
+	 * 删除标记
+	 */
+	@TableLogic
+	@TableField(fill = FieldFill.INSERT)
+	@Schema(description = "删除标记,1:已删除,0:正常")
+	private String delFlag;
+
+	/**
+	 * 创建人
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	@Schema(description = "创建人")
+	private String createBy;
+
+	/**
+	 * 修改人
+	 */
+	@TableField(fill = FieldFill.UPDATE)
+	@Schema(description = "修改人")
+	private String updateBy;
+
+	/**
+	 * 创建时间
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	@Schema(description = "创建时间")
+	private LocalDateTime createTime;
+
+	/**
+	 * 更新时间
+	 */
+	@TableField(fill = FieldFill.UPDATE)
+	@Schema(description = "更新时间")
+	private LocalDateTime updateTime;
+}

+ 99 - 0
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/user/MktStatNewUser.java

@@ -0,0 +1,99 @@
+package com.pig4cloud.pig.statistics.api.entity.user;
+
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.time.LocalDateTime;
+
+/**
+ * @author: lwh
+ * @date: 2025-08-15
+ * @description: 营销统计-新增用户
+ */
+@Data
+@Schema(description = "新增用户")
+@EqualsAndHashCode(callSuper = true)
+public class MktStatNewUser extends Model<MktStatNewUser> {
+
+	/**
+	 * id
+	 */
+	@TableId(value = "id")
+	private Long id;
+
+	/**
+	 * 用户ID
+	 */
+	@Schema(description = "用户ID")
+	private String userId;
+
+	/**
+	 * 应用ID
+	 */
+	@Schema(description = "应用ID")
+	private String appId;
+
+	/**
+	 * 渠道
+	 */
+	@Schema(description = "渠道")
+	private String channel;
+
+	/**
+	 * 版本
+	 */
+	@Schema(description = "版本")
+	private String version;
+
+	/**
+	 * 旧版本
+	 */
+	@Schema(description = "旧版本")
+	private String oldVersion;
+
+	/**
+	 * 统计时间
+	 */
+	@Schema(description = "统计时间")
+	private LocalDateTime statDate;
+
+	/**
+	 * 删除标记
+	 */
+	@TableLogic
+	@TableField(fill = FieldFill.INSERT)
+	@Schema(description = "删除标记,1:已删除,0:正常")
+	private String delFlag;
+
+	/**
+	 * 创建人
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	@Schema(description = "创建人")
+	private String createBy;
+
+	/**
+	 * 修改人
+	 */
+	@TableField(fill = FieldFill.UPDATE)
+	@Schema(description = "修改人")
+	private String updateBy;
+
+	/**
+	 * 创建时间
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	@Schema(description = "创建时间")
+	private LocalDateTime createTime;
+
+	/**
+	 * 更新时间
+	 */
+	@TableField(fill = FieldFill.UPDATE)
+	@Schema(description = "更新时间")
+	private LocalDateTime updateTime;
+}

+ 1 - 1
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/MktStatUserAnalysis.java → pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/user/MktStatUserAnalysis.java

@@ -1,4 +1,4 @@
-package com.pig4cloud.pig.statistics.api.entity;
+package com.pig4cloud.pig.statistics.api.entity.user;
 
 
 import com.baomidou.mybatisplus.annotation.FieldFill;

+ 1 - 1
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/MktStatUserRetention.java → pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/user/MktStatUserRetention.java

@@ -1,4 +1,4 @@
-package com.pig4cloud.pig.statistics.api.entity;
+package com.pig4cloud.pig.statistics.api.entity.user;
 
 
 import com.baomidou.mybatisplus.annotation.FieldFill;

+ 15 - 0
pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/mapper/MktStatActiveUserMapper.java

@@ -0,0 +1,15 @@
+package com.pig4cloud.pig.statistics.mapper;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.pig4cloud.pig.statistics.api.entity.user.MktStatActiveUser;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * @author: lwh
+ * @date: 2025-08-15
+ * @description: 活跃用户Mapper
+ */
+@Mapper
+public interface MktStatActiveUserMapper extends BaseMapper<MktStatActiveUser> {
+}

+ 15 - 0
pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/mapper/MktStatNewUserMapper.java

@@ -0,0 +1,15 @@
+package com.pig4cloud.pig.statistics.mapper;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.pig4cloud.pig.statistics.api.entity.user.MktStatNewUser;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * @author: lwh
+ * @date: 2025-08-15
+ * @description: 新增用户mapper
+ */
+@Mapper
+public interface MktStatNewUserMapper extends BaseMapper<MktStatNewUser> {
+}

+ 1 - 1
pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/mapper/MktStatUserAnalysisMapper.java

@@ -2,7 +2,7 @@ package com.pig4cloud.pig.statistics.mapper;
 
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.pig4cloud.pig.statistics.api.entity.MktStatUserAnalysis;
+import com.pig4cloud.pig.statistics.api.entity.user.MktStatUserAnalysis;
 import org.apache.ibatis.annotations.Mapper;
 
 /**

+ 1 - 1
pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/mapper/MktStatUserRetentionMapper.java

@@ -2,7 +2,7 @@ package com.pig4cloud.pig.statistics.mapper;
 
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import com.pig4cloud.pig.statistics.api.entity.MktStatUserRetention;
+import com.pig4cloud.pig.statistics.api.entity.user.MktStatUserRetention;
 import org.apache.ibatis.annotations.Mapper;
 
 /**

+ 140 - 42
pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/service/impl/UserAnalyseServiceImpl.java

@@ -6,9 +6,13 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.pig4cloud.pig.common.core.exception.BusinessException;
 import com.pig4cloud.pig.statistics.api.dto.user.*;
-import com.pig4cloud.pig.statistics.api.entity.MktStatUserAnalysis;
-import com.pig4cloud.pig.statistics.api.entity.MktStatUserRetention;
+import com.pig4cloud.pig.statistics.api.entity.user.MktStatActiveUser;
+import com.pig4cloud.pig.statistics.api.entity.user.MktStatNewUser;
+import com.pig4cloud.pig.statistics.api.entity.user.MktStatUserAnalysis;
+import com.pig4cloud.pig.statistics.api.entity.user.MktStatUserRetention;
 import com.pig4cloud.pig.statistics.api.vo.user.*;
+import com.pig4cloud.pig.statistics.mapper.MktStatActiveUserMapper;
+import com.pig4cloud.pig.statistics.mapper.MktStatNewUserMapper;
 import com.pig4cloud.pig.statistics.mapper.MktStatUserAnalysisMapper;
 import com.pig4cloud.pig.statistics.mapper.MktStatUserRetentionMapper;
 import com.pig4cloud.pig.statistics.service.UserAnalyseService;
@@ -43,8 +47,12 @@ public class UserAnalyseServiceImpl implements UserAnalyseService {
 
 	private final MktStatUserAnalysisMapper userAnalysisMapper;
 
-
 	private final MktStatUserRetentionMapper userRetentionMapper;
+
+	private final MktStatActiveUserMapper activeUserMapper;
+
+	private final MktStatNewUserMapper newUserMapper;
+
 	/**
 	 * 获取新增趋势
 	 * @param reqDto 请求参数
@@ -428,49 +436,83 @@ public class UserAnalyseServiceImpl implements UserAnalyseService {
 	 */
 	@Override
 	public GetActiveUserBaseVO getActiveViscosity(UserAnalyseQueryBaseDTO reqDto) {
-		GetActiveUserBaseVO result = new GetActiveUserBaseVO();
+		if (!"day".equals(reqDto.getTimeUnit())){
+			throw new BusinessException("时间单位只能为day");
+		}
+		String version = null;
+		if (reqDto.getVersion() != null && !reqDto.getVersion().isEmpty()) {
+			version =reqDto.getVersion().get(0);
+		}
+		List<ActiveUserComposeVO> items = new ArrayList<>();
 
-		// 构建日期列表(可根据 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<BigDecimal> dayCounts = new ArrayList<>();
+		List<BigDecimal> sevenCounts = new ArrayList<>();
+		List<BigDecimal> thirtyCounts = new ArrayList<>();
+		List<BigDecimal> sevenRates = new ArrayList<>();
+		List<BigDecimal> thirtyRates = new ArrayList<>();
 
-		// 构建活跃用户组成数据
-		List<ActiveUserComposeVO> items = new ArrayList<>();
+		List<String> dates = generateTimeAxis(reqDto.getFromDate(), reqDto.getToDate(), reqDto.getTimeUnit());
+		for (String date : dates) {
+			LocalDateTime startTime = getStartTime(date, reqDto.getTimeUnit());
+			LocalDateTime endTime = getEndTime(date, reqDto.getTimeUnit());
+			LocalDateTime sevenDaysAgo = startTime.minusDays(7);
+			LocalDateTime thirtyDaysAgo = startTime.minusDays(30);
+			// 今日活跃用户数
+			BigDecimal dayCount = BigDecimal.valueOf(statActiveUserCount(startTime, endTime, reqDto.getAppId(), version, reqDto.getChannel()));
+			dayCounts.add(dayCount);
+			// 过去7日活跃用户
+			BigDecimal sevenCount = BigDecimal.valueOf(statActiveUserCount(sevenDaysAgo, startTime, reqDto.getAppId(), version, reqDto.getChannel()));
+			sevenCounts.add(sevenCount);
+			// 过去7日活跃用户
+			BigDecimal thirtyCount = BigDecimal.valueOf(statActiveUserCount(thirtyDaysAgo, startTime, reqDto.getAppId(), version, reqDto.getChannel()));
+			thirtyCounts.add(thirtyCount);
+			// 计算7日活跃用户占比
+			sevenRates.add(dayCount.compareTo(BigDecimal.ZERO) == 0 || sevenCount.compareTo(BigDecimal.ZERO) == 0
+					? BigDecimal.ZERO
+					: dayCount.divide(sevenCount, 4, RoundingMode.HALF_UP));
+			// 计算30日活跃用户占比
+			thirtyRates.add(dayCount.compareTo(BigDecimal.ZERO) == 0 || thirtyCount.compareTo(BigDecimal.ZERO) == 0
+					? BigDecimal.ZERO:
+					dayCount.divide(thirtyCount, 4, RoundingMode.HALF_UP));
+		}
+		// 组装返回数据
+		ActiveUserComposeVO activeUser = new ActiveUserComposeVO();
+		activeUser.setData(dayCounts);
+		activeUser.setName("日活");
+		activeUser.setKey("activeUser");
+		activeUser.setVersion(version == null ? "All" : version);
+		items.add(activeUser);
 
-		// 日活数据
-		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);
+		ActiveUserComposeVO wau = new ActiveUserComposeVO();
+		wau.setData(sevenCounts);
+		wau.setName("过去7日活跃用户");
+		wau.setKey("wau");
+		wau.setVersion(version == null ? "All" : version);
+		items.add(wau);
+
+		ActiveUserComposeVO wauRate = new ActiveUserComposeVO();
+		wauRate.setData(sevenRates);
+		wauRate.setName("DAU/过去7日活跃用户");
+		wauRate.setKey("wauRate");
+		wauRate.setVersion(version == null ? "All" : version);
+		items.add(wauRate);
+
+		ActiveUserComposeVO mau = new ActiveUserComposeVO();
+		mau.setData(thirtyCounts);
+		mau.setName("过去30日活跃用户");
+		mau.setKey("mau");
+		mau.setVersion(version == null ? "All" : version);
+		items.add(mau);
+
+		ActiveUserComposeVO mauRate = new ActiveUserComposeVO();
+		mauRate.setData(thirtyRates);
+		mauRate.setName("DAU/过去30日活跃用户");
+		mauRate.setKey("mauRate");
+		mauRate.setVersion(version == null ? "All" : version);
+		items.add(mauRate);
 
+		GetActiveUserBaseVO result = new GetActiveUserBaseVO();
+		result.setDates(dates);
 		result.setItems(items);
 		return result;
 	}
@@ -1461,4 +1503,60 @@ public class UserAnalyseServiceImpl implements UserAnalyseService {
 				throw new IllegalArgumentException("不支持的时间单位: " + timeUnit);
 		}
 	}
+
+	/**
+	 * 统计指定时间范围内的新增用户数
+	 */
+	private Long statNewUserCount(LocalDateTime startTime, LocalDateTime endTime, String appId, String version, List<String> channels){
+		// 1. 空值判断
+		if (startTime == null || endTime == null) {
+			return 0L;
+		}
+		// 2. 组装查询条件
+		LambdaQueryWrapper<MktStatNewUser> queryWrapper = Wrappers.<MktStatNewUser>lambdaQuery()
+				.eq(MktStatNewUser::getAppId, appId)
+				.ge(MktStatNewUser::getStatDate, startTime)
+				.lt(MktStatNewUser::getStatDate, endTime);
+
+		// 添加渠道条件
+		if (channels != null && !channels.isEmpty()) {
+			queryWrapper.in(MktStatNewUser::getChannel, channels);
+		}
+		// 添加版本条件
+		if (version != null && !version.isEmpty()){
+			queryWrapper.eq(MktStatNewUser::getVersion, version);
+		}
+		// 3. 统计新增用户数,不用去重
+		List<MktStatNewUser> newUsers = newUserMapper.selectList(queryWrapper);
+		return newUsers == null ? 0L : newUsers.size();
+	}
+
+	/**
+	 * 统计指定时间范围内的活跃用户数(去重)
+	 */
+	private Long statActiveUserCount(LocalDateTime startTime, LocalDateTime endTime, String appId, String version, List<String> channels){
+		// 1. 空值判断
+		if (startTime == null || endTime == null) {
+			return 0L;
+		}
+		// 2. 组装查询条件
+		LambdaQueryWrapper<MktStatActiveUser> queryWrapper = Wrappers.<MktStatActiveUser>lambdaQuery()
+				.eq(MktStatActiveUser::getAppId, appId)
+				.ge(MktStatActiveUser::getStatDate, startTime)
+				.lt(MktStatActiveUser::getStatDate, endTime)
+				.select(MktStatActiveUser::getUserId)
+				.groupBy(MktStatActiveUser::getUserId);
+
+		// 添加渠道条件
+		if (channels != null && !channels.isEmpty()) {
+			queryWrapper.in(MktStatActiveUser::getChannel, channels);
+		}
+		// 添加版本条件
+		if (version != null && !version.isEmpty()){
+			queryWrapper.eq(MktStatActiveUser::getVersion, version);
+		}
+		// 3. 统计活跃用户数,根据userID去重
+		List<MktStatActiveUser> activeUsers = activeUserMapper.selectList(queryWrapper);
+		return activeUsers == null ? 0L : activeUsers.size();
+	}
 }