package com.mosquito.project.controller; import com.mosquito.project.domain.Activity; import com.mosquito.project.dto.ActivityStatsResponse; import com.mosquito.project.dto.ApiResponse; import com.mosquito.project.service.ActivityService; import com.mosquito.project.permission.ApprovalFlowService; import com.mosquito.project.permission.SysApprovalRecord; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; /** * 仪表盘控制器 - 提供管理后台首页数据 */ @RestController @RequestMapping("/api/dashboard") public class DashboardController { private final ActivityService activityService; private final ApprovalFlowService approvalFlowService; public DashboardController( ActivityService activityService, ApprovalFlowService approvalFlowService) { this.activityService = activityService; this.approvalFlowService = approvalFlowService; } /** * 获取仪表盘数据 */ @GetMapping public ResponseEntity>> getDashboard() { Map data = new HashMap<>(); // KPI数据 data.put("kpis", buildKpiData()); // 活动列表 data.put("activities", buildActivityList()); // 告警/异常 data.put("alerts", buildAlerts()); // 待办事项 data.put("todos", buildTodos()); // 更新时间 data.put("updatedAt", LocalDateTime.now().toString()); return ResponseEntity.ok(ApiResponse.success(data)); } /** * 获取KPI统计数据 */ @GetMapping("/kpis") public ResponseEntity>>> getKpis() { return ResponseEntity.ok(ApiResponse.success(buildKpiData())); } /** * 获取活动统计摘要 */ @GetMapping("/activities") public ResponseEntity>> getActivitiesSummary() { Map summary = new HashMap<>(); List activities = activityService.getAllActivities(); // 统计活动数量 summary.put("total", activities.size()); // 活动列表(简要信息) List> activityList = activities.stream() .limit(10) .map(this::convertActivitySummary) .collect(Collectors.toList()); summary.put("list", activityList); return ResponseEntity.ok(ApiResponse.success(summary)); } /** * 获取待办事项 */ @GetMapping("/todos") public ResponseEntity>>> getTodoList() { return ResponseEntity.ok(ApiResponse.success(buildTodos())); } private List> buildKpiData() { List> kpis = new ArrayList<>(); // 获取统计数据 List activities = activityService.getAllActivities(); long totalActivities = activities.size(); // 待审批数量 long pendingApprovals = approvalFlowService.getPendingApprovals(1L).size(); // 后续可接入实际统计服务的数据 long totalUsers = 0L; long pendingRewards = 0L; long pendingRisks = 0L; // 访问量(模拟数据) Map visits = new HashMap<>(); visits.put("label", "访问"); visits.put("value", 0L); visits.put("status", totalActivities > 0 ? "正常" : "待同步"); visits.put("hint", "接入埋点后显示实时数据"); kpis.add(visits); // 分享数(模拟数据) Map shares = new HashMap<>(); shares.put("label", "分享"); shares.put("value", 0L); shares.put("status", totalActivities > 0 ? "正常" : "待同步"); shares.put("hint", "活动开启后统计分享次数"); kpis.add(shares); // 转化数(模拟数据) Map conversions = new HashMap<>(); conversions.put("label", "转化"); conversions.put("value", 0L); conversions.put("status", totalUsers > 0 ? "正常" : "待同步"); conversions.put("hint", "用户注册转化将在此展示"); kpis.add(conversions); // 新增用户 Map newUsers = new HashMap<>(); newUsers.put("label", "新增"); newUsers.put("value", totalUsers); newUsers.put("status", "正常"); newUsers.put("hint", "当前用户总数"); kpis.add(newUsers); // 奖励待审批 Map pendingRewardKpi = new HashMap<>(); pendingRewardKpi.put("label", "待审批奖励"); pendingRewardKpi.put("value", pendingRewards); pendingRewardKpi.put("status", pendingRewards > 0 ? "待处理" : "已清零"); pendingRewardKpi.put("hint", "待审批的奖励申请"); kpis.add(pendingRewardKpi); // 待审批 Map pendingApprovalKpi = new HashMap<>(); pendingApprovalKpi.put("label", "待审批"); pendingApprovalKpi.put("value", pendingApprovals); pendingApprovalKpi.put("status", pendingApprovals > 0 ? "待处理" : "已清零"); pendingApprovalKpi.put("hint", "待审批的申请"); kpis.add(pendingApprovalKpi); // 风险告警 Map riskKpi = new HashMap<>(); riskKpi.put("label", "风险告警"); riskKpi.put("value", pendingRisks); riskKpi.put("status", pendingRisks > 0 ? "需关注" : "正常"); riskKpi.put("hint", "待处理的风险告警"); kpis.add(riskKpi); return kpis; } private List> buildActivityList() { List activities = activityService.getAllActivities(); return activities.stream() .limit(10) .map(this::convertActivitySummary) .collect(Collectors.toList()); } private Map convertActivitySummary(Activity activity) { Map summary = new HashMap<>(); summary.put("id", activity.getId()); summary.put("name", activity.getName()); summary.put("startTime", activity.getStartTime() != null ? activity.getStartTime().toString() : null); summary.put("endTime", activity.getEndTime() != null ? activity.getEndTime().toString() : null); // 获取活动统计 try { ActivityStatsResponse stats = activityService.getActivityStats(activity.getId()); summary.put("participants", stats.getTotalParticipants()); summary.put("shares", stats.getTotalShares()); summary.put("conversions", stats.getTotalParticipants()); } catch (Exception e) { summary.put("participants", 0); summary.put("shares", 0); summary.put("conversions", 0); } return summary; } private List> buildAlerts() { List> alerts = new ArrayList<>(); // 检查待审批记录 List pendingRecords = approvalFlowService.getPendingApprovals(1L); if (!pendingRecords.isEmpty()) { Map alert = new HashMap<>(); alert.put("title", "待审批事项"); alert.put("detail", pendingRecords.size() + "条申请待审批"); alert.put("type", "APPROVAL"); alert.put("level", "INFO"); alerts.add(alert); } return alerts; } private List> buildTodos() { List> todos = new ArrayList<>(); // 待审批记录 List pendingRecords = approvalFlowService.getPendingApprovals(1L); if (!pendingRecords.isEmpty()) { Map todo = new HashMap<>(); todo.put("id", "approval-pending"); todo.put("title", "审批申请"); todo.put("description", pendingRecords.size() + "条申请待审批"); todo.put("type", "APPROVAL"); todo.put("link", "/approvals"); todo.put("priority", "HIGH"); todos.add(todo); } return todos; } /** * 导出仪表盘数据为CSV */ @GetMapping("/export") public ResponseEntity exportDashboard(@RequestParam(defaultValue = "csv") String format) { StringBuilder csv = new StringBuilder(); csv.append("导出时间:").append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).append("\n\n"); // KPI数据 csv.append("KPI指标\n"); csv.append("指标,数值,状态,说明\n"); for (Map kpi : buildKpiData()) { csv.append(kpi.get("label")).append(",") .append(kpi.get("value")).append(",") .append(kpi.get("status")).append(",") .append(kpi.get("hint")).append("\n"); } csv.append("\n"); // 活动数据 csv.append("活动列表\n"); csv.append("ID,名称,开始时间,结束时间,参与人数,分享数,转化数\n"); for (Activity activity : activityService.getAllActivities()) { csv.append(activity.getId()).append(",") .append(escapeCsv(activity.getName())).append(",") .append(activity.getStartTime() != null ? activity.getStartTime().toString() : "").append(",") .append(activity.getEndTime() != null ? activity.getEndTime().toString() : "").append(","); try { ActivityStatsResponse stats = activityService.getActivityStats(activity.getId()); csv.append(stats.getTotalParticipants()).append(",") .append(stats.getTotalShares()).append(",") .append(stats.getTotalParticipants()).append("\n"); } catch (Exception e) { csv.append("0,0,0\n"); } } byte[] body = csv.toString().getBytes(java.nio.charset.StandardCharsets.UTF_8); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.parseMediaType("text/csv; charset=UTF-8")); headers.set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"dashboard_export_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + ".csv\""); return new ResponseEntity<>(body, headers, org.springframework.http.HttpStatus.OK); } /** * 导出KPI数据为CSV */ @GetMapping("/kpis/export") public ResponseEntity exportKpis() { StringBuilder csv = new StringBuilder(); csv.append("指标,数值,状态,说明\n"); for (Map kpi : buildKpiData()) { csv.append(kpi.get("label")).append(",") .append(kpi.get("value")).append(",") .append(kpi.get("status")).append(",") .append(kpi.get("hint")).append("\n"); } byte[] body = csv.toString().getBytes(java.nio.charset.StandardCharsets.UTF_8); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.parseMediaType("text/csv; charset=UTF-8")); headers.set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"kpi_export_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + ".csv\""); return new ResponseEntity<>(body, headers, org.springframework.http.HttpStatus.OK); } /** * 导出活动数据为CSV */ @GetMapping("/activities/export") public ResponseEntity exportActivities() { StringBuilder csv = new StringBuilder(); csv.append("ID,名称,开始时间,结束时间,参与人数,分享数,转化数\n"); for (Activity activity : activityService.getAllActivities()) { csv.append(activity.getId()).append(",") .append(escapeCsv(activity.getName())).append(",") .append(activity.getStartTime() != null ? activity.getStartTime().toString() : "").append(",") .append(activity.getEndTime() != null ? activity.getEndTime().toString() : "").append(","); try { ActivityStatsResponse stats = activityService.getActivityStats(activity.getId()); csv.append(stats.getTotalParticipants()).append(",") .append(stats.getTotalShares()).append(",") .append(stats.getTotalParticipants()).append("\n"); } catch (Exception e) { csv.append("0,0,0\n"); } } byte[] body = csv.toString().getBytes(java.nio.charset.StandardCharsets.UTF_8); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.parseMediaType("text/csv; charset=UTF-8")); headers.set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"activity_export_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + ".csv\""); return new ResponseEntity<>(body, headers, org.springframework.http.HttpStatus.OK); } /** * 转义CSV特殊字符 */ private String escapeCsv(String value) { if (value == null) return ""; if (value.contains(",") || value.contains("\"") || value.contains("\n")) { return "\"" + value.replace("\"", "\"\"") + "\""; } return value; } }