diff --git a/continew-admin-plugins/continew-admin-generator/src/main/java/top/continew/admin/generator/model/entity/InnerGenConfigDO.java b/continew-admin-plugins/continew-admin-generator/src/main/java/top/continew/admin/generator/model/entity/InnerGenConfigDO.java index 1124c11d1..83d631351 100644 --- a/continew-admin-plugins/continew-admin-generator/src/main/java/top/continew/admin/generator/model/entity/InnerGenConfigDO.java +++ b/continew-admin-plugins/continew-admin-generator/src/main/java/top/continew/admin/generator/model/entity/InnerGenConfigDO.java @@ -31,7 +31,7 @@ /** * 内部生成配置信息 * - * @author zhangqcc + * @author Charles7c * @since 2024/8/30 19:35 */ @Data diff --git a/continew-admin-system/src/main/java/top/continew/admin/system/mapper/LogMapper.java b/continew-admin-system/src/main/java/top/continew/admin/system/mapper/LogMapper.java index afcc73d30..4f8edb9f3 100644 --- a/continew-admin-system/src/main/java/top/continew/admin/system/mapper/LogMapper.java +++ b/continew-admin-system/src/main/java/top/continew/admin/system/mapper/LogMapper.java @@ -16,17 +16,21 @@ package top.continew.admin.system.mapper; +import com.alicp.jetcache.anno.Cached; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Constants; import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import top.continew.admin.common.constant.CacheConstants; import top.continew.admin.system.model.entity.LogDO; import top.continew.admin.system.model.resp.dashboard.DashboardAccessTrendResp; import top.continew.admin.system.model.resp.dashboard.DashboardChartCommonResp; -import top.continew.admin.system.model.resp.dashboard.DashboardTotalResp; +import top.continew.admin.system.model.resp.dashboard.DashboardOverviewCommonResp; import top.continew.admin.system.model.resp.log.LogResp; import top.continew.starter.data.mp.base.BaseMapper; +import java.util.Date; import java.util.List; /** @@ -56,19 +60,54 @@ IPage selectLogPage(@Param("page") IPage page, List selectLogList(@Param(Constants.WRAPPER) QueryWrapper queryWrapper); /** - * 查询仪表盘总计信息 + * 查询总数量 * - * @return 仪表盘总计信息 + * @return 总数量 */ - DashboardTotalResp selectDashboardTotal(); + @Select("SELECT COUNT(*) FROM sys_log") + Long selectTotalCount(); + + /** + * 查询仪表盘 PV 总览 + * + * @return 仪表盘 PV 总览 + */ + DashboardOverviewCommonResp selectDashboardOverviewPv(); + + /** + * 查询仪表盘 IP 总览 + * + * @return 仪表盘 IP 总览 + */ + DashboardOverviewCommonResp selectDashboardOverviewIp(); + + /** + * 查询仪表盘 PV 近 N 月各月份信息 + * + * @param months 近 N 月月份列表 + * @return 仪表盘 PV 近 N 月各月份信息 + */ + @Cached(key = "#months[0]", name = CacheConstants.DASHBOARD_KEY_PREFIX + "PV:") + List selectListDashboardAnalysisPv(@Param("months") List months); + + /** + * 查询仪表盘 IP 近 N 月各月份信息 + * + * @param months 近 N 月月份列表 + * @return 仪表盘 IP 近 N 月各月份信息 + */ + @Cached(key = "#months[0]", name = CacheConstants.DASHBOARD_KEY_PREFIX + "IP:") + List selectListDashboardAnalysisIp(@Param("months") List months); /** * 查询仪表盘访问趋势信息 * - * @param days 日期数 + * @param startTime 开始时间 + * @param endTime 结束时间 * @return 仪表盘访问趋势信息 */ - List selectListDashboardAccessTrend(@Param("days") Integer days); + List selectListDashboardAccessTrend(@Param("startTime") Date startTime, + @Param("endTime") Date endTime); /** * 查询仪表盘访问时段分析信息 diff --git a/continew-admin-system/src/main/java/top/continew/admin/system/model/resp/dashboard/DashboardAccessTrendResp.java b/continew-admin-system/src/main/java/top/continew/admin/system/model/resp/dashboard/DashboardAccessTrendResp.java index a567a608c..dbfef2acd 100644 --- a/continew-admin-system/src/main/java/top/continew/admin/system/model/resp/dashboard/DashboardAccessTrendResp.java +++ b/continew-admin-system/src/main/java/top/continew/admin/system/model/resp/dashboard/DashboardAccessTrendResp.java @@ -17,7 +17,9 @@ package top.continew.admin.system.model.resp.dashboard; import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; import java.io.Serial; import java.io.Serializable; @@ -29,6 +31,8 @@ * @since 2023/9/9 20:20 */ @Data +@NoArgsConstructor +@AllArgsConstructor @Schema(description = "仪表盘-访问趋势信息") public class DashboardAccessTrendResp implements Serializable { diff --git a/continew-admin-system/src/main/java/top/continew/admin/system/model/resp/dashboard/DashboardOverviewCommonResp.java b/continew-admin-system/src/main/java/top/continew/admin/system/model/resp/dashboard/DashboardOverviewCommonResp.java new file mode 100644 index 000000000..fee0080b8 --- /dev/null +++ b/continew-admin-system/src/main/java/top/continew/admin/system/model/resp/dashboard/DashboardOverviewCommonResp.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.admin.system.model.resp.dashboard; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.List; + +/** + * 仪表盘-通用总览信息 + * + * @author Charles7c + * @since 2024/10/19 12:19 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "仪表盘-通用总览信息") +public class DashboardOverviewCommonResp implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 总数 + */ + @Schema(description = "总数", example = "888888") + private Long total; + + /** + * 今日数量 + */ + @Schema(description = "今日数量", example = "888") + private Long today; + + /** + * 较昨日新增(百分比) + */ + @Schema(description = "较昨日新增(百分比)", example = "23.4") + private BigDecimal growth; + + /** + * 图表数据 + */ + @Schema(description = "图表数据") + private List dataList; + + /** + * 昨日数量 + */ + @JsonIgnore + private Long yesterday; +} diff --git a/continew-admin-system/src/main/java/top/continew/admin/system/service/DashboardService.java b/continew-admin-system/src/main/java/top/continew/admin/system/service/DashboardService.java index b0a1c6fb8..f4ea349c8 100644 --- a/continew-admin-system/src/main/java/top/continew/admin/system/service/DashboardService.java +++ b/continew-admin-system/src/main/java/top/continew/admin/system/service/DashboardService.java @@ -29,26 +29,33 @@ public interface DashboardService { /** - * 查询总计信息 + * 查询公告列表 * - * @return 总计信息 + * @return 公告列表 */ - DashboardTotalResp getTotal(); + List listNotice(); /** - * 查询访问趋势信息 + * 查询 PV 总览 * - * @param days 日期数 - * @return 访问趋势信息 + * @return PV 总览 */ - List listAccessTrend(Integer days); + DashboardOverviewCommonResp getOverviewPv(); /** - * 查询公告列表 + * 查询 IP 总览 * - * @return 公告列表 + * @return IP 总览 */ - List listNotice(); + DashboardOverviewCommonResp getOverviewIp(); + + /** + * 查询访问趋势信息 + * + * @param days 日期数 + * @return 访问趋势信息 + */ + List listAccessTrend(Integer days); /** * 查询访问时段分析信息 diff --git a/continew-admin-system/src/main/java/top/continew/admin/system/service/LogService.java b/continew-admin-system/src/main/java/top/continew/admin/system/service/LogService.java index fbbe37f3f..b811e1ddc 100644 --- a/continew-admin-system/src/main/java/top/continew/admin/system/service/LogService.java +++ b/continew-admin-system/src/main/java/top/continew/admin/system/service/LogService.java @@ -18,17 +18,12 @@ import jakarta.servlet.http.HttpServletResponse; import top.continew.admin.system.model.query.LogQuery; -import top.continew.admin.system.model.resp.dashboard.DashboardAccessTrendResp; -import top.continew.admin.system.model.resp.dashboard.DashboardChartCommonResp; -import top.continew.admin.system.model.resp.dashboard.DashboardTotalResp; import top.continew.admin.system.model.resp.log.LogDetailResp; import top.continew.admin.system.model.resp.log.LogResp; import top.continew.starter.extension.crud.model.query.PageQuery; import top.continew.starter.extension.crud.model.query.SortQuery; import top.continew.starter.extension.crud.model.resp.PageResp; -import java.util.List; - /** * 系统日志业务接口 * @@ -71,58 +66,4 @@ public interface LogService { * @param response 响应对象 */ void exportOperationLog(LogQuery query, SortQuery sortQuery, HttpServletResponse response); - - /** - * 查询仪表盘总计信息 - * - * @return 仪表盘总计信息 - */ - DashboardTotalResp getDashboardTotal(); - - /** - * 查询仪表盘访问趋势信息 - * - * @param days 日期数 - * @return 仪表盘访问趋势信息 - */ - List listDashboardAccessTrend(Integer days); - - /** - * 查询仪表盘访问时段分析信息 - * - * @return 仪表盘访问时段分析信息 - */ - List listDashboardAnalysisTimeslot(); - - /** - * 查询仪表盘地域分析信息 - * - * @param top 显示数量 - * @return 仪表盘地域分析信息 - */ - List listDashboardAnalysisGeo(int top); - - /** - * 查询仪表盘模块分析信息 - * - * @param top 显示数量 - * @return 仪表盘模块分析信息 - */ - List listDashboardAnalysisModule(int top); - - /** - * 查询仪表盘终端分析信息 - * - * @param top 显示数量 - * @return 仪表盘终端分析信息 - */ - List listDashboardAnalysisOs(int top); - - /** - * 查询仪表盘浏览器分析信息 - * - * @param top 显示数量 - * @return 仪表盘浏览器分析信息 - */ - List listDashboardAnalysisBrowser(int top); } diff --git a/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/DashboardServiceImpl.java b/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/DashboardServiceImpl.java index 9fadbb929..af3aa8caa 100644 --- a/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/DashboardServiceImpl.java +++ b/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/DashboardServiceImpl.java @@ -16,16 +16,21 @@ package top.continew.admin.system.service.impl; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.*; import cn.hutool.core.util.NumberUtil; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import top.continew.admin.system.model.resp.dashboard.*; +import top.continew.admin.system.mapper.LogMapper; +import top.continew.admin.system.model.resp.dashboard.DashboardAccessTrendResp; +import top.continew.admin.system.model.resp.dashboard.DashboardChartCommonResp; +import top.continew.admin.system.model.resp.dashboard.DashboardNoticeResp; +import top.continew.admin.system.model.resp.dashboard.DashboardOverviewCommonResp; import top.continew.admin.system.service.DashboardService; -import top.continew.admin.system.service.LogService; import top.continew.admin.system.service.NoticeService; import java.math.BigDecimal; -import java.util.List; +import java.util.*; /** * 仪表盘业务实现 @@ -37,54 +42,153 @@ @RequiredArgsConstructor public class DashboardServiceImpl implements DashboardService { - private final LogService logService; + private final LogMapper logMapper; private final NoticeService noticeService; @Override - public DashboardTotalResp getTotal() { - DashboardTotalResp totalResp = logService.getDashboardTotal(); - Long todayPvCount = totalResp.getTodayPvCount(); - Long yesterdayPvCount = totalResp.getYesterdayPvCount(); - BigDecimal newPvCountFromYesterday = NumberUtil.sub(todayPvCount, yesterdayPvCount); - BigDecimal newPvFromYesterday = (0 == yesterdayPvCount) - ? BigDecimal.valueOf(100) - : NumberUtil.round(NumberUtil.mul(NumberUtil.div(newPvCountFromYesterday, yesterdayPvCount), 100), 1); - totalResp.setNewPvFromYesterday(newPvFromYesterday); - return totalResp; + public List listNotice() { + return noticeService.listDashboard(); } @Override - public List listAccessTrend(Integer days) { - return logService.listDashboardAccessTrend(days); + public DashboardOverviewCommonResp getOverviewPv() { + DashboardOverviewCommonResp resp = logMapper.selectDashboardOverviewPv(); + resp.setGrowth(this.calcGrowthFromYesterday(resp.getToday(), resp.getYesterday())); + List last12MonthList = this.getLast12Months(); + List dataList = logMapper.selectListDashboardAnalysisPv(last12MonthList); + if (dataList.size() < 12) { + // 填充缺失的数据 + this.fillMissingDateData(last12MonthList, dataList); + } + resp.setDataList(dataList); + return resp; } @Override - public List listNotice() { - return noticeService.listDashboard(); + public DashboardOverviewCommonResp getOverviewIp() { + DashboardOverviewCommonResp resp = logMapper.selectDashboardOverviewIp(); + resp.setGrowth(this.calcGrowthFromYesterday(resp.getToday(), resp.getYesterday())); + List last12MonthList = this.getLast12Months(); + List dataList = logMapper.selectListDashboardAnalysisIp(last12MonthList); + if (dataList.size() < 12) { + // 填充缺失的数据 + this.fillMissingDateData(last12MonthList, dataList); + } + resp.setDataList(dataList); + return resp; + } + + @Override + public List listAccessTrend(Integer days) { + DateTime currentDate = DateUtil.date(); + Date startTime = DateUtil.beginOfDay(DateUtil.offsetDay(currentDate, -days)).toJdkDate(); + Date endTime = DateUtil.endOfDay(DateUtil.offsetDay(currentDate, -1)).toJdkDate(); + List list = logMapper.selectListDashboardAccessTrend(startTime, endTime); + if (list.size() < days) { + List all = DateUtil.rangeToList(startTime, endTime, DateField.DAY_OF_MONTH) + .stream() + .map(date -> date.toString(DatePattern.NORM_DATE_FORMAT)) + .toList(); + Collection missings = CollUtil.disjunction(all, list.stream() + .map(DashboardAccessTrendResp::getDate) + .toList()); + list.addAll(missings.stream().map(missing -> new DashboardAccessTrendResp(missing, 0L, 0L)).toList()); + list.sort(Comparator.comparing(DashboardAccessTrendResp::getDate)); + } + return list; } @Override public List getAnalysisTimeslot() { - return logService.listDashboardAnalysisTimeslot(); + List list = logMapper.selectListDashboardAnalysisTimeslot(); + if (list.size() < 12) { + // 获取所有时间段 + List allTimeSlotList = new ArrayList<>(12); + for (int hour = 0; hour < 24; hour += 2) { + allTimeSlotList.add(String.format("%02d:00", hour)); + } + // 填充缺失的数据 + this.fillMissingDateData(allTimeSlotList, list); + } + return list; } @Override public List getAnalysisGeo() { - return logService.listDashboardAnalysisGeo(10); + List list = logMapper.selectListDashboardAnalysisGeo(9); + return this.buildOtherPieChartData(list); } @Override public List getAnalysisModule() { - return logService.listDashboardAnalysisModule(5); + return logMapper.selectListDashboardAnalysisModule(10); } @Override public List getAnalysisOs() { - return logService.listDashboardAnalysisOs(5); + List list = logMapper.selectListDashboardAnalysisOs(4); + return this.buildOtherPieChartData(list); } @Override public List getAnalysisBrowser() { - return logService.listDashboardAnalysisBrowser(5); + List list = logMapper.selectListDashboardAnalysisBrowser(4); + return this.buildOtherPieChartData(list); + } + + /** + * 计算增长百分比 + * + * @param today 今日数量 + * @param yesterday 昨日数量 + * @return 增长百分比 + */ + private BigDecimal calcGrowthFromYesterday(Long today, Long yesterday) { + return (0 == yesterday) + ? BigDecimal.valueOf(100) + : NumberUtil.round(NumberUtil.mul(NumberUtil.div(NumberUtil.sub(today, yesterday), yesterday), 100), 1); + } + + /** + * 构建其他饼图数据 + * + * @param list 饼图数据列表 + * @return 饼图数据列表 + */ + private List buildOtherPieChartData(List list) { + Long totalCount = logMapper.selectTotalCount(); + long sumCount = list.stream().mapToLong(DashboardChartCommonResp::getValue).sum(); + if (sumCount < totalCount) { + list.add(new DashboardChartCommonResp("其他", totalCount - sumCount)); + } + return list; + } + + /** + * 填充缺失时间段的数据 + * + * @param all 所有时间段 + * @param list 待填充数据 + */ + private void fillMissingDateData(List all, List list) { + Collection missings = CollUtil.disjunction(all, list.stream() + .map(DashboardChartCommonResp::getName) + .toList()); + list.addAll(missings.stream().map(missing -> new DashboardChartCommonResp(missing, 0L)).toList()); + list.sort(Comparator.comparing(DashboardChartCommonResp::getName)); + } + + /** + * 获取最近12个月的月份列表 + * + * @return 月份列表 + */ + private List getLast12Months() { + DateTime currentMonth = DateUtil.beginOfMonth(DateUtil.date()); + return DateUtil.rangeToList(DateUtil.offsetMonth(currentMonth, -12), DateUtil + .offsetMonth(currentMonth, -1), DateField.MONTH) + .stream() + .map(dateTime -> DateUtil.format(dateTime, DatePattern.NORM_MONTH_FORMAT)) + .toList(); } } diff --git a/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/LogServiceImpl.java b/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/LogServiceImpl.java index 7b90f2753..219814b77 100644 --- a/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/LogServiceImpl.java +++ b/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/LogServiceImpl.java @@ -33,9 +33,6 @@ import top.continew.admin.system.mapper.LogMapper; import top.continew.admin.system.model.entity.LogDO; import top.continew.admin.system.model.query.LogQuery; -import top.continew.admin.system.model.resp.dashboard.DashboardAccessTrendResp; -import top.continew.admin.system.model.resp.dashboard.DashboardChartCommonResp; -import top.continew.admin.system.model.resp.dashboard.DashboardTotalResp; import top.continew.admin.system.model.resp.log.LogDetailResp; import top.continew.admin.system.model.resp.log.LogResp; import top.continew.admin.system.model.resp.log.LoginLogExportResp; @@ -47,8 +44,6 @@ import top.continew.starter.extension.crud.model.resp.PageResp; import top.continew.starter.file.excel.util.ExcelUtils; -import java.util.ArrayList; -import java.util.Comparator; import java.util.Date; import java.util.List; @@ -95,75 +90,6 @@ public void exportOperationLog(LogQuery query, SortQuery sortQuery, HttpServletR ExcelUtils.export(list, "导出操作日志数据", OperationLogExportResp.class, response); } - @Override - public DashboardTotalResp getDashboardTotal() { - return baseMapper.selectDashboardTotal(); - } - - @Override - public List listDashboardAccessTrend(Integer days) { - return baseMapper.selectListDashboardAccessTrend(days); - } - - @Override - public List listDashboardAnalysisTimeslot() { - List list = baseMapper.selectListDashboardAnalysisTimeslot(); - if (list.size() < 12) { - // 获取所有时间段 - List allTimeSlots = new ArrayList<>(); - for (int hour = 0; hour < 24; hour += 2) { - String timeSlot = String.format("%02d:00", hour); - allTimeSlots.add(timeSlot); - } - // 补充缺失的时间段 - List missingTimeSlots = allTimeSlots.stream() - .filter(timeSlot -> list.stream().noneMatch(item -> item.getName().equals(timeSlot))) - .toList(); - list.addAll(missingTimeSlots.stream().map(timeSlot -> new DashboardChartCommonResp(timeSlot, 0L)).toList()); - list.sort(Comparator.comparing(DashboardChartCommonResp::getName)); - } - return list; - } - - @Override - public List listDashboardAnalysisGeo(int top) { - List list = baseMapper.selectListDashboardAnalysisGeo(top > 1 ? top - 1 : top); - return this.buildOtherPieChartData(list); - } - - @Override - public List listDashboardAnalysisModule(int top) { - List list = baseMapper.selectListDashboardAnalysisModule(top > 1 ? top - 1 : top); - return this.buildOtherPieChartData(list); - } - - @Override - public List listDashboardAnalysisOs(int top) { - List list = baseMapper.selectListDashboardAnalysisOs(top > 1 ? top - 1 : top); - return this.buildOtherPieChartData(list); - } - - @Override - public List listDashboardAnalysisBrowser(int top) { - List list = baseMapper.selectListDashboardAnalysisBrowser(top > 1 ? top - 1 : top); - return this.buildOtherPieChartData(list); - } - - /** - * 构建其他饼图数据 - * - * @param list 饼图数据列表 - * @return 饼图数据列表 - */ - private List buildOtherPieChartData(List list) { - Long totalCount = baseMapper.lambdaQuery().count(); - long sumCount = list.stream().mapToLong(DashboardChartCommonResp::getValue).sum(); - if (sumCount < totalCount) { - list.add(new DashboardChartCommonResp("其他", totalCount - sumCount)); - } - return list; - } - /** * 查询列表 * diff --git a/continew-admin-system/src/main/resources/mapper/LogMapper.xml b/continew-admin-system/src/main/resources/mapper/LogMapper.xml index 7d20f9b45..6269f91b4 100644 --- a/continew-admin-system/src/main/resources/mapper/LogMapper.xml +++ b/continew-admin-system/src/main/resources/mapper/LogMapper.xml @@ -41,12 +41,46 @@ ${ew.customSqlSegment} - SELECT - (SELECT COUNT(*) FROM sys_log) AS pvCount, - (SELECT COUNT(DISTINCT ip) FROM sys_log) AS ipCount, - (SELECT COUNT(*) FROM sys_log WHERE DATE(create_time) = CURRENT_DATE) AS todayPvCount, - (SELECT COUNT(*) FROM sys_log WHERE DATE(create_time) = CURRENT_DATE - 1) AS yesterdayPvCount + (SELECT COUNT(*) FROM sys_log) AS total, + (SELECT COUNT(*) FROM sys_log WHERE DATE(create_time) = CURRENT_DATE) AS today, + (SELECT COUNT(*) FROM sys_log WHERE DATE(create_time) = CURRENT_DATE - 1) AS yesterday + + + + + + + listNotice() { return dashboardService.listNotice(); } + @Operation(summary = "查询PV总览", description = "查询PV总览") + @GetMapping("/analysis/overview/pv") + public DashboardOverviewCommonResp getOverviewPv() { + return dashboardService.getOverviewPv(); + } + + @Operation(summary = "查询IP总览", description = "查询IP总览") + @GetMapping("/analysis/overview/ip") + public DashboardOverviewCommonResp getOverviewIp() { + return dashboardService.getOverviewIp(); + } + @Operation(summary = "查询访问趋势信息", description = "查询访问趋势信息") @Parameter(name = "days", description = "日期数", example = "30", in = ParameterIn.PATH) @GetMapping("/access/trend/{days}")