|
@@ -0,0 +1,777 @@
|
|
|
+package com.fs.his.service.impl;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import com.fs.common.constant.Constants;
|
|
|
+import com.fs.common.core.redis.RedisCache;
|
|
|
+import com.fs.common.exception.ServiceException;
|
|
|
+import com.fs.common.utils.DateUtils;
|
|
|
+import com.fs.common.utils.StringUtils;
|
|
|
+import com.fs.his.config.HealthIndicatorConfig;
|
|
|
+import com.fs.his.domain.FsUserHealthData;
|
|
|
+import com.fs.his.domain.FsUserHealthProfile;
|
|
|
+import com.fs.his.domain.FsUserInfo;
|
|
|
+import com.fs.his.enums.HealthDataLevelEnum;
|
|
|
+import com.fs.his.enums.HealthDataTypeEnum;
|
|
|
+import com.fs.his.mapper.FsUserHealthDataMapper;
|
|
|
+import com.fs.his.service.IFsUserHealthDataService;
|
|
|
+import com.fs.his.service.IFsUserHealthProfileService;
|
|
|
+import com.fs.his.service.IFsUserInfoService;
|
|
|
+import com.fs.system.domain.SysConfig;
|
|
|
+import com.fs.system.service.ISysConfigService;
|
|
|
+import com.github.pagehelper.PageHelper;
|
|
|
+import com.github.pagehelper.PageInfo;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.math.RoundingMode;
|
|
|
+import java.util.Collections;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 用户身体检测数据Service业务层处理
|
|
|
+ *
|
|
|
+ * @author fs
|
|
|
+ * @date 2025-08-27
|
|
|
+ */
|
|
|
+@Service
|
|
|
+public class FsUserHealthDataServiceImpl extends ServiceImpl<FsUserHealthDataMapper, FsUserHealthData> implements IFsUserHealthDataService {
|
|
|
+
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private RedisCache redisCache;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ISysConfigService configService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IFsUserInfoService fsUserInfoService;
|
|
|
+ @Autowired
|
|
|
+ private IFsUserHealthProfileService fsUserHealthProfileService;
|
|
|
+
|
|
|
+ private static final String HEALTH_INDICATOR_KEY = "his.healthIndexConfig";
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询用户身体检测数据列表
|
|
|
+ *
|
|
|
+ * @param fsUserHealthData 用户身体检测数据
|
|
|
+ * @return 用户身体检测数据
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public List<FsUserHealthData> selectFsUserHealthDataList(FsUserHealthData fsUserHealthData) {
|
|
|
+ return baseMapper.selectFsUserHealthDataList(fsUserHealthData);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @Description: 查询用户身体检测数据列表 获取数量
|
|
|
+ * @Param:
|
|
|
+ * @Return:
|
|
|
+ * @Author xgb
|
|
|
+ * @Date 2025/9/1 14:58
|
|
|
+ */
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public int selectFsUserHealthDataListCount(FsUserHealthData fsUserHealthData) {
|
|
|
+ return baseMapper.selectFsUserHealthDataListCount(fsUserHealthData);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Map<String, Object> selectFsUserHealthDataListInfo(FsUserHealthData fsUserHealthData, Integer pageNum, Integer pageSize) {
|
|
|
+ // 时间格式字段处理
|
|
|
+ if (StringUtils.isNotEmpty(fsUserHealthData.getTimeSearch())) {
|
|
|
+ Map<String, Object> timeMap = new HashMap<>();
|
|
|
+ // 时间格式处理 2025-01-21 2025-01-01;2025-01-12 2025-01
|
|
|
+ if (fsUserHealthData.getTimeSearch().contains(";")) {
|
|
|
+ String[] timeArr = fsUserHealthData.getTimeSearch().split(";");
|
|
|
+ timeMap.put("beginTime", timeArr[0]);
|
|
|
+ timeMap.put("endTime", timeArr[1]);
|
|
|
+ } else if (fsUserHealthData.getTimeSearch().length() == 10) {
|
|
|
+ fsUserHealthData.setMeasurementDate(DateUtils.parseDate(fsUserHealthData.getTimeSearch()));
|
|
|
+ } else if (fsUserHealthData.getTimeSearch().length() == 7) {
|
|
|
+ // 按月 取当月第一个和最后一天
|
|
|
+ timeMap.put("beginTime", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, DateUtils.getStartOfMonth(DateUtils.parseDate(fsUserHealthData.getTimeSearch()))));
|
|
|
+ timeMap.put("endTime", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, DateUtils.getEndOfMonth(DateUtils.parseDate(fsUserHealthData.getTimeSearch()))));
|
|
|
+ }
|
|
|
+ fsUserHealthData.setParams(timeMap);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ PageHelper.startPage(pageNum, pageSize);
|
|
|
+ List<FsUserHealthData> list = selectFsUserHealthDataList(fsUserHealthData);
|
|
|
+
|
|
|
+ Map<String, Object> data = new HashMap<>();
|
|
|
+ data.put("data", new PageInfo<>(list));
|
|
|
+
|
|
|
+
|
|
|
+ // 如果测量等级是空 需要查询各等级(无-0,轻微-1,严重-2) 数量
|
|
|
+ if (fsUserHealthData.getLevel() == null) {
|
|
|
+ Map<String, Object> count = new HashMap<>();
|
|
|
+ for (int i = 0; i < 3; i++) {
|
|
|
+ fsUserHealthData.setLevel(i);
|
|
|
+ int num = selectFsUserHealthDataListCount(fsUserHealthData);
|
|
|
+ count.put("count" + i, num);
|
|
|
+ }
|
|
|
+ data.put("count", count);
|
|
|
+ }
|
|
|
+ return data;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @Description: 查询用户身体检测数据列表 获取最新的数据
|
|
|
+ * @Param:
|
|
|
+ * @Return:
|
|
|
+ * @Author xgb
|
|
|
+ * @Date 2025/9/5 16:01
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public Map<String, Object> selectFsUserHealthDataListInfoLatest(FsUserHealthData fsUserHealthData, Integer pageNum, Integer pageSize) {
|
|
|
+ if (StringUtils.isEmpty(fsUserHealthData.getTimeSearch())) {
|
|
|
+ throw new ServiceException("查询时间不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ List<FsUserHealthData> list = Collections.emptyList();
|
|
|
+ Map<String, Object> timeMap = new HashMap<>();
|
|
|
+
|
|
|
+ // 时间格式处理 2025-01-21 2025-01-01;2025-01-12 2025-01
|
|
|
+
|
|
|
+ if (fsUserHealthData.getTimeSearch().contains(";")) {
|
|
|
+ String[] timeArr = fsUserHealthData.getTimeSearch().split(";");
|
|
|
+ timeMap.put("beginTime", timeArr[0]);
|
|
|
+ timeMap.put("endTime", timeArr[1]);
|
|
|
+ // 获取每天最新的数据
|
|
|
+ fsUserHealthData.setParams(timeMap);
|
|
|
+ list = baseMapper.selectFsUserHealthDataListInfoLatest(fsUserHealthData);
|
|
|
+ list.forEach(item -> {// 设置周
|
|
|
+ item.setWeek(DateUtils.getWeek(item.getMeasurementDate()));
|
|
|
+ });
|
|
|
+ } else if (fsUserHealthData.getTimeSearch().length() == 10) {
|
|
|
+ fsUserHealthData.setMeasurementDate(DateUtils.parseDate(fsUserHealthData.getTimeSearch()));
|
|
|
+ PageHelper.startPage(pageNum, pageSize);
|
|
|
+ list = selectFsUserHealthDataList(fsUserHealthData);
|
|
|
+ } else if (fsUserHealthData.getTimeSearch().length() == 7) {
|
|
|
+ // 按月 取当月第一个和最后一天
|
|
|
+ timeMap.put("beginTime", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, DateUtils.getStartOfMonth(DateUtils.parseDate(fsUserHealthData.getTimeSearch()))));
|
|
|
+ timeMap.put("endTime", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, DateUtils.getEndOfMonth(DateUtils.parseDate(fsUserHealthData.getTimeSearch()))));
|
|
|
+ fsUserHealthData.setParams(timeMap);
|
|
|
+ list = baseMapper.selectFsUserHealthDataListInfoLatest(fsUserHealthData);
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<String, Object> data = new HashMap<>();
|
|
|
+ data.put("data", new PageInfo<>(list));
|
|
|
+
|
|
|
+
|
|
|
+ // 如果测量等级是空 需要查询各等级(无-0,轻微-1,严重-2) 数量
|
|
|
+ if (fsUserHealthData.getLevel() == null) {
|
|
|
+ Map<String, Object> count = new HashMap<>();
|
|
|
+ for (int i = 0; i < 3; i++) {
|
|
|
+ fsUserHealthData.setLevel(i);
|
|
|
+ int num = selectFsUserHealthDataListCount(fsUserHealthData);
|
|
|
+ count.put("count" + i, num);
|
|
|
+ }
|
|
|
+ data.put("count", count);
|
|
|
+ }
|
|
|
+
|
|
|
+ return data;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 新增用户身体检测数据
|
|
|
+ *
|
|
|
+ * @param fsUserHealthData 用户身体检测数据
|
|
|
+ * @return 结果
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public int insertFsUserHealthData(FsUserHealthData fsUserHealthData) {
|
|
|
+ return baseMapper.insertFsUserHealthData(fsUserHealthData);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 修改用户身体检测数据
|
|
|
+ *
|
|
|
+ * @param fsUserHealthData 用户身体检测数据
|
|
|
+ * @return 结果
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public int updateFsUserHealthData(FsUserHealthData fsUserHealthData) {
|
|
|
+ return baseMapper.updateFsUserHealthData(fsUserHealthData);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 删除用户身体检测数据信息
|
|
|
+ *
|
|
|
+ * @param id 用户身体检测数据主键
|
|
|
+ * @return 结果
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public int deleteFsUserHealthDataById(Long id) {
|
|
|
+ return baseMapper.deleteFsUserHealthDataById(id);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @Description: 查询用户身体检测最新数据
|
|
|
+ * @Param:
|
|
|
+ * @Return:
|
|
|
+ * @Author xgb
|
|
|
+ * @Date 2025/8/29 17:48
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public FsUserHealthData selectFsUserHealthDataByUserId(FsUserHealthData fsUserHealthData) {
|
|
|
+
|
|
|
+ return baseMapper.selectFsUserHealthDataByUserId(fsUserHealthData);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @Description: 查询用户身体检测数据详情
|
|
|
+ * @Param:
|
|
|
+ * @Return:
|
|
|
+ * @Author xgb
|
|
|
+ * @Date 2025/8/29 17:48
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public FsUserHealthData selectFsUserHealthDataById(Long Id) {
|
|
|
+ return baseMapper.selectFsUserHealthDataById(Id);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @Description: 更新用户身体检测数据
|
|
|
+ * @Param: fsUserHealthData
|
|
|
+ * @Return:
|
|
|
+ * @Author xgb
|
|
|
+ * @Date 2025/9/1 10:50
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public void updateFsUserHealthDataAndLevel(FsUserHealthData fsUserHealthData) {
|
|
|
+ // 优化后的代码
|
|
|
+ int type = fsUserHealthData.getMeasurementType();
|
|
|
+ boolean hasValue1 = fsUserHealthData.getValue1() != null;
|
|
|
+ boolean hasValue2 = fsUserHealthData.getValue2() != null;
|
|
|
+
|
|
|
+ switch (type) {
|
|
|
+ case 3: // 血压
|
|
|
+ case 5: // BMI
|
|
|
+ // 参数校验: 血压和BMI的Value1和Value2必须同时有值或同时没值
|
|
|
+ if (hasValue1 != hasValue2) {
|
|
|
+ throw new ServiceException("血压和BMI必须同时有值或同时没值");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (hasValue1 && hasValue2) {
|
|
|
+ if (type == 3) { // 血压
|
|
|
+ // 计算测量值对应等级
|
|
|
+ int level = getHealthIndicatorLevel(fsUserHealthData);
|
|
|
+ fsUserHealthData.setLevel(level);
|
|
|
+ } else { // BMI
|
|
|
+ // 保存原始value1
|
|
|
+ BigDecimal originalValue1 = fsUserHealthData.getValue1();
|
|
|
+ // 计算BMI
|
|
|
+ BigDecimal bmi = calculateBMI(fsUserHealthData.getValue1(), fsUserHealthData.getValue2());
|
|
|
+ fsUserHealthData.setValue1(bmi);
|
|
|
+ // 计算测量值对应等级
|
|
|
+ int level = getHealthIndicatorLevel(fsUserHealthData);
|
|
|
+ fsUserHealthData.setLevel(level);
|
|
|
+ // 恢复原始value1
|
|
|
+ fsUserHealthData.setValue1(originalValue1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 更新用户身体检测数据信息
|
|
|
+ if (updateFsUserHealthData(fsUserHealthData) <= 0) {
|
|
|
+ throw new ServiceException("用户身体检测数据修改失败");
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 0: // 腰围
|
|
|
+ case 1: // 臀围
|
|
|
+ // 更新用户身体检测数据信息
|
|
|
+ if (updateFsUserHealthData(fsUserHealthData) <= 0) {
|
|
|
+ throw new ServiceException("用户身体检测数据修改失败");
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 2: // 血糖
|
|
|
+ // 计算测量值对应等级
|
|
|
+ int level = getHealthIndicatorLevel(fsUserHealthData);
|
|
|
+ fsUserHealthData.setLevel(level);
|
|
|
+ // 更新用户身体检测数据信息
|
|
|
+ if (updateFsUserHealthData(fsUserHealthData) <= 0) {
|
|
|
+ throw new ServiceException("用户身体检测数据修改失败");
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 4: // 尿酸
|
|
|
+ // 根据userId查询用户信息
|
|
|
+ FsUserInfo user = fsUserInfoService.selectFsUserInfoById(fsUserHealthData.getUserId());
|
|
|
+ if (user.getSex() == null || "2".equals(String.valueOf(user.getSex()))) {
|
|
|
+ throw new ServiceException("尿酸判断需要性别信息,请完善用户性别信息");
|
|
|
+ }
|
|
|
+ fsUserHealthData.setSex(user.getSex());
|
|
|
+ // 计算测量值对应等级
|
|
|
+ int uricLevel = getHealthIndicatorLevel(fsUserHealthData);
|
|
|
+ fsUserHealthData.setLevel(uricLevel);
|
|
|
+ // 更新用户身体检测数据信息
|
|
|
+ if (updateFsUserHealthData(fsUserHealthData) <= 0) {
|
|
|
+ throw new ServiceException("用户身体检测数据修改失败");
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ throw new ServiceException("不支持的测量类型");
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @Description: 解析健康指标
|
|
|
+ * @Param: []
|
|
|
+ * @Return: java.util.Map<java.lang.String, java.lang.Object>
|
|
|
+ * @Author xgb
|
|
|
+ * @Date 2025/8/28 9:10
|
|
|
+ */
|
|
|
+ public HealthIndicatorConfig parseHealthIndicator() {
|
|
|
+ String configKey = Constants.SYS_CONFIG_KEY + HEALTH_INDICATOR_KEY;
|
|
|
+ String str = redisCache.getCacheObject(Constants.SYS_CONFIG_KEY + HEALTH_INDICATOR_KEY);
|
|
|
+ // str JSON串转 map
|
|
|
+ if (StringUtils.isEmpty(str)) {
|
|
|
+ // 查询sys_config表配置
|
|
|
+ SysConfig config = configService.selectConfigByConfigKey(HEALTH_INDICATOR_KEY);
|
|
|
+ if (config != null && StringUtils.isNotEmpty(config.getConfigValue())) {
|
|
|
+ redisCache.setCacheObject(configKey, config.getConfigValue());
|
|
|
+ return HealthIndicatorConfig.fromJson(config.getConfigValue());
|
|
|
+ } else {
|
|
|
+ throw new ServiceException("健康指标配置不存在,请联系管理人员");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 解析健康指标JSON 放入HealthIndicatorConfig
|
|
|
+ return HealthIndicatorConfig.fromJson(str);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @Description: 解析健康指标配置
|
|
|
+ * @Param:
|
|
|
+ * @Return:
|
|
|
+ * @Author xgb
|
|
|
+ * @Date 2025/9/3 10:55
|
|
|
+ */
|
|
|
+ private String parseHealthIndicatorConfig(Map<String, Object> map, String key, String level) {
|
|
|
+ if (StringUtils.equalsAny(key, "severity", "male", "female")) {
|
|
|
+ // 处理严重程度级别
|
|
|
+ List<Map<String, Object>> severityList = (List<Map<String, Object>>) map.get(key);
|
|
|
+ for (Map<String, Object> severity : severityList) {
|
|
|
+ if (level.equals(severity.get("level"))) {
|
|
|
+ return (String) severity.get("range");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 处理普通键值
|
|
|
+ Map<String, Object> keyMap = (Map<String, Object>) map.get(key);
|
|
|
+ if (keyMap != null) {
|
|
|
+ return (String) keyMap.get(level);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String parseHealthIndicatorConfigTwo(Map<String, Object> map, String key, String level, String subType) {
|
|
|
+ if ("severity".equals(key)) {
|
|
|
+ // 处理血压严重程度级别
|
|
|
+ List<Map<String, Object>> severityList = (List<Map<String, Object>>) map.get("severity");
|
|
|
+ for (Map<String, Object> severity : severityList) {
|
|
|
+ // 同时匹配级别和血压类型(收缩压/舒张压)
|
|
|
+ if (level.equals(severity.get("level")) && subType.equals(severity.get("type"))) {
|
|
|
+ return (String) severity.get("range");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 处理保护范围等
|
|
|
+ Map<String, Object> keyMap = (Map<String, Object>) map.get(key);
|
|
|
+ if (keyMap != null) {
|
|
|
+ return (String) keyMap.get(level);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取健康指标值
|
|
|
+ *
|
|
|
+ * @param config 健康指标配置对象
|
|
|
+ * @param type 指标类型 (bloodGlucose 血糖, bloodPressure 血压, uricAcid 尿酸(分男女), bmi 胖瘦)
|
|
|
+ * @param key 指标键值 (bloodGlucose使用(fasting 正常, post1Hour 饭后一小时, post2Hour 饭后两小时 )尿酸(male 男性 female 女性) severity 等)
|
|
|
+ * @param level 指标级别 (normal 正常, mild 轻微, severe 严重 等)
|
|
|
+ * @param subType 子类型 (bloodPressure时使用,systolic 收缩压, diastolic 舒张压)
|
|
|
+ * @return 指标值
|
|
|
+ */
|
|
|
+ public String getHealthIndicatorValue(HealthIndicatorConfig config, String type, String key, String level, String subType) {
|
|
|
+ if (config == null) {
|
|
|
+ throw new ServiceException("健康指标配置不存在,请联系管理人员");
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ switch (type) {
|
|
|
+ case "bloodGlucose": // 血糖
|
|
|
+ return parseHealthIndicatorConfig(config.getBloodGlucose(), key, level);
|
|
|
+ case "bloodPressure": // 血压
|
|
|
+ return parseHealthIndicatorConfigTwo(config.getBloodPressure(), key, level, subType);
|
|
|
+ case "uricAcid":// 尿酸
|
|
|
+ return parseHealthIndicatorConfig(config.getUricAcid(), key, level);
|
|
|
+ case "waist":// 腰围
|
|
|
+ return parseHealthIndicatorConfig(config.getWaist(), key, level);
|
|
|
+ case "hip":// 臀围
|
|
|
+ return parseHealthIndicatorConfig(config.getHip(), key, level);
|
|
|
+ case "bmi":// BMI
|
|
|
+ return parseHealthIndicatorConfig(config.getBmi(), key, level);
|
|
|
+ default:
|
|
|
+ throw new ServiceException("不支持的健康指标类型: " + type);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new ServiceException("获取健康指标值失败: " + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取健康指标值 (重载方法,用于不需要subType的场景)
|
|
|
+ *
|
|
|
+ * @param config 健康指标配置对象
|
|
|
+ * @param type 指标类型
|
|
|
+ * @param key 指标键值
|
|
|
+ * @param level 指标级别
|
|
|
+ * @return 指标值
|
|
|
+ */
|
|
|
+ public String getHealthIndicatorValue(HealthIndicatorConfig config, String type, String key, String level) {
|
|
|
+ return getHealthIndicatorValue(config, type, key, level, null);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @Description: 获取健康指标级别 根据测量值判断指标级别
|
|
|
+ * @Param: [fsUserHealthData]
|
|
|
+ * @Return: int 0 表示正常,1 表示轻度,2 表示重度 3 异常数据(不在测量值范围内)
|
|
|
+ * @Author xgb
|
|
|
+ * @Date 2025/8/28 17:19
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public int getHealthIndicatorLevel(FsUserHealthData fsUserHealthData) {
|
|
|
+ HealthIndicatorConfig config = parseHealthIndicator();
|
|
|
+
|
|
|
+ HealthDataTypeEnum dataType = HealthDataTypeEnum.getEnumByKey(fsUserHealthData.getMeasurementType());
|
|
|
+ if (dataType == null) {
|
|
|
+ throw new ServiceException("不支持的健康指标类型: " + fsUserHealthData.getMeasurementType());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 定义健康级别的优先级顺序和对应常量
|
|
|
+ String[] levels = {HealthIndicatorConfig.NORMAL, HealthIndicatorConfig.MILD, HealthIndicatorConfig.SEVERE};
|
|
|
+ int[] levelValues = {0, 1, 2};
|
|
|
+
|
|
|
+ BigDecimal userValue = fsUserHealthData.getValue1();
|
|
|
+
|
|
|
+ // 根据不同的测量类型处理
|
|
|
+ switch (dataType) {
|
|
|
+ case GLUCOSE: // 血糖
|
|
|
+ case BMI: // BMI指标(胖瘦)
|
|
|
+ // 遍历各个健康级别,检查用户数据是否符合该级别范围
|
|
|
+ for (int i = 0; i < levels.length; i++) {
|
|
|
+ String rule = getHealthIndicatorValue(config, dataType.getType(), HealthIndicatorConfig.SEVERITY, levels[i]);
|
|
|
+ if (isContain(rule, userValue)) {
|
|
|
+ return levelValues[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 如果没有匹配的级别,则返回异常数据
|
|
|
+ return HealthDataLevelEnum.EXCEPTION.getValue();
|
|
|
+ case BLOOD_PRESSURE: // 血压
|
|
|
+ // 血压判断 从严重,轻微,正常顺序判断 只要收缩压和舒张压其中一个符合该级别范围,则返回该级别
|
|
|
+ // 获取血压的子类型
|
|
|
+ String[] subTypes = {HealthIndicatorConfig.SYSTOLIC, HealthIndicatorConfig.DIASTOLIC};
|
|
|
+ // 遍历各个健康级别,检查用户数据是否符合该级别范围
|
|
|
+ for (int i = 2; i >= 0; i--) {
|
|
|
+ // 判断收缩压
|
|
|
+ String rule = getHealthIndicatorValue(config, dataType.getType(), HealthIndicatorConfig.SEVERITY, levels[i], subTypes[0]);
|
|
|
+ if (isContain(rule, userValue)) {
|
|
|
+ return levelValues[i];
|
|
|
+ }
|
|
|
+ // 判断舒张压
|
|
|
+ BigDecimal userValue2 = fsUserHealthData.getValue2();
|
|
|
+ rule = getHealthIndicatorValue(config, dataType.getType(), HealthIndicatorConfig.SEVERITY, levels[i], subTypes[1]);
|
|
|
+ if (isContain(rule, userValue2)) {
|
|
|
+ return levelValues[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 如果没有匹配的级别,则返回异常数据
|
|
|
+ return HealthDataLevelEnum.EXCEPTION.getValue();
|
|
|
+ // 可以继续添加其他类型,如血压、尿酸等
|
|
|
+ case URIC_ACID: // 尿酸
|
|
|
+ case WAIST: // 腰围
|
|
|
+ case HIP: // 臀围
|
|
|
+ // 判断性别 0-男 1-女
|
|
|
+ int sex = fsUserHealthData.getSex();
|
|
|
+ String key;
|
|
|
+
|
|
|
+ if (0 == sex) { // 男
|
|
|
+ key = HealthIndicatorConfig.MALE;
|
|
|
+ } else if (1 == sex) { // 女
|
|
|
+ key = HealthIndicatorConfig.FEMALE;
|
|
|
+ } else {
|
|
|
+ throw new ServiceException("不支持的性别类型: " + sex);
|
|
|
+ }
|
|
|
+ for (int i = 0; i < levels.length; i++) {
|
|
|
+ String rule = getHealthIndicatorValue(config, dataType.getType(), key, levels[i]);
|
|
|
+ if (isContain(rule, userValue)) {
|
|
|
+ return levelValues[i];
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ // 如果没有匹配的级别,则返回异常数据
|
|
|
+ return HealthDataLevelEnum.EXCEPTION.getValue();
|
|
|
+ default:
|
|
|
+ throw new ServiceException("未实现的健康指标类型处理: " + dataType.getType());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @Description: 根据身高体重计算BMI
|
|
|
+ * @Param: height 身高cm weight 体重kg
|
|
|
+ * @Return: BMI值
|
|
|
+ * @Author xgb
|
|
|
+ * @Date 2025/8/29 11:00
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public BigDecimal calculateBMI(BigDecimal height, BigDecimal weight) {
|
|
|
+ if (height == null || weight == null) {
|
|
|
+ throw new IllegalArgumentException("身高和体重不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (height.compareTo(BigDecimal.ZERO) <= 0 || weight.compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
+ throw new IllegalArgumentException("身高和体重必须大于0");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 将身高从厘米转换为米 (除以100)
|
|
|
+ BigDecimal heightInMeter = height.divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP);
|
|
|
+
|
|
|
+ // 计算BMI: 体重(kg) / 身高²(m²)
|
|
|
+ return weight.divide(heightInMeter.multiply(heightInMeter), 1, RoundingMode.HALF_UP);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @Description: 初始化健康档案时登记初始化用户健康数据
|
|
|
+ * @Param: fsUserHealthProfile
|
|
|
+ * @Return:
|
|
|
+ * @Author xgb
|
|
|
+ * @Date 2025/8/29 13:37
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public void initHealthData(FsUserHealthProfile fsUserHealthProfile) {
|
|
|
+ // 查询档案信息获取登记时间
|
|
|
+ fsUserHealthProfile = fsUserHealthProfileService.selectFsUserHealthProfileByUserId(fsUserHealthProfile.getUserId());
|
|
|
+ if (fsUserHealthProfile == null) {
|
|
|
+ throw new ServiceException("用户健康档案不存在");
|
|
|
+ }
|
|
|
+ // 第一次登记档案的时候 若存在身高体重 BMI 则进行BMI等级判断
|
|
|
+ FsUserHealthData fsUserHealthData = new FsUserHealthData();
|
|
|
+ fsUserHealthData.setUserId(fsUserHealthProfile.getUserId());
|
|
|
+ fsUserHealthData.setMeasurementDate(fsUserHealthProfile.getCreatedTime());
|
|
|
+ fsUserHealthData.setMeasurementTime(fsUserHealthProfile.getCreatedTime());
|
|
|
+ // 若存在身高体重 则登记BMI测量值
|
|
|
+ if (fsUserHealthProfile.getHeight() != null && fsUserHealthProfile.getWeight() != null) {
|
|
|
+ // 计算BMI值
|
|
|
+ BigDecimal bmi = calculateBMI(fsUserHealthProfile.getHeight(), fsUserHealthProfile.getWeight());
|
|
|
+ // 计算BMI等级
|
|
|
+ /** 测量类型(0-腰围,1-臀围,2-血糖,3-血压,4-尿酸 5-BMI) */
|
|
|
+ fsUserHealthData.setMeasurementType(HealthDataTypeEnum.BMI.getValue());
|
|
|
+ fsUserHealthData.setValue1(bmi);
|
|
|
+ int healthIndicatorLevel = getHealthIndicatorLevel(fsUserHealthData);
|
|
|
+ fsUserHealthData.setValue1(fsUserHealthProfile.getHeight());
|
|
|
+ fsUserHealthData.setValue2(fsUserHealthProfile.getWeight());
|
|
|
+ fsUserHealthData.setLevel(healthIndicatorLevel);
|
|
|
+
|
|
|
+ if (insertFsUserHealthData(fsUserHealthData) <= 0) {
|
|
|
+ throw new ServiceException("BMI数据登记失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // 若存在血压
|
|
|
+ if (fsUserHealthProfile.getSystolicPressure() != null && fsUserHealthProfile.getDiastolicPressure() != null) {
|
|
|
+
|
|
|
+ /** 测量类型(0-腰围,1-臀围,2-血糖,3-血压,4-尿酸 5-BMI) */
|
|
|
+ fsUserHealthData.setMeasurementType(HealthDataTypeEnum.BLOOD_PRESSURE.getValue());
|
|
|
+ fsUserHealthData.setValue1(fsUserHealthProfile.getSystolicPressure());
|
|
|
+ fsUserHealthData.setValue2(fsUserHealthProfile.getDiastolicPressure());
|
|
|
+ int healthIndicatorLevel = getHealthIndicatorLevel(fsUserHealthData);
|
|
|
+ fsUserHealthData.setLevel(healthIndicatorLevel);
|
|
|
+ if (insertFsUserHealthData(fsUserHealthData) <= 0) {
|
|
|
+ throw new ServiceException("血压数据登记失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 若存在血糖
|
|
|
+ if (fsUserHealthProfile.getHyperglycemiaValue() != null) {
|
|
|
+ /** 测量类型(0-腰围,1-臀围,2-血糖,3-血压,4-尿酸 5-BMI) */
|
|
|
+ fsUserHealthData.setMeasurementType(HealthDataTypeEnum.GLUCOSE.getValue());
|
|
|
+ fsUserHealthData.setValue1(fsUserHealthProfile.getHyperglycemiaValue());
|
|
|
+ int healthIndicatorLevel = getHealthIndicatorLevel(fsUserHealthData);
|
|
|
+ fsUserHealthData.setLevel(healthIndicatorLevel);
|
|
|
+ if (insertFsUserHealthData(fsUserHealthData) <= 0) {
|
|
|
+ throw new ServiceException("血糖数据登记失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 若存在尿酸
|
|
|
+ if (fsUserHealthProfile.getHyperuricemiaValue() != null) {
|
|
|
+ // 查询用户信息获取 性别
|
|
|
+ FsUserInfo fsUserInfo = fsUserInfoService.selectFsUserInfoById(fsUserHealthProfile.getUserId());
|
|
|
+ if (fsUserInfo == null || fsUserInfo.getSex() == null) {
|
|
|
+ throw new ServiceException("用户已注销或基础信息未维护性别不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 测量类型(0-腰围,1-臀围,2-血糖,3-血压,4-尿酸 5-BMI) */
|
|
|
+ fsUserHealthData.setMeasurementType(HealthDataTypeEnum.URIC_ACID.getValue());
|
|
|
+ fsUserHealthData.setValue1(fsUserHealthProfile.getHyperuricemiaValue());
|
|
|
+ fsUserHealthData.setSex(fsUserInfo.getSex());
|
|
|
+ int healthIndicatorLevel = getHealthIndicatorLevel(fsUserHealthData);
|
|
|
+ fsUserHealthData.setLevel(healthIndicatorLevel);
|
|
|
+ if (insertFsUserHealthData(fsUserHealthData) <= 0) {
|
|
|
+ throw new ServiceException("尿酸数据登记失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 若存在腰围
|
|
|
+ if (fsUserHealthProfile.getWaistCircumference() != null) {
|
|
|
+ // 查询用户信息获取 性别
|
|
|
+ FsUserInfo fsUserInfo = fsUserInfoService.selectFsUserInfoById(fsUserHealthProfile.getUserId());
|
|
|
+ if (fsUserInfo == null || fsUserInfo.getSex() == null) {
|
|
|
+ throw new ServiceException("用户已注销或性别不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 测量类型(0-腰围,1-臀围,2-血糖,3-血压,4-尿酸 5-BMI) */
|
|
|
+ fsUserHealthData.setMeasurementType(HealthDataTypeEnum.WAIST.getValue());
|
|
|
+ fsUserHealthData.setValue1(fsUserHealthProfile.getWaistCircumference());
|
|
|
+ fsUserHealthData.setSex(fsUserInfo.getSex());
|
|
|
+ int healthIndicatorLevel = getHealthIndicatorLevel(fsUserHealthData);
|
|
|
+ fsUserHealthData.setLevel(healthIndicatorLevel);
|
|
|
+ if (insertFsUserHealthData(fsUserHealthData) <= 0) {
|
|
|
+ throw new ServiceException("腰围数据登记失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 若存在臀围
|
|
|
+ if (fsUserHealthProfile.getHipCircumference() != null) {
|
|
|
+ // 查询用户信息获取 性别
|
|
|
+ FsUserInfo fsUserInfo = fsUserInfoService.selectFsUserInfoById(fsUserHealthProfile.getUserId());
|
|
|
+ if (fsUserInfo == null || fsUserInfo.getSex() == null) {
|
|
|
+ throw new ServiceException("用户已注销或性别信息不存在");
|
|
|
+ }
|
|
|
+ /** 测量类型(0-腰围,1-臀围,2-血糖,3-血压,4-尿酸 5-BMI) */
|
|
|
+ fsUserHealthData.setMeasurementType(HealthDataTypeEnum.HIP.getValue());
|
|
|
+ fsUserHealthData.setValue1(fsUserHealthProfile.getHipCircumference());
|
|
|
+ fsUserHealthData.setSex(fsUserInfo.getSex());
|
|
|
+ int healthIndicatorLevel = getHealthIndicatorLevel(fsUserHealthData);
|
|
|
+ fsUserHealthData.setLevel(healthIndicatorLevel);
|
|
|
+ if (insertFsUserHealthData(fsUserHealthData) <= 0) {
|
|
|
+ throw new ServiceException("臀围数据登记失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @Description: 新增健康各类型数据 0-腰围,1-臀围,2-血糖,3-血压,4-尿酸 5-BMI
|
|
|
+ * @Param: fsUserHealthData
|
|
|
+ * @Return:
|
|
|
+ * @Author xgb
|
|
|
+ * @Date 2025/8/29 16:06
|
|
|
+ */
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void addHealthData(FsUserHealthData fsUserHealthData) {
|
|
|
+ int type = fsUserHealthData.getMeasurementType();
|
|
|
+ // 0-腰围,1-臀围,2-血糖,3-血压,4-尿酸 5-BMI
|
|
|
+ if (type == 0 || type == 1 || type == 4) { // 尿酸查询等级信息时需要性别信息
|
|
|
+ // 根据userId 查询用户信息
|
|
|
+ FsUserInfo user = fsUserInfoService.selectFsUserInfoById(fsUserHealthData.getUserId());
|
|
|
+ if (user.getSex() == null || "2".equals(String.valueOf(user.getSex()))) {
|
|
|
+ throw new ServiceException("尿酸判断需要性别信息,请完善用户性别信息");
|
|
|
+ }
|
|
|
+ fsUserHealthData.setSex(user.getSex());
|
|
|
+ }
|
|
|
+ // 2-血糖,3-血压,4-尿酸 5-BMI 判断等级
|
|
|
+ if (type == 0 || type == 1 || type == 2 || type == 3 || type == 4) {
|
|
|
+ // 计算测量值对应等级
|
|
|
+ int level = getHealthIndicatorLevel(fsUserHealthData);
|
|
|
+ fsUserHealthData.setLevel(level);
|
|
|
+ } else if (type == 5) {// BMI 需要用身高体重先计算出BMI
|
|
|
+ // 计算BMI
|
|
|
+ BigDecimal value1 = fsUserHealthData.getValue1();
|
|
|
+ fsUserHealthData.setValue1(calculateBMI(fsUserHealthData.getValue1(), fsUserHealthData.getValue2()));
|
|
|
+ // 计算测量值对应等级
|
|
|
+ int level = getHealthIndicatorLevel(fsUserHealthData);
|
|
|
+ fsUserHealthData.setLevel(level);
|
|
|
+ fsUserHealthData.setValue1(value1);
|
|
|
+ } else {
|
|
|
+ throw new ServiceException("不支持的测量类型");
|
|
|
+ }
|
|
|
+ // 登记检测数据信息
|
|
|
+ if (insertFsUserHealthData(fsUserHealthData) <= 0) {
|
|
|
+ throw new ServiceException("新增用户身体检测数据失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 判断value1是否在value规则范围内
|
|
|
+ *
|
|
|
+ * @param value 规则字符串,如 "0~100"、"<100"、"≤100"、">100"、"≥100"
|
|
|
+ * @param value1 实际测量值
|
|
|
+ * @return 是否在范围内
|
|
|
+ */
|
|
|
+ private static Boolean isContain(String value, BigDecimal value1) {
|
|
|
+ if (value == null || value1 == null) {
|
|
|
+ throw new ServiceException("参数不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理范围值 "0~100"
|
|
|
+ if (value.contains("~")) {
|
|
|
+ String[] parts = value.split("~");
|
|
|
+ if (parts.length != 2) {
|
|
|
+ throw new ServiceException("无效的范围值格式: " + value);
|
|
|
+ }
|
|
|
+ BigDecimal lower = new BigDecimal(parts[0]);
|
|
|
+ BigDecimal upper = new BigDecimal(parts[1]);
|
|
|
+ return value1.compareTo(lower) >= 0 && value1.compareTo(upper) <= 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理小于 "<100"
|
|
|
+ if (value.startsWith("<")) {
|
|
|
+ BigDecimal threshold = new BigDecimal(value.substring(1));
|
|
|
+ return value1.compareTo(threshold) < 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理小于等于 "≤100"
|
|
|
+ if (value.startsWith("≤")) {
|
|
|
+ BigDecimal threshold = new BigDecimal(value.substring(1));
|
|
|
+ return value1.compareTo(threshold) <= 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理大于 ">100"
|
|
|
+ if (value.startsWith(">")) {
|
|
|
+ BigDecimal threshold = new BigDecimal(value.substring(1));
|
|
|
+ return value1.compareTo(threshold) > 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理大于等于 "≥100"
|
|
|
+ if (value.startsWith("≥")) {
|
|
|
+ BigDecimal threshold = new BigDecimal(value.substring(1));
|
|
|
+ return value1.compareTo(threshold) >= 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 尝试直接转换为数字进行比较
|
|
|
+ try {
|
|
|
+ BigDecimal threshold = new BigDecimal(value);
|
|
|
+ return value1.compareTo(threshold) == 0;
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ throw new ServiceException("不支持的指标值规则: " + value + ";请联系管理员处理");
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+}
|