|
@@ -1,20 +1,35 @@
|
|
|
package com.pig4cloud.pig.statistics.controller;
|
|
|
|
|
|
|
|
|
+import cn.idev.excel.EasyExcel;
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
+import com.pig4cloud.pig.common.core.exception.BusinessException;
|
|
|
import com.pig4cloud.pig.common.core.util.R;
|
|
|
import com.pig4cloud.pig.statistics.api.dto.user.*;
|
|
|
import com.pig4cloud.pig.statistics.api.vo.user.*;
|
|
|
import com.pig4cloud.pig.statistics.service.UserAnalyseService;
|
|
|
+import com.pig4cloud.plugin.excel.annotation.ResponseExcel;
|
|
|
+import com.pig4cloud.plugin.excel.annotation.Sheet;
|
|
|
import io.swagger.v3.oas.annotations.Operation;
|
|
|
+import io.swagger.v3.oas.annotations.media.Schema;
|
|
|
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
|
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
|
+import jakarta.servlet.http.HttpServletResponse;
|
|
|
import jakarta.validation.Valid;
|
|
|
import lombok.AllArgsConstructor;
|
|
|
+import org.springdoc.core.annotations.ParameterObject;
|
|
|
+import org.springframework.beans.BeanUtils;
|
|
|
import org.springframework.http.HttpHeaders;
|
|
|
+import org.springframework.util.CollectionUtils;
|
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
|
|
|
+import java.io.OutputStream;
|
|
|
+import java.net.URLEncoder;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Collections;
|
|
|
import java.util.List;
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -47,10 +62,39 @@ public class UserAnalyseController {
|
|
|
return R.ok(result);
|
|
|
}
|
|
|
|
|
|
- @GetMapping("/new/trend/export")
|
|
|
- @Operation(summary = "导出新增趋势")
|
|
|
- public R exportNewUserTrend() {
|
|
|
- return R.ok();
|
|
|
+ @ResponseExcel(name = "新增趋势详情")
|
|
|
+ @PostMapping("/new/trend/export")
|
|
|
+ @Operation(summary = "导出新增趋势详情")
|
|
|
+ public List<PageNewUserTrendDetailVO> exportNewUserTrend(@Valid @RequestBody UserAnalyseQueryBaseDTO reqDto) {
|
|
|
+ // 初始化结果集
|
|
|
+ List<PageNewUserTrendDetailVO> allRecords = new ArrayList<>();
|
|
|
+ // 分页查询参数
|
|
|
+ PageUserAnalyseDTO pageQuery = new PageUserAnalyseDTO();
|
|
|
+ BeanUtils.copyProperties(reqDto, pageQuery);
|
|
|
+ // 每次查询的批次大小,根据实际内存情况调整
|
|
|
+ long batchSize = 1000;
|
|
|
+ pageQuery.setSize(batchSize);
|
|
|
+ pageQuery.setCurrent(1);
|
|
|
+
|
|
|
+ while (true) {
|
|
|
+ // 分批查询数据
|
|
|
+ Page<PageNewUserTrendDetailVO> pageResult = userAnalyseService.pageNewUserTrendDetail(pageQuery);
|
|
|
+ List<PageNewUserTrendDetailVO> records = pageResult.getRecords();
|
|
|
+ if (CollectionUtils.isEmpty(records)) {
|
|
|
+ // 没有更多数据,退出循环
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ // 添加到结果集
|
|
|
+ allRecords.addAll(records);
|
|
|
+ // 如果当前页记录数小于批次大小,说明是最后一页
|
|
|
+ if (records.size() < batchSize) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ // 准备查询下一页
|
|
|
+ pageQuery.setCurrent(pageQuery.getCurrent() + 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ return allRecords;
|
|
|
}
|
|
|
|
|
|
@PostMapping("/new/retention")
|
|
@@ -66,10 +110,39 @@ public class UserAnalyseController {
|
|
|
return R.ok(result);
|
|
|
}
|
|
|
|
|
|
- @GetMapping("/new/retention/export")
|
|
|
- @Operation(summary = "导出次日留存率")
|
|
|
- public R exportNewUserRetention() {
|
|
|
- return R.ok();
|
|
|
+ @ResponseExcel(name = "次日留存率详情")
|
|
|
+ @PostMapping("/new/retention/export")
|
|
|
+ @Operation(summary = "导出次日留存率详情")
|
|
|
+ public List<PageRetentionDetailVO> exportNewUserRetention(@Valid @RequestBody UserAnalyseQueryBaseDTO reqDto) {
|
|
|
+ // 初始化结果集
|
|
|
+ List<PageRetentionDetailVO> allRecords = new ArrayList<>();
|
|
|
+ // 分页查询参数
|
|
|
+ PageUserAnalyseDTO pageQuery = new PageUserAnalyseDTO();
|
|
|
+ BeanUtils.copyProperties(reqDto, pageQuery);
|
|
|
+ // 每次查询的批次大小,根据实际内存情况调整
|
|
|
+ long batchSize = 1000;
|
|
|
+ pageQuery.setSize(batchSize);
|
|
|
+ pageQuery.setCurrent(1);
|
|
|
+
|
|
|
+ while (true) {
|
|
|
+ // 分批查询数据
|
|
|
+ Page<PageRetentionDetailVO> pageResult = userAnalyseService.pageNewUserRetentionDetail(pageQuery);
|
|
|
+ List<PageRetentionDetailVO> records = pageResult.getRecords();
|
|
|
+ if (CollectionUtils.isEmpty(records)) {
|
|
|
+ // 没有更多数据,退出循环
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ // 添加到结果集
|
|
|
+ allRecords.addAll(records);
|
|
|
+ // 如果当前页记录数小于批次大小,说明是最后一页
|
|
|
+ if (records.size() < batchSize) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ // 准备查询下一页
|
|
|
+ pageQuery.setCurrent(pageQuery.getCurrent() + 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ return allRecords;
|
|
|
}
|
|
|
|
|
|
/***************************************** 活跃用户 *****************************************/
|
|
@@ -116,10 +189,64 @@ public class UserAnalyseController {
|
|
|
return R.ok(result);
|
|
|
}
|
|
|
|
|
|
- @GetMapping("/active/export")
|
|
|
+ @PostMapping("/active/export")
|
|
|
@Operation(summary = "导出活跃详情")
|
|
|
- public R exportActiveDetail() {
|
|
|
- return R.ok();
|
|
|
+ public void exportActiveDetail(@Valid @RequestBody UserAnalyseQueryBaseDTO reqDto, HttpServletResponse response) throws Exception {
|
|
|
+ // 1. 根据时间单位确定需要排除的字段
|
|
|
+ List<String> excludeFields = new ArrayList<>();
|
|
|
+ String timeUnit = reqDto.getTimeUnit();
|
|
|
+ switch (timeUnit) {
|
|
|
+ case "day":
|
|
|
+ excludeFields.add("monthActiveUserRate");
|
|
|
+ excludeFields.add("weekActiveUserRate");
|
|
|
+ break;
|
|
|
+ case "week":
|
|
|
+ excludeFields.add("monthActiveUserRate");
|
|
|
+ excludeFields.add("mauRate");
|
|
|
+ excludeFields.add("wauRate");
|
|
|
+ break;
|
|
|
+ case "month":
|
|
|
+ excludeFields.add("weekActiveUserRate");
|
|
|
+ excludeFields.add("mauRate");
|
|
|
+ excludeFields.add("wauRate");
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ // 可根据需要处理默认情况
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 分页查询数据(保持原有逻辑)
|
|
|
+ List<PageActiveDetailVO> allRecords = new ArrayList<>();
|
|
|
+ PageUserAnalyseDTO pageQuery = new PageUserAnalyseDTO();
|
|
|
+ BeanUtils.copyProperties(reqDto, pageQuery);
|
|
|
+ long batchSize = 1000;
|
|
|
+ pageQuery.setSize(batchSize);
|
|
|
+ pageQuery.setCurrent(1);
|
|
|
+
|
|
|
+ while (true) {
|
|
|
+ Page<PageActiveDetailVO> pageResult = userAnalyseService.pageActiveDetail(pageQuery);
|
|
|
+ List<PageActiveDetailVO> records = pageResult.getRecords();
|
|
|
+ if (CollectionUtils.isEmpty(records)) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ allRecords.addAll(records);
|
|
|
+ if (records.size() < batchSize) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ pageQuery.setCurrent(pageQuery.getCurrent() + 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 动态设置Excel响应和导出字段
|
|
|
+ response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
|
|
+ response.setCharacterEncoding("utf-8");
|
|
|
+ String fileName = URLEncoder.encode("活跃详情", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
|
|
|
+ response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
|
|
|
+
|
|
|
+ // 使用EasyExcel编程式导出,指定排除字段
|
|
|
+ EasyExcel.write(response.getOutputStream(), PageActiveDetailVO.class)
|
|
|
+ .excludeColumnFiledNames(excludeFields)
|
|
|
+ .sheet("活跃详情")
|
|
|
+ .doWrite(allRecords);
|
|
|
}
|
|
|
|
|
|
/***************************************** 启动次数 *****************************************/
|
|
@@ -137,10 +264,39 @@ public class UserAnalyseController {
|
|
|
return R.ok(result);
|
|
|
}
|
|
|
|
|
|
- @GetMapping("/launch/export")
|
|
|
+ @ResponseExcel(name = "启动次数详情")
|
|
|
+ @PostMapping("/launch/export")
|
|
|
@Operation(summary = "导出启动次数详情")
|
|
|
- public R exportLaunchDetail() {
|
|
|
- return R.ok();
|
|
|
+ public List<PageLaunchDetailVO> exportLaunchDetail(@Valid @RequestBody UserAnalyseQueryBaseDTO reqDto) {
|
|
|
+ // 初始化结果集
|
|
|
+ List<PageLaunchDetailVO> allRecords = new ArrayList<>();
|
|
|
+ // 分页查询参数
|
|
|
+ PageUserAnalyseDTO pageQuery = new PageUserAnalyseDTO();
|
|
|
+ BeanUtils.copyProperties(reqDto, pageQuery);
|
|
|
+ // 每次查询的批次大小,根据实际内存情况调整
|
|
|
+ long batchSize = 1000;
|
|
|
+ pageQuery.setSize(batchSize);
|
|
|
+ pageQuery.setCurrent(1);
|
|
|
+
|
|
|
+ while (true) {
|
|
|
+ // 分批查询数据
|
|
|
+ Page<PageLaunchDetailVO> pageResult = userAnalyseService.pageLaunchDetail(pageQuery);
|
|
|
+ List<PageLaunchDetailVO> records = pageResult.getRecords();
|
|
|
+ if (CollectionUtils.isEmpty(records)) {
|
|
|
+ // 没有更多数据,退出循环
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ // 添加到结果集
|
|
|
+ allRecords.addAll(records);
|
|
|
+ // 如果当前页记录数小于批次大小,说明是最后一页
|
|
|
+ if (records.size() < batchSize) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ // 准备查询下一页
|
|
|
+ pageQuery.setCurrent(pageQuery.getCurrent() + 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ return allRecords;
|
|
|
}
|
|
|
|
|
|
/***************************************** 版本分布 *****************************************/
|
|
@@ -152,10 +308,53 @@ public class UserAnalyseController {
|
|
|
return R.ok(result);
|
|
|
}
|
|
|
|
|
|
+ @ResponseExcel(name = "全部版本详情", sheets = {
|
|
|
+ @Sheet(sheetName = "今日"),
|
|
|
+ @Sheet(sheetName = "昨日")
|
|
|
+ })
|
|
|
@GetMapping("/version/export")
|
|
|
@Operation(summary = "导出全部版本详情")
|
|
|
- public R exportAllVersionDetail() {
|
|
|
- return R.ok();
|
|
|
+ public List<List<PageAllVersionDetailVO>> exportAllVersionDetail(
|
|
|
+ @Schema(description = "应用ID",example = "Fqs2CL9CUn7U1AqilSFXgb")
|
|
|
+ @ParameterObject String appId) {
|
|
|
+ if (appId == null || appId.isEmpty()){
|
|
|
+ throw new BusinessException("appId不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ List<List<PageAllVersionDetailVO>> result = new ArrayList<>();
|
|
|
+ for (int i = 0; i < 2; i++) {
|
|
|
+ // 初始化结果集
|
|
|
+ List<PageAllVersionDetailVO> allRecords = new ArrayList<>();
|
|
|
+ // 分页查询参数
|
|
|
+ PageAllVersionDetailDTO pageQuery = new PageAllVersionDetailDTO();
|
|
|
+ pageQuery.setAppId(appId);
|
|
|
+ pageQuery.setQueryDate(i);
|
|
|
+ // 每次查询的批次大小,根据实际内存情况调整
|
|
|
+ long batchSize = 1000;
|
|
|
+ pageQuery.setSize(batchSize);
|
|
|
+ pageQuery.setCurrent(1);
|
|
|
+
|
|
|
+ while (true) {
|
|
|
+ // 分批查询数据
|
|
|
+ Page<PageAllVersionDetailVO> pageResult = userAnalyseService.pageAllVersionDetail(pageQuery);
|
|
|
+ List<PageAllVersionDetailVO> records = pageResult.getRecords();
|
|
|
+ if (CollectionUtils.isEmpty(records)) {
|
|
|
+ // 没有更多数据,退出循环
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ // 添加到结果集
|
|
|
+ allRecords.addAll(records);
|
|
|
+ // 如果当前页记录数小于批次大小,说明是最后一页
|
|
|
+ if (records.size() < batchSize) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ // 准备查询下一页
|
|
|
+ pageQuery.setCurrent(pageQuery.getCurrent() + 1);
|
|
|
+ }
|
|
|
+ result.add(allRecords);
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
@PostMapping("/version/single/detail")
|
|
@@ -165,10 +364,54 @@ public class UserAnalyseController {
|
|
|
return R.ok(result);
|
|
|
}
|
|
|
|
|
|
- @GetMapping("/version/single/export")
|
|
|
+ @PostMapping("/version/single/export")
|
|
|
@Operation(summary = "导出单版本详情")
|
|
|
- public R exportSingleVersionDetail() {
|
|
|
- return R.ok();
|
|
|
+ public void exportSingleVersionDetail(
|
|
|
+ @Valid @RequestBody UserAnalyseQueryBaseDTO reqDto,
|
|
|
+ HttpServletResponse response) throws Exception {
|
|
|
+
|
|
|
+ // 获取版本并验证
|
|
|
+ if (reqDto.getVersion() == null || reqDto.getVersion().isEmpty()){
|
|
|
+ throw new BusinessException("版本不能为空");
|
|
|
+ }
|
|
|
+ String version = reqDto.getVersion().get(0);
|
|
|
+ String sheetName = version + "版本详情"; // 动态生成表名
|
|
|
+
|
|
|
+ // 初始化结果集
|
|
|
+ List<PageSingleVersionDetailVO> allRecords = new ArrayList<>();
|
|
|
+ // 分页查询参数
|
|
|
+ PageUserAnalyseDTO pageQuery = new PageUserAnalyseDTO();
|
|
|
+ BeanUtils.copyProperties(reqDto, pageQuery);
|
|
|
+ long batchSize = 1000;
|
|
|
+ pageQuery.setSize(batchSize);
|
|
|
+ pageQuery.setCurrent(1);
|
|
|
+
|
|
|
+ // 分批查询数据
|
|
|
+ while (true) {
|
|
|
+ Page<PageSingleVersionDetailVO> pageResult = userAnalyseService.pageSingleVersionDetail(pageQuery);
|
|
|
+ List<PageSingleVersionDetailVO> records = pageResult.getRecords();
|
|
|
+ if (CollectionUtils.isEmpty(records)) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ allRecords.addAll(records);
|
|
|
+ if (records.size() < batchSize) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ pageQuery.setCurrent(pageQuery.getCurrent() + 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置响应头,动态生成文件名
|
|
|
+ String fileName = URLEncoder.encode(sheetName, StandardCharsets.UTF_8)
|
|
|
+ .replaceAll("\\+", "%20");
|
|
|
+ response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
|
|
+ response.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
|
|
+ response.setHeader("Content-disposition",
|
|
|
+ "attachment;filename*=utf-8''" + fileName + ".xlsx");
|
|
|
+
|
|
|
+ // 使用EasyExcel手动写入,指定动态表名
|
|
|
+ EasyExcel.write(response.getOutputStream(), PageSingleVersionDetailVO.class)
|
|
|
+ .sheet(sheetName) // 设置工作表名称
|
|
|
+ .doWrite(allRecords);
|
|
|
}
|
|
|
|
|
|
@PostMapping("/version/distribution")
|
|
@@ -186,10 +429,85 @@ public class UserAnalyseController {
|
|
|
}
|
|
|
|
|
|
|
|
|
- @GetMapping("/version/distribution/export")
|
|
|
+ @PostMapping("/version/distribution/export")
|
|
|
@Operation(summary = "导出版本用户来源详情")
|
|
|
- public R exportVersionDistributionDetail() {
|
|
|
- return R.ok();
|
|
|
+ public void exportVersionDistributionDetail(
|
|
|
+ @Valid @RequestBody GetVersionDistributionDTO reqDto,
|
|
|
+ HttpServletResponse response) throws Exception {
|
|
|
+
|
|
|
+ // 1. 参数校验与获取
|
|
|
+ String version = reqDto.getVersion();
|
|
|
+ String type = reqDto.getType();
|
|
|
+ if (version == null || version.isEmpty()) {
|
|
|
+ throw new BusinessException("版本不能为空");
|
|
|
+ }
|
|
|
+ if (type == null || type.isEmpty()) {
|
|
|
+ throw new BusinessException("类型不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 动态生成文件名和表头
|
|
|
+ String fileName;
|
|
|
+ List<List<String>> head = new ArrayList<>();
|
|
|
+ String sheetName = version + "版本用户来源详情"; // 固定sheet名
|
|
|
+
|
|
|
+ switch (type) {
|
|
|
+ case "newUserChannel":
|
|
|
+ fileName = version + "版本新增用户渠道详情";
|
|
|
+ head.add(Collections.singletonList("渠道"));
|
|
|
+ head.add(Collections.singletonList("新增用户"));
|
|
|
+ head.add(Collections.singletonList("新增用户占比"));
|
|
|
+ break;
|
|
|
+ case "upgradeChannel":
|
|
|
+ fileName = version + "版本升级用户渠道详情";
|
|
|
+ head.add(Collections.singletonList("渠道"));
|
|
|
+ head.add(Collections.singletonList("升级用户"));
|
|
|
+ head.add(Collections.singletonList("升级用户占比"));
|
|
|
+ break;
|
|
|
+ case "upgradeVersion":
|
|
|
+ fileName = version + "版本升级用户版本详情";
|
|
|
+ head.add(Collections.singletonList("版本"));
|
|
|
+ head.add(Collections.singletonList("升级用户"));
|
|
|
+ head.add(Collections.singletonList("升级用户占比"));
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ throw new BusinessException("不支持的导出类型: " + type);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 设置Excel响应头(确保文件类型正确)
|
|
|
+ response.reset();
|
|
|
+ response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
|
|
+ response.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
|
|
+ String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
|
|
|
+ response.setHeader("Content-Disposition",
|
|
|
+ "attachment;filename=\"" + encodedFileName + ".xlsx\";" +
|
|
|
+ "filename*=utf-8''" + encodedFileName + ".xlsx");
|
|
|
+
|
|
|
+ // 4. 分页查询数据
|
|
|
+ List<PageVersionDistributionDetailVO> allRecords = new ArrayList<>();
|
|
|
+ PageVersionDistributionDetailDTO pageQuery = new PageVersionDistributionDetailDTO();
|
|
|
+ BeanUtils.copyProperties(reqDto, pageQuery);
|
|
|
+ long batchSize = 1000;
|
|
|
+ pageQuery.setSize(batchSize);
|
|
|
+ pageQuery.setCurrent(1);
|
|
|
+
|
|
|
+ while (true) {
|
|
|
+ Page<PageVersionDistributionDetailVO> pageResult = userAnalyseService.pageVersionDistributionDetail(pageQuery);
|
|
|
+ List<PageVersionDistributionDetailVO> records = pageResult.getRecords();
|
|
|
+ if (records == null || records.isEmpty()) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ allRecords.addAll(records);
|
|
|
+ if (records.size() < batchSize) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ pageQuery.setCurrent(pageQuery.getCurrent() + 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 使用EasyExcel手动写入,指定动态表名
|
|
|
+ EasyExcel.write(response.getOutputStream())
|
|
|
+ .head(head)
|
|
|
+ .sheet(sheetName)
|
|
|
+ .doWrite(allRecords);
|
|
|
}
|
|
|
|
|
|
}
|