移动端首页手表数据修改

This commit is contained in:
wanghao
2026-03-03 10:13:15 +08:00
parent 98dc17552d
commit 291f6a4eaa
4 changed files with 107 additions and 17 deletions
@@ -12,6 +12,8 @@ import java.util.Date;
*/
@Data
public class UserStat {
/** 数据类型:0=心率 1=血氧 2=压力 3=体温 4=睡眠 */
private String type;
private BigDecimal latest;
private BigDecimal max;
private BigDecimal min;
@@ -20,6 +20,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
import java.util.List;
import java.util.Map;
@RestController
@@ -41,6 +42,16 @@ public class WatchDataApiController {
return Result.ok(watchDataApiService.userStatResult(type));
}
/**
* 用户手表数据(批量返回)
*
* @return data
*/
@GetMapping("userWatchDataAll")
public Result<List<UserStat>> userStatResultAll(@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date date) {
return Result.ok(watchDataApiService.userStatResultAll(date));
}
/**
* 用户此刻是否拥有手表
*
@@ -11,6 +11,7 @@ import com.renkang.watch.vo.UserData.res.sleep.WatchDataSleepRes;
import org.jeecg.common.api.vo.Result;
import java.util.Date;
import java.util.List;
import java.util.Map;
public interface WatchDataApiService {
@@ -43,6 +44,14 @@ public interface WatchDataApiService {
UserStat userStatResult(String type);
/**
* 查询当前登录用户所有健康指标统计数据(按指定日期过滤)
*
* @param date 查询日期,为 null 时返回最新一条数据
* @return 各指标统计结果列表
*/
List<UserStat> userStatResultAll(Date date);
Boolean userHaveWatch(String userId);
UserWatchInfo findWatchInfo(String userId);
@@ -28,6 +28,7 @@ import org.apache.commons.collections4.CollectionUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.global.GlobalUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
@@ -36,6 +37,7 @@ import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.CompletableFuture;
@Service
public class WatchDataApiServiceImpl implements WatchDataApiService {
@@ -112,6 +114,12 @@ public class WatchDataApiServiceImpl implements WatchDataApiService {
@Autowired
private WatchStatUserInfoDayTempMapper watchStatUserInfoDayTempMapper;
@Autowired
private RedisUtil redisUtil;
/** 用户统计全量数据 Redis 缓存 key 前缀 */
private static final String USER_STAT_ALL_CACHE_KEY = "watch:userStatAll:";
@Override
public Result<Map<String,Object>> selectSportCostListApi() {
LoginUser loginUser = GlobalUtils.getLoginUser();
@@ -834,20 +842,63 @@ public class WatchDataApiServiceImpl implements WatchDataApiService {
String userId = GlobalUtils.getLoginUser().getId();
switch (type) {
case "0":
return handleHeartRate(userId);
return handleHeartRate(userId,null);
case "1":
return handleBloodOxygen(userId);
return handleBloodOxygen(userId,null);
case "2":
return handleStress(userId);
return handleStress(userId,null);
case "3":
return handleBodyTemperature(userId);
return handleBodyTemperature(userId,null);
case "4":
return handleSleep(userId);
return handleSleep(userId,null);
default:
return null;
}
}
@Override
public List<UserStat> userStatResultAll(Date date) {
// 在主线程提前获取 userId,避免子线程无法访问 ThreadLocal 中的登录信息
String userId = GlobalUtils.getLoginUser().getId();
// 有时间参数时缓存 key 携带日期,避免与无参缓存冲突
String cacheKey = USER_STAT_ALL_CACHE_KEY + userId + (date != null ? "_" + date.getTime() : "");
// 命中 Redis 缓存直接返回
Object cached = redisUtil.get(cacheKey);
if (cached != null) {
//noinspection unchecked
return (List<UserStat>) cached;
}
// 并行异步查询5种数据,thenApply 在任务完成时立即绑定 type,与顺序无关
CompletableFuture<UserStat> heartRateFuture = CompletableFuture.supplyAsync(() -> handleHeartRate(userId, date))
.thenApply(stat -> setType(stat, "0"));
CompletableFuture<UserStat> bloodOxygenFuture = CompletableFuture.supplyAsync(() -> handleBloodOxygen(userId, date))
.thenApply(stat -> setType(stat, "1"));
CompletableFuture<UserStat> stressFuture = CompletableFuture.supplyAsync(() -> handleStress(userId, date))
.thenApply(stat -> setType(stat, "2"));
CompletableFuture<UserStat> bodyTempFuture = CompletableFuture.supplyAsync(() -> handleBodyTemperature(userId, date))
.thenApply(stat -> setType(stat, "3"));
CompletableFuture<UserStat> sleepFuture = CompletableFuture.supplyAsync(() -> handleSleep(userId, date))
.thenApply(stat -> setType(stat, "4"));
// 等待所有子任务完成
CompletableFuture.allOf(heartRateFuture, bloodOxygenFuture, stressFuture, bodyTempFuture, sleepFuture).join();
// 组装结果列表,每条数据已在异步阶段绑定好 type
List<UserStat> result = Arrays.asList(
heartRateFuture.join(),
bloodOxygenFuture.join(),
stressFuture.join(),
bodyTempFuture.join(),
sleepFuture.join()
);
// 写入 Redis 缓存,TTL=3分钟(180秒)
redisUtil.set(cacheKey, result, 180);
return result;
}
@Override
public Boolean userHaveWatch(String userId) {
if (StrUtil.isBlank(userId)) {
@@ -885,7 +936,7 @@ public class WatchDataApiServiceImpl implements WatchDataApiService {
}
private UserStat handleSleep(String userId) {
private UserStat handleSleep(String userId, Date date) {
LambdaQueryWrapper<WatchStatUserInfoDaySleep> queryWrapper = Wrappers.lambdaQuery(WatchStatUserInfoDaySleep.class)
.select(WatchStatUserInfoDaySleep::getId,
WatchStatUserInfoDaySleep::getDeepSleepTimes,
@@ -893,7 +944,9 @@ public class WatchDataApiServiceImpl implements WatchDataApiService {
WatchStatUserInfoDaySleep::getDeepLightTimes,
WatchStatUserInfoDaySleep::getDataDate)
.eq(WatchStatUserInfoDaySleep::getUserId, userId)
.orderByDesc(WatchStatUserInfoDaySleep::getDataDate)
// 传了日期则精确匹配,否则取最新一条
.eq(date != null, WatchStatUserInfoDaySleep::getDataDate, date)
.orderByDesc(date == null, WatchStatUserInfoDaySleep::getDataDate)
.last("limit 1");
WatchStatUserInfoDaySleep data = watchStatUserInfoDaySleepMapper.selectOne(queryWrapper);
@@ -915,7 +968,7 @@ public class WatchDataApiServiceImpl implements WatchDataApiService {
return stat;
}
private UserStat handleBodyTemperature(String userId) {
private UserStat handleBodyTemperature(String userId, Date date) {
int type = 5;
int scale = 1;
// 最新数据
@@ -923,7 +976,7 @@ public class WatchDataApiServiceImpl implements WatchDataApiService {
if (userStat == null) {
return null;
}
LambdaQueryWrapper<WatchStatUserInfoDayTemp> queryWrapper = getQueryWrapper(userId);
LambdaQueryWrapper<WatchStatUserInfoDayTemp> queryWrapper = getQueryWrapper(userId, date);
WatchStatUserInfoDayTemp data = watchStatUserInfoDayTempMapper.selectOne(queryWrapper);
if (data == null) {
return userStat;
@@ -933,7 +986,7 @@ public class WatchDataApiServiceImpl implements WatchDataApiService {
return userStat;
}
private UserStat handleStress(String userId) {
private UserStat handleStress(String userId, Date date) {
int type = 3;
int scale = 0;
// 最新数据
@@ -941,7 +994,7 @@ public class WatchDataApiServiceImpl implements WatchDataApiService {
if (userStat == null) {
return null;
}
LambdaQueryWrapper<WatchStatUserInfoDayStress> queryWrapper = getQueryWrapper(userId);
LambdaQueryWrapper<WatchStatUserInfoDayStress> queryWrapper = getQueryWrapper(userId, date);
WatchStatUserInfoDayStress data = watchStatUserInfoDayStressMapper.selectOne(queryWrapper);
if (data == null) {
return userStat;
@@ -951,7 +1004,7 @@ public class WatchDataApiServiceImpl implements WatchDataApiService {
return userStat;
}
private UserStat handleBloodOxygen(String userId) {
private UserStat handleBloodOxygen(String userId, Date date) {
int type = 2;
int scale = 0;
// 最新数据
@@ -959,7 +1012,7 @@ public class WatchDataApiServiceImpl implements WatchDataApiService {
if (userStat == null) {
return null;
}
LambdaQueryWrapper<WatchStatUserInfoDaySpo2> queryWrapper = getQueryWrapper(userId);
LambdaQueryWrapper<WatchStatUserInfoDaySpo2> queryWrapper = getQueryWrapper(userId, date);
WatchStatUserInfoDaySpo2 data = watchStatUserInfoDaySpo2Mapper.selectOne(queryWrapper);
if (data == null) {
return userStat;
@@ -969,7 +1022,7 @@ public class WatchDataApiServiceImpl implements WatchDataApiService {
return userStat;
}
private UserStat handleHeartRate(String userId) {
private UserStat handleHeartRate(String userId, Date date) {
int type = 1;
int scale = 0;
// 最新数据
@@ -977,7 +1030,7 @@ public class WatchDataApiServiceImpl implements WatchDataApiService {
if (userStat == null) {
return null;
}
LambdaQueryWrapper<WatchStatUserInfoDayHeartRate> queryWrapper = getQueryWrapper(userId);
LambdaQueryWrapper<WatchStatUserInfoDayHeartRate> queryWrapper = getQueryWrapper(userId, date);
WatchStatUserInfoDayHeartRate data = watchStatUserInfoDayHeartRateMapper.selectOne(queryWrapper);
if (data == null) {
return userStat;
@@ -1029,10 +1082,12 @@ public class WatchDataApiServiceImpl implements WatchDataApiService {
return stat;
}
private <T> LambdaQueryWrapper<T> getQueryWrapper(String userId) {
private <T> LambdaQueryWrapper<T> getQueryWrapper(String userId, Date date) {
QueryWrapper<T> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id", userId)
.orderByDesc("data_date")
// 传了日期则精确匹配,否则取最新一条
.eq(date != null, "data_date", date)
.orderByDesc(date == null, "data_date")
.last("limit 1");
return queryWrapper.lambda();
}
@@ -1051,4 +1106,17 @@ public class WatchDataApiServiceImpl implements WatchDataApiService {
return BigDecimal.valueOf(value).setScale(0, RoundingMode.HALF_UP);
}
/**
* 设置统计数据类型标识,stat 为 null 时直接返回 null
*
* @param stat UserStat 对象
* @param type 类型编码:0=心率 1=血氧 2=压力 3=体温 4=睡眠
*/
private UserStat setType(UserStat stat, String type) {
if (stat != null) {
stat.setType(type);
}
return stat;
}
}