zjk
2026-09-29 54dcf0a82e7490fa58b1c056d5c0b9cb739c2931
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package com.tcm.training.admin.statistics.service;
 
import com.tcm.training.admin.statistics.mapper.ContentStatisticsMapper;
import com.tcm.training.admin.statistics.row.ContentStatisticsDailyRow;
import com.tcm.training.admin.statistics.vo.ContentStatisticsOverviewVO;
import com.tcm.training.admin.statistics.vo.ContentStatisticsTrendItemVO;
import com.tcm.training.admin.statistics.vo.ContentStatisticsVO;
import org.springframework.stereotype.Service;
 
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
@Service
public class ContentStatisticsAppService {
 
    private final ContentStatisticsMapper contentStatisticsMapper;
 
    public ContentStatisticsAppService(ContentStatisticsMapper contentStatisticsMapper) {
        this.contentStatisticsMapper = contentStatisticsMapper;
    }
 
    public ContentStatisticsVO statistics(LocalDate dateFrom, LocalDate dateTo) {
        DateRange range = normalizeRange(dateFrom, dateTo);
        List<ContentStatisticsDailyRow> rows = contentStatisticsMapper.selectDailyStatistics(
                range.getStart().atStartOfDay(),
                LocalDateTime.of(range.getEnd(), LocalTime.MAX)
        );
 
        Map<LocalDate, ContentStatisticsDailyRow> rowMap = new HashMap<LocalDate, ContentStatisticsDailyRow>();
        for (ContentStatisticsDailyRow row : rows) {
            rowMap.put(row.getStatDate(), row);
        }
 
        ContentStatisticsOverviewVO overview = new ContentStatisticsOverviewVO();
        overview.setVideoPlayCount(0L);
        overview.setCourseFavoriteCount(0L);
        overview.setPointsEarnedCount(0L);
        overview.setConsultClickCount(0L);
 
        List<ContentStatisticsTrendItemVO> contentTrend = new ArrayList<ContentStatisticsTrendItemVO>();
        List<ContentStatisticsTrendItemVO> pointsTrend = new ArrayList<ContentStatisticsTrendItemVO>();
 
        LocalDate cursor = range.getStart();
        while (!cursor.isAfter(range.getEnd())) {
            ContentStatisticsDailyRow row = rowMap.get(cursor);
            Long videoPlayCount = nvl(row == null ? null : row.getVideoPlayCount());
            Long courseFavoriteCount = nvl(row == null ? null : row.getCourseFavoriteCount());
            Long consultClickCount = nvl(row == null ? null : row.getConsultClickCount());
            Long pointsEarnedCount = nvl(row == null ? null : row.getPointsEarnedCount());
 
            ContentStatisticsTrendItemVO contentTrendItem = new ContentStatisticsTrendItemVO();
            contentTrendItem.setDate(cursor.toString());
            contentTrendItem.setVideoPlayCount(videoPlayCount);
            contentTrendItem.setCourseFavoriteCount(courseFavoriteCount);
            contentTrendItem.setConsultClickCount(consultClickCount);
            contentTrend.add(contentTrendItem);
 
            ContentStatisticsTrendItemVO pointsTrendItem = new ContentStatisticsTrendItemVO();
            pointsTrendItem.setDate(cursor.toString());
            pointsTrendItem.setPointsEarnedCount(pointsEarnedCount);
            pointsTrend.add(pointsTrendItem);
 
            overview.setVideoPlayCount(overview.getVideoPlayCount() + videoPlayCount);
            overview.setCourseFavoriteCount(overview.getCourseFavoriteCount() + courseFavoriteCount);
            overview.setConsultClickCount(overview.getConsultClickCount() + consultClickCount);
            overview.setPointsEarnedCount(overview.getPointsEarnedCount() + pointsEarnedCount);
            cursor = cursor.plusDays(1);
        }
 
        ContentStatisticsVO result = new ContentStatisticsVO();
        result.setOverview(overview);
        result.setContentTrend(contentTrend);
        result.setPointsTrend(pointsTrend);
        return result;
    }
 
    private DateRange normalizeRange(LocalDate dateFrom, LocalDate dateTo) {
        LocalDate start = dateFrom;
        LocalDate end = dateTo;
        if (start == null && end == null) {
            start = LocalDate.now();
            end = start;
        } else if (start == null) {
            start = end;
        } else if (end == null) {
            end = start;
        }
        if (start.isAfter(end)) {
            throw new IllegalArgumentException("开始日期不能晚于结束日期");
        }
        return new DateRange(start, end);
    }
 
    private Long nvl(Long value) {
        return value == null ? 0L : value;
    }
 
    private static class DateRange {
        private final LocalDate start;
        private final LocalDate end;
 
        private DateRange(LocalDate start, LocalDate end) {
            this.start = start;
            this.end = end;
        }
 
        private LocalDate getStart() {
            return start;
        }
 
        private LocalDate getEnd() {
            return end;
        }
    }
}