wangcl 3 settimane fa
parent
commit
d2bff6d269
19 ha cambiato i file con 674 aggiunte e 244 eliminazioni
  1. 22 0
      pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/dto/uninstall/InstallUninstallRatioDTO.java
  2. 12 0
      pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/dto/uninstall/UninstallPortraitDTO.java
  3. 17 2
      pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/dto/uninstall/UninstallPredictDTO.java
  4. 4 2
      pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktDeviceAction.java
  5. 4 2
      pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktDeviceCount.java
  6. 5 2
      pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktDeviceInterfere.java
  7. 4 2
      pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktDeviceTime.java
  8. 45 0
      pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktInstallUninstallRatio.java
  9. 55 0
      pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktPortrait.java
  10. 47 0
      pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktPredict.java
  11. 4 4
      pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktTrendSummary.java
  12. 6 5
      pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/vo/uninstall/InstallUninstallRatioVO.java
  13. 5 0
      pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/Util/ConfigUtils.java
  14. 2 2
      pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/controller/UninstallAnalyseController.java
  15. 14 0
      pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/mapper/MktInstallUninstallRatioMapper.java
  16. 14 0
      pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/mapper/MktPortraitMapper.java
  17. 14 0
      pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/mapper/MktPredictMapper.java
  18. 2 2
      pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/service/UninstallAnalyseService.java
  19. 398 221
      pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/service/impl/UninstallAnalyseServiceImpl.java

+ 22 - 0
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/dto/uninstall/InstallUninstallRatioDTO.java

@@ -15,4 +15,26 @@ public class InstallUninstallRatioDTO {
 
 	@Schema(description = "周期(周/月)")
 	private String cycle;
+	
+	@Schema(description = "应用ID")
+	private String appId;
+	
+	@Schema(description = "渠道")
+	private String channel;
+	
+	@Schema(description = "应用版本")
+	private String version;
+	
+	@Schema(description = "开始日期(明细接口不传)")
+	private String startDate;
+
+	@Schema(description = "结束日期(明细接口不传)")
+	private String endDate;
+	
+	@Schema(description = "页码")
+	private Integer pageNum;
+	
+	@Schema(description = "每页大小")
+	private Integer pageSize;
+
 }

+ 12 - 0
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/dto/uninstall/UninstallPortraitDTO.java

@@ -16,6 +16,18 @@ public class UninstallPortraitDTO {
 	@Schema(description = "开始时间(yyyy-MM-dd),不传则默认为当周第一天")
 	private String startDate;
 
+	@Schema(description = "结束时间(yyyy-MM-dd),不传则默认为当周最后一天")
+	private String endDate;
+
 	@Schema(description = "时间单位(week/month),不传则默认为week")
 	private String timeUnit;
+
+	@Schema(description = "appId")
+	private String appId;
+
+	@Schema(description = "渠道")
+	private String channel;
+
+	@Schema(description = "版本")
+	private String version;
 }

+ 17 - 2
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/dto/uninstall/UninstallPredictDTO.java

@@ -16,6 +16,21 @@ public class UninstallPredictDTO {
 	@Schema(description = "周期(周/月)")
 	private String cycle;
 
-	@Schema(description = "类型(卸载流失设备/召回设备(预测))")
-	private String type;
+	@Schema(description = "类型(0-卸载流失设备, 1-召回设备(预测))")
+	private Integer type;
+	
+	@Schema(description = "应用ID")
+	private String appId;
+	
+	@Schema(description = "渠道")
+	private String channel;
+	
+	@Schema(description = "应用版本")
+	private String version;
+	
+	@Schema(description = "开始日期")
+	private String startDate;
+	
+	@Schema(description = "结束日期")
+	private String endDate;
 }

+ 4 - 2
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktDeviceAction.java

@@ -25,6 +25,8 @@ public class MktDeviceAction {
     private Integer triggerCount; // 触发次数
     private String ext1;
     private String ext2;
-    private Date createdAt;
-    private Date updatedAt;
+	private Date createTime;
+	private Date updateTime;
+	private String createBy;
+	private String updateBy;
 }

+ 4 - 2
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktDeviceCount.java

@@ -26,6 +26,8 @@ public class MktDeviceCount {
     private Double rate; // 占比(%)
     private String ext1;
     private String ext2;
-    private Date createdAt;
-    private Date updatedAt;
+	private Date createTime;
+	private Date updateTime;
+	private String createBy;
+	private String updateBy;
 }

+ 5 - 2
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktDeviceInterfere.java

@@ -25,6 +25,9 @@ public class MktDeviceInterfere {
     private Integer num; // 次数
     private String ext1;
     private String ext2;
-    private Date createdAt;
-    private Date updatedAt;
+    private Date createTime;
+    private Date updateTime;
+	private String createBy;
+	private String updateBy;
+
 }

+ 4 - 2
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktDeviceTime.java

@@ -26,6 +26,8 @@ public class MktDeviceTime {
     private Double rate; // 占比(%)
     private String ext1;
     private String ext2;
-    private Date createdAt;
-    private Date updatedAt;
+	private Date createTime;
+	private Date updateTime;
+	private String createBy;
+	private String updateBy;
 }

+ 45 - 0
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktInstallUninstallRatio.java

@@ -0,0 +1,45 @@
+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/20 16:00
+ * @description: 安装卸载比统计表实体
+ */
+@Data
+@TableName("install_uninstall_ratio")
+public class MktInstallUninstallRatio {
+    /** 主键 */
+    @TableId
+    private Long id;
+    /** 统计日期 */
+    private Date statDate;
+    /** 统计周期(week、month) */
+    private String statCycle;
+    /** 应用ID */
+    private String appId;
+    /** 渠道 */
+    private String channel;
+    /** 应用版本 */
+    private String appVersion;
+    /** 行业类型(当前应用、移动视频、医疗服务等) */
+    private Integer industryType;
+    /** 安装卸载比占比 */
+    private Double rate;
+    /** 扩展字段1 */
+    private String ext1;
+    /** 扩展字段2 */
+    private String ext2;
+    /** 创建者 */
+    private String createBy;
+    /** 创建时间 */
+    private Date createTime;
+    /** 更新时间 */
+    private Date updateTime;
+    /** 更新者 */
+    private String updateBy;
+}

+ 55 - 0
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktPortrait.java

@@ -0,0 +1,55 @@
+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/20 15:30
+ * @description: 卸载画像统计表实体
+ */
+@Data
+@TableName("uninstall_portrait")
+public class MktPortrait {
+    /** 主键 */
+    @TableId
+    private Long id;
+    /** 统计日期 */
+    private Date statDate;
+    /** 统计周期(week、month) */
+    private String statCycle;
+    /** 应用ID */
+    private String appId;
+    /** 渠道 */
+    private String channel;
+    /** 应用版本 */
+    private String appVersion;
+    /** 特征名称 */
+    private String featureName;
+    /** TGI */
+    private String tgi;
+    /** 百分比 */
+    private String percent;
+    /** 0-易卸载特征 1-不易卸载特征 */
+    private Integer status;
+    /** 卸载阶段 */
+    private String phase;
+    /** 阶段数量 */
+    private Integer phaseCount;
+    /** 阶段占比 */
+    private Double phaseRate;
+    /** 扩展字段1 */
+    private String ext1;
+    /** 扩展字段2 */
+    private String ext2;
+    /** 创建者 */
+    private String createBy;
+    /** 创建时间 */
+    private Date createTime;
+    /** 更新时间 */
+    private Date updateTime;
+    /** 更新者 */
+    private String updateBy;
+}

+ 47 - 0
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/entity/uninstall/MktPredict.java

@@ -0,0 +1,47 @@
+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/20 16:30
+ * @description: 卸载预测统计表实体
+ */
+@Data
+@TableName("uninstall_predict")
+public class MktPredict {
+    /** 主键 */
+    @TableId
+    private Long id;
+    /** 预测统计日期 */
+    private Date statDate;
+    /** 统计周期(week、month) */
+    private String statCycle;
+    /** 应用ID */
+    private String appId;
+    /** 渠道 */
+    private String channel;
+    /** 应用版本 */
+    private String appVersion;
+    /** 预测时间 */
+    private Date predictTime;
+    /** 0-卸载流失设备 1-召回设备(预测) */
+    private Integer type;
+    /** 预测卸载数量 */
+    private Integer uninstallCount;
+    /** 扩展字段1 */
+    private String ext1;
+    /** 扩展字段2 */
+    private String ext2;
+    /** 创建者 */
+    private String createBy;
+    /** 创建时间 */
+    private Date createTime;
+    /** 更新时间 */
+    private Date updateTime;
+    /** 更新者 */
+    private String updateBy;
+}

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

@@ -36,8 +36,8 @@ public class MktTrendSummary {
     private String ext1;
     /** 扩展字段2 */
     private String ext2;
-    /** 创建时间 */
-    private Date createdAt;
-    /** 更新时间 */
-    private Date updatedAt;
+	private Date createTime;
+	private Date updateTime;
+	private String createBy;
+	private String updateBy;
 }

+ 6 - 5
pig-statistics/pig-statistics-api/src/main/java/com/pig4cloud/pig/statistics/api/vo/uninstall/InstallUninstallRatioVO.java

@@ -4,7 +4,9 @@ package com.pig4cloud.pig.statistics.api.vo.uninstall;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
-import java.sql.Date;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
 
 /**
  * @author wcl
@@ -18,9 +20,8 @@ public class InstallUninstallRatioVO {
 	@Schema(description = "时间格式 yyyy-MM-dd")
 	private Date date;
 
-	@Schema(description = "行业")
-	private String type;
+	@Schema(description = "行业-占比")
+	private List<Map<String, Double>> type;
+
 
-	@Schema(description = "占比")
-	private Double rate;
 }

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

@@ -3,6 +3,7 @@ package com.pig4cloud.pig.statistics.Util;
 
 import com.pig4cloud.pig.statistics.api.entity.ConfigItem;
 import com.pig4cloud.pig.statistics.mapper.SysConfigMapper;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Component;
@@ -16,6 +17,7 @@ import java.util.concurrent.TimeUnit;
  * @description: 配置缓存工具类
  */
 @Component
+@Slf4j
 public class ConfigUtils {
 
 	private static SysConfigMapper sysConfigMapper;
@@ -40,7 +42,10 @@ public class ConfigUtils {
 			return cached;
 		}
 		List<ConfigItem> list = sysConfigMapper.selectByConfigKey(configKey);
+		// 日志
+		log.info("---存入redis~~~~~~");
 		redisTemplate.opsForValue().set(cacheKey, list, 1, TimeUnit.HOURS);
+		log.info("---已存redis~~~~~~");
 		return list;
 	}
 

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

@@ -85,7 +85,7 @@ public class UninstallAnalyseController {
 
 	@PostMapping("/predict")
 	@Operation(summary = "卸载归因-卸载预测")
-	public R<UninstallPredictVO> getUninstallPredict(@RequestBody UninstallPredictDTO dto) {
+	public R<List<UninstallPredictVO>> getUninstallPredict(@RequestBody UninstallPredictDTO dto) {
 		return R.ok(uninstallAnalyseService.getUninstallPredict(dto));
 	}
 
@@ -97,7 +97,7 @@ public class UninstallAnalyseController {
 
 	@PostMapping("/predict/detailList")
 	@Operation(summary = "卸载归因-安装卸载比明细")
-	public R<List<InstallUninstallRatioVO>> getInstallUninstallRatioDetail(@RequestBody InstallUninstallRatioDTO dto) {
+	public R<Page<InstallUninstallRatioVO>> getInstallUninstallRatioDetail(@RequestBody InstallUninstallRatioDTO dto) {
 		return R.ok(uninstallAnalyseService.getInstallUninstallRatioDetail(dto));
 	}
 

+ 14 - 0
pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/mapper/MktInstallUninstallRatioMapper.java

@@ -0,0 +1,14 @@
+package com.pig4cloud.pig.statistics.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.pig4cloud.pig.statistics.api.entity.uninstall.MktInstallUninstallRatio;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * @author wcl
+ * @date 2025/8/20 16:00
+ * @description: 安装卸载比统计表Mapper
+ */
+@Mapper
+public interface MktInstallUninstallRatioMapper extends BaseMapper<MktInstallUninstallRatio> {
+}

+ 14 - 0
pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/mapper/MktPortraitMapper.java

@@ -0,0 +1,14 @@
+package com.pig4cloud.pig.statistics.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.pig4cloud.pig.statistics.api.entity.uninstall.MktPortrait;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * @author wcl
+ * @date 2025/8/20 15:30
+ * @description: 卸载画像统计表Mapper
+ */
+@Mapper
+public interface MktPortraitMapper extends BaseMapper<MktPortrait> {
+}

+ 14 - 0
pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/mapper/MktPredictMapper.java

@@ -0,0 +1,14 @@
+package com.pig4cloud.pig.statistics.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.pig4cloud.pig.statistics.api.entity.uninstall.MktPredict;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * @author wcl
+ * @date 2025/8/20 16:30
+ * @description: 卸载预测统计表Mapper
+ */
+@Mapper
+public interface MktPredictMapper extends BaseMapper<MktPredict> {
+}

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

@@ -67,7 +67,7 @@ public interface UninstallAnalyseService {
 	/**
 	 * 卸载归因-卸载预测
 	 */
-	UninstallPredictVO getUninstallPredict(UninstallPredictDTO dto);
+	List<UninstallPredictVO> getUninstallPredict(UninstallPredictDTO dto);
 
 	/**
 	 * 安装卸载比
@@ -77,5 +77,5 @@ public interface UninstallAnalyseService {
 	/**
 	 * 安装卸载比明细
 	 */
-	List<InstallUninstallRatioVO> getInstallUninstallRatioDetail(InstallUninstallRatioDTO dto);
+	Page<InstallUninstallRatioVO> getInstallUninstallRatioDetail(InstallUninstallRatioDTO dto);
 }

+ 398 - 221
pig-statistics/pig-statistics-biz/src/main/java/com/pig4cloud/pig/statistics/service/impl/UninstallAnalyseServiceImpl.java

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