“mitao”
2026-03-27 cde5977f64ff1dfa928d1076c059e8865c02d70b
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package com.tcm.training.admin.statistics.service;
 
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tcm.training.admin.live.entity.HealthCourse;
import com.tcm.training.admin.live.mapper.HealthCourseMapper;
import com.tcm.training.admin.member.entity.AppUser;
import com.tcm.training.admin.member.mapper.UserMapper;
import com.tcm.training.admin.points.entity.PointsExchangeOrder;
import com.tcm.training.admin.points.mapper.PointsExchangeOrderMapper;
import com.tcm.training.admin.statistics.mapper.RevenueStatisticsMapper;
import com.tcm.training.admin.statistics.mapper.UserStatisticsMapper;
import com.tcm.training.admin.statistics.row.RevenueStatisticsDailyRow;
import com.tcm.training.admin.statistics.row.UserStatisticsRegisterTrendRow;
import com.tcm.training.admin.statistics.vo.HomeDashboardOverviewVO;
import com.tcm.training.admin.statistics.vo.HomeDashboardRevenueTrendItemVO;
import com.tcm.training.admin.statistics.vo.HomeDashboardUserTrendItemVO;
import com.tcm.training.admin.statistics.vo.HomeDashboardVO;
import com.tcm.training.admin.trade.service.PaymentFlowAppService;
import org.springframework.stereotype.Service;
 
import java.math.BigDecimal;
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 HomeDashboardAppService {
 
    private static final int HOME_RECENT_DAYS = 7;
 
    private final UserMapper userMapper;
    private final HealthCourseMapper healthCourseMapper;
    private final PointsExchangeOrderMapper pointsExchangeOrderMapper;
    private final UserStatisticsMapper userStatisticsMapper;
    private final RevenueStatisticsMapper revenueStatisticsMapper;
    private final PaymentFlowAppService paymentFlowAppService;
 
    public HomeDashboardAppService(UserMapper userMapper,
                                   HealthCourseMapper healthCourseMapper,
                                   PointsExchangeOrderMapper pointsExchangeOrderMapper,
                                   UserStatisticsMapper userStatisticsMapper,
                                   RevenueStatisticsMapper revenueStatisticsMapper,
                                   PaymentFlowAppService paymentFlowAppService) {
        this.userMapper = userMapper;
        this.healthCourseMapper = healthCourseMapper;
        this.pointsExchangeOrderMapper = pointsExchangeOrderMapper;
        this.userStatisticsMapper = userStatisticsMapper;
        this.revenueStatisticsMapper = revenueStatisticsMapper;
        this.paymentFlowAppService = paymentFlowAppService;
    }
 
    public HomeDashboardVO dashboard() {
        LocalDate endDate = LocalDate.now();
        LocalDate startDate = endDate.minusDays(HOME_RECENT_DAYS - 1L);
        LocalDateTime startTime = startDate.atStartOfDay();
        LocalDateTime endTime = LocalDateTime.of(endDate, LocalTime.MAX);
 
        paymentFlowAppService.syncFlows();
 
        HomeDashboardVO result = new HomeDashboardVO();
        result.setOverview(buildOverview());
        result.setUserRegisterTrend(buildUserRegisterTrend(
                userStatisticsMapper.selectRegisterTrend(null, startTime, endTime),
                startDate,
                endDate
        ));
        result.setRevenueTrend(buildRevenueTrend(
                revenueStatisticsMapper.selectDailyStatistics(null, startTime, endTime),
                startDate,
                endDate
        ));
        result.setPendingPointsExchangeShipmentCount(countPendingPointsExchangeShipment());
        return result;
    }
 
    private HomeDashboardOverviewVO buildOverview() {
        HomeDashboardOverviewVO overview = new HomeDashboardOverviewVO();
        overview.setRegisteredUserCount(userMapper.selectCount(new LambdaQueryWrapper<AppUser>()
                .eq(AppUser::getDeleted, 0)));
        overview.setRegisteredDoctorCount(userMapper.selectCount(new LambdaQueryWrapper<AppUser>()
                .eq(AppUser::getDeleted, 0)
                .eq(AppUser::getType, 1)));
        overview.setMemberUserCount(userMapper.selectCount(new LambdaQueryWrapper<AppUser>()
                .eq(AppUser::getDeleted, 0)
                .isNotNull(AppUser::getMemberExpireAt)
                .gt(AppUser::getMemberExpireAt, LocalDateTime.now())));
        overview.setHealthCourseCount(healthCourseMapper.selectCount(new LambdaQueryWrapper<HealthCourse>()
                .eq(HealthCourse::getDeleted, 0)));
        return overview;
    }
 
    private List<HomeDashboardUserTrendItemVO> buildUserRegisterTrend(List<UserStatisticsRegisterTrendRow> rows,
                                                                      LocalDate startDate,
                                                                      LocalDate endDate) {
        Map<LocalDate, UserStatisticsRegisterTrendRow> rowMap = new HashMap<LocalDate, UserStatisticsRegisterTrendRow>();
        for (UserStatisticsRegisterTrendRow row : rows) {
            rowMap.put(row.getStatDate(), row);
        }
 
        List<HomeDashboardUserTrendItemVO> result = new ArrayList<HomeDashboardUserTrendItemVO>();
        LocalDate cursor = startDate;
        while (!cursor.isAfter(endDate)) {
            UserStatisticsRegisterTrendRow row = rowMap.get(cursor);
            HomeDashboardUserTrendItemVO item = new HomeDashboardUserTrendItemVO();
            item.setDate(cursor.toString());
            item.setRegisteredUserCount(nvl(row == null ? null : row.getRegisteredUserCount()));
            result.add(item);
            cursor = cursor.plusDays(1);
        }
        return result;
    }
 
    private List<HomeDashboardRevenueTrendItemVO> buildRevenueTrend(List<RevenueStatisticsDailyRow> rows,
                                                                    LocalDate startDate,
                                                                    LocalDate endDate) {
        Map<LocalDate, RevenueStatisticsDailyRow> rowMap = new HashMap<LocalDate, RevenueStatisticsDailyRow>();
        for (RevenueStatisticsDailyRow row : rows) {
            rowMap.put(row.getStatDate(), row);
        }
 
        List<HomeDashboardRevenueTrendItemVO> result = new ArrayList<HomeDashboardRevenueTrendItemVO>();
        LocalDate cursor = startDate;
        while (!cursor.isAfter(endDate)) {
            RevenueStatisticsDailyRow row = rowMap.get(cursor);
            HomeDashboardRevenueTrendItemVO item = new HomeDashboardRevenueTrendItemVO();
            item.setDate(cursor.toString());
            item.setHealthIncome(nvl(row == null ? null : row.getHealthIncome()));
            item.setMemberIncome(nvl(row == null ? null : row.getMemberIncome()));
            result.add(item);
            cursor = cursor.plusDays(1);
        }
        return result;
    }
 
    private Long countPendingPointsExchangeShipment() {
        return pointsExchangeOrderMapper.selectCount(new LambdaQueryWrapper<PointsExchangeOrder>()
                .eq(PointsExchangeOrder::getDeleted, 0)
                .eq(PointsExchangeOrder::getStatus, 0));
    }
 
    private Long nvl(Long value) {
        return value == null ? 0L : value;
    }
 
    private BigDecimal nvl(BigDecimal value) {
        return value == null ? BigDecimal.ZERO : value;
    }
}