Bläddra i källkod

腕表小护士功能迁移

wangxy 2 veckor sedan
förälder
incheckning
25f00666a5
100 ändrade filer med 6425 tillägg och 926 borttagningar
  1. 12 3
      fs-company/src/main/java/com/fs/company/controller/course/FsCourseWatchLogController.java
  2. 6 1
      fs-company/src/main/java/com/fs/hisStore/controller/FsStoreStatisticsScrmController.java
  3. 7 0
      fs-service/src/main/java/com/fs/aiChat/mapper/InterestAiChatSessionMapper.java
  4. 2 1
      fs-service/src/main/java/com/fs/course/param/FsCourseWatchLogListParam.java
  5. 78 0
      fs-service/src/main/java/com/fs/his/domain/FsHealthPulse.java
  6. 83 0
      fs-service/src/main/java/com/fs/his/domain/FsHealthSurface.java
  7. 48 0
      fs-service/src/main/java/com/fs/his/domain/FsThirdDeviceData.java
  8. 84 0
      fs-service/src/main/java/com/fs/his/domain/FsUserAdditionalData.java
  9. 74 0
      fs-service/src/main/java/com/fs/his/mapper/FsHealthPulseMapper.java
  10. 77 0
      fs-service/src/main/java/com/fs/his/mapper/FsHealthSurfaceMapper.java
  11. 147 0
      fs-service/src/main/java/com/fs/his/mapper/FsThirdDeviceDataMapper.java
  12. 68 0
      fs-service/src/main/java/com/fs/his/mapper/FsUserAdditionalDataMapper.java
  13. 16 0
      fs-service/src/main/java/com/fs/his/param/FsHealthPulseListUParam.java
  14. 16 0
      fs-service/src/main/java/com/fs/his/param/FsHealthSurfaceListUParam.java
  15. 2 0
      fs-service/src/main/java/com/fs/his/param/FsHealthTongueListUParam.java
  16. 80 0
      fs-service/src/main/java/com/fs/his/service/IFsThirdDeviceDataService.java
  17. 65 0
      fs-service/src/main/java/com/fs/his/service/IFsUserAdditionalDataService.java
  18. 435 0
      fs-service/src/main/java/com/fs/his/service/impl/FsThirdDeviceDataServiceImpl.java
  19. 98 0
      fs-service/src/main/java/com/fs/his/service/impl/FsUserAdditionalDataServiceImpl.java
  20. 69 0
      fs-service/src/main/java/com/fs/his/vo/FsHealthPulseListVO.java
  21. 83 0
      fs-service/src/main/java/com/fs/his/vo/FsHealthSurfaceListVO.java
  22. 544 0
      fs-service/src/main/java/com/fs/watch/calculation/SleepScoreCalculator.java
  23. 4 0
      fs-service/src/main/java/com/fs/watch/domain/DeviceFamily.java
  24. 0 83
      fs-service/src/main/java/com/fs/watch/domain/FsMonitorDataType.java
  25. 68 0
      fs-service/src/main/java/com/fs/watch/domain/SleepStatistics.java
  26. 96 0
      fs-service/src/main/java/com/fs/watch/domain/WatchAudioMsgLog.java
  27. 0 108
      fs-service/src/main/java/com/fs/watch/domain/WatchDeviceBeginnerGuide.java
  28. 56 0
      fs-service/src/main/java/com/fs/watch/domain/WatchDeviceWeek.java
  29. 6 0
      fs-service/src/main/java/com/fs/watch/domain/WatchFsUser.java
  30. 89 0
      fs-service/src/main/java/com/fs/watch/domain/WatchSosCallLogs.java
  31. 25 0
      fs-service/src/main/java/com/fs/watch/domain/WatchUser.java
  32. 4 0
      fs-service/src/main/java/com/fs/watch/domain/vo/AppFsUserHealthReportVo.java
  33. 4 0
      fs-service/src/main/java/com/fs/watch/domain/vo/AppFsUserHealthVo.java
  34. 7 0
      fs-service/src/main/java/com/fs/watch/domain/vo/AppFsUserVo.java
  35. 4 0
      fs-service/src/main/java/com/fs/watch/domain/vo/AppWatchSleepDataVo.java
  36. 27 0
      fs-service/src/main/java/com/fs/watch/domain/vo/DailySleepStatusVo.java
  37. 69 0
      fs-service/src/main/java/com/fs/watch/domain/vo/WatchDeviceInfoAndIotExportVO.java
  38. 0 9
      fs-service/src/main/java/com/fs/watch/domain/vo/WatchDeviceInfoAndUserIdVo.java
  39. 2 0
      fs-service/src/main/java/com/fs/watch/domain/vo/WatchSleepDataVo.java
  40. 12 0
      fs-service/src/main/java/com/fs/watch/domain/vo/WatchSportDataByDateAndThirdDeviceVo.java
  41. 10 0
      fs-service/src/main/java/com/fs/watch/domain/vo/WatchSportRecordVo.java
  42. 2 0
      fs-service/src/main/java/com/fs/watch/mapper/WatchAlarmDataMapper.java
  43. 12 0
      fs-service/src/main/java/com/fs/watch/mapper/WatchAudioMsgLogMapper.java
  44. 4 8
      fs-service/src/main/java/com/fs/watch/mapper/WatchBloodPressureDataMapper.java
  45. 2 0
      fs-service/src/main/java/com/fs/watch/mapper/WatchDeviceInfoClicMapper.java
  46. 4 0
      fs-service/src/main/java/com/fs/watch/mapper/WatchDeviceInfoMapper.java
  47. 68 0
      fs-service/src/main/java/com/fs/watch/mapper/WatchDeviceWeekMapper.java
  48. 2 0
      fs-service/src/main/java/com/fs/watch/mapper/WatchDoctorMapper.java
  49. 2 0
      fs-service/src/main/java/com/fs/watch/mapper/WatchHeartRateDataMapper.java
  50. 36 0
      fs-service/src/main/java/com/fs/watch/mapper/WatchSosCallLogsMapper.java
  51. 2 0
      fs-service/src/main/java/com/fs/watch/mapper/WatchSpo2DataMapper.java
  52. 0 1
      fs-service/src/main/java/com/fs/watch/param/WatchChartQueryParam.java
  53. 15 0
      fs-service/src/main/java/com/fs/watch/param/WatchDeviceInfoQueryParam.java
  54. 17 0
      fs-service/src/main/java/com/fs/watch/param/WatchUserByDeviceIdParam.java
  55. 8 0
      fs-service/src/main/java/com/fs/watch/service/DeviceSetUpService.java
  56. 7 0
      fs-service/src/main/java/com/fs/watch/service/WatchAudioMsgLogService.java
  57. 2 1
      fs-service/src/main/java/com/fs/watch/service/WatchBasicInfoService.java
  58. 6 4
      fs-service/src/main/java/com/fs/watch/service/WatchBloodGlucoseDataService.java
  59. 2 0
      fs-service/src/main/java/com/fs/watch/service/WatchBloodPressureDataService.java
  60. 4 3
      fs-service/src/main/java/com/fs/watch/service/WatchDataService.java
  61. 0 24
      fs-service/src/main/java/com/fs/watch/service/WatchDeviceBeginnerGuideService.java
  62. 3 0
      fs-service/src/main/java/com/fs/watch/service/WatchDeviceInfoClicService.java
  63. 2 0
      fs-service/src/main/java/com/fs/watch/service/WatchDeviceInfoService.java
  64. 11 0
      fs-service/src/main/java/com/fs/watch/service/WatchDeviceWeekService.java
  65. 4 2
      fs-service/src/main/java/com/fs/watch/service/WatchHeartRateDataService.java
  66. 1 1
      fs-service/src/main/java/com/fs/watch/service/WatchSleepDataService.java
  67. 33 0
      fs-service/src/main/java/com/fs/watch/service/WatchSosCallLogsService.java
  68. 2 2
      fs-service/src/main/java/com/fs/watch/service/WatchSpo2DataService.java
  69. 3 3
      fs-service/src/main/java/com/fs/watch/service/WatchSportDataService.java
  70. 4 4
      fs-service/src/main/java/com/fs/watch/service/WatchThirdBpDataService.java
  71. 4 4
      fs-service/src/main/java/com/fs/watch/service/WatchThirdUaDataService.java
  72. 6 1
      fs-service/src/main/java/com/fs/watch/service/WatchUserService.java
  73. 63 0
      fs-service/src/main/java/com/fs/watch/service/impl/DeviceSetUpServiceImpl.java
  74. 81 0
      fs-service/src/main/java/com/fs/watch/service/impl/WatchAudioMsgLogServiceImpl.java
  75. 673 31
      fs-service/src/main/java/com/fs/watch/service/impl/WatchBasicInfoServiceImpl.java
  76. 107 24
      fs-service/src/main/java/com/fs/watch/service/impl/WatchBloodGlucoseDataServiceImpl.java
  77. 38 6
      fs-service/src/main/java/com/fs/watch/service/impl/WatchBloodPressureDataServiceImpl.java
  78. 314 116
      fs-service/src/main/java/com/fs/watch/service/impl/WatchDataServiceImpl.java
  79. 0 79
      fs-service/src/main/java/com/fs/watch/service/impl/WatchDeviceBeginnerGuideServiceImpl.java
  80. 97 0
      fs-service/src/main/java/com/fs/watch/service/impl/WatchDeviceInfoClicServiceImpl.java
  81. 11 3
      fs-service/src/main/java/com/fs/watch/service/impl/WatchDeviceInfoServiceImpl.java
  82. 46 14
      fs-service/src/main/java/com/fs/watch/service/impl/WatchHeartRateDataServiceImpl.java
  83. 152 63
      fs-service/src/main/java/com/fs/watch/service/impl/WatchSleepDataServiceImpl.java
  84. 72 0
      fs-service/src/main/java/com/fs/watch/service/impl/WatchSosCallLogsServiceImpl.java
  85. 68 28
      fs-service/src/main/java/com/fs/watch/service/impl/WatchSpo2DataServiceImpl.java
  86. 222 57
      fs-service/src/main/java/com/fs/watch/service/impl/WatchSportDataServiceImpl.java
  87. 76 22
      fs-service/src/main/java/com/fs/watch/service/impl/WatchThirdBpDataServiceImpl.java
  88. 62 17
      fs-service/src/main/java/com/fs/watch/service/impl/WatchThirdUaDataServiceImpl.java
  89. 273 37
      fs-service/src/main/java/com/fs/watch/service/impl/WatchUserServiceImpl.java
  90. 23 0
      fs-service/src/main/java/com/fs/watch/task/HealthCheckTask.java
  91. 207 0
      fs-service/src/main/java/com/fs/watch/utils/AudioConvertUtil.java
  92. 53 0
      fs-service/src/main/java/com/fs/watch/utils/MD5Utils.java
  93. 1 2
      fs-service/src/main/java/com/fs/watch/utils/MyDateTimeUtils.java
  94. 42 12
      fs-service/src/main/java/com/fs/watch/utils/MyHttpUtils.java
  95. 165 152
      fs-service/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml
  96. 136 0
      fs-service/src/main/resources/mapper/his/FsHealthPulseMapper.xml
  97. 148 0
      fs-service/src/main/resources/mapper/his/FsHealthSurfaceMapper.xml
  98. 315 0
      fs-service/src/main/resources/mapper/his/FsThirdDeviceDataMapper.xml
  99. 124 0
      fs-service/src/main/resources/mapper/his/FsUserAdditionalDataMapper.xml
  100. 11 0
      fs-service/src/main/resources/mapper/his/InterestAiChatSessionMapper.xml

+ 12 - 3
fs-company/src/main/java/com/fs/company/controller/course/FsCourseWatchLogController.java

@@ -1,6 +1,7 @@
 package com.fs.company.controller.course;
 
 import cn.hutool.core.util.ObjectUtil;
+import com.fs.common.annotation.DataScope;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
@@ -67,6 +68,7 @@ public class FsCourseWatchLogController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('course:courseWatchLog:list')")
     @GetMapping("/list")
+    @DataScope(deptAlias = "cu", userAlias = "cu")
     public TableDataInfo list(FsCourseWatchLogListParam param)
     {
 
@@ -100,6 +102,7 @@ public class FsCourseWatchLogController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('course:courseWatchLog:deptList')")
     @GetMapping("/deptList")
+    @DataScope(deptAlias = "cu", userAlias = "cu")
     public TableDataInfo deptList(FsCourseWatchLogListParam param) {
 
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
@@ -147,6 +150,7 @@ public class FsCourseWatchLogController extends BaseController
 
     @PreAuthorize("@ss.hasPermi('course:courseWatchLog:deptListExport')")
     @GetMapping("/deptListExport")
+    @DataScope(deptAlias = "cu", userAlias = "cu")
     public AjaxResult  deptListExport(FsCourseWatchLogListParam param){
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
 
@@ -176,7 +180,7 @@ public class FsCourseWatchLogController extends BaseController
                 if (!longs.isEmpty()){
                     param.setPeriodIds(longs);
                 }else {
-                   return  AjaxResult.error("请选择营期时间");
+                    return  AjaxResult.error("请选择营期时间");
                 }
             }else {
                 return  AjaxResult.error("请选择营期时间");
@@ -191,6 +195,7 @@ public class FsCourseWatchLogController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('course:courseWatchLog:myList')")
     @GetMapping("/myList")
+    @DataScope(deptAlias = "cu", userAlias = "cu")
     public TableDataInfo myList(FsCourseWatchLogListParam param)
     {
 
@@ -233,7 +238,7 @@ public class FsCourseWatchLogController extends BaseController
         List<FsCourseWatchLogStatisticsListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogStatisticsListVO(param);
         return getDataTable(list);
     }
-//    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:statisticsExport')")
+    //    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:statisticsExport')")
     @GetMapping("/statisticsExport")
     public  AjaxResult  statisticsExport(FsCourseWatchLogStatisticsListParam param)
     {
@@ -354,6 +359,7 @@ public class FsCourseWatchLogController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:courseWatchLog:export')")
     @Log(title = "短链课程看课记录", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
+    @DataScope(deptAlias = "cu", userAlias = "cu")
     public AjaxResult export(FsCourseWatchLogListParam param)
     {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
@@ -369,6 +375,7 @@ public class FsCourseWatchLogController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:courseWatchLog:myExport')")
     @Log(title = "短链课程看课记录", businessType = BusinessType.EXPORT)
     @GetMapping("/myExport")
+    @DataScope(deptAlias = "cu", userAlias = "cu")
     public AjaxResult myExport(FsCourseWatchLogListParam param)
     {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
@@ -385,6 +392,7 @@ public class FsCourseWatchLogController extends BaseController
      */
 //    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:appSalesReport')")
     @GetMapping("/appSalesWatchLogReport")
+    @DataScope(deptAlias = "cu", userAlias = "cu")
     public TableDataInfo appSalesWatchLogReport(FsCourseWatchLogStatisticsListParam param)
     {
         startPage();
@@ -399,6 +407,7 @@ public class FsCourseWatchLogController extends BaseController
      */
     @Log(title = "APP销售维度看课统计", businessType = BusinessType.EXPORT)
     @GetMapping("/appSalesWatchLogReportExport")
+    @DataScope(deptAlias = "cu", userAlias = "cu")
     public AjaxResult appSalesWatchLogReportExport(FsCourseWatchLogStatisticsListParam param)
     {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
@@ -471,7 +480,7 @@ public class FsCourseWatchLogController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('course:courseWatchLog:remove')")
     @Log(title = "短链课程看课记录", businessType = BusinessType.DELETE)
-	@DeleteMapping("/{logIds}")
+    @DeleteMapping("/{logIds}")
     public AjaxResult remove(@PathVariable Long[] logIds)
     {
         return toAjax(fsCourseWatchLogService.deleteFsCourseWatchLogByLogIds(logIds));

+ 6 - 1
fs-company/src/main/java/com/fs/hisStore/controller/FsStoreStatisticsScrmController.java

@@ -1,6 +1,7 @@
 package com.fs.hisStore.controller;
 
 import com.alibaba.fastjson.JSONObject;
+import com.fs.common.annotation.DataScope;
 import com.fs.common.annotation.Excel;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
@@ -213,6 +214,7 @@ public class FsStoreStatisticsScrmController extends BaseController {
      * 看课统计报表
      */
     @GetMapping("/watchLogReport")
+    @DataScope(deptAlias = "cu", userAlias = "cu")
     public TableDataInfo watchLogReport(FsCourseWatchLogStatisticsListParam param) {
         startPage();
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
@@ -226,6 +228,7 @@ public class FsStoreStatisticsScrmController extends BaseController {
      * @return
      */
     @GetMapping("/appWatchLogReportSales")
+    @DataScope(deptAlias = "cu", userAlias = "cu")
     public TableDataInfo aPPWatchLogReportSales(FsCourseWatchLogStatisticsListParam param) {
         startPage();
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
@@ -239,6 +242,7 @@ public class FsStoreStatisticsScrmController extends BaseController {
      * @return
      */
     @GetMapping("/appWatchLogReportSalesExport")
+    @DataScope(deptAlias = "cu", userAlias = "cu")
     public AjaxResult appWatchLogReportSalesExport(FsCourseWatchLogStatisticsListParam param) {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         param.setCompanyId(loginUser.getCompany().getCompanyId());
@@ -275,7 +279,7 @@ public class FsStoreStatisticsScrmController extends BaseController {
     private List<String> getAppWatchLogReportFields() {
         // 需要排除的字段:app会员数、销售数、新注册app会员数
         List<String> excludeFields = Arrays.asList("AppUserCount", "salesCount", "AppNewUser");
-        
+
         return Arrays.stream(AppWatchLogReportVO.class.getDeclaredFields())
                 .filter(field -> field.isAnnotationPresent(Excel.class))
                 .map(Field::getName)
@@ -284,6 +288,7 @@ public class FsStoreStatisticsScrmController extends BaseController {
     }
 
     @GetMapping("/watchLogReportExport")
+    @DataScope(deptAlias = "cu", userAlias = "cu")
     public AjaxResult watchLogReportExport(FsCourseWatchLogStatisticsListParam param) {
         startPage();
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());

+ 7 - 0
fs-service/src/main/java/com/fs/aiChat/mapper/InterestAiChatSessionMapper.java

@@ -5,6 +5,7 @@ import com.fs.aiChat.domain.DoctorAiChatLog;
 import com.fs.aiChat.domain.InterestAiChatMsg;
 import com.fs.aiChat.domain.InterestAiSession;
 import com.fs.aiChat.domain.SessionRoleInfo;
+import com.fs.aiChat.param.InterestAiMessage;
 import com.fs.his.domain.FsInterestAiMsg;
 import com.fs.his.domain.FsInterestAiRole;
 import com.fs.his.domain.FsInterestAiSession;
@@ -56,4 +57,10 @@ public interface InterestAiChatSessionMapper extends BaseMapper<DoctorAiChatLog>
 
 
     FsInterestAiRole selectFsInterestAiRoleByRoleId(Long roleId);
+
+    Integer selectSessionIdByUserAndRole(@Param("userId") Long userId, @Param("roleId") Integer roleId);
+
+    FsInterestAiSession selectSessionBySessionId(@Param("sessionId") String sessionId);
+
+    Integer selectAiMsgBySessionIdAndMsg(@Param("param") InterestAiMessage message);
 }

+ 2 - 1
fs-service/src/main/java/com/fs/course/param/FsCourseWatchLogListParam.java

@@ -1,6 +1,7 @@
 package com.fs.course.param;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.core.domain.BaseEntity;
 import lombok.Data;
 
 import java.io.Serializable;
@@ -8,7 +9,7 @@ import java.util.Date;
 import java.util.List;
 
 @Data
-public class FsCourseWatchLogListParam implements Serializable {
+public class FsCourseWatchLogListParam extends BaseEntity implements Serializable {
 
     private Long userId;
 

+ 78 - 0
fs-service/src/main/java/com/fs/his/domain/FsHealthPulse.java

@@ -0,0 +1,78 @@
+package com.fs.his.domain;
+
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 脉诊对象 fs_health_pulse
+ *
+ * @author fs
+ * @date 2025-10-11
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsHealthPulse extends BaseEntity{
+
+    /** id */
+    private Long id;
+
+    /** 用户id */
+    @Excel(name = "用户id")
+    private Long userId;
+
+    /** 用户名 */
+    @Excel(name = "用户名")
+    private String name;
+
+    /** 性别 */
+    @Excel(name = "性别")
+    private Long sex;
+
+    /** 年龄 */
+    @Excel(name = "年龄")
+    private Long age;
+
+    /** 状态 */
+    @Excel(name = "状态")
+    private Long status;
+
+    /** 左手结果 */
+    @Excel(name = "左手结果")
+    private String leftHandResult;
+
+    /** 右手结果 */
+    @Excel(name = "右手结果")
+    private String rightHandResult;
+
+    /** 脉诊总结 */
+    @Excel(name = "脉诊总结")
+    private String pulseSummary;
+
+    /** 脉诊建议 */
+    @Excel(name = "脉诊建议")
+    private String pulseSuggestions;
+
+    /** 脉诊设备测量ID */
+    @Excel(name = "脉诊设备测量ID")
+    private String measureId;
+
+    /**左手尺寸 */
+    @TableField(exist = false)
+    private String leftHandSize;
+
+     /**右手尺寸 */
+    @TableField(exist = false)
+    private String rightHandSize;
+
+    /**脉诊设备检测结果*/
+    @TableField(exist = false)
+    private Object pulseEquipmentResult;
+
+    /** url */
+    @Excel(name = "url")
+    private String pulseUrl;
+}

+ 83 - 0
fs-service/src/main/java/com/fs/his/domain/FsHealthSurface.java

@@ -0,0 +1,83 @@
+package com.fs.his.domain;
+
+
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+
+/**
+ * 面诊对象 fs_health_surface
+ *
+ * @author fs
+ * @date 2025-10-10
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsHealthSurface extends BaseEntity{
+
+    /** id */
+    private Long id;
+
+    /** 用户id */
+    @Excel(name = "用户id")
+    private Long userId;
+
+    /** 用户名 */
+    @Excel(name = "用户名")
+    private String name;
+
+    /** 性别 */
+    @Excel(name = "性别")
+    private Integer sex;
+
+    /** 年龄 */
+    @Excel(name = "年龄")
+    private Integer age;
+
+    /** 状态 */
+    @Excel(name = "状态")
+    private Integer status;
+
+    /** 面诊图片 */
+    @Excel(name = "面诊图片")
+    private String surfaceUrl;
+
+    /** 肤色的结果 */
+    @Excel(name = "肤色的结果")
+    private String complexionResult;
+
+    /** 肤色结果类型 */
+    @Excel(name = "肤色结果类型")
+    private String complexionTypes;
+
+    /** 区域色斑问题 */
+    @Excel(name = "区域色斑问题")
+    private String spotProblems;
+
+    /** 浮肿问题 */
+    @Excel(name = "浮肿问题")
+    private String swellingProblems;
+
+    /** 光泽度结果 */
+    @Excel(name = "光泽度结果")
+    private String glowResult;
+
+    /** 面诊总结 */
+    @Excel(name = "面诊总结")
+    private String diagnosisSummary;
+
+    /** 健康建议 */
+    @Excel(name = "健康建议")
+    private String healthSuggestions;
+
+    /** 时间 */
+    @Excel(name = "时间")
+    private Date createTime;
+
+    /** 备注 */
+    @Excel(name = "备注")
+    private String remark;
+}

+ 48 - 0
fs-service/src/main/java/com/fs/his/domain/FsThirdDeviceData.java

@@ -0,0 +1,48 @@
+package com.fs.his.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 三方设备健康数据对象 fs_third_device_data
+ *
+ * @author fs
+ * @date 2026-03-19
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsThirdDeviceData extends BaseEntity{
+
+    /** 记录id */
+    @TableId
+    private Long id;
+
+    /** 用户id */
+    @Excel(name = "用户id")
+    private Long userId;
+
+    /** 记录类型 0:血压 1:血糖 2:心率  3尿酸 4血氧 */
+    @Excel(name = "记录类型 0:血压 1:血糖 2:心率  3尿酸 4血氧 5步数 6运动 7睡眠")
+    private Integer recordType;
+
+    /** 记录数值 */
+    @Excel(name = "记录数值")
+    private String recordValue;
+
+    /** 记录数值 */
+    @Excel(name = "设备id")
+    private String deviceId;
+
+    /** 设备类型 0小护士设备 1手表 */
+    @Excel(name = "设备类型 0小护士设备 1手表")
+    private Integer deviceType;
+
+    /** 状态 */
+    @Excel(name = "状态")
+    private Integer status;
+
+
+}

+ 84 - 0
fs-service/src/main/java/com/fs/his/domain/FsUserAdditionalData.java

@@ -0,0 +1,84 @@
+package com.fs.his.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 设备注册用户额外参数对象 fs_user_additional_data
+ *
+ * @author fs
+ * @date 2025-10-17
+ */
+@Data
+public class FsUserAdditionalData {
+
+    /** $column.columnComment */
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /** 用户名 */
+    @Excel(name = "用户名")
+    private String username;
+
+    /** 用户ID */
+    @Excel(name = "用户ID")
+    private Long fsUserId;
+
+    /** 电话 */
+    @Excel(name = "电话")
+    private String phone;
+
+    /** 身高 */
+    @Excel(name = "身高")
+    private String height;
+
+    /** 体重 */
+    @Excel(name = "体重")
+    private String weight;
+
+    /** 年龄-出生年月 */
+    @Excel(name = "年龄-出生年月")
+    private String age;
+
+    /** 性别 */
+    @Excel(name = "性别")
+    private Integer sex;
+
+    /** 既往病史 */
+    @Excel(name = "既往病史")
+    private String previousMedicalHistory;
+
+    /** 创建时间 **/
+    private Date createTime;
+
+    /** 状态 */
+    @Excel(name = "状态")
+    private Integer status;
+
+    /** 备注 **/
+    private String remark;
+
+    /** 脉诊设备返回H5 **/
+    private String pulseUrl;
+
+    /** 过敏史 */
+    private String historyOfAllergies;
+
+    /** 生活习惯 */
+    private String habit;
+
+    @TableField(exist = false)
+    private List<Object> habitList;
+
+    /** 身份证号码 **/
+    private String idCard;
+
+    private String consultationRecord;
+
+}

+ 74 - 0
fs-service/src/main/java/com/fs/his/mapper/FsHealthPulseMapper.java

@@ -0,0 +1,74 @@
+package com.fs.his.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.his.domain.FsHealthPulse;
+import com.fs.his.param.FsHealthPulseListUParam;
+import com.fs.his.vo.FsHealthPulseListVO;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+/**
+ * 脉诊Mapper接口
+ *
+ * @author fs
+ * @date 2025-10-11
+ */
+public interface FsHealthPulseMapper extends BaseMapper<FsHealthPulse>{
+    /**
+     * 查询脉诊
+     *
+     * @param id 脉诊主键
+     * @return 脉诊
+     */
+    FsHealthPulse selectFsHealthPulseById(Long id);
+
+    /**
+     * 查询脉诊列表
+     *
+     * @param fsHealthPulse 脉诊
+     * @return 脉诊集合
+     */
+    List<FsHealthPulse> selectFsHealthPulseList(FsHealthPulse fsHealthPulse);
+
+    /**
+     * 新增脉诊
+     *
+     * @param fsHealthPulse 脉诊
+     * @return 结果
+     */
+    int insertFsHealthPulse(FsHealthPulse fsHealthPulse);
+
+    /**
+     * 修改脉诊
+     *
+     * @param fsHealthPulse 脉诊
+     * @return 结果
+     */
+    int updateFsHealthPulse(FsHealthPulse fsHealthPulse);
+
+    /**
+     * 删除脉诊
+     *
+     * @param id 脉诊主键
+     * @return 结果
+     */
+    int deleteFsHealthPulseById(Long id);
+
+    /**
+     * 批量删除脉诊
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsHealthPulseByIds(Long[] ids);
+
+    @Select("SELECT * from fs_health_pulse where user_id=#{userId} and status=0 order by create_time desc limit 1")
+    FsHealthPulse queryUserLatestHealthPulse(@Param("userId") Long userId);
+
+    List<FsHealthPulseListVO> selectFsHealthPulseListVO(FsHealthPulseListUParam param);
+
+    List<String> selectListByDateAndUserId(@Param("startDate") String startDate,@Param("endDate") String endDate,@Param("userId") Long userId);
+
+}

+ 77 - 0
fs-service/src/main/java/com/fs/his/mapper/FsHealthSurfaceMapper.java

@@ -0,0 +1,77 @@
+package com.fs.his.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.his.domain.FsHealthSurface;
+import com.fs.his.param.FsHealthSurfaceListUParam;
+import com.fs.his.vo.FsHealthSurfaceListVO;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+
+/**
+ * 面诊Mapper接口
+ *
+ * @author fs
+ * @date 2025-10-10
+ */
+public interface FsHealthSurfaceMapper extends BaseMapper<FsHealthSurface>{
+    /**
+     * 查询面诊
+     *
+     * @param id 面诊主键
+     * @return 面诊
+     */
+    FsHealthSurface selectFsHealthSurfaceById(Long id);
+
+    /**
+     * 查询面诊列表
+     *
+     * @param fsHealthSurface 面诊
+     * @return 面诊集合
+     */
+    List<FsHealthSurface> selectFsHealthSurfaceList(FsHealthSurface fsHealthSurface);
+
+    /**
+     * 新增面诊
+     *
+     * @param fsHealthSurface 面诊
+     * @return 结果
+     */
+    int insertFsHealthSurface(FsHealthSurface fsHealthSurface);
+
+    /**
+     * 修改面诊
+     *
+     * @param fsHealthSurface 面诊
+     * @return 结果
+     */
+    int updateFsHealthSurface(FsHealthSurface fsHealthSurface);
+
+    /**
+     * 删除面诊
+     *
+     * @param id 面诊主键
+     * @return 结果
+     */
+    int deleteFsHealthSurfaceById(Long id);
+
+    /**
+     * 批量删除面诊
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsHealthSurfaceByIds(Long[] ids);
+
+    @Select("SELECT * from fs_health_surface where user_id=#{userId} and status=0 order by create_time desc limit 1")
+    FsHealthSurface queryUserLatestHealthSurface(@Param("userId") Long userId);
+
+    List<FsHealthSurfaceListVO> selectFsHealthSurfaceListVO(FsHealthSurfaceListUParam param);
+
+    List<String> selectListByDateAndUserId(@Param("startDate") String startDate,@Param("endDate") String endDate,@Param("userId") Long userId);
+
+
+
+}

+ 147 - 0
fs-service/src/main/java/com/fs/his/mapper/FsThirdDeviceDataMapper.java

@@ -0,0 +1,147 @@
+package com.fs.his.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.his.domain.FsThirdDeviceData;
+import com.fs.watch.domain.vo.WatchSportRecordVo;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 三方设备健康数据Mapper接口
+ * 
+ * @author fs
+ * @date 2026-03-19
+ */
+public interface FsThirdDeviceDataMapper extends BaseMapper<FsThirdDeviceData>{
+    /**
+     * 查询三方设备健康数据
+     * 
+     * @param id 三方设备健康数据主键
+     * @return 三方设备健康数据
+     */
+    FsThirdDeviceData selectFsThirdDeviceDataById(Long id);
+
+    /**
+     * 查询三方设备健康数据列表
+     * 
+     * @param fsThirdDeviceData 三方设备健康数据
+     * @return 三方设备健康数据集合
+     */
+    List<FsThirdDeviceData> selectFsThirdDeviceDataList(FsThirdDeviceData fsThirdDeviceData);
+
+    /**
+     * 新增三方设备健康数据
+     * 
+     * @param fsThirdDeviceData 三方设备健康数据
+     * @return 结果
+     */
+    int insertFsThirdDeviceData(FsThirdDeviceData fsThirdDeviceData);
+
+    /**
+     * 修改三方设备健康数据
+     * 
+     * @param fsThirdDeviceData 三方设备健康数据
+     * @return 结果
+     */
+    int updateFsThirdDeviceData(FsThirdDeviceData fsThirdDeviceData);
+
+    /**
+     * 删除三方设备健康数据
+     * 
+     * @param id 三方设备健康数据主键
+     * @return 结果
+     */
+    int deleteFsThirdDeviceDataById(Long id);
+
+    /**
+     * 批量删除三方设备健康数据
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsThirdDeviceDataByIds(Long[] ids);
+
+//    Map<String, Integer> countMaxAndMinBpByDate(String currentStartDate, String currentEndDate, String deviceId);
+
+    void insertFsThirdDeviceDataList(@Param("list") List<FsThirdDeviceData> fsThirdDeviceData);
+
+    List<FsThirdDeviceData> getLastData(@Param("userId")Long userId,@Param("deviceType") Integer deviceType,@Param("deviceId") String deviceId);
+
+    /**
+     * 血压
+     * @param startTime
+     * @param endTime
+     * @param deviceId
+     * @return
+     */
+    Map<String, Integer> countMaxAndMinBpByDate(@Param("startTime") String startTime, @Param("endTime") String endTime,
+                                                @Param("deviceId") String deviceId);
+
+    List<FsThirdDeviceData> queryBgByDate(@Param("startTime")String startTime,@Param("endTime") String endTime,
+                                              @Param("deviceId")String deviceId);
+
+    Map<String, Integer> countMaxAndAvgBpByDate(@Param("startTime")String startTime, @Param("endTime") String endTime,
+                                                @Param("deviceId")String deviceId);
+
+    FsThirdDeviceData getFirstDataByDeviceId(@Param("deviceId")String deviceId);
+
+    List<FsThirdDeviceData> queryByMonth(@Param("deviceId")String deviceId, @Param("monthStr")String monthStr,
+                                           @Param("recordType")Integer recordType);
+
+    FsThirdDeviceData getLatest(@Param("deviceId")String deviceId,
+                                @Param("recordType")Integer recordType);
+
+    List<FsThirdDeviceData> selectListByDateAndDeviceIdAndRecordType(@Param("startTime")Date startTime,
+                                                                     @Param("endTime") Date endTime,
+                                                                     @Param("deviceId")String deviceId,
+                                                                     @Param("recordType")Integer recordType,
+                                                                     @Param("status")Integer status);
+
+    List<Map<String, Object>> countByDateAndDeviceIdAndRecordType(@Param("startTime")Date startTime,
+                                                                  @Param("endTime") Date endTime,
+                                                                  @Param("deviceId")String deviceId,
+                                                                  @Param("recordType")Integer recordType,
+                                                                  @Param("status")Integer status);
+
+    int countPageByDateAndDeviceIdAndRecordType(@Param("startTime")Date startTime,
+                                                @Param("endTime") Date endTime,
+                                                @Param("deviceId")String deviceId,
+                                                @Param("recordType")Integer recordType,
+                                                @Param("status")Integer status);
+
+    List<FsThirdDeviceData> queryPageByDateAndDeviceIdAndRecordType(@Param("startTime")Date startTime,
+                                                                    @Param("endTime") Date endTime,
+                                                                    @Param("deviceId")String deviceId,
+                                                                    @Param("recordType")Integer recordType,
+                                                                    @Param("status")Integer status,
+                                                                    @Param("num")Integer num,
+                                                                    @Param("size")Integer size
+                                                                    );
+
+    Float countAvgBpByDate(@Param("startTime") String startTime, @Param("endTime") String endTime, @Param("deviceId") String deviceId);
+
+    WatchSportRecordVo getOtherData(@Param("startTime")Date startTime,
+                                    @Param("endTime") Date endTime,
+                                    @Param("deviceId")String deviceId,
+                                    @Param("recordType")Integer recordType,
+                                    @Param("status")Integer status);
+
+    List<WatchSportRecordVo> queryActivityRecord(@Param("startTime")Date startTime,
+                                                 @Param("endTime") Date endTime,
+                                                 @Param("deviceId")String deviceId,
+                                                 @Param("recordType")Integer recordType,
+                                                 @Param("status")Integer status);
+
+    WatchSportRecordVo getOtherDataOther(@Param("startTime")Date startTime,
+                                         @Param("endTime") Date endTime,
+                                         @Param("deviceId")String deviceId,
+                                         @Param("recordType")Integer recordType);
+
+    List<FsThirdDeviceData> selectListByDateAndDeviceIdAndRecordTypeOther(@Param("startTime")Date startTime,
+                                                                          @Param("endTime") Date endTime,
+                                                                          @Param("deviceId")String deviceId,
+                                                                          @Param("recordType")Integer recordType);
+}

+ 68 - 0
fs-service/src/main/java/com/fs/his/mapper/FsUserAdditionalDataMapper.java

@@ -0,0 +1,68 @@
+package com.fs.his.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.his.domain.FsUserAdditionalData;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+
+/**
+ * 设备注册用户额外参数Mapper接口
+ *
+ * @author fs
+ * @date 2025-10-17
+ */
+public interface FsUserAdditionalDataMapper extends BaseMapper<FsUserAdditionalData>{
+    /**
+     * 查询设备注册用户额外参数
+     *
+     * @param id 设备注册用户额外参数主键
+     * @return 设备注册用户额外参数
+     */
+    FsUserAdditionalData selectFsUserAdditionalDataById(Long id);
+
+    /**
+     * 查询设备注册用户额外参数列表
+     *
+     * @param fsUserAdditionalData 设备注册用户额外参数
+     * @return 设备注册用户额外参数集合
+     */
+    List<FsUserAdditionalData> selectFsUserAdditionalDataList(FsUserAdditionalData fsUserAdditionalData);
+
+    /**
+     * 新增设备注册用户额外参数
+     *
+     * @param fsUserAdditionalData 设备注册用户额外参数
+     * @return 结果
+     */
+    int insertFsUserAdditionalData(FsUserAdditionalData fsUserAdditionalData);
+
+    /**
+     * 修改设备注册用户额外参数
+     *
+     * @param fsUserAdditionalData 设备注册用户额外参数
+     * @return 结果
+     */
+    int updateFsUserAdditionalData(FsUserAdditionalData fsUserAdditionalData);
+
+    /**
+     * 删除设备注册用户额外参数
+     *
+     * @param id 设备注册用户额外参数主键
+     * @return 结果
+     */
+    int deleteFsUserAdditionalDataById(Long id);
+
+    /**
+     * 批量删除设备注册用户额外参数
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsUserAdditionalDataByIds(Long[] ids);
+
+    @Select("select * from fs_user_additional_data where status=0 and fs_user_id=#{fsUserId}")
+    FsUserAdditionalData selectUserByUserId(@Param("fsUserId") Long fsUserId);
+}

+ 16 - 0
fs-service/src/main/java/com/fs/his/param/FsHealthPulseListUParam.java

@@ -0,0 +1,16 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class FsHealthPulseListUParam extends BaseParam implements Serializable {
+    /** id */
+    private Long id;
+
+
+    private Long userId;
+
+    private String createDay;
+}

+ 16 - 0
fs-service/src/main/java/com/fs/his/param/FsHealthSurfaceListUParam.java

@@ -0,0 +1,16 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class FsHealthSurfaceListUParam extends BaseParam implements Serializable {
+    /** id */
+    private Long id;
+
+
+    private Long userId;
+
+    private String createDay;
+}

+ 2 - 0
fs-service/src/main/java/com/fs/his/param/FsHealthTongueListUParam.java

@@ -12,4 +12,6 @@ public class FsHealthTongueListUParam extends BaseParam implements Serializable
     /** 状态 */
     @Excel(name = "状态")
     private Long userId;
+
+    private String createDay;
 }

+ 80 - 0
fs-service/src/main/java/com/fs/his/service/IFsThirdDeviceDataService.java

@@ -0,0 +1,80 @@
+package com.fs.his.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.his.domain.FsThirdDeviceData;
+import com.fs.watch.domain.vo.WatchSportDataByDateVo;
+import com.fs.watch.domain.vo.WatchSportDetailDataVo;
+import com.fs.watch.domain.vo.WatchSportRecordVo;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 三方设备健康数据Service接口
+ * 
+ * @author fs
+ * @date 2026-03-19
+ */
+public interface IFsThirdDeviceDataService extends IService<FsThirdDeviceData>{
+    /**
+     * 查询三方设备健康数据
+     * 
+     * @param id 三方设备健康数据主键
+     * @return 三方设备健康数据
+     */
+    FsThirdDeviceData selectFsThirdDeviceDataById(Long id);
+
+    /**
+     * 查询三方设备健康数据列表
+     * 
+     * @param fsThirdDeviceData 三方设备健康数据
+     * @return 三方设备健康数据集合
+     */
+    List<FsThirdDeviceData> selectFsThirdDeviceDataList(FsThirdDeviceData fsThirdDeviceData);
+
+    /**
+     * 新增三方设备健康数据
+     * 
+     * @param fsThirdDeviceData 三方设备健康数据
+     * @return 结果
+     */
+    int insertFsThirdDeviceData(FsThirdDeviceData fsThirdDeviceData);
+
+    /**
+     * 修改三方设备健康数据
+     * 
+     * @param fsThirdDeviceData 三方设备健康数据
+     * @return 结果
+     */
+    int updateFsThirdDeviceData(FsThirdDeviceData fsThirdDeviceData);
+
+    /**
+     * 批量删除三方设备健康数据
+     * 
+     * @param ids 需要删除的三方设备健康数据主键集合
+     * @return 结果
+     */
+    int deleteFsThirdDeviceDataByIds(Long[] ids);
+
+    /**
+     * 删除三方设备健康数据信息
+     * 
+     * @param id 三方设备健康数据主键
+     * @return 结果
+     */
+    int deleteFsThirdDeviceDataById(Long id);
+
+    void insertFsThirdDeviceDataList(List<FsThirdDeviceData> fsThirdDeviceData);
+
+    List<FsThirdDeviceData> getLastData(Long userId,Integer deviceType,String deviceId);
+
+    List<WatchSportDataByDateVo> sportDataByDate(Date startTime, Date endTime, String deviceId);
+
+    WatchSportDetailDataVo dataByType(String deviceId, String type);
+
+    public WatchSportRecordVo getOtherData(Date startTime,
+                                           Date endTime,
+                                           String deviceId,
+                                           Integer recordType,
+                                           Integer status);
+}

+ 65 - 0
fs-service/src/main/java/com/fs/his/service/IFsUserAdditionalDataService.java

@@ -0,0 +1,65 @@
+package com.fs.his.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.his.domain.FsUserAdditionalData;
+
+import java.util.List;
+
+/**
+ * 设备注册用户额外参数Service接口
+ *
+ * @author fs
+ * @date 2025-10-17
+ */
+public interface IFsUserAdditionalDataService extends IService<FsUserAdditionalData>{
+    /**
+     * 查询设备注册用户额外参数
+     *
+     * @param id 设备注册用户额外参数主键
+     * @return 设备注册用户额外参数
+     */
+    FsUserAdditionalData selectFsUserAdditionalDataById(Long id);
+
+    /**
+     * 查询设备注册用户额外参数列表
+     *
+     * @param fsUserAdditionalData 设备注册用户额外参数
+     * @return 设备注册用户额外参数集合
+     */
+    List<FsUserAdditionalData> selectFsUserAdditionalDataList(FsUserAdditionalData fsUserAdditionalData);
+
+    /**
+     * 新增设备注册用户额外参数
+     *
+     * @param fsUserAdditionalData 设备注册用户额外参数
+     * @return 结果
+     */
+    int insertFsUserAdditionalData(FsUserAdditionalData fsUserAdditionalData);
+
+    /**
+     * 修改设备注册用户额外参数
+     *
+     * @param fsUserAdditionalData 设备注册用户额外参数
+     * @return 结果
+     */
+    int updateFsUserAdditionalData(FsUserAdditionalData fsUserAdditionalData);
+
+    /**
+     * 批量删除设备注册用户额外参数
+     *
+     * @param ids 需要删除的设备注册用户额外参数主键集合
+     * @return 结果
+     */
+    int deleteFsUserAdditionalDataByIds(Long[] ids);
+
+    /**
+     * 删除设备注册用户额外参数信息
+     *
+     * @param id 设备注册用户额外参数主键
+     * @return 结果
+     */
+    int deleteFsUserAdditionalDataById(Long id);
+
+    FsUserAdditionalData selectUserByUserId(Long fsUserId);
+
+}

+ 435 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsThirdDeviceDataServiceImpl.java

@@ -0,0 +1,435 @@
+package com.fs.his.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.his.domain.FsThirdDeviceData;
+import com.fs.his.mapper.FsThirdDeviceDataMapper;
+import com.fs.his.service.IFsThirdDeviceDataService;
+import com.fs.watch.domain.vo.WatchSportDataByDateAndThirdDeviceVo;
+import com.fs.watch.domain.vo.WatchSportDataByDateVo;
+import com.fs.watch.domain.vo.WatchSportDetailDataVo;
+import com.fs.watch.domain.vo.WatchSportRecordVo;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAdjusters;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 三方设备健康数据Service业务层处理
+ * 
+ * @author fs
+ * @date 2026-03-19
+ */
+@Service
+public class FsThirdDeviceDataServiceImpl extends ServiceImpl<FsThirdDeviceDataMapper, FsThirdDeviceData> implements IFsThirdDeviceDataService {
+
+    /**
+     * 查询三方设备健康数据
+     * 
+     * @param id 三方设备健康数据主键
+     * @return 三方设备健康数据
+     */
+    @Override
+    public FsThirdDeviceData selectFsThirdDeviceDataById(Long id)
+    {
+        return baseMapper.selectFsThirdDeviceDataById(id);
+    }
+
+    /**
+     * 查询三方设备健康数据列表
+     * 
+     * @param fsThirdDeviceData 三方设备健康数据
+     * @return 三方设备健康数据
+     */
+    @Override
+    public List<FsThirdDeviceData> selectFsThirdDeviceDataList(FsThirdDeviceData fsThirdDeviceData)
+    {
+        return baseMapper.selectFsThirdDeviceDataList(fsThirdDeviceData);
+    }
+
+    /**
+     * 新增三方设备健康数据
+     * 
+     * @param fsThirdDeviceData 三方设备健康数据
+     * @return 结果
+     */
+    @Override
+    public int insertFsThirdDeviceData(FsThirdDeviceData fsThirdDeviceData)
+    {
+        fsThirdDeviceData.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertFsThirdDeviceData(fsThirdDeviceData);
+    }
+
+    /**
+     * 修改三方设备健康数据
+     * 
+     * @param fsThirdDeviceData 三方设备健康数据
+     * @return 结果
+     */
+    @Override
+    public int updateFsThirdDeviceData(FsThirdDeviceData fsThirdDeviceData)
+    {
+        return baseMapper.updateFsThirdDeviceData(fsThirdDeviceData);
+    }
+
+    /**
+     * 批量删除三方设备健康数据
+     * 
+     * @param ids 需要删除的三方设备健康数据主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsThirdDeviceDataByIds(Long[] ids)
+    {
+        return baseMapper.deleteFsThirdDeviceDataByIds(ids);
+    }
+
+    /**
+     * 删除三方设备健康数据信息
+     * 
+     * @param id 三方设备健康数据主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsThirdDeviceDataById(Long id)
+    {
+        return baseMapper.deleteFsThirdDeviceDataById(id);
+    }
+
+    @Override
+    public void insertFsThirdDeviceDataList(List<FsThirdDeviceData> fsThirdDeviceData) {
+        baseMapper.insertFsThirdDeviceDataList(fsThirdDeviceData);
+    }
+
+    @Override
+    public List<FsThirdDeviceData> getLastData(Long userId,Integer deviceType,String deviceId) {
+        return baseMapper.getLastData(userId,deviceType,deviceId);
+    }
+
+    /**
+     * 查询运动
+     * @param startTime
+     * @param endTime
+     * @param deviceId
+     * @return
+     */
+    @Override
+    public List<WatchSportDataByDateVo> sportDataByDate(Date startTime, Date endTime, String deviceId) {
+        //活动
+        ArrayList<FsThirdDeviceData> activity = new ArrayList<>();
+        List<FsThirdDeviceData> activity1 = baseMapper.selectListByDateAndDeviceIdAndRecordType(startTime, endTime, deviceId,5,null);
+        activity.addAll(activity1);
+//        activity.addAll(activity2);
+        //解析成活动数据
+        if(!activity.isEmpty()){
+            ArrayList<WatchSportDataByDateAndThirdDeviceVo> vos = new ArrayList<>();
+            for (FsThirdDeviceData fsThirdDeviceData : activity) {
+                String recordValue = fsThirdDeviceData.getRecordValue();
+                if (StringUtils.isNotBlank(recordValue)) {
+                    WatchSportDataByDateAndThirdDeviceVo data = new WatchSportDataByDateAndThirdDeviceVo();
+                    JSONObject jsonObject = JSONObject.parseObject(recordValue);
+                    data.setDeviceId(jsonObject.getString("deviceId"));
+                    data.setStep(Integer.valueOf(jsonObject.get("steps").toString()));
+                    data.setDistance(Float.parseFloat(jsonObject.get("distance").toString())*1000);
+                    data.setCalorie(Float.valueOf(jsonObject.get("calories").toString()));
+//                    data.setType(getActivityType(Integer.valueOf(jsonObject.get("sportType").toString())));
+                    data.setState(0);
+                    data.setCreateTime(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss",fsThirdDeviceData.getCreateTime()));
+                    vos.add(data);
+
+                }
+            }
+            // 计算时间差(以毫秒为单位)
+            long timeDifferenceInMillis = endTime.getTime() - startTime.getTime();
+
+            // 判断是一天还是一周
+            if (timeDifferenceInMillis > 24 * 60 * 60 * 1000) {
+                // 一周的数据(按天统计)
+                return getWeekData(vos, LocalDateTime.ofInstant(startTime.toInstant(), ZoneId.systemDefault()),
+                        LocalDateTime.ofInstant(endTime.toInstant(), ZoneId.systemDefault()));
+            } else {
+                // 一天的数据(按小时统计)
+                return getDayData(vos);
+            }
+        }
+        return null;
+
+    }
+
+    @Override
+    public WatchSportDetailDataVo dataByType(String deviceId, String type) {
+        if (StringUtils.isNotBlank(deviceId)) {
+            //详情
+            WatchSportDetailDataVo vo = new WatchSportDetailDataVo();
+            ArrayList<WatchSportDataByDateVo> list = new ArrayList<>();
+            //1.总计 距离 次数
+            WatchSportRecordVo recordVo = null; //总计只有一条数据
+            List<FsThirdDeviceData> otherDetail = null;
+            if ("其他运动".equals(type)) {
+                //游泳", "登山", "骑行", "跑步", "球类", "健走", "走路"
+                //25,17,1,9,21,5,13
+                recordVo = baseMapper.getOtherDataOther(null, null, deviceId, 6);
+                otherDetail = baseMapper.selectListByDateAndDeviceIdAndRecordTypeOther(null, null, deviceId, 6);
+            } else {
+                Integer sportType = getSportType(type);
+                //步数
+                recordVo = baseMapper.getOtherData(null, null, deviceId, 6, sportType);
+                //2.详情
+                otherDetail = baseMapper.selectListByDateAndDeviceIdAndRecordType(null, null, deviceId, 6, sportType);
+            }
+            long otherTime = 0L;
+            if (otherDetail != null && !otherDetail.isEmpty()) {
+                for (FsThirdDeviceData fsThirdDeviceData : otherDetail) {
+                    String recordValue = fsThirdDeviceData.getRecordValue();
+                    if (StringUtils.isNotBlank(recordValue)) {
+                        JSONObject jsonObject = JSONObject.parseObject(recordValue);
+                        float distance = Float.parseFloat(jsonObject.get("distance").toString());
+                        Float calories = Float.valueOf(jsonObject.get("calories").toString());
+                        String createTime = DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", fsThirdDeviceData.getCreateTime());
+                        float duration = Float.parseFloat(jsonObject.get("duration").toString());
+                        otherTime = otherTime + Long.parseLong(jsonObject.get("duration").toString());
+
+                        //详情
+                        WatchSportDataByDateVo watchSportDataByDateVo = new WatchSportDataByDateVo();
+                        watchSportDataByDateVo.setCreateTime(createTime);
+                        watchSportDataByDateVo.setCalorie(calories);
+                        watchSportDataByDateVo.setDistance(distance);
+                        watchSportDataByDateVo.setTime(duration);
+                        watchSportDataByDateVo.setSpeed((float) Math.round((distance)/(duration/3600)));
+                        list.add(watchSportDataByDateVo);
+                    }
+                }
+            }
+            if (recordVo != null) {
+                vo.setDistanceTotal(recordVo.getDistance()); //换算公里 保留两位
+                vo.setCountTotal(recordVo.getCount());
+                //1.2时长
+                BigDecimal timeInMinutes = new BigDecimal(otherTime)
+                        .divide(new BigDecimal(3600), 2, RoundingMode.HALF_UP);
+                vo.setTimeTotal(Float.valueOf(timeInMinutes+""));
+            }
+            vo.setList(list);
+            return vo;
+        }
+        return null;
+    }
+
+    private String getActivityType(Integer sportType) {
+        if (sportType == null) {
+            return null;
+        }
+        switch (sportType) {
+            case 1:
+                return "骑行";
+            case 5:
+                return "户外跑/健走";
+            case 9:
+                return "室内跑";
+            case 13:
+                return "步行";
+            case 17:
+                return "爬山";
+            case 21:
+                return "篮球";
+            case 25:
+                return "游泳";
+            case 29:
+                return "羽毛球";
+            case 33:
+                return "足球";
+            case 37:
+                return "椭圆机";
+            case 41:
+                return "瑜伽";
+            case 45:
+                return "乒乓球";
+            case 49:
+                return "跳绳";
+            case 53:
+                return "划船机";
+            case 65:
+                return "自由训练";
+            case 69:
+                return "网球";
+            case 85:
+                return "自由运动";
+            case 89:
+                return "力量训练";
+            case 105:
+                return "舞蹈";
+            case 109:
+                return "呼啦圈";
+            case 113:
+                return "高尔夫";
+            default:
+                return null;
+        }
+    }
+
+    private Integer getSportType(String activityType) {
+        //游泳", "登山", "骑行", "跑步", "球类", "健走", "走路" 25,17,1,9,21,5,13
+        if (activityType == null || activityType.isEmpty()) {
+            return null;
+        }
+        switch (activityType) {
+            case "骑行":
+                return 1;
+            case "健步走":
+                return 5;
+            case "跑步":
+                return 9;
+            case "走路":
+                return 13;
+            case "登山":
+                return 17;
+            case "球类":
+                return 21;
+            case "游泳":
+                return 25;
+            case "羽毛球":
+                return 29;
+            case "足球":
+                return 33;
+            case "椭圆机":
+                return 37;
+            case "瑜伽":
+                return 41;
+            case "乒乓球":
+                return 45;
+            case "跳绳":
+                return 49;
+            case "划船机":
+                return 53;
+            case "自由训练":
+                return 65;
+            case "网球":
+                return 69;
+            case "自由运动":
+                return 85;
+            case "力量训练":
+                return 89;
+            case "舞蹈":
+                return 105;
+            case "呼啦圈":
+                return 109;
+            case "高尔夫":
+                return 113;
+            default:
+                return null;
+
+        }
+    }
+
+    private List<WatchSportDataByDateVo> getWeekData(List<WatchSportDataByDateAndThirdDeviceVo> activity, LocalDateTime startTime, LocalDateTime endTime) {
+        // 按天分组
+        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        Map<LocalDate, List<WatchSportDataByDateAndThirdDeviceVo>> groupedByDate = activity.stream()
+                .collect(Collectors.groupingBy(data -> {
+                    LocalDateTime dateTime = LocalDateTime.parse(data.getCreateTime(), dateTimeFormatter);
+                    return dateTime.toLocalDate();
+                }));
+
+        // 确定一周的起始日期(周一)
+        LocalDate startOfWeek = startTime.toLocalDate().with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
+        // 初始化结果列表,确保返回7天的数据
+        List<WatchSportDataByDateVo> result = new ArrayList<>();
+        for (int i = 0; i < 7; i++) {
+            LocalDate currentDate = startOfWeek.plusDays(i);
+//            LocalDate currentDate = startDate.plusDays(i);
+            List<WatchSportDataByDateAndThirdDeviceVo> dayData = groupedByDate.getOrDefault(currentDate, Collections.emptyList());
+
+            // 汇总每天数据
+            float totalDistance = (float) dayData.stream()
+                    .mapToDouble(data -> Optional.ofNullable(data.getDistance()).orElse(0f)).sum();
+            float totalCalorie = (float) dayData.stream()
+                    .mapToDouble(data -> Optional.ofNullable(data.getCalorie()).orElse(0f)).sum();
+            float totalTime = (float) dayData.stream()
+                    .mapToDouble(data -> Optional.ofNullable(data.getDuration()).orElse(0f)).sum();
+
+
+            // 创建统计对象
+            WatchSportDataByDateVo vo = new WatchSportDataByDateVo();
+            Float distance = Math.round(totalDistance/1000 * 100) / 100f;
+            vo.setDistance(distance); //换算公里
+            vo.setCalorie(Math.round(totalCalorie * 100) / 100f);
+            Float time = Math.round(totalTime * 100) / 100f;
+            if (time <=0){
+                time = 24*60*60f;
+            }
+            vo.setTime(time); //秒
+            float avgSpeed = time > 0 ? distance / (totalTime/3600) : 0;
+            vo.setSpeed(Math.round(avgSpeed * 100) / 100f);
+            result.add(vo);
+        }
+        return result;
+    }
+
+    private List<WatchSportDataByDateVo> getDayData(List<WatchSportDataByDateAndThirdDeviceVo> activity) {
+        // 提前分配24小时结果数组
+        WatchSportDataByDateVo[] result = new WatchSportDataByDateVo[24];
+        for (int i = 0; i < 24; i++) {
+            result[i] = new WatchSportDataByDateVo(); // 初始化每小时的默认值
+            result[i].setDistance(0f);
+            result[i].setCalorie(0f);
+            result[i].setTime(0f); // 默认总时间为0秒
+            result[i].setSpeed(0f);
+        }
+
+        // 定义时间解析器
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+        // 按小时分组并直接统计
+        for (WatchSportDataByDateAndThirdDeviceVo data : activity) {
+            // 解析 createTime 的小时
+            LocalDateTime dateTime = LocalDateTime.parse(data.getCreateTime(), formatter);
+            int hour = dateTime.getHour();
+
+            // 获取对应小时的统计对象
+            WatchSportDataByDateVo vo = result[hour];
+
+            // 累加距离和卡路里
+            float dis = vo.getDistance() + ((Optional.ofNullable(data.getDistance()).orElse(0f)) / 1000);
+            float cal = vo.getCalorie() + Optional.ofNullable(data.getCalorie()).orElse(0f);
+            float time = vo.getTime() + Optional.ofNullable(data.getDuration()).orElse(0f);
+            vo.setDistance(Math.round(dis * 100) / 100f); //换算公里
+            vo.setCalorie(Math.round(cal * 100) / 100f);
+            // 假设每条记录表示1分钟运动///todo
+//            vo.setTime(vo.getTime() + 1f / 60); // 累加时间,单位为小时
+            if (time <= 0) {
+                time = 3600;
+            }
+            vo.setTime(time); // 累加时间,单位秒
+        }
+
+
+        // 计算每小时的平均速度
+        for (WatchSportDataByDateVo vo : result) {
+            if (vo.getTime() > 0) {
+                vo.setSpeed(Math.round((vo.getDistance() / (vo.getTime()/3600)) * 100) / 100f); // 平均速度 = 距离 / 时间
+            }
+        }
+        return Arrays.asList(result);
+    }
+
+    @Override
+    public WatchSportRecordVo getOtherData(Date startTime,
+                                    Date endTime,
+                                    String deviceId,
+                                    Integer recordType,
+                                    Integer status){
+        return baseMapper.getOtherData(startTime,endTime,deviceId,recordType,status);
+
+    }
+
+
+}

+ 98 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsUserAdditionalDataServiceImpl.java

@@ -0,0 +1,98 @@
+package com.fs.his.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.utils.DateUtils;
+import com.fs.his.domain.FsUserAdditionalData;
+import com.fs.his.mapper.FsUserAdditionalDataMapper;
+import com.fs.his.service.IFsUserAdditionalDataService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 设备注册用户额外参数Service业务层处理
+ *
+ * @author fs
+ * @date 2025-10-17
+ */
+@Service
+public class FsUserAdditionalDataServiceImpl extends ServiceImpl<FsUserAdditionalDataMapper, FsUserAdditionalData> implements IFsUserAdditionalDataService {
+
+    /**
+     * 查询设备注册用户额外参数
+     *
+     * @param id 设备注册用户额外参数主键
+     * @return 设备注册用户额外参数
+     */
+    @Override
+    public FsUserAdditionalData selectFsUserAdditionalDataById(Long id)
+    {
+        return baseMapper.selectFsUserAdditionalDataById(id);
+    }
+
+    /**
+     * 查询设备注册用户额外参数列表
+     *
+     * @param fsUserAdditionalData 设备注册用户额外参数
+     * @return 设备注册用户额外参数
+     */
+    @Override
+    public List<FsUserAdditionalData> selectFsUserAdditionalDataList(FsUserAdditionalData fsUserAdditionalData)
+    {
+        return baseMapper.selectFsUserAdditionalDataList(fsUserAdditionalData);
+    }
+
+    /**
+     * 新增设备注册用户额外参数
+     *
+     * @param fsUserAdditionalData 设备注册用户额外参数
+     * @return 结果
+     */
+    @Override
+    public int insertFsUserAdditionalData(FsUserAdditionalData fsUserAdditionalData)
+    {
+        fsUserAdditionalData.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertFsUserAdditionalData(fsUserAdditionalData);
+    }
+
+    /**
+     * 修改设备注册用户额外参数
+     *
+     * @param fsUserAdditionalData 设备注册用户额外参数
+     * @return 结果
+     */
+    @Override
+    public int updateFsUserAdditionalData(FsUserAdditionalData fsUserAdditionalData)
+    {
+        return baseMapper.updateFsUserAdditionalData(fsUserAdditionalData);
+    }
+
+    /**
+     * 批量删除设备注册用户额外参数
+     *
+     * @param ids 需要删除的设备注册用户额外参数主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsUserAdditionalDataByIds(Long[] ids)
+    {
+        return baseMapper.deleteFsUserAdditionalDataByIds(ids);
+    }
+
+    /**
+     * 删除设备注册用户额外参数信息
+     *
+     * @param id 设备注册用户额外参数主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsUserAdditionalDataById(Long id)
+    {
+        return baseMapper.deleteFsUserAdditionalDataById(id);
+    }
+
+    @Override
+    public FsUserAdditionalData selectUserByUserId(Long fsUserId) {
+        return baseMapper.selectUserByUserId(fsUserId);
+    }
+}

+ 69 - 0
fs-service/src/main/java/com/fs/his/vo/FsHealthPulseListVO.java

@@ -0,0 +1,69 @@
+package com.fs.his.vo;
+
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 脉诊对象 fs_health_pulse
+ *
+ * @author fs
+ * @date 2025-10-11
+ */
+@Data
+public class FsHealthPulseListVO extends BaseEntity{
+
+    /** id */
+    private Long id;
+
+    /** 用户id */
+    @Excel(name = "用户id")
+    private Long userId;
+
+    /** 用户名 */
+    @Excel(name = "用户名")
+    private String name;
+
+    /** 性别 */
+    @Excel(name = "性别")
+    private Long sex;
+
+    /** 年龄 */
+    @Excel(name = "年龄")
+    private Long age;
+
+    /** 状态 */
+    @Excel(name = "状态")
+    private Long status;
+
+    /** 左手结果 */
+    @Excel(name = "左手结果")
+    private String leftHandResult;
+
+    /** 右手结果 */
+    @Excel(name = "右手结果")
+    private String rightHandResult;
+
+    /** 脉诊总结 */
+    @Excel(name = "脉诊总结")
+    private String pulseSummary;
+
+    /** 脉诊建议 */
+    @Excel(name = "脉诊建议")
+    private String pulseSuggestions;
+
+    /** 脉诊设备测量ID */
+    @Excel(name = "脉诊设备测量ID")
+    private String measureId;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    /** url */
+    @Excel(name = "url")
+    private String pulseUrl;
+}

+ 83 - 0
fs-service/src/main/java/com/fs/his/vo/FsHealthSurfaceListVO.java

@@ -0,0 +1,83 @@
+package com.fs.his.vo;
+
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 面诊对象 fs_health_surface
+ *
+ * @author fs
+ * @date 2025-10-10
+ */
+@Data
+public class FsHealthSurfaceListVO extends BaseEntity{
+
+    /** id */
+    private Long id;
+
+    /** 用户id */
+    @Excel(name = "用户id")
+    private Long userId;
+
+    /** 用户名 */
+    @Excel(name = "用户名")
+    private String name;
+
+    /** 性别 */
+    @Excel(name = "性别")
+    private Integer sex;
+
+    /** 年龄 */
+    @Excel(name = "年龄")
+    private Integer age;
+
+    /** 状态 */
+    @Excel(name = "状态")
+    private Integer status;
+
+    /** 面诊图片 */
+    @Excel(name = "面诊图片")
+    private String surfaceUrl;
+
+    /** 肤色的结果 */
+    @Excel(name = "肤色的结果")
+    private String complexionResult;
+
+    /** 肤色结果类型 */
+    @Excel(name = "肤色结果类型")
+    private String complexionTypes;
+
+    /** 区域色斑问题 */
+    @Excel(name = "区域色斑问题")
+    private String spotProblems;
+
+    /** 浮肿问题 */
+    @Excel(name = "浮肿问题")
+    private String swellingProblems;
+
+    /** 光泽度结果 */
+    @Excel(name = "光泽度结果")
+    private String glowResult;
+
+    /** 面诊总结 */
+    @Excel(name = "面诊总结")
+    private String diagnosisSummary;
+
+    /** 健康建议 */
+    @Excel(name = "健康建议")
+    private String healthSuggestions;
+
+    /** 时间 */
+    @Excel(name = "时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    /** 备注 */
+    @Excel(name = "备注")
+    private String remark;
+}

+ 544 - 0
fs-service/src/main/java/com/fs/watch/calculation/SleepScoreCalculator.java

@@ -0,0 +1,544 @@
+package com.fs.watch.calculation;
+
+import com.alibaba.fastjson.JSONObject;
+import com.fs.common.utils.DateUtils;
+import com.fs.his.domain.FsThirdDeviceData;
+import com.fs.his.mapper.FsThirdDeviceDataMapper;
+import com.fs.watch.domain.SleepSection;
+import com.fs.watch.domain.SleepStatistics;
+import com.fs.watch.domain.vo.AppWatchSleepDataVo;
+import com.fs.watch.domain.vo.DailySleepStatusVo;
+import com.fs.watch.enums.WatchSleepStatusEnum;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.stereotype.Component;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.ExecutorCompletionService;
+import java.util.concurrent.Future;
+
+/**
+ * 睡眠评分计算工具类
+ */
+@Slf4j
+@Component
+public class SleepScoreCalculator {
+
+    // 类型常量
+    private static final int TYPE_DEEP_SLEEP = 3;      // 深睡
+    private static final int TYPE_LIGHT_SLEEP = 4;     // 浅睡
+    private static final int TYPE_AWAKE = 6;           // 清醒
+    private static final int TYPE_REM = 7;             // 快速眼动
+    @Autowired
+    private ThreadPoolTaskExecutor threadPoolTaskExecutor;  // 现在可以注入了
+
+    @Autowired
+    private FsThirdDeviceDataMapper sleepDataMapper;
+
+    /**
+     * 计算睡眠评分
+     * @param sleepRecords 睡眠记录列表
+     * @return 睡眠评分(0-100分)
+     */
+    public static int calculateSleepScore(List<FsThirdDeviceData> sleepRecords) {
+        if (sleepRecords == null || sleepRecords.isEmpty()) {
+            return 0;
+        }
+
+        long totalDuration = 0;      // 总睡眠时长(毫秒)
+        long deepSleepDuration = 0;   // 深睡时长(毫秒)
+        long lightSleepDuration = 0;  // 浅睡时长(毫秒)
+        long awakeDuration = 0;       // 清醒时长(毫秒)
+        int awakeCount = 0;           // 清醒次数
+
+        for (FsThirdDeviceData record : sleepRecords) {
+            String recordValue = record.getRecordValue();
+            if (recordValue == null || recordValue.isEmpty()) {
+                continue;
+            }
+
+            try {
+                JSONObject json = JSONObject.parseObject(recordValue);
+                Long startTime = json.getLong("startTime");
+                Long endTime = json.getLong("endTime");
+                Integer status = json.getInteger("status");
+
+                if (startTime == null || endTime == null || status == null) {
+                    continue;
+                }
+
+                long duration = endTime - startTime;
+                totalDuration += duration;
+
+                switch (status) {
+                    case 1: // 深睡
+                        deepSleepDuration += duration;
+                        break;
+                    case 2: // 浅睡
+                        lightSleepDuration += duration;
+                        break;
+                    case 3: // 清醒
+                        awakeDuration += duration;
+                        awakeCount++;
+                        break;
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+        // 计算各维度得分
+        int durationScore = calculateDurationScore(totalDuration);
+        int deepSleepRatioScore = calculateDeepSleepRatioScore(deepSleepDuration, totalDuration);
+        int lightSleepRatioScore = calculateLightSleepRatioScore(lightSleepDuration, totalDuration);
+        int awakeScore = calculateAwakeScore(awakeDuration, awakeCount, totalDuration);
+
+        // 总分 = 时长分*30% + 深睡比例分*35% + 浅睡比例分*15% + 清醒分*20%
+        int totalScore = (int)(durationScore * 0.30
+                + deepSleepRatioScore * 0.35
+                + lightSleepRatioScore * 0.15
+                + awakeScore * 0.20);
+
+        return Math.min(100, Math.max(0, totalScore));
+    }
+
+    /**
+     * 计算详细的睡眠统计数据
+     * @param sleepRecords 睡眠记录列表
+     * @return 睡眠统计信息
+     */
+    public static SleepStatistics calculateDetailedStatistics(List<FsThirdDeviceData> sleepRecords) {
+        SleepStatistics statistics = new SleepStatistics();
+
+        if (sleepRecords == null || sleepRecords.isEmpty()) {
+            return statistics;
+        }
+
+        long totalDuration = 0;
+        long deepSleepDuration = 0;
+        long lightSleepDuration = 0;
+        long awakeDuration = 0;
+        long remDuration = 0;
+        int deepSleepCount = 0;
+        int lightSleepCount = 0;
+        int awakeCount = 0;
+        int remCount = 0;
+
+        List<SleepSection> sleepSectionList = new ArrayList<>();
+        for (FsThirdDeviceData record : sleepRecords) {
+            String recordValue = record.getRecordValue();
+            if (recordValue == null || recordValue.isEmpty()) {
+                continue;
+            }
+
+            try {
+                JSONObject json = JSONObject.parseObject(recordValue);
+                Long startTime = json.getLong("startTime");
+                Long endTime = json.getLong("endTime");
+                Integer status = json.getInteger("status");
+
+                if (startTime == null || endTime == null || status == null) {
+                    continue;
+                }
+
+                long duration = endTime - startTime;
+                totalDuration += duration;
+
+                // 创建睡眠区间
+                SleepSection section = new SleepSection();
+                // 将时间戳转换为指定格式
+                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                section.setStart(sdf.format(new Date(startTime)));
+                section.setEnd(sdf.format(new Date(endTime)));
+
+                // status 转换为 type
+                // status: 1深睡, 2浅睡, 3清醒
+                // type: 3深睡, 4浅睡, 6清醒, 7快速眼动
+                Integer type = convertStatusToType(status);
+                section.setType(type);
+                sleepSectionList.add(section);
+
+                switch (status) {
+                    case 1: // 深睡
+                        deepSleepDuration += duration;
+                        deepSleepCount++;
+                        break;
+                    case 2: // 浅睡
+                        lightSleepDuration += duration;
+                        lightSleepCount++;
+                        break;
+                    case 3: // 清醒
+                        awakeDuration += duration;
+                        awakeCount++;
+                        break;
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+        // 设置统计数据
+        statistics.setTotalDuration(totalDuration);
+        statistics.setTotalSleepHours(totalDuration / 3600000.0);
+        statistics.setDeepSleepDuration(deepSleepDuration);
+        statistics.setDeepSleepHours(deepSleepDuration / 3600000.0);
+        statistics.setDeepSleepCount(deepSleepCount);
+        statistics.setLightSleepDuration(lightSleepDuration);
+        statistics.setLightSleepHours(lightSleepDuration / 3600000.0);
+        statistics.setLightSleepCount(lightSleepCount);
+        statistics.setAwakeDuration(awakeDuration);
+        statistics.setAwakeHours(awakeDuration / 3600000.0);
+        statistics.setAwakeCount(awakeCount);
+        statistics.setRemDuration(remDuration);
+        statistics.setRemHours(remDuration / 3600000.0);
+        statistics.setRemCount(remCount);
+        statistics.setSleepSection(sleepSectionList);
+
+        if (totalDuration > 0) {
+            statistics.setDeepSleepRatio((double) deepSleepDuration / totalDuration);
+            statistics.setLightSleepRatio((double) lightSleepDuration / totalDuration);
+            statistics.setAwakeRatio((double) awakeDuration / totalDuration);
+            statistics.setRemRatio((double) remDuration / totalDuration);
+        }
+
+        return statistics;
+    }
+
+    /**
+     * 将 status 转换为 type
+     * @param status 1:深睡 2:浅睡 3:清醒
+     * @return type 3:深睡 4:浅睡 6:清醒 7:快速眼动
+     */
+    private static Integer convertStatusToType(Integer status) {
+        if (status == null) {
+            return 6; // 默认清醒
+        }
+        switch (status) {
+            case 1:
+                return TYPE_DEEP_SLEEP;  // 深睡
+            case 2:
+                return TYPE_LIGHT_SLEEP; // 浅睡
+            case 3:
+                return TYPE_AWAKE;       // 清醒
+            default:
+                return TYPE_AWAKE;
+        }
+    }
+
+
+    /**
+     * 睡眠时长评分(满分100分)
+     * 标准:成人建议7-8小时
+     */
+    private static int calculateDurationScore(long totalDurationMs) {
+        double hours = totalDurationMs / 3600000.0;
+
+        if (hours >= 7 && hours <= 8) {
+            return 100;
+        } else if (hours >= 6 && hours < 7) {
+            return 80;
+        } else if (hours >= 8 && hours <= 9) {
+            return 85;
+        } else if (hours >= 5 && hours < 6) {
+            return 60;
+        } else if (hours > 9 && hours <= 10) {
+            return 70;
+        } else if (hours >= 4 && hours < 5) {
+            return 40;
+        } else if (hours > 10) {
+            return 50;
+        } else {
+            return 20;
+        }
+    }
+
+    /**
+     * 深睡比例评分(满分100分)
+     * 标准:深睡应占总睡眠时长的20-25%
+     */
+    private static int calculateDeepSleepRatioScore(long deepSleepDuration, long totalDuration) {
+        if (totalDuration <= 0) {
+            return 0;
+        }
+
+        double ratio = (double) deepSleepDuration / totalDuration;
+
+        if (ratio >= 0.20 && ratio <= 0.25) {
+            return 100;
+        } else if (ratio >= 0.15 && ratio < 0.20) {
+            return 80;
+        } else if (ratio > 0.25 && ratio <= 0.30) {
+            return 85;
+        } else if (ratio >= 0.10 && ratio < 0.15) {
+            return 60;
+        } else if (ratio > 0.30 && ratio <= 0.35) {
+            return 70;
+        } else if (ratio >= 0.05 && ratio < 0.10) {
+            return 40;
+        } else {
+            return 20;
+        }
+    }
+
+    /**
+     * 浅睡比例评分(满分100分)
+     * 标准:浅睡应占总睡眠时长的50-60%
+     */
+    private static int calculateLightSleepRatioScore(long lightSleepDuration, long totalDuration) {
+        if (totalDuration <= 0) {
+            return 0;
+        }
+
+        double ratio = (double) lightSleepDuration / totalDuration;
+
+        if (ratio >= 0.50 && ratio <= 0.60) {
+            return 100;
+        } else if (ratio >= 0.40 && ratio < 0.50) {
+            return 80;
+        } else if (ratio > 0.60 && ratio <= 0.70) {
+            return 85;
+        } else if (ratio >= 0.30 && ratio < 0.40) {
+            return 60;
+        } else if (ratio > 0.70 && ratio <= 0.80) {
+            return 70;
+        } else {
+            return 40;
+        }
+    }
+
+    /**
+     * 清醒评分(满分100分)
+     * 评估清醒时长和清醒次数
+     */
+    private static int calculateAwakeScore(long awakeDuration, int awakeCount, long totalDuration) {
+        if (totalDuration <= 0) {
+            return 0;
+        }
+
+        double awakeRatio = (double) awakeDuration / totalDuration;
+
+        // 清醒时长评分
+        int durationScore;
+        if (awakeRatio <= 0.05) {
+            durationScore = 100;
+        } else if (awakeRatio <= 0.10) {
+            durationScore = 80;
+        } else if (awakeRatio <= 0.15) {
+            durationScore = 60;
+        } else if (awakeRatio <= 0.20) {
+            durationScore = 40;
+        } else {
+            durationScore = 20;
+        }
+
+        // 清醒次数评分
+        int countScore;
+        if (awakeCount <= 2) {
+            countScore = 100;
+        } else if (awakeCount <= 4) {
+            countScore = 80;
+        } else if (awakeCount <= 6) {
+            countScore = 60;
+        } else if (awakeCount <= 8) {
+            countScore = 40;
+        } else {
+            countScore = 20;
+        }
+
+        return (int)(durationScore * 0.6 + countScore * 0.4);
+    }
+
+    /**
+     * 获取睡眠状态评估结果
+     * @param startTime 开始时间
+     * @param endTime 结束时间
+     * @param deviceId 设备ID
+     * @return 睡眠状态描述
+     */
+    public String getSleepStatus(Date startTime, Date endTime, String deviceId
+                                 ) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        // 构造日期列表
+        List<String> dateList = new ArrayList<>();
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(startTime);
+        while (!calendar.getTime().after(endTime)) {
+            dateList.add(sdf.format(calendar.getTime()));
+            calendar.add(Calendar.DATE, 1);
+        }
+
+        int taskCount = dateList.size();
+        ExecutorCompletionService<WatchSleepStatusEnum> completionService =
+                new ExecutorCompletionService<>(threadPoolTaskExecutor);
+
+        // 提交任务
+        for (String date : dateList) {
+            completionService.submit(() -> {
+                AppWatchSleepDataVo sleepVo = queryByDateAndDeviceIdAndState(date, deviceId);
+                return getSleepEnum(sleepVo);
+            });
+        }
+
+        try {
+            for (int i = 0; i < taskCount; i++) {
+                Future<WatchSleepStatusEnum> future = completionService.take();
+                WatchSleepStatusEnum result = future.get();
+                if (!WatchSleepStatusEnum.NORMAL.equals(result)) {
+                    return result.getDesc();
+                }
+            }
+        } catch (Exception e) {
+            log.error("判断睡眠状态异常:{}", e.getMessage(), e);
+        }
+        return WatchSleepStatusEnum.NORMAL.getDesc();
+    }
+
+    /**
+     * 根据日期和设备ID查询睡眠数据
+     * @param date 日期(yyyy-MM-dd格式)
+     * @param deviceId 设备ID
+     * @return 睡眠数据VO
+     */
+    private AppWatchSleepDataVo queryByDateAndDeviceIdAndState(String date, String deviceId) {
+        try {
+            // 解析日期范围
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+            Date startDate = sdf.parse(date);
+            Date endDate = DateUtils.addMilliseconds(
+                    DateUtils.addDays(startDate, 1),
+                    -1
+            );
+
+            // 查询当天的所有睡眠记录
+            List<FsThirdDeviceData> sleepRecords = sleepDataMapper.selectListByDateAndDeviceIdAndRecordType(
+                    startDate, endDate, deviceId, 7, null);
+
+            if (sleepRecords == null || sleepRecords.isEmpty()) {
+                return null;
+            }
+
+            // 计算详细统计信息
+            SleepStatistics statistics = calculateDetailedStatistics(sleepRecords);
+
+            // 转换为 AppWatchSleepDataVo
+            AppWatchSleepDataVo sleepVo = new AppWatchSleepDataVo();
+
+            // 总睡眠时间(分钟)
+            if (statistics.getTotalSleepHours() != null) {
+                sleepVo.setSleepTime((int) (statistics.getTotalSleepHours() * 60));
+            }
+
+            // 深睡时间(分钟)
+            if (statistics.getDeepSleepHours() != null) {
+                sleepVo.setDeepSleep((int) (statistics.getDeepSleepHours() * 60));
+            }
+
+            // 浅睡时间(分钟)
+            if (statistics.getLightSleepHours() != null) {
+                sleepVo.setLightSleep((int) (statistics.getLightSleepHours() * 60));
+            }
+
+            // 清醒次数
+            sleepVo.setWeakTime(statistics.getAwakeCount());
+
+            // 夜间睡眠次数(深睡次数 + 浅睡次数)
+            sleepVo.setSleepCount(statistics.getDeepSleepCount() + statistics.getLightSleepCount());
+
+            // 深睡比例(百分比)
+            if (statistics.getDeepSleepRatio() != null) {
+                sleepVo.setDeepScale((int) (statistics.getDeepSleepRatio() * 100));
+            }
+
+            // 浅睡比例(百分比)
+            if (statistics.getLightSleepRatio() != null) {
+                sleepVo.setLightScale((int) (statistics.getLightSleepRatio() * 100));
+            }
+
+            // 快速眼动比例(百分比)
+            if (statistics.getRemRatio() != null) {
+                sleepVo.setEyemoveScale((int) (statistics.getRemRatio() * 100));
+            }
+
+            return sleepVo;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 根据睡眠数据获取睡眠状态枚举
+     * @param sleepVo 睡眠数据VO
+     * @return 睡眠状态枚举
+     */
+    private WatchSleepStatusEnum getSleepEnum(AppWatchSleepDataVo sleepVo) {
+        WatchSleepStatusEnum sleepEnum = WatchSleepStatusEnum.NORMAL;
+        if (sleepVo != null) {
+            Integer sleepTime = sleepVo.getSleepTime();  // 总睡眠时间(分钟)
+            Integer deepSleep = sleepVo.getDeepSleep(); // 深睡时间(分钟)
+
+            if (sleepTime != null && sleepTime > 0) {
+                // 睡眠剥夺:总睡眠时间少于5小时(300分钟)
+                if (sleepTime < 300) {
+                    return WatchSleepStatusEnum.DEPRIVATION;
+                }
+                // OSA高风险:深睡比例低于15%
+                if (deepSleep != null) {
+                    double deepSleepRatio = (double) deepSleep / sleepTime;
+                    if (deepSleepRatio < 0.15) {
+                        return WatchSleepStatusEnum.OSA;
+                    }
+                }
+            }
+        }
+        return sleepEnum;
+    }
+
+    /**
+     * 批量获取多日睡眠状态(用于趋势分析)
+     * @param startTime 开始时间
+     * @param endTime 结束时间
+     * @param deviceId 设备ID
+     * @return 每日睡眠状态列表
+     */
+    public List<DailySleepStatusVo> getDailySleepStatusList(Date startTime, Date endTime,
+                                                            String deviceId) {
+        List<DailySleepStatusVo> resultList = new ArrayList<>();
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(startTime);
+
+        while (!calendar.getTime().after(endTime)) {
+            String dateStr = sdf.format(calendar.getTime());
+            DailySleepStatusVo dailyStatus = new DailySleepStatusVo();
+            dailyStatus.setDate(dateStr);
+
+            try {
+                AppWatchSleepDataVo sleepVo = queryByDateAndDeviceIdAndState(dateStr, deviceId);
+                WatchSleepStatusEnum statusEnum = getSleepEnum(sleepVo);
+                dailyStatus.setStatus(statusEnum.getDesc());
+                dailyStatus.setStatusValue(statusEnum.getValue());
+
+                if (sleepVo != null) {
+                    dailyStatus.setSleepTime(sleepVo.getSleepTime());
+                    dailyStatus.setDeepSleep(sleepVo.getDeepSleep());
+                    dailyStatus.setDeepScale(sleepVo.getDeepScale());
+                }
+            } catch (Exception e) {
+                log.error("查询日期 {} 睡眠状态异常:{}", dateStr, e.getMessage());
+                dailyStatus.setStatus("查询失败");
+            }
+
+            resultList.add(dailyStatus);
+            calendar.add(Calendar.DATE, 1);
+        }
+
+        return resultList;
+    }
+}

+ 4 - 0
fs-service/src/main/java/com/fs/watch/domain/DeviceFamily.java

@@ -8,6 +8,10 @@ public class DeviceFamily {
     private String name;
     //设备id
     private String deviceId;
+    //小护士设备
+    private String xhsDeviceId;
+    //小护士手表
+    private String newXhsDeviceId;
     //关系
     private String relationship;
 }

+ 0 - 83
fs-service/src/main/java/com/fs/watch/domain/FsMonitorDataType.java

@@ -1,83 +0,0 @@
-package com.fs.watch.domain;
-
-import com.fs.common.annotation.Excel;
-import com.fs.common.core.domain.BaseEntity;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
-/**
- * app-健康监测数据类型对象 fs_monitor_data_type
- *
- * @author fs
- * @date 2024-08-26
- */
-public class FsMonitorDataType extends BaseEntity
-{
-    private static final long serialVersionUID = 1L;
-
-    /** id */
-    private String id;
-
-    /** 数据类型 */
-    @Excel(name = "数据类型")
-    private String type;
-
-    /** 小标题 */
-    @Excel(name = "小标题")
-    private String title;
-
-    /** 图标 */
-    @Excel(name = "图标")
-    private String icon;
-
-    public void setId(String id)
-    {
-        this.id = id;
-    }
-
-    public String getId()
-    {
-        return id;
-    }
-    public void setType(String type)
-    {
-        this.type = type;
-    }
-
-    public String getType()
-    {
-        return type;
-    }
-    public void setTitle(String title)
-    {
-        this.title = title;
-    }
-
-    public String getTitle()
-    {
-        return title;
-    }
-    public void setIcon(String icon)
-    {
-        this.icon = icon;
-    }
-
-    public String getIcon()
-    {
-        return icon;
-    }
-
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
-            .append("id", getId())
-            .append("type", getType())
-            .append("title", getTitle())
-            .append("icon", getIcon())
-            .append("createTime", getCreateTime())
-            .append("createBy", getCreateBy())
-            .append("updateTime", getUpdateTime())
-            .append("updateBy", getUpdateBy())
-            .toString();
-    }
-}

+ 68 - 0
fs-service/src/main/java/com/fs/watch/domain/SleepStatistics.java

@@ -0,0 +1,68 @@
+package com.fs.watch.domain;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 睡眠统计信息
+ */
+@Data
+public class SleepStatistics {
+    /** 总睡眠时长(小时) */
+    private Double totalSleepHours;
+
+    /** 总睡眠时长(毫秒) */
+    private Long totalDuration;
+
+    /** 深睡时长(小时) */
+    private Double deepSleepHours;
+
+    /** 深睡时长(毫秒) */
+    private Long deepSleepDuration;
+
+    /** 深睡次数 */
+    private Integer deepSleepCount;
+
+    /** 浅睡时长(小时) */
+    private Double lightSleepHours;
+
+    /** 浅睡时长(毫秒) */
+    private Long lightSleepDuration;
+
+    /** 浅睡次数 */
+    private Integer lightSleepCount;
+
+    /** 清醒时长(小时) */
+    private Double awakeHours;
+
+    /** 清醒时长(毫秒) */
+    private Long awakeDuration;
+
+    /** 清醒次数 */
+    private Integer awakeCount;
+
+    /** 快速眼动时长(小时) */
+    private Double remHours;
+
+    /** 快速眼动时长(毫秒) */
+    private Long remDuration;
+
+    /** 快速眼动次数 */
+    private Integer remCount;
+
+    /** 深睡比例(0-1) */
+    private Double deepSleepRatio;
+
+    /** 浅睡比例(0-1) */
+    private Double lightSleepRatio;
+
+    /** 清醒比例(0-1) */
+    private Double awakeRatio;
+
+    /** 快速眼动比例(0-1) */
+    private Double remRatio;
+
+    /** 睡眠区间列表(用于图表展示) */
+    private List<SleepSection> sleepSection;
+}

+ 96 - 0
fs-service/src/main/java/com/fs/watch/domain/WatchAudioMsgLog.java

@@ -0,0 +1,96 @@
+package com.fs.watch.domain;
+
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+import java.util.UUID;
+
+/**
+* 语音聊天记录
+* @TableName watch_audio_msg_log
+*/
+public class WatchAudioMsgLog implements Serializable {
+
+    /**
+    * 主键id
+    */
+    private UUID id;
+    /**
+    * 设备编号
+    */
+    @ApiModelProperty("设备编号")
+    private String deviceId;
+
+    @ApiModelProperty("文件地址")
+    private String fileUrl;
+
+    @ApiModelProperty("0:发送 1:接收")
+    private Integer type;
+
+    @ApiModelProperty("结果 0:失败 1:成功")
+    private Integer status;
+
+    @ApiModelProperty("返回信息")
+    private String msg;
+
+    @ApiModelProperty("创建时间")
+    private String createTime;
+
+    public String getFileUrl() {
+        return fileUrl;
+    }
+
+    public void setFileUrl(String fileUrl) {
+        this.fileUrl = fileUrl;
+    }
+
+    public Integer getType() {
+        return type;
+    }
+
+    public void setType(Integer type) {
+        this.type = type;
+    }
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public String getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(String createTime) {
+        this.createTime = createTime;
+    }
+
+    public UUID getId() {
+        return id;
+    }
+
+    public void setId(UUID id) {
+        this.id = id;
+    }
+
+    public String getDeviceId() {
+        return deviceId;
+    }
+
+    public void setDeviceId(String deviceId) {
+        this.deviceId = deviceId;
+    }
+
+
+}

+ 0 - 108
fs-service/src/main/java/com/fs/watch/domain/WatchDeviceBeginnerGuide.java

@@ -1,108 +0,0 @@
-package com.fs.watch.domain;
-
-import com.fs.common.annotation.Excel;
-import com.fs.common.core.domain.BaseEntity;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-
-/**
- * 新手引导对象 device_beginner_uide
- *
- * @author fs
- * @date 2024-09-06
- */
-public class WatchDeviceBeginnerGuide extends BaseEntity
-{
-    private static final long serialVersionUID = 1L;
-
-    /** 主键id */
-    private Long id;
-
-    /** 标题 */
-    @Excel(name = "标题")
-    private String title;
-
-    /** 链接 */
-    @Excel(name = "链接")
-    private String url;
-
-    /** 资料类型 1:文章 2:视频 */
-    @Excel(name = "资料类型 1:文章 2:视频")
-    private Long type;
-
-    /** 是否已删除 */
-    @Excel(name = "是否已删除")
-    private Long isDel;
-
-    public String getBelong() {
-        return belong;
-    }
-
-    public void setBelong(String belong) {
-        this.belong = belong;
-    }
-
-    private String belong;
-
-    public void setId(Long id)
-    {
-        this.id = id;
-    }
-
-    public Long getId()
-    {
-        return id;
-    }
-    public void setTitle(String title)
-    {
-        this.title = title;
-    }
-
-    public String getTitle()
-    {
-        return title;
-    }
-    public void setUrl(String url)
-    {
-        this.url = url;
-    }
-
-    public String getUrl()
-    {
-        return url;
-    }
-    public void setType(Long type)
-    {
-        this.type = type;
-    }
-
-    public Long getType()
-    {
-        return type;
-    }
-    public void setIsDel(Long isDel)
-    {
-        this.isDel = isDel;
-    }
-
-    public Long getIsDel()
-    {
-        return isDel;
-    }
-
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
-            .append("id", getId())
-            .append("title", getTitle())
-            .append("url", getUrl())
-            .append("type", getType())
-            .append("createBy", getCreateBy())
-            .append("createTime", getCreateTime())
-            .append("updateBy", getUpdateBy())
-            .append("updateTime", getUpdateTime())
-            .append("isDel", getIsDel())
-            .append("belong", getBelong())
-            .toString();
-    }
-}

+ 56 - 0
fs-service/src/main/java/com/fs/watch/domain/WatchDeviceWeek.java

@@ -0,0 +1,56 @@
+package com.fs.watch.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fs.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+* 每周健康周报汇总
+* @TableName watch_device_week
+*/
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("watch_device_week") // 确保表名正确
+public class WatchDeviceWeek extends BaseEntity {
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+    /**
+    * 设备编号
+    */
+    @ApiModelProperty("设备编号")
+    private String deviceId;
+    /**
+    * 异常数据
+    */
+    @ApiModelProperty("异常数据")
+    private String listJson;
+    /**
+    * 标题
+    */
+    @ApiModelProperty("标题")
+    private String title;
+    /**
+    * 详细描述
+    */
+    @ApiModelProperty("详细描述")
+    private String desc;
+    /**
+    * 评分
+    */
+    @ApiModelProperty("评分")
+    private Integer score;
+    /**
+    *
+    */
+    private String aiSuggestion;
+
+    private Long userId;
+
+
+
+}

+ 6 - 0
fs-service/src/main/java/com/fs/watch/domain/WatchFsUser.java

@@ -177,4 +177,10 @@ public class WatchFsUser extends BaseEntity {
      */
     private String monitorDataTypeOrder;
 
+    //小护士设备id
+    private String xhsDeviceId;
+
+    //小护士手表设备id
+    private String newXhsDeviceId;
+
 }

+ 89 - 0
fs-service/src/main/java/com/fs/watch/domain/WatchSosCallLogs.java

@@ -0,0 +1,89 @@
+package com.fs.watch.domain;
+
+import java.io.Serializable;
+import java.util.UUID;
+
+/**
+ * sos报警日志(WatchSosCallLogs)实体类
+ *
+ * @author makejava
+ * @since 2024-12-24 14:30:26
+ */
+public class WatchSosCallLogs implements Serializable {
+    private static final long serialVersionUID = 656916219606367008L;
+/**
+     * 主键id
+     */
+    private UUID id;
+/**
+     * 设备编号
+     */
+    private String deviceId;
+/**
+     * 报警时间
+     */
+    private String alarmTime;
+/**
+     * sos时的定位 纬度
+     */
+    private String lat;
+/**
+     * sos时的定位 经度
+     */
+    private String lon;
+/**
+     * 通话日志json
+     */
+    private String callLogs;
+
+
+    public UUID getId() {
+        return id;
+    }
+
+    public void setId(UUID id) {
+        this.id = id;
+    }
+
+    public String getDeviceId() {
+        return deviceId;
+    }
+
+    public void setDeviceId(String deviceId) {
+        this.deviceId = deviceId;
+    }
+
+    public String getAlarmTime() {
+        return alarmTime;
+    }
+
+    public void setAlarmTime(String alarmTime) {
+        this.alarmTime = alarmTime;
+    }
+
+    public String getLat() {
+        return lat;
+    }
+
+    public void setLat(String lat) {
+        this.lat = lat;
+    }
+
+    public String getLon() {
+        return lon;
+    }
+
+    public void setLon(String lon) {
+        this.lon = lon;
+    }
+
+    public String getCallLogs() {
+        return callLogs;
+    }
+
+    public void setCallLogs(String callLogs) {
+        this.callLogs = callLogs;
+    }
+
+}
+

+ 25 - 0
fs-service/src/main/java/com/fs/watch/domain/WatchUser.java

@@ -87,6 +87,15 @@ public class WatchUser implements Serializable {
 
 
 
+    //小护士设备id
+    private String xhsDeviceId;
+
+
+    //小护士手表设备id
+    private String newXhsDeviceId;
+
+
+
     public String getTargetActivity() {
         return targetActivity;
     }
@@ -223,5 +232,21 @@ public class WatchUser implements Serializable {
     public void setNickName(String nickName) {
         this.nickName = nickName;
     }
+    public String getXhsDeviceId() {
+        return xhsDeviceId;
+    }
+
+    public void setXhsDeviceId(String xhsDeviceId) {
+        this.xhsDeviceId = xhsDeviceId;
+    }
+
+
+    public String getNewXhsDeviceId() {
+        return newXhsDeviceId;
+    }
+
+    public void setNewXhsDeviceId(String newXhsDeviceId) {
+        this.newXhsDeviceId = newXhsDeviceId;
+    }
 }
 

+ 4 - 0
fs-service/src/main/java/com/fs/watch/domain/vo/AppFsUserHealthReportVo.java

@@ -10,4 +10,8 @@ public class AppFsUserHealthReportVo {
     private String title; //标题
     private String desc; //详细描述
     private Integer score;//评分
+    private String aiSuggestion;
+    private Integer sessionId;
+    private Integer roleId = 140;
+
 }

+ 4 - 0
fs-service/src/main/java/com/fs/watch/domain/vo/AppFsUserHealthVo.java

@@ -20,5 +20,9 @@ public class AppFsUserHealthVo{
 
     //舌诊日期
     private List<String> tongueDateList;
+    //面诊日期
+    private List<String> pulseDateList;
+    //脉诊日期
+    private List<String> surfaceDateList;
 
 }

+ 7 - 0
fs-service/src/main/java/com/fs/watch/domain/vo/AppFsUserVo.java

@@ -119,4 +119,11 @@ public class AppFsUserVo {
     /** 微信公众号OPENID */
     @Excel(name = "微信公众号OPENID")
     private String mpOpenId;
+    /** 既往病史 */
+    @Excel(name = "既往病史")
+    private String previousMedicalHistory;
+
+    //小护士设备id
+    private String xhsDeviceId;
+
 }

+ 4 - 0
fs-service/src/main/java/com/fs/watch/domain/vo/AppWatchSleepDataVo.java

@@ -2,6 +2,8 @@ package com.fs.watch.domain.vo;
 
 import lombok.Data;
 
+import java.util.List;
+
 @Data
 public class AppWatchSleepDataVo extends WatchSleepDataVo {
     /**
@@ -39,4 +41,6 @@ public class AppWatchSleepDataVo extends WatchSleepDataVo {
      * 呼吸质量 得分(百分制)
      */
     private Integer breathScore;
+
+    private List<WatchSleepDataVo> watchSleepDataVoList;
 }

+ 27 - 0
fs-service/src/main/java/com/fs/watch/domain/vo/DailySleepStatusVo.java

@@ -0,0 +1,27 @@
+package com.fs.watch.domain.vo;
+
+import lombok.Data;
+
+/**
+ * 每日睡眠状态VO
+ */
+@Data
+public class DailySleepStatusVo {
+    /** 日期(yyyy-MM-dd) */
+    private String date;
+
+    /** 睡眠状态描述 */
+    private String status;
+
+    /** 睡眠状态值 */
+    private Integer statusValue;
+
+    /** 总睡眠时间(分钟) */
+    private Integer sleepTime;
+
+    /** 深睡时间(分钟) */
+    private Integer deepSleep;
+
+    /** 深睡比例(百分比) */
+    private Integer deepScale;
+}

+ 69 - 0
fs-service/src/main/java/com/fs/watch/domain/vo/WatchDeviceInfoAndIotExportVO.java

@@ -0,0 +1,69 @@
+package com.fs.watch.domain.vo;
+
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+/**
+ * @author MixLiu
+ * @date 2025/11/18 下午1:44)
+ */
+
+@Data
+public class WatchDeviceInfoAndIotExportVO {
+
+
+
+    @Excel(name = "所属公司")
+    private String companyName;
+
+    @Excel(name = "设备编号")
+    private String deviceId;
+
+
+    @Excel(name = "ICCID")
+    private String iccid;
+
+    //物联网卡运营商类型:1=移动 2=联通 3=电信
+    private Integer operatorType;
+
+    @Excel(name = "运营商")
+    private String operatorTypeName;
+
+    //当前状态 5=已激活 6=已停用
+    private Integer status;
+
+    //当前状态 5=已激活 6=已停用
+    @Excel(name = "状态")
+    private String statusName;
+
+    //当月总流量,单位MB
+    @Excel(name = "当月总流量")
+    private Integer totalFlowSize;
+
+    //当月已使用流量,单位MB
+    @Excel(name = "当月已使用流量")
+    private Integer usedFlowSize;
+
+    //当前套餐名称
+    @Excel(name = "当前套餐")
+    private String currentPlanName;
+
+    //套餐开始时间
+    @Excel(name = "套餐开始时间")
+    private String currentPlanStartTime;
+
+    //套餐失效时间
+    @Excel(name = "套餐失效时间")
+    private String currentPlanExpireTime;
+
+    //下期套餐名称
+    @Excel(name = "下期套餐")
+    private String nextPlanName;
+
+    //实名状态 0 未认证  1 已认证 2人工审核中
+    private Integer certified;
+
+    //实名状态 0 未认证  1 已认证 2人工审核中
+    @Excel(name = "实名状态")
+    private String certifiedName;
+}

+ 0 - 9
fs-service/src/main/java/com/fs/watch/domain/vo/WatchDeviceInfoAndUserIdVo.java

@@ -1,9 +0,0 @@
-package com.fs.watch.domain.vo;
-
-import com.fs.watch.domain.WatchDeviceInfo;
-import lombok.Data;
-
-@Data
-public class WatchDeviceInfoAndUserIdVo extends WatchDeviceInfo {
-    private Long userId;
-}

+ 2 - 0
fs-service/src/main/java/com/fs/watch/domain/vo/WatchSleepDataVo.java

@@ -15,6 +15,8 @@ public class WatchSleepDataVo {
      */
     private String deviceId;
 
+    private String date; //时间
+
     /**
      * 开始时间
      */

+ 12 - 0
fs-service/src/main/java/com/fs/watch/domain/vo/WatchSportDataByDateAndThirdDeviceVo.java

@@ -0,0 +1,12 @@
+package com.fs.watch.domain.vo;
+
+import com.fs.watch.domain.WatchSportData;
+import lombok.Data;
+
+@Data
+public class WatchSportDataByDateAndThirdDeviceVo extends WatchSportData {
+    /**
+     * 时长(秒)
+     */
+    private Float duration;
+}

+ 10 - 0
fs-service/src/main/java/com/fs/watch/domain/vo/WatchSportRecordVo.java

@@ -23,4 +23,14 @@ public class WatchSportRecordVo {
      */
     private Float time;
 
+    /**
+     * 步数
+     */
+    private Long step;
+
+    /**
+     * 卡路里
+     */
+    private Float calorie;
+
 }

+ 2 - 0
fs-service/src/main/java/com/fs/watch/mapper/WatchAlarmDataMapper.java

@@ -36,4 +36,6 @@ public interface WatchAlarmDataMapper{
     Integer setAppStatusByDeviceId(@Param("deviceId")String deviceId);
 
     Boolean deleteByDeviceId(@Param("deviceId")String deviceId);
+
+    Integer setLocation(@Param("data")WatchAlarmData watchAlarmData);
 }

+ 12 - 0
fs-service/src/main/java/com/fs/watch/mapper/WatchAudioMsgLogMapper.java

@@ -0,0 +1,12 @@
+package com.fs.watch.mapper;
+
+import com.fs.common.annotation.DataSource;
+import com.fs.common.enums.DataSourceType;
+import com.fs.watch.domain.WatchAudioMsgLog;
+import org.apache.ibatis.annotations.Param;
+
+@DataSource(DataSourceType.CLICKHOUSE)
+public interface WatchAudioMsgLogMapper {
+
+    void insert(@Param("data") WatchAudioMsgLog data);
+}

+ 4 - 8
fs-service/src/main/java/com/fs/watch/mapper/WatchBloodPressureDataMapper.java

@@ -14,34 +14,30 @@ import java.util.Map;
 * @createDate 2024-10-15 11:06:50
 * @Entity watch.domain.WatchBloodPressureData
 */
+@DataSource(DataSourceType.CLICKHOUSE)
 public interface WatchBloodPressureDataMapper{
 
-    @DataSource(DataSourceType.CLICKHOUSE)
     void insert(@Param("data") WatchBloodPressureData data);
 
-    @DataSource(DataSourceType.CLICKHOUSE)
     Integer queryByCreateTime(@Param("createTime") String createTime);
 
-    @DataSource(DataSourceType.CLICKHOUSE)
     List<?> queryByDateAndDeviceId(@Param("date") String date, @Param("deviceId") String deviceId);
 
-    @DataSource(DataSourceType.CLICKHOUSE)
     List<WatchBloodPressureData> queryBpByDate(@Param("startTime") String startTime, @Param("endTime") String endTime,
                                                @Param("deviceId") String deviceId, @Param("status") Integer status);
 
-    @DataSource(DataSourceType.CLICKHOUSE)
+
     List<Map<String, Object>> countBpByDate(@Param("startTime") String startTime, @Param("endTime") String endTime, @Param("deviceId") String deviceId);
 
-    @DataSource(DataSourceType.CLICKHOUSE)
+    Map<String, Integer> countMaxAndMinBpByDate(@Param("startTime") String startTime, @Param("endTime") String endTime, @Param("deviceId") String deviceId);
+
     WatchBloodPressureData getLatest(@Param("deviceId") String deviceId);
 
-    @DataSource(DataSourceType.CLICKHOUSE)
     int countBpPageByDate(@Param("startTime") String startTime,
                           @Param("endTime") String endTime,
                           @Param("deviceId") String deviceId,
                           @Param("status") Integer status);
 
-    @DataSource(DataSourceType.CLICKHOUSE)
     List<WatchBloodPressureData> queryBgPageByDate(@Param("startTime") String startTime,
                                                    @Param("endTime") String endTime,
                                                    @Param("deviceId") String deviceId,

+ 2 - 0
fs-service/src/main/java/com/fs/watch/mapper/WatchDeviceInfoClicMapper.java

@@ -32,5 +32,7 @@ public interface WatchDeviceInfoClicMapper {
     List<WatchDeviceInfoClic> selectDeviceInfoList(WatchDeviceInfoClicParam param);
 
     WatchDeviceInfoClic selectOneByIcc(@Param("iccid")String iccid);
+
+    List<WatchDeviceInfoClic> selectListByIccList(@Param("iccidList") List<String> iccidList);
 }
 

+ 4 - 0
fs-service/src/main/java/com/fs/watch/mapper/WatchDeviceInfoMapper.java

@@ -69,4 +69,8 @@ public interface WatchDeviceInfoMapper{
     List<WatchDeviceInfo> selectListByUserOrFamilyUser(@Param("userId") Long userId);
 
     void removeUserId(WatchDeviceInfo data);
+
+    WatchDeviceInfo selectByUserId(String userId);
+
+    List<WatchDeviceInfoVo> selectCompanyNameByList(@Param("deviceIds") List<String> deviceIds);
 }

+ 68 - 0
fs-service/src/main/java/com/fs/watch/mapper/WatchDeviceWeekMapper.java

@@ -0,0 +1,68 @@
+package com.fs.watch.mapper;
+
+import com.fs.watch.domain.WatchDeviceWeek;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+* @author Administrator
+* @description 针对表【watch_device_week(每周健康周报汇总)】的数据库操作Mapper
+* @createDate 2025-10-11 13:22:54
+* @Entity generator.domain.WatchDeviceWeek
+*/
+public interface WatchDeviceWeekMapper {
+
+    /**
+     * 查询每周健康周报汇总
+     *
+     * @param id 每周健康周报汇总主键
+     * @return 每周健康周报汇总
+     */
+    WatchDeviceWeek selectWatchDeviceWeekById(Long id);
+
+    /**
+     * 查询每周健康周报汇总列表
+     *
+     * @param watchDeviceWeek 每周健康周报汇总
+     * @return 每周健康周报汇总集合
+     */
+    List<WatchDeviceWeek> selectWatchDeviceWeekList(WatchDeviceWeek watchDeviceWeek);
+
+    /**
+     * 新增每周健康周报汇总
+     *
+     * @param watchDeviceWeek 每周健康周报汇总
+     * @return 结果
+     */
+    int insertWatchDeviceWeek(WatchDeviceWeek watchDeviceWeek);
+
+    /**
+     * 修改每周健康周报汇总
+     *
+     * @param watchDeviceWeek 每周健康周报汇总
+     * @return 结果
+     */
+    int updateWatchDeviceWeek(WatchDeviceWeek watchDeviceWeek);
+
+    /**
+     * 删除每周健康周报汇总
+     *
+     * @param id 每周健康周报汇总主键
+     * @return 结果
+     */
+    int deleteWatchDeviceWeekById(Long id);
+
+    /**
+     * 批量删除每周健康周报汇总
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteWatchDeviceWeekByIds(Long[] ids);
+
+    WatchDeviceWeek getByDeviceIdAndTime(@Param("deviceId") String deviceId,@Param("createTime") Date createTime);
+
+    WatchDeviceWeek getByUserIdAndTime(@Param("userId") Long userId,@Param("createTime") Date createTime);
+}

+ 2 - 0
fs-service/src/main/java/com/fs/watch/mapper/WatchDoctorMapper.java

@@ -65,4 +65,6 @@ public interface WatchDoctorMapper extends BaseMapper<WatchDoctor>{
     void insertBatchWatchUserCompany(@Param("list") ArrayList<WatchDoctor> dList);
 
     void deleteBatch(@Param("deviceId")Long deviceId,@Param("list") List<String> subDoctorList);
+
+    WatchDoctor selectDoctorByDeviceId(Long deviceId);
 }

+ 2 - 0
fs-service/src/main/java/com/fs/watch/mapper/WatchHeartRateDataMapper.java

@@ -38,5 +38,7 @@ public interface WatchHeartRateDataMapper{
 
     List<Map<String, Object>> countBpByDate(@Param("startTime")String startTime, @Param("endTime") String endTime, @Param("deviceId")String deviceId);
 
+    Map<String, Integer> countMaxAndAvgBpByDate(@Param("startTime")String startTime, @Param("endTime") String endTime, @Param("deviceId")String deviceId);
+
     List<WatchHeartRateData> queryByMonth(@Param("deviceId")String deviceId, @Param("monthStr")String monthStr);
 }

+ 36 - 0
fs-service/src/main/java/com/fs/watch/mapper/WatchSosCallLogsMapper.java

@@ -0,0 +1,36 @@
+package com.fs.watch.mapper;
+
+import com.fs.common.annotation.DataSource;
+import com.fs.common.enums.DataSourceType;
+import com.fs.watch.domain.WatchSosCallLogs;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * sos报警日志(WatchSosCallLogs)表数据库访问层
+ *
+ * @author makejava
+ * @since 2024-12-24 14:30:26
+ */
+@DataSource(DataSourceType.CLICKHOUSE)
+public interface WatchSosCallLogsMapper {
+
+
+    /**
+     * 新增数据
+     *
+     * @param watchSosCallLogs 实例对象
+     * @return 影响行数
+     */
+    void insert(@Param("data")WatchSosCallLogs watchSosCallLogs);
+
+    Integer queryByAlarmTime(@Param("alarmTime")String alarmTime);
+
+    WatchSosCallLogs getByDeviceIdAndTime(@Param("deviceId") String deviceId, @Param("alarmTime") String alarmTime);
+
+    WatchSosCallLogs getByDeviceIdAndTimeOne(@Param("deviceId") String deviceId, @Param("alarmTime") long alarmTime);
+
+    void batchInsertData(@Param("list") List<WatchSosCallLogs> list);
+}
+

+ 2 - 0
fs-service/src/main/java/com/fs/watch/mapper/WatchSpo2DataMapper.java

@@ -40,4 +40,6 @@ public interface WatchSpo2DataMapper {
                                             @Param("num") Integer num,
                                             @Param("size") Integer size
     );
+
+    Float countAvgBpByDate(@Param("startTime") String startTime, @Param("endTime") String endTime, @Param("deviceId") String deviceId);
 }

+ 0 - 1
fs-service/src/main/java/com/fs/watch/param/WatchChartQueryParam.java

@@ -1,6 +1,5 @@
 package com.fs.watch.param;
 
-import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fs.common.core.domain.BaseEntity;
 import lombok.Data;
 

+ 15 - 0
fs-service/src/main/java/com/fs/watch/param/WatchDeviceInfoQueryParam.java

@@ -22,6 +22,16 @@ public class WatchDeviceInfoQueryParam extends BaseQueryParam{
      */
     private Long doctorId;
 
+    /**
+     * 绑定用户id
+     */
+    private String userId;
+
+    /**
+     * 绑定家人用户id
+     */
+    private String familyUserId;
+
     /**
      * 所属医生名字
      */
@@ -59,4 +69,9 @@ public class WatchDeviceInfoQueryParam extends BaseQueryParam{
      */
     private String watchUserName;
 
+    /**
+     * 健康状态
+     */
+    private Integer isNormal;
+
 }

+ 17 - 0
fs-service/src/main/java/com/fs/watch/param/WatchUserByDeviceIdParam.java

@@ -0,0 +1,17 @@
+package com.fs.watch.param;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class WatchUserByDeviceIdParam {
+    private List<WatchUserByDeviceIdTemp> params;
+    private Boolean isFamily;
+
+    @Data
+    public static class WatchUserByDeviceIdTemp {
+        private String deviceId;
+        private Integer deviceType;
+    }
+}

+ 8 - 0
fs-service/src/main/java/com/fs/watch/service/DeviceSetUpService.java

@@ -3,6 +3,7 @@ package com.fs.watch.service;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.watch.domain.*;
 import com.fs.watch.domain.vo.AlarmClockVos;
+import com.fs.watch.param.DeviceSendParam;
 
 public interface DeviceSetUpService {
     Boolean userinfo(UserInfo userInfo);
@@ -72,4 +73,11 @@ public interface DeviceSetUpService {
     Boolean temperatureUnit (String deviceNumber,Integer unit);
 
     DeviceUserInfo getUserinfo(String deviceId,Long userId,Integer selectType);
+
+    /**
+     * 发送语音给腕表
+     * @param param
+     * @return
+     */
+    Boolean sendMp3(DeviceSendParam param);
 }

+ 7 - 0
fs-service/src/main/java/com/fs/watch/service/WatchAudioMsgLogService.java

@@ -0,0 +1,7 @@
+package com.fs.watch.service;
+
+import com.fs.watch.domain.WatchAudioMsgLog;
+
+public interface WatchAudioMsgLogService {
+    Boolean insert(WatchAudioMsgLog data);
+}

+ 2 - 1
fs-service/src/main/java/com/fs/watch/service/WatchBasicInfoService.java

@@ -46,5 +46,6 @@ public interface WatchBasicInfoService{
 
     List<GnssVo> queryGnssByDate(String starTime, String endTime, String deviceId);
 
-    AppFsUserHealthReportVo getAppFsUserHealthReportVo(Date startTime, Date endTime, String deviceId);
+    AppFsUserHealthReportVo getAppFsUserHealthReportVo(Date startTime, Date endTime, String deviceId,Long watchUserId
+            ,Boolean isFamily,Integer isRefresh,Integer deviceType);
 }

+ 6 - 4
fs-service/src/main/java/com/fs/watch/service/WatchBloodGlucoseDataService.java

@@ -17,13 +17,15 @@ public interface WatchBloodGlucoseDataService{
 
     List<WatchBloodGlucoseData> queryByDateAndDeviceId(String date, String deviceId);
 
-    List<WatchBloodGlucoseData> queryBgByDate(Date startTime, Date endTime, String deviceId, Integer status);
+    List<WatchBloodGlucoseData> queryBgByDate(Date startTime, Date endTime, String deviceId, Integer status,Integer deviceType);
 
-    List<Map<String,Object>> countBgByDate(Date startTime, Date endTime, String deviceId);
+    List<Map<String,Object>> countBgByDate(Date startTime, Date endTime, String deviceId,Integer deviceType);
 
     WatchBloodGlucoseData getLatest(String deviceId);
 
-    int countBgPageByDate(Date startTime, Date endTime, String deviceId,Integer status);
+    int countBgPageByDate(Date startTime, Date endTime, String deviceId,Integer status,Integer deviceType);
 
-    List<WatchBloodGlucoseData> queryBgPageByDate(Date startTime, Date endTime, String deviceId, Integer status,Integer num, Integer size);
+    List<WatchBloodGlucoseData> queryBgPageByDate(Date startTime, Date endTime, String deviceId, Integer status,Integer num, Integer size,Integer deviceType);
+
+    Integer getStatus(Double num);
 }

+ 2 - 0
fs-service/src/main/java/com/fs/watch/service/WatchBloodPressureDataService.java

@@ -28,4 +28,6 @@ public interface WatchBloodPressureDataService{
     int countBpPageByDate(Date startTime, Date endTime, String deviceId, Integer status);
 
     List<WatchBloodPressureData> queryBgPageByDate(Date startTime, Date endTime, String deviceId, Integer status, Integer num, Integer size);
+
+    Integer getStatus(int sbp, int dbp);
 }

+ 4 - 3
fs-service/src/main/java/com/fs/watch/service/WatchDataService.java

@@ -5,13 +5,14 @@ import com.fs.watch.domain.vo.AppInfoVo;
 import com.fs.watch.domain.vo.FsMonitorDataVo;
 import com.fs.watch.domain.vo.QueryPageMonthVo;
 import com.fs.watch.domain.vo.WatchLastHealthDataVo;
+import com.fs.watch.param.WatchUserByDeviceIdParam;
 
 import java.util.List;
 
 public interface WatchDataService {
-    List<FsMonitorDataVo> queryIndexWatchData(List<String> types, String deviceId,String userId);
+    List<FsMonitorDataVo> queryIndexWatchData(List<String> types, String deviceId,String userId,Integer deviceType);
 
-    List<AppInfoVo> getUserByDeviceId(String deviceIds, Boolean isFamily,Long userId);
+    List<AppInfoVo> getUserByDeviceId(WatchUserByDeviceIdParam watchUserByDeviceIdParam, Long userId);
 
     Boolean power(String deviceId, Boolean isLcdgesture, Boolean isLocation, Boolean isPower, Boolean isHeartHealth);
 
@@ -21,7 +22,7 @@ public interface WatchDataService {
 
     Boolean setDeviceMode(String deviceId, Boolean isLocation, Integer interval, Boolean isPower);
 
-    QueryPageMonthVo queryMonthByDeviceId(String deviceId, Integer pageSize, Integer pageNum);
+    QueryPageMonthVo queryMonthByDeviceId(String deviceId, Integer pageSize, Integer pageNum,Integer deviceType);
 
     List<WatchLastHealthDataVo> queryLastWatchData(String deviceId);
 

+ 0 - 24
fs-service/src/main/java/com/fs/watch/service/WatchDeviceBeginnerGuideService.java

@@ -1,24 +0,0 @@
-package com.fs.watch.service;
-
-import com.fs.watch.domain.WatchDeviceBeginnerGuide;
-
-import java.util.List;
-
-public interface WatchDeviceBeginnerGuideService {
-    /**
-     * 查询新手引导
-     *
-     * @param id 新手引导主键
-     * @return 新手引导
-     */
-    public WatchDeviceBeginnerGuide selectDeviceBeginnerGuideById(Long id);
-
-    /**
-     * 查询新手引导列表
-     *
-     * @param deviceBeginnerGuide 新手引导
-     * @return 新手引导集合
-     */
-    public List<WatchDeviceBeginnerGuide> selectDeviceBeginnerGuideList(WatchDeviceBeginnerGuide deviceBeginnerGuide);
-
-}

+ 3 - 0
fs-service/src/main/java/com/fs/watch/service/WatchDeviceInfoClicService.java

@@ -2,6 +2,7 @@ package com.fs.watch.service;
 
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.watch.domain.WatchDeviceInfoClic;
+import com.fs.watch.domain.vo.WatchDeviceInfoAndIotExportVO;
 import com.fs.watch.param.DeviceIdAndIotInfoQueryParam;
 import com.fs.watch.param.WatchDeviceInfoClicParam;
 
@@ -25,4 +26,6 @@ public interface WatchDeviceInfoClicService {
     TableDataInfo getDeviceIdAndIotInfo(DeviceIdAndIotInfoQueryParam param);
 
     List<WatchDeviceInfoClic> selectWatchDeviceInfoClicList(WatchDeviceInfoClicParam param);
+
+    List<WatchDeviceInfoAndIotExportVO> exportDeviceIdAndIotInfo(DeviceIdAndIotInfoQueryParam param);
 }

+ 2 - 0
fs-service/src/main/java/com/fs/watch/service/WatchDeviceInfoService.java

@@ -62,4 +62,6 @@ public interface WatchDeviceInfoService{
     void bindCompany(CompanyUserUser map);
 
     void removeUserId(String deviceId);
+
+    List<WatchDeviceInfoVo> selectCompanyNameByList(List<String> deviceIds);
 }

+ 11 - 0
fs-service/src/main/java/com/fs/watch/service/WatchDeviceWeekService.java

@@ -0,0 +1,11 @@
+package com.fs.watch.service;
+
+
+/**
+* @author Administrator
+* @description 针对表【watch_device_week(每周健康周报汇总)】的数据库操作Service
+* @createDate 2025-10-11 13:22:54
+*/
+public interface WatchDeviceWeekService {
+
+}

+ 4 - 2
fs-service/src/main/java/com/fs/watch/service/WatchHeartRateDataService.java

@@ -20,7 +20,7 @@ public interface WatchHeartRateDataService{
 
     WatchHeartRateDataVo queryByDate(String date, String deviceId);
 
-    WatchHeartRateDataVo list(Date startTime, Date endTime, String deviceId);
+    WatchHeartRateDataVo list(Date startTime, Date endTime, String deviceId, Integer deviceType);
 
     WatchHeartRateData getLatest(String deviceId);
 
@@ -29,5 +29,7 @@ public interface WatchHeartRateDataService{
     List<WatchHeartRateData> queryHeartPageByDate(Date startTime, Date endTime, String deviceId, Integer pageNum,
                                                   Integer pageSize);
 
-    List<Map<String, Object>> countHeartByDate(Date startTime, Date endTime, String deviceId);
+    List<Map<String, Object>> countHeartByDate(Date startTime, Date endTime, String deviceId,Integer deviceType);
+
+    Integer getStatus(int maxBpm, int minBpm);
 }

+ 1 - 1
fs-service/src/main/java/com/fs/watch/service/WatchSleepDataService.java

@@ -21,7 +21,7 @@ public interface WatchSleepDataService{
 
     AppWatchSleepDataVo queryByDateAndDeviceIdAndState(String date, String deviceId);
 
-    AppWatchSleepDataVo list(Date startTime, Date endTime, String deviceId);
+    AppWatchSleepDataVo list(Date startTime, Date endTime, String deviceId, Integer deviceType);
 
 
     WatchSleepData getLast(String deviceId);

+ 33 - 0
fs-service/src/main/java/com/fs/watch/service/WatchSosCallLogsService.java

@@ -0,0 +1,33 @@
+package com.fs.watch.service;
+
+
+import com.fs.watch.domain.WatchSosCallLogs;
+
+import java.util.List;
+
+/**
+ * sos报警日志(WatchSosCallLogs)表服务接口
+ *
+ * @author makejava
+ * @since 2024-12-24 14:30:26
+ */
+public interface WatchSosCallLogsService {
+
+
+    /**
+     * 新增数据
+     *
+     * @param watchSosCallLogs 实例对象
+     * @return 实例对象
+     */
+    Boolean insert(WatchSosCallLogs watchSosCallLogs);
+
+    /**
+     * 批量添加
+     * @param list
+     * @return
+     */
+    Boolean batchInsertData(List<WatchSosCallLogs> list);
+
+
+}

+ 2 - 2
fs-service/src/main/java/com/fs/watch/service/WatchSpo2DataService.java

@@ -19,11 +19,11 @@ public interface WatchSpo2DataService{
 
     List<WatchSpo2DataVo> queryByDateAndDeviceIdAndState(String date, String deviceId);
 
-    WatchSpo2DataQueryVo querySpByDate(Date startTime, Date endTime, String deviceId);
+    WatchSpo2DataQueryVo querySpByDate(Date startTime, Date endTime, String deviceId,Integer deviceType);
 
     Integer getStatus(int maxOxy, int minOxy);
 
-    List<Map<String,Object>> countSpByDate(Date startTime, Date endTime, String deviceId);
+    List<Map<String,Object>> countSpByDate(Date startTime, Date endTime, String deviceId,Integer deviceType);
 
     WatchSpo2DataVo getLatest(String deviceId);
 

+ 3 - 3
fs-service/src/main/java/com/fs/watch/service/WatchSportDataService.java

@@ -23,15 +23,15 @@ public interface WatchSportDataService{
 
     List<WatchSportListVo> queryPageByDataAndDeviceId(Date startTime, Date endTime, String deviceId,Integer pageSize, Integer pageNum);
 
-    List<WatchSportRecordVo> queryRecord(String deviceId);
+    List<WatchSportRecordVo> queryRecord(String deviceId,Integer deviceType);
 
-    WatchSportIndexVo sportData(String userId,String deviceId,Boolean isFamily);
+    WatchSportIndexVo sportData(String userId,String deviceId,Boolean isFamily,Integer deviceType);
 
     List<WatchSportDataByDateVo> sportDataByDate(Date startTime, Date endTime, String deviceId);
 
     WatchSportDetailDataVo dataByType(String deviceId, String type);
 
-    AppFsUserHealthVo getUserHealthInfoByDeviceId(String deviceId,Date startTime, Date endTime,Long userId);
+    AppFsUserHealthVo getUserHealthInfoByDeviceId(String deviceId,Date startTime, Date endTime,Long userId,Integer deviceType);
 
     WatchStepStatusEnum getWeekStatus(String deviceId, String startTime, String endTime);
 }

+ 4 - 4
fs-service/src/main/java/com/fs/watch/service/WatchThirdBpDataService.java

@@ -23,15 +23,15 @@ public interface WatchThirdBpDataService{
 
     List<WatchThirdBpData> queryByDateAndDeviceId(String date, String deviceId);
 
-    List<WatchThirdBpData> queryBpByDate(String startTime, String endTime, String deviceId, Integer status);
+    List<WatchThirdBpData> queryBpByDate(String startTime, String endTime, String deviceId, Integer status,Integer deviceType);
 
     WatchThirdBpData getLatest(String deviceId);
 
     Integer getStatus(int sbp, int dbp);
 
-    List<Map<String, Object>> countBpByDate(Date startTime, Date endTime, String deviceId);
+    List<Map<String, Object>> countBpByDate(Date startTime, Date endTime, String deviceId,Integer deviceType);
 
-    int countBpPageByDate(Date startTime, Date endTime, String deviceId, Integer status);
+    int countBpPageByDate(Date startTime, Date endTime, String deviceId, Integer status,Integer deviceType);
 
-    List<WatchThirdBpData> queryBgPageByDate(Date startTime, Date endTime, String deviceId, Integer status, Integer num, Integer size);
+    List<WatchThirdBpData> queryBgPageByDate(Date startTime, Date endTime, String deviceId, Integer status, Integer num, Integer size,Integer deviceType);
 }

+ 4 - 4
fs-service/src/main/java/com/fs/watch/service/WatchThirdUaDataService.java

@@ -22,12 +22,12 @@ public interface WatchThirdUaDataService{
 
     List<WatchThirdUaData> queryByDateAndDeviceId(String date, String deviceId);
 
-    List<WatchThirdUaData> list(Date startTime, Date endTime, String deviceId);
+    List<WatchThirdUaData> list(Date startTime, Date endTime, String deviceId,Integer deviceType);
 
-    List<Map<String, Object>> countUaByDate(Date startTime, Date endTime, String deviceId);
+    List<Map<String, Object>> countUaByDate(Date startTime, Date endTime, String deviceId,Integer deviceType);
 
     List<WatchThirdUaData> queryListByDate(Date startTime, Date endTime, String deviceId, Integer pageNum,
-                                                Integer pageSize,Integer status);
+                                                Integer pageSize,Integer status,Integer deviceType);
 
-    int countTotalDate(Date startTime, Date endTime, String deviceId,Integer status);
+    int countTotalDate(Date startTime, Date endTime, String deviceId,Integer status,Integer deviceType);
 }

+ 6 - 1
fs-service/src/main/java/com/fs/watch/service/WatchUserService.java

@@ -10,6 +10,7 @@ import com.fs.watch.domain.vo.WatchUserAndHealthVo;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageRequest;
 
+import java.util.HashMap;
 import java.util.List;
 
 /**
@@ -40,7 +41,7 @@ public interface WatchUserService {
      * @param deviceId
      * @return
      */
-    AppFsUserVo getUserInfoByDeviceId(String deviceId,Boolean isFamily,Long watchUserId);
+    AppFsUserVo getUserInfoByDeviceId(String deviceId,Boolean isFamily,Long watchUserId,Integer deviceType);
 
     /**
      * 通过ID查询单条数据
@@ -95,4 +96,8 @@ public interface WatchUserService {
     List<WatchUserAndHealthVo> listByDeviceIdNotNull();
 
     FsHealthTongue getLastTongueByDeviceId(String deviceId);
+
+    R editXHSDevice(HashMap<String, String> param);
+
+    R removeXHSDevice(String userId, String xhsDeviceId,String newXhsDeviceId);
 }

+ 63 - 0
fs-service/src/main/java/com/fs/watch/service/impl/DeviceSetUpServiceImpl.java

@@ -11,8 +11,13 @@ import com.fs.his.utils.PhoneUtil;
 import com.fs.watch.domain.*;
 import com.fs.watch.domain.vo.AlarmClockObjectVo;
 import com.fs.watch.domain.vo.AlarmClockVos;
+import com.fs.watch.mapper.WatchAudioMsgLogMapper;
+import com.fs.watch.param.DeviceSendParam;
 import com.fs.watch.service.*;
+import com.fs.watch.utils.AudioConvertUtil;
+import com.fs.watch.utils.MD5Utils;
 import com.fs.watch.utils.MyHttpUtils;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -26,6 +31,7 @@ import java.time.format.DateTimeFormatter;
 import java.util.*;
 
 @Service
+@Slf4j
 public class DeviceSetUpServiceImpl implements DeviceSetUpService {
     private MyHttpUtils httpUtils = new MyHttpUtils();
     @Autowired
@@ -38,6 +44,8 @@ public class DeviceSetUpServiceImpl implements DeviceSetUpService {
     private WatchSendMsgSetService watchSendMsgSetService;
     @Autowired
     private WatchSendMsgLogService watchSendMsgLogService;
+    @Autowired
+    private WatchAudioMsgLogMapper watchAudioMsgLogMapper;
 
     /**
      * 下发用户设置到设备
@@ -1271,9 +1279,64 @@ public class DeviceSetUpServiceImpl implements DeviceSetUpService {
                 } else {
                     userInfo.setPhone(PhoneUtil.decryptPhone(phone));
                 }
+                //2025-8-8新增需求手机号码脱敏显示
+                if(StringUtils.isNotBlank(userInfo.getPhone())){
+                    userInfo.setPhone(userInfo.getPhone().replaceAll("(\\d{3})\\d{8}", "$1********"));
+                }
             }
             return userInfo;
         }
         return null;
     }
+
+    @Override
+    public Boolean sendMp3(DeviceSendParam param) {
+        Date nowDate = DateUtils.getNowDate();
+        String fileUrl = param.getFileUrl();
+        String sendUserName = param.getSendUserName();
+        String deviceId = param.getDeviceId();
+        try {
+            fileUrl = AudioConvertUtil.convertUploadAndClean(
+                    fileUrl,
+                    deviceId,
+                    DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss",nowDate),
+                    "/tmp/audio/"
+            );
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        JSONObject fileInfo = MD5Utils.getMd5AndSizeFromUrl(fileUrl);
+        Map<String, Object> map = new HashMap<>();
+        map.put("type",3);
+        map.put("device_id",deviceId);
+        map.put("url",fileUrl);
+        map.put("md5",fileInfo.getString("md5"));
+        map.put("size",Long.valueOf(fileInfo.getString("size")));
+        map.put("sender",sendUserName);
+        //取时间的 时:分
+        map.put("send_time", DateUtils.parseDateToStr("HH:mm",nowDate));
+        Map response = httpUtils.getPost("/entservice2/file/download", map);
+        WatchAudioMsgLog watchAudioMsgLog = new WatchAudioMsgLog();
+        watchAudioMsgLog.setDeviceId(deviceId);
+        watchAudioMsgLog.setFileUrl(param.getFileUrl());
+        watchAudioMsgLog.setType(0);
+        watchAudioMsgLog.setCreateTime(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss",nowDate));
+        watchAudioMsgLog.setStatus(0);
+        watchAudioMsgLog.setMsg(JSON.toJSONString(response));
+        if (response != null){
+            String rrpcCode = response.get("RrpcCode").toString();
+            if ("SUCCESS".equals(rrpcCode) || "TIMEOUT".equals(rrpcCode)){
+                watchAudioMsgLog.setStatus(1);
+            }
+
+        }
+        //记录发送记录
+        try {
+            watchAudioMsgLogMapper.insert(watchAudioMsgLog);
+        } catch (Exception e) {
+            log.error("插入 watchAudioMsgLog 失败,参数: {}", watchAudioMsgLog, e); // 关键:打印完整异常
+            throw new RuntimeException(e);
+        }
+        return watchAudioMsgLog.getStatus()==1?true:false;
+    }
 }

+ 81 - 0
fs-service/src/main/java/com/fs/watch/service/impl/WatchAudioMsgLogServiceImpl.java

@@ -0,0 +1,81 @@
+package com.fs.watch.service.impl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fs.fastgptApi.util.AudioUtils;
+import com.fs.im.dto.OpenImMsgDTO;
+import com.fs.im.service.OpenIMService;
+import com.fs.watch.domain.WatchAudioMsgLog;
+import com.fs.watch.domain.WatchDeviceInfo;
+import com.fs.watch.domain.WatchDoctor;
+import com.fs.watch.mapper.WatchAudioMsgLogMapper;
+import com.fs.watch.mapper.WatchDeviceInfoMapper;
+import com.fs.watch.mapper.WatchDoctorMapper;
+import com.fs.watch.service.WatchAudioMsgLogService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Service
+@Slf4j
+public class WatchAudioMsgLogServiceImpl implements WatchAudioMsgLogService {
+
+    @Autowired
+    private WatchAudioMsgLogMapper mapper;
+    @Autowired
+    private WatchDeviceInfoMapper watchDeviceInfoMapper;
+    @Autowired
+    private WatchDoctorMapper watchDoctorMapper;
+    @Autowired
+    private OpenIMService openIMService;
+    @Override
+    public Boolean insert(WatchAudioMsgLog data) {
+        try {
+            mapper.insert(data);
+            //查询用户信息
+            WatchDeviceInfo watchDeviceInfo = watchDeviceInfoMapper.selectByDeviceNumber(data.getDeviceId());
+            //查询医生
+            WatchDoctor watchDoctor = watchDoctorMapper.selectDoctorByDeviceId(watchDeviceInfo.getDeviceId());
+            if (watchDoctor!=null){
+                OpenImMsgDTO openImMsgDTO = new OpenImMsgDTO();
+                openImMsgDTO.setSendID("U"+watchDeviceInfo.getUserId());
+                openImMsgDTO.setRecvID("D"+watchDoctor.getDoctorId());
+                openImMsgDTO.setContentType(103);
+                openImMsgDTO.setSessionType(1);
+                OpenImMsgDTO.Content content = new OpenImMsgDTO.Content();
+                HashMap<String, Object> map = new HashMap<>();
+                map.put("uuid","");
+                map.put("soundPath","");
+                map.put("dataSize",0);
+                map.put("soundType","");
+                map.put("sourceUrl",data.getFileUrl());
+                Integer durations = AudioUtils.getDurations(data.getFileUrl());
+                map.put("duration",durations);
+                ObjectMapper mapper = new ObjectMapper();
+                String json = mapper.writeValueAsString(map);
+                content.setContent(json);
+                openImMsgDTO.setContent(content);
+                openIMService.openIMSendMsg(openImMsgDTO);
+            }
+        } catch (Exception e) {
+            log.error("===============watchAudioData:insert=========================={}", e.getMessage());
+            return false;
+        }
+        return true;
+    }
+
+
+    private Map<String, Object> getAudioMsgLogMap(WatchAudioMsgLog data) {
+        Map<String, Object> params = new HashMap<>();
+        params.put("id", data.getId());
+        params.put("deviceId", data.getDeviceId());
+        params.put("fileUrl", data.getFileUrl());
+        params.put("type", data.getType());
+        params.put("status", data.getStatus());
+        params.put("msg", data.getMsg());
+        params.put("createTime", data.getCreateTime());
+        return params;
+    }
+}

+ 673 - 31
fs-service/src/main/java/com/fs/watch/service/impl/WatchBasicInfoServiceImpl.java

@@ -1,14 +1,32 @@
 package com.fs.watch.service.impl;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fs.aiChat.mapper.InterestAiChatSessionMapper;
+import com.fs.common.core.domain.R;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
-import com.fs.watch.domain.WatchBasicInfo;
-import com.fs.watch.domain.WatchDeviceInfo;
-import com.fs.watch.domain.WatchHeartRateData;
-import com.fs.watch.domain.vo.AppFsUserHealthReportVo;
-import com.fs.watch.domain.vo.AppHealthReportVo;
-import com.fs.watch.domain.vo.GnssVo;
-import com.fs.watch.domain.vo.WatchSleepDataVo;
+import com.fs.fastgptApi.param.ChatParam;
+import com.fs.fastgptApi.result.ChatDetailTStreamFResult;
+import com.fs.fastgptApi.result.KnowledgeBaseResult;
+import com.fs.fastgptApi.service.ChatService;
+import com.fs.his.domain.FsThirdDeviceData;
+import com.fs.his.mapper.FsHealthPulseMapper;
+import com.fs.his.mapper.FsHealthSurfaceMapper;
+import com.fs.his.mapper.FsHealthTongueMapper;
+import com.fs.his.mapper.FsThirdDeviceDataMapper;
+import com.fs.his.param.FsHealthPulseListUParam;
+import com.fs.his.param.FsHealthSurfaceListUParam;
+import com.fs.his.param.FsHealthTongueListUParam;
+import com.fs.his.vo.FsHealthPulseListVO;
+import com.fs.his.vo.FsHealthSurfaceListVO;
+import com.fs.his.vo.FsHealthTongueListUVO;
+import com.fs.system.service.ISysConfigService;
+import com.fs.watch.calculation.SleepScoreCalculator;
+import com.fs.watch.domain.*;
+import com.fs.watch.domain.vo.*;
 import com.fs.watch.enums.*;
 import com.fs.watch.mapper.*;
 import com.fs.watch.param.WatchDataQueryParam;
@@ -16,11 +34,15 @@ import com.fs.watch.service.*;
 import lombok.extern.slf4j.Slf4j;
 import org.jetbrains.annotations.NotNull;
 import org.mybatis.spring.MyBatisSystemException;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
 import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -55,6 +77,28 @@ public class WatchBasicInfoServiceImpl implements WatchBasicInfoService {
     private WatchSportDataService watchSportDataService;
     @Autowired
     private WatchDeviceInfoMapper watchDeviceInfoMapper;
+    @Autowired
+    private ChatService chatService;
+    @Autowired
+    private WatchUserService userService;
+    @Autowired
+    private WatchSportDataMapper sportDataMapper;
+    @Autowired
+    private FsHealthTongueMapper fsHealthTongueMapper;
+    @Autowired
+    private WatchDeviceWeekMapper watchDeviceWeekMapper;
+    @Autowired
+    private FsHealthSurfaceMapper fsHealthSurfaceMapper;
+    @Autowired
+    private FsHealthPulseMapper fsHealthPulseMapper;
+    @Autowired
+    InterestAiChatSessionMapper interestAiChatSessionMapper;
+    @Autowired
+    private FsThirdDeviceDataMapper fsThirdDeviceDataMapper;
+    @Autowired
+    private ISysConfigService sysConfigService;
+    private static final ObjectMapper objectMapper = new ObjectMapper();
+
 
     /**
      * 新增数据
@@ -64,11 +108,6 @@ public class WatchBasicInfoServiceImpl implements WatchBasicInfoService {
      */
     @Override
     public Boolean insert(WatchBasicInfo watchBasicInfo) {
-        //判断创建时间是否唯一
-        Integer num = watchBasicInfoMapper.queryByCreateTime(watchBasicInfo.getCreateTime());
-        if (num != null && num > 0) {
-            return false;
-        }
         try {
             watchBasicInfoMapper.insert(watchBasicInfo);
             //更新mysql的腕表数据
@@ -196,6 +235,14 @@ public class WatchBasicInfoServiceImpl implements WatchBasicInfoService {
         return gnssVos;
     }
 
+    private static final String HIS_CONFIG_KEY = "his.config";
+    private static final String AI_APP_KEY_FIELD = "watchAiAppKey";
+    private static final String AI_URL_FIELD = "watchAiUrl";
+    private static final String AI_APP_KEY_CONFIG_KEY = "watch.ai.appKey";
+    private static final String AI_URL_CONFIG_KEY = "watch.ai.url";
+    private static final String DEFAULT_APPKEY = "mygpt-nJvzjw0r7aEcvSA8po2BdHbUhm4oy8MEmK2V3r4YDHduo6gCJYWp";
+    private static final String DEFAULT_AIURL = "http://154.8.194.176:3000/api";
+
     /**
      * >3个异常 只给出3个异常,优先级顺序 血糖、血压、心率、尿酸、血氧、睡眠、体温、步数
      *
@@ -205,28 +252,132 @@ public class WatchBasicInfoServiceImpl implements WatchBasicInfoService {
      * @return
      */
     @Override
-    public AppFsUserHealthReportVo getAppFsUserHealthReportVo(Date startTime, Date endTime, String deviceId) {
+    public AppFsUserHealthReportVo getAppFsUserHealthReportVo(Date startTime, Date endTime, String deviceId,
+                                                              Long watchUserId,
+                                                              Boolean isFamily,
+                                                              Integer isRefresh,
+                                                              Integer deviceType) {
         AppFsUserHealthReportVo res = new AppFsUserHealthReportVo();
+        //查询用户和指定ai医生的会话
+        Integer sessionId = interestAiChatSessionMapper.selectSessionIdByUserAndRole(watchUserId, 140);
+        res.setRoleId(140);
+        if (sessionId != null){
+            res.setSessionId(sessionId);
+        }
+        //1.查询是否存在结果
+        WatchDeviceWeek weekData;
+        if (StringUtils.isBlank(deviceId)) {
+            if (watchUserId == null) {
+                return res;
+            }
+            weekData = watchDeviceWeekMapper.getByUserIdAndTime(watchUserId, startTime);
+        } else {
+            weekData = watchDeviceWeekMapper.getByDeviceIdAndTime(deviceId, startTime);
+        }
+        if (weekData != null ) {
+            if (endTime.before(DateUtils.getNowDate()) || (isRefresh == null || isRefresh == 0)){
+                BeanUtils.copyProperties(weekData, res);
+                String listJson = weekData.getListJson();
+                if (StringUtils.isNotBlank(listJson)) {
+                    res.setList(JSON.parseArray(listJson, AppHealthReportVo.class));
+                }
+                return res;
+            }
+        }
+        //获取ai解析
+        CompletableFuture<Void> aiSuggestionFuture = CompletableFuture.runAsync(() -> {
+            getAiSuggestion(startTime, endTime, deviceId, watchUserId, isFamily, res,deviceType);
+        });
+        CompletableFuture<Void> totalScoreFuture = null;
+        if (StringUtils.isNotBlank(deviceId) && (deviceType == null || deviceType == 0)) {
+            //获取异常数据及分析
+            totalScoreFuture = CompletableFuture.runAsync(() -> {
+                getTotalScoreAndNormalData(startTime, endTime, deviceId, res);
+            });
+        }
+        try {
+            if (totalScoreFuture != null){
+                // 设置超时时间为30秒
+                CompletableFuture.allOf(aiSuggestionFuture, totalScoreFuture)
+                        .get(360, TimeUnit.SECONDS);
+            } else {
+                // 设置超时时间为30秒
+                CompletableFuture.allOf(aiSuggestionFuture)
+                        .get(360, TimeUnit.SECONDS);
+            }
+
+        } catch (TimeoutException e) {
+            // 超时处理
+            throw new RuntimeException("处理超时", e);
+        } catch (Exception e) {
+            throw new RuntimeException("异步执行失败", e);
+        }
+        //存到每周数据表
+        saveWeekData(startTime,endTime, deviceId, watchUserId,res);
+        return res;
+    }
+
+    /**
+     * 存到每周数据表
+     *
+     * @param startTime
+     * @param res
+     */
+    private void saveWeekData(Date startTime, Date endTime,String deviceId, Long userId, AppFsUserHealthReportVo res) {
+        //判断最后一天是否晚于当前时间
+//        if (!endTime.after(DateUtils.getNowDate())){
+            //否
+            if (StringUtils.isNotBlank(res.getAiSuggestion()) || res.getScore() != null) {
+                WatchDeviceWeek watchDeviceWeek = new WatchDeviceWeek();
+                BeanUtils.copyProperties(res, watchDeviceWeek);
+                List<AppHealthReportVo> list = res.getList();
+                if (list != null && !list.isEmpty()) {
+                    watchDeviceWeek.setListJson(JSON.toJSONString(list));
+                }
+                watchDeviceWeek.setCreateTime(startTime);
+                WatchDeviceWeek oldWeekData = null;
+                if (StringUtils.isNotBlank(deviceId)) {
+                    watchDeviceWeek.setDeviceId(deviceId);
+                    oldWeekData = watchDeviceWeekMapper.getByDeviceIdAndTime(deviceId, startTime);
+
+                } else {
+                    watchDeviceWeek.setDeviceId(userId.toString());
+                    oldWeekData = watchDeviceWeekMapper.getByUserIdAndTime(userId, startTime);
+                }
+                watchDeviceWeek.setUserId(userId);
+                //查询是否存在 存在更新
+                if (oldWeekData != null && oldWeekData.getId() != null) {
+                    watchDeviceWeek.setId(oldWeekData.getId());
+                    watchDeviceWeekMapper.updateWatchDeviceWeek(watchDeviceWeek);
+                } else {
+                    watchDeviceWeekMapper.insertWatchDeviceWeek(watchDeviceWeek);
+                }
+            }
+//        }
+
+    }
+
+    private void getTotalScoreAndNormalData(Date startTime, Date endTime, String deviceId, AppFsUserHealthReportVo res) {
         ArrayList<AppHealthReportVo> vos = new ArrayList<>();
         AtomicInteger score = new AtomicInteger(100); //分数
         String start = DateUtils.parseDateToStr("yyyy-MM-dd hh:mm:ss", startTime);
         String end = DateUtils.parseDateToStr("yyyy-MM-dd hh:mm:ss", endTime);
         //先查询睡眠数据
-        watchSleepDataService.getSleepStatus(startTime,endTime,deviceId);
+        watchSleepDataService.getSleepStatus(startTime, endTime, deviceId);
 
         // 顺序执行各项异常处理(最多保留3个)
-        getHealth(watchBloodGlucoseDataMapper.countBpByDate(start, end, deviceId), vos, WatchBgStatusEnum.class,score);
-        getHealth(watchBloodPressureDataMapper.countBpByDate(start, end, deviceId), vos, WatchBpStatusEnum.class,score);
-        getHealth(watchHeartRateDataMapper.countBpByDate(start, end, deviceId), vos, WatchHrStatusEnum.class,score);
-        getHealth(watchThirdUaDataMapper.countUaByDate(start, end, deviceId), vos, WatchUaStatusEnum.class,score);
-        getHealth(watchSpo2DataMapper.countSpByDate(start, end, deviceId), vos, WatchSpo2StatusEnum.class,score);
-        getHealth(watchSleepDataService.countSlByDate(start, end, deviceId), vos, WatchSleepStatusEnum.class,score);
-        getHealth(watchTemperatureDataMapper.countByDate(start, end, deviceId), vos, WatchTemperatureStatusEnum.class,score);
+        getHealth(watchBloodGlucoseDataMapper.countBpByDate(start, end, deviceId), vos, WatchBgStatusEnum.class, score);
+        getHealth(watchBloodPressureDataMapper.countBpByDate(start, end, deviceId), vos, WatchBpStatusEnum.class, score);
+        getHealth(watchHeartRateDataMapper.countBpByDate(start, end, deviceId), vos, WatchHrStatusEnum.class, score);
+        getHealth(watchThirdUaDataMapper.countUaByDate(start, end, deviceId), vos, WatchUaStatusEnum.class, score);
+        getHealth(watchSpo2DataMapper.countSpByDate(start, end, deviceId), vos, WatchSpo2StatusEnum.class, score);
+        getHealth(watchSleepDataService.countSlByDate(start, end, deviceId), vos, WatchSleepStatusEnum.class, score);
+        getHealth(watchTemperatureDataMapper.countByDate(start, end, deviceId), vos, WatchTemperatureStatusEnum.class, score);
 
 
         // 2. 步数(枚举可能不需要,可直接判断)
         WatchStepStatusEnum weekStatus = watchSportDataService.getWeekStatus(start, end, deviceId);
-        if (!Objects.equals(weekStatus.getValue(), WatchStepStatusEnum.NORMAL.getValue())){
+        if (!Objects.equals(weekStatus.getValue(), WatchStepStatusEnum.NORMAL.getValue())) {
             AppHealthReportVo vo = new AppHealthReportVo();
             vo.setPrediction(weekStatus.getPrediction());
             vo.setAnalysis(weekStatus.getAnalysis());
@@ -250,29 +401,520 @@ public class WatchBasicInfoServiceImpl implements WatchBasicInfoService {
         res.setScore(finalScore);
 
         WatchHealthEnum healthEnum = null;
-        if(finalScore>=90){
+        if (finalScore >= 90) {
             healthEnum = WatchHealthEnum.EXCELLENT;
-        } else if (finalScore>=80){
+        } else if (finalScore >= 80) {
             healthEnum = WatchHealthEnum.GOOD;
-        } else if (finalScore>=70){
+        } else if (finalScore >= 70) {
             healthEnum = WatchHealthEnum.GENERAL;
-        } else{
+        } else {
             healthEnum = WatchHealthEnum.POOR;
         }
         res.setTitle(healthEnum.getTitle());
         res.setDesc(healthEnum.getDesc());
+    }
 
-        return res;
+
+    /**
+     *
+     * @param startTime
+     * @param endTime
+     * @param deviceId
+     * @param watchUserId
+     * @param isFamily
+     * @param res
+     * @param deviceType 0腕表1小护士2新表
+     */
+    private void getAiSuggestion(Date startTime, Date endTime, String deviceId, Long watchUserId, Boolean isFamily,
+                                 AppFsUserHealthReportVo res,Integer deviceType) {
+        String aiSuggestion = "";
+        ChatParam param = new ChatParam();
+        param.setStream(false);
+        param.setDetail(true);
+        ChatParam.Variables variables = new ChatParam.Variables();
+        variables.setName("healthReport");
+        List<ChatParam.Message> messageList = new ArrayList<ChatParam.Message>();
+        param.setMessages(messageList);
+        ChatParam.Message message1 = new ChatParam.Message();
+        message1.setRole("user");
+        //组合询问问题
+        StringBuilder str = new StringBuilder();
+        str.append("今日日期:");
+        str.append(DateUtils.dateTimeNow("MM月dd日"));
+        //1.身高体重
+        if (watchUserId != null) {
+            AppFsUserVo userVo = userService.getUserInfoByDeviceId(deviceId, isFamily, watchUserId,deviceType);
+            if (userVo != null && userVo.getHeight() != null && userVo.getWeight() != null) {
+                str.append("【身高 ").append(userVo.getHeight()).append("cm 体重 ").append(userVo.getWeight()).append("kg】");
+            }
+        }
+        //按天查询总数
+        //创建日历实例用于遍历日期
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(startTime);
+
+        Calendar endCalendar = Calendar.getInstance();
+        endCalendar.setTime(endTime);
+        //遍历每一天
+        //运动
+        StringBuilder spotStr = new StringBuilder();
+        //血压
+        StringBuilder bpStr = new StringBuilder();
+        //血糖
+        StringBuilder bgStr = new StringBuilder();
+        //心率
+        StringBuilder hrStr = new StringBuilder();
+        //血氧
+        StringBuilder spo2Str = new StringBuilder();
+        //睡眠
+        StringBuilder sleepStr = new StringBuilder();
+        //舌诊
+        StringBuilder tongueStr = new StringBuilder();
+        //面诊
+        StringBuilder surfaceStr = new StringBuilder();
+        StringBuilder pulseStr = new StringBuilder();
+        //判断是否需要ai解析
+        Boolean isRequestAi = false;
+        while (!calendar.after(endCalendar)) {
+            Date currentStartDate = calendar.getTime();
+            String start = DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", currentStartDate);
+            String dateToStr = DateUtils.parseDateToStr("MM月dd日", currentStartDate);
+            //创建当天结束时间(23:59:59)
+            Calendar dayEndCalendar = (Calendar) calendar.clone();
+            dayEndCalendar.add(Calendar.DAY_OF_MONTH, 1);
+            dayEndCalendar.add(Calendar.SECOND, -1);
+            Date currentEndDate = dayEndCalendar.getTime();
+            String end = DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", currentEndDate);
+
+            if (StringUtils.isNotBlank(deviceId)) {
+                //2.计算每天步数总和
+                calculateStep(deviceId, start, end, spotStr, dateToStr,deviceType);
+                //3.血压
+                calculateBp(deviceId, start, end, bpStr, dateToStr,deviceType);
+
+
+                //4.血糖
+                calculateBg(deviceId, start, end, bgStr, dateToStr,deviceType);
+                //5.心率
+                calculateHr(deviceId, start, end, hrStr, dateToStr,deviceType);
+                //6.血氧
+                calculateSpo2(deviceId, start, end, spo2Str, dateToStr,deviceType);
+
+                //7.睡眠
+                calculateSleep(deviceId, DateUtils.parseDateToStr("yyyy-MM-dd", currentStartDate), sleepStr, dateToStr,deviceType);
+            }
+            if (watchUserId != null) {
+                //8.舌诊
+                calculateTongue(watchUserId, DateUtils.parseDateToStr("yyyy-MM-dd", currentStartDate), tongueStr, dateToStr);
+                //9.面诊
+                calculateSurface(watchUserId, DateUtils.parseDateToStr("yyyy-MM-dd", currentStartDate), surfaceStr, dateToStr);
+                //10.脉诊
+                calculatePulse(watchUserId, DateUtils.parseDateToStr("yyyy-MM-dd", currentStartDate), pulseStr, dateToStr);
+            }
+
+
+
+
+
+            //日期加1天
+            calendar.add(Calendar.DAY_OF_MONTH, 1);
+            setToStartOfDay(calendar);
+        }
+        if (spotStr.length() > 0) {
+            str.append("\n").append("【步行:").append(spotStr).append("】");
+        }
+        if (bpStr.length() > 0) {
+            str.append("\n").append("【血压:").append(bpStr).append("】");
+            isRequestAi = true;
+        }
+        if (bgStr.length() > 0) {
+            str.append("\n").append("【血糖:").append(bgStr).append("】");
+            isRequestAi = true;
+        }
+        if (hrStr.length() > 0) {
+            str.append("\n").append("【心率:").append(hrStr).append("】");
+            isRequestAi = true;
+        }
+        if (spo2Str.length() > 0) {
+            str.append("\n").append("【血氧:").append(spo2Str).append("】");
+            isRequestAi = true;
+        }
+        if (sleepStr.length() > 0) {
+            if (sleepStr.toString().endsWith(",")) {
+                sleepStr.deleteCharAt(sleepStr.length() - 1);
+            }
+            str.append("\n").append("【睡眠:").append(sleepStr).append("】");
+            isRequestAi = true;
+        }
+        if (tongueStr.length() > 0) {
+            str.append("\n").append("【舌诊:").append(tongueStr).append("】");
+            isRequestAi = true;
+        }
+        if (surfaceStr.length() > 0) {
+            str.append("\n").append("【面诊:").append(surfaceStr).append("】");
+            isRequestAi = true;
+        }
+        if (pulseStr.length() > 0) {
+            str.append("\n").append("【脉诊:").append(pulseStr).append("】");
+            isRequestAi = true;
+        }
+
+
+
+        if (StringUtils.isNotBlank(str) && isRequestAi) {
+            log.info("健康报告:{}", str);
+            message1.setContent(str.toString());
+            messageList.add(message1);
+
+
+            String aiUrl = getConfigValue(AI_URL_CONFIG_KEY, DEFAULT_AIURL);
+            String appKey = getConfigValue(AI_APP_KEY_CONFIG_KEY, DEFAULT_APPKEY);
+            R r = chatService.initiatingTakeChat(param, aiUrl, appKey);
+            if (r != null && r.get("data") != null) {
+                Object data = r.get("data");
+                if (!(data instanceof KnowledgeBaseResult)) {
+                    ChatDetailTStreamFResult result = (ChatDetailTStreamFResult) r.get("data");
+                    if (result != null) {
+                        List<ChatDetailTStreamFResult.Choice> choices = result.getChoices();
+                        //默认取第一条
+                        if (choices != null && choices.size() > 0) {
+                            ChatDetailTStreamFResult.Choice choice = choices.get(0);
+                            ChatDetailTStreamFResult.Choice.Message message = choice.message;
+                            if (message != null) {
+                                String content = message.getContent();
+                                if (StringUtils.isNotBlank(content)) {
+                                    aiSuggestion = content;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        res.setAiSuggestion(aiSuggestion);
     }
 
+    private String getConfigValue(String configKey, String defaultValue) {
+        String configValue = getHisConfigValue(configKey);
+        if (StringUtils.isBlank(configValue)) {
+            configValue = sysConfigService.selectConfigByKey(configKey);
+        }
+        return StringUtils.isNotBlank(configValue) ? configValue : defaultValue;
+    }
 
+    private String getHisConfigValue(String configKey) {
+        String configValue = sysConfigService.selectConfigByKey(HIS_CONFIG_KEY);
+        if (StringUtils.isBlank(configValue)) {
+            return null;
+        }
+        JSONObject hisConfig = JSON.parseObject(configValue);
+        if (AI_URL_CONFIG_KEY.equals(configKey)) {
+            return hisConfig.getString(AI_URL_FIELD);
+        }
+        if (AI_APP_KEY_CONFIG_KEY.equals(configKey)) {
+            return hisConfig.getString(AI_APP_KEY_FIELD);
+        }
+        return null;
+    }
+
+
+
+    private void calculatePulse(Long userId, String date, StringBuilder pulseStr, String dateToStr) {
+        FsHealthPulseListUParam param = new FsHealthPulseListUParam();
+        param.setUserId(userId);
+        param.setCreateDay(date);
+
+        List<FsHealthPulseListVO> fsHealthPulseListVOS = fsHealthPulseMapper.selectFsHealthPulseListVO(param);
+        if (fsHealthPulseListVOS != null && !fsHealthPulseListVOS.isEmpty()) {
+            FsHealthPulseListVO vo = fsHealthPulseListVOS.get(0);
+
+            String leftJson = vo.getLeftHandResult();
+            String rightJson = vo.getRightHandResult();
+
+            String leftResult = "", leftSize = "", rightResult = "", rightSize = "";
+
+            try {
+                if (StringUtils.isNotEmpty(leftJson)) {
+                    JsonNode node = objectMapper.readTree(leftJson);
+                    leftResult = node.path("leftHandResult").asText("");
+                    leftSize = node.path("leftHandSize").asText("");
+                }
+
+                if (StringUtils.isNotEmpty(rightJson)) {
+                    JsonNode node = objectMapper.readTree(rightJson);
+                    rightResult = node.path("rightHandResult").asText("");
+                    rightSize = node.path("rightHandSize").asText("");
+                }
+            } catch (Exception e) {
+                log.error("解析脉象JSON失败: {}", e.getMessage());
+            }
+
+            pulseStr.append(dateToStr).append(" 左手 ").append(leftSize).append(" ").append("右手 ").append(rightSize).append(" ");
+        }
+    }
+
+
+    private void calculateSurface(Long userId, String date, StringBuilder surfaceStr, String dateToStr) {
+        FsHealthSurfaceListUParam param = new FsHealthSurfaceListUParam();
+        param.setUserId(userId);
+        param.setCreateDay(date);
+        List<FsHealthSurfaceListVO> fsHealthSurfaceListVOS = fsHealthSurfaceMapper.selectFsHealthSurfaceListVO(param);
+        if (fsHealthSurfaceListVOS != null && !fsHealthSurfaceListVOS.isEmpty()) {
+            FsHealthSurfaceListVO vo = fsHealthSurfaceListVOS.get(0);
+            surfaceStr.append(dateToStr).append(" ").append(vo.getComplexionResult()).append(" ").append(vo.getGlowResult()).append(" ").append(vo.getSwellingProblems()).append(" ");
+        }
+    }
+
+    /**
+     * 计算每天舌诊
+     *
+     * @param userId
+     * @param date
+     * @param tongueStr
+     * @param dateToStr
+     */
+    private void calculateTongue(Long userId, String date, StringBuilder tongueStr, String dateToStr) {
+        FsHealthTongueListUParam param = new FsHealthTongueListUParam();
+        param.setUserId(userId);
+        param.setCreateDay(date);
+        List<FsHealthTongueListUVO> vos = fsHealthTongueMapper.selectFsHealthTongueUListVO(param);
+        if (vos != null && !vos.isEmpty()) {
+            FsHealthTongueListUVO vo = vos.get(0);
+            tongueStr.append(dateToStr).append(" ").append(vo.getTypeName()).append(" ").append(vo.getShemianName()).append(" ").append(vo.getTaiseName()).append(" ");
+            try {
+                String chihenDesc = vo.getChihenDesc();
+                if (StringUtils.isNotBlank(chihenDesc)) {
+                    chihenDesc = chihenDesc.substring(1).split("表示")[0];
+                    tongueStr.append(chihenDesc).append(" ");
+                }
+                String liewenDesc = vo.getLiewenDesc();
+                if (StringUtils.isNotBlank(liewenDesc)) {
+                    liewenDesc = liewenDesc.substring(1).split("表示")[0];
+                    tongueStr.append(liewenDesc).append(" ");
+                }
+                String botaiDesc = vo.getBotaiDesc();
+                if (StringUtils.isNotBlank(botaiDesc)) {
+                    botaiDesc = botaiDesc.substring(1).split("表示")[0];
+                    tongueStr.append(botaiDesc).append(" ");
+                }
+                String taiseDesc = vo.getTaiseDesc();
+                if (StringUtils.isNotBlank(taiseDesc)) {
+                    tongueStr.append(taiseDesc).append(" ");
+                }
+            } catch (Exception e) {
+                log.error("舌苔详细解析错误{}错误信息:{}", vo, e.getMessage());
+            }
+
+        }
+    }
+
+    /**
+     * 计算每天睡眠
+     *
+     * @param deviceId
+     * @param date
+     * @param sleepStr
+     * @param dateToStr
+     */
+    private void calculateSleep(String deviceId, String date, StringBuilder sleepStr, String dateToStr,Integer deviceType) {
+        if (deviceType == null || deviceType == 0) {
+            WatchSleepDataVo vo = watchSleepDataService.getSleepSection(date, deviceId);
+            if (vo != null) {
+                if (StringUtils.isNotBlank(vo.getStartTime())) {
+                    sleepStr.append(dateToStr).append(" ").append(vo.getStartTime()).append("入睡,");
+                } else {
+                    return;
+                }
+                if (StringUtils.isNotBlank(vo.getEndTime())) {
+                    sleepStr.append(vo.getEndTime()).append("醒来,");
+                }
+                if (vo.getSleepTime() != null) {
+                    sleepStr.append("深睡 ").append(vo.getSleepTime()).append(" 分钟,");
+                }
+                if (vo.getLightSleep() != null) {
+                    sleepStr.append("浅睡 ").append(vo.getLightSleep()).append(" 分钟,");
+                }
+                if (vo.getEyemoveSleep() != null) {
+                    sleepStr.append("快速眼动 ").append(vo.getEyemoveSleep()).append(" 分钟,");
+                }
+                if (vo.getWeakSleep() != null) {
+                    sleepStr.append("清醒 ").append(vo.getWeakSleep()).append(" 分钟,");
+                }
+            }
+        } else {
+            Date dateTemp = DateUtils.dateTime("yyyy-MM-dd", date);
+            Date dayStartTime = DateUtils.truncate(dateTemp, Calendar.DATE);
+            Date dayEndTime =  DateUtils.addMilliseconds(
+                    DateUtils.addDays(DateUtils.truncate(dateTemp, Calendar.DATE), 1),
+                    -1
+            );
+            List<FsThirdDeviceData> list = fsThirdDeviceDataMapper.selectListByDateAndDeviceIdAndRecordType(dayStartTime, dayEndTime, deviceId, 7, null);
+            if (list != null && !list.isEmpty()) {
+                SleepStatistics sleepStatistics = SleepScoreCalculator.calculateDetailedStatistics(list);
+                sleepStr.append(dateToStr).append(" ").append(list.get(0).getCreateTime()).append("入睡,");
+                if (list.size() > 1) {
+                    sleepStr.append(list.get(list.size()-1).getCreateTime()).append("醒来,");
+                }
+                sleepStr.append("深睡 ").append(sleepStatistics.getDeepSleepHours()*60).append(" 分钟,");
+                sleepStr.append("浅睡 ").append(sleepStatistics.getLightSleepHours()*60).append(" 分钟,");
+                sleepStr.append("清醒 ").append(sleepStatistics.getAwakeHours()*60).append(" 分钟,");
+            }
+
+        }
+    }
+
+
+    /**
+     * 计算每天血氧
+     *
+     * @param deviceId
+     * @param currentStartDate
+     * @param currentEndDate
+     * @param spo2Str
+     * @param dateToStr
+     */
+    private void calculateSpo2(String deviceId, String currentStartDate, String currentEndDate, StringBuilder spo2Str,
+                               String dateToStr,Integer deviceType) {
+        Float value = null;
+        if (deviceType == null || deviceType == 1) {
+            value = watchSpo2DataMapper.countAvgBpByDate(currentStartDate, currentEndDate, deviceId);
+
+        } else {
+            value = fsThirdDeviceDataMapper.countAvgBpByDate(currentStartDate, currentEndDate, deviceId);
+        }
+        if (value != null) {
+            spo2Str.append(dateToStr).append(" ").append(value).append("% ");
+        }
+    }
+
+    /**
+     * 计算每天心率
+     *
+     * @param deviceId
+     * @param currentStartDate
+     * @param currentEndDate
+     * @param hrStr
+     * @param dateToStr
+     */
+    private void calculateHr(String deviceId, String currentStartDate, String currentEndDate, StringBuilder hrStr,
+                             String dateToStr,Integer deviceType) {
+        Map<String, Integer> map = null;
+        if (deviceType == null || deviceType == 0) {
+            map = watchHeartRateDataMapper.countMaxAndAvgBpByDate(currentStartDate, currentEndDate, deviceId);
+        } else {
+            map = fsThirdDeviceDataMapper.countMaxAndAvgBpByDate(currentStartDate, currentEndDate, deviceId);
+        }
+        if (map != null && map.get("avgBpm") != null && map.get("maxBpm") != null) {
+            hrStr.append(dateToStr).append(" 平均").append(map.get("avgBpm")).append(" 最高 ").append(map.get("maxBpm")).append(" ");
+        }
+    }
+
+    /**
+     * 计算每天血糖
+     *
+     * @param deviceId
+     * @param currentStartDate
+     * @param currentEndDate
+     * @param bgStr
+     */
+    private void calculateBg(String deviceId, String currentStartDate, String currentEndDate, StringBuilder bgStr,
+                             String dateToStr,Integer deviceType) {
+        if (deviceType == null || deviceType == 0) {
+            List<WatchBloodGlucoseData> bgData = watchBloodGlucoseDataMapper.queryBgByDate(currentStartDate, currentEndDate, deviceId, null);
+
+            if (bgData != null && !bgData.isEmpty()) {
+                WatchBloodGlucoseData watchBloodGlucoseData = bgData.get(bgData.size() - 1);
+                bgStr.append(dateToStr).append(" ").append(watchBloodGlucoseData.getBloodGlucose()).append("mmol/L ");
+            }
+        } else {
+            List<FsThirdDeviceData> bgData = fsThirdDeviceDataMapper.queryBgByDate(currentStartDate, currentEndDate, deviceId);
+
+            if (bgData != null && !bgData.isEmpty()) {
+                FsThirdDeviceData fsThirdDeviceData = bgData.get(bgData.size() - 1);
+                bgStr.append(dateToStr).append(" ").append(fsThirdDeviceData.getRecordValue()).append("mmol/L ");
+            }
+        }
+
+    }
+
+    /**
+     * 计算每天血压
+     *
+     * @param deviceId
+     * @param currentStartDate
+     * @param currentEndDate
+     * @param bpStr
+     */
+    private void calculateBp(String deviceId, String currentStartDate, String currentEndDate, StringBuilder bpStr
+            , String dateToStr,Integer deviceType) {
+        Map<String, Integer> map = new HashMap<>();
+        if(deviceType == null || deviceType == 0){
+            //原腕表
+            map = watchBloodPressureDataMapper.countMaxAndMinBpByDate(currentStartDate, currentEndDate, deviceId);
+        } else {
+            //小护士
+            map = fsThirdDeviceDataMapper.countMaxAndMinBpByDate(currentStartDate, currentEndDate, deviceId);
+        }
+        if (map != null && map.get("max") != null && map.get("min") != null) {
+            bpStr.append(dateToStr).append(" 高压 ").append(map.get("max")).append(" 低压 ").append(map.get("min")).append(" ");
+        }
+
+
+    }
+
+    /**
+     * 计算每天步数总和
+     *
+     * @param deviceId
+     * @param currentStartDate
+     * @param currentEndDate
+     * @param spotStr
+     */
+    private void calculateStep(String deviceId, String currentStartDate, String currentEndDate, StringBuilder spotStr,
+                               String dateToStr,Integer deviceType) {
+        long dailyStep = 0;
+        if (deviceType == null || deviceType == 0) {
+            List<WatchSportData> list = sportDataMapper.getByType(currentStartDate, currentEndDate, deviceId, null);
+            if (list != null && !list.isEmpty()) {
+                for (WatchSportData data : list) {
+                    dailyStep += data.getStep() == null ? 0 : data.getStep();
+                }
+            }
+
+        } else {
+            //小护士设备
+            WatchSportRecordVo otherData1 = fsThirdDeviceDataMapper.getOtherData(DateUtils.dateTime("yyyy-MM-dd HH:mm:ss", currentStartDate),
+                    DateUtils.dateTime("yyyy-MM-dd HH:mm:ss", currentEndDate), deviceId, 5, null);
+            WatchSportRecordVo otherData2 = fsThirdDeviceDataMapper.getOtherData(DateUtils.dateTime("yyyy-MM-dd HH:mm:ss", currentStartDate),
+                    DateUtils.dateTime("yyyy-MM-dd HH:mm:ss", currentEndDate), deviceId, 6, null);
+            if (otherData1 != null){
+                dailyStep = dailyStep + (otherData1.getStep() == null?0:otherData1.getStep());
+            }
+            if (otherData2 != null){
+                dailyStep = dailyStep + (otherData2.getStep() == null?0:otherData2.getStep());
+            }
+        }
+        if (dailyStep > 0) {
+            spotStr.append(dateToStr).append(" ").append(dailyStep).append("步 ");
+        }
+    }
+
+    /**
+     * 将日历设置为当天的开始时间(00:00:00)
+     */
+    private void setToStartOfDay(Calendar calendar) {
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+    }
 
 
     public <T extends Enum<T> & HealthStatusEnum> void getHealth(
             List<Map<String, Object>> data,
             List<AppHealthReportVo> vos,
             Class<T> enumClass,
-            AtomicInteger  score
+            AtomicInteger score
     ) {
         if (data == null) {
             return;
@@ -281,7 +923,7 @@ public class WatchBasicInfoServiceImpl implements WatchBasicInfoService {
             Integer status = Integer.valueOf(map.get("status").toString());
             Integer count = Integer.valueOf(map.get("count").toString());
             if (count > 0) {
-                AppHealthReportVo vo = createHealthReportVo(status, count, enumClass,score);
+                AppHealthReportVo vo = createHealthReportVo(status, count, enumClass, score);
                 if (vo != null) {
                     vos.add(vo);
                 }
@@ -293,7 +935,7 @@ public class WatchBasicInfoServiceImpl implements WatchBasicInfoService {
             Integer status,
             Integer count,
             Class<T> enumClass,
-            AtomicInteger  score
+            AtomicInteger score
     ) {
         if (status == null || enumClass == null) return null;
 
@@ -310,7 +952,7 @@ public class WatchBasicInfoServiceImpl implements WatchBasicInfoService {
         vo.setSuggestion(matchedEnum.getSuggestion());
         vo.setPrecautions(matchedEnum.getPrecautions());
         //扣得分 出现一次异常减5分,无数据不扣分
-        score.addAndGet(-(5*count)); // 异常就减分
+        score.addAndGet(-(5 * count)); // 异常就减分
         return vo;
     }
 

+ 107 - 24
fs-service/src/main/java/com/fs/watch/service/impl/WatchBloodGlucoseDataServiceImpl.java

@@ -2,6 +2,8 @@ package com.fs.watch.service.impl;
 
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
+import com.fs.his.domain.FsThirdDeviceData;
+import com.fs.his.mapper.FsThirdDeviceDataMapper;
 import com.fs.watch.domain.WatchBloodGlucoseData;
 import com.fs.watch.domain.WatchDeviceInfo;
 import com.fs.watch.enums.WatchBgStatusEnum;
@@ -30,15 +32,12 @@ public class WatchBloodGlucoseDataServiceImpl implements WatchBloodGlucoseDataSe
     private WatchThirdBpDataService watchThirdBpDataService;
     @Autowired
     private WatchDeviceInfoMapper watchDeviceInfoMapper;
+    @Autowired
+    private FsThirdDeviceDataMapper fsThirdDeviceDataMapper;
 
 
     @Override
     public Boolean insert(WatchBloodGlucoseData watchBloodGlucoseData) {
-        //判断创建时间是否唯一
-        Integer num = mapper.queryByCreateTime(watchBloodGlucoseData.getCreateTime());
-        if (num != null && num > 0) {
-            return false;
-        }
         try {
             mapper.insert(watchBloodGlucoseData);
         } catch (Exception e) {
@@ -80,27 +79,56 @@ public class WatchBloodGlucoseDataServiceImpl implements WatchBloodGlucoseDataSe
     }
 
     @Override
-    public List<WatchBloodGlucoseData> queryBgByDate(Date startTime, Date endTime, String deviceId, Integer status) {
+    public List<WatchBloodGlucoseData> queryBgByDate(Date startTime, Date endTime, String deviceId, Integer status,Integer deviceType) {
         if (StringUtils.isNotBlank(deviceId)) {
-            List<WatchBloodGlucoseData> data = mapper.queryBgByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
-                    DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),
-                    deviceId,
-                    status);
-            return data;
+            if (deviceType == null || deviceType == 0) {
+                return mapper.queryBgByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
+                        DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),
+                        deviceId,
+                        status);
+            } else {
+                List<FsThirdDeviceData> list = fsThirdDeviceDataMapper.selectListByDateAndDeviceIdAndRecordType(startTime, endTime, deviceId, 1, status);
+                if (list != null && !list.isEmpty()) {
+                    List<WatchBloodGlucoseData> voList= new ArrayList<>();
+                    list.forEach(fsThirdDeviceData -> {
+                        WatchBloodGlucoseData data = new WatchBloodGlucoseData();
+                        data.setDeviceId(fsThirdDeviceData.getDeviceId());
+                        String recordValue = fsThirdDeviceData.getRecordValue();
+                        if (recordValue != null) {
+                            // 移除所有双引号
+                            recordValue = recordValue.replace("\"", "");
+                            // 或者只移除首尾的引号和可能的空格
+                            recordValue = recordValue.replaceAll("^[\"']+|[\"']+$", "");
+                        }
+                        data.setBloodGlucose(Float.valueOf(recordValue));
+                        data.setCreateTime(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss",fsThirdDeviceData.getCreateTime()));
+                        data.setStatus(fsThirdDeviceData.getStatus());
+                        voList.add(data);
+                    });
+                    return voList;
+                }
+            }
+
         }
         return null;
     }
 
 
     @Override
-    public List<Map<String, Object>> countBgByDate(Date startTime, Date endTime, String deviceId) {
+    public List<Map<String, Object>> countBgByDate(Date startTime, Date endTime, String deviceId,Integer deviceType) {
         if (StringUtils.isBlank(deviceId)) {
             return null;
         }
         //返回对象
         List<Map<String, Object>> res = null;
-        res = mapper.countBpByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
-                DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime), deviceId);
+        if (deviceType == null || deviceType == 0) {
+            res = mapper.countBpByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
+                    DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime), deviceId);
+        } else {
+            res = fsThirdDeviceDataMapper.countByDateAndDeviceIdAndRecordType(startTime, endTime, deviceId, 1,null);
+        }
+
+
 
         return res;
     }
@@ -111,20 +139,75 @@ public class WatchBloodGlucoseDataServiceImpl implements WatchBloodGlucoseDataSe
     }
 
     @Override
-    public int countBgPageByDate(Date startTime, Date endTime, String deviceId, Integer status) {
-        return mapper.countBgPageByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
-                DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),
-                deviceId, status);
+    public int countBgPageByDate(Date startTime, Date endTime, String deviceId, Integer status,Integer deviceType) {
+        if (deviceType == null || deviceType == 0) {
+            return mapper.countBgPageByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
+                    DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),
+                    deviceId, status);
+        } else {
+            return fsThirdDeviceDataMapper.countPageByDateAndDeviceIdAndRecordType(startTime,endTime,deviceId,1,status);
+        }
+
     }
 
     @Override
-    public List<WatchBloodGlucoseData> queryBgPageByDate(Date startTime, Date endTime, String deviceId, Integer status, Integer num, Integer size) {
-        if (StringUtils.isNotBlank(deviceId)) {
-            return mapper.queryBgPageByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
-                    DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),
-                    deviceId, status, num, size);
+    public List<WatchBloodGlucoseData> queryBgPageByDate(Date startTime, Date endTime, String deviceId, Integer status, Integer num, Integer size,Integer deviceType) {
+        if (deviceType == null || deviceType == 0) {
+            if (StringUtils.isNotBlank(deviceId)) {
+                return mapper.queryBgPageByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
+                        DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),
+                        deviceId, status, num, size);
+            } else {
+                return null;
+            }
         } else {
-            return null;
+            List<WatchBloodGlucoseData> voList= new ArrayList<>();
+            List<FsThirdDeviceData> list = fsThirdDeviceDataMapper.queryPageByDateAndDeviceIdAndRecordType(startTime, endTime, deviceId, 1,status, num, size);
+            if (list != null && !list.isEmpty()) {
+                list.forEach(fsThirdDeviceData -> {
+                    WatchBloodGlucoseData data = new WatchBloodGlucoseData();
+                    data.setDeviceId(fsThirdDeviceData.getDeviceId());
+                    String recordValue = fsThirdDeviceData.getRecordValue();
+                    if (recordValue != null) {
+                        // 移除所有双引号
+                        recordValue = recordValue.replace("\"", "");
+                        // 或者只移除首尾的引号和可能的空格
+                        recordValue = recordValue.replaceAll("^[\"']+|[\"']+$", "");
+                    }
+                    data.setBloodGlucose(Float.valueOf(recordValue));
+                    data.setCreateTime(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss",fsThirdDeviceData.getCreateTime()));
+                    data.setStatus(fsThirdDeviceData.getStatus());
+                    voList.add(data);
+                });
+
+            }
+            return voList;
         }
+
     }
+
+    /**
+     * 高风险:血糖值大于等于 7.0 mmol/L,返回 1。
+     * 一般:血糖值在 6.0 mmol/L 和 7.0 mmol/L 之间,返回 3。
+     * 良好:血糖值在 5.0 mmol/L 和 6.0 mmol/L 之间,返回 4。
+     * 正常:血糖值在 3.9 mmol/L和 4.0 mmol/L 之间,,返回 5。
+     * 不良:血糖值小于 3.9 mmol/L 之间,返回 2。
+     * 获得血糖状态
+     *
+     * @param num
+     * @return 状态码
+     */
+    @Override
+    public Integer getStatus(Double num) {
+        if (num >= 7.0) {
+            return WatchBgStatusEnum.HYPERGLYCEMIA.getValue(); // 高风险(糖尿病)
+        } else if (num >= 6.1) {
+            return WatchBgStatusEnum.HIGHER.getValue(); // 一般(糖尿病前期)
+        } else if (num >= 3.9) {
+            return WatchBgStatusEnum.NORMAL.getValue(); // 良好正常
+        } else {
+            return WatchBgStatusEnum.HYPOGLYCEMIA.getValue(); //不良 (低血糖)
+        }
+    }
+
 }

+ 38 - 6
fs-service/src/main/java/com/fs/watch/service/impl/WatchBloodPressureDataServiceImpl.java

@@ -35,11 +35,6 @@ public class WatchBloodPressureDataServiceImpl implements WatchBloodPressureData
 
     @Override
     public Boolean insert(WatchBloodPressureData watchBloodPressureData) {
-        //判断创建时间是否唯一
-        Integer num = mapper.queryByCreateTime(watchBloodPressureData.getCreateTime());
-        if (num != null && num > 0) {
-            return false;
-        }
         try {
             mapper.insert(watchBloodPressureData);
         } catch (Exception e) {
@@ -94,7 +89,7 @@ public class WatchBloodPressureDataServiceImpl implements WatchBloodPressureData
                     DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
                     DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),
                     deviceId,
-                    status);
+                    status,0);
             if (!watchThirdBpDatas.isEmpty()){
                 return watchThirdBpDatas;
             } else {
@@ -162,4 +157,41 @@ public class WatchBloodPressureDataServiceImpl implements WatchBloodPressureData
             return null;
         }
     }
+
+    /**
+     * 重度: 收缩压 > 180 mmHg 或 舒张压 > 110 mmHg 1
+     * 中度: 收缩压在 160-179 mmHg 之间 或 舒张压在 100-109 mmHg 之间 2
+     * 轻度: 收缩压在 140-159 mmHg 之间 或 舒张压在 90-99 mmHg 之间 3
+     * 正常高值: 收缩压在 130-139 mmHg 之间 或 舒张压在 85-89 mmHg 之间 4
+     * 偏低: 收缩压 < 90 mmHg 或 舒张压 < 60 mmHg 5
+     * 正常: 收缩压在 90-139 mmHg 之间 且 舒张压在 60-89 mmHg 之间 6
+     * @param sbp
+     * @param dbp
+     * @return
+     */
+    @Override
+    public Integer getStatus(int sbp, int dbp) {
+        int status;
+//        if (sbp > 180 || dbp > 110) {
+//            status = 1; // 重度
+//        } else if (sbp >= 160 || dbp >= 100) {
+//            status = 2; // 中度
+//        } else if (sbp >= 140 || dbp >= 90) {
+//            status = 3; // 轻度
+//        } else if (sbp >= 130 || dbp >= 85) {
+//            status = 4; // 正常高值
+//        } else if (sbp < 90 || dbp < 60) {
+//            status = 5; // 偏低
+//        } else {
+//            status = 6; // 正常
+//        }
+        if (sbp >= 140 || dbp >=90 ) {
+            status = WatchBpStatusEnum.HYPERTENSION.getValue(); // 重度(高血压)
+        } else if (sbp >= 90 || dbp >= 60) {
+            status = WatchBpStatusEnum.NORMAL.getValue(); // 正常范围
+        } else {
+            status = WatchBpStatusEnum.HYPOTENSION.getValue(); // 低血压
+        }
+        return status;
+    }
 }

+ 314 - 116
fs-service/src/main/java/com/fs/watch/service/impl/WatchDataServiceImpl.java

@@ -6,11 +6,15 @@ import com.alibaba.fastjson.JSONObject;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.his.domain.FsHealthTongue;
+import com.fs.his.domain.FsThirdDeviceData;
+import com.fs.his.mapper.FsThirdDeviceDataMapper;
 import com.fs.his.utils.PhoneUtil;
+import com.fs.watch.calculation.SleepScoreCalculator;
 import com.fs.watch.domain.*;
 import com.fs.watch.domain.vo.*;
 import com.fs.watch.enums.*;
 import com.fs.watch.mapper.*;
+import com.fs.watch.param.WatchUserByDeviceIdParam;
 import com.fs.watch.service.*;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -71,9 +75,11 @@ public class WatchDataServiceImpl implements WatchDataService {
     private WatchSpo2DataService watchSpo2DataService;
     @Autowired
     private WatchFatigueDataService watchFatigueDataService;
+    @Autowired
+    private FsThirdDeviceDataMapper fsThirdDeviceDataMapper;
 
     @Override
-    public List<FsMonitorDataVo> queryIndexWatchData(List<String> types, String deviceId,String userId) {
+    public List<FsMonitorDataVo> queryIndexWatchData(List<String> types, String deviceId,String userId,Integer deviceType) {
         //返回对象
         List<FsMonitorDataVo> vos = new ArrayList<>();
         for (String typeStr : types) {
@@ -88,43 +94,90 @@ public class WatchDataServiceImpl implements WatchDataService {
             int type = Integer.parseInt(typeStr);
             switch (type) {
                 case 1:  //血糖
-                    WatchBloodGlucoseData bgData = watchBloodGlucoseDataService.getLatest(deviceId);
-                    if (bgData != null) {
+                    if (deviceId == null || deviceType == 0) {
+                        WatchBloodGlucoseData bgData = watchBloodGlucoseDataService.getLatest(deviceId);
+                        if (bgData != null) {
 //                        vo.setDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,bgData.getCreateTime()));
-                        vo.setDate(bgData.getCreateTime());
-                        vo.setData(bgData.getBloodGlucose().toString());
+                            vo.setDate(bgData.getCreateTime());
+                            vo.setData(bgData.getBloodGlucose().toString());
+                        } else {
+                            vo.setData("");
+                        }
                     } else {
-                        vo.setData("");
+                        FsThirdDeviceData data = fsThirdDeviceDataMapper.getLatest(deviceId,1);
+                        if (data != null) {
+//                        vo.setDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,bgData.getCreateTime()));
+                            vo.setDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,data.getCreateTime()));
+                            vo.setData(data.getRecordValue());
+                        } else {
+                            vo.setData("");
+                        }
                     }
+
+
                     vos.add(vo);
                     break;
                 case 2:  //血压
-                    WatchThirdBpData bpData = watchBloodPressureDataService.getLatest(deviceId);
-                    if (bpData != null) {
+                    if (deviceId == null || deviceType == 0) {
+                        WatchThirdBpData bpData = watchBloodPressureDataService.getLatest(deviceId);
+                        if (bpData != null) {
 //                        vo.setDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,bpData.getCreateTime()));
-                        vo.setDate(bpData.getCreateTime());
-                        vo.setData(bpData.getDbp() + "/" + bpData.getSbp().toString());
+                            vo.setDate(bpData.getCreateTime());
+                            vo.setData(bpData.getDbp() + "/" + bpData.getSbp().toString());
+                        } else {
+                            vo.setData("");
+                        }
                     } else {
-                        vo.setData("");
+                        FsThirdDeviceData data = fsThirdDeviceDataMapper.getLatest(deviceId,0);
+                        if (data != null) {
+//                        vo.setDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,bgData.getCreateTime()));
+                            vo.setDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,data.getCreateTime()));
+                            String recordValue = data.getRecordValue();
+                            if (StringUtils.isNotBlank(recordValue)) {
+                                JSONObject jsonObject = JSONObject.parseObject(recordValue);
+                                String sdb = jsonObject.get("sdb").toString();
+                                String dbp = jsonObject.get("dbp").toString();
+                                vo.setData(dbp + "/" + sdb );
+                            } else {
+                                vo.setData("");
+                            }
+                        } else {
+                            vo.setData("");
+                        }
                     }
+
                     vos.add(vo);
                     break;
                 case 3:  //心率
-                    WatchHeartRateData hrData = watchHeartRateDataService.getLatest(deviceId);
-                    if (hrData != null) {
+                    if (deviceId == null || deviceType == 0) {
+                        WatchHeartRateData hrData = watchHeartRateDataService.getLatest(deviceId);
+                        if (hrData != null) {
 //                        vo.setDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,hrData.getCreateTime()));
-                        vo.setDate(hrData.getCreateTime());
-                        vo.setData(hrData.getAvgBpm().toString());
+                            vo.setDate(hrData.getCreateTime());
+                            vo.setData(hrData.getAvgBpm().toString());
+                        } else {
+                            vo.setData("");
+                        }
                     } else {
-                        vo.setData("");
+                        FsThirdDeviceData data = fsThirdDeviceDataMapper.getLatest(deviceId,2);
+                        if (data != null) {
+//                        vo.setDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,bgData.getCreateTime()));
+                            vo.setDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,data.getCreateTime()));
+                            vo.setData(data.getRecordValue());
+                        } else {
+                            vo.setData("");
+                        }
                     }
+
+
                     vos.add(vo);
                     break;
                 case 4:  //血氧
-                    WatchSpo2DataVo spo2DataVo = watchSpo2DataService.getLatest(deviceId);
-                    if (spo2DataVo != null) {
-                        vo.setDate(spo2DataVo.getCreateTime());
-                        vo.setData(spo2DataVo.getAvgBoxy().toString());
+                    if (deviceId == null || deviceType == 0) {
+                        WatchSpo2DataVo spo2DataVo = watchSpo2DataService.getLatest(deviceId);
+                        if (spo2DataVo != null) {
+                            vo.setDate(spo2DataVo.getCreateTime());
+                            vo.setData(spo2DataVo.getAvgBoxy().toString());
 
 //                    WatchContinuousSpo2Data continuousSpo2Data = watchContinuousSpo2DataService.getLastByDeviceId(deviceId);
 //                    if (continuousSpo2Data != null) {
@@ -150,75 +203,159 @@ public class WatchDataServiceImpl implements WatchDataService {
 //                        } else {
 //                            vo.setData("");
 //                        }
+                        } else {
+                            vo.setData("");
+                        }
                     } else {
-                        vo.setData("");
+                        FsThirdDeviceData data = fsThirdDeviceDataMapper.getLatest(deviceId,4);
+                        if (data != null) {
+//                        vo.setDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,bgData.getCreateTime()));
+                            vo.setDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,data.getCreateTime()));
+                            vo.setData(data.getRecordValue());
+                        } else {
+                            vo.setData("");
+                        }
                     }
+
+
                     vos.add(vo);
                     break;
                 case 5:  //体温
-                    WatchTemperatureData temperatureData = watchTemperatureDataService.getLatest(deviceId);
-                    if (temperatureData != null) {
+                    if (deviceId == null || deviceType == 0) {
+                        WatchTemperatureData temperatureData = watchTemperatureDataService.getLatest(deviceId);
+                        if (temperatureData != null) {
 //                        vo.setDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,temperatureData.getCreateTime()));
-                        vo.setDate(temperatureData.getCreateTime());
-                        vo.setData(temperatureData.getEstTemp().toString());
+                            vo.setDate(temperatureData.getCreateTime());
+                            vo.setData(temperatureData.getEstTemp().toString());
+                        } else {
+                            vo.setData("");
+                        }
                     } else {
                         vo.setData("");
                     }
+
+
                     vos.add(vo);
                     break;
                 case 6:  //呼吸 todo
-                    vo.setDate(DateUtils.dateTimeNow());
-                    vo.setData(120 + "");
+                    if (deviceId == null || deviceType == 0) {
+                        vo.setDate(DateUtils.dateTimeNow());
+                        vo.setData(120 + "");
+                    } else {
+                        vo.setDate(DateUtils.dateTimeNow());
+                        vo.setData(120 + "");
+
+                    }
+
                     vos.add(vo);
                     break;
                 case 7:  //血脂 todo
-                    vo.setData("");
+                    if (deviceId == null || deviceType == 0) {
+                        vo.setData("");
+                    } else {
+                        vo.setData("");
+                    }
+
+
+
                     vos.add(vo);
                     break;
                 case 8:  //尿酸
-                    WatchThirdUaData uaData = watchThirdUaDataService.getLatest(deviceId);
-                    if (uaData != null) {
-                        vo.setDate(uaData.getCreateTime());
-                        vo.setData(WatchUaStatusEnum.toType(
-                                watchThirdUaDataService.getStatus(deviceId,uaData.getVal(),Long.parseLong(userId),0)
-                        ).getDesc());
+                    if (deviceId == null || deviceType == 0) {
+                        WatchThirdUaData uaData = watchThirdUaDataService.getLatest(deviceId);
+                        if (uaData != null) {
+                            vo.setDate(uaData.getCreateTime());
+                            vo.setData(WatchUaStatusEnum.toType(
+                                    watchThirdUaDataService.getStatus(deviceId,uaData.getVal(),Long.parseLong(userId),0)
+                            ).getDesc());
+                        } else {
+                            vo.setData("");
+                        }
                     } else {
-                        vo.setData("");
+                        FsThirdDeviceData data = fsThirdDeviceDataMapper.getLatest(deviceId,3);
+                        if (data != null) {
+//                        vo.setDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,bgData.getCreateTime()));
+                            vo.setDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,data.getCreateTime()));
+                            vo.setData(data.getRecordValue());
+                        } else {
+                            vo.setData("");
+                        }
                     }
+
+
+
+
                     vos.add(vo);
                     break;
                 case 9:  //血管硬化 todo
-                    vo.setData("");
+                    if (deviceId == null || deviceType == 0) {
+                        vo.setData("");
+                    } else {
+                        vo.setData("");
+                    }
+
+
+
+
                     vos.add(vo);
                     break;
                 case 10:  //血酮
-                    WatchThirdBkData bkData = watchThirdBkDataService.getLatest(deviceId);
-                    if (bkData != null) {
+                    if (deviceId == null || deviceType == 0) {
+                        WatchThirdBkData bkData = watchThirdBkDataService.getLatest(deviceId);
+                        if (bkData != null) {
 //                        vo.setDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,bkData.getCreateTime()));
-                        vo.setDate(bkData.getCreateTime());
+                            vo.setDate(bkData.getCreateTime());
 //                        list.add(bkData.getVal().toString());
-                        Integer status = bkData.getStatus();
-                        vo.setData(status == 0 ? "正常" : "异常");
+                            Integer status = bkData.getStatus();
+                            vo.setData(status == 0 ? "正常" : "异常");
+                        } else {
+                            vo.setData("");
+                        }
                     } else {
                         vo.setData("");
                     }
+
+
+
                     vos.add(vo);
                     break;
                 case 11:  //睡眠 todo 未确定返回数据
-                    //查询最新日期
-                    WatchSleepData data = watchSleepDataService.getLast(deviceId);
-                    if (data != null) {
-                        String date = data.getCreateTime().split(" ")[0];
-                        WatchSleepDataVo sleepSection = watchSleepDataService.getSleepSection(date, deviceId);
-                        if (sleepSection != null) {
-                            vo.setDate(date);
-                            Integer score = sleepSection.getScore();
-                            vo.setData(score==null?"":score.toString());
+                    if (deviceId == null || deviceType == 0) {
+                        //查询最新日期
+                        WatchSleepData data = watchSleepDataService.getLast(deviceId);
+                        if (data != null) {
+                            String date = data.getCreateTime().split(" ")[0];
+                            WatchSleepDataVo sleepSection = watchSleepDataService.getSleepSection(date, deviceId);
+                            if (sleepSection != null) {
+                                vo.setDate(date);
+                                Integer score = sleepSection.getScore();
+                                vo.setData(score==null?"":score.toString());
+                                vos.add(vo);
+                                break;
+                            }
+                        }
+                        vo.setData("");
+                    } else {
+                        FsThirdDeviceData data = fsThirdDeviceDataMapper.getLatest(deviceId, 7);
+                        if (data != null) {
+                            Date endTime = data.getCreateTime();
+                            vo.setDate(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", endTime));
+                            Date starTime = DateUtils.truncate(endTime, Calendar.DATE);
+                            List<FsThirdDeviceData> list = fsThirdDeviceDataMapper.selectListByDateAndDeviceIdAndRecordType(starTime, endTime, deviceId, 7, null);
+                            // 计算睡眠评分
+                            int score = 0;
+//                            SleepStatistics statistics = null;
+                            if (list != null && !list.isEmpty()) {
+                                // 计算详细统计信息
+//                                statistics = SleepScoreCalculator.calculateDetailedStatistics(list);
+                                score = SleepScoreCalculator.calculateSleepScore(list);
+                            }
+                            vo.setData(String.valueOf(score));
                             vos.add(vo);
                             break;
                         }
+                        vo.setData("");
                     }
-                    vo.setData("");
                     vos.add(vo);
                     break;
 //                case 12:  //房颤 todo 未确定返回数据
@@ -236,13 +373,19 @@ public class WatchDataServiceImpl implements WatchDataService {
                     vos.add(vo);
                     break;
                 case 13:  //压力
-                    WatchFatigueData fatigue = watchFatigueDataService.getLastByDeviceId(deviceId);
-                    if (fatigue != null){
-                        vo.setDate(fatigue.getCreateTime());
-                        vo.setData(WatchFatigueStatusEnum.toType(fatigue.getStatus()).getDesc());
+                    if (deviceId == null || deviceType == 0) {
+                        WatchFatigueData fatigue = watchFatigueDataService.getLastByDeviceId(deviceId);
+                        if (fatigue != null){
+                            vo.setDate(fatigue.getCreateTime());
+                            vo.setData(WatchFatigueStatusEnum.toType(fatigue.getStatus()).getDesc());
+                        } else {
+                            vo.setData("");
+                        }
                     } else {
                         vo.setData("");
                     }
+
+
                     vos.add(vo);
                     break;
                 default:
@@ -253,51 +396,64 @@ public class WatchDataServiceImpl implements WatchDataService {
     }
 
     @Override
-    public List<AppInfoVo> getUserByDeviceId(String deviceIds, Boolean isFamily,Long userId) {
-        List<String> list = Arrays.asList(deviceIds.split(","));
-        WatchFsUser user = null;
-        if (list != null && list.size() > 0) {
-            //设备绑定用户名
-            user = userService.selectWatchFsUserByDeviceIdAndUserId(list.get(0), userId,isFamily?1:0);
+    public List<AppInfoVo> getUserByDeviceId(WatchUserByDeviceIdParam watchUserByDeviceIdParam, Long userId) {
+        List<WatchUserByDeviceIdParam.WatchUserByDeviceIdTemp> params = watchUserByDeviceIdParam.getParams();
+        Boolean isFamily = watchUserByDeviceIdParam.getIsFamily();
+        List<AppInfoVo> vos = new ArrayList<>();
+        for (WatchUserByDeviceIdParam.WatchUserByDeviceIdTemp temp : params) {
+            WatchFsUser user = null;
+            String deviceId = temp.getDeviceId();
+            Integer deviceType = temp.getDeviceType();
+            if (deviceType == null || deviceType == 0) {
+                user = userService.selectWatchFsUserByDeviceIdAndUserId(deviceId, userId, isFamily ? 1 : 0);
+            } else if (deviceType == 1) {
+                user = userService.selectWatchFsUserByDeviceIdAndUserId(deviceId, userId, isFamily ? 3 : 2);
+            }else if (deviceType == 2){
+                user = userService.selectWatchFsUserByDeviceIdAndUserId(deviceId, userId, isFamily ? 5: 4);
+            }
             if (user != null) {
                 //处理电话
                 String phone = user.getPhone();
                 if (StringUtils.isNotBlank(phone)) {
                     if (phone.length() != 11 && !phone.startsWith("1")) {
-                        user.setPhone(PhoneUtil.decryptPhone(phone));
+                        user.setPhone(PhoneUtil.decryptPhoneMk(phone));
                     }
                 }
             }
 
             if (!isFamily && user == null) {
-                return null;
+                continue;
             }
-            List<AppInfoVo> vos = new ArrayList<>();
-            for (String deviceId : list) {
-                AppInfoVo appInfoVo = new AppInfoVo();
-                appInfoVo.setUser(user);
-                //设备型号
-                WatchDeviceData data = watchDeviceDataMapper.getByDeviceId(deviceId);
+
+            AppInfoVo appInfoVo = new AppInfoVo();
+            appInfoVo.setUser(user);
+            //设备型号
+            WatchDeviceData data = null;
+            Map<String, Object> statusData = null;
+            if (deviceType == null || deviceType == 0) {
+                data = watchDeviceDataMapper.getByDeviceId(deviceId);
                 if (data != null) {
                     appInfoVo.setBle(data.getBle());
                 } else {
                     appInfoVo.setBle("H102C");
                 }
                 //获取设备状态
-                Map<String, Object> statusData = deviceInfoService.getInfo(deviceId);
+                statusData = deviceInfoService.getInfo(deviceId);
                 if (statusData == null) {
                     appInfoVo.setStatus(3);
                 } else if (statusData.get("status") != null) {
                     appInfoVo.setStatus(Integer.parseInt(statusData.get("status").toString()));
                 }
-                vos.add(appInfoVo);
-
-
+            } else if (deviceType == 1) {
+                appInfoVo.setBle("小护士设备:" + deviceId);
+                appInfoVo.setStatus(3);
+            } else if (deviceType == 2) {
+                appInfoVo.setBle("小护士手表:" + deviceId);
+                appInfoVo.setStatus(3);
             }
-            return vos;
-        } else {
-            return null;
+            vos.add(appInfoVo);
         }
+        return vos;
 
     }
 
@@ -459,19 +615,28 @@ public class WatchDataServiceImpl implements WatchDataService {
     }
 
     @Override
-    public QueryPageMonthVo queryMonthByDeviceId(String deviceId, Integer pageSize, Integer pageNum) {
+    public QueryPageMonthVo queryMonthByDeviceId(String deviceId, Integer pageSize, Integer pageNum,Integer deviceType) {
         if (StringUtils.isBlank(deviceId)) {
             return null;
         }
-        //从watch_device_data有数据开始
-        WatchDeviceData lastByDeviceId = watchDeviceDataMapper.getByDeviceId(deviceId);
-        if (lastByDeviceId == null) {
-            return null;
+        Date createTime = null;
+        List<String> monthList = null;
+        if (deviceType == null || deviceType == 0) {
+            //从watch_device_data有数据开始
+            WatchDeviceData lastByDeviceId = watchDeviceDataMapper.getByDeviceId(deviceId);
+            if (lastByDeviceId == null) {
+                return null;
+            }
+            // 获取设备创建时间
+            createTime = DateUtils.dateTime("yyyy-MM-dd HH:mm:ss",lastByDeviceId.getCreateTime());
+        } else {
+            FsThirdDeviceData firstDataByDeviceId = fsThirdDeviceDataMapper.getFirstDataByDeviceId(deviceId);
+            if (firstDataByDeviceId == null) {
+                return null;
+            }
+            createTime = firstDataByDeviceId.getCreateTime();
         }
 
-        List<String> monthList = null;
-        // 获取设备创建时间
-        Date createTime = DateUtils.dateTime("yyyy-MM-dd HH:mm:ss",lastByDeviceId.getCreateTime());
 
         // 获取当前时间
         Calendar current = Calendar.getInstance();
@@ -491,7 +656,7 @@ public class WatchDataServiceImpl implements WatchDataService {
 
             //有数据才添加
             //
-            Boolean flag = isHavingData(deviceId, monthStr);
+            Boolean flag = isHavingData(deviceId, monthStr,deviceType);
             if (flag){
                 // 获取当前日期并格式化为yyyy-MM,并存入列表
                 monthList.add(dateFormat.format(calendar.getTime()));
@@ -510,36 +675,69 @@ public class WatchDataServiceImpl implements WatchDataService {
         return vo;
     }
 
-    private  Boolean isHavingData(String deviceId, String monthStr) {
+    private  Boolean isHavingData(String deviceId, String monthStr,Integer deviceType) {
         boolean flag = false;
-        List<WatchThirdBpData> bpList = watchThirdBpDataMapper.queryByMonth(deviceId, monthStr);
-        if (bpList != null && !bpList.isEmpty()) {
-            flag = true;
-            return flag;
-        }
-        //血氧
-        List<WatchContinuousSpo2Data> spo2DataList = watchContinuousSpo2DataMapper.queryByMonth(deviceId, monthStr);
-        if (spo2DataList != null && !spo2DataList.isEmpty()) {
-            flag = true;
-            return flag;
-        }
-        //心率
-        List<WatchHeartRateData> hrList = watchHeartRateDataMapper.queryByMonth(deviceId, monthStr);
-        if (hrList != null && !hrList.isEmpty()) {
-            flag = true;
-            return flag;
-        }
-        //睡眠
-        List<WatchSleepData> sleepList = watchSleepDataMapper.queryByMonth(deviceId, monthStr);
-        if (sleepList != null && !sleepList.isEmpty()) {
-            flag = true;
-            return flag;
-        }
-        //血糖
-        List<WatchBloodGlucoseData> bgList = watchBloodGlucoseDataMapper.queryByMonth(deviceId, monthStr);
-        if (bgList != null && !bgList.isEmpty()) {
-            flag = true;
-            return flag;
+        if (deviceType == null ||  deviceType == 0) {
+            List<WatchThirdBpData> bpList = watchThirdBpDataMapper.queryByMonth(deviceId, monthStr);
+            if (bpList != null && !bpList.isEmpty()) {
+                flag = true;
+                return flag;
+            }
+            //血氧
+            List<WatchContinuousSpo2Data> spo2DataList = watchContinuousSpo2DataMapper.queryByMonth(deviceId, monthStr);
+            if (spo2DataList != null && !spo2DataList.isEmpty()) {
+                flag = true;
+                return flag;
+            }
+            //心率
+            List<WatchHeartRateData> hrList = watchHeartRateDataMapper.queryByMonth(deviceId, monthStr);
+            if (hrList != null && !hrList.isEmpty()) {
+                flag = true;
+                return flag;
+            }
+            //睡眠
+            List<WatchSleepData> sleepList = watchSleepDataMapper.queryByMonth(deviceId, monthStr);
+            if (sleepList != null && !sleepList.isEmpty()) {
+                flag = true;
+                return flag;
+            }
+            //血糖
+            List<WatchBloodGlucoseData> bgList = watchBloodGlucoseDataMapper.queryByMonth(deviceId, monthStr);
+            if (bgList != null && !bgList.isEmpty()) {
+                flag = true;
+                return flag;
+            }
+
+        } else {
+            List<FsThirdDeviceData> bpList = fsThirdDeviceDataMapper.queryByMonth(deviceId, monthStr,0);
+            if (bpList != null && !bpList.isEmpty()) {
+                flag = true;
+                return flag;
+            }
+            //血氧
+//            List<WatchContinuousSpo2Data> spo2DataList = fsThirdDeviceDataMapper.querySpo2ByMonth(deviceId, monthStr);
+//            if (spo2DataList != null && !spo2DataList.isEmpty()) {
+//                flag = true;
+//                return flag;
+//            }
+            //心率
+            List<FsThirdDeviceData> hrList = fsThirdDeviceDataMapper.queryByMonth(deviceId, monthStr,2);
+            if (hrList != null && !hrList.isEmpty()) {
+                flag = true;
+                return flag;
+            }
+            //睡眠
+//            List<WatchSleepData> sleepList = fsThirdDeviceDataMapper.querySleepByMonth(deviceId, monthStr);
+//            if (sleepList != null && !sleepList.isEmpty()) {
+//                flag = true;
+//                return flag;
+//            }
+            //血糖
+            List<FsThirdDeviceData> bgList = fsThirdDeviceDataMapper.queryByMonth(deviceId, monthStr,1);
+            if (bgList != null && !bgList.isEmpty()) {
+                flag = true;
+                return flag;
+            }
         }
         return flag;
     }
@@ -668,8 +866,8 @@ public class WatchDataServiceImpl implements WatchDataService {
             Integer status = uaData.getStatus();
             vo6.setData(uaData.getVal().toString());
             vo6.setStatus(WatchUaStatusEnum.toType(
-                    watchThirdUaDataService.getStatus(deviceId,uaData.getVal(),0L,0)
-            ).getDesc());
+                    watchThirdUaDataService.getStatus(deviceId,uaData.getVal()*10,0L,0)
+            ).getDesc()); //需根据性别判断新的 getLatest的结果是/10 所以此处应该*10
         } else {
             vo6.setDate("");
             vo6.setData("");

+ 0 - 79
fs-service/src/main/java/com/fs/watch/service/impl/WatchDeviceBeginnerGuideServiceImpl.java

@@ -1,79 +0,0 @@
-package com.fs.watch.service.impl;
-
-import com.alibaba.fastjson.JSONObject;
-import com.fs.common.config.WatchConfig;
-import com.fs.watch.domain.WatchDeviceBeginnerGuide;
-import com.fs.watch.service.WatchDeviceBeginnerGuideService;
-import com.fs.watch.utils.MyHttpUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import java.util.*;
-
-@Service
-public class WatchDeviceBeginnerGuideServiceImpl implements WatchDeviceBeginnerGuideService {
-    @Autowired
-    private WatchConfig sysConfig;
-
-    private final static MyHttpUtils httpUtils = new MyHttpUtils();
-    /**
-     * 查询新手引导
-     *
-     * @param id 新手引导主键
-     * @return 新手引导
-     */
-    @Override
-    public WatchDeviceBeginnerGuide selectDeviceBeginnerGuideById(Long id)
-    {
-
-        WatchDeviceBeginnerGuide watchDeviceBeginnerGuide = null;
-        Map res = httpUtils.getRequest2(sysConfig.getWatchUrl(), "/watch/guide/" + id);
-        if (res!=null){
-            Object data = res.get("data");
-            if (data !=null){
-                watchDeviceBeginnerGuide = JSONObject.parseObject((String) data, WatchDeviceBeginnerGuide.class);
-            }
-        }
-        return watchDeviceBeginnerGuide;
-    }
-
-    /**
-     * 查询新手引导列表
-     *
-     * @param deviceBeginnerGuide 新手引导
-     * @return 新手引导
-     */
-    @Override
-    public List<WatchDeviceBeginnerGuide> selectDeviceBeginnerGuideList(WatchDeviceBeginnerGuide deviceBeginnerGuide)
-    {
-        List<WatchDeviceBeginnerGuide>  watchDeviceBeginnerGuides = new ArrayList<>();
-        Map rse = httpUtils.getRequest3(sysConfig.getWatchUrl(),
-                "/watch/guide/getList",
-                Objects.requireNonNull(getguideMap(deviceBeginnerGuide)));
-        if (rse!=null){
-            Object data = rse.get("data");
-            if (data !=null){
-                List list = JSONObject.parseObject(JSONObject.toJSONString(data), List.class);
-                if (list != null && !list.isEmpty()){
-                    for (Object o : list) {
-                        WatchDeviceBeginnerGuide guide = JSONObject.parseObject(JSONObject.toJSONString(o), WatchDeviceBeginnerGuide.class);
-                        watchDeviceBeginnerGuides.add(guide);
-                    }
-                }
-            }
-        }
-        return watchDeviceBeginnerGuides;
-    }
-
-    private Map<String, Object> getguideMap(WatchDeviceBeginnerGuide deviceBeginnerGuide) {
-        Map<String, Object> map = new HashMap<>();
-        map.put("id", deviceBeginnerGuide.getId());
-        map.put("title", deviceBeginnerGuide.getTitle());
-        map.put("url", deviceBeginnerGuide.getUrl());
-        map.put("type", deviceBeginnerGuide.getType());
-        map.put("isDel", deviceBeginnerGuide.getIsDel());
-        map.put("createTime", deviceBeginnerGuide.getCreateTime());
-        map.put("belong", deviceBeginnerGuide.getBelong());
-        return map;
-    }
-}

+ 97 - 0
fs-service/src/main/java/com/fs/watch/service/impl/WatchDeviceInfoClicServiceImpl.java

@@ -4,6 +4,7 @@ import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.utils.StringUtils;
 import com.fs.watch.domain.IotSim;
 import com.fs.watch.domain.WatchDeviceInfoClic;
+import com.fs.watch.domain.vo.WatchDeviceInfoAndIotExportVO;
 import com.fs.watch.domain.vo.WatchDeviceInfoAndIotVo;
 import com.fs.watch.domain.vo.WatchDeviceInfoVo;
 import com.fs.watch.mapper.WatchDeviceInfoClicMapper;
@@ -18,8 +19,11 @@ import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.stream.Collectors;
 
 /**
  * 设备原始回传信息记录(WatchDeviceInfo)表服务实现类
@@ -166,4 +170,97 @@ public class WatchDeviceInfoClicServiceImpl implements WatchDeviceInfoClicServic
         return watchDeviceInfoClicMapper.selectDeviceInfoList(param);
     }
 
+    @Override
+    public List<WatchDeviceInfoAndIotExportVO> exportDeviceIdAndIotInfo(DeviceIdAndIotInfoQueryParam param) {
+
+        List<WatchDeviceInfoAndIotExportVO> resultList = new ArrayList<>();
+        int pageIndex = 1;
+        int pageSize = 1000;
+        while (true) {
+            //查询所有物联网卡
+            TableDataInfo tableDataInfo = IotUtils.querySIMTable(pageIndex, pageSize);
+            if (tableDataInfo != null) {
+                List<IotSim> iotSims = (List<IotSim>) tableDataInfo.getRows();
+                List<String> iccIds = iotSims.stream().map(x -> x.getIccid()).collect(Collectors.toList());
+                List<WatchDeviceInfoClic> watchDeviceInfoClics = watchDeviceInfoClicMapper.selectListByIccList(iccIds);
+                List<String> deviceIds = watchDeviceInfoClics.stream().map(m -> m.getDeviceId()).collect(Collectors.toList());
+                List<WatchDeviceInfoVo> watchDeviceInfos = deviceInfoService.selectCompanyNameByList(deviceIds);
+                Map<String, WatchDeviceInfoClic> mp = watchDeviceInfoClics.stream().filter(device -> device.getSim1Iccid() != null)
+                        .collect(Collectors.toMap(
+                                WatchDeviceInfoClic::getSim1Iccid,
+                                x -> x,
+                                (existing, replacement) -> existing
+                        ));
+                Map<Long, String> companyMp = watchDeviceInfos.stream().filter(x -> x.getDeviceId() != null && x.getCompanyName() != null).collect(Collectors.toMap(WatchDeviceInfoVo::getDeviceId, WatchDeviceInfoVo::getCompanyName));
+
+                //查询对应卡信息
+                if (iotSims != null && !iotSims.isEmpty()) {
+                    for (IotSim temp : iotSims) {
+                        WatchDeviceInfoAndIotExportVO addItem = new WatchDeviceInfoAndIotExportVO();
+                        BeanUtils.copyProperties(temp,addItem );
+                        if (mp.containsKey(addItem.getIccid())) {
+                            WatchDeviceInfoClic watchDeviceInfoClic = mp.get(addItem.getIccid());
+                            addItem.setDeviceId(watchDeviceInfoClic.getDeviceId());
+                            //查询公司名称
+                            if (companyMp.containsKey(watchDeviceInfoClic.getDeviceId())) {
+                                addItem.setCompanyName(companyMp.get(watchDeviceInfoClic.getDeviceId()));
+                            } else {
+                                addItem.setCompanyName(null);
+                            }
+                            if (watchDeviceInfoClic != null) {
+                                addItem.setDeviceId(watchDeviceInfoClic.getDeviceId());
+                                //查询公司名称
+                                WatchDeviceInfoVo deviceInfoVo = deviceInfoService.getByNumber(watchDeviceInfoClic.getDeviceId());
+                                addItem.setCompanyName(deviceInfoVo != null ? deviceInfoVo.getCompanyName() : null);
+                            }
+                        }
+
+                        switch(addItem.getCertified()){
+                            case 0:
+                                addItem.setCertifiedName("未认证");
+                                break;
+                            case 1:
+                                addItem.setCertifiedName("已认证");
+                                break;
+                            case 2:
+                                addItem.setCertifiedName("人工审核中");
+                                break;
+                            default:
+                                addItem.setCertifiedName("未知");
+                        }
+                        switch(addItem.getOperatorType()){
+                            case 1:
+                                addItem.setOperatorTypeName("移动");
+                                break;
+                            case 2:
+                                addItem.setOperatorTypeName("联通");
+                                break;
+                            case 3:
+                                addItem.setOperatorTypeName("电信");
+                                break;
+                            default:
+                                addItem.setOperatorTypeName("未知");
+                        }
+                        switch(addItem.getStatus()){
+                            case 5:
+                                addItem.setStatusName("已激活");
+                                break;
+                            case 6:
+                                addItem.setStatusName("已停用");
+                                break;
+                            default:
+                                addItem.setStatusName("未知");
+                        }
+                        resultList.add(addItem);
+                    }
+                }
+            }
+            if (tableDataInfo.getRows().size() < pageSize) {
+                break;
+            }
+            pageIndex++;
+        }
+        return resultList;
+    }
+
 }

+ 11 - 3
fs-service/src/main/java/com/fs/watch/service/impl/WatchDeviceInfoServiceImpl.java

@@ -9,8 +9,8 @@ import com.fs.company.service.ICompanyService;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.his.service.IFsDoctorService;
 import com.fs.his.service.IFsUserService;
-import com.fs.watch.domain.*;
 import com.fs.watch.domain.vo.FsUserAndCompanyAndDoctorVo;
+import com.fs.watch.domain.*;
 import com.fs.watch.domain.vo.WatchDeviceInfoVo;
 import com.fs.watch.mapper.*;
 import com.fs.watch.param.WatchDeviceInfoQueryParam;
@@ -18,7 +18,9 @@ import com.fs.watch.service.DeviceSetUpService;
 import com.fs.watch.service.WatchBasicInfoService;
 import com.fs.watch.service.WatchDataService;
 import com.fs.watch.service.WatchDeviceInfoService;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -30,6 +32,7 @@ import java.util.*;
  * @description 针对表【watch_device_info(设备硬件信息)】的数据库操作Service实现
  * @createDate 2024-10-15 11:06:50
  */
+@Slf4j
 @Service
 public class WatchDeviceInfoServiceImpl implements WatchDeviceInfoService {
     @Autowired
@@ -48,7 +51,7 @@ public class WatchDeviceInfoServiceImpl implements WatchDeviceInfoService {
 
     @Autowired
     private DeviceSetUpService deviceSetUpService;
-
+    @Lazy
     @Autowired
     private ICompanyService companyService;
     @Autowired
@@ -352,7 +355,7 @@ public class WatchDeviceInfoServiceImpl implements WatchDeviceInfoService {
         //电量 信号
         WatchBasicInfo info = watchBasicInfoService.queryLastByDeviceId(deviceNumber);
         if (info != null) {
-            System.out.println(info);
+            log.info("数据:{}", info);
             Map<String, Object> map = new HashMap<>();
             map.put("rssi", info.getRssi());
             map.put("device_id", deviceNumber);
@@ -707,6 +710,11 @@ public class WatchDeviceInfoServiceImpl implements WatchDeviceInfoService {
         }
     }
 
+    @Override
+    public  List<WatchDeviceInfoVo> selectCompanyNameByList(List<String> deviceIds){
+        return mapper.selectCompanyNameByList(deviceIds);
+    }
+
     /**
      * 查询有设备编号的家人信息
      * @param str

+ 46 - 14
fs-service/src/main/java/com/fs/watch/service/impl/WatchHeartRateDataServiceImpl.java

@@ -2,6 +2,8 @@ package com.fs.watch.service.impl;
 
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
+import com.fs.his.domain.FsThirdDeviceData;
+import com.fs.his.mapper.FsThirdDeviceDataMapper;
 import com.fs.watch.domain.WatchDeviceInfo;
 import com.fs.watch.domain.WatchHeartRateData;
 import com.fs.watch.domain.vo.WatchHeartRateDataVo;
@@ -27,15 +29,11 @@ public class WatchHeartRateDataServiceImpl implements WatchHeartRateDataService
     private WatchHeartRateDataMapper mapper;
     @Autowired
     private WatchDeviceInfoMapper watchDeviceInfoMapper;
+    @Autowired
+    private FsThirdDeviceDataMapper fsThirdDeviceDataMapper;
 
     @Override
     public Boolean insert(WatchHeartRateData watchHeartRateData) {
-        //判断创建时间是否唯一
-        Integer num = mapper.queryByCreateTime(watchHeartRateData.getCreateTime());
-        if (num != null && num > 0) {
-            log.error("===============watchHeartRateData:insert:num=========================={}", num);
-            return false;
-        }
         try {
             mapper.insert(watchHeartRateData);
         } catch (Exception e) {
@@ -76,7 +74,7 @@ public class WatchHeartRateDataServiceImpl implements WatchHeartRateDataService
         Integer max = 0;
         Integer min = 0;
         Integer avg = 0;
-        if (list.size() > 0) {
+        if (!list.isEmpty()) {
             max = list.stream().max(Comparator.comparingInt(WatchHeartRateData::getMaxBpm)).get().getMaxBpm();
             min = list.stream().min(Comparator.comparingInt(WatchHeartRateData::getMinBpm)).get().getMinBpm();
             //计算平均值
@@ -96,11 +94,29 @@ public class WatchHeartRateDataServiceImpl implements WatchHeartRateDataService
     }
 
     @Override
-    public WatchHeartRateDataVo list(Date startTime, Date endTime, String deviceId) {
+    public WatchHeartRateDataVo list(Date startTime, Date endTime, String deviceId, Integer deviceType) {
         if (StringUtils.isNotBlank(deviceId)) {
-            List<WatchHeartRateData> data = mapper.list(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
-                    DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),
-                    deviceId);
+            List<WatchHeartRateData> data = new ArrayList<>();
+            if (deviceType == null || deviceType == 0){
+                data = mapper.list(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
+                        DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),
+                        deviceId);
+
+            } else {
+                List<FsThirdDeviceData> list = fsThirdDeviceDataMapper.selectListByDateAndDeviceIdAndRecordType(startTime, endTime, deviceId, 2, null);
+                if (list != null && !list.isEmpty()) {
+                    for (FsThirdDeviceData item : list) {
+                        WatchHeartRateData watchHeartRateData = new WatchHeartRateData();
+                        watchHeartRateData.setDeviceId(item.getDeviceId());
+                        watchHeartRateData.setMaxBpm(Integer.valueOf(item.getRecordValue()));
+                        watchHeartRateData.setMinBpm(Integer.valueOf(item.getRecordValue()));
+                        watchHeartRateData.setAvgBpm(Integer.valueOf(item.getRecordValue()));
+                        watchHeartRateData.setCreateTime(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss",item.getCreateTime()));
+                        watchHeartRateData.setStatus(item.getStatus());
+                        data.add(watchHeartRateData);
+                    }
+                }
+            }
             return getWatchHeartRateDataVo(data);
         }
         return null;
@@ -132,15 +148,31 @@ public class WatchHeartRateDataServiceImpl implements WatchHeartRateDataService
 
 
     @Override
-    public List<Map<String, Object>> countHeartByDate(Date startTime, Date endTime, String deviceId) {
+    public List<Map<String, Object>> countHeartByDate(Date startTime, Date endTime, String deviceId,Integer deviceType) {
         if (StringUtils.isBlank(deviceId)) {
             return null;
         }
         //返回对象
         List<Map<String, Object>> res = null;
-        res = mapper.countBpByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
-                DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime), deviceId);
+        if (deviceType == null || deviceType == 0){
+            res = mapper.countBpByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
+                    DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime), deviceId);
+        } else {
+            res = fsThirdDeviceDataMapper.countByDateAndDeviceIdAndRecordType(startTime, endTime, deviceId, 2, null);
+        }
+
 
         return res;
     }
+
+    @Override
+    public Integer getStatus(int maxBpm, int minBpm) {
+        if (maxBpm > 100) {
+            return WatchHrStatusEnum.FAST.getValue();
+        } else if (minBpm < 60) {
+            return WatchHrStatusEnum.LOW.getValue();
+        } else {
+            return WatchHrStatusEnum.NORMAL.getValue();
+        }
+    }
 }

+ 152 - 63
fs-service/src/main/java/com/fs/watch/service/impl/WatchSleepDataServiceImpl.java

@@ -5,7 +5,10 @@ import com.alibaba.fastjson.JSONObject;
 import com.fs.common.config.WatchConfig;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
+import com.fs.his.domain.FsThirdDeviceData;
+import com.fs.his.mapper.FsThirdDeviceDataMapper;
 import com.fs.watch.calculation.SleepPreprocessor;
+import com.fs.watch.calculation.SleepScoreCalculator;
 import com.fs.watch.domain.*;
 import com.fs.watch.domain.vo.AppWatchSleepDataVo;
 import com.fs.watch.domain.vo.WatchSleepDataVo;
@@ -17,6 +20,7 @@ import com.fs.watch.service.WatchRriDataService;
 import com.fs.watch.service.WatchSleepDataService;
 import com.fs.watch.utils.MyHttpUtils;
 import lombok.extern.slf4j.Slf4j;
+import org.jetbrains.annotations.NotNull;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 import org.springframework.stereotype.Service;
@@ -26,6 +30,7 @@ import java.text.SimpleDateFormat;
 import java.time.Duration;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeParseException;
 import java.util.*;
@@ -55,16 +60,14 @@ public class WatchSleepDataServiceImpl implements WatchSleepDataService {
     @Autowired
     private ThreadPoolTaskExecutor threadPoolTaskExecutor;
 
+    @Autowired
+    private FsThirdDeviceDataMapper fsThirdDeviceDataMapper;
+
 
     private static final MyHttpUtils httpUtils = new MyHttpUtils();
 
     @Override
     public Boolean insert(WatchSleepData watchSleepData) {
-        //判断创建时间是否唯一
-        Integer num = mapper.queryByCreateTime(watchSleepData.getCreateTime());
-        if (num != null && num > 0) {
-            return false;
-        }
         try {
             mapper.insert(watchSleepData);
         } catch (Exception e) {
@@ -154,52 +157,69 @@ public class WatchSleepDataServiceImpl implements WatchSleepDataService {
             String password = null;
             //获取账号密码
             WatchDeviceAccount deviceAccount = watchDeviceAccountMapper.selectWatchDeviceAccountByDeviceId(deviceId);
-            boolean flag = true;
+            boolean flag = false;
             if(deviceAccount!=null){
                 account = deviceAccount.getAccount();
                 password = deviceAccount.getPassword();
-                tryPostGetSleep(param,account,password,list,vo);
+                Boolean tryRequest = tryPostGetSleep(param, account, password, list, vo);
+                flag = tryRequest == null ?true:tryRequest;
             } else {
+                flag = true;
+            }
+            if (!flag) {
                 account = watchConfig.getAccount1();
                 password = watchConfig.getPassword1();
-                flag = tryPostGetSleep(param, account, password, list, vo);
+                flag = tryPostGetSleep(param, account, password, list, vo) != null;
                 if (!flag){
-                    flag = tryPostGetSleep(param, account, password, list, vo);
+                    flag = tryPostGetSleep(param, account, password, list, vo) != null;
                     if (!flag){
                         account = watchConfig.getAccount2();
                         password = watchConfig.getPassword2();
-                        flag = tryPostGetSleep(param, account, password, list, vo);
+                        flag = tryPostGetSleep(param, account, password, list, vo) != null;
                         if (!flag){
                             account = watchConfig.getAccount3();
                             password = watchConfig.getPassword3();
-                            tryPostGetSleep(param, account, password, list, vo);
+                            flag = tryPostGetSleep(param, account, password, list, vo) != null;
                         }
                     }
                 }
-                //存储账号密码
-                WatchDeviceAccount insertAccountTemp = new WatchDeviceAccount();
-                insertAccountTemp.setDeviceId(deviceId);
-                insertAccountTemp.setAccount(account);
-                insertAccountTemp.setPassword(password);
-                watchDeviceAccountMapper.insertWatchDeviceAccount(insertAccountTemp);
+                if (flag){
+                    //存储账号密码
+                    WatchDeviceAccount insertAccountTemp = new WatchDeviceAccount();
+                    insertAccountTemp.setDeviceId(deviceId);
+                    insertAccountTemp.setAccount(account);
+                    insertAccountTemp.setPassword(password);
+                    if (deviceAccount.getId() != null){
+                        insertAccountTemp.setId(deviceAccount.getId());
+                        watchDeviceAccountMapper.updateWatchDeviceAccount(insertAccountTemp);
+                    } else {
+                        watchDeviceAccountMapper.insertWatchDeviceAccount(insertAccountTemp);
+
+                    }
+
+                }
             }
+
             //存到每日情况
             if (vo.getScore() != null && vo.getScore() > 0) {
-                //查询是否存在
-                WatchDeviceDay dayInfo = new WatchDeviceDay();
-                dayInfo.setSleepScore(vo.getScore());
-                dayInfo.setSleepDetail(JSONObject.toJSONString(vo));
-                //dayInfo.setSleepStatus(getSleepEnum().getValue());
-                if (oldInfo != null) {
-                    dayInfo.setId(oldInfo.getId());
-                    watchDeviceDayMapper.updateWatchDeviceDay(dayInfo);
-                } else {
+                //10.11 优化->存今天以前的数据,防止一天的睡眠数据还在变动
+                // 获取今天的 00:00:00
+                LocalDateTime todayStart = LocalDate.now().atStartOfDay();
+                // 将 Date 转换为 LocalDateTime
+                LocalDateTime createDateTime = createTime.toInstant()
+                        .atZone(ZoneId.systemDefault())
+                        .toLocalDateTime();
+
+                if (createDateTime.isBefore(todayStart)) {
+                    //查询是否存在
+                    WatchDeviceDay dayInfo = new WatchDeviceDay();
+                    dayInfo.setSleepScore(vo.getScore());
+                    dayInfo.setSleepDetail(JSONObject.toJSONString(vo));
+                    //dayInfo.setSleepStatus(getSleepEnum().getValue());
                     dayInfo.setDeviceId(deviceId);
                     dayInfo.setCreateTime(createTime);
                     watchDeviceDayMapper.insertWatchDeviceDay(dayInfo);
                 }
-
-
             }
         }
 
@@ -207,20 +227,30 @@ public class WatchSleepDataServiceImpl implements WatchSleepDataService {
         return vo;
     }
 
-    private boolean tryPostGetSleep(HashMap<String, Object> param,String account,String password,List<SleepSection> list,WatchSleepDataVo vo){
+    private Boolean tryPostGetSleep(HashMap<String, Object> param,String account,String password,List<SleepSection> list,WatchSleepDataVo vo){
         param.put("account",account);
         param.put("password",password);
         Map resData = httpUtils.getPost2("https://api1.iwown.com/algoservice", "/calculation/sleep", param);
         if (resData != null) {
+            if (resData.get("message") != null){
+                if ("the device_id not belong to you".equals(resData.get("message").toString())){
+                    return null;
+                }
+            }
             String startTime = resData.get("start_time").toString();
             String endTime = resData.get("end_time").toString();
             list = JSONObject.parseArray(JSONObject.toJSONString(resData.get("sections")), SleepSection.class);
             vo.setSleepSection(list);
+            AppWatchSleepDataVo appWatchSleepDataVo = parserResult(vo.getDeviceId(), vo);
+            vo.setSleepTime(appWatchSleepDataVo.getSleepTime());
+            vo.setLightSleep(appWatchSleepDataVo.getLightSleep());
+            vo.setEyemoveSleep(appWatchSleepDataVo.getEyemoveSleep());
+            vo.setWeakSleep(appWatchSleepDataVo.getWeakSleep());
             vo.setStartTime(startTime);
             vo.setEndTime(endTime);
             vo.setScore(Integer.parseInt(resData.get("score").toString()));
             return true;
-        } else {
+        }  else {
             return false;
         }
     }
@@ -261,7 +291,7 @@ public class WatchSleepDataServiceImpl implements WatchSleepDataService {
     }
 
     @Override
-    public AppWatchSleepDataVo list(Date startTime, Date endTime, String deviceId) {
+    public AppWatchSleepDataVo list(Date startTime, Date endTime, String deviceId, Integer deviceType) {
         //返回对象
         AppWatchSleepDataVo vo = new AppWatchSleepDataVo();
         // 使用 Calendar 类来循环增加日期
@@ -283,33 +313,76 @@ public class WatchSleepDataServiceImpl implements WatchSleepDataService {
         //夜间睡眠时间(深睡+浅睡)
         Integer sleepCount=0;
         long timeTotal = 0L; //睡眠总时间
-
+        List<WatchSleepDataVo> watchSleepDataVos = new ArrayList<>();
         while (calendar.getTime().before(endTime) || calendar.getTime().equals(endTime)) {
             Date currentDate = calendar.getTime();
-//                System.out.println(currentDate);
-            WatchSleepDataVo watchSleepDataVo = getSleepSection(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, currentDate), deviceId);
-            if (watchSleepDataVo != null && watchSleepDataVo.getSleepSection() !=null && watchSleepDataVo.getSleepSection().size() > 0) {
-                AppWatchSleepDataVo appWatchSleepDataVo = parserResult(deviceId, watchSleepDataVo);
-                //统计图对象
-                sleepSection.addAll(appWatchSleepDataVo.getSleepSection());
-                //深睡时间
-                sSleep = sSleep + appWatchSleepDataVo.getDeepSleep();
-                //浅睡时间
-                lightSleep =lightSleep+ appWatchSleepDataVo.getLightSleep();
-                //清醒时间
-                weakSleep =weakSleep+ appWatchSleepDataVo.getWeakSleep();
-                //快速眼动时间
-                eyemoveSleep =eyemoveSleep+ appWatchSleepDataVo.getEyemoveSleep();
-                //清醒次数
-                weakTime = weakTime + appWatchSleepDataVo.getWeakTime();
-                //夜间睡眠时间(深睡+浅睡)
-                sleepCount=sleepCount+appWatchSleepDataVo.getSleepCount();
-
-                timeTotal = timeTotal + appWatchSleepDataVo.getSleepTime();
-
-                //呼吸质量 得分(百分制)
+            if (deviceType == null || deviceType == 0) {
+//                log.info(currentDate);
+                WatchSleepDataVo watchSleepDataVo = getSleepSection(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, currentDate), deviceId);
+                if (watchSleepDataVo != null && watchSleepDataVo.getSleepSection() !=null && !watchSleepDataVo.getSleepSection().isEmpty()) {
+                    watchSleepDataVo.setDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, currentDate));
+                    watchSleepDataVos.add(watchSleepDataVo);
+                    AppWatchSleepDataVo appWatchSleepDataVo = parserResult(deviceId, watchSleepDataVo);
+                    //统计图对象
+                    sleepSection.addAll(appWatchSleepDataVo.getSleepSection());
+                    //深睡时间
+                    sSleep = sSleep + appWatchSleepDataVo.getDeepSleep();
+                    //浅睡时间
+                    lightSleep =lightSleep+ appWatchSleepDataVo.getLightSleep();
+                    //清醒时间
+                    weakSleep =weakSleep+ appWatchSleepDataVo.getWeakSleep();
+                    //快速眼动时间
+                    eyemoveSleep =eyemoveSleep+ appWatchSleepDataVo.getEyemoveSleep();
+                    //清醒次数
+                    weakTime = weakTime + appWatchSleepDataVo.getWeakTime();
+                    //夜间睡眠时间(深睡+浅睡)
+                    sleepCount=sleepCount+appWatchSleepDataVo.getSleepCount();
+
+                    timeTotal = timeTotal + appWatchSleepDataVo.getSleepTime();
+
+                }
+            } else {
+                Date dayStartTime = DateUtils.truncate(currentDate, Calendar.DATE);
+                Date dayEndTime =  DateUtils.addMilliseconds(
+                        DateUtils.addDays(DateUtils.truncate(currentDate, Calendar.DATE), 1),
+                        -1
+                );
+                List<FsThirdDeviceData> list = fsThirdDeviceDataMapper.selectListByDateAndDeviceIdAndRecordType(dayStartTime, dayEndTime, deviceId, 7, null);
+                if (list != null && !list.isEmpty()) {
+                    SleepStatistics sleepStatistics = SleepScoreCalculator.calculateDetailedStatistics(list);
+                    List<SleepSection> sleepSection1 = sleepStatistics.getSleepSection();
+                    //统计图对象
+                    sleepSection.addAll(sleepSection1);
+                    //深睡时间
+                    sSleep = sSleep + sleepStatistics.getDeepSleepHours().longValue()*60;
+                    //浅睡时间
+                    lightSleep =lightSleep+ sleepStatistics.getLightSleepHours().longValue()*60;
+                    //清醒时间
+                    weakSleep = (long) (weakSleep+ (sleepStatistics.getAwakeDuration() / (1000.0 * 60)));
+                    //没有快速眼动时间
+                    //清醒次数
+                    weakTime = weakTime + sleepStatistics.getAwakeCount();
+                    //夜间睡眠时间(深睡+浅睡)
+                    sleepCount=sleepCount+(sleepStatistics.getDeepSleepCount() + sleepStatistics.getLightSleepCount());
+
+                    timeTotal = timeTotal + sleepStatistics.getTotalSleepHours().longValue()*60;
+                    WatchSleepDataVo watchSleepDataVo = new WatchSleepDataVo();
+                    watchSleepDataVo.setDeviceId(deviceId);
+                    watchSleepDataVo.setDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, currentDate));
+                    watchSleepDataVo.setStartTime(sleepSection1.get(0).getStart());
+                    watchSleepDataVo.setEndTime(sleepSection1.get(sleepSection1.size()-1).getEnd());
+                    watchSleepDataVo.setDeepSleep(sleepStatistics.getDeepSleepHours().intValue() * 60);
+                    watchSleepDataVo.setLightSleep(sleepStatistics.getLightSleepHours().intValue() * 60);
+                    watchSleepDataVo.setWeakSleep((int) (sleepStatistics.getAwakeDuration() / (1000.0 * 60)));
+                    watchSleepDataVo.setEyemoveSleep(sleepStatistics.getRemHours().intValue() * 60);
+//                    watchSleepDataVo.setScore(score); // 需要从某处获取睡眠得分
+                    watchSleepDataVo.setSleepTime(sleepStatistics.getTotalSleepHours().intValue() * 60);
+                    watchSleepDataVo.setSleepSection(sleepSection1);
+                    watchSleepDataVos.add(watchSleepDataVo);
+                }
             }
 
+
             // 增加一天
             calendar.add(Calendar.DAY_OF_MONTH, 1);
         }
@@ -322,6 +395,7 @@ public class WatchSleepDataServiceImpl implements WatchSleepDataService {
         vo.setWeakTime(weakTime);
         vo.setSleepCount(sleepCount);
         vo.setSleepTime((int)timeTotal);
+        vo.setWatchSleepDataVoList(watchSleepDataVos);
 
         if (timeTotal == 0){
             vo.setDeepScale(0);
@@ -455,7 +529,7 @@ public class WatchSleepDataServiceImpl implements WatchSleepDataService {
         DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
 
 
-        if (list != null && list.size() > 0) {
+        if (list != null && !list.isEmpty()) {
             for (SleepSection sleepSection : list) {
                 /**
                  * {
@@ -466,8 +540,11 @@ public class WatchSleepDataServiceImpl implements WatchSleepDataService {
                  */
 
                 // 解析字符串为 LocalDateTime 对象
-                LocalDateTime start = LocalDateTime.parse(sleepSection.getStart(), formatter);
-                LocalDateTime end = LocalDateTime.parse(sleepSection.getEnd(), formatter);
+
+                String startSleep = getTimeString(sleepSection.getStart());
+                String endSleep = getTimeString(sleepSection.getEnd());
+                LocalDateTime start = LocalDateTime.parse(startSleep, formatter);
+                LocalDateTime end = LocalDateTime.parse(endSleep, formatter);
 
                 // 计算时间差(以分钟为单位)
                 long minutes = Duration.between(start, end).toMinutes();
@@ -508,12 +585,12 @@ public class WatchSleepDataServiceImpl implements WatchSleepDataService {
             vo.setSleepTime(timeTotal.intValue());
             vo.setSleepSection(list);
             Integer score = watchSleepDataVo.getScore();
-            if (score ==null || score ==0){
-                //计算睡眠得分
-                vo.setScore(calculateSleepScore(iCount, vo));
-            } else {
-                vo.setScore(score);
-            }
+//            if (score ==null || score ==0){
+//                //计算睡眠得分
+//                vo.setScore(calculateSleepScore(iCount, vo));
+//            } else {
+            vo.setScore(score);
+//            }
             //深睡比例 28%
             vo.setDeepScale((int) (sTime * 100 / timeTotal));
             //浅睡比例 46%
@@ -525,6 +602,18 @@ public class WatchSleepDataServiceImpl implements WatchSleepDataService {
         return vo;
     }
 
+    private static @NotNull String getTimeString(String startSleep) {
+        if (startSleep == null) {
+            return "";
+        }
+
+        // 使用正则表达式匹配并替换负数情况
+        // 直接将":-数字"替换为":00"
+        String result = startSleep.replaceAll(":-\\d+", ":00");
+
+        return result;
+    }
+
     private static int calculateDeepSleepScore(Long sTime) {
         int MAX_SLEEP_HOURS = 6;
         // 满分标准为8小时深睡

+ 72 - 0
fs-service/src/main/java/com/fs/watch/service/impl/WatchSosCallLogsServiceImpl.java

@@ -0,0 +1,72 @@
+package com.fs.watch.service.impl;
+
+import com.fs.watch.domain.WatchSosCallLogs;
+import com.fs.watch.mapper.WatchSosCallLogsMapper;
+import com.fs.watch.service.WatchSosCallLogsService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * sos报警日志(WatchSosCallLogs)表服务实现类
+ *
+ * @author makejava
+ * @since 2024-12-24 14:30:26
+ */
+@Service("watchSosCallLogsService")
+@Slf4j
+public class WatchSosCallLogsServiceImpl implements WatchSosCallLogsService {
+    @Autowired
+    private WatchSosCallLogsMapper mapper;
+
+
+
+
+    /**
+     * 新增数据
+     *
+     * @param data 实例对象
+     * @return 实例对象
+     */
+    @Override
+    public Boolean insert(WatchSosCallLogs data) {
+        try {
+            mapper.insert(data);
+        } catch (Exception e) {
+            log.error("===============watchSosCall:insert=========================={}", e.getMessage());
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public Boolean batchInsertData(List<WatchSosCallLogs> list) {
+        try {
+            if (list.size() > 0) {
+                mapper.batchInsertData(list);
+
+            }
+        } catch (Exception e) {
+            log.error("===============watchSosCall:insert=========================={}", e.getMessage());
+            return false;
+        }
+        return true;
+    }
+
+    private Map<String, Object> getSosCallMap(WatchSosCallLogs data) {
+        Map<String, Object> params = new HashMap<>();
+        params.put("id", data.getId());
+        params.put("deviceId", data.getDeviceId());
+        params.put("alarmTime", data.getAlarmTime());
+        params.put("lat", data.getLat());
+        params.put("lon", data.getLon());
+        params.put("callLogs", data.getCallLogs());
+        return params;
+    }
+
+}

+ 68 - 28
fs-service/src/main/java/com/fs/watch/service/impl/WatchSpo2DataServiceImpl.java

@@ -2,6 +2,8 @@ package com.fs.watch.service.impl;
 
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
+import com.fs.his.domain.FsThirdDeviceData;
+import com.fs.his.mapper.FsThirdDeviceDataMapper;
 import com.fs.watch.domain.WatchContinuousSpo2Data;
 import com.fs.watch.domain.WatchDeviceInfo;
 import com.fs.watch.domain.WatchSpo2Data;
@@ -35,14 +37,12 @@ public class WatchSpo2DataServiceImpl implements WatchSpo2DataService {
     @Autowired
     private WatchDeviceInfoMapper watchDeviceInfoMapper;
 
+    @Autowired
+    private FsThirdDeviceDataMapper fsThirdDeviceDataMapper;
+
 
     @Override
     public Boolean insert(WatchSpo2Data watchSpo2Data) {
-        //判断创建时间是否唯一
-        Integer num = mapper.queryByCreateTime(watchSpo2Data.getCreateTime());
-        if (num != null && num > 0) {
-            return false;
-        }
         try {
             mapper.insert(watchSpo2Data);
         } catch (Exception e) {
@@ -71,41 +71,76 @@ public class WatchSpo2DataServiceImpl implements WatchSpo2DataService {
     }
 
     @Override
-    public WatchSpo2DataQueryVo querySpByDate(Date startTime, Date endTime, String deviceId) {
+    public WatchSpo2DataQueryVo querySpByDate(Date startTime, Date endTime, String deviceId,Integer deviceType) {
         if (StringUtils.isNotBlank(deviceId)) {
-            List<WatchSpo2DataVo> spo2DataVos = mapper.querySpByDate(DateUtils.parseDateToStr(
-                    DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
-                    DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),
-                    deviceId);
+            WatchSpo2DataQueryVo watchSpo2DataQueryVo = new WatchSpo2DataQueryVo();
+            if (deviceType == null || deviceType == 0){
+                List<WatchSpo2DataVo> spo2DataVos = mapper.querySpByDate(DateUtils.parseDateToStr(
+                                DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
+                        DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),
+                        deviceId);
 //            List<WatchContinuousSpo2Data> datas = continuousSpo2DataService.querySpByDate(DateUtils.parseDateToStr(
 //                    DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
 //                    DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),
 //                    deviceId);
 //            //数据处理
 //            ArrayList<WatchSpo2DataVo> spo2DataVos = getWatchSpo2DataVos(deviceId, datas);
-            WatchSpo2DataQueryVo watchSpo2DataQueryVo = new WatchSpo2DataQueryVo();
-            watchSpo2DataQueryVo.setList(spo2DataVos);
-            Integer max = 0;
-            Integer min = 0;
-            double avg = 0.;
+                watchSpo2DataQueryVo.setList(spo2DataVos);
+                Integer max = 0;
+                Integer min = 0;
+                double avg = 0.;
 //
-            if (!spo2DataVos.isEmpty()){
-                max = spo2DataVos.stream().map(WatchSpo2DataVo::getMaxBoxy).max(Integer::compareTo).get();
-                min = spo2DataVos.stream().map(WatchSpo2DataVo::getMinBoxy).min(Integer::compareTo).get();
-                avg = spo2DataVos.stream().map(WatchSpo2DataVo::getAvgBoxy).min(Double::compareTo).get();
+                if (!spo2DataVos.isEmpty()){
+                    max = spo2DataVos.stream().map(WatchSpo2DataVo::getMaxBoxy).max(Integer::compareTo).get();
+                    min = spo2DataVos.stream().map(WatchSpo2DataVo::getMinBoxy).min(Integer::compareTo).get();
+                    avg = spo2DataVos.stream().map(WatchSpo2DataVo::getAvgBoxy).min(Double::compareTo).get();
 //                OptionalDouble  averageValue = spo2DataVos.stream().filter(temp->temp.getAvgBoxy()!=null).mapToDouble(WatchSpo2DataVo::getAvgBoxy)
 //                        .average();
-                // 如果平均值存在,将其转换为 int 类型并输出
+                    // 如果平均值存在,将其转换为 int 类型并输出
 //                if (averageValue.isPresent()) {
 ////                    avg = (int) averageValue.getAsDouble();  // 将 double 转换为 int
 //                    avg = averageValue.getAsDouble();  // 将 double 转换为 int
 //                    avg = Math.round(avg * 100.0) / 100.0;
 //                }
-            }
+                }
+
+                watchSpo2DataQueryVo.setMax(max);
+                watchSpo2DataQueryVo.setMin(min);
+                watchSpo2DataQueryVo.setAvg(avg);
 
-            watchSpo2DataQueryVo.setMax(max);
-            watchSpo2DataQueryVo.setMin(min);
-            watchSpo2DataQueryVo.setAvg(avg);
+            } else {
+                List<FsThirdDeviceData> list = fsThirdDeviceDataMapper.selectListByDateAndDeviceIdAndRecordType(startTime,endTime,deviceId,4,null);
+                if (list != null && !list.isEmpty()) {
+                    int max = 0;
+                    int min = 0;
+                    double avg = 0.;
+                    int sum = 0;
+                    List<WatchSpo2DataVo> listVos = new ArrayList<>();
+                    for (FsThirdDeviceData fsThirdDeviceData : list) {
+                        WatchSpo2DataVo vo = new WatchSpo2DataVo();
+                        vo.setDeviceId(fsThirdDeviceData.getDeviceId());
+                        int num = Integer.parseInt(fsThirdDeviceData.getRecordValue());
+                        vo.setMinBoxy(num);
+                        vo.setMaxBoxy(num);
+                        vo.setAvgBoxy(Double.valueOf(num));
+                        vo.setStatus(getStatus(num,num));
+                        listVos.add(vo);
+                        max = Math.max(num, max);
+                        min = Math.min(num, min);
+                        sum += num;
+                    }
+                    if (sum > 0){
+                        avg = (double) sum / listVos.size();
+                    }
+                    watchSpo2DataQueryVo.setMin(min);
+                    watchSpo2DataQueryVo.setMax(max);
+                    watchSpo2DataQueryVo.setAvg(avg);
+                    watchSpo2DataQueryVo.setList(listVos);
+                } else {
+                    return null;
+                }
+
+            }
             return watchSpo2DataQueryVo;
         }
         return null;
@@ -173,20 +208,25 @@ public class WatchSpo2DataServiceImpl implements WatchSpo2DataService {
     }
 
     @Override
-    public List<Map<String, Object>> countSpByDate(Date startTime, Date endTime, String deviceId) {
+    public List<Map<String, Object>> countSpByDate(Date startTime, Date endTime, String deviceId,Integer deviceType) {
         if (StringUtils.isBlank(deviceId)) {
             return null;
         }
-//        res = mapper.countSpByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
+        if (deviceType == null || deviceType == 0) {
+            //        res = mapper.countSpByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
 //                DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),deviceId);
-        return mapper.countSpByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
-                DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),deviceId);
+            return mapper.countSpByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
+                    DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),deviceId);
 //        List<WatchContinuousSpo2Data> list = continuousSpo2DataService.querySpByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
 //                DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime), deviceId);
 //        if (list != null && list.size() > 0) {
 //            return getStatusCount(list);
 //        }
 //        return null;
+        } else {
+           return fsThirdDeviceDataMapper.countByDateAndDeviceIdAndRecordType(startTime, endTime, deviceId, 4,null);
+        }
+
     }
 
     private List<Map<String, Integer>> getStatusCount(List<WatchContinuousSpo2Data> list) {

+ 222 - 57
fs-service/src/main/java/com/fs/watch/service/impl/WatchSportDataServiceImpl.java

@@ -2,7 +2,11 @@ package com.fs.watch.service.impl;
 
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
+import com.fs.his.mapper.FsHealthPulseMapper;
+import com.fs.his.mapper.FsHealthSurfaceMapper;
 import com.fs.his.mapper.FsHealthTongueMapper;
+import com.fs.his.mapper.FsThirdDeviceDataMapper;
+import com.fs.watch.calculation.SleepScoreCalculator;
 import com.fs.watch.domain.WatchFsUser;
 import com.fs.watch.domain.WatchSportData;
 import com.fs.watch.domain.vo.*;
@@ -47,15 +51,18 @@ public class WatchSportDataServiceImpl implements WatchSportDataService {
     private WatchSleepDataService sleepDataService;
     @Autowired
     private FsHealthTongueMapper fsHealthTongueMapper;
+    @Autowired
+    private FsHealthSurfaceMapper fsHealthSurfaceMapper;
+    @Autowired
+    private FsHealthPulseMapper fsHealthPulseMapper;
+    @Autowired
+    private FsThirdDeviceDataMapper fsThirdDeviceDataMapper;
+    @Autowired
+    private SleepScoreCalculator sleepScoreCalculator;
 
 
     @Override
     public Boolean insert(WatchSportData sportData) {
-        //判断创建时间是否唯一
-        Integer num = mapper.queryByCreateTime(sportData.getCreateTime());
-        if (num != null && num > 0) {
-            return false;
-        }
         try {
             mapper.insert(sportData);
         } catch (Exception e) {
@@ -262,26 +269,95 @@ public class WatchSportDataServiceImpl implements WatchSportDataService {
     }
 
     @Override
-    public List<WatchSportRecordVo> queryRecord(String deviceId) {
+    public List<WatchSportRecordVo> queryRecord(String deviceId,Integer deviceType) {
+        String s = DateUtils.dateTimeNow("yyyy-MM-dd");
+        Date startTime = DateUtils.parseDate(s + " 00:00:00");
+        Date endTime = DateUtils.parseDate(s + " 23:59:59");
         if (StringUtils.isNotBlank(deviceId)) {
-            String s = DateUtils.dateTimeNow("yyyy-MM-dd");
-            Date startTime = DateUtils.parseDate(s + " 00:00:00");
-            Date endTime = DateUtils.parseDate(s + " 23:59:59");
-            List<WatchSportRecordVo> res = mapper.queryRecord(startTime, endTime, deviceId, null);
-            List<String> types = new ArrayList<>(Arrays.asList("游泳", "登山", "骑行", "跑步", "球类", "健走", "走路"));
-//            //其他运动
-            WatchSportRecordVo vo = mapper.getOtherData(null, null, deviceId, types);
+            WatchSportRecordVo vo =  new WatchSportRecordVo();
+            List<WatchSportRecordVo> res = new ArrayList<>();
+            if (deviceType == null || deviceType == 0) {
+                res = mapper.queryRecord(startTime, endTime, deviceId, null);
+                List<String> types = new ArrayList<>(Arrays.asList("游泳", "登山", "骑行", "跑步", "球类", "健走", "走路"));
+            //其他运动
+                vo = mapper.getOtherData(null, null, deviceId, types);
+                //计算时长
+//            mapper.getByTypeAndDeviceIdAndDate(deviceId,typ)
+            } else {
+                vo = fsThirdDeviceDataMapper.getOtherDataOther(startTime, endTime, deviceId, 6);
+                List<WatchSportRecordVo> list = fsThirdDeviceDataMapper.queryActivityRecord(startTime, endTime, deviceId, 6, null);
+                if (list != null && !list.isEmpty()) {
+                    for (WatchSportRecordVo data : list) {
+                        String sportType = data.getType();
+                        if (StringUtils.isNotBlank(sportType)) {
+                            data.setType(getActivityType(Integer.parseInt(sportType)));
+                            res.add(data);
+                        }
+                    }
+                }
+
+            }
             vo.setType("其他运动");
             res.add(vo);
-            //计算时长
-//            mapper.getByTypeAndDeviceIdAndDate(deviceId,typ)
             return res;
         }
         return null;
     }
 
+    private String getActivityType(Integer sportType) {
+        if (sportType == null) {
+            return null;
+        }
+        switch (sportType) {
+            case 1:
+                return "骑行";
+            case 5:
+                return "健步走";
+            case 9:
+                return "跑步";
+            case 13:
+                return "走路";
+            case 17:
+                return "登山";
+            case 21:
+                return "球类";
+            case 25:
+                return "游泳";
+            case 29:
+                return "羽毛球";
+            case 33:
+                return "足球";
+            case 37:
+                return "椭圆机";
+            case 41:
+                return "瑜伽";
+            case 45:
+                return "乒乓球";
+            case 49:
+                return "跳绳";
+            case 53:
+                return "划船机";
+            case 65:
+                return "自由训练";
+            case 69:
+                return "网球";
+            case 85:
+                return "自由运动";
+            case 89:
+                return "力量训练";
+            case 105:
+                return "舞蹈";
+            case 109:
+                return "呼啦圈";
+            case 113:
+                return "高尔夫";
+            default:
+                return null;
+        }
+    }
+
     @Override
-    public WatchSportIndexVo sportData(String userId, String deviceId,Boolean isFamily) {
+    public WatchSportIndexVo sportData(String userId, String deviceId,Boolean isFamily,Integer deviceType) {
         WatchSportIndexVo vo = new WatchSportIndexVo();
         if (isFamily != null && isFamily) {
             WatchFamilyUserVo watchFamilyUserVo = familyUserService.selectWatchFamilyUserByDeviceId(deviceId, null);
@@ -304,18 +380,56 @@ public class WatchSportDataServiceImpl implements WatchSportDataService {
 
         //2.查询当日完成
         //2.1卡路里,步数
-        WatchSportData map = mapper.sumStepAndCalorie(deviceId);
-        if (map != null) {
-            vo.setStep(map.getStep().toString());
-            vo.setCalorie(String.format("%.2f", map.getCalorie()));
+        if (deviceType == null || deviceType == 0) {
+            WatchSportData map = mapper.sumStepAndCalorie(deviceId);
+            if (map != null) {
+                vo.setStep(map.getStep().toString());
+                vo.setCalorie(String.format("%.2f", map.getCalorie()));
+            }
+            //2.2 时长
+            Long sportTime = getSportTime(deviceId, null, "today");
+            //2.2.1 活动
+            Long activityTime = getActivityTime(deviceId);//分钟
+            //2.2.2 锻炼
+            vo.setSport(sportTime == null ? "0" : sportTime.toString());
+            vo.setActivity(activityTime == null ? "0" : new BigDecimal(activityTime).divide(new BigDecimal(60), 2, RoundingMode.HALF_UP) + "");
+        } else {
+            Date starTime = DateUtils.truncate(new Date(), Calendar.DATE);
+            Date endTime = DateUtils.getNowDate();
+            //步数
+            WatchSportRecordVo map1 = fsThirdDeviceDataMapper.getOtherData(starTime,endTime,deviceId,5,null);
+            //运动
+            WatchSportRecordVo map2 = fsThirdDeviceDataMapper.getOtherData(starTime,endTime,deviceId,6,null);
+            long stepTotal = 0L;
+            float calorieTotal = 0f;
+            vo.setActivity("0");
+            vo.setSport("0");
+            if (map1 != null) {
+                stepTotal = stepTotal + (map1.getStep()==null?0:map1.getStep());
+                if (map1.getCalorie()!=null && map1.getCalorie()>0) {
+                    calorieTotal = map1.getCalorie();
+                }
+                Float time = map1.getTime();
+                if (time != null) {
+                    vo.setActivity(String.valueOf(time));
+                }
+
+            }
+            if (map2 != null) {
+                stepTotal = stepTotal + (map2.getStep()==null?0:map2.getStep());
+                Float time = map2.getTime();
+                if (time != null) {
+                    vo.setSport(String.valueOf(time*60));
+                }
+
+            }
+            //2.2.2 锻炼
+            vo.setStep(String.valueOf(stepTotal));
+            vo.setCalorie(String.valueOf(calorieTotal));
+
         }
-        //2.2 时长
-        Long sportTime = getSportTime(deviceId, null, "today");
-        //2.2.1 活动
-        Long activityTime = getActivityTime(deviceId);//分钟
-        //2.2.2 锻炼
-        vo.setSport(sportTime == null ? "0" : sportTime.toString());
-        vo.setActivity(activityTime == null ? "0" : new BigDecimal(activityTime).divide(new BigDecimal(60), 2, RoundingMode.HALF_UP) + "");
+
+
         return vo;
     }
 
@@ -498,32 +612,64 @@ public class WatchSportDataServiceImpl implements WatchSportDataService {
     }
 
     @Override
-    public AppFsUserHealthVo getUserHealthInfoByDeviceId(String deviceId,Date startTime, Date endTime,Long userId) {
+    public AppFsUserHealthVo getUserHealthInfoByDeviceId(String deviceId,Date startTime, Date endTime,Long userId,Integer deviceType) {
         AppFsUserHealthVo vo = new AppFsUserHealthVo();
         // 格式化时间
-        String startDate = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime);
-        String endDate = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime);
-        // 异步任务 1:睡眠状态
-        CompletableFuture<String> sleepFuture = CompletableFuture.supplyAsync(() ->
-                sleepDataService.getSleepStatus(startTime, endTime, deviceId)
-        );
-
-
-        // 异步任务 2:运动数据
-        CompletableFuture<Void> sportFuture = CompletableFuture.runAsync(() -> {
-            List<WatchSportData> list = mapper.getByType(startDate, endDate, deviceId, null);
-            int step = 0;
-            float calorie = 0;
-            if (list != null && !list.isEmpty()) {
-                for (WatchSportData data : list) {
-                    step += data.getStep() == null ? 0 : data.getStep();
-                    calorie += data.getCalorie() == null ? 0 : data.getCalorie();
-                }
+        String startDate = DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", startTime);
+        String endDate = DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", endTime);
+        CompletableFuture<String>  sleepFuture = null;
+        CompletableFuture<Void>  sportFuture = null;
+        if (StringUtils.isNotBlank(deviceId)){
+            // 异步任务 1:睡眠状态
+            if (deviceType == null || deviceType == 0){
+                sleepFuture = CompletableFuture.supplyAsync(() ->
+                        sleepDataService.getSleepStatus(startTime, endTime, deviceId)
+                );
+
+
+                // 异步任务 2:运动数据
+                sportFuture = CompletableFuture.runAsync(() -> {
+                    List<WatchSportData> list = mapper.getByType(startDate, endDate, deviceId, null);
+                    int step = 0;
+                    float calorie = 0;
+                    if (list != null && !list.isEmpty()) {
+                        for (WatchSportData data : list) {
+                            step += data.getStep() == null ? 0 : data.getStep();
+                            calorie += data.getCalorie() == null ? 0 : data.getCalorie();
+                        }
+                    }
+                    vo.setStep(step);
+                    vo.setCalorie((int) calorie);
+                });
+            } else {
+                sleepFuture = CompletableFuture.supplyAsync(() ->
+                        sleepScoreCalculator.getSleepStatus(startTime, endTime, deviceId)
+                );
+
+
+                // 异步任务 2:运动数据
+                sportFuture = CompletableFuture.runAsync(() -> {
+//                    List<WatchSportData> list = mapper.getByType(startDate, endDate, deviceId, null);
+                    WatchSportRecordVo otherData1 = fsThirdDeviceDataMapper.getOtherData(startTime, endTime, deviceId, 5, null);
+                    WatchSportRecordVo otherData2 = fsThirdDeviceDataMapper.getOtherData(startTime, endTime, deviceId, 6, null);
+                    int step = 0;
+                    float calorie = 0;
+                    if (otherData1 != null) {
+                        step += otherData1.getStep() == null ? 0 : Integer.parseInt(otherData1.getStep().toString());
+                        calorie += otherData1.getCalorie() == null ? 0 : otherData1.getCalorie();
+                    }
+                    if (otherData2 != null) {
+                        step += otherData2.getStep() == null ? 0 : Integer.parseInt(otherData2.getStep().toString());
+                        calorie += otherData2.getCalorie() == null ? 0 : otherData2.getCalorie();
+                    }
+                    vo.setStep(step);
+                    vo.setCalorie((int) calorie);
+                });
             }
-            vo.setStep(step);
-            vo.setCalorie((int) calorie);
-        });
 
+
+
+        }
         // 异步任务 3:舌诊数据
         CompletableFuture<Void> tongueFuture = CompletableFuture.runAsync(() -> {
             if (userId != null){
@@ -531,14 +677,33 @@ public class WatchSportDataServiceImpl implements WatchSportDataService {
                 vo.setTongueDateList(list);
             }
         });
-
-        // 等待所有任务完成
-        CompletableFuture.allOf(sleepFuture, sportFuture,tongueFuture).join();
-        try {
-            vo.setSleepStatus(sleepFuture.get());
-        } catch (Exception e) {
-            log.error("获取睡眠状态失败: {}", e.getMessage(), e);
-            vo.setSleepStatus("未知");
+        // 异步任务 3:面诊数据
+        CompletableFuture<Void> surfaceFuture = CompletableFuture.runAsync(() -> {
+            if (userId != null){
+                List<String> list = fsHealthSurfaceMapper.selectListByDateAndUserId(startDate, endDate, userId);
+                vo.setSurfaceDateList(list);
+            }
+        });
+        // 异步任务 3:脉诊数据
+        CompletableFuture<Void> pulseFuture = CompletableFuture.runAsync(() -> {
+            if (userId != null){
+                List<String> list = fsHealthPulseMapper.selectListByDateAndUserId(startDate, endDate, userId);
+                vo.setPulseDateList(list);
+            }
+        });
+        if(StringUtils.isNotBlank(deviceId)){
+            // 等待所有任务完成
+            CompletableFuture.allOf(sleepFuture, sportFuture,tongueFuture,surfaceFuture,pulseFuture).join();
+
+            try {
+                vo.setSleepStatus(sleepFuture.get());
+            } catch (Exception e) {
+                log.error("获取睡眠状态失败: {}", e.getMessage(), e);
+                vo.setSleepStatus("未知");
+            }
+        } else {
+            // 等待所有任务完成
+            CompletableFuture.allOf(tongueFuture,surfaceFuture,pulseFuture).join();
         }
         return vo;
     }

+ 76 - 22
fs-service/src/main/java/com/fs/watch/service/impl/WatchThirdBpDataServiceImpl.java

@@ -1,7 +1,10 @@
 package com.fs.watch.service.impl;
 
+import com.alibaba.fastjson.JSONObject;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
+import com.fs.his.domain.FsThirdDeviceData;
+import com.fs.his.mapper.FsThirdDeviceDataMapper;
 import com.fs.watch.domain.WatchThirdBpData;
 import com.fs.watch.mapper.WatchThirdBpDataMapper;
 import com.fs.watch.service.WatchThirdBpDataService;
@@ -9,10 +12,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 /**
 * @author Administrator
@@ -24,6 +24,8 @@ import java.util.Map;
 public class WatchThirdBpDataServiceImpl implements WatchThirdBpDataService {
     @Autowired
     private WatchThirdBpDataMapper mapper;
+    @Autowired
+    private FsThirdDeviceDataMapper fsThirdDeviceDataMapper;
 
     /**
      * 新增数据
@@ -33,11 +35,6 @@ public class WatchThirdBpDataServiceImpl implements WatchThirdBpDataService {
      */
     @Override
     public Boolean insert(WatchThirdBpData watchThirdBpData) {
-        //判断创建时间是否唯一
-        Integer num = mapper.queryByCreateTime(watchThirdBpData.getCreateTime());
-        if (num != null && num > 0) {
-            return false;
-        }
         try {
             mapper.insert(watchThirdBpData);
         } catch (Exception e) {
@@ -69,8 +66,32 @@ public class WatchThirdBpDataServiceImpl implements WatchThirdBpDataService {
     }
 
     @Override
-    public List<WatchThirdBpData> queryBpByDate(String startTime, String endTime, String deviceId, Integer status) {
-        return mapper.queryBpByDate(startTime,endTime,deviceId,status);
+    public List<WatchThirdBpData> queryBpByDate(String startTime, String endTime, String deviceId, Integer status,Integer deviceType) {
+        if (deviceType == null || deviceType == 0) {
+            return mapper.queryBpByDate(startTime,endTime,deviceId,status);
+        } else {
+            List<WatchThirdBpData> voList = new ArrayList<>();
+            List<FsThirdDeviceData> list = fsThirdDeviceDataMapper.selectListByDateAndDeviceIdAndRecordType(DateUtils.dateTime("yyyy-MM-dd HH:mm:ss",startTime), DateUtils.dateTime("yyyy-MM-dd HH:mm:ss",endTime), deviceId, 0, status);
+
+            if (list != null && !list.isEmpty()) {
+                for (FsThirdDeviceData fsThirdDeviceData : list) {
+                    WatchThirdBpData watchThirdBpData = new WatchThirdBpData();
+                    watchThirdBpData.setDeviceId(fsThirdDeviceData.getDeviceId());
+                    String recordValue = fsThirdDeviceData.getRecordValue();
+                    if (StringUtils.isNotBlank(recordValue)) {
+                        JSONObject jsonObject = JSONObject.parseObject(recordValue);
+                        watchThirdBpData.setSbp(Integer.valueOf(jsonObject.get("sdb").toString()));
+                        watchThirdBpData.setDbp(Integer.valueOf(jsonObject.get("dbp").toString()));
+                        watchThirdBpData.setCreateTime(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss",fsThirdDeviceData.getCreateTime()));
+                        watchThirdBpData.setStatus(fsThirdDeviceData.getStatus());
+                        voList.add(watchThirdBpData);
+                    }
+
+                }
+            }
+            return voList;
+        }
+
     }
 
 
@@ -115,31 +136,64 @@ public class WatchThirdBpDataServiceImpl implements WatchThirdBpDataService {
     }
 
     @Override
-    public List<Map<String, Object>> countBpByDate(Date startTime, Date endTime, String deviceId) {
+    public List<Map<String, Object>> countBpByDate(Date startTime, Date endTime, String deviceId,Integer deviceType) {
         if (StringUtils.isBlank(deviceId)) {
             return null;
         }
         //返回对象
         List<Map<String, Object>>  res = null;
-        res = mapper.countBpByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
-                DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),deviceId);
+        if (deviceType == null || deviceType == 0) {
+            res = mapper.countBpByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
+                    DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),deviceId);
+        } else {
+            res = fsThirdDeviceDataMapper.countByDateAndDeviceIdAndRecordType(startTime,endTime,deviceId,0,null);
+        }
+
 
         return res;
     }
 
     @Override
-    public int countBpPageByDate(Date startTime, Date endTime, String deviceId, Integer status) {
-        return mapper.countBpPageByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
-                DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),
-                deviceId,status);
+    public int countBpPageByDate(Date startTime, Date endTime, String deviceId, Integer status,Integer deviceType) {
+        if (deviceType == null || deviceType == 0) {
+            return mapper.countBpPageByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
+                    DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),
+                    deviceId,status);
+        } else {
+            return fsThirdDeviceDataMapper.countPageByDateAndDeviceIdAndRecordType(startTime,endTime,deviceId,0,status);
+        }
+
     }
 
     @Override
-    public List<WatchThirdBpData> queryBgPageByDate(Date startTime, Date endTime, String deviceId, Integer status, Integer num, Integer size) {
+    public List<WatchThirdBpData> queryBgPageByDate(Date startTime, Date endTime, String deviceId, Integer status, Integer num, Integer size,Integer deviceType) {
         if (StringUtils.isNotBlank(deviceId)) {
-            return mapper.queryBgPageByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
-                    DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),
-                    deviceId,status,num,size);
+            if (deviceType == null || deviceType == 0) {
+                return mapper.queryBgPageByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
+                        DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),
+                        deviceId,status,num,size);
+            } else {
+                List<WatchThirdBpData> voList = new ArrayList<>();
+                List<FsThirdDeviceData> list = fsThirdDeviceDataMapper.queryPageByDateAndDeviceIdAndRecordType(startTime, endTime, deviceId, 0, status, num, size);
+                if (list != null && !list.isEmpty()) {
+                    for (FsThirdDeviceData fsThirdDeviceData : list) {
+                        WatchThirdBpData vo = new WatchThirdBpData();
+                        vo.setDeviceId(fsThirdDeviceData.getDeviceId());
+                        String recordValue = fsThirdDeviceData.getRecordValue();
+                        if (StringUtils.isNotBlank(recordValue)) {
+                            JSONObject jsonObject = JSONObject.parseObject(recordValue);
+                            vo.setDbp(Integer.valueOf(jsonObject.get("dbp").toString()));
+                            vo.setSbp(Integer.valueOf(jsonObject.get("sdb").toString()));
+                            vo.setStatus(fsThirdDeviceData.getStatus());
+                            vo.setCreateTime(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss",fsThirdDeviceData.getCreateTime()));
+
+                        }
+                        voList.add(vo);
+                    }
+                }
+                return voList;
+            }
+
         } else {
             return null;
         }

+ 62 - 17
fs-service/src/main/java/com/fs/watch/service/impl/WatchThirdUaDataServiceImpl.java

@@ -2,6 +2,8 @@ package com.fs.watch.service.impl;
 
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
+import com.fs.his.domain.FsThirdDeviceData;
+import com.fs.his.mapper.FsThirdDeviceDataMapper;
 import com.fs.watch.domain.WatchDeviceInfo;
 import com.fs.watch.domain.WatchFsUser;
 import com.fs.watch.domain.WatchThirdUaData;
@@ -31,13 +33,11 @@ public class WatchThirdUaDataServiceImpl implements WatchThirdUaDataService {
     private WatchUserService userService;
     @Autowired
     private WatchDeviceInfoMapper watchDeviceInfoMapper;
+    @Autowired
+    private FsThirdDeviceDataMapper fsThirdDeviceDataMapper;
 
     @Override
     public Boolean insert(WatchThirdUaData watchThirdUaData) {
-        Integer num = mapper.queryByCreateTime(watchThirdUaData.getCreateTime());
-        if (num != null && num > 0) {
-            return false;
-        }
         try {
             mapper.insert(watchThirdUaData);
         } catch (Exception e) {
@@ -119,38 +119,83 @@ public class WatchThirdUaDataServiceImpl implements WatchThirdUaDataService {
     }
 
     @Override
-    public List<WatchThirdUaData> list(Date startTime, Date endTime, String deviceId) {
-        return mapper.list(startTime, endTime, deviceId);
+    public List<WatchThirdUaData> list(Date startTime, Date endTime, String deviceId,Integer deviceType) {
+        List<WatchThirdUaData> list = new ArrayList<>();
+        if(deviceType==null || deviceType==0){
+            list = mapper.list(startTime, endTime, deviceId);
+        } else {
+            List<FsThirdDeviceData> fsThirdDeviceDataList = fsThirdDeviceDataMapper.selectListByDateAndDeviceIdAndRecordType(startTime, endTime, deviceId, 3, null);
+            if (fsThirdDeviceDataList != null && !fsThirdDeviceDataList.isEmpty()) {
+                for (FsThirdDeviceData fsThirdDeviceData : fsThirdDeviceDataList) {
+
+                    WatchThirdUaData watchThirdUaData = new WatchThirdUaData();
+                    watchThirdUaData.setDeviceId(fsThirdDeviceData.getDeviceId());
+                    watchThirdUaData.setVal(Integer.valueOf(fsThirdDeviceData.getRecordValue()));
+                    watchThirdUaData.setCreateTime(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss",fsThirdDeviceData.getCreateTime()));
+                    watchThirdUaData.setStatus(fsThirdDeviceData.getStatus());
+                    list.add(watchThirdUaData);
+                }
+            }
+        }
+        return list;
     }
 
     @Override
-    public List<Map<String, Object>> countUaByDate(Date startTime, Date endTime, String deviceId) {
+    public List<Map<String, Object>> countUaByDate(Date startTime, Date endTime, String deviceId,Integer deviceType) {
         if (StringUtils.isBlank(deviceId)) {
             return null;
         }
         //返回对象
         List<Map<String, Object>> res = null;
-        res = mapper.countUaByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
-                DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime), deviceId);
+        if (deviceType==null || deviceType==0) {
+            res = mapper.countUaByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
+                    DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime), deviceId);
+        } else {
+            res = fsThirdDeviceDataMapper.countByDateAndDeviceIdAndRecordType(startTime, endTime, deviceId, 3, null);
+
+        }
 
         return res;
     }
 
     @Override
-    public List<WatchThirdUaData> queryListByDate(Date startTime, Date endTime, String deviceId, Integer pageNum, Integer pageSize, Integer status) {
+    public List<WatchThirdUaData> queryListByDate(Date startTime, Date endTime, String deviceId, Integer pageNum, Integer pageSize, Integer status,Integer deviceType) {
         if (StringUtils.isNotBlank(deviceId)) {
-            return mapper.queryListByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
-                    DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),
-                    deviceId, pageNum, pageSize, status);
+            if (deviceType==null || deviceType==0) {
+                return mapper.queryListByDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
+                        DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),
+                        deviceId, pageNum, pageSize, status);
+            } else {
+                List<WatchThirdUaData> voList = new ArrayList<>();
+                List<FsThirdDeviceData> fsThirdDeviceDataList = fsThirdDeviceDataMapper
+                        .queryPageByDateAndDeviceIdAndRecordType(startTime, endTime, deviceId, 3, status,pageNum,pageSize);
+                if (fsThirdDeviceDataList != null && !fsThirdDeviceDataList.isEmpty()) {
+                    for (FsThirdDeviceData fsThirdDeviceData : fsThirdDeviceDataList) {
+                        WatchThirdUaData watchThirdUaData = new WatchThirdUaData();
+                        watchThirdUaData.setDeviceId(fsThirdDeviceData.getDeviceId());
+                        watchThirdUaData.setVal(Integer.valueOf(fsThirdDeviceData.getRecordValue()));
+                        watchThirdUaData.setCreateTime(DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss",fsThirdDeviceData.getCreateTime()));
+                        watchThirdUaData.setStatus(fsThirdDeviceData.getStatus());
+                        voList.add(watchThirdUaData);
+                    }
+                }
+                return voList;
+            }
+
         } else {
             return null;
         }
     }
 
     @Override
-    public int countTotalDate(Date startTime, Date endTime, String deviceId, Integer status) {
-        return mapper.countTotalDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
-                DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),
-                deviceId, status);
+    public int countTotalDate(Date startTime, Date endTime, String deviceId, Integer status,Integer deviceType) {
+        if (deviceType==null || deviceType==0) {
+            return mapper.countTotalDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, startTime),
+                    DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime),
+                    deviceId, status);
+        } else {
+            return fsThirdDeviceDataMapper.countPageByDateAndDeviceIdAndRecordType(startTime,endTime,deviceId,3,status);
+        }
+
     }
 }

+ 273 - 37
fs-service/src/main/java/com/fs/watch/service/impl/WatchUserServiceImpl.java

@@ -25,10 +25,7 @@ import java.text.SimpleDateFormat;
 import java.time.LocalDate;
 import java.time.Period;
 import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.List;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -192,6 +189,8 @@ public class WatchUserServiceImpl implements WatchUserService {
         watchUser.setTargetStep(watchFsUser.getTargetStep());
         watchUser.setTargetCalorie(watchFsUser.getTargetCalorie());
         watchUser.setDeviceId(watchFsUser.getDeviceId());
+        watchUser.setXhsDeviceId(watchFsUser.getXhsDeviceId());
+        watchUser.setNewXhsDeviceId(watchFsUser.getNewXhsDeviceId());
         watchUser.setOtherDevice(watchFsUser.getOtherDevice());
         watchUser.setMonitorDataTypeOrder(watchFsUser.getMonitorDataTypeOrder());
         watchUser.setCreateTime(watchFsUser.getCreateTime());
@@ -306,17 +305,50 @@ public class WatchUserServiceImpl implements WatchUserService {
             List<DeviceFamily> deviceFamilies = JSON.parseArray(otherDevice, DeviceFamily.class);
             if (deviceFamilies != null && !deviceFamilies.isEmpty()) {
                 for (DeviceFamily deviceFamily : deviceFamilies) {
-                    WatchInfoVo vo = new WatchInfoVo();
-                    BeanUtils.copyProperties(deviceFamily, vo);
-                    //查询设备名字
-                    WatchDeviceData deviceData = watchDeviceDataService.getByDeviceId(deviceFamily.getDeviceId());
-                    if (deviceData != null) {
-                        vo.setBle(deviceData.getBle());
+                    boolean hasDevice = false;
+                    String deviceId = deviceFamily.getDeviceId();
+                    if (StringUtils.isNotBlank(deviceId)) {
+                        WatchInfoVo vo = new WatchInfoVo();
+                        BeanUtils.copyProperties(deviceFamily, vo);
+                        //查询设备名字
+                        WatchDeviceData deviceData = watchDeviceDataService.getByDeviceId(deviceId);
+                        if (deviceData != null) {
+                            vo.setBle(deviceData.getBle());
+                        }
+                        //设备状态
+                        Integer status = deviceInfoService.getStatus(deviceId);
+                        vo.setStatus(status != null ? status : -1);
+                        vo.setDeviceId(deviceId);
+                        res.add(vo);
+                        hasDevice = true;
+                    }
+                    String xhsDeviceId = deviceFamily.getXhsDeviceId();
+                    if (StringUtils.isNotBlank(xhsDeviceId)) {
+                        WatchInfoVo vo = new WatchInfoVo();
+                        BeanUtils.copyProperties(deviceFamily, vo);
+                        vo.setDeviceId(xhsDeviceId);
+                        vo.setBle("小护士设备:" + xhsDeviceId);
+                        vo.setStatus(3);
+                        res.add(vo);
+                        hasDevice = true;
+                    }
+
+                    String newXhsDeviceId = deviceFamily.getNewXhsDeviceId();
+                    if (StringUtils.isNotBlank(newXhsDeviceId)) {
+                        WatchInfoVo vo = new WatchInfoVo();
+                        BeanUtils.copyProperties(deviceFamily, vo);
+                        vo.setDeviceId(newXhsDeviceId);
+                        vo.setBle("小护士手表:" + deviceFamily.getNewXhsDeviceId());
+                        vo.setStatus(3);
+                        res.add(vo);
+                        hasDevice = true;
+                    }
+                    if (!hasDevice) {
+                        WatchInfoVo vo = new WatchInfoVo();
+                        BeanUtils.copyProperties(deviceFamily, vo);
+                        res.add(vo);
                     }
-                    //设备状态
-                    Integer status = deviceInfoService.getStatus(deviceFamily.getDeviceId());
-                    vo.setStatus(status != null ? status : -1);
-                    res.add(vo);
+
                 }
             }
             //自己
@@ -329,7 +361,7 @@ public class WatchUserServiceImpl implements WatchUserService {
                         vo.setName("自己");
                         vo.setRelationship("自己");
 
-                        vo.setDeviceId(deviceId);
+                        vo.setDeviceId(deId);
                         WatchDeviceData deviceData = watchDeviceDataService.getByDeviceId(deId);
                         if (deviceData != null) {
                             vo.setBle(deviceData.getBle());
@@ -340,14 +372,47 @@ public class WatchUserServiceImpl implements WatchUserService {
                         res.add(vo);
                     }
                 }
-            } else {
+            }
+            String xhsDeviceId = user.getXhsDeviceId();
+            if (StringUtils.isNotBlank(xhsDeviceId)) {
+                List<String> xhsDeviceIdList = Arrays.asList(xhsDeviceId.split(","));
+                if (!xhsDeviceIdList.isEmpty()) {
+                    for (String deId : xhsDeviceIdList) {
+                        WatchInfoVo vo = new WatchInfoVo();
+                        vo.setName("自己");
+                        vo.setRelationship("自己");
+
+                        vo.setDeviceId(deId);
+                        vo.setBle("小护士设备:" + deId);
+                        vo.setStatus(3);
+                        res.add(vo);
+                    }
+                }
+            }
+
+            String newXhsDeviceId = user.getNewXhsDeviceId();
+            if (StringUtils.isNotBlank(newXhsDeviceId)) {
+                List<String> newXhsDeviceIdList = Arrays.asList(newXhsDeviceId.split(","));
+                if (!newXhsDeviceIdList.isEmpty()) {
+                    for (String deId : newXhsDeviceIdList) {
+                        WatchInfoVo vo = new WatchInfoVo();
+                        vo.setName("自己");
+                        vo.setRelationship("自己");
+
+                        vo.setDeviceId(deId);
+                        vo.setBle("小护士手表:" + deId);
+                        vo.setStatus(3);
+                        res.add(vo);
+                    }
+                }
+            }
+            if (res.isEmpty()) {
                 WatchInfoVo vo = new WatchInfoVo();
                 vo.setName("自己");
                 vo.setRelationship("自己");
                 //设备状态
                 res.add(vo);
             }
-
         }
         return res;
     }
@@ -362,12 +427,168 @@ public class WatchUserServiceImpl implements WatchUserService {
         return watchUserMapper.getLastTongueByDeviceId(deviceId);
     }
 
+    @Override
+    public R editXHSDevice(HashMap<String, String> param) {
+        String userId = param.get("userId");
+        String xhsDeviceId = param.get("xhsDeviceId");
+        String newXhsDeviceId = param.get("newXhsDeviceId");
+        //查询设备是否已经绑定自己
+        long userIdL = Long.parseLong(userId);
+        //1.编辑绑定设备 ,更新用户表
+        WatchFsUser watchFsUser = selectWatchFsUserById(userIdL);
+        if (watchFsUser == null) {
+            WatchUser watchUser = new WatchUser();
+            watchUser.setUserId(userIdL);
+            if (StringUtils.isNotBlank(xhsDeviceId)) {
+                watchUser.setXhsDeviceId(xhsDeviceId);
+            }
+            if (StringUtils.isNotBlank(newXhsDeviceId)) {
+                watchUser.setNewXhsDeviceId(newXhsDeviceId);
+            }
+            insert(watchUser);
+        } else {
+            if (StringUtils.isNotBlank(xhsDeviceId)) {
+                String deviceId = watchFsUser.getXhsDeviceId();
+                if (StringUtils.isBlank(deviceId)) {
+                    watchFsUser.setXhsDeviceId(xhsDeviceId);
+                } else {
+                    watchFsUser.setXhsDeviceId(deviceId + "," + xhsDeviceId);
+                }
+            }
+            if (StringUtils.isNotBlank(newXhsDeviceId)) {
+                String deviceId = watchFsUser.getNewXhsDeviceId();
+                if (StringUtils.isBlank(deviceId)) {
+                    watchFsUser.setNewXhsDeviceId(newXhsDeviceId);
+                } else {
+                    watchFsUser.setNewXhsDeviceId(deviceId + "," + newXhsDeviceId);
+                }
+            }
+
+            WatchUser watchUser = setWatchUser(watchFsUser);
+            //查询是否含有腕表用户信息
+            updateWatchUser(watchUser);
+        }
+
+
+        //3.添加设备设置信息
+        if (StringUtils.isNotBlank(xhsDeviceId)) {
+            WatchDeviceSetup temp = deviceSetupService.selectDeviceSetupByDeviceId(xhsDeviceId);
+            if (temp == null) {
+                WatchDeviceSetup deviceSetup = new WatchDeviceSetup();
+                deviceSetup.setDeviceId(xhsDeviceId);
+                deviceSetup.setSmartDoctor(0);
+                deviceSetup.setSedentary(JSONUtil.toJsonStr(new DeviceSedentary()));
+                deviceSetup.setFallcheck(0);
+                deviceSetup.setHeartHealth(0);
+                deviceSetup.setHralarm(JSONUtil.toJsonStr(new DeviceHralarm()));
+                deviceSetup.setSpo2alarm(JSONUtil.toJsonStr(new DeviceSpo2alarm()));
+                deviceSetup.setAlarmClock(JSONUtil.toJsonStr(new DeviceAlarmClock()));
+                deviceSetup.setPower(JSONUtil.toJsonStr(new DevicePower()));
+                deviceSetup.setPhonebook(JSONUtil.toJsonStr(new DevicePhonebooks()));
+                deviceSetup.setTime(JSONUtil.toJsonStr(new DeviceTime()));
+                deviceSetup.setLcdgesture(JSONUtil.toJsonStr(new DeviceLcdgesture()));
+                deviceSetup.setUnit(JSONUtil.toJsonStr(new DeviceUnit()));
+                deviceSetup.setMode(JSONUtil.toJsonStr(new DeviceMode()));
+                deviceSetup.setVersion("1.1.0");
+                deviceSetupService.insertDeviceSetup(deviceSetup);
+            }
+        }
+
+        if (StringUtils.isNotBlank(newXhsDeviceId)) {
+            WatchDeviceSetup temp = deviceSetupService.selectDeviceSetupByDeviceId(newXhsDeviceId);
+            if (temp == null) {
+                WatchDeviceSetup deviceSetup = new WatchDeviceSetup();
+                deviceSetup.setDeviceId(newXhsDeviceId);
+                deviceSetup.setSmartDoctor(0);
+                deviceSetup.setSedentary(JSONUtil.toJsonStr(new DeviceSedentary()));
+                deviceSetup.setFallcheck(0);
+                deviceSetup.setHeartHealth(0);
+                deviceSetup.setHralarm(JSONUtil.toJsonStr(new DeviceHralarm()));
+                deviceSetup.setSpo2alarm(JSONUtil.toJsonStr(new DeviceSpo2alarm()));
+                deviceSetup.setAlarmClock(JSONUtil.toJsonStr(new DeviceAlarmClock()));
+                deviceSetup.setPower(JSONUtil.toJsonStr(new DevicePower()));
+                deviceSetup.setPhonebook(JSONUtil.toJsonStr(new DevicePhonebooks()));
+                deviceSetup.setTime(JSONUtil.toJsonStr(new DeviceTime()));
+                deviceSetup.setLcdgesture(JSONUtil.toJsonStr(new DeviceLcdgesture()));
+                deviceSetup.setUnit(JSONUtil.toJsonStr(new DeviceUnit()));
+                deviceSetup.setMode(JSONUtil.toJsonStr(new DeviceMode()));
+                deviceSetup.setVersion("1.1.0");
+                deviceSetupService.insertDeviceSetup(deviceSetup);
+            }
+        }
+        return R.ok("绑定成功!");
+    }
+
+    @Override
+    public R removeXHSDevice(String userId, String xhsDeviceId,String newXhsDeviceId) {
+        //1.编辑绑定设备 ,更新用户表
+        if (StringUtils.isNotBlank(xhsDeviceId) || StringUtils.isNotBlank(newXhsDeviceId)) {
+            Long userIdL = Long.valueOf(userId);
+            //1.1判断该设备是否已经绑定
+            WatchFsUser user = null;
+            if (StringUtils.isNotBlank(xhsDeviceId)) {
+                user = selectWatchFsUserByDeviceIdAndUserId(xhsDeviceId, userIdL, 2);
+            } else if (StringUtils.isNotBlank(newXhsDeviceId)) {
+                user = selectWatchFsUserByDeviceIdAndUserId(newXhsDeviceId, userIdL, 4);
+            }
+
+            if (user == null) {
+                return R.error("该用户未绑定设备:"+xhsDeviceId);
+            }
+            //1.2 解除绑定设备
+            //查询是否有该设备
+            if (StringUtils.isNotBlank(xhsDeviceId)) {
+                String deviceIds = user.getXhsDeviceId();
+
+                List<String> list = Arrays.asList(deviceIds.split(","));
+                if (!list.isEmpty()) {
+                    if (list.contains(xhsDeviceId)) {
+                        list = list.stream().filter(s -> !(xhsDeviceId.equals(s))).collect(Collectors.toList());
+                        StringBuilder newDeviceIds = new StringBuilder();
+                        for (int i = 0; i < list.size(); i++) {
+                            if (i == 0) {
+                                newDeviceIds.append(list.get(i));
+                            } else {
+                                newDeviceIds.append(",").append(list.get(i));
+                            }
+                        }
+                        user.setXhsDeviceId(newDeviceIds.toString());
+                    }
+                }
+            } else if (StringUtils.isNotBlank(newXhsDeviceId)) {
+                String deviceIds = user.getNewXhsDeviceId();
+
+                List<String> list = Arrays.asList(deviceIds.split(","));
+                if (!list.isEmpty()) {
+                    if (list.contains(newXhsDeviceId)) {
+                        list = list.stream().filter(s -> !(newXhsDeviceId.equals(s))).collect(Collectors.toList());
+                        StringBuilder newDeviceIds = new StringBuilder();
+                        for (int i = 0; i < list.size(); i++) {
+                            if (i == 0) {
+                                newDeviceIds.append(list.get(i));
+                            } else {
+                                newDeviceIds.append(",").append(list.get(i));
+                            }
+                        }
+                        user.setNewXhsDeviceId(newDeviceIds.toString());
+                    }
+                }
+            }
+            WatchUser watchUser = new WatchUser();
+            BeanUtils.copyProperties(user, watchUser);
+            updateWatchUser(watchUser);
+            return R.ok("解绑成功!");
+        } else {
+            return R.error("无解绑设备,解绑失败!");
+        }
+    }
+
     /**
      * 查询腕表用户信息
      *
      * @param deviceId
      * @param userId
-     * @param type     0:user 1:familyUser
+     * @param type     0:user 1:familyUser 2:xshUser 3:xhsFamilyUser  4:newXshUser 5:newXhsFamilyUser
      * @return
      */
     @Override
@@ -379,7 +600,7 @@ public class WatchUserServiceImpl implements WatchUserService {
         String phone = watchFsUser.getPhone();
         if (StringUtils.isNotBlank(phone)) {
             if (phone.length() > 13) {
-                watchFsUser.setPhone(PhoneUtil.decryptPhone(phone));
+                watchFsUser.setPhone(PhoneUtil.decryptPhoneMk(phone));
             }
         }
         return watchFsUser;
@@ -391,29 +612,44 @@ public class WatchUserServiceImpl implements WatchUserService {
     }
 
     @Override
-    public AppFsUserVo getUserInfoByDeviceId(String deviceId, Boolean isFamily, Long watchUserId) {
+    public AppFsUserVo getUserInfoByDeviceId(String deviceId, Boolean isFamily, Long watchUserId,Integer deviceType) {
         AppFsUserVo appFsUserVo = new AppFsUserVo();
-        if (isFamily) {
-            WatchFamilyUserVo familyUser = watchFamilyUserService.selectWatchFamilyUserByDeviceId(deviceId, watchUserId);
-            if (familyUser != null) {
-                BeanUtils.copyProperties(familyUser, appFsUserVo);
-                if (familyUser.getBirthday() != null) {
-                    appFsUserVo.setAge(getAge(familyUser.getBirthday()));
-                }
-            }
+        if (StringUtils.isBlank(deviceId)) {
+            //查询原有用户信息
+            FsUser fsUser = fsUserService.selectFsUserByUserId(watchUserId);
+            BeanUtils.copyProperties(fsUser, appFsUserVo);
+            return appFsUserVo;
         } else {
-            //根据设备id获取用户信息
-            WatchFsUser user = selectWatchFsUserByDeviceIdAndUserId(deviceId, watchUserId, 0);
-            if (user != null) {
-                BeanUtils.copyProperties(user, appFsUserVo);
-                if (user.getBirthday() != null) {
-                    //计算年龄
-                    appFsUserVo.setAge(getAge(user.getBirthday()));
+            if (isFamily) {
+                WatchFamilyUserVo familyUser = watchFamilyUserService.selectWatchFamilyUserByDeviceId(deviceId, watchUserId);
+                if (familyUser != null) {
+                    BeanUtils.copyProperties(familyUser, appFsUserVo);
+                    if (familyUser.getBirthday() != null) {
+                        appFsUserVo.setAge(getAge(familyUser.getBirthday()));
+                    }
+                }
+            } else {
+                //根据设备id获取用户信息
+                WatchFsUser user = null;
+                if (deviceType == null || deviceType == 0) {
+                    user = selectWatchFsUserByDeviceIdAndUserId(deviceId, watchUserId, 0);
+                } else if (deviceType == 1) {
+                    user = selectWatchFsUserByDeviceIdAndUserId(deviceId, watchUserId, 2);
+                } else if (deviceType == 2) {
+                    user = selectWatchFsUserByDeviceIdAndUserId(deviceId, watchUserId, 4);
+                }
+
+                if (user != null) {
+                    BeanUtils.copyProperties(user, appFsUserVo);
+                    if (user.getBirthday() != null) {
+                        //计算年龄
+                        appFsUserVo.setAge(getAge(user.getBirthday()));
+                    }
                 }
             }
-        }
 
-        return appFsUserVo;
+            return appFsUserVo;
+        }
     }
 
     private static int getAge(Date birthDate) {

+ 23 - 0
fs-service/src/main/java/com/fs/watch/task/HealthCheckTask.java

@@ -0,0 +1,23 @@
+package com.fs.watch.task;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Supplier;
+
+public class HealthCheckTask {
+    private final String type;
+    private final Supplier<List<Map<String, Object>>> queryFunction;
+
+    public HealthCheckTask(String type, Supplier<List<Map<String, Object>>> queryFunction) {
+        this.type = type;
+        this.queryFunction = queryFunction;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public List<Map<String, Object>> query() {
+        return queryFunction.get();
+    }
+}

+ 207 - 0
fs-service/src/main/java/com/fs/watch/utils/AudioConvertUtil.java

@@ -0,0 +1,207 @@
+package com.fs.watch.utils;
+
+import com.fs.system.oss.CloudStorageService;
+import com.fs.system.oss.OSSFactory;
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+//import static sun.misc.IOUtils.readNBytes;
+
+public class AudioConvertUtil {
+
+    // 之前的方法 convertHardwareCompatibleAudio、uploadFileToCOS 等假设已经存在
+
+    /**
+     * 转换wav到硬件兼容 opuswb,上传到 COS,并删除临时文件
+     *
+     * @param inputWavPath wav 文件路径
+     * @param deviceId 设备ID,用于命名
+     * @param recordTime 录音时间字符串 "yyyy-MM-dd HH:mm:ss"
+     * @param audioBasePath 本地生成音频文件根目录
+     * @return 上传后的 COS URL
+     * @throws Exception 转换或上传失败抛出异常
+     */
+    public static String convertUploadAndClean(
+            String inputWavPath,
+            String deviceId,
+            String recordTime,
+            String audioBasePath) throws Exception {
+
+        // 1. 转换生成硬件兼容 opuswb 文件路径
+        String outputOpuswbPath = convertHardwareCompatibleAudio(inputWavPath, deviceId, recordTime, audioBasePath);
+
+        // 2. 计算上传到云存储的路径 cosPath
+        String datePart = recordTime.substring(0, 10); // 例如 "2025-07-22"
+        String[] ymd = datePart.split("-"); // ["2025", "07", "22"]
+
+        String fileName = deviceId + "-" +
+                recordTime.substring(11, 13) +
+                recordTime.substring(14, 16) +
+                recordTime.substring(17, 19) +
+                ".opuswb";
+
+        String cosPath = String.format("sendAudio/%s%s%s/%s", ymd[0],ymd[1], ymd[2], fileName);
+
+        // 3. 上传文件到云存储
+        try (InputStream inputStream = new FileInputStream(outputOpuswbPath)) {
+            CloudStorageService storage = OSSFactory.build();
+            storage.upload(inputStream, cosPath);
+        }
+
+        // 4. 删除本地临时文件
+        File tempFile = new File(outputOpuswbPath);
+        if (tempFile.exists() && !tempFile.delete()) {
+            System.err.println("临时文件删除失败:" + outputOpuswbPath);
+        }
+
+        // 5. 构造并返回访问URL,示例写法请根据你实际域名修改
+        return "https://cos.his.cdwjyyh.com/" + cosPath;
+    }
+
+
+
+    public static String convertHardwareCompatibleAudio(
+            String inputWavPath, String deviceId, String recordTime, String audioBasePath) throws Exception {
+
+        String subdir = recordTime.substring(0, 10);
+        String dirPath = Paths.get(audioBasePath, subdir).toString();
+        Files.createDirectories(Paths.get(dirPath));
+
+        String fileTimePart = recordTime.substring(11, 13) + recordTime.substring(14, 16) + recordTime.substring(17, 19);
+        String outputOpusFile = Paths.get(dirPath, deviceId + "-" + fileTimePart + ".opus").toString();
+        convertWavToOpus(inputWavPath, outputOpusFile);
+
+        String hardwareOpusFile = Paths.get(dirPath, deviceId + "-" + fileTimePart + ".opuswb").toString();
+        File hwOpus = new File(hardwareOpusFile);
+        if (hwOpus.exists()) hwOpus.delete();
+
+        decodeOggOpusToRawOpus(new File(outputOpusFile), hwOpus);
+
+        return hardwareOpusFile;
+    }
+
+    public static void convertWavToOpus(String inputWavPath, String outputOpusPath) throws IOException, InterruptedException {
+        File outputFile = new File(outputOpusPath);
+        if (outputFile.exists()) {
+            outputFile.delete();
+        }
+        List<String> command = Arrays.asList(
+                "ffmpeg",
+                "-i", inputWavPath,
+                "-c:a", "libopus",
+                "-b:a", "16k",
+                "-ar", "16000",
+                "-ac", "1",
+                "-vbr", "off",
+                "-frame_duration", "20",
+                "-application", "voip",
+                outputOpusPath
+        );
+        ProcessBuilder pb = new ProcessBuilder(command);
+        Process process = pb.start();
+        int exitCode = process.waitFor();
+        if (exitCode != 0) {
+            try (BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
+                String line;
+                while ((line = errorReader.readLine()) != null) {
+                    System.err.println(line);
+                }
+            }
+            throw new RuntimeException("ffmpeg 转码失败");
+        }
+    }
+
+    public static void decodeOggOpusToRawOpus(File inputFile, File outputFile) throws IOException {
+        try (InputStream in = new FileInputStream(inputFile);
+             OutputStream out = new FileOutputStream(outputFile)) {
+
+            int packetsSkipped = 0;
+            byte[] headerBuf = new byte[27];
+            while (true) {
+                int readBytes = in.read(headerBuf);
+                if (readBytes < 27) break;
+
+                if (!(headerBuf[0] == 'O' && headerBuf[1] == 'g' && headerBuf[2] == 'g' && headerBuf[3] == 'S')) {
+                    throw new IOException("Invalid Ogg file");
+                }
+
+                int segments = headerBuf[26] & 0xFF;
+                byte[] lacingValues = new byte[segments];
+                if (in.read(lacingValues) < segments) break;
+
+                List<Integer> packetSizes = new ArrayList<>();
+                int currentSize = 0;
+                for (byte b : lacingValues) {
+                    currentSize += (b & 0xFF);
+                    if ((b & 0xFF) < 255) {
+                        packetSizes.add(currentSize);
+                        currentSize = 0;
+                    }
+                }
+
+                for (int size : packetSizes) {
+                    byte[] packet = readNBytes(in,size);
+
+                    if (packetsSkipped < 2) {
+                        packetsSkipped++;
+                        continue;
+                    }
+
+                    out.write(ByteBuffer.allocate(4).putInt(size).array());
+                    out.write(ByteBuffer.allocate(4).putInt(size).array());
+                    out.write(packet);
+                }
+            }
+        }
+    }
+
+    /**
+     * 从输入流中读取最多 len 个字节,返回读取到的字节数组(等价于 readNBytes)
+     * @param in 输入流(如 FileInputStream、ByteArrayInputStream)
+     * @param len 要读取的最大字节数
+     * @return 实际读取到的字节数组
+     * @throws IOException 读取 IO 异常
+     */
+    public static byte[] readNBytes(InputStream in, int len) throws IOException {
+        // 参数合法性校验
+        if (len < 0) {
+            throw new IllegalArgumentException("读取字节长度不能为负数");
+        }
+        if (in == null) {
+            throw new NullPointerException("输入流不能为 null");
+        }
+
+        byte[] buffer = new byte[len];
+        int totalReadBytes = 0; // 累计已读取的字节数
+
+        // 循环读取,直到读取到指定长度或输入流结束
+        while (totalReadBytes < len) {
+            // 每次读取剩余未完成的字节数
+            int readBytes = in.read(buffer, totalReadBytes, len - totalReadBytes);
+
+            // 输入流已到达末尾(返回 -1),终止循环
+            if (readBytes == -1) {
+                break;
+            }
+
+            totalReadBytes += readBytes;
+        }
+
+        // 若实际读取的字节数小于指定长度,截取有效字节数组返回
+        if (totalReadBytes < len) {
+            byte[] result = new byte[totalReadBytes];
+            System.arraycopy(buffer, 0, result, 0, totalReadBytes);
+            return result;
+        }
+
+        return buffer;
+    }
+
+}
+

+ 53 - 0
fs-service/src/main/java/com/fs/watch/utils/MD5Utils.java

@@ -0,0 +1,53 @@
+package com.fs.watch.utils;
+
+import com.alibaba.fastjson.JSONObject;
+
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.net.URL;
+import java.security.MessageDigest;
+
+public class MD5Utils {
+    public static String  getFileMD5FromURL(String fileUrl) {
+        try (InputStream is = new URL(fileUrl).openStream()) {
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            byte[] buffer = new byte[8192];
+            int bytesRead;
+
+            while ((bytesRead = is.read(buffer)) != -1) {
+                md.update(buffer, 0, bytesRead);
+            }
+
+            byte[] digest = md.digest();
+            // 转换为 32 位小写十六进制字符串
+            return String.format("%032x", new BigInteger(1, digest));
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    // 计算文件 MD5 并返回字节数和 MD5 值
+    public static JSONObject getMd5AndSizeFromUrl(String fileUrl) {
+        JSONObject result = new JSONObject();
+        try (InputStream is = new URL(fileUrl).openStream()) {
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            byte[] buffer = new byte[8192];
+            int bytesRead;
+            long totalSize = 0;
+
+            while ((bytesRead = is.read(buffer)) != -1) {
+                md.update(buffer, 0, bytesRead);
+                totalSize += bytesRead;
+            }
+
+            byte[] digest = md.digest();
+            String md5 = String.format("%032x", new BigInteger(1, digest));
+            result.put("md5", md5);
+            result.put("size", totalSize);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return result;
+    }
+}

+ 1 - 2
fs-service/src/main/java/com/fs/watch/utils/MyDateTimeUtils.java

@@ -1,15 +1,14 @@
 package com.fs.watch.utils;
 
 
-
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.time.Duration;
 import java.time.LocalDateTime;
+import java.time.ZoneId;
 import java.time.format.DateTimeFormatter;
 import java.util.Date;
 import java.util.TimeZone;
-import java.time.ZoneId;
 
 public class MyDateTimeUtils {
 

+ 42 - 12
fs-service/src/main/java/com/fs/watch/utils/MyHttpUtils.java

@@ -173,7 +173,8 @@ public class MyHttpUtils {
         //创建post方式请求对象
         HttpPost httpPost = new HttpPost(path);
         //创建httpclient对象
-        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+        CloseableHttpClient httpClient = HttpClients.createDefault();
+        try {
             Map<String, Object> resMap = getObjectMap(params, httpPost, httpClient);
             if ((int) resMap.get("ReturnCode") == 0) {
                 return JSONObject.parseObject(resMap.get("Data").toString(), HashMap.class);
@@ -181,9 +182,15 @@ public class MyHttpUtils {
                 return null;
             }
         } catch (Exception e) {
-            System.out.println(e.getMessage());
+
+        } finally {
+            //释放连接
+            try {
+                httpClient.close();
+            } catch (Exception e) {
+
+            }
         }
-        //释放连接
         return null;
     }
 
@@ -194,20 +201,29 @@ public class MyHttpUtils {
         //创建post方式请求对象
         HttpPost httpPost = new HttpPost(path);
         //创建httpclient对象
-        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+        CloseableHttpClient httpClient = HttpClients.createDefault();
+        try {
             Map<String, Object> resMap = getObjectMap(params, httpPost, httpClient);
             if ((int) resMap.get("ReturnCode") == 0) {
                 if (resMap.get("Data") == null) {
                     return JSONObject.parseObject(resMap.get("data").toString(), HashMap.class);
                 }
                 return JSONObject.parseObject(resMap.get("Data").toString(), HashMap.class);
+            } else if (Integer.parseInt(resMap.get("ReturnCode").toString()) == 10403 && "the device_id not belong to you".equals(resMap.get("message").toString())){
+                return resMap;
             } else {
                 return null;
             }
         } catch (Exception e) {
-            System.out.println(e.getMessage());
+            log.info(e.getMessage());
+        } finally {
+            //释放连接
+            try {
+                httpClient.close();
+            } catch (Exception e) {
+
+            }
         }
-        //释放连接
         return null;
     }
 
@@ -219,7 +235,8 @@ public class MyHttpUtils {
         //创建post方式请求对象
         HttpPost httpPost = new HttpPost(path);
         //创建httpclient对象
-        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+        CloseableHttpClient httpClient = HttpClients.createDefault();
+        try {
             BasicResponseHandler handler = new BasicResponseHandler();
             //设置请求格式
             String jsonData = JSONObject.toJSONString(params);
@@ -232,9 +249,15 @@ public class MyHttpUtils {
             Map<String, Object> resMap = JSONObject.parseObject(result, HashMap.class);
             return resMap;
         } catch (Exception e) {
-            System.out.println(e.getMessage());
+
+        } finally {
+            //释放连接
+            try {
+                httpClient.close();
+            } catch (Exception e) {
+
+            }
         }
-        //释放连接
         return null;
     }
 
@@ -244,7 +267,8 @@ public class MyHttpUtils {
         //创建post方式请求对象
         HttpDelete httpDelete = new HttpDelete(path);
         // 创建HTTP客户端
-        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+        CloseableHttpClient httpClient = HttpClients.createDefault();
+        try {
 //            BasicResponseHandler handler = new BasicResponseHandler();
 //            //设置请求格式
 //            String jsonData = JSONObject.toJSONString(params);
@@ -259,9 +283,15 @@ public class MyHttpUtils {
             result.put("message", responseBody.get("msg"));
             return result;
         } catch (Exception e) {
-            System.out.println(e.getMessage());
+
+        } finally {
+            //释放连接
+            try {
+                httpClient.close();
+            } catch (Exception e) {
+
+            }
         }
-        //释放连接
         return null;
     }
 

+ 165 - 152
fs-service/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml

@@ -63,14 +63,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         cu.nick_name as company_user_name ,l.send_type,l.create_time,l.update_time,l.last_heartbeat_time,
         qu.qw_user_name,qec.name as external_user_name,c.company_id,u.avatar as fsAvatar,u.nick_name as fsNickName,qec.create_time as qec_create_time,
         u.is_vip isVip,l.reward_type
-         from fs_course_watch_log l
-         left join fs_user_course_video v on v.video_id = l.video_id
-         left join fs_user_course uc on uc.course_id = l.course_id
-         left join fs_user u on u.user_id = l.user_id
-         left join company_user cu on cu.user_id = l.company_user_id
-         left join company c on c.company_id = l.company_id
-         LEFT JOIN qw_user qu on qu.id= l.qw_user_id
-         LEFT JOIN qw_external_contact qec on l.qw_external_contact_id = qec.id
+        from fs_course_watch_log l
+        left join fs_user_course_video v on v.video_id = l.video_id
+        left join fs_user_course uc on uc.course_id = l.course_id
+        left join fs_user u on u.user_id = l.user_id
+        left join company_user cu on cu.user_id = l.company_user_id
+        left join company c on c.company_id = l.company_id
+        LEFT JOIN qw_user qu on qu.id= l.qw_user_id
+        LEFT JOIN qw_external_contact qec on l.qw_external_contact_id = qec.id
         <where>
             <if test ='maps.isVip != null and maps.isVip == 0'>
                 and (l.user_id = 0 or l.user_id is null)
@@ -172,8 +172,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                     #{item}
                 </foreach>
             </if>
+            ${maps.params.dataScope}
         </where>
-         order by l.finish_time desc,l.update_time desc,l.create_time desc
+        order by l.finish_time desc,l.update_time desc,l.create_time desc
     </select>
 
     <select id="selectFsCourseWatchLogListByParam" resultType="com.fs.course.vo.FsCourseWatchLogListVO">
@@ -596,7 +597,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         GROUP BY o.video_id,o.user_id,DATE(o.create_time),o.project,o.course_id
         ORDER BY o.video_id ,DATE(o.create_time)
 
-<!--        limit ${(pageNum-1)*pageSize},${pageSize}-->
+        <!--        limit ${(pageNum-1)*pageSize},${pageSize}-->
     </select>
     <select id="selectFsCourseWatchLogStatisticsListVONewCount" resultType="java.lang.Long">
         SELECT COUNT(*)
@@ -948,30 +949,30 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                     #{periodId}
                 </foreach>
             </if>
-
+            ${maps.params.dataScope}
         </where>
         order by l.finish_time desc,l.update_time desc,l.create_time desc
     </select>
 
     <select id="getWatchCourseByVideoId" resultType="com.fs.course.domain.FsCourseWatchLog">
         SELECT
-            *
+        *
         FROM
-            fs_course_watch_log
+        fs_course_watch_log
         WHERE
-            send_type = 1
-          AND video_id = #{videoId}
-          AND user_id in
-            <foreach item="userId" index="index" collection="userIds" open="(" separator="," close=")">
-                #{userId}
-            </foreach>
+        send_type = 1
+        AND video_id = #{videoId}
+        AND user_id in
+        <foreach item="userId" index="index" collection="userIds" open="(" separator="," close=")">
+            #{userId}
+        </foreach>
         ORDER BY
-            log_id DESC
+        log_id DESC
     </select>
     <select id="getUserCountByCampId" resultType="java.lang.Integer">
         select count(distinct cwl.user_id)
         from fs_user_course_period ucp
-        inner join fs_course_watch_log cwl on ucp.period_id = cwl.period_id
+                 inner join fs_course_watch_log cwl on ucp.period_id = cwl.period_id
         where ucp.training_camp_id = #{trainingCampId}
     </select>
 
@@ -1016,11 +1017,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             </if>
         </where>
         GROUP BY
-            DATE (o.create_time),
-            o.company_id
+        DATE (o.create_time),
+        o.company_id
         ORDER BY
         comp.company_id,
-            DATE (o.create_time)
+        DATE (o.create_time)
     </select>
     <select id="selectQwFsCourseWatchLogStatisticsListVO"
             resultType="com.fs.course.vo.FsCourseWatchLogStatisticsListVO" parameterType="com.fs.qw.param.QwSidebarStatsParam">
@@ -1069,10 +1070,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             COUNT(DISTINCT CASE WHEN o.log_type = 2 THEN o.user_id END) AS finishUserCount
         FROM
             fs_course_watch_log o
-            LEFT JOIN company c ON c.company_id = o.company_id
+                LEFT JOIN company c ON c.company_id = o.company_id
         WHERE
             o.create_time &gt;= #{params.startTime}
-            AND o.create_time &lt;= #{params.endTime}
+          AND o.create_time &lt;= #{params.endTime}
         GROUP BY
             o.company_id,
             o.send_type
@@ -1150,25 +1151,25 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </select>
     <select id="selectWatchStatsByUserIds" resultType="com.fs.his.vo.FsUserReportVO">
         SELECT
-            user_id AS userId,
-            company_user_id AS companyUserId,
-            MAX(
-                    COALESCE ( update_time, create_time )) AS lastWatchTime,
-            COUNT( log_id ) AS watchCount,
-            COUNT( DISTINCT period_id ) AS periodCount,
-            CASE
-                ( SELECT log_type FROM fs_course_watch_log w2 WHERE w2.user_id = w1.user_id ORDER BY create_time DESC LIMIT 1 )
-		WHEN '1' THEN
-		'看课中'
-		WHEN '2' THEN
-		'完课'
-		WHEN '3' THEN
-		'待看课'
-		WHEN '4' THEN
-		'看课中断' ELSE '无'
+        user_id AS userId,
+        company_user_id AS companyUserId,
+        MAX(
+        COALESCE ( update_time, create_time )) AS lastWatchTime,
+        COUNT( log_id ) AS watchCount,
+        COUNT( DISTINCT period_id ) AS periodCount,
+        CASE
+        ( SELECT log_type FROM fs_course_watch_log w2 WHERE w2.user_id = w1.user_id ORDER BY create_time DESC LIMIT 1 )
+        WHEN '1' THEN
+        '看课中'
+        WHEN '2' THEN
+        '完课'
+        WHEN '3' THEN
+        '待看课'
+        WHEN '4' THEN
+        '看课中断' ELSE '无'
         END AS watchStatus
-FROM
-	fs_course_watch_log w1
+        FROM
+        fs_course_watch_log w1
         WHERE (user_id, company_user_id) IN
         <foreach collection="userConditions" item="condition" open="(" close=")" separator=",">
             (#{condition.userId}, #{condition.companyUserId})
@@ -1199,7 +1200,7 @@ FROM
         SUM(amount) AS receivedAmount
         FROM fs_course_red_packet_log
         WHERE status = 1
-         and (user_id, company_user_id) IN
+        and (user_id, company_user_id) IN
         <foreach collection="userConditions" item="condition" open="(" close=")" separator=",">
             (#{condition.userId}, #{condition.companyUserId})
         </foreach>
@@ -1256,7 +1257,7 @@ FROM
         LEFT JOIN fs_user_course_video cv ON log.video_id = cv.video_id
         WHERE log.send_type =1 and log.watch_type = 2
         <include refid="commonConditions"/>
-         <if test="orderSTime != null and orderETime != null">
+        <if test="orderSTime != null and orderETime != null">
             AND DATE(po.create_time) BETWEEN #{orderSTime} AND #{orderETime}
         </if>
         group by log.user_id
@@ -1326,30 +1327,33 @@ FROM
         <if test="nickName != null and nickName != ''">
             AND u.nick_name LIKE CONCAT('%', #{nickName}, '%')
         </if>
+        <if test="params.dataScope != null and params.dataScope != ''">
+            ${params.dataScope}
+        </if>
         GROUP BY cu.user_id
 
     </select>
-        <select id="selectCompanyBaseData" resultType="com.fs.his.vo.WatchLogReportVO">
-            SELECT
-            log.user_id userId,
-            log.period_id periodId,
-            log.log_id logId,
-            log.create_time courseTime,
-            d.dept_id AS deptId,
-            d.dept_name AS salesDept,
-            c.company_name AS salesCompany,
-            COUNT(DISTINCT cu.user_id) AS salesCount,
-            COUNT(DISTINCT u.user_id) AS userCount,
-            COUNT(DISTINCT CASE WHEN u.STATUS = 1 THEN u.user_id END) AS onlineUserCount,
-            cv.title videoTitle,
-            COUNT(DISTINCT log.log_id) AS totalLogCount,
-            COUNT(DISTINCT CASE WHEN log.log_type = '2' THEN log.log_id END) AS finishedCount,
-            COUNT(DISTINCT CASE WHEN log.log_type IN ('1', '3', '4') THEN log.log_id END) AS unfinishedCount,
-            COUNT(DISTINCT log.user_id) - COUNT(DISTINCT CASE WHEN log.log_type = '2' THEN log.user_id END) AS notWatchedCount
-            FROM fs_course_watch_log log
-            <if test="orderSTime != null and orderETime != null">
-                LEFT JOIN fs_package_order po ON po.user_id = log.user_id
-            </if>
+    <select id="selectCompanyBaseData" resultType="com.fs.his.vo.WatchLogReportVO">
+        SELECT
+        log.user_id userId,
+        log.period_id periodId,
+        log.log_id logId,
+        log.create_time courseTime,
+        d.dept_id AS deptId,
+        d.dept_name AS salesDept,
+        c.company_name AS salesCompany,
+        COUNT(DISTINCT cu.user_id) AS salesCount,
+        COUNT(DISTINCT u.user_id) AS userCount,
+        COUNT(DISTINCT CASE WHEN u.STATUS = 1 THEN u.user_id END) AS onlineUserCount,
+        cv.title videoTitle,
+        COUNT(DISTINCT log.log_id) AS totalLogCount,
+        COUNT(DISTINCT CASE WHEN log.log_type = '2' THEN log.log_id END) AS finishedCount,
+        COUNT(DISTINCT CASE WHEN log.log_type IN ('1', '3', '4') THEN log.log_id END) AS unfinishedCount,
+        COUNT(DISTINCT log.user_id) - COUNT(DISTINCT CASE WHEN log.log_type = '2' THEN log.user_id END) AS notWatchedCount
+        FROM fs_course_watch_log log
+        <if test="orderSTime != null and orderETime != null">
+            LEFT JOIN fs_package_order po ON po.user_id = log.user_id
+        </if>
         LEFT JOIN company_user cu ON log.company_user_id = cu.user_id
         LEFT JOIN fs_user u on log.user_id= u.user_id
         LEFT JOIN company_dept d ON cu.dept_id = d.dept_id
@@ -1366,7 +1370,7 @@ FROM
         <if test="companyId != null and companyId != ''">
             AND c.company_id = #{companyId}
         </if>
-          <!--部门 -->
+        <!--部门 -->
         <if test="deptId != null and deptId != ''">
             AND d.dept_id = #{deptId}
         </if>
@@ -1393,6 +1397,9 @@ FROM
         <if test="nickName != null and nickName != ''">
             AND u.nick_name LIKE CONCAT('%', #{nickName}, '%')
         </if>
+        <if test="params.dataScope != null and params.dataScope != ''">
+            ${params.dataScope}
+        </if>
         GROUP BY d.dept_id
     </select>
     <select id="selectUserWatchDetails" resultType="com.fs.his.vo.WatchLogReportVO">
@@ -1869,17 +1876,17 @@ FROM
     <!-- 公司维度合并查询(基础数据+统计数据) -->
     <select id="selectCompanyDeptStatsMerged" resultType="com.fs.his.vo.WatchLogReportVO">
         SELECT
-            d.dept_id AS deptId,
-            d.dept_name AS salesDept,
-            c.company_name AS salesCompany,
-            COUNT(DISTINCT cu.user_id) AS salesCount,
-            COUNT(DISTINCT u.user_id) AS userCount,
-            COUNT(DISTINCT CASE WHEN u.STATUS = 1 THEN u.user_id END) AS onlineUserCount,
-            COUNT(DISTINCT log.log_id) AS totalLogCount,
-            COUNT(DISTINCT CASE WHEN log.log_type = '2' THEN log.log_id END) AS finishedCount,
-            COUNT(DISTINCT CASE WHEN log.log_type IN ('1', '3', '4') THEN log.log_id END) AS unfinishedCount,
-            COUNT(DISTINCT log.user_id) - COUNT(DISTINCT CASE WHEN log.log_type = '2' THEN log.user_id END) AS notWatchedCount,
-            COUNT(DISTINCT log.log_id) - COUNT(DISTINCT a.watch_log_id) AS notAnsweredCount
+        d.dept_id AS deptId,
+        d.dept_name AS salesDept,
+        c.company_name AS salesCompany,
+        COUNT(DISTINCT cu.user_id) AS salesCount,
+        COUNT(DISTINCT u.user_id) AS userCount,
+        COUNT(DISTINCT CASE WHEN u.STATUS = 1 THEN u.user_id END) AS onlineUserCount,
+        COUNT(DISTINCT log.log_id) AS totalLogCount,
+        COUNT(DISTINCT CASE WHEN log.log_type = '2' THEN log.log_id END) AS finishedCount,
+        COUNT(DISTINCT CASE WHEN log.log_type IN ('1', '3', '4') THEN log.log_id END) AS unfinishedCount,
+        COUNT(DISTINCT log.user_id) - COUNT(DISTINCT CASE WHEN log.log_type = '2' THEN log.user_id END) AS notWatchedCount,
+        COUNT(DISTINCT log.log_id) - COUNT(DISTINCT a.watch_log_id) AS notAnsweredCount
         FROM fs_course_watch_log log
         LEFT JOIN company_user cu ON log.company_user_id = cu.user_id
         LEFT JOIN fs_user u ON log.user_id = u.user_id
@@ -1914,6 +1921,9 @@ FROM
         <if test="nickName != null and nickName != ''">
             AND u.nick_name LIKE CONCAT('%', #{nickName}, '%')
         </if>
+        <if test="params.dataScope != null and params.dataScope != ''">
+            ${params.dataScope}
+        </if>
         GROUP BY d.dept_id
     </select>
 
@@ -2069,19 +2079,19 @@ FROM
         ON camp.training_camp_id = period.training_camp_id
         LEFT JOIN company c
         ON FIND_IN_SET(c.company_id, period.company_id) > 0
-       <where>
-        <!-- 只有当传入公司ID参数时才筛选公司 -->
-        <if test="companyId != null">
-            c.company_id = #{companyId}
-        </if>
-        <!-- 训练营 -->
-        <if test="trainingCampId != null and trainingCampId != ''">
-            AND period.training_camp_id= #{trainingCampId}
-        </if>
-        <!-- 营期 -->
-        <if test="periodId != null and periodId != ''">
-            AND period.period_id = #{periodId}
-        </if>
+        <where>
+            <!-- 只有当传入公司ID参数时才筛选公司 -->
+            <if test="companyId != null">
+                c.company_id = #{companyId}
+            </if>
+            <!-- 训练营 -->
+            <if test="trainingCampId != null and trainingCampId != ''">
+                AND period.training_camp_id= #{trainingCampId}
+            </if>
+            <!-- 营期 -->
+            <if test="periodId != null and periodId != ''">
+                AND period.period_id = #{periodId}
+            </if>
         </where>
         ORDER BY period.create_time DESC
     </select>
@@ -2097,12 +2107,12 @@ FROM
     </select>
     <select id="selectAppWatchStatistics" resultType="com.fs.his.vo.AppCourseReportVO">
         SELECT
-            log_id logId,
-            company_id AS companyId,
-                COUNT(CASE WHEN log_type = 3 THEN log_id END) AS pendingCount,
-                COUNT(CASE WHEN log_type = 1 THEN log_id END) AS watchingCount,
-                COUNT(CASE WHEN log_type = 2 THEN log_id END) AS finishedCount,
-                count(log_id) as accessCount
+        log_id logId,
+        company_id AS companyId,
+        COUNT(CASE WHEN log_type = 3 THEN log_id END) AS pendingCount,
+        COUNT(CASE WHEN log_type = 1 THEN log_id END) AS watchingCount,
+        COUNT(CASE WHEN log_type = 2 THEN log_id END) AS finishedCount,
+        count(log_id) as accessCount
         FROM fs_course_watch_log
         <where>
             watch_type =1 and send_type = 1
@@ -2120,8 +2130,8 @@ FROM
     </select>
     <select id="selectAppAnswerStatistics" resultType="com.fs.his.vo.AppCourseReportVO">
         SELECT
-            l.company_id AS companyId,
-            COUNT( l.log_id) AS answerUserCount
+        l.company_id AS companyId,
+        COUNT( l.log_id) AS answerUserCount
         FROM fs_course_answer_logs l
         LEFT JOIN fs_course_watch_log a on l.watch_log_id=a.log_id
         WHERE l.company_id IN
@@ -2228,12 +2238,15 @@ FROM
         <if test="nickName != null and nickName != ''">
             AND u.nick_name LIKE CONCAT('%', #{nickName}, '%')
         </if>
+        <if test="params.dataScope != null and params.dataScope != ''">
+            ${params.dataScope}
+        </if>
     </sql>
 
     <!-- 销售维度APP会员数统计(直接查fs_user表) -->
     <select id="selectAppSalesUserStats" resultType="com.fs.his.vo.AppSalesWatchLogReportVO">
         SELECT
-            cu.user_id AS salesId,
+        cu.user_id AS salesId,
         COUNT(DISTINCT CASE WHEN (u.source IS NOT NULL AND u.source != '') OR (u.login_device IS NOT NULL AND u.login_device != '') OR u.app_create_time IS NOT NULL THEN u.user_id END) AS appUserCount,
         <choose>
             <when test="startDate != null and startDate != '' and endDate != null and endDate != ''">
@@ -2248,9 +2261,9 @@ FROM
         INNER JOIN company_user cu ON cuu.company_user_id = cu.user_id
         INNER JOIN company c ON cuu.company_id = c.company_id
         WHERE ((u.source IS NOT NULL AND u.source != '') OR (u.login_device IS NOT NULL AND u.login_device != '') OR u.app_create_time IS NOT NULL)
-          AND u.status = 1
-          AND u.is_del=0
-          AND cuu.status IN (0, 1)
+        AND u.status = 1
+        AND u.is_del=0
+        AND cuu.status IN (0, 1)
         <if test="companyId != null and companyId != ''">
             AND cuu.company_id = #{companyId}
         </if>
@@ -2267,21 +2280,21 @@ FROM
     </select>
 
     <!-- 销售维度基础数据+看课统计(合并查询) -->
-        <select id="selectAppSalesWatchStats" resultType="com.fs.his.vo.AppSalesWatchLogReportVO">
+    <select id="selectAppSalesWatchStats" resultType="com.fs.his.vo.AppSalesWatchLogReportVO">
         SELECT
-            cu.user_id AS salesId,
-            cu.nick_name AS salesName,
-            cd.dept_name AS salesDept,
-            c.company_name AS salesCompany,
-            cd.dept_id AS deptId,
-            c.company_id AS companyId,
-            COUNT( CASE WHEN log.log_type = 2 THEN log.log_id END ) AS finishedCount,
-            COUNT(log.log_id)- COUNT(CASE WHEN log.log_type = 2 THEN log.log_id END )AS unfinishedCount,
-            COUNT( CASE WHEN log.log_type = 3 THEN log.log_id END ) AS notWatchedCount,
-            COUNT( a.watch_log_id ) answeredCount,
-            COALESCE ( SUM( rpl.amount ), 0 ) AS redPacketAmount,
-            COUNT( rpl.log_id) AS packetUserCount
-            FROM fs_course_watch_log log
+        cu.user_id AS salesId,
+        cu.nick_name AS salesName,
+        cd.dept_name AS salesDept,
+        c.company_name AS salesCompany,
+        cd.dept_id AS deptId,
+        c.company_id AS companyId,
+        COUNT( CASE WHEN log.log_type = 2 THEN log.log_id END ) AS finishedCount,
+        COUNT(log.log_id)- COUNT(CASE WHEN log.log_type = 2 THEN log.log_id END )AS unfinishedCount,
+        COUNT( CASE WHEN log.log_type = 3 THEN log.log_id END ) AS notWatchedCount,
+        COUNT( a.watch_log_id ) answeredCount,
+        COALESCE ( SUM( rpl.amount ), 0 ) AS redPacketAmount,
+        COUNT( rpl.log_id) AS packetUserCount
+        FROM fs_course_watch_log log
         LEFT JOIN company_user cu ON log.company_user_id = cu.user_id
         LEFT JOIN company c ON log.company_id = c.company_id
         LEFT JOIN company_dept cd ON cu.dept_id = cd.dept_id
@@ -2297,10 +2310,10 @@ FROM
     <!-- 销售维度订单统计 -->
     <select id="selectAppSalesOrderStats" resultType="com.fs.his.vo.AppSalesWatchLogReportVO">
         SELECT
-            cu.user_id AS salesId,
-            log.period_id AS periodId,
-            log.video_id AS videoId,
-            COUNT(DISTINCT CASE WHEN po.status = 3 THEN po.order_id END) AS historyOrderCount
+        cu.user_id AS salesId,
+        log.period_id AS periodId,
+        log.video_id AS videoId,
+        COUNT(DISTINCT CASE WHEN po.status = 3 THEN po.order_id END) AS historyOrderCount
         FROM fs_course_watch_log log
         LEFT JOIN company_user cu ON log.company_user_id = cu.user_id
         LEFT JOIN company c ON log.company_id = c.company_id
@@ -2349,8 +2362,8 @@ FROM
         WHERE ((u.source IS NOT NULL AND u.source != '') OR (u.login_device IS NOT NULL AND u.login_device != '') OR u.app_create_time IS NOT NULL)
         AND u.status = 1
         and u.is_del=0
-          AND u.status = 1
-          AND cuu.status IN (0, 1)
+        AND u.status = 1
+        AND cuu.status IN (0, 1)
         <if test="companyId != null and companyId != ''">
             AND cuu.company_id = #{companyId}
         </if>
@@ -2396,10 +2409,10 @@ FROM
     <!-- 销售部门维度订单统计 -->
     <select id="selectAppDeptOrderStats" resultType="com.fs.his.vo.AppSalesWatchLogReportVO">
         SELECT
-            cd.dept_id AS deptId,
-            log.period_id AS periodId,
-            log.video_id AS videoId,
-            COUNT(DISTINCT CASE WHEN po.status = 3 THEN po.order_id END) AS historyOrderCount
+        cd.dept_id AS deptId,
+        log.period_id AS periodId,
+        log.video_id AS videoId,
+        COUNT(DISTINCT CASE WHEN po.status = 3 THEN po.order_id END) AS historyOrderCount
         FROM fs_course_watch_log log
         LEFT JOIN company_user cu ON log.company_user_id = cu.user_id
         LEFT JOIN company c ON log.company_id = c.company_id
@@ -2414,18 +2427,18 @@ FROM
     <!-- APP用户看课记录列表 -->
     <select id="selectAppUserWatchLogList" resultType="com.fs.course.vo.AppUserWatchLogVO">
         SELECT
-            l.log_id AS logId,
-            l.course_id AS courseId,
-            c.course_name AS courseName,
-            c.img_url as imgUrl,
-            l.video_id AS videoId,
-            v.title AS videoName,
-            l.log_type AS logType,
-            l.duration AS duration,
-            SEC_TO_TIME(l.duration) AS durationFormat,
-            l.create_time AS createTime,
-            l.finish_time AS finishTime,
-            l.watch_type AS watchType
+        l.log_id AS logId,
+        l.course_id AS courseId,
+        c.course_name AS courseName,
+        c.img_url as imgUrl,
+        l.video_id AS videoId,
+        v.title AS videoName,
+        l.log_type AS logType,
+        l.duration AS duration,
+        SEC_TO_TIME(l.duration) AS durationFormat,
+        l.create_time AS createTime,
+        l.finish_time AS finishTime,
+        l.watch_type AS watchType
         FROM fs_course_watch_log l
         LEFT JOIN fs_user_course c ON l.course_id = c.course_id
         LEFT JOIN fs_user_course_video v ON l.video_id = v.video_id
@@ -2472,21 +2485,21 @@ FROM
             pd.id as periodDaysId,
             pd.end_date_time AS endDateTime
         FROM fs_course_watch_log l
-        LEFT JOIN fs_user_course c ON l.course_id = c.course_id
-        LEFT JOIN fs_user_course_video v ON l.video_id = v.video_id
-        LEFT JOIN fs_user_course_period_days pd ON l.video_id = pd.video_id AND l.period_id = pd.period_id and pd.del_flag=0
-        LEFT JOIN fs_user_course_period p ON l.period_id = p.period_id
+                 LEFT JOIN fs_user_course c ON l.course_id = c.course_id
+                 LEFT JOIN fs_user_course_video v ON l.video_id = v.video_id
+                 LEFT JOIN fs_user_course_period_days pd ON l.video_id = pd.video_id AND l.period_id = pd.period_id and pd.del_flag=0
+                 LEFT JOIN fs_user_course_period p ON l.period_id = p.period_id
         WHERE l.user_id = #{userId}
-        AND l.watch_type = 1
-        AND l.send_type = 1
-        AND l.create_time &gt;= CURDATE()
-        AND l.create_time &lt; DATE_ADD(CURDATE(), INTERVAL 1 DAY)
-        AND l.log_type &lt;&gt; 2
-        AND NOT EXISTS (
+          AND l.watch_type = 1
+          AND l.send_type = 1
+          AND l.create_time &gt;= CURDATE()
+          AND l.create_time &lt; DATE_ADD(CURDATE(), INTERVAL 1 DAY)
+          AND l.log_type &lt;&gt; 2
+          AND NOT EXISTS (
             SELECT 1 FROM fs_course_watch_log f
             WHERE f.user_id = l.user_id
-            AND f.video_id = l.video_id
-            AND f.log_type = 2
+              AND f.video_id = l.video_id
+              AND f.log_type = 2
         )
         GROUP BY l.course_id
         ORDER BY l.create_time DESC

+ 136 - 0
fs-service/src/main/resources/mapper/his/FsHealthPulseMapper.xml

@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.his.mapper.FsHealthPulseMapper">
+
+    <resultMap type="FsHealthPulse" id="FsHealthPulseResult">
+        <result property="id"    column="id"    />
+        <result property="userId"    column="user_id"    />
+        <result property="name"    column="name"    />
+        <result property="sex"    column="sex"    />
+        <result property="age"    column="age"    />
+        <result property="status"    column="status"    />
+        <result property="leftHandResult"    column="left_hand_result"    />
+        <result property="rightHandResult"    column="right_hand_result"    />
+        <result property="pulseSummary"    column="pulse_summary"    />
+        <result property="pulseSuggestions"    column="pulse_suggestions"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="remark"    column="remark"    />
+        <result property="measureId"    column="measure_id"    />
+        <result property="pulseUrl"    column="pulse_url"    />
+    </resultMap>
+
+    <sql id="selectFsHealthPulseVo">
+        select id, user_id, name, sex, age, status, left_hand_result, right_hand_result, pulse_summary, pulse_suggestions, create_time, remark, measure_id,pulse_url from fs_health_pulse
+    </sql>
+
+    <select id="selectFsHealthPulseList" parameterType="FsHealthPulse" resultMap="FsHealthPulseResult">
+        <include refid="selectFsHealthPulseVo"/>
+        <where>
+            <if test="userId != null "> and user_id = #{userId}</if>
+            <if test="name != null  and name != ''"> and name like concat('%', #{name}, '%')</if>
+            <if test="sex != null "> and sex = #{sex}</if>
+            <if test="age != null "> and age = #{age}</if>
+            <if test="status != null "> and status = #{status}</if>
+            <if test="leftHandResult != null  and leftHandResult != ''"> and left_hand_result = #{leftHandResult}</if>
+            <if test="rightHandResult != null  and rightHandResult != ''"> and right_hand_result = #{rightHandResult}</if>
+            <if test="pulseSummary != null  and pulseSummary != ''"> and pulse_summary = #{pulseSummary}</if>
+            <if test="pulseSuggestions != null  and pulseSuggestions != ''"> and pulse_suggestions = #{pulseSuggestions}</if>
+            <if test="measureId != null  and measureId != ''"> and measure_id = #{measureId}</if>
+            <if test="pulseUrl != null  and pulseUrl != ''"> and pulse_url = #{pulseUrl}</if>
+        </where>
+    </select>
+
+    <select id="selectFsHealthPulseById" parameterType="Long" resultMap="FsHealthPulseResult">
+        <include refid="selectFsHealthPulseVo"/>
+        where id = #{id}
+    </select>
+    <select id="selectFsHealthPulseListVO" resultType="com.fs.his.vo.FsHealthPulseListVO">
+        select  * from fs_health_pulse where user_id=#{userId}
+        <if test="createDay != null and createDay !=''">
+            AND DATE(create_time) = #{createDay}
+        </if>
+        order by create_time desc
+    </select>
+    <select id="selectListByDateAndUserId" resultType="java.lang.String">
+        select DATE(create_time) from fs_health_pulse
+        <where>
+            <if test="startDate != null">
+                and create_time <![CDATA[>=]]> #{startDate}
+            </if>
+            <if test="endDate != null">
+                and create_time <![CDATA[<=]]> #{endDate}
+            </if>
+            <if test="userId != null">
+                and user_id= #{userId}
+            </if>
+        </where>
+        GROUP BY DATE(create_time)
+    </select>
+
+    <insert id="insertFsHealthPulse" parameterType="FsHealthPulse" useGeneratedKeys="true" keyProperty="id">
+        insert into fs_health_pulse
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="userId != null">user_id,</if>
+            <if test="name != null">name,</if>
+            <if test="sex != null">sex,</if>
+            <if test="age != null">age,</if>
+            <if test="status != null">status,</if>
+            <if test="leftHandResult != null">left_hand_result,</if>
+            <if test="rightHandResult != null">right_hand_result,</if>
+            <if test="pulseSummary != null">pulse_summary,</if>
+            <if test="pulseSuggestions != null">pulse_suggestions,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="remark != null">remark,</if>
+            <if test="measureId != null">measure_id,</if>
+            <if test="pulseUrl != null">pulse_url,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="userId != null">#{userId},</if>
+            <if test="name != null">#{name},</if>
+            <if test="sex != null">#{sex},</if>
+            <if test="age != null">#{age},</if>
+            <if test="status != null">#{status},</if>
+            <if test="leftHandResult != null">#{leftHandResult},</if>
+            <if test="rightHandResult != null">#{rightHandResult},</if>
+            <if test="pulseSummary != null">#{pulseSummary},</if>
+            <if test="pulseSuggestions != null">#{pulseSuggestions},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="remark != null">#{remark},</if>
+            <if test="measureId != null">#{measureId},</if>
+            <if test="pulseUrl != null">#{pulseUrl},</if>
+         </trim>
+    </insert>
+
+    <update id="updateFsHealthPulse" parameterType="FsHealthPulse">
+        update fs_health_pulse
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="userId != null">user_id = #{userId},</if>
+            <if test="name != null">name = #{name},</if>
+            <if test="sex != null">sex = #{sex},</if>
+            <if test="age != null">age = #{age},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="leftHandResult != null">left_hand_result = #{leftHandResult},</if>
+            <if test="rightHandResult != null">right_hand_result = #{rightHandResult},</if>
+            <if test="pulseSummary != null">pulse_summary = #{pulseSummary},</if>
+            <if test="pulseSuggestions != null">pulse_suggestions = #{pulseSuggestions},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="remark != null">remark = #{remark},</if>
+            <if test="measureId != null">measure_id = #{measureId},</if>
+            <if test="pulseUrl != null">pulse_url = #{pulseUrl},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteFsHealthPulseById" parameterType="Long">
+        delete from fs_health_pulse where id = #{id}
+    </delete>
+
+    <delete id="deleteFsHealthPulseByIds" parameterType="String">
+        delete from fs_health_pulse where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 148 - 0
fs-service/src/main/resources/mapper/his/FsHealthSurfaceMapper.xml

@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.his.mapper.FsHealthSurfaceMapper">
+
+    <resultMap type="FsHealthSurface" id="FsHealthSurfaceResult">
+        <result property="id"    column="id"    />
+        <result property="userId"    column="user_id"    />
+        <result property="name"    column="name"    />
+        <result property="sex"    column="sex"    />
+        <result property="age"    column="age"    />
+        <result property="status"    column="status"    />
+        <result property="surfaceUrl"    column="surface_url"    />
+        <result property="complexionResult"    column="complexion_result"    />
+        <result property="complexionTypes"    column="complexion_types"    />
+        <result property="spotProblems"    column="spot_problems"    />
+        <result property="swellingProblems"    column="swelling_problems"    />
+        <result property="glowResult"    column="glow_result"    />
+        <result property="diagnosisSummary"    column="diagnosis_summary"    />
+        <result property="healthSuggestions"    column="health_suggestions"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="remark"    column="remark"    />
+    </resultMap>
+
+    <sql id="selectFsHealthSurfaceVo">
+        select id, user_id, name, sex, age, status, surface_url, complexion_result, complexion_types, spot_problems, swelling_problems, glow_result, diagnosis_summary, health_suggestions,create_time,remark from fs_health_surface
+    </sql>
+
+    <select id="selectFsHealthSurfaceList" parameterType="FsHealthSurface" resultMap="FsHealthSurfaceResult">
+        <include refid="selectFsHealthSurfaceVo"/>
+        <where>
+            <if test="userId != null "> and user_id = #{userId}</if>
+            <if test="name != null  and name != ''"> and name like concat('%', #{name}, '%')</if>
+            <if test="sex != null "> and sex = #{sex}</if>
+            <if test="age != null "> and age = #{age}</if>
+            <if test="status != null "> and status = #{status}</if>
+            <if test="surfaceUrl != null  and surfaceUrl != ''"> and surface_url = #{surfaceUrl}</if>
+            <if test="complexionResult != null  and complexionResult != ''"> and complexion_result = #{complexionResult}</if>
+            <if test="complexionTypes != null  and complexionTypes != ''"> and complexion_types = #{complexionTypes}</if>
+            <if test="spotProblems != null  and spotProblems != ''"> and spot_problems = #{spotProblems}</if>
+            <if test="swellingProblems != null  and swellingProblems != ''"> and swelling_problems = #{swellingProblems}</if>
+            <if test="glowResult != null  and glowResult != ''"> and glow_result = #{glowResult}</if>
+            <if test="diagnosisSummary != null  and diagnosisSummary != ''"> and diagnosis_summary = #{diagnosisSummary}</if>
+            <if test="healthSuggestions != null  and healthSuggestions != ''"> and health_suggestions = #{healthSuggestions}</if>
+            <if test="createTime != null  and createTime != ''"> and create_time = #{createTime}</if>
+            <if test="remark != null  and remark != ''"> and remark = #{remark}</if>
+        </where>
+    </select>
+
+    <select id="selectFsHealthSurfaceById" parameterType="Long" resultMap="FsHealthSurfaceResult">
+        <include refid="selectFsHealthSurfaceVo"/>
+        where id = #{id}
+    </select>
+    <select id="selectFsHealthSurfaceListVO" resultType="com.fs.his.vo.FsHealthSurfaceListVO">
+        select  * from fs_health_surface where user_id=#{userId}
+        <if test="createDay != null and createDay !=''">
+            AND DATE(create_time) = #{createDay}
+        </if>
+        order by create_time desc
+    </select>
+    <select id="selectListByDateAndUserId" resultType="java.lang.String">
+        select DATE(create_time) from fs_health_surface
+        <where>
+            <if test="startDate != null">
+                and create_time <![CDATA[>=]]> #{startDate}
+            </if>
+            <if test="endDate != null">
+                and create_time <![CDATA[<=]]> #{endDate}
+            </if>
+            <if test="userId != null">
+                and user_id= #{userId}
+            </if>
+        </where>
+        GROUP BY DATE(create_time)
+    </select>
+
+    <insert id="insertFsHealthSurface" parameterType="FsHealthSurface" useGeneratedKeys="true" keyProperty="id">
+        insert into fs_health_surface
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="userId != null">user_id,</if>
+            <if test="name != null">name,</if>
+            <if test="sex != null">sex,</if>
+            <if test="age != null">age,</if>
+            <if test="status != null">status,</if>
+            <if test="surfaceUrl != null">surface_url,</if>
+            <if test="complexionResult != null">complexion_result,</if>
+            <if test="complexionTypes != null">complexion_types,</if>
+            <if test="spotProblems != null">spot_problems,</if>
+            <if test="swellingProblems != null">swelling_problems,</if>
+            <if test="glowResult != null">glow_result,</if>
+            <if test="diagnosisSummary != null">diagnosis_summary,</if>
+            <if test="healthSuggestions != null">health_suggestions,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="remark != null">remark,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="userId != null">#{userId},</if>
+            <if test="name != null">#{name},</if>
+            <if test="sex != null">#{sex},</if>
+            <if test="age != null">#{age},</if>
+            <if test="status != null">#{status},</if>
+            <if test="surfaceUrl != null">#{surfaceUrl},</if>
+            <if test="complexionResult != null">#{complexionResult},</if>
+            <if test="complexionTypes != null">#{complexionTypes},</if>
+            <if test="spotProblems != null">#{spotProblems},</if>
+            <if test="swellingProblems != null">#{swellingProblems},</if>
+            <if test="glowResult != null">#{glowResult},</if>
+            <if test="diagnosisSummary != null">#{diagnosisSummary},</if>
+            <if test="healthSuggestions != null">#{healthSuggestions},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="remark != null">#{remark},</if>
+         </trim>
+    </insert>
+
+    <update id="updateFsHealthSurface" parameterType="FsHealthSurface">
+        update fs_health_surface
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="userId != null">user_id = #{userId},</if>
+            <if test="name != null">name = #{name},</if>
+            <if test="sex != null">sex = #{sex},</if>
+            <if test="age != null">age = #{age},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="surfaceUrl != null">surface_url = #{surfaceUrl},</if>
+            <if test="complexionResult != null">complexion_result = #{complexionResult},</if>
+            <if test="complexionTypes != null">complexion_types = #{complexionTypes},</if>
+            <if test="spotProblems != null">spot_problems = #{spotProblems},</if>
+            <if test="swellingProblems != null">swelling_problems = #{swellingProblems},</if>
+            <if test="glowResult != null">glow_result = #{glowResult},</if>
+            <if test="diagnosisSummary != null">diagnosis_summary = #{diagnosisSummary},</if>
+            <if test="healthSuggestions != null">health_suggestions = #{healthSuggestions},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="remark != null">remark = #{remark},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteFsHealthSurfaceById" parameterType="Long">
+        delete from fs_health_surface where id = #{id}
+    </delete>
+
+    <delete id="deleteFsHealthSurfaceByIds" parameterType="String">
+        delete from fs_health_surface where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 315 - 0
fs-service/src/main/resources/mapper/his/FsThirdDeviceDataMapper.xml

@@ -0,0 +1,315 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.his.mapper.FsThirdDeviceDataMapper">
+    
+    <resultMap type="FsThirdDeviceData" id="FsThirdDeviceDataResult">
+        <result property="id"    column="id"    />
+        <result property="userId"    column="user_id"    />
+        <result property="recordType"    column="record_type"    />
+        <result property="recordValue"    column="record_value"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="deviceId"    column="device_id"    />
+        <result property="deviceType"    column="device_type"    />
+        <result property="status"    column="status"    />
+    </resultMap>
+
+    <sql id="selectFsThirdDeviceDataVo">
+        select id, user_id, record_type, record_value, create_time,device_id,device_type,`status` from fs_third_device_data
+    </sql>
+
+    <select id="selectFsThirdDeviceDataList" parameterType="FsThirdDeviceData" resultMap="FsThirdDeviceDataResult">
+        <include refid="selectFsThirdDeviceDataVo"/>
+        <where>  
+            <if test="userId != null "> and user_id = #{userId}</if>
+            <if test="recordType != null "> and record_type = #{recordType}</if>
+            <if test="recordValue != null  and recordValue != ''"> and record_value = #{recordValue}</if>
+            <if test="deviceId != null  and deviceId != ''"> and device_id = #{deviceId}</if>
+            <if test="deviceType != null  and deviceType != ''"> and device_type = #{deviceType}</if>
+            <if test="status != null  "> and `status` = #{status}</if>
+        </where>
+    </select>
+    
+    <select id="selectFsThirdDeviceDataById" parameterType="Long" resultMap="FsThirdDeviceDataResult">
+        <include refid="selectFsThirdDeviceDataVo"/>
+        where id = #{id}
+    </select>
+    <select id="getLastData" resultType="com.fs.his.domain.FsThirdDeviceData">
+        SELECT record_type,
+               record_value,
+               create_time,
+               device_id,
+               device_type
+        FROM (
+                 SELECT *,
+                        ROW_NUMBER() OVER (PARTITION BY record_type ORDER BY create_time DESC) as rn
+                 FROM fs_third_device_data
+                 WHERE user_id = #{userId} AND device_type = #{deviceType} AND device_id = #{deviceId}
+             ) t
+        WHERE rn = 1
+        ORDER BY record_type;
+    </select>
+    <select id="countMaxAndMinBpByDate" resultType="java.util.Map">
+        SELECT
+            MAX(JSON_UNQUOTE(JSON_EXTRACT(record_value, '$.sdb'))) AS `max`,
+            MIN(JSON_UNQUOTE(JSON_EXTRACT(record_value, '$.dbp'))) AS `min`
+        FROM
+            fs_third_device_data
+        WHERE
+            device_id = #{deviceId}
+          AND record_type = 0  -- 只查询血压记录
+          AND create_time BETWEEN #{startTime} AND #{endTime}
+        GROUP BY
+            device_id;
+    </select>
+    <select id="queryBgByDate" resultType="com.fs.his.domain.FsThirdDeviceData">
+        <include refid="selectFsThirdDeviceDataVo"/>
+        WHERE  record_type = 1 AND
+        device_id = #{deviceId}
+        AND create_time BETWEEN #{startTime} AND #{endTime}
+        ORDER BY
+        create_time ASC
+    </select>
+    <select id="countMaxAndAvgBpByDate" resultType="java.util.Map">
+        SELECT
+            MAX(record_value) AS maxBpm,
+            AVG(record_value) AS avgBpm
+        FROM
+            fs_third_device_data
+        WHERE
+            record_type = 2
+          AND device_id = #{deviceId} AND
+            create_time BETWEEN #{startTime} AND #{endTime}
+        GROUP BY
+            device_id
+    </select>
+    <select id="getFirstDataByDeviceId" resultType="com.fs.his.domain.FsThirdDeviceData">
+        <include refid="selectFsThirdDeviceDataVo"/>
+        where device_id = #{deviceId} order by create_time asc limit 1
+    </select>
+    <select id="queryByMonth" resultType="com.fs.his.domain.FsThirdDeviceData">
+        SELECT *
+        FROM fs_third_device_data
+        WHERE device_id like #{deviceId} and toYYYYMM(create_time) = #{monthStr} and record_type = #{recordType}
+    </select>
+    <select id="getLatest" resultType="com.fs.his.domain.FsThirdDeviceData">
+        <include refid="selectFsThirdDeviceDataVo"/>
+        where device_id = #{deviceId} and record_type = #{recordType} order by create_time desc limit 1
+    </select>
+    <select id="selectListByDateAndDeviceIdAndRecordType" resultType="com.fs.his.domain.FsThirdDeviceData">
+        <include refid="selectFsThirdDeviceDataVo"/>
+        where
+        device_id = #{deviceId}
+        and record_type = #{recordType}
+        <if test="startTime != null">
+            and create_time >= #{startTime}
+        </if>
+
+        <if test="endTime != null">
+            and create_time &lt;= #{endTime}
+        </if>
+
+        <if test="status != null">
+            AND record_value->>'$.sportType' = #{status}
+        </if>
+        order by create_time asc
+    </select>
+    <select id="countByDateAndDeviceIdAndRecordType" resultType="java.util.Map">
+        select `status`,
+               COUNT(*) AS `count` from fs_third_device_data where device_id = #{deviceId}
+                                             and record_type = #{recordType}
+                                             and create_time >= #{startTime}
+                                             and create_time &lt;= #{endTime}
+                                                             <if test="status != null">
+                                                                 and `status` = #{status}
+                                                             </if>
+        group by `status`
+
+    </select>
+    <select id="countPageByDateAndDeviceIdAndRecordType" resultType="java.lang.Integer">
+        select count(*) from fs_third_device_data
+                        where
+        device_id = #{deviceId}
+        and record_type = #{recordType}
+        and create_time >= #{startTime}
+        and create_time &lt;= #{endTime}
+        <if test="status != null">
+            and `status` = #{status}
+        </if>
+
+    </select>
+    <select id="queryPageByDateAndDeviceIdAndRecordType" resultType="com.fs.his.domain.FsThirdDeviceData">
+        <include refid="selectFsThirdDeviceDataVo"/>
+        where
+        device_id = #{deviceId}
+        and record_type = #{recordType}
+        and create_time >= #{startTime}
+        and create_time &lt;= #{endTime}
+        <if test="status != null">
+            and `status` = #{status}
+        </if>
+        order by create_time asc LIMIT #{num},#{size}
+    </select>
+    <select id="countAvgBpByDate" resultType="java.lang.Float">
+        SELECT
+            AVG(CAST(record_value AS DECIMAL(10,2))) AS avg_value
+        FROM
+            fs_third_device_data
+        WHERE
+            create_time BETWEEN #{startTime} AND #{endTime}
+          AND device_id = #{deviceId}
+          AND record_type = 4
+        GROUP BY
+            device_id
+    </select>
+    <select id="getOtherData" resultType="com.fs.watch.domain.vo.WatchSportRecordVo">
+        SELECT
+        COUNT(*) AS `count`,
+        SUM(COALESCE(CAST(record_value->>'$.distance' AS DECIMAL(10, 2)), 0)) AS distance,
+        ROUND(SUM(COALESCE(CAST(record_value->>'$.duration' AS DECIMAL(10, 2)), 0)) / 3600, 2) AS `time`,
+        SUM(COALESCE(CAST(record_value->>'$.steps' AS SIGNED), 0)) AS `step`,
+        SUM(COALESCE(CAST(record_value->>'$.calories' AS DECIMAL(10, 2)), 0)) AS calorie
+        FROM `fs_third_device_data`
+        WHERE
+        device_id = #{deviceId}
+        AND record_type = #{recordType}
+        <if test="startTime != null">
+            AND create_time >= #{startTime}
+        </if>
+        <if test="endTime != null">
+            AND create_time &lt;= #{endTime}
+        </if>
+        <if test="status != null">
+            AND record_value->>'$.sportType' = #{status}
+        </if>
+    </select>
+    <select id="queryActivityRecord" resultType="com.fs.watch.domain.vo.WatchSportRecordVo">
+        SELECT
+        record_value->>'$.sportType' AS `type`,
+        COUNT(*) AS `count`,
+        SUM(COALESCE(CAST(record_value->>'$.distance' AS DECIMAL(10, 2)), 0)) AS distance
+        FROM `fs_third_device_data`
+        WHERE
+        device_id = #{deviceId}
+        AND record_type = #{recordType}
+        <if test="startTime != null">
+            AND create_time >= #{startTime}
+        </if>
+        <if test="endTime != null">
+            AND create_time &lt;= #{endTime}
+        </if>
+        <if test="status != null">
+            AND `status` = #{status}
+        </if>
+        GROUP BY record_value->>'$.sportType'
+        ORDER BY `type`
+    </select>
+    <select id="getOtherDataOther" resultType="com.fs.watch.domain.vo.WatchSportRecordVo">
+        SELECT
+        COUNT(*) AS `count`,
+        SUM(COALESCE(CAST(record_value->>'$.distance' AS DECIMAL(10, 2)), 0)) AS distance,
+        ROUND(SUM(COALESCE(CAST(record_value->>'$.duration' AS DECIMAL(10, 2)), 0)) / 3600, 2) AS `time`,
+        SUM(COALESCE(CAST(record_value->>'$.steps' AS SIGNED), 0)) AS `step`,
+        SUM(COALESCE(CAST(record_value->>'$.calories' AS DECIMAL(10, 2)), 0)) AS calorie
+        FROM `fs_third_device_data`
+        WHERE
+        device_id = #{deviceId}
+        AND record_type = #{recordType}
+        <if test="startTime != null">
+            AND create_time >= #{startTime}
+        </if>
+        <if test="endTime != null">
+            AND create_time &lt;= #{endTime}
+        </if>
+
+            AND record_value->>'$.sportType' not in (25,17,1,9,21,5,13)
+
+    </select>
+    <select id="selectListByDateAndDeviceIdAndRecordTypeOther"
+            resultType="com.fs.his.domain.FsThirdDeviceData">
+        <include refid="selectFsThirdDeviceDataVo"/>
+        where
+        device_id = #{deviceId}
+        and record_type = #{recordType}
+        <if test="startTime != null">
+            and create_time >= #{startTime}
+        </if>
+
+        <if test="endTime != null">
+            and create_time &lt;= #{endTime}
+        </if>
+        AND record_value->>'$.sportType' not in (25,17,1,9,21,5,13)
+        order by create_time asc
+    </select>
+
+
+    <insert id="insertFsThirdDeviceData" parameterType="FsThirdDeviceData" useGeneratedKeys="true" keyProperty="id">
+        insert into fs_third_device_data
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="userId != null">user_id,</if>
+            <if test="recordType != null">record_type,</if>
+            <if test="recordValue != null and recordValue != ''">record_value,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="deviceId != null">device_id,</if>
+            <if test="deviceType != null">device_type,</if>
+            <if test="status != null">`status`,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="userId != null">#{userId},</if>
+            <if test="recordType != null">#{recordType},</if>
+            <if test="recordValue != null and recordValue != ''">#{recordValue},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="deviceId != null">#{deviceId},</if>
+            <if test="deviceType != null">#{deviceType},</if>
+            <if test="status != null">#{status},</if>
+         </trim>
+    </insert>
+    <insert id="insertFsThirdDeviceDataList" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="id">
+        INSERT INTO fs_third_device_data (
+        user_id,
+        record_type,
+        record_value,
+        create_time,
+        device_id,
+        device_type,
+        `status`
+        ) VALUES
+        <foreach collection="list" item="item" separator=",">
+            (
+            #{item.userId},
+            #{item.recordType},
+            #{item.recordValue},
+            #{item.createTime},
+            #{item.deviceId},
+            #{item.deviceType},
+            #{item.status}
+            )
+        </foreach>
+    </insert>
+
+    <update id="updateFsThirdDeviceData" parameterType="FsThirdDeviceData">
+        update fs_third_device_data
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="userId != null">user_id = #{userId},</if>
+            <if test="recordType != null">record_type = #{recordType},</if>
+            <if test="recordValue != null and recordValue != ''">record_value = #{recordValue},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="deviceId != null">device_id = #{deviceId},</if>
+            <if test="deviceType != null">device_type = #{deviceType},</if>
+            <if test="status != null">`status` = #{status},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteFsThirdDeviceDataById" parameterType="Long">
+        delete from fs_third_device_data where id = #{id}
+    </delete>
+
+    <delete id="deleteFsThirdDeviceDataByIds" parameterType="String">
+        delete from fs_third_device_data where id in 
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 124 - 0
fs-service/src/main/resources/mapper/his/FsUserAdditionalDataMapper.xml

@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.his.mapper.FsUserAdditionalDataMapper">
+
+    <resultMap type="FsUserAdditionalData" id="FsUserAdditionalDataResult">
+        <result property="id"    column="id"    />
+        <result property="fsUserId"    column="fs_user_id"    />
+        <result property="height"    column="height"    />
+        <result property="weight"    column="weight"    />
+        <result property="age"    column="age"    />
+        <result property="sex"    column="sex"    />
+        <result property="previousMedicalHistory"    column="previous_medical_history"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="status"    column="status"    />
+        <result property="remark"    column="remark"    />
+        <result property="username"    column="username"    />
+        <result property="phone"    column="phone"    />
+        <result property="historyOfAllergies"    column="history_of_allergies"    />
+        <result property="habit"    column="habit"    />
+        <result property="idCard"    column="id_card"    />
+        <result property="consultationRecord"    column="consultation_record"    />
+    </resultMap>
+
+    <sql id="selectFsUserAdditionalDataVo">
+        select id, fs_user_id, height, weight, age, sex, previous_medical_history, create_time, status, remark,username,phone,history_of_allergies,habit,id_card,consultation_record from fs_user_additional_data
+    </sql>
+
+    <select id="selectFsUserAdditionalDataList" parameterType="FsUserAdditionalData" resultMap="FsUserAdditionalDataResult">
+        <include refid="selectFsUserAdditionalDataVo"/>
+        <where>
+            <if test="fsUserId != null "> and fs_user_id = #{fsUserId}</if>
+            <if test="height != null  and height != ''"> and height = #{height}</if>
+            <if test="weight != null  and weight != ''"> and weight = #{weight}</if>
+            <if test="age != null  and age != ''"> and age = #{age}</if>
+            <if test="sex != null "> and sex = #{sex}</if>
+            <if test="previousMedicalHistory != null  and previousMedicalHistory != ''"> and previous_medical_history = #{previousMedicalHistory}</if>
+            <if test="status != null "> and status = #{status}</if>
+            <if test="username != null "> and username = #{username}</if>
+            <if test="phone != null "> and phone = #{phone}</if>
+            <if test="historyOfAllergies != null "> and history_of_allergies = #{historyOfAllergies}</if>
+            <if test="habit != null "> and habit = #{habit}</if>
+            <if test="idCard != null "> and id_card = #{idCard}</if>
+            <if test="consultationRecord != null "> and consultation_record = #{consultationRecord}</if>
+        </where>
+    </select>
+
+    <select id="selectFsUserAdditionalDataById" parameterType="Long" resultMap="FsUserAdditionalDataResult">
+        <include refid="selectFsUserAdditionalDataVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertFsUserAdditionalData" parameterType="FsUserAdditionalData" useGeneratedKeys="true" keyProperty="id">
+        insert into fs_user_additional_data
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="fsUserId != null">fs_user_id,</if>
+            <if test="height != null">height,</if>
+            <if test="weight != null">weight,</if>
+            <if test="age != null">age,</if>
+            <if test="sex != null">sex,</if>
+            <if test="previousMedicalHistory != null">previous_medical_history,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="status != null">status,</if>
+            <if test="remark != null">remark,</if>
+            <if test="username != null">username,</if>
+            <if test="phone != null">phone,</if>
+            <if test="historyOfAllergies != null">history_of_allergies,</if>
+            <if test="habit != null">habit,</if>
+            <if test="idCard != null">id_card,</if>
+            <if test="consultationRecord != null">consultation_record,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="fsUserId != null">#{fsUserId},</if>
+            <if test="height != null">#{height},</if>
+            <if test="weight != null">#{weight},</if>
+            <if test="age != null">#{age},</if>
+            <if test="sex != null">#{sex},</if>
+            <if test="previousMedicalHistory != null">#{previousMedicalHistory},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="status != null">#{status},</if>
+            <if test="remark != null">#{remark},</if>
+            <if test="username != null">#{username},</if>
+            <if test="phone != null">#{phone},</if>
+            <if test="historyOfAllergies != null">#{historyOfAllergies},</if>
+            <if test="habit != null">#{habit},</if>
+            <if test="idCard != null">#{idCard},</if>
+            <if test="consultationRecord != null">#{consultationRecord},</if>
+         </trim>
+    </insert>
+
+    <update id="updateFsUserAdditionalData" parameterType="FsUserAdditionalData">
+        update fs_user_additional_data
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="fsUserId != null">fs_user_id = #{fsUserId},</if>
+            <if test="height != null">height = #{height},</if>
+            <if test="weight != null">weight = #{weight},</if>
+            <if test="age != null">age = #{age},</if>
+            <if test="sex != null">sex = #{sex},</if>
+            <if test="previousMedicalHistory != null">previous_medical_history = #{previousMedicalHistory},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="remark != null">remark = #{remark},</if>
+            <if test="username != null">remark = #{username},</if>
+            <if test="phone != null">phone = #{phone},</if>
+            <if test="historyOfAllergies != null">history_of_allergies = #{historyOfAllergies},</if>
+            <if test="habit != null">habit = #{habit},</if>
+            <if test="idCard != null">id_card = #{idCard},</if>
+            <if test="consultationRecord != null">consultation_record = #{consultationRecord},</if>
+        </trim>
+        where fs_user_id = #{fsUserId}
+    </update>
+
+    <delete id="deleteFsUserAdditionalDataById" parameterType="Long">
+        delete from fs_user_additional_data where id = #{id}
+    </delete>
+
+    <delete id="deleteFsUserAdditionalDataByIds" parameterType="String">
+        delete from fs_user_additional_data where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 11 - 0
fs-service/src/main/resources/mapper/his/InterestAiChatSessionMapper.xml

@@ -136,6 +136,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         inner join fs_interest_ai_role t3 on t3.role_id = t2.role_id
         where t2.session_id = #{sessionId}
     </select>
+    <select id="selectSessionIdByUserAndRole" resultType="java.lang.Integer">
+        select session_id from fs_interest_ai_session where user_id = #{userId} and role_id = #{roleId} limit 1
+    </select>
+    <select id="selectSessionBySessionId" resultType="com.fs.his.domain.FsInterestAiSession">
+        select session_id,chat_id,user_id,role_id,role_name, status, nick_name,avatar,create_time,update_time
+        from fs_interest_ai_session where session_id = #{sessionId}
+    </select>
+    <select id="selectAiMsgBySessionIdAndMsg" resultType="java.lang.Integer">
+        <![CDATA[ select count(*) from fs_interest_ai_msg where session_id = #{param.sessionId} and content = #{param.message}
+                                                            and begin_time = #{param.beginTime}]]>
+    </select>
 
     <insert id="insertFsInterestAiSession" parameterType="FsInterestAiSession" useGeneratedKeys="true" keyProperty="sessionId">
         insert into fs_interest_ai_session

Vissa filer visades inte eftersom för många filer har ändrats