Compare commits
No commits in common. "e0f47ce1b6bab95497e2b2f8f7db588e5fb0aefb" and "a2adaf38d124472ce7798fa8e06f265436ea83f1" have entirely different histories.
e0f47ce1b6
...
a2adaf38d1
@ -1,221 +0,0 @@
|
|||||||
package org.leocoder.thin.domain.model.vo.system;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 仪表盘统计数据响应对象
|
|
||||||
*
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
|
||||||
public class DashboardStatisticsVo implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户统计数据
|
|
||||||
*/
|
|
||||||
@JsonProperty("userStats")
|
|
||||||
private UserStatsVo userStats;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录统计数据
|
|
||||||
*/
|
|
||||||
@JsonProperty("loginStats")
|
|
||||||
private LoginStatsVo loginStats;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 存储统计数据
|
|
||||||
*/
|
|
||||||
@JsonProperty("storageStats")
|
|
||||||
private StorageStatsVo storageStats;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 今日活跃统计数据
|
|
||||||
*/
|
|
||||||
@JsonProperty("dailyActivityStats")
|
|
||||||
private DailyActivityStatsVo dailyActivityStats;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户统计数据
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public static class UserStatsVo implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 总用户数
|
|
||||||
*/
|
|
||||||
@JsonProperty("totalUsers")
|
|
||||||
private Integer totalUsers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 今日新增用户数
|
|
||||||
*/
|
|
||||||
@JsonProperty("todayNewUsers")
|
|
||||||
private Integer todayNewUsers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 活跃用户数
|
|
||||||
*/
|
|
||||||
@JsonProperty("activeUsers")
|
|
||||||
private Integer activeUsers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前在线用户数
|
|
||||||
*/
|
|
||||||
@JsonProperty("onlineUsers")
|
|
||||||
private Integer onlineUsers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录统计数据
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public static class LoginStatsVo implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 今日登录次数
|
|
||||||
*/
|
|
||||||
@JsonProperty("todayLogins")
|
|
||||||
private Integer todayLogins;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 累计登录次数
|
|
||||||
*/
|
|
||||||
@JsonProperty("totalLogins")
|
|
||||||
private Integer totalLogins;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录趋势数据
|
|
||||||
*/
|
|
||||||
@JsonProperty("loginTrend")
|
|
||||||
private List<LoginTrendItemVo> loginTrend;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 存储统计数据
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public static class StorageStatsVo implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 总文件数
|
|
||||||
*/
|
|
||||||
@JsonProperty("totalFiles")
|
|
||||||
private Integer totalFiles;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 总图片数
|
|
||||||
*/
|
|
||||||
@JsonProperty("totalImages")
|
|
||||||
private Integer totalImages;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 总存储大小(格式化)
|
|
||||||
*/
|
|
||||||
@JsonProperty("totalSize")
|
|
||||||
private String totalSize;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 今日上传文件数
|
|
||||||
*/
|
|
||||||
@JsonProperty("todayUploads")
|
|
||||||
private Integer todayUploads;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 存储使用率(百分比)
|
|
||||||
*/
|
|
||||||
@JsonProperty("storageUsage")
|
|
||||||
private Double storageUsage;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 可用空间(格式化)
|
|
||||||
*/
|
|
||||||
@JsonProperty("availableSpace")
|
|
||||||
private String availableSpace;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 今日活跃统计数据
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public static class DailyActivityStatsVo implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 今日访问量
|
|
||||||
*/
|
|
||||||
@JsonProperty("todayVisits")
|
|
||||||
private Integer todayVisits;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 今日操作数
|
|
||||||
*/
|
|
||||||
@JsonProperty("todayOperations")
|
|
||||||
private Integer todayOperations;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 活跃用户数
|
|
||||||
*/
|
|
||||||
@JsonProperty("activeUsers")
|
|
||||||
private Integer activeUsers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新增内容数
|
|
||||||
*/
|
|
||||||
@JsonProperty("newContent")
|
|
||||||
private Integer newContent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* API调用次数
|
|
||||||
*/
|
|
||||||
@JsonProperty("apiCalls")
|
|
||||||
private Integer apiCalls;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 平均响应时间(毫秒)
|
|
||||||
*/
|
|
||||||
@JsonProperty("avgResponseTime")
|
|
||||||
private Integer avgResponseTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录趋势项
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public static class LoginTrendItemVo implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 日期(YYYY-MM-DD格式)
|
|
||||||
*/
|
|
||||||
@JsonProperty("date")
|
|
||||||
private String date;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当日登录次数
|
|
||||||
*/
|
|
||||||
@JsonProperty("count")
|
|
||||||
private Integer count;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 显示标签(用于图表展示)
|
|
||||||
*/
|
|
||||||
@JsonProperty("label")
|
|
||||||
private String label;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,53 +0,0 @@
|
|||||||
package org.leocoder.thin.domain.model.vo.system;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录趋势数据响应对象
|
|
||||||
*
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
|
||||||
public class LoginTrendVo implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录趋势数据列表
|
|
||||||
*/
|
|
||||||
@JsonProperty("loginTrend")
|
|
||||||
private List<LoginTrendItemVo> loginTrend;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录趋势项
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public static class LoginTrendItemVo implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 日期(YYYY-MM-DD格式)
|
|
||||||
*/
|
|
||||||
@JsonProperty("date")
|
|
||||||
private String date;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当日登录次数
|
|
||||||
*/
|
|
||||||
@JsonProperty("count")
|
|
||||||
private Integer count;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 显示标签(用于图表展示)
|
|
||||||
*/
|
|
||||||
@JsonProperty("label")
|
|
||||||
private String label;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,173 +0,0 @@
|
|||||||
package org.leocoder.thin.system.controller.dashboard;
|
|
||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
|
||||||
import org.leocoder.thin.common.exception.coder.YUtil;
|
|
||||||
import org.leocoder.thin.domain.model.vo.system.DashboardStatisticsVo;
|
|
||||||
import org.leocoder.thin.domain.model.vo.system.LoginTrendVo;
|
|
||||||
import org.leocoder.thin.system.service.dashboard.DashboardService;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 仪表盘统计控制器
|
|
||||||
*
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
@Tag(name = "仪表盘管理", description = "仪表盘统计数据接口")
|
|
||||||
@Slf4j
|
|
||||||
@Validated
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/coder/dashboard")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class DashboardController {
|
|
||||||
|
|
||||||
private final DashboardService dashboardService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取仪表盘统计数据
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
@Operation(
|
|
||||||
summary = "获取仪表盘统计数据",
|
|
||||||
description = "获取用户、登录、存储、活跃度等核心统计数据"
|
|
||||||
)
|
|
||||||
@GetMapping("/getStatistics")
|
|
||||||
@SaCheckPermission("dashboard:view")
|
|
||||||
public DashboardStatisticsVo getStatistics() {
|
|
||||||
DashboardStatisticsVo statistics = dashboardService.getStatistics();
|
|
||||||
YUtil.isTrue(ObjectUtils.isEmpty(statistics), "获取仪表盘统计数据失败");
|
|
||||||
return statistics;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取登录趋势数据
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
@Operation(
|
|
||||||
summary = "获取登录趋势数据",
|
|
||||||
description = "获取最近N天的登录趋势图表数据"
|
|
||||||
)
|
|
||||||
@GetMapping("/getLoginTrend")
|
|
||||||
@SaCheckPermission("dashboard:view")
|
|
||||||
public LoginTrendVo getLoginTrend(
|
|
||||||
@Parameter(description = "查询天数", example = "7") @RequestParam(
|
|
||||||
defaultValue = "7"
|
|
||||||
) Integer days
|
|
||||||
) {
|
|
||||||
LoginTrendVo loginTrend = dashboardService.getLoginTrend(days);
|
|
||||||
YUtil.isTrue(ObjectUtils.isEmpty(loginTrend), "获取登录趋势数据失败");
|
|
||||||
return loginTrend;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取完整仪表盘数据
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
@Operation(
|
|
||||||
summary = "获取完整仪表盘数据",
|
|
||||||
description = "一次性获取所有仪表盘数据,减少前端请求次数"
|
|
||||||
)
|
|
||||||
@GetMapping("/getAllData")
|
|
||||||
@SaCheckPermission("dashboard:view")
|
|
||||||
public DashboardStatisticsVo getAllData(
|
|
||||||
@Parameter(
|
|
||||||
description = "是否包含趋势数据",
|
|
||||||
example = "true"
|
|
||||||
) @RequestParam(defaultValue = "true") Boolean includeTrend,
|
|
||||||
@Parameter(description = "趋势数据天数", example = "7") @RequestParam(
|
|
||||||
defaultValue = "7"
|
|
||||||
) Integer trendDays
|
|
||||||
) {
|
|
||||||
DashboardStatisticsVo allData = dashboardService.getAllData(
|
|
||||||
includeTrend,
|
|
||||||
trendDays
|
|
||||||
);
|
|
||||||
YUtil.isTrue(ObjectUtils.isEmpty(allData), "获取完整仪表盘数据失败");
|
|
||||||
return allData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取用户统计数据
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
@Operation(
|
|
||||||
summary = "获取用户统计数据",
|
|
||||||
description = "获取用户相关的统计信息"
|
|
||||||
)
|
|
||||||
@GetMapping("/getUserStats")
|
|
||||||
@SaCheckPermission("dashboard:view")
|
|
||||||
public DashboardStatisticsVo.UserStatsVo getUserStats() {
|
|
||||||
DashboardStatisticsVo.UserStatsVo userStats =
|
|
||||||
dashboardService.getUserStats();
|
|
||||||
YUtil.isTrue(ObjectUtils.isEmpty(userStats), "获取用户统计数据失败");
|
|
||||||
return userStats;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取登录统计数据
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
@Operation(
|
|
||||||
summary = "获取登录统计数据",
|
|
||||||
description = "获取登录相关的统计信息"
|
|
||||||
)
|
|
||||||
@GetMapping("/getLoginStats")
|
|
||||||
@SaCheckPermission("dashboard:view")
|
|
||||||
public DashboardStatisticsVo.LoginStatsVo getLoginStats(
|
|
||||||
@Parameter(
|
|
||||||
description = "是否包含趋势数据",
|
|
||||||
example = "false"
|
|
||||||
) @RequestParam(defaultValue = "false") Boolean includeTrend,
|
|
||||||
@Parameter(description = "趋势数据天数", example = "7") @RequestParam(
|
|
||||||
defaultValue = "7"
|
|
||||||
) Integer trendDays
|
|
||||||
) {
|
|
||||||
DashboardStatisticsVo.LoginStatsVo loginStats =
|
|
||||||
dashboardService.getLoginStats(includeTrend, trendDays);
|
|
||||||
YUtil.isTrue(ObjectUtils.isEmpty(loginStats), "获取登录统计数据失败");
|
|
||||||
return loginStats;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取存储统计数据
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
@Operation(
|
|
||||||
summary = "获取存储统计数据",
|
|
||||||
description = "获取存储相关的统计信息"
|
|
||||||
)
|
|
||||||
@GetMapping("/getStorageStats")
|
|
||||||
@SaCheckPermission("dashboard:view")
|
|
||||||
public DashboardStatisticsVo.StorageStatsVo getStorageStats() {
|
|
||||||
DashboardStatisticsVo.StorageStatsVo storageStats =
|
|
||||||
dashboardService.getStorageStats();
|
|
||||||
YUtil.isTrue(ObjectUtils.isEmpty(storageStats), "获取存储统计数据失败");
|
|
||||||
return storageStats;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取今日活跃统计数据
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
@Operation(
|
|
||||||
summary = "获取今日活跃统计数据",
|
|
||||||
description = "获取今日活跃相关的统计信息"
|
|
||||||
)
|
|
||||||
@GetMapping("/getDailyActivityStats")
|
|
||||||
@SaCheckPermission("dashboard:view")
|
|
||||||
public DashboardStatisticsVo.DailyActivityStatsVo getDailyActivityStats() {
|
|
||||||
DashboardStatisticsVo.DailyActivityStatsVo activityStats =
|
|
||||||
dashboardService.getDailyActivityStats();
|
|
||||||
YUtil.isTrue(
|
|
||||||
ObjectUtils.isEmpty(activityStats),
|
|
||||||
"获取今日活跃统计数据失败"
|
|
||||||
);
|
|
||||||
return activityStats;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,54 +0,0 @@
|
|||||||
package org.leocoder.thin.system.service.dashboard;
|
|
||||||
|
|
||||||
import org.leocoder.thin.domain.model.vo.system.DashboardStatisticsVo;
|
|
||||||
import org.leocoder.thin.domain.model.vo.system.LoginTrendVo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 仪表盘统计服务接口
|
|
||||||
*
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
public interface DashboardService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取仪表盘统计数据
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
DashboardStatisticsVo getStatistics();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取登录趋势数据
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
LoginTrendVo getLoginTrend(Integer days);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取完整仪表盘数据
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
DashboardStatisticsVo getAllData(Boolean includeTrend, Integer trendDays);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取用户统计数据
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
DashboardStatisticsVo.UserStatsVo getUserStats();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取登录统计数据
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
DashboardStatisticsVo.LoginStatsVo getLoginStats(Boolean includeTrend, Integer trendDays);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取存储统计数据
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
DashboardStatisticsVo.StorageStatsVo getStorageStats();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取今日活跃统计数据
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
DashboardStatisticsVo.DailyActivityStatsVo getDailyActivityStats();
|
|
||||||
}
|
|
||||||
@ -1,370 +0,0 @@
|
|||||||
package org.leocoder.thin.system.service.dashboard;
|
|
||||||
|
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.leocoder.thin.domain.model.vo.system.DashboardStatisticsVo;
|
|
||||||
import org.leocoder.thin.domain.model.vo.system.LoginTrendVo;
|
|
||||||
import org.leocoder.thin.domain.pojo.system.*;
|
|
||||||
import org.leocoder.thin.mybatisplus.mapper.system.*;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 仪表盘统计服务实现类
|
|
||||||
*
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class DashboardServiceImpl implements DashboardService {
|
|
||||||
|
|
||||||
private final SysLoginUserMapper sysLoginUserMapper;
|
|
||||||
private final SysLoginLogMapper sysLoginLogMapper;
|
|
||||||
private final SysOperLogMapper sysOperLogMapper;
|
|
||||||
private final SysFileMapper sysFileMapper;
|
|
||||||
private final SysPictureMapper sysPictureMapper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取仪表盘统计数据
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public DashboardStatisticsVo getStatistics() {
|
|
||||||
DashboardStatisticsVo statisticsVo = new DashboardStatisticsVo();
|
|
||||||
|
|
||||||
// 设置用户统计数据
|
|
||||||
statisticsVo.setUserStats(getUserStats());
|
|
||||||
|
|
||||||
// 设置登录统计数据(不包含趋势)
|
|
||||||
statisticsVo.setLoginStats(getLoginStats(false, null));
|
|
||||||
|
|
||||||
// 设置存储统计数据
|
|
||||||
statisticsVo.setStorageStats(getStorageStats());
|
|
||||||
|
|
||||||
// 设置今日活跃统计数据
|
|
||||||
statisticsVo.setDailyActivityStats(getDailyActivityStats());
|
|
||||||
|
|
||||||
return statisticsVo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取登录趋势数据
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public LoginTrendVo getLoginTrend(Integer days) {
|
|
||||||
if (days == null || days <= 0) {
|
|
||||||
days = 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
LoginTrendVo loginTrendVo = new LoginTrendVo();
|
|
||||||
List<LoginTrendVo.LoginTrendItemVo> trendList = new ArrayList<>();
|
|
||||||
|
|
||||||
LocalDate today = LocalDate.now();
|
|
||||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
||||||
DateTimeFormatter labelFormatter = DateTimeFormatter.ofPattern(
|
|
||||||
"M月d日"
|
|
||||||
);
|
|
||||||
|
|
||||||
for (int i = days - 1; i >= 0; i--) {
|
|
||||||
LocalDate date = today.minusDays(i);
|
|
||||||
String dateStr = date.format(formatter);
|
|
||||||
String label = date.format(labelFormatter);
|
|
||||||
|
|
||||||
// 统计该日的登录次数
|
|
||||||
LambdaQueryWrapper<SysLoginLog> wrapper =
|
|
||||||
new LambdaQueryWrapper<>();
|
|
||||||
wrapper
|
|
||||||
.apply("DATE(login_time) = {0}", dateStr)
|
|
||||||
// 成功登录
|
|
||||||
.eq(SysLoginLog::getLoginStatus, "0");
|
|
||||||
Long count = sysLoginLogMapper.selectCount(wrapper);
|
|
||||||
|
|
||||||
LoginTrendVo.LoginTrendItemVo trendItem =
|
|
||||||
new LoginTrendVo.LoginTrendItemVo();
|
|
||||||
trendItem.setDate(dateStr);
|
|
||||||
trendItem.setCount(count != null ? count.intValue() : 0);
|
|
||||||
trendItem.setLabel(label);
|
|
||||||
|
|
||||||
trendList.add(trendItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
loginTrendVo.setLoginTrend(trendList);
|
|
||||||
return loginTrendVo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取完整仪表盘数据
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public DashboardStatisticsVo getAllData(
|
|
||||||
Boolean includeTrend,
|
|
||||||
Integer trendDays
|
|
||||||
) {
|
|
||||||
DashboardStatisticsVo statisticsVo = new DashboardStatisticsVo();
|
|
||||||
|
|
||||||
// 设置用户统计数据
|
|
||||||
statisticsVo.setUserStats(getUserStats());
|
|
||||||
|
|
||||||
// 设置登录统计数据(根据参数决定是否包含趋势)
|
|
||||||
statisticsVo.setLoginStats(getLoginStats(includeTrend, trendDays));
|
|
||||||
|
|
||||||
// 设置存储统计数据
|
|
||||||
statisticsVo.setStorageStats(getStorageStats());
|
|
||||||
|
|
||||||
// 设置今日活跃统计数据
|
|
||||||
statisticsVo.setDailyActivityStats(getDailyActivityStats());
|
|
||||||
|
|
||||||
return statisticsVo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取用户统计数据
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public DashboardStatisticsVo.UserStatsVo getUserStats() {
|
|
||||||
DashboardStatisticsVo.UserStatsVo userStats =
|
|
||||||
new DashboardStatisticsVo.UserStatsVo();
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 总用户数
|
|
||||||
Long totalUsers = sysLoginUserMapper.selectCount(null);
|
|
||||||
userStats.setTotalUsers(
|
|
||||||
totalUsers != null ? totalUsers.intValue() : 0
|
|
||||||
);
|
|
||||||
|
|
||||||
// 今日新增用户数
|
|
||||||
LambdaQueryWrapper<SysLoginUser> todayWrapper =
|
|
||||||
new LambdaQueryWrapper<>();
|
|
||||||
todayWrapper.apply("DATE(create_time) = CURDATE()");
|
|
||||||
Long todayNewUsers = sysLoginUserMapper.selectCount(todayWrapper);
|
|
||||||
userStats.setTodayNewUsers(
|
|
||||||
todayNewUsers != null ? todayNewUsers.intValue() : 0
|
|
||||||
);
|
|
||||||
|
|
||||||
// 活跃用户数(最近30天有登录记录的用户)
|
|
||||||
LambdaQueryWrapper<SysLoginLog> activeWrapper =
|
|
||||||
new LambdaQueryWrapper<>();
|
|
||||||
activeWrapper
|
|
||||||
.apply("login_time >= DATE_SUB(NOW(), INTERVAL 30 DAY)")
|
|
||||||
.eq(SysLoginLog::getLoginStatus, "0")
|
|
||||||
.select(SysLoginLog::getLoginName)
|
|
||||||
.groupBy(SysLoginLog::getLoginName);
|
|
||||||
Long activeUsers = sysLoginLogMapper.selectCount(activeWrapper);
|
|
||||||
userStats.setActiveUsers(
|
|
||||||
activeUsers != null ? activeUsers.intValue() : 0
|
|
||||||
);
|
|
||||||
|
|
||||||
// 当前在线用户数(通过Sa-Token获取)
|
|
||||||
List<String> onlineTokens = StpUtil.searchTokenValue(
|
|
||||||
"",
|
|
||||||
0,
|
|
||||||
-1,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
userStats.setOnlineUsers(
|
|
||||||
onlineTokens != null ? onlineTokens.size() : 0
|
|
||||||
);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("获取用户统计数据失败", e);
|
|
||||||
// 设置默认值
|
|
||||||
userStats.setTotalUsers(0);
|
|
||||||
userStats.setTodayNewUsers(0);
|
|
||||||
userStats.setActiveUsers(0);
|
|
||||||
userStats.setOnlineUsers(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return userStats;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取登录统计数据
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public DashboardStatisticsVo.LoginStatsVo getLoginStats(
|
|
||||||
Boolean includeTrend,
|
|
||||||
Integer trendDays
|
|
||||||
) {
|
|
||||||
DashboardStatisticsVo.LoginStatsVo loginStats =
|
|
||||||
new DashboardStatisticsVo.LoginStatsVo();
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 今日登录次数
|
|
||||||
LambdaQueryWrapper<SysLoginLog> todayWrapper =
|
|
||||||
new LambdaQueryWrapper<>();
|
|
||||||
todayWrapper
|
|
||||||
.apply("DATE(login_time) = CURDATE()")
|
|
||||||
.eq(SysLoginLog::getLoginStatus, "0"); // 成功登录
|
|
||||||
Long todayLogins = sysLoginLogMapper.selectCount(todayWrapper);
|
|
||||||
loginStats.setTodayLogins(
|
|
||||||
todayLogins != null ? todayLogins.intValue() : 0
|
|
||||||
);
|
|
||||||
|
|
||||||
// 累计登录次数
|
|
||||||
LambdaQueryWrapper<SysLoginLog> totalWrapper =
|
|
||||||
new LambdaQueryWrapper<>();
|
|
||||||
totalWrapper.eq(SysLoginLog::getLoginStatus, "0"); // 成功登录
|
|
||||||
Long totalLogins = sysLoginLogMapper.selectCount(totalWrapper);
|
|
||||||
loginStats.setTotalLogins(
|
|
||||||
totalLogins != null ? totalLogins.intValue() : 0
|
|
||||||
);
|
|
||||||
|
|
||||||
// 根据参数决定是否包含趋势数据
|
|
||||||
if (Boolean.TRUE.equals(includeTrend)) {
|
|
||||||
LoginTrendVo trendVo = getLoginTrend(trendDays);
|
|
||||||
// 转换LoginTrendItemVo类型
|
|
||||||
if (trendVo.getLoginTrend() != null) {
|
|
||||||
List<DashboardStatisticsVo.LoginTrendItemVo> trendItems =
|
|
||||||
new ArrayList<>();
|
|
||||||
for (LoginTrendVo.LoginTrendItemVo item : trendVo.getLoginTrend()) {
|
|
||||||
DashboardStatisticsVo.LoginTrendItemVo trendItem =
|
|
||||||
new DashboardStatisticsVo.LoginTrendItemVo();
|
|
||||||
trendItem.setDate(item.getDate());
|
|
||||||
trendItem.setCount(item.getCount());
|
|
||||||
trendItem.setLabel(item.getLabel());
|
|
||||||
trendItems.add(trendItem);
|
|
||||||
}
|
|
||||||
loginStats.setLoginTrend(trendItems);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("获取登录统计数据失败", e);
|
|
||||||
// 设置默认值
|
|
||||||
loginStats.setTodayLogins(0);
|
|
||||||
loginStats.setTotalLogins(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return loginStats;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取存储统计数据
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public DashboardStatisticsVo.StorageStatsVo getStorageStats() {
|
|
||||||
DashboardStatisticsVo.StorageStatsVo storageStats =
|
|
||||||
new DashboardStatisticsVo.StorageStatsVo();
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 总文件数
|
|
||||||
Long totalFiles = sysFileMapper.selectCount(null);
|
|
||||||
storageStats.setTotalFiles(
|
|
||||||
totalFiles != null ? totalFiles.intValue() : 0
|
|
||||||
);
|
|
||||||
|
|
||||||
// 总图片数
|
|
||||||
Long totalImages = sysPictureMapper.selectCount(null);
|
|
||||||
storageStats.setTotalImages(
|
|
||||||
totalImages != null ? totalImages.intValue() : 0
|
|
||||||
);
|
|
||||||
|
|
||||||
// 今日上传文件数
|
|
||||||
LambdaQueryWrapper<SysFile> todayWrapper =
|
|
||||||
new LambdaQueryWrapper<>();
|
|
||||||
todayWrapper.apply("DATE(create_time) = CURDATE()");
|
|
||||||
Long todayUploads = sysFileMapper.selectCount(todayWrapper);
|
|
||||||
storageStats.setTodayUploads(
|
|
||||||
todayUploads != null ? todayUploads.intValue() : 0
|
|
||||||
);
|
|
||||||
|
|
||||||
// 计算总存储大小(这里可以根据实际情况优化)
|
|
||||||
// 由于文件大小计算比较复杂,这里先设置示例数据
|
|
||||||
storageStats.setTotalSize("2.3 GB");
|
|
||||||
storageStats.setStorageUsage(67.5);
|
|
||||||
storageStats.setAvailableSpace("1.2 GB");
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("获取存储统计数据失败", e);
|
|
||||||
// 设置默认值
|
|
||||||
storageStats.setTotalFiles(0);
|
|
||||||
storageStats.setTotalImages(0);
|
|
||||||
storageStats.setTodayUploads(0);
|
|
||||||
storageStats.setTotalSize("0 B");
|
|
||||||
storageStats.setStorageUsage(0.0);
|
|
||||||
storageStats.setAvailableSpace("0 B");
|
|
||||||
}
|
|
||||||
|
|
||||||
return storageStats;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 获取今日活跃统计数据
|
|
||||||
* @author Leocoder
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public DashboardStatisticsVo.DailyActivityStatsVo getDailyActivityStats() {
|
|
||||||
DashboardStatisticsVo.DailyActivityStatsVo activityStats =
|
|
||||||
new DashboardStatisticsVo.DailyActivityStatsVo();
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 今日访问量
|
|
||||||
LambdaQueryWrapper<SysOperLog> todayWrapper =
|
|
||||||
new LambdaQueryWrapper<>();
|
|
||||||
todayWrapper.apply("DATE(oper_time) = CURDATE()");
|
|
||||||
Long todayVisits = sysOperLogMapper.selectCount(todayWrapper);
|
|
||||||
activityStats.setTodayVisits(
|
|
||||||
todayVisits != null ? todayVisits.intValue() : 0
|
|
||||||
);
|
|
||||||
|
|
||||||
// 今日操作数(排除查询操作)
|
|
||||||
LambdaQueryWrapper<SysOperLog> operWrapper =
|
|
||||||
new LambdaQueryWrapper<>();
|
|
||||||
operWrapper
|
|
||||||
.apply("DATE(oper_time) = CURDATE()")
|
|
||||||
// 排除查询操作
|
|
||||||
.ne(SysOperLog::getOperType, "SELECT");
|
|
||||||
Long todayOperations = sysOperLogMapper.selectCount(operWrapper);
|
|
||||||
activityStats.setTodayOperations(
|
|
||||||
todayOperations != null ? todayOperations.intValue() : 0
|
|
||||||
);
|
|
||||||
|
|
||||||
// 活跃用户数(取用户统计中的活跃用户数)
|
|
||||||
DashboardStatisticsVo.UserStatsVo userStats = getUserStats();
|
|
||||||
activityStats.setActiveUsers(userStats.getActiveUsers());
|
|
||||||
|
|
||||||
// 新增内容数(今日新增的文件和图片)
|
|
||||||
LambdaQueryWrapper<SysFile> fileWrapper =
|
|
||||||
new LambdaQueryWrapper<>();
|
|
||||||
fileWrapper.apply("DATE(create_time) = CURDATE()");
|
|
||||||
Long newFiles = sysFileMapper.selectCount(fileWrapper);
|
|
||||||
|
|
||||||
LambdaQueryWrapper<SysPicture> pictureWrapper =
|
|
||||||
new LambdaQueryWrapper<>();
|
|
||||||
pictureWrapper.apply("DATE(create_time) = CURDATE()");
|
|
||||||
Long newPictures = sysPictureMapper.selectCount(pictureWrapper);
|
|
||||||
|
|
||||||
int newContent =
|
|
||||||
(newFiles != null ? newFiles.intValue() : 0) +
|
|
||||||
(newPictures != null ? newPictures.intValue() : 0);
|
|
||||||
activityStats.setNewContent(newContent);
|
|
||||||
|
|
||||||
// API调用次数(今日操作日志总数)
|
|
||||||
activityStats.setApiCalls(activityStats.getTodayVisits());
|
|
||||||
|
|
||||||
// 平均响应时间(这里可以根据实际情况计算)
|
|
||||||
// 示例数据
|
|
||||||
activityStats.setAvgResponseTime(235);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("获取今日活跃统计数据失败", e);
|
|
||||||
// 设置默认值
|
|
||||||
activityStats.setTodayVisits(0);
|
|
||||||
activityStats.setTodayOperations(0);
|
|
||||||
activityStats.setActiveUsers(0);
|
|
||||||
activityStats.setNewContent(0);
|
|
||||||
activityStats.setApiCalls(0);
|
|
||||||
activityStats.setAvgResponseTime(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return activityStats;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -36,14 +36,6 @@ public class ResultResponseHandler implements ResponseBodyAdvice<Object> {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean supports(@Nullable MethodParameter methodParameter, @Nullable Class<? extends HttpMessageConverter<?>> CoderClass) {
|
public boolean supports(@Nullable MethodParameter methodParameter, @Nullable Class<? extends HttpMessageConverter<?>> CoderClass) {
|
||||||
// 排除Swagger相关路径,避免干扰OpenAPI文档生成
|
|
||||||
if (methodParameter != null && methodParameter.getMethod() != null) {
|
|
||||||
String className = methodParameter.getMethod().getDeclaringClass().getName();
|
|
||||||
// 排除SpringDoc相关的Controller
|
|
||||||
if (className.contains("springdoc") || className.contains("swagger")) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,15 +44,6 @@ public class ResultResponseHandler implements ResponseBodyAdvice<Object> {
|
|||||||
// 参数body 代表其实就是SpringMvc的请求的方法的结果
|
// 参数body 代表其实就是SpringMvc的请求的方法的结果
|
||||||
// 对请求的结果在这里统一返回和处理
|
// 对请求的结果在这里统一返回和处理
|
||||||
|
|
||||||
// 排除Swagger相关路径,避免包装OpenAPI文档
|
|
||||||
String requestPath = serverHttpRequest.getURI().getPath();
|
|
||||||
if (requestPath.startsWith("/v3/api-docs") ||
|
|
||||||
requestPath.startsWith("/swagger-ui") ||
|
|
||||||
requestPath.contains("/swagger") ||
|
|
||||||
requestPath.contains("/api-docs")) {
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (body instanceof ErrorHandler errorHandler) {
|
if (body instanceof ErrorHandler errorHandler) {
|
||||||
// 如果返回的结果是一个异常的结果,就把异常返回的结构数据倒腾到R.error里面即可
|
// 如果返回的结果是一个异常的结果,就把异常返回的结构数据倒腾到R.error里面即可
|
||||||
return ResultUtils.error(errorHandler.getStatus(), errorHandler.getMsg());
|
return ResultUtils.error(errorHandler.getStatus(), errorHandler.getMsg());
|
||||||
|
|||||||
@ -52,12 +52,6 @@ public class CoderSaTokenInterceptor implements WebMvcConfigurer {
|
|||||||
// ignoreUrls.add("/**/*.js");
|
// ignoreUrls.add("/**/*.js");
|
||||||
// 上传路径
|
// 上传路径
|
||||||
ignoreUrls.add(baseFilePath + "/**");
|
ignoreUrls.add(baseFilePath + "/**");
|
||||||
// Swagger API文档相关路径
|
|
||||||
ignoreUrls.add("/swagger-ui/**");
|
|
||||||
ignoreUrls.add("/v3/api-docs/**");
|
|
||||||
ignoreUrls.add("/v3/api-docs");
|
|
||||||
ignoreUrls.add("/swagger-ui.html");
|
|
||||||
ignoreUrls.add("/webjars/**");
|
|
||||||
|
|
||||||
// 除白名单路径外均需要登录认证
|
// 除白名单路径外均需要登录认证
|
||||||
SaRouter.match("/**").notMatch(ignoreUrls).check(r -> StpUtil.checkLogin());
|
SaRouter.match("/**").notMatch(ignoreUrls).check(r -> StpUtil.checkLogin());
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user