Przeglądaj źródła

Merge branch 'dev/wcl' of https://s-20coaj910c.zht2.com/lwh/seo into dev/lwh

lwh 3 tygodni temu
rodzic
commit
46b8fe2676
21 zmienionych plików z 683 dodań i 197 usunięć
  1. 3 0
      pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/dto/uninstall/GetUninstallInsightDTO.java
  2. 3 0
      pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/dto/uninstall/GetUninstallTrendDTO.java
  3. 6 0
      pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/dto/uninstall/GetUninstallTrendDetailDTO.java
  4. 3 0
      pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/dto/uninstall/UninstallPredictDTO.java
  5. 17 0
      pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/ConfigItem.java
  6. 30 0
      pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktDeviceAction.java
  7. 31 0
      pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktDeviceCount.java
  8. 30 0
      pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktDeviceInterfere.java
  9. 31 0
      pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktDeviceTime.java
  10. 43 0
      pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktTrendSummary.java
  11. 3 0
      pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/vo/uninstall/UninstallPortraitCharacterVO.java
  12. 71 0
      pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/Util/ConfigUtils.java
  13. 22 15
      pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/controller/UninstallAnalyseController.java
  14. 8 0
      pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/mapper/MktDeviceActionMapper.java
  15. 8 0
      pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/mapper/MktDeviceCountMapper.java
  16. 8 0
      pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/mapper/MktDeviceInterfereMapper.java
  17. 8 0
      pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/mapper/MktDeviceTimeMapper.java
  18. 10 0
      pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/mapper/MktTrendSummaryMapper.java
  19. 21 0
      pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/mapper/SysConfigMapper.java
  20. 39 15
      pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/service/UninstallAnalyseService.java
  21. 288 167
      pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/service/impl/UninstallAnalyseServiceImpl.java

+ 3 - 0
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/dto/uninstall/GetUninstallInsightDTO.java

@@ -14,4 +14,7 @@ public class GetUninstallInsightDTO {
 
 	@Schema(description = "周期(周/月)")
 	private String cycle;
+
+	@Schema(description = "类型(0-active 1-before)")
+	private String type;
 }

+ 3 - 0
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/dto/uninstall/GetUninstallTrendDTO.java

@@ -15,6 +15,9 @@ public class GetUninstallTrendDTO {
 	@Schema(description = "开始时间(yyyy-MM-dd),不传则默认为当周第一天")
 	private String startDate;
 
+	@Schema(description = "结束时间(yyyy-MM-dd),不传则默认为当前时间")
+	private String endDate;
+
 	
 	@Schema(description = "时间单位(day/week/month),不传则默认为day")
 	private String timeUnit;

+ 6 - 0
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/dto/uninstall/GetUninstallTrendDetailDTO.java

@@ -20,4 +20,10 @@ public class GetUninstallTrendDetailDTO {
 
 	@Schema(description = "时间单位(week/month)")
 	private String timeUnit;
+
+	@Schema(description = "页码")
+	private Integer pageNum;
+
+	@Schema(description = "每页条数")
+	private Integer pageSize;
 }

+ 3 - 0
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/dto/uninstall/UninstallPredictDTO.java

@@ -15,4 +15,7 @@ public class UninstallPredictDTO {
 
 	@Schema(description = "周期(周/月)")
 	private String cycle;
+
+	@Schema(description = "类型(卸载流失设备/召回设备(预测))")
+	private String type;
 }

+ 17 - 0
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/ConfigItem.java

@@ -0,0 +1,17 @@
+package com.pig4cloud.pig.statistics.api.entity;
+
+
+import lombok.Data;
+
+/**
+ * @author wcl
+ * @date 2025/8/19 10:53
+ * @description: 配置
+ */
+@Data
+public class ConfigItem {
+
+	private String key; // config_key
+	private String value; // config_value
+	private String label; // config_label
+}

+ 30 - 0
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktDeviceAction.java

@@ -0,0 +1,30 @@
+package com.pig4cloud.pig.statistics.api.entity.uninstall;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import java.util.Date;
+
+/**
+ * @author wcl
+ * @date 2025/8/19 10:53
+ * @description: 卸载前后操作行为分布表实体
+ */
+@Data
+@TableName("uninstall_device_action")
+public class MktDeviceAction {
+    @TableId
+    private Long id;
+    private Date statDate; // 统计日期
+    private String statCycle; // 统计周期
+    private String appId; // 应用ID
+    private String channel; // 渠道
+    private String appVersion; // 应用版本
+    private String actionType; // 操作类型
+    private String actionValue; // 操作值
+    private Integer triggerCount; // 触发次数
+    private String ext1;
+    private String ext2;
+    private Date createdAt;
+    private Date updatedAt;
+}

+ 31 - 0
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktDeviceCount.java

@@ -0,0 +1,31 @@
+package com.pig4cloud.pig.statistics.api.entity.uninstall;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import java.util.Date;
+
+/**
+ * @author wcl
+ * @date 2025/8/19 10:53
+ * @description: 卸载相关次数分布表实体
+ */
+@Data
+@TableName("uninstall_device_count")
+public class MktDeviceCount {
+    @TableId
+    private Long id;
+    private Date statDate; // 统计日期
+    private String statCycle; // 统计周期
+    private String appId; // 应用ID
+    private String channel; // 渠道
+    private String appVersion; // 应用版本
+    private String type; // 分布类型
+    private String countRange; // 次数区间
+    private Integer num; // 设备数/次数
+    private Double rate; // 占比(%)
+    private String ext1;
+    private String ext2;
+    private Date createdAt;
+    private Date updatedAt;
+}

+ 30 - 0
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktDeviceInterfere.java

@@ -0,0 +1,30 @@
+package com.pig4cloud.pig.statistics.api.entity.uninstall;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import java.util.Date;
+
+/**
+ * @author wcl
+ * @date 2025/8/19 10:53
+ * @description: 卸载前干预类型分布表实体
+ */
+@Data
+@TableName("uninstall_device_interfere")
+public class MktDeviceInterfere {
+    @TableId
+    private Long id;
+    private Date statDate; // 统计日期
+    private String statCycle; // 统计周期
+    private String appId; // 应用ID
+    private String channel; // 渠道
+    private String appVersion; // 应用版本
+    private String interfereType; // 干预类型
+    private String countRange; // 次数区间
+    private Integer num; // 次数
+    private String ext1;
+    private String ext2;
+    private Date createdAt;
+    private Date updatedAt;
+}

+ 31 - 0
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktDeviceTime.java

@@ -0,0 +1,31 @@
+package com.pig4cloud.pig.statistics.api.entity.uninstall;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import java.util.Date;
+
+/**
+ * @author wcl
+ * @date 2025/8/19 10:53
+ * @description: 卸载相关时长分布表实体
+ */
+@Data
+@TableName("uninstall_device_time")
+public class MktDeviceTime {
+    @TableId
+    private Long id; // 主键
+    private Date statDate; // 统计日期
+    private String statCycle; // 统计周期
+    private String appId; // 应用ID
+    private String channel; // 渠道
+    private String appVersion; // 应用版本
+    private String type; // 分布类型(before, after, sys, insight等)
+    private String timeRange; // 时长区间
+    private Integer deviceCount; // 设备数
+    private Double rate; // 占比(%)
+    private String ext1;
+    private String ext2;
+    private Date createdAt;
+    private Date updatedAt;
+}

+ 43 - 0
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktTrendSummary.java

@@ -0,0 +1,43 @@
+package com.pig4cloud.pig.statistics.api.entity.uninstall;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import java.util.Date;
+
+/**
+ * @author wcl
+ * @date 2025/8/19 10:53
+ * @description: 卸载趋势汇总表实体
+ */
+@Data
+@TableName("uninstall_trend_summary")
+public class MktTrendSummary {
+    /** 主键 */
+    @TableId
+    private Long id;
+    /** 统计日期 */
+    private Date statDate;
+    /** 统计周期(week、month等) */
+    private String statCycle;
+    /** 应用ID */
+    private String appId;
+    /** 渠道 */
+    private String channel;
+    /** 应用版本 */
+    private String appVersion;
+    /** 趋势类型(0-卸载, 1-召回等) */
+    private Integer trendType;
+    /** 数量 */
+    private Integer count;
+    /** 比率(%) */
+    private Double rate;
+    /** 扩展字段1 */
+    private String ext1;
+    /** 扩展字段2 */
+    private String ext2;
+    /** 创建时间 */
+    private Date createdAt;
+    /** 更新时间 */
+    private Date updatedAt;
+}

+ 3 - 0
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/vo/uninstall/UninstallPortraitCharacterVO.java

@@ -21,4 +21,7 @@ public class UninstallPortraitCharacterVO {
 
 	@Schema(description = "百分比")
 	private String percent;
+
+	@Schema(description = "状态 0-易卸载特征 1-不易卸载特征")
+	private Integer status;
 }

+ 71 - 0
pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/Util/ConfigUtils.java

@@ -0,0 +1,71 @@
+package com.pig4cloud.pig.statistics.Util;
+
+
+import com.pig4cloud.pig.statistics.api.entity.ConfigItem;
+import com.pig4cloud.pig.statistics.mapper.SysConfigMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author wcl
+ * @date 2025/8/19 10:51
+ * @description: 配置缓存工具类
+ */
+@Component
+public class ConfigUtils {
+
+	private static SysConfigMapper sysConfigMapper;
+	private static RedisTemplate<String, Object> redisTemplate;
+	private static final String CONFIG_CACHE_PREFIX = "sys_config:";
+
+	@Autowired
+	public ConfigUtils(SysConfigMapper sysConfigMapper, RedisTemplate<String, Object> redisTemplate) {
+		ConfigUtils.sysConfigMapper = sysConfigMapper;
+		ConfigUtils.redisTemplate = redisTemplate;
+	}
+
+	/**
+	 * 获取配置项
+	 * @param configKey 配置项key
+	 * @return 配置项
+	 */
+	public static List<ConfigItem> getConfigValues(String configKey) {
+		String cacheKey = CONFIG_CACHE_PREFIX + configKey;
+		List<ConfigItem> cached = (List<ConfigItem>) redisTemplate.opsForValue().get(cacheKey);
+		if (cached != null) {
+			return cached;
+		}
+		List<ConfigItem> list = sysConfigMapper.selectByConfigKey(configKey);
+		redisTemplate.opsForValue().set(cacheKey, list, 1, TimeUnit.HOURS);
+		return list;
+	}
+
+	public static void clearConfigCache(String configKey) {
+		redisTemplate.delete(CONFIG_CACHE_PREFIX + configKey);
+	}
+
+	/**
+	 * 获取一条配置
+	 * @param configKey
+	 * @param configValue
+	 * @return
+	 */
+	public static ConfigItem getConfigValue(String configKey , String configValue) {
+
+		ConfigItem configItem = new ConfigItem();
+		List<ConfigItem> configValues = getConfigValues(configKey);
+
+		for (ConfigItem item : configValues) {
+			if (item.getValue().equals(configValue)) {
+				configItem = item;
+				break;
+			}
+		}
+
+		return configItem;
+	}
+}

+ 22 - 15
pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/controller/UninstallAnalyseController.java

@@ -1,5 +1,6 @@
 package com.pig4cloud.pig.statistics.controller;
 
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.pig4cloud.pig.common.core.util.R;
 import com.pig4cloud.pig.statistics.api.dto.uninstall.*;
 import com.pig4cloud.pig.statistics.api.vo.uninstall.*;
@@ -35,51 +36,57 @@ public class UninstallAnalyseController {
 
 	@PostMapping("/trend/detail")
 	@Operation(summary = "获取卸载趋势明细数据")
-	public R<List<UninstallTrendDtlVO>> getUninstallTrendDetail(@RequestBody GetUninstallTrendDetailDTO dto) {
+	public R<Page<UninstallTrendDtlVO>> getUninstallTrendDetail(@RequestBody GetUninstallTrendDetailDTO dto) {
 		return R.ok(uninstallAnalyseService.getUninstallTrendDetail(dto));
 	}
 
 	@PostMapping("/active")
-	@Operation(summary = "卸载设备活跃情况")
+	@Operation(summary = "卸载洞察-卸载设备活跃情况")
 	public R<UninstallInsightVO> getActive(@RequestBody GetUninstallInsightDTO dto)  {
-		return R.ok();
+		return R.ok(uninstallAnalyseService.getUninstallDeviceActive(dto));
 	}
 
 	@PostMapping("/uninstallBefore")
-	@Operation(summary = "卸载前状态")
+	@Operation(summary = "卸载洞察-卸载前状态")
 	public R<UninstallBeforeVO> uninstallBefore(@RequestBody GetUninstallInsightDTO dto) {
-		return R.ok();
+		return R.ok(uninstallAnalyseService.uninstallBefore(dto));
 	}
 
 	@PostMapping("/uninstallAfter")
-	@Operation(summary = "卸载后流失")
+	@Operation(summary = "卸载洞察-卸载后流失")
 	public R<List<UninstallOfterAPPOV>> uninstallAfter(@RequestBody GetUninstallInsightDTO dto) {
-		return R.ok();
+		return R.ok(uninstallAnalyseService.uninstallAfter(dto));
 	}
 
 	@PostMapping("/uninstallSys")
-	@Operation(summary = "设备系统分布")
+	@Operation(summary = "卸载洞察-设备系统分布")
 	public R<List<UninstallSYSOV>> uninstallSys(@RequestBody GetUninstallInsightDTO dto) {
-		return R.ok();
+		return R.ok(uninstallAnalyseService.uninstallSys(dto));
 	}
 
 
 	@PostMapping("/portrait")
 	@Operation(summary = "卸载画像")
 	public R<UninstallPortraitOV> getUninstallPortrait(@RequestBody UninstallPortraitDTO dto) {
-		return R.ok();
+		return R.ok(uninstallAnalyseService.getUninstallPortrait(dto));
 	}
 
 	@PostMapping("/predict")
-	@Operation(summary = "卸载预测")
+	@Operation(summary = "卸载归因-卸载预测")
 	public R<UninstallPredictVO> getUninstallPredict(@RequestBody UninstallPredictDTO dto) {
-		return R.ok();
+		return R.ok(uninstallAnalyseService.getUninstallPredict(dto));
 	}
 
 	@PostMapping("/predict/detail")
-	@Operation(summary = "安装卸载比")
-	public R<InstallUninstallRatioVO> getInstallUninstallRatio(@RequestBody InstallUninstallRatioDTO dto) {
-		return R.ok();
+	@Operation(summary = "卸载归因-安装卸载比")
+	public R<List<InstallUninstallRatioVO>> getInstallUninstallRatio(@RequestBody InstallUninstallRatioDTO dto) {
+		return R.ok(uninstallAnalyseService.getInstallUninstallRatio(dto));
+	}
+
+	@PostMapping("/predict/detailList")
+	@Operation(summary = "卸载归因-安装卸载比明细")
+	public R<List<InstallUninstallRatioVO>> getInstallUninstallRatioDetail(@RequestBody InstallUninstallRatioDTO dto) {
+		return R.ok(uninstallAnalyseService.getInstallUninstallRatioDetail(dto));
 	}
 
 }

+ 8 - 0
pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/mapper/MktDeviceActionMapper.java

@@ -0,0 +1,8 @@
+package com.pig4cloud.pig.statistics.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.pig4cloud.pig.statistics.api.entity.uninstall.MktDeviceAction;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface MktDeviceActionMapper extends BaseMapper<MktDeviceAction> {}

+ 8 - 0
pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/mapper/MktDeviceCountMapper.java

@@ -0,0 +1,8 @@
+package com.pig4cloud.pig.statistics.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.pig4cloud.pig.statistics.api.entity.uninstall.MktDeviceCount;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface MktDeviceCountMapper extends BaseMapper<MktDeviceCount> {}

+ 8 - 0
pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/mapper/MktDeviceInterfereMapper.java

@@ -0,0 +1,8 @@
+package com.pig4cloud.pig.statistics.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.pig4cloud.pig.statistics.api.entity.uninstall.MktDeviceInterfere;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface MktDeviceInterfereMapper extends BaseMapper<MktDeviceInterfere> {}

+ 8 - 0
pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/mapper/MktDeviceTimeMapper.java

@@ -0,0 +1,8 @@
+package com.pig4cloud.pig.statistics.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.pig4cloud.pig.statistics.api.entity.uninstall.MktDeviceTime;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface MktDeviceTimeMapper extends BaseMapper<MktDeviceTime> {}

+ 10 - 0
pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/mapper/MktTrendSummaryMapper.java

@@ -0,0 +1,10 @@
+package com.pig4cloud.pig.statistics.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.pig4cloud.pig.statistics.api.entity.uninstall.MktTrendSummary;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface MktTrendSummaryMapper extends BaseMapper<MktTrendSummary> {
+    // 可扩展自定义方法
+}

+ 21 - 0
pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/mapper/SysConfigMapper.java

@@ -0,0 +1,21 @@
+package com.pig4cloud.pig.statistics.mapper;
+
+
+import com.pig4cloud.pig.statistics.api.entity.ConfigItem;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+/**
+ * @author wcl
+ * @date 2025/8/19 10:52
+ * @description: 配置Mapper
+ */
+@Mapper
+public interface SysConfigMapper {
+
+	@Select("SELECT config_key as key , config_value as value, config_label as label FROM sys_config WHERE config_key = #{configKey} AND enable = 1 ORDER BY sort ASC")
+	List<ConfigItem> selectByConfigKey(@Param("configKey") String configKey);
+}

+ 39 - 15
pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/service/UninstallAnalyseService.java

@@ -1,12 +1,8 @@
 package com.pig4cloud.pig.statistics.service;
 
-import com.pig4cloud.pig.statistics.api.dto.uninstall.GetUninstallInsightDTO;
-import com.pig4cloud.pig.statistics.api.dto.uninstall.GetUninstallTrendDTO;
-import com.pig4cloud.pig.statistics.api.dto.uninstall.GetUninstallTrendDetailDTO;
-import com.pig4cloud.pig.statistics.api.vo.uninstall.UninstallCompetitorVO;
-import com.pig4cloud.pig.statistics.api.vo.uninstall.UninstallInsightVO;
-import com.pig4cloud.pig.statistics.api.vo.uninstall.UninstallTrendDtlVO;
-import com.pig4cloud.pig.statistics.api.vo.uninstall.UninstallTrendVO;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.pig4cloud.pig.statistics.api.dto.uninstall.*;
+import com.pig4cloud.pig.statistics.api.vo.uninstall.*;
 
 import java.util.List;
 
@@ -29,19 +25,47 @@ public interface UninstallAnalyseService {
 	 * @param dto 查询参数
 	 * @return 趋势明细列表
 	 */
-	List<UninstallTrendDtlVO> getUninstallTrendDetail(GetUninstallTrendDetailDTO dto);
+	Page<UninstallTrendDtlVO> getUninstallTrendDetail(GetUninstallTrendDetailDTO dto);
 
 	/**
-	 * 获取卸载用户洞察
+	 * 卸载设备活跃情况(时长分布+历史卸载次数分布,模拟数据)
 	 * @param dto 查询参数
-	 * @return 用户洞察数据
+	 * @return UninstallInsightVO
 	 */
-	UninstallInsightVO getUninstallInsight(GetUninstallInsightDTO dto);
+	UninstallInsightVO getUninstallDeviceActive(GetUninstallInsightDTO dto);
 
 	/**
-	 * 获取流失去向分析
-	 * @param dto 查询参数
-	 * @return 流失去向数据
+	 * 卸载前状态
+	 */
+	UninstallBeforeVO uninstallBefore(GetUninstallInsightDTO dto);
+
+	/**
+	 * 卸载后流失
+	 */
+	List<UninstallOfterAPPOV> uninstallAfter(GetUninstallInsightDTO dto);
+
+	/**
+	 * 卸载后系统设备分布
+	 */
+	List<UninstallSYSOV> uninstallSys(GetUninstallInsightDTO dto);
+
+	/**
+	 * 卸载画像
+	 */
+	UninstallPortraitOV getUninstallPortrait(UninstallPortraitDTO dto);
+
+	/**
+	 * 卸载归因-卸载预测
+	 */
+	UninstallPredictVO getUninstallPredict(UninstallPredictDTO dto);
+
+	/**
+	 * 安装卸载比
+	 */
+	List<InstallUninstallRatioVO> getInstallUninstallRatio(InstallUninstallRatioDTO dto);
+
+	/**
+	 * 安装卸载比明细
 	 */
-	UninstallCompetitorVO getUninstallCompetitor(GetUninstallTrendDTO dto);
+	List<InstallUninstallRatioVO> getInstallUninstallRatioDetail(InstallUninstallRatioDTO dto);
 }

+ 288 - 167
pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/service/impl/UninstallAnalyseServiceImpl.java

@@ -1,17 +1,19 @@
 package com.pig4cloud.pig.statistics.service.impl;
 
-import cn.hutool.core.util.StrUtil;
-import com.pig4cloud.pig.statistics.api.dto.uninstall.GetUninstallInsightDTO;
-import com.pig4cloud.pig.statistics.api.dto.uninstall.GetUninstallTrendDTO;
-import com.pig4cloud.pig.statistics.api.dto.uninstall.GetUninstallTrendDetailDTO;
-import com.pig4cloud.pig.statistics.api.vo.uninstall.UninstallCompetitorVO;
-import com.pig4cloud.pig.statistics.api.vo.uninstall.UninstallInsightVO;
-import com.pig4cloud.pig.statistics.api.vo.uninstall.UninstallTrendDtlVO;
-import com.pig4cloud.pig.statistics.api.vo.uninstall.UninstallTrendVO;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.pig4cloud.pig.statistics.Util.ConfigUtils;
+import com.pig4cloud.pig.statistics.api.dto.uninstall.*;
+import com.pig4cloud.pig.statistics.api.entity.ConfigItem;
+import com.pig4cloud.pig.statistics.api.entity.uninstall.*;
+import com.pig4cloud.pig.statistics.api.vo.uninstall.*;
+import com.pig4cloud.pig.statistics.mapper.*;
 import com.pig4cloud.pig.statistics.service.UninstallAnalyseService;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.time.DayOfWeek;
 import java.time.LocalDate;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
@@ -27,61 +29,69 @@ public class UninstallAnalyseServiceImpl implements UninstallAnalyseService {
 
 	private static final Random random = new Random();
 
-	@Override
-	public UninstallTrendVO getUninstallTrend(GetUninstallTrendDTO dto) {
-
-		// 参数校验
-		LocalDate startDate = LocalDate.parse(dto.getStartDate());
-		if (StrUtil.isBlank(dto.getStartDate()) ) {
-			// 为空则取当前日期
-			startDate = LocalDate.now();
-		}
-		// 计算本周一到当前日期的数据
-		LocalDate firstDayOfWeek = startDate.minusDays(startDate.getDayOfWeek().getValue() - 1);
-
-		UninstallTrendVO summary = new UninstallTrendVO();
-		summary.setStartDate(firstDayOfWeek.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
-		summary.setUninstallCounts(generateRandomCount(10, 200));
-		summary.setRecallCounts(generateRandomCount(10, 200));
-		summary.setUninstallRates( calculateRates(summary.getUninstallCounts(), 1000));
-		summary.setRecallRates(calculateRates(summary.getRecallCounts(), summary.getUninstallCounts()));
-		
-		return summary;
-	}
+    @Autowired
+    private MktTrendSummaryMapper mktTrendSummaryMapper;
+    @Autowired
+    private MktDeviceTimeMapper mktDeviceTimeMapper;
+    @Autowired
+    private MktDeviceCountMapper mktDeviceCountMapper;
+    @Autowired
+    private MktDeviceInterfereMapper mktDeviceInterfereMapper;
+    @Autowired
+    private MktDeviceActionMapper mktDeviceActionMapper;
 
-	@Override
-	public List<UninstallTrendDtlVO> getUninstallTrendDetail(GetUninstallTrendDetailDTO dto) {
-		// 参数校验
-		if (StrUtil.isBlank(dto.getStartDate()) ) {
-			throw new IllegalArgumentException("开始日期不能为空");
-		}
-		if (!"week".equals(dto.getTimeUnit()) && !"month".equals(dto.getTimeUnit())) {
-			throw new IllegalArgumentException("时间单位只能是week或month");
+    @Override
+    public UninstallTrendVO getUninstallTrend(GetUninstallTrendDTO dto) {
+		LocalDate startDate, endDate;
+		if (dto.getStartDate() == null) {
+			LocalDate now = LocalDate.now();
+			startDate = now.minusWeeks(1).with(DayOfWeek.MONDAY);
+			endDate = now.minusWeeks(1).with(DayOfWeek.SUNDAY);
+		} else {
+			startDate = LocalDate.parse(dto.getStartDate());
+			endDate = dto.getEndDate() != null ? LocalDate.parse(dto.getEndDate()) : startDate;
 		}
 
-		// 生成周/月时间点列表
-		List<String> timePoints = generateTimePoints(dto.getStartDate(), dto.getEndDate(), dto.getTimeUnit());
-		
-		// 生成周/月统计数据
-		List<UninstallTrendDtlVO> result = new ArrayList<>();
-		for (String timePoint : timePoints) {
-			UninstallTrendDtlVO vo = new UninstallTrendDtlVO();
-			vo.setStartDate(timePoint);
-			
-			// 根据时间单位生成对应的统计数据
-			if ("week".equals(dto.getTimeUnit())) {
-				vo.setUninstallCounts(generateRandomCount(100, 500)); // 周卸载量
-				vo.setRecallCounts(generateRandomCount(10, 100)); // 周召回量
-			} else {
-				vo.setUninstallCounts(generateRandomCount(500, 2000)); // 月卸载量
-				vo.setRecallCounts(generateRandomCount(50, 500)); // 月召回量
-			}
+        QueryWrapper<MktTrendSummary> wrapper = new QueryWrapper<>();
+        wrapper.between("stat_date", startDate, endDate);
+        List<MktTrendSummary> list = mktTrendSummaryMapper.selectList(wrapper);
+        UninstallTrendVO vo = new UninstallTrendVO();
+        if (!list.isEmpty()) {
+            // 这里只取第一个,实际可按业务聚合
+            MktTrendSummary summary = list.get(0);
+            vo.setStartDate(summary.getStatDate() != null ? summary.getStatDate().toString() : null);
+            vo.setUninstallCounts(summary.getCount());
+            vo.setUninstallRates(summary.getRate());
+            // 其他字段可根据VO结构补充
+        }
+        return vo;
+    }
 
-			result.add(vo);
-		}
-		
-		return result;
-	}
+    @Override
+    public Page<UninstallTrendDtlVO> getUninstallTrendDetail(GetUninstallTrendDetailDTO dto) {
+        // 假设dto有pageNum和pageSize字段
+        int pageNum = dto.getPageNum() == null ? 1 : dto.getPageNum();
+        int pageSize = dto.getPageSize() == null ? 10 : dto.getPageSize();
+        Page<MktTrendSummary> page = new Page<>(pageNum, pageSize);
+        QueryWrapper<MktTrendSummary> wrapper = new QueryWrapper<>();
+        wrapper.eq("stat_date", dto.getStartDate());
+        Page<MktTrendSummary> entityPage = mktTrendSummaryMapper.selectPage(page, wrapper);
+        Page<UninstallTrendDtlVO> voPage = new Page<>();
+        voPage.setCurrent(entityPage.getCurrent());
+        voPage.setSize(entityPage.getSize());
+        voPage.setTotal(entityPage.getTotal());
+        voPage.setPages(entityPage.getPages());
+        List<UninstallTrendDtlVO> voList = new ArrayList<>();
+        for (MktTrendSummary summary : entityPage.getRecords()) {
+            UninstallTrendDtlVO vo = new UninstallTrendDtlVO();
+            vo.setStartDate(summary.getStatDate() != null ? summary.getStatDate().toString() : null);
+            vo.setUninstallCounts(summary.getCount());
+            // 其他字段可根据VO结构补充
+            voList.add(vo);
+        }
+        voPage.setRecords(voList);
+        return voPage;
+    }
 
 	private int generateRandomCount(int min, int max) {
 		return new Random().nextInt(max - min + 1) + min;
@@ -124,17 +134,6 @@ public class UninstallAnalyseServiceImpl implements UninstallAnalyseService {
 		return timePoints;
 	}
 
-	/**
-	 * 生成随机数量列表
-	 */
-	private List<Integer> generateRandomCounts(int size, int min, int max) {
-		List<Integer> counts = new ArrayList<>();
-		for (int i = 0; i < size; i++) {
-			counts.add(min + random.nextInt(max - min));
-		}
-		return counts;
-	}
-
 	/**
 	 * 计算比率列表
 	 */
@@ -142,113 +141,235 @@ public class UninstallAnalyseServiceImpl implements UninstallAnalyseService {
 		return (double)numerators / denominator * 100;
 	}
 
-	/**
-	 * 计算比率列表(分子为列表)
-	 */
-	private List<Double> calculateRates(List<Integer> numerators, List<Integer> denominators) {
-		List<Double> rates = new ArrayList<>();
-		for (int i = 0; i < numerators.size(); i++) {
-			if (denominators.get(i) == 0) {
-				rates.add(0.0);
-			} else {
-				rates.add((double) numerators.get(i) / denominators.get(i) * 100);
-			}
+	@Override
+	public UninstallInsightVO getUninstallDeviceActive(GetUninstallInsightDTO dto) {
+		return getUninstallDeviceActiveVO(dto);
+	}
+
+	public UninstallInsightVO getUninstallDeviceActiveVO(GetUninstallInsightDTO dto) {
+		QueryWrapper<MktDeviceTime> wrapper = new QueryWrapper<>();
+		wrapper.eq("type", dto.getType());
+		List<MktDeviceTime> list = mktDeviceTimeMapper.selectList(wrapper);
+		List<InstallStockVO> voList = new ArrayList<>();
+		for (MktDeviceTime entity : list) {
+			InstallStockVO vo = new InstallStockVO();
+			ConfigItem configValue = ConfigUtils.getConfigValue("Time-range", entity.getTimeRange());
+			vo.setTime(configValue.getLabel());
+			vo.setUninstallCount(entity.getDeviceCount());
+			vo.setUninstallRate(entity.getRate());
+			voList.add(vo);
 		}
-		return rates;
+		UninstallInsightVO result = new UninstallInsightVO();
+		result.setLifecycleDistribution(voList);
+		return result;
 	}
 
 	@Override
-	public UninstallInsightVO getUninstallInsight(GetUninstallInsightDTO dto) {
-		/*UninstallInsightVO vo = new UninstallInsightVO();
-		
-		// 生成生命周期分布数据
-		vo.setLifecycleDistribution(Map.of(
-			"1-7天", random.nextInt(100),
-			"8-30天", random.nextInt(80),
-			"1-3个月", random.nextInt(60),
-			"3-6个月", random.nextInt(40),
-			"6个月以上", random.nextInt(20)
-		));
-		
-		// 生成使用热度数据
-		vo.setUsageHeatBeforeUninstall(Map.of(
-			"0-1次", random.nextDouble() * 50,
-			"1-3次", random.nextDouble() * 30,
-			"3-5次", random.nextDouble() * 20,
-			"5次以上", random.nextDouble() * 10
-		));
-		
-		// 生成崩溃统计数据
-		vo.setCrashStats(Map.of(
-			"0次", random.nextInt(100),
-			"1-3次", random.nextInt(80),
-			"3-5次", random.nextInt(50),
-			"5次以上", random.nextInt(20)
-		));
-		
-		// 根据请求参数生成可选特征数据
-		if (Boolean.TRUE.equals(dto.getIncludeDevice())) {
-			vo.setDeviceFeatures(Map.of(
-				"Android", random.nextDouble() * 70,
-				"iOS", random.nextDouble() * 30
-			));
+	public UninstallBeforeVO uninstallBefore(GetUninstallInsightDTO dto) {
+		// 1. 卸载时间差分布
+		QueryWrapper<MktDeviceTime> timeWrapper = new QueryWrapper<>();
+		timeWrapper.eq("type", dto.getType());
+		List<MktDeviceTime> timeList = mktDeviceTimeMapper.selectList(timeWrapper);
+		List<UninstallTimeDiffVO> timeDiffs = new ArrayList<>();
+		for (MktDeviceTime entity : timeList) {
+			UninstallTimeDiffVO vo = new UninstallTimeDiffVO();
+			ConfigItem configValue = ConfigUtils.getConfigValue("Time-range", entity.getTimeRange());
+			vo.setTime(configValue.getLabel());
+			vo.setCount(entity.getDeviceCount());
+			vo.setRate(entity.getRate());
+			timeDiffs.add(vo);
 		}
-		
-		if (Boolean.TRUE.equals(dto.getIncludeRegion())) {
-			vo.setRegionFeatures(Map.of(
-				"华东", random.nextDouble() * 40,
-				"华北", random.nextDouble() * 30,
-				"华南", random.nextDouble() * 20,
-				"其他", random.nextDouble() * 10
-			));
+		// 2. 卸载前7天使用次数分布
+		QueryWrapper<MktDeviceCount> countWrapper = new QueryWrapper<>();
+		countWrapper.eq("type", dto.getType());
+		List<MktDeviceCount> countList = mktDeviceCountMapper.selectList(countWrapper);
+		List<UninstallBeforeSevenVO> beforeSevens = new ArrayList<>();
+		for (MktDeviceCount entity : countList) {
+			UninstallBeforeSevenVO vo = new UninstallBeforeSevenVO();
+			ConfigItem configValue = ConfigUtils.getConfigValue("Count_range", entity.getCountRange());
+
+			vo.setTime(configValue.getLabel());
+			vo.setCount(entity.getNum());
+			vo.setRate(entity.getRate());
+			beforeSevens.add(vo);
 		}
-		
-		if (Boolean.TRUE.equals(dto.getIncludeBehavior())) {
-			vo.setLastBehaviorFeatures(Map.of(
-				"浏览", random.nextDouble() * 50,
-				"搜索", random.nextDouble() * 30,
-				"购买", random.nextDouble() * 20
-			));
+		// 3. 卸载前干扰指标
+		QueryWrapper<MktDeviceInterfere> interfereWrapper = new QueryWrapper<>();
+		List<MktDeviceInterfere> interfereList = mktDeviceInterfereMapper.selectList(interfereWrapper);
+		Map<String, Map<String, Integer>> interfereMap = new LinkedHashMap<>();
+		for (MktDeviceInterfere entity : interfereList) {
+			ConfigItem configValue = ConfigUtils.getConfigValue("Count_range", entity.getCountRange());
+			interfereMap.computeIfAbsent(entity.getInterfereType(), k -> new LinkedHashMap<>())
+				.put(configValue.getLabel(), entity.getNum());
 		}
-		
-		return vo;*/
-		return null;
+		List<UninstallBeforeInterfereVO> interfereVOList = new ArrayList<>();
+		for (Map.Entry<String, Map<String, Integer>> entry : interfereMap.entrySet()) {
+			UninstallBeforeInterfereVO vo = new UninstallBeforeInterfereVO();
+			vo.setType(entry.getKey());
+			vo.setValue(entry.getValue());
+			interfereVOList.add(vo);
+		}
+		// 4. 卸载前行为还原
+		QueryWrapper<MktDeviceAction> actionWrapper = new QueryWrapper<>();
+		List<MktDeviceAction> actionList = mktDeviceActionMapper.selectList(actionWrapper);
+		Map<String, Map<String, Integer>> actionMap = new LinkedHashMap<>();
+		for (MktDeviceAction entity : actionList) {
+			actionMap.computeIfAbsent(entity.getActionType(), k -> new LinkedHashMap<>())
+				.put(entity.getActionValue(), entity.getTriggerCount());
+		}
+		List<UninstallBeforeActionVO> actionVOList = new ArrayList<>();
+		for (Map.Entry<String, Map<String, Integer>> entry : actionMap.entrySet()) {
+			UninstallBeforeActionVO vo = new UninstallBeforeActionVO();
+			vo.setActionType(entry.getKey());
+			vo.setValue(entry.getValue());
+			actionVOList.add(vo);
+		}
+		UninstallBeforeVO result = new UninstallBeforeVO();
+		result.setUninstallTimeDiffs(timeDiffs);
+		result.setUninstallBeforeSevens(beforeSevens);
+		result.setUninstallBeforeInterferences(interfereVOList);
+		result.setUninstallBeforeActions(actionVOList);
+		return result;
 	}
 
 	@Override
-	public UninstallCompetitorVO getUninstallCompetitor(GetUninstallTrendDTO dto) {
-		UninstallCompetitorVO vo = new UninstallCompetitorVO();
-		
-		// 生成竞品类型列表
-		List<String> competitorTypes = List.of("竞品A", "竞品B", "竞品C", "竞品D");
-		vo.setCompetitorTypes(competitorTypes);
-		
-		// 生成流向各竞品的用户数量
-		Map<String, Integer> competitorCounts = Map.of(
-			"竞品A", random.nextInt(200),
-			"竞品B", random.nextInt(150),
-			"竞品C", random.nextInt(100),
-			"竞品D", random.nextInt(50)
-		);
-		vo.setCompetitorUserCounts(competitorCounts);
-		
-		// 计算总用户数(包括未知去向)
-		int total = competitorCounts.values().stream().mapToInt(Integer::intValue).sum() + random.nextInt(100);
-		
-		// 计算各竞品占比
-		Map<String, Double> competitorPercentages = Map.of(
-			"竞品A", (double) competitorCounts.get("竞品A") / total * 100,
-			"竞品B", (double) competitorCounts.get("竞品B") / total * 100,
-			"竞品C", (double) competitorCounts.get("竞品C") / total * 100,
-			"竞品D", (double) competitorCounts.get("竞品D") / total * 100
-		);
-		vo.setCompetitorUserPercentages(competitorPercentages);
-		
-		// 设置未知去向数据
-		int unknownCount = total - competitorCounts.values().stream().mapToInt(Integer::intValue).sum();
-		vo.setUnknownCount(unknownCount);
-		vo.setUnknownPercentage((double) unknownCount / total * 100);
-		
+	public List<UninstallOfterAPPOV> uninstallAfter(GetUninstallInsightDTO dto) {
+		// 这里只做演示,实际可查mkt_device_time或相关表
+		QueryWrapper<MktDeviceTime> wrapper = new QueryWrapper<>();
+		wrapper.eq("type", "after");
+		List<MktDeviceTime> list = mktDeviceTimeMapper.selectList(wrapper);
+		List<UninstallOfterAPPOV> result = new ArrayList<>();
+		for (MktDeviceTime entity : list) {
+			UninstallOfterAPPOV vo = new UninstallOfterAPPOV();
+			vo.setAppName(entity.getTimeRange()); // 假设timeRange存appName
+			vo.setCount(entity.getDeviceCount());
+			vo.setProportion(entity.getRate() != null ? entity.getRate().toString() : null);
+			result.add(vo);
+		}
+		return result;
+	}
+
+	@Override
+	public List<UninstallSYSOV> uninstallSys(GetUninstallInsightDTO dto) {
+		QueryWrapper<MktDeviceTime> wrapper = new QueryWrapper<>();
+		wrapper.eq("type", "sys");
+		List<MktDeviceTime> list = mktDeviceTimeMapper.selectList(wrapper);
+		Map<String, List<Map<String, Integer>>> sysMap = new LinkedHashMap<>();
+		for (MktDeviceTime entity : list) {
+			sysMap.computeIfAbsent(entity.getTimeRange(), k -> new ArrayList<>())
+				.add(Collections.singletonMap(entity.getAppVersion(), entity.getDeviceCount()));
+		}
+		List<UninstallSYSOV> result = new ArrayList<>();
+		for (Map.Entry<String, List<Map<String, Integer>>> entry : sysMap.entrySet()) {
+			UninstallSYSOV vo = new UninstallSYSOV();
+			vo.setDimensionName(entry.getKey());
+			vo.setDistribution(entry.getValue());
+			result.add(vo);
+		}
+		return result;
+	}
+
+	@Override
+	public UninstallPortraitOV getUninstallPortrait(UninstallPortraitDTO dto) {
+		UninstallPortraitOV vo = new UninstallPortraitOV();
+		// 1. 卸载数量
+		UninstallPortraitSumOV sum = new UninstallPortraitSumOV();
+		sum.setTimeUnit(dto.getTimeUnit() == null ? "week" : dto.getTimeUnit());
+		sum.setCount(1000 + random.nextInt(1000));
+		vo.setUninstallCount(sum);
+		// 2. 用户特征情况
+		List<UninstallPortraitCharacterVO> charList = new ArrayList<>();
+		String[] easyNames = {"专科", "便捷生活_智能生活", "社交通讯_同城本地社区", "影音娱乐_乐器", "教育_考公务员"};
+		String[] hardNames = {"25-29岁", "三线城市", "普通消费", "商务办公_CRM营销工具", "影音娱乐_在线音乐"};
+		for (String name : easyNames) {
+			UninstallPortraitCharacterVO c = new UninstallPortraitCharacterVO();
+			c.setName(name);
+			c.setTgi(String.valueOf(80 + random.nextInt(40)));
+			c.setPercent(String.valueOf(10 + random.nextInt(20)));
+			c.setStatus(0);
+			charList.add(c);
+		}
+		for (String name : hardNames) {
+			UninstallPortraitCharacterVO c = new UninstallPortraitCharacterVO();
+			c.setName(name);
+			c.setTgi(String.valueOf(80 + random.nextInt(40)));
+			c.setPercent(String.valueOf(10 + random.nextInt(20)));
+			c.setStatus(1);
+			charList.add(c);
+		}
+		vo.setUninstallPortraitCharactList(charList);
+		// 3. 卸载阶段
+		String[] phases = {"未使用", "使用1次", "使用2次", "使用3次", "使用4次", "使用5次", "6次以上"};
+		List<UninstallPortraitPhaseVO> phaseList = new ArrayList<>();
+		int total = 1000 + random.nextInt(1000);
+		double percentSum = 0;
+		int countSum = 0;
+		double[] raw = new double[phases.length];
+		double sumPhase = 0;
+		for (int i = 0; i < phases.length; i++) {
+			raw[i] = 10 + random.nextDouble() * 90;
+			sumPhase += raw[i];
+		}
+		for (int i = 0; i < phases.length; i++) {
+			UninstallPortraitPhaseVO p = new UninstallPortraitPhaseVO();
+			p.setPhase(phases[i]);
+			if (i < phases.length - 1) {
+				p.setRate(Math.round(raw[i] / sumPhase * 10000.0) / 100.0);
+				percentSum += p.getRate();
+				p.setCount((int)Math.round(p.getRate() / 100 * total));
+				countSum += p.getCount();
+			} else {
+				p.setRate(Math.round((100.0 - percentSum) * 100.0) / 100.0);
+				p.setCount(total - countSum);
+			}
+			phaseList.add(p);
+		}
+		vo.setUninstallPortraitPhaseList(phaseList);
+		return vo;
+	}
+
+	@Override
+	public UninstallPredictVO getUninstallPredict(UninstallPredictDTO dto) {
+		UninstallPredictVO vo = new UninstallPredictVO();
+		// 预测时间为一周最后一天
+		LocalDate start = LocalDate.now();
+		LocalDate predictTime = start.plusDays(6);
+		vo.setPredictTime(predictTime.toString());
+		vo.setUninstallCount(100 + random.nextInt(200));
+		vo.setRecallCount(10 + random.nextInt(50));
 		return vo;
 	}
+
+	@Override
+	public List<InstallUninstallRatioVO> getInstallUninstallRatio(InstallUninstallRatioDTO dto) {
+		List<InstallUninstallRatioVO> list = new ArrayList<>();
+		String[] types = {"当前应用", "移动视频", "医疗服务"};
+		LocalDate start = LocalDate.now();
+		for (String type : types) {
+			InstallUninstallRatioVO vo = new InstallUninstallRatioVO();
+			vo.setDate(java.sql.Date.valueOf(start));
+			vo.setType(type);
+			vo.setRate(Math.round((10 + random.nextDouble() * 90) * 100.0) / 100.0);
+			list.add(vo);
+		}
+		return list;
+	}
+
+	@Override
+	public List<InstallUninstallRatioVO> getInstallUninstallRatioDetail(InstallUninstallRatioDTO dto) {
+		List<InstallUninstallRatioVO> list = new ArrayList<>();
+		String[] types = {"当前应用", "移动视频", "医疗服务"};
+		LocalDate start = LocalDate.now();
+		for (int i = 0; i < 7; i++) {
+			LocalDate date = start.plusDays(i);
+			for (String type : types) {
+				InstallUninstallRatioVO vo = new InstallUninstallRatioVO();
+				vo.setDate(java.sql.Date.valueOf(date));
+				vo.setType(type);
+				vo.setRate(Math.round((10 + random.nextDouble() * 90) * 100.0) / 100.0);
+				list.add(vo);
+			}
+		}
+		return list;
+	}
 }