feat: 完成仪表盘和导出功能
- DashboardController: 实现完整的后端API - /api/dashboard - 仪表盘数据 - /api/dashboard/kpis - KPI统计 - /api/dashboard/activities - 活动摘要 - /api/dashboard/todos - 待办事项 - /api/dashboard/export - 导出CSV - /api/dashboard/kpis/export - KPI导出 - /api/dashboard/activities/export - 活动导出 - dashboard.ts: 前端服务 - 完整的API调用封装 - 导出功能支持 - 下载工具函数 - 更新任务状态: - TASK-401-405: 仪表盘模块100% - TASK-501-502: 单元测试 Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -6,10 +6,13 @@ 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;
|
||||
|
||||
@@ -232,4 +235,116 @@ public class DashboardController {
|
||||
|
||||
return todos;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出仪表盘数据为CSV
|
||||
*/
|
||||
@GetMapping("/export")
|
||||
public ResponseEntity<byte[]> 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<String, Object> 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<byte[]> exportKpis() {
|
||||
StringBuilder csv = new StringBuilder();
|
||||
csv.append("指标,数值,状态,说明\n");
|
||||
for (Map<String, Object> 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<byte[]> 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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user