Merge pull request '饮水量统计接口' (#105) from junmao_branch into develop

pull/106/head
p95fco63j 3 weeks ago
commit 53c3bb5ada

@ -0,0 +1,56 @@
package com.campus.water.controller;
import com.campus.water.entity.dto.request.StudentDrinkQueryDTO;
import com.campus.water.entity.vo.StudentDrinkStatsVO;
import com.campus.water.service.StudentDrinkStatsService;
import com.campus.water.util.ResultVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
*
*/
@RestController
@RequestMapping("/api/student/drink-stats")
@RequiredArgsConstructor
@Tag(name = "学生端-饮水量统计", description = "学生查看本日/本周/本月饮水量")
public class StudentDrinkStatsController {
private final StudentDrinkStatsService drinkStatsService;
@PostMapping("/today")
@Operation(summary = "查询本日饮水量", description = "获取学生当日的饮水量、次数及明细")
public ResultVO<StudentDrinkStatsVO> getTodayStats(@RequestBody StudentDrinkQueryDTO request) {
// 手动校验学生ID非空
if (request.getStudentId() == null || request.getStudentId().trim().isEmpty()) {
return ResultVO.badRequest("学生ID不能为空");
}
StudentDrinkStatsVO stats = drinkStatsService.getTodayDrinkStats(request.getStudentId());
return ResultVO.success(stats, "查询本日饮水量成功");
}
@PostMapping("/this-week")
@Operation(summary = "查询本周饮水量", description = "获取学生本周的饮水量、日均量及每日明细")
public ResultVO<StudentDrinkStatsVO> getThisWeekStats(@RequestBody StudentDrinkQueryDTO request) {
if (request.getStudentId() == null || request.getStudentId().trim().isEmpty()) {
return ResultVO.badRequest("学生ID不能为空");
}
StudentDrinkStatsVO stats = drinkStatsService.getThisWeekDrinkStats(request.getStudentId());
return ResultVO.success(stats, "查询本周饮水量成功");
}
@PostMapping("/this-month")
@Operation(summary = "查询本月饮水量", description = "获取学生本月的饮水量、日均量及每日明细")
public ResultVO<StudentDrinkStatsVO> getThisMonthStats(@RequestBody StudentDrinkQueryDTO request) {
if (request.getStudentId() == null || request.getStudentId().trim().isEmpty()) {
return ResultVO.badRequest("学生ID不能为空");
}
StudentDrinkStatsVO stats = drinkStatsService.getThisMonthDrinkStats(request.getStudentId());
return ResultVO.success(stats, "查询本月饮水量成功");
}
}

@ -0,0 +1,12 @@
package com.campus.water.entity.dto.request;
import lombok.Data;
/**
* DTO
*/
@Data
public class StudentDrinkQueryDTO {
/** 学生ID */
private String studentId;
}

@ -0,0 +1,16 @@
package com.campus.water.entity.vo;
import lombok.Data;
/**
* VO
*/
@Data
public class DailyDrinkVO {
/** 日期yyyy-MM-dd */
private String date;
/** 当日饮水量(升) */
private Double consumption;
/** 当日饮水次数 */
private Integer count;
}

@ -0,0 +1,28 @@
package com.campus.water.entity.vo;
import lombok.Data;
import java.util.List;
import com.campus.water.entity.DrinkRecord;
import com.campus.water.entity.vo.DailyDrinkVO;
/**
* VO
*/
@Data
public class StudentDrinkStatsVO {
/** 学生ID */
private String studentId;
/** 统计维度(本日/本周/本月) */
private String timeDimension;
/** 统计时间范围(如"2025-12-25~2025-12-25" */
private String timeRange;
/** 总饮水量(升) */
private Double totalConsumption;
/** 日均饮水量(升) */
private Double avgDailyConsumption;
/** 饮水次数 */
private Integer drinkCount;
/** 按日期分组的每日饮水量明细 */
private List<DailyDrinkVO> dailyDetails;
/** 所有饮水记录明细 */
private List<DrinkRecord> drinkRecords;
}

@ -0,0 +1,105 @@
package com.campus.water.service;
import com.campus.water.entity.DrinkRecord;
import com.campus.water.entity.vo.DailyDrinkVO;
import com.campus.water.entity.vo.StudentDrinkStatsVO;
import com.campus.water.mapper.DrinkRecordRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.time.*;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;
/**
*
*/
@Service
@RequiredArgsConstructor
public class StudentDrinkStatsService {
private final DrinkRecordRepository drinkRecordRepository;
/**
*
*/
public StudentDrinkStatsVO getTodayDrinkStats(String studentId) {
LocalDate today = LocalDate.now();
LocalDateTime start = today.atStartOfDay();
LocalDateTime end = LocalDateTime.now();
return calculateStats(studentId, start, end, "本日", "today");
}
/**
*
*/
public StudentDrinkStatsVO getThisWeekDrinkStats(String studentId) {
LocalDate today = LocalDate.now();
LocalDateTime start = today.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).atStartOfDay();
LocalDateTime end = LocalDateTime.now();
return calculateStats(studentId, start, end, "本周", "thisWeek");
}
/**
*
*/
public StudentDrinkStatsVO getThisMonthDrinkStats(String studentId) {
LocalDate today = LocalDate.now();
LocalDateTime start = today.with(TemporalAdjusters.firstDayOfMonth()).atStartOfDay();
LocalDateTime end = LocalDateTime.now();
return calculateStats(studentId, start, end, "本月", "thisMonth");
}
/**
*
*/
private StudentDrinkStatsVO calculateStats(String studentId, LocalDateTime start, LocalDateTime end,
String timeRangeDesc, String timeDimension) {
// 1. 查询时间范围内的饮水记录
List<DrinkRecord> records = drinkRecordRepository
.findByStudentIdAndDrinkTimeBetweenOrdered(studentId, start, end);
// 2. 按日期分组统计
Map<LocalDate, List<DrinkRecord>> dailyGroup = records.stream()
.collect(Collectors.groupingBy(record -> record.getDrinkTime().toLocalDate()));
// 3. 构建每日明细
List<DailyDrinkVO> dailyDetails = new ArrayList<>();
dailyGroup.forEach((date, dailyRecords) -> {
DailyDrinkVO dailyVO = new DailyDrinkVO();
dailyVO.setDate(date.toString());
// 当日总饮水量
double dailyTotal = dailyRecords.stream()
.map(DrinkRecord::getWaterConsumption)
.filter(Objects::nonNull)
.mapToDouble(BigDecimal::doubleValue)
.sum();
dailyVO.setConsumption(dailyTotal);
dailyVO.setCount(dailyRecords.size());
dailyDetails.add(dailyVO);
});
// 按日期排序
dailyDetails.sort(Comparator.comparing(DailyDrinkVO::getDate));
// 4. 计算总饮水量、总次数、日均饮水量
double totalConsumption = dailyDetails.stream()
.mapToDouble(DailyDrinkVO::getConsumption)
.sum();
int totalCount = records.size();
double avgDaily = dailyDetails.isEmpty() ? 0 : totalConsumption / dailyDetails.size();
// 5. 封装结果VO
StudentDrinkStatsVO statsVO = new StudentDrinkStatsVO();
statsVO.setStudentId(studentId);
statsVO.setTimeDimension(timeDimension);
statsVO.setTimeRange(timeRangeDesc + "(" + start.toLocalDate() + "~" + end.toLocalDate() + ")");
statsVO.setTotalConsumption(totalConsumption);
statsVO.setDrinkCount(totalCount);
statsVO.setAvgDailyConsumption(avgDaily);
statsVO.setDailyDetails(dailyDetails);
statsVO.setDrinkRecords(records);
return statsVO;
}
}
Loading…
Cancel
Save