移动端首页手表数据修改
This commit is contained in:
+2
@@ -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;
|
||||
|
||||
+11
@@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户此刻是否拥有手表
|
||||
*
|
||||
|
||||
+9
@@ -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);
|
||||
|
||||
+85
-17
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user