新增答辩用后台管理系统
This commit is contained in:
+2
-2
@@ -26,7 +26,7 @@ public class DataStatisticsDao {
|
||||
* 统计指定时间范围内新增会员数
|
||||
*/
|
||||
public Mono<Long> countNewMembers(LocalDateTime startTime, LocalDateTime endTime) {
|
||||
return databaseClient.sql("SELECT COUNT(*) FROM member_user WHERE created_at >= :startTime AND created_at < :endTime AND is_deleted = false")
|
||||
return databaseClient.sql("SELECT COUNT(*) FROM member_user WHERE created_at >= :startTime AND created_at < :endTime AND deleted_at IS NULL")
|
||||
.bind("startTime", startTime)
|
||||
.bind("endTime", endTime)
|
||||
.map(row -> row.get(0, Long.class))
|
||||
@@ -37,7 +37,7 @@ public class DataStatisticsDao {
|
||||
* 统计总会员数
|
||||
*/
|
||||
public Mono<Long> countTotalMembers() {
|
||||
return databaseClient.sql("SELECT COUNT(*) FROM member_user WHERE is_deleted = false")
|
||||
return databaseClient.sql("SELECT COUNT(*) FROM member_user WHERE deleted_at IS NULL")
|
||||
.map(row -> row.get(0, Long.class))
|
||||
.one();
|
||||
}
|
||||
|
||||
+5
@@ -4,6 +4,8 @@ import cn.novalon.gym.manage.datacount.domain.*;
|
||||
import cn.novalon.gym.manage.datacount.service.IDataStatisticsService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -25,6 +27,8 @@ import java.time.format.DateTimeFormatter;
|
||||
@Tag(name = "数据统计", description = "数据统计相关操作")
|
||||
public class DataStatisticsHandler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DataStatisticsHandler.class);
|
||||
|
||||
@Autowired
|
||||
private IDataStatisticsService dataStatisticsService;
|
||||
|
||||
@@ -35,6 +39,7 @@ public class DataStatisticsHandler {
|
||||
return dataStatisticsService.getStatisticsSummaryWithCache(query)
|
||||
.flatMap(summary -> ServerResponse.ok().bodyValue(summary))
|
||||
.onErrorResume(e -> {
|
||||
log.error("获取综合统计数据失败", e);
|
||||
StatisticsSummary errorSummary = StatisticsSummary.builder()
|
||||
.statDate(LocalDateTime.now().toLocalDate().toString())
|
||||
.generatedAt(LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME))
|
||||
|
||||
+82
-9
@@ -13,6 +13,7 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
@@ -22,7 +23,9 @@ import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.TemporalAdjusters;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -173,9 +176,25 @@ public class DataStatisticsServiceImpl implements IDataStatisticsService {
|
||||
|
||||
@Override
|
||||
public Mono<StatisticsSummary> getStatisticsSummary(StatisticsQuery query) {
|
||||
Mono<MemberStatistics> memberStatsMono = getMemberStatistics(query);
|
||||
Mono<BookingStatistics> bookingStatsMono = getBookingStatistics(query);
|
||||
Mono<SignInStatistics> signInStatsMono = getSignInStatistics(query);
|
||||
String statDate = query.getStartTime() != null
|
||||
? query.getStartTime().toLocalDate().toString()
|
||||
: LocalDateTime.now().toLocalDate().toString();
|
||||
|
||||
Mono<MemberStatistics> memberStatsMono = getMemberStatistics(query)
|
||||
.onErrorResume(e -> {
|
||||
log.error("获取会员统计数据失败", e);
|
||||
return Mono.just(MemberStatistics.builder().statDate(statDate).build());
|
||||
});
|
||||
Mono<BookingStatistics> bookingStatsMono = getBookingStatistics(query)
|
||||
.onErrorResume(e -> {
|
||||
log.error("获取预约统计数据失败", e);
|
||||
return Mono.just(BookingStatistics.builder().statDate(statDate).build());
|
||||
});
|
||||
Mono<SignInStatistics> signInStatsMono = getSignInStatistics(query)
|
||||
.onErrorResume(e -> {
|
||||
log.error("获取签到统计数据失败", e);
|
||||
return Mono.just(SignInStatistics.builder().statDate(statDate).build());
|
||||
});
|
||||
|
||||
return Mono.zip(memberStatsMono, bookingStatsMono, signInStatsMono)
|
||||
.map(tuple -> StatisticsSummary.builder()
|
||||
@@ -188,21 +207,75 @@ public class DataStatisticsServiceImpl implements IDataStatisticsService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public reactor.core.publisher.Flux<DataStatistics> queryHistoricalStatistics(StatisticsQuery query) {
|
||||
public Flux<DataStatistics> queryHistoricalStatistics(StatisticsQuery query) {
|
||||
// 历史统计数据查询(从Redis缓存中获取)
|
||||
String cacheKey = buildCacheKey(query);
|
||||
return redisUtil.get(cacheKey, String.class)
|
||||
.flatMapMany(json -> {
|
||||
try {
|
||||
java.util.List<DataStatistics> stats = objectMapper.readValue(json,
|
||||
objectMapper.getTypeFactory().constructCollectionType(java.util.List.class, DataStatistics.class));
|
||||
return reactor.core.publisher.Flux.fromIterable(stats);
|
||||
List<DataStatistics> stats = objectMapper.readValue(json,
|
||||
objectMapper.getTypeFactory().constructCollectionType(List.class, DataStatistics.class));
|
||||
return Flux.fromIterable(stats);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to parse historical statistics from cache", e);
|
||||
return reactor.core.publisher.Flux.empty();
|
||||
return Flux.empty();
|
||||
}
|
||||
})
|
||||
.switchIfEmpty(reactor.core.publisher.Flux.empty());
|
||||
.switchIfEmpty(buildLiveStatistics(query));
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存未命中时,从数据库实时构建统计数据
|
||||
*/
|
||||
private Flux<DataStatistics> buildLiveStatistics(StatisticsQuery query) {
|
||||
LocalDateTime startTime = getStartTime(query);
|
||||
LocalDateTime endTime = getEndTime(query);
|
||||
String periodType = query.getPeriodType() != null ? query.getPeriodType() : "DAY";
|
||||
LocalDateTime statDate = endTime;
|
||||
|
||||
Mono<Long> memberCountMono = dataStatisticsDao.countNewMembers(startTime, endTime);
|
||||
Mono<Long> totalMembersMono = dataStatisticsDao.countTotalMembers();
|
||||
Mono<Long> bookingCountMono = dataStatisticsDao.countBookings(startTime, endTime);
|
||||
Mono<Long> signInCountMono = dataStatisticsDao.countSignIns(startTime, endTime);
|
||||
|
||||
return Mono.zip(memberCountMono, totalMembersMono, bookingCountMono, signInCountMono)
|
||||
.flatMapMany(tuple -> {
|
||||
long newMembers = tuple.getT1() != null ? tuple.getT1() : 0L;
|
||||
long totalMembers = tuple.getT2() != null ? tuple.getT2() : 0L;
|
||||
long bookings = tuple.getT3() != null ? tuple.getT3() : 0L;
|
||||
long signIns = tuple.getT4() != null ? tuple.getT4() : 0L;
|
||||
|
||||
List<DataStatistics> list = new ArrayList<>();
|
||||
|
||||
DataStatistics memberStat = DataStatistics.builder()
|
||||
.statType(DataStatistics.StatType.MEMBER)
|
||||
.periodType(periodType)
|
||||
.statDate(statDate)
|
||||
.count(totalMembers)
|
||||
.extraData("新增" + newMembers + "人")
|
||||
.build();
|
||||
list.add(memberStat);
|
||||
|
||||
DataStatistics bookingStat = DataStatistics.builder()
|
||||
.statType(DataStatistics.StatType.BOOKING)
|
||||
.periodType(periodType)
|
||||
.statDate(statDate)
|
||||
.count(bookings)
|
||||
.extraData("新增" + bookings + "条预约")
|
||||
.build();
|
||||
list.add(bookingStat);
|
||||
|
||||
DataStatistics signInStat = DataStatistics.builder()
|
||||
.statType(DataStatistics.StatType.SIGN_IN)
|
||||
.periodType(periodType)
|
||||
.statDate(statDate)
|
||||
.count(signIns)
|
||||
.extraData("新增" + signIns + "次签到")
|
||||
.build();
|
||||
list.add(signInStat);
|
||||
|
||||
return Flux.fromIterable(list);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user