浏览代码

Merge branch 'master' into bjcz_his_scrm

# Conflicts:
#	fs-admin/src/main/java/com/fs/course/controller/FsUserCourseVideoController.java
#	fs-service/src/main/java/com/fs/course/domain/FsUserCourseVideo.java
#	fs-service/src/main/resources/mapper/his/FsUserMapper.xml
xw 1 月之前
父节点
当前提交
34abc734ee
共有 37 个文件被更改,包括 534 次插入56 次删除
  1. 22 0
      fs-admin/src/main/java/com/fs/api/controller/IndexStatisticsController.java
  2. 9 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseVideoController.java
  3. 3 1
      fs-admin/src/main/java/com/fs/live/controller/LiveAfterSalesController.java
  4. 24 5
      fs-company/src/main/java/com/fs/company/controller/company/IndexStatisticsController.java
  5. 10 2
      fs-company/src/main/java/com/fs/framework/config/DataSourceConfig.java
  6. 9 2
      fs-framework/src/main/java/com/fs/framework/config/DataSourceConfig.java
  7. 8 1
      fs-live-app/src/main/java/com/fs/framework/config/DataSourceConfig.java
  8. 29 0
      fs-service/src/main/java/com/fs/course/domain/FsDepVideoShow.java
  9. 4 0
      fs-service/src/main/java/com/fs/course/domain/FsUserCourseVideo.java
  10. 43 0
      fs-service/src/main/java/com/fs/course/mapper/FsDepVideoShowMapper.java
  11. 17 1
      fs-service/src/main/java/com/fs/gtPush/service/impl/uniPush2ServiceImpl.java
  12. 4 0
      fs-service/src/main/java/com/fs/his/domain/FsAppVersion.java
  13. 4 0
      fs-service/src/main/java/com/fs/his/domain/FsUser.java
  14. 3 0
      fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java
  15. 8 0
      fs-service/src/main/java/com/fs/his/service/IFsUserCouponService.java
  16. 44 0
      fs-service/src/main/java/com/fs/his/service/impl/FsUserCouponServiceImpl.java
  17. 1 1
      fs-service/src/main/java/com/fs/live/mapper/LiveOrderMapper.java
  18. 5 5
      fs-service/src/main/java/com/fs/live/service/impl/LiveServiceImpl.java
  19. 2 1
      fs-service/src/main/java/com/fs/live/utils/redis/RedisBatchHandler.java
  20. 6 0
      fs-service/src/main/java/com/fs/qw/mapper/QwWatchLogMapper.java
  21. 6 0
      fs-service/src/main/java/com/fs/qw/param/QwWatchLogStatisticsListParam.java
  22. 1 1
      fs-service/src/main/java/com/fs/statis/dto/AnalysisPreviewQueryDTO.java
  23. 7 0
      fs-service/src/main/java/com/fs/statis/service/impl/StatisticsServiceImpl.java
  24. 2 2
      fs-service/src/main/resources/application-druid-jzzx-test.yml
  25. 2 2
      fs-service/src/main/resources/application-druid-jzzx.yml
  26. 3 3
      fs-service/src/main/resources/application-druid-kyt.yml
  27. 2 1
      fs-service/src/main/resources/application-druid-sxjz.yml
  28. 5 1
      fs-service/src/main/resources/mapper/his/FsAppVersionMapper.xml
  29. 0 2
      fs-service/src/main/resources/mapper/his/FsUserIntegralLogsMapper.xml
  30. 22 0
      fs-service/src/main/resources/mapper/his/FsUserMapper.xml
  31. 3 3
      fs-service/src/main/resources/mapper/statis/ConsumptionBalanceMapper.xml
  32. 178 20
      fs-user-app/src/main/java/com/fs/app/controller/AppLoginController.java
  33. 18 0
      fs-user-app/src/main/java/com/fs/app/controller/store/H5ScrmController.java
  34. 9 0
      fs-user-app/src/main/java/com/fs/app/param/FsUserEditPhoneParam.java
  35. 17 0
      fs-user-app/src/main/java/com/fs/app/param/FsUserLoginByAppleParam.java
  36. 2 0
      fs-user-app/src/main/java/com/fs/app/param/FsUserLoginByWeChatParam.java
  37. 2 2
      fs-user-app/src/main/java/com/fs/framework/config/DataSourceConfig.java

+ 22 - 0
fs-admin/src/main/java/com/fs/api/controller/IndexStatisticsController.java

@@ -13,6 +13,7 @@ import com.fs.statis.StatisticsRedisConstant;
 import com.fs.statis.dto.*;
 import com.fs.statis.param.StatisticsDeptCompanyParam;
 import com.fs.statis.service.IStatisticsService;
+import com.fs.statis.service.impl.StatisticsCompanyServiceImpl;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.service.ISysConfigService;
 import com.fs.system.service.ISysDeptService;
@@ -56,6 +57,9 @@ public class IndexStatisticsController {
 
     @Autowired
     private IStatisticsService statisticsService;
+    @Autowired
+    private StatisticsCompanyServiceImpl statisticsCompanyService;
+
     /**
      * 分析概览
      */
@@ -72,6 +76,9 @@ public class IndexStatisticsController {
         if(userType == null) {
             userType = 0;
         }
+        if(param.getType().equals(5)){
+            return R.ok().put("data",statisticsService.analysisPreview(param));
+        }
         if(medicalMallConfig.isStatics()|| (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)){
             analysisPreviewDTO = redisCache.getCacheObject(String.format("%s:%d:%d",DATA_OVERVIEW_DEALER_ANALYSISPREVIEW,type,userType));
         }else if(param.getCompanyId() != null){
@@ -255,6 +262,9 @@ public class IndexStatisticsController {
             userType = 0;
         }
         List<WatchEndPlayTrendDTO> watchEndPlayTrendDTOS;
+        if (param.getType().equals(5)){
+            return R.ok().put("data", statisticsCompanyService.watchEndPlayTrend(param));
+        }
         // 参考watchCourseTopTen方法的处理逻辑
         if (!medicalMallConfig.isStatics() || (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)){
             String key = String.format("%s:%d:%d", DATA_OVERVIEW_DEALER_CHARTS, type,userType);
@@ -339,6 +349,9 @@ public class IndexStatisticsController {
             userType = 0;
         }
         List<DeaMemberTopTenDTO> deaMemberTopTenDTOS = new ArrayList<>();
+        if (param.getType().equals(5)){
+            return R.ok().put("data", statisticsService.deaMemberTopTen(param));
+        }
         // 参考deaMemberTopTen方法处理逻辑
         if (!medicalMallConfig.isStatics() || (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)){
             String key = String.format("%s:%d:%d:%d", CHARTS_MEMBER_TOP_TEN_WATCH, type, statisticalType,userType);
@@ -396,6 +409,9 @@ public class IndexStatisticsController {
         Integer dataType = param.getDataType();
         Integer userType = param.getUserType();
         List<RewardMoneyTopTenDTO> rewardMoneyTopTenDTOS = new ArrayList<>();
+        if (param.getType().equals(5)){
+            return R.ok().put("data", statisticsService.rewardMoneyTopTen(param));
+        }
         // 参考rewardMoneyTopTen方法处理逻辑
         if(!medicalMallConfig.isStatics() || (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)){
             String key = String.format("%s:%d:%d:%d", CHARTS_REWARD_MONEY_TOP_TEN, type,dataType,userType);
@@ -450,6 +466,9 @@ public class IndexStatisticsController {
         Integer type = param.getType();
         Integer userType = param.getUserType();
         List<RewardMoneyTrendDTO> rewardMoneyTrendDTOS = new ArrayList<>();
+        if (param.getType().equals(5)){
+            return R.ok().put("data", statisticsService.rewardMoneyTrendDTO(param));
+        }
         // 参考rewardMoneyTrend方法处理逻辑
         if(!medicalMallConfig.isStatics() || (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)){
             String key = String.format("%s:%d:%d", CHARTS_REWARD_MONEY_TREND, type,userType);
@@ -503,6 +522,9 @@ public class IndexStatisticsController {
         Integer statisticalType = param.getStatisticalType();
         Integer userType = param.getUserType();
         List<CourseStatsDTO> courseStatsDTOS;
+        if (param.getType().equals(5)){
+            return R.ok().put("data", statisticsCompanyService.watchCourseTopTen(param));
+        }
         if (!medicalMallConfig.isStatics() || (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)){
             courseStatsDTOS = redisCache.getCacheObject(String.format("%s:%d:%d:%d:%s", CHARTS_WATCH_TOP_TEN, type,statisticalType,userType,sort));
         }else if(param.getCompanyId() != null){

+ 9 - 0
fs-admin/src/main/java/com/fs/course/controller/FsUserCourseVideoController.java

@@ -2,6 +2,7 @@ package com.fs.course.controller;
 
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.fs.common.annotation.Log;
 import com.fs.common.annotation.RepeatSubmit;
 import com.fs.common.core.controller.BaseController;
@@ -13,13 +14,16 @@ import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.course.config.CourseConfig;
+import com.fs.course.domain.FsDepVideoShow;
 import com.fs.course.domain.FsUserCourse;
 import com.fs.course.domain.FsUserCoursePeriod;
 import com.fs.course.domain.FsUserCoursePeriodDays;
 import com.fs.course.dto.CoursePeriodSyncResultDTO;
 import com.fs.course.domain.FsUserCourseVideo;
+import com.fs.course.mapper.FsDepVideoShowMapper;
 import com.fs.course.mapper.FsUserCoursePeriodDaysMapper;
 import com.fs.course.mapper.FsUserCourseVideoMapper;
+import com.fs.course.param.*;
 import com.fs.course.param.BatchEditCoverParam;
 import com.fs.course.param.BatchRedUpdate;
 import com.fs.course.param.BatchTitleUpdate;
@@ -37,6 +41,7 @@ import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
@@ -82,6 +87,10 @@ public class FsUserCourseVideoController extends BaseController
     @Autowired
     private IFsUserCoursePeriodDaysService sysUserCoursePeriodDaysService;
 
+    @Autowired
+    private FsDepVideoShowMapper fsDepVideoShowMapper;
+    @Value("${cloud_host.company_name}")
+    private String companyName;
     /**
      * 查询课堂视频列表
      */

+ 3 - 1
fs-admin/src/main/java/com/fs/live/controller/LiveAfterSalesController.java

@@ -79,7 +79,9 @@ public class LiveAfterSalesController extends BaseController
         List<LiveAfterSalesItem> list = liveAfterSalesItemService.selectLiveAfterSalesItemByAfterId(id);
         List<LiveAfterSalesLogs> logList = liveAfterSalesLogsService.selectLiveAfterSalesLogsByAfterId(id);
         FsUser user=userService.selectFsUserById(liveAfterSales.getUserId());
-        user.setPhone(ParseUtils.parsePhone(user.getPhone()));
+        if (user != null) {
+            user.setPhone(ParseUtils.parsePhone(user.getPhone()));
+        }
         LiveOrder liveOrder = orderService.selectLiveOrderByOrderId(String.valueOf(liveAfterSales.getOrderId()));
         return R.ok().put("afterSales",liveAfterSales).put("items",list).put("logs",logList).put("user",user).put("order",liveOrder);
 

+ 24 - 5
fs-company/src/main/java/com/fs/company/controller/company/IndexStatisticsController.java

@@ -11,6 +11,7 @@ import com.fs.framework.service.TokenService;
 import com.fs.statis.StatisticsRedisConstant;
 import com.fs.statis.dto.*;
 import com.fs.statis.service.IStatisticsService;
+import com.fs.statis.service.impl.StatisticsCompanyServiceImpl;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
@@ -42,6 +43,9 @@ public class IndexStatisticsController {
 
     @Autowired
     CloudHostProper cloudHostProper;
+    @Autowired
+    private StatisticsCompanyServiceImpl statisticsCompanyService;
+
     /**
      * 分析概览
      */
@@ -60,7 +64,11 @@ public class IndexStatisticsController {
         }
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         param.setCompanyId(loginUser.getCompany().getCompanyId());
-        analysisPreviewDTO = redisCache.getCacheObject(String.format("%s:%d:%d:%d",DATA_OVERVIEW_DEALER_ANALYSISPREVIEW,type,userType,param.getCompanyId()));
+        if (param.getType().equals(5)){// 指定日期直接查,不走缓存
+            return R.ok().put("data",statisticsCompanyService.analysisPreview(param));
+        }else {
+            analysisPreviewDTO = redisCache.getCacheObject(String.format("%s:%d:%d:%d",DATA_OVERVIEW_DEALER_ANALYSISPREVIEW,type,userType,param.getCompanyId()));
+        }
 
         return R.ok().put("data",analysisPreviewDTO);
     }
@@ -179,7 +187,9 @@ public class IndexStatisticsController {
         }else{
             Long companyId = loginUser.getCompany().getCompanyId();
             param.setCompanyId(companyId);
-
+            if (param.getType().equals(5)){
+                return R.ok().put("data", statisticsCompanyService.watchEndPlayTrend(param));
+            }
             String key = String.format("%s:%d:%d:%d", DATA_OVERVIEW_DEALER_CHARTS, type,userType,param.getCompanyId());
             List<DeaMemberTopTenDTO> deaMemberTopTenDTOS = redisCache.getCacheObject(key);
             return R.ok().put("data", deaMemberTopTenDTOS);
@@ -204,7 +214,9 @@ public class IndexStatisticsController {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         Long companyId = loginUser.getCompany().getCompanyId();
         param.setCompanyId(companyId);
-
+        if (param.getType().equals(5)){
+            return R.ok().put("data", statisticsService.deaMemberTopTen(param));
+        }
         List<DeaMemberTopTenDTO> deaMemberTopTenDTOS = redisCache.getCacheObject(String.format("%s:%d:%d:%d:%d", CHARTS_MEMBER_TOP_TEN_WATCH, type, statisticalType,userType,param.getCompanyId()));
         if(deaMemberTopTenDTOS == null){
             deaMemberTopTenDTOS = new ArrayList<>();
@@ -223,7 +235,9 @@ public class IndexStatisticsController {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         Long companyId = loginUser.getCompany().getCompanyId();
         param.setCompanyId(companyId);
-
+        if (param.getType().equals(5)){
+            R.ok().put("data", statisticsCompanyService.rewardMoneyTopTen(param));
+        }
         List<RewardMoneyTopTenDTO> rewardMoneyTopTenDTOS = redisCache.getCacheObject( String.format("%s:%d:%d:%d:%d", CHARTS_REWARD_MONEY_TOP_TEN, type,dataType,userType,param.getCompanyId()));
         return R.ok().put("data", rewardMoneyTopTenDTOS);
     }
@@ -238,7 +252,9 @@ public class IndexStatisticsController {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         Long companyId = loginUser.getCompany().getCompanyId();
         param.setCompanyId(companyId);
-
+        if (param.getType().equals(5)){
+            return R.ok().put("data", statisticsCompanyService.rewardMoneyTrendDTO(param));
+        }
         List<RewardMoneyTrendDTO> rewardMoneyTrendDTOS = redisCache.getCacheObject( String.format("%s:%d:%d:%d", CHARTS_REWARD_MONEY_TREND, type,userType,param.getCompanyId()));
         return R.ok().put("data", rewardMoneyTrendDTOS);
     }
@@ -256,6 +272,9 @@ public class IndexStatisticsController {
         Long companyId = loginUser.getCompany().getCompanyId();
         param.setCompanyId(companyId);
 
+        if (param.getType().equals(5)){
+            return R.ok().put("data",statisticsService.watchCourseTopTen(param));
+        }
         List<CourseStatsDTO> courseStatsDTOS = redisCache.getCacheObject(String.format("%s:%d:%d:%d:%s:%d", CHARTS_WATCH_TOP_TEN, type,statisticalType,userType,sort,param.getCompanyId()));
         return R.ok().put("data", courseStatsDTOS);
     }

+ 10 - 2
fs-company/src/main/java/com/fs/framework/config/DataSourceConfig.java

@@ -34,13 +34,21 @@ public class DataSourceConfig {
         return new DruidDataSource();
     }
 
+    @Bean
+    @ConfigurationProperties(prefix = "spring.datasource.mysql.druid.slave")
+    public DataSource slaveDataSource() {
+        return new DruidDataSource();
+    }
+
 
 
     @Bean
     @Primary
-    public DynamicDataSource dataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("sopDataSource") DataSource sopDataSource) {
+    public DynamicDataSource dataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("sopDataSource") DataSource sopDataSource,
+                                        @Qualifier("slaveDataSource") DataSource slaveDataSource) {
         Map<Object, Object> targetDataSources = new HashMap<>();
-        targetDataSources.put(DataSourceType.MASTER, masterDataSource);
+        targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
+        targetDataSources.put(DataSourceType.SLAVE.name(), masterDataSource);
         targetDataSources.put(DataSourceType.SOP.name(), sopDataSource);
         return new DynamicDataSource(masterDataSource, targetDataSources);
     }

+ 9 - 2
fs-framework/src/main/java/com/fs/framework/config/DataSourceConfig.java

@@ -32,6 +32,11 @@ public class DataSourceConfig {
     public DataSource masterDataSource() {
         return new DruidDataSource();
     }
+    @Bean
+    @ConfigurationProperties(prefix = "spring.datasource.mysql.druid.slave")
+    public DataSource slaveDataSource() {
+        return new DruidDataSource();
+    }
 
     @Bean
     @ConfigurationProperties(prefix = "spring.datasource.clickhouse")
@@ -41,9 +46,11 @@ public class DataSourceConfig {
 
     @Bean
     @Primary
-    public DynamicDataSource dataSource(@Qualifier("clickhouseDataSource") DataSource clickhouseDataSource,@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("sopDataSource") DataSource sopDataSource) {
+    public DynamicDataSource dataSource(@Qualifier("clickhouseDataSource") DataSource clickhouseDataSource,@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("sopDataSource") DataSource sopDataSource,
+             @Qualifier("slaveDataSource") DataSource slaveDataSource) {
         Map<Object, Object> targetDataSources = new HashMap<>();
-        targetDataSources.put(DataSourceType.MASTER, masterDataSource);
+        targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
+        targetDataSources.put(DataSourceType.SLAVE.name(), slaveDataSource);
         targetDataSources.put(DataSourceType.SOP.name(), sopDataSource);
         targetDataSources.put(DataSourceType.CLICKHOUSE.name(), clickhouseDataSource);
         return new DynamicDataSource(masterDataSource, targetDataSources);

+ 8 - 1
fs-live-app/src/main/java/com/fs/framework/config/DataSourceConfig.java

@@ -34,12 +34,19 @@ public class DataSourceConfig {
         return new DruidDataSource();
     }
 
+    @Bean
+    @ConfigurationProperties(prefix = "spring.datasource.mysql.druid.slave")
+    public DataSource slaveDataSource() {
+        return new DruidDataSource();
+    }
 
 
     @Bean
     @Primary
-    public DynamicDataSource dataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("sopDataSource") DataSource sopDataSource) {
+    public DynamicDataSource dataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("sopDataSource") DataSource sopDataSource
+            , @Qualifier("slaveDataSource") DataSource slaveDataSource) {
         Map<Object, Object> targetDataSources = new HashMap<>();
+        targetDataSources.put(DataSourceType.SLAVE.name(), slaveDataSource);
         targetDataSources.put(DataSourceType.SOP.name(), sopDataSource);
         return new DynamicDataSource(masterDataSource, targetDataSources);
     }

+ 29 - 0
fs-service/src/main/java/com/fs/course/domain/FsDepVideoShow.java

@@ -0,0 +1,29 @@
+package com.fs.course.domain;
+
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 部门视频疗包展示关联对象 fs_dep_video_show
+ *
+ * @author fs
+ * @date 2025-10-11
+ */
+@Data
+@EqualsAndHashCode()
+public class FsDepVideoShow {
+
+    /** 视频id */
+    private Long videoId;
+
+    /** 是否展示疗包 0展示 1不展示 */
+    @Excel(name = "是否展示疗包 0展示 1不展示")
+    private String isShow;
+
+    /** 部门id */
+    @Excel(name = "部门id")
+    private Long depId;
+
+
+}

+ 4 - 0
fs-service/src/main/java/com/fs/course/domain/FsUserCourseVideo.java

@@ -161,4 +161,8 @@ public class FsUserCourseVideo extends BaseEntity
      * 完课标签 表中的ID
      */
     private Long watchedTgId;
+
+    @TableField(exist = false)
+    private Integer showProduct; //1不展示疗法,0展示疗法
+
 }

+ 43 - 0
fs-service/src/main/java/com/fs/course/mapper/FsDepVideoShowMapper.java

@@ -0,0 +1,43 @@
+package com.fs.course.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.course.domain.FsDepVideoShow;
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
+
+/**
+ * 部门视频疗包展示关联Mapper接口
+ * 
+ * @author fs
+ * @date 2025-10-11
+ */
+public interface FsDepVideoShowMapper extends BaseMapper<FsDepVideoShow>{
+    /**
+     * 部门视频疗包展示关联
+     * 
+     * @param videoId, depId  部门视频疗包展示关联主键
+     * @return 部门视频疗包展示关联
+     */
+    @Select("<script>" +
+            "SELECT is_show FROM fs_dep_video_show WHERE video_id = #{videoId}" +
+            "<if test='depId != null'> AND dep_id = #{depId}</if>" +
+            "</script>")
+    String selectFsDepVideoShowByVideoId(@Param("videoId")Long videoId,@Param("depId") Long depId);
+
+    @Select("SELECT is_show FROM fs_dep_video_show WHERE video_id = #{videoId}")
+    String searchAllByVideoIdString(Long videoId);
+    /**
+     * 增加部门视频疗包展示关联
+     *
+     * @param fsDepVideoShow 部门视频疗包展示关联主键
+     * @return 部门视频疗包展示关联
+     */
+    @Insert("INSERT INTO fs_dep_video_show(video_id, is_show, dep_id) VALUES(#{videoId}, #{isShow}, #{depId})")
+    int insertFsDepVideoShowByVideoId(FsDepVideoShow fsDepVideoShow);
+
+    @Update("UPDATE fs_dep_video_show SET is_show = #{isShow} WHERE video_id = #{videoId} AND dep_id = #{depId}")
+    int updateByVideoId(FsDepVideoShow fsDepVideoShow);
+
+}

+ 17 - 1
fs-service/src/main/java/com/fs/gtPush/service/impl/uniPush2ServiceImpl.java

@@ -2,6 +2,7 @@ package com.fs.gtPush.service.impl;
 
 import cn.hutool.http.HttpUtil;
 import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSONObject;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.alibaba.fastjson.JSON;
 import com.fasterxml.jackson.core.JsonProcessingException;
@@ -14,11 +15,14 @@ import com.fs.gtPush.domain.UniPushLog;
 import com.fs.gtPush.service.UniPushLogService;
 import com.fs.gtPush.service.uniPush2Service;
 import com.fs.im.service.OpenIMService;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.service.ISysConfigService;
 import org.springframework.beans.factory.annotation.Autowired;
 import com.fs.gtPush.utils.PushUtils;
 import com.fs.his.domain.FsUser;
 import com.fs.his.service.IFsUserService;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 import java.util.HashMap;
@@ -28,16 +32,28 @@ import java.util.Map;
 public class uniPush2ServiceImpl implements uniPush2Service {
     @Autowired
     private OpenIMService openIMService;
-    private static final String url = "https://fc-mp-de6e03a9-c1a3-439b-9eec-d0dc3c565e4e.next.bspapp.com/push";
+//    private static final String url = "https://fc-mp-de6e03a9-c1a3-439b-9eec-d0dc3c565e4e.next.bspapp.com/push";
+
+//    @Value("${openIM.pushUrl}")
+//    private String openIMpushUrl;
 
     @Autowired
     private IFsUserService userService;
 
     @Autowired
     private UniPushLogService logService;
+    @Autowired
+    private ISysConfigService iSysConfigService;
 
     @Override
     public PushResult pushMessage(PushReqBean push) {
+        SysConfig config = iSysConfigService.selectConfigByConfigKey("his.config");
+        JSONObject json = JSON.parseObject(config.getConfigValue());
+        String url = json.getString("appPushUrl");
+        if (StringUtils.isBlank(url)) {
+            throw new RuntimeException("his.config 中未配置 appPushUrl");
+        }
+
         String result = HttpUtil.post(url, push.toString());
         PushResult pushResult = JSONUtil.toBean(result, PushResult.class);
         return pushResult;

+ 4 - 0
fs-service/src/main/java/com/fs/his/domain/FsAppVersion.java

@@ -36,6 +36,10 @@ public class FsAppVersion extends BaseEntity
     @Excel(name = "下载地址")
     private String url;
 
+    /** 下载地址 */
+    @Excel(name = "wgt下载地址")
+    private String wgtUrl;
+
     /** APP类型 1android 2ios */
     @Excel(name = "APP类型 1android 2ios")
     private Integer type;

+ 4 - 0
fs-service/src/main/java/com/fs/his/domain/FsUser.java

@@ -190,6 +190,10 @@ public class FsUser extends BaseEntity
     /** app登录后不为null(表示是否下载app) */
     private String historyApp;
 
+    private String appOpenId;
+
+    private String appleKey; // 苹果key登陆验证
+
     public void setNickName(String nickname)
     {
         if(StringUtils.isNotEmpty(nickname)){

+ 3 - 0
fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java

@@ -489,4 +489,7 @@ public interface FsUserMapper
      * 查询用户列表(用于积分管理,支持手机号和昵称模糊查询)
      */
     List<FsUser> selectFsUserListForIntegral(FsUser fsUser);
+
+    @Select("select * from fs_user where apple_key = #{appleKey}")
+    FsUser findUserByAppleKey(String appleKey);
 }

+ 8 - 0
fs-service/src/main/java/com/fs/his/service/IFsUserCouponService.java

@@ -1,6 +1,8 @@
 package com.fs.his.service;
 
 import java.util.List;
+
+import com.fs.his.domain.FsUser;
 import com.fs.his.domain.FsUserCoupon;
 import com.fs.his.param.FsUserCouponParam;
 import com.fs.his.param.FsUserCouponSendParam;
@@ -74,4 +76,10 @@ public interface IFsUserCouponService
     List<FsUserCouponListUVO> getMyEnableCouponList(FsUserCouponUParam param);
 
     FsUserCouponCountUVO selectFsUserCouponCountUVO(FsUserCouponUParam param);
+
+    /**
+     * 发送注册优惠券
+     * @param user
+     */
+    void sendRegisterCoupon(FsUser user);
 }

+ 44 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsUserCouponServiceImpl.java

@@ -1,12 +1,18 @@
 package com.fs.his.service.impl;
 
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.Date;
 import java.util.List;
 
+import cn.hutool.json.JSONUtil;
 import com.fs.common.exception.CustomException;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.SecurityUtils;
 import com.fs.common.utils.StringUtils;
+import com.fs.his.config.CouponConfig;
 import com.fs.his.domain.FsCoupon;
+import com.fs.his.domain.FsUser;
 import com.fs.his.mapper.FsCouponMapper;
 import com.fs.his.param.FsUserCouponParam;
 import com.fs.his.param.FsUserCouponSendParam;
@@ -15,6 +21,7 @@ import com.fs.his.utils.PhoneUtil;
 import com.fs.his.vo.FsUserCouponCountUVO;
 import com.fs.his.vo.FsUserCouponListUVO;
 import com.fs.his.vo.FsUserCouponListVO;
+import com.fs.system.service.ISysConfigService;
 import org.checkerframework.checker.units.qual.A;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -37,6 +44,10 @@ public class FsUserCouponServiceImpl implements IFsUserCouponService
 
     @Autowired
     private FsCouponMapper fsCouponMapper;
+
+    @Autowired
+    private ISysConfigService configService;
+
     /**
      * 查询会员优惠券
      *
@@ -192,4 +203,37 @@ public class FsUserCouponServiceImpl implements IFsUserCouponService
         }
         return countUVO;
     }
+
+    @Override
+    public void sendRegisterCoupon(FsUser user) {
+        Date createTime = user.getCreateTime();
+        if (!isCreateTimeMoreThanOneDay(createTime)) {
+            Long userId = user.getUserId();
+            String json = configService.selectConfigByKey("his.coupon");
+            CouponConfig config = JSONUtil.toBean(json, CouponConfig.class);
+            Long[] registerCoupons = config.getRegisterCoupon();
+            if (registerCoupons != null){
+                for (Long registerCoupon : registerCoupons) {
+                    FsUserCouponSendParam param = new FsUserCouponSendParam();
+                    param.setCouponId(registerCoupon);
+                    param.setUserId(userId);
+                    sendFsUserCoupon(param);
+                }
+            }
+
+        }
+    }
+
+    /**
+     * 判断是否超过一天
+     * @param createTime
+     * @return
+     */
+    public static boolean isCreateTimeMoreThanOneDay(Date createTime) {
+        LocalDateTime now = LocalDateTime.now();
+        LocalDateTime createTimeLocal = createTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
+
+        // 判断是否超过一天
+        return createTimeLocal.isBefore(now.minusDays(1));
+    }
 }

+ 1 - 1
fs-service/src/main/java/com/fs/live/mapper/LiveOrderMapper.java

@@ -503,7 +503,7 @@ public interface LiveOrderMapper {
     /*
     * 查询订单创建时间为最近30分钟的订单
     * */
-    @Select("SELECT * FROM live_order WHERE create_time >= '2026-01-15 19:00:00' and status = 0 and refund_status = 0")
+    @Select("SELECT * FROM live_order WHERE create_time >= DATE_SUB(NOW(), INTERVAL 30 MINUTE) and status = 0 and refund_status = 0")
     List<LiveOrder> selectBankOrder();
 
 

+ 5 - 5
fs-service/src/main/java/com/fs/live/service/impl/LiveServiceImpl.java

@@ -1021,16 +1021,16 @@ public class LiveServiceImpl implements ILiveService
             }
 
             // 如果视频时长大于0,将直播间信息存入Redis
-            if (videoDuration > 0 && live.getStartTime() != null) {
+            if (videoDuration > 0 && exist.getStartTime() != null) {
                 Map<String, Object> tagMarkInfo = new HashMap<>();
-                tagMarkInfo.put("liveId", live.getLiveId());
-                tagMarkInfo.put("startTime", live.getStartTime().atZone(java.time.ZoneId.systemDefault()).toInstant().toEpochMilli());
+                tagMarkInfo.put("liveId", exist.getLiveId());
+                tagMarkInfo.put("startTime", exist.getStartTime().atZone(java.time.ZoneId.systemDefault()).toInstant().toEpochMilli());
                 tagMarkInfo.put("videoDuration", videoDuration);
 
-                String tagMarkKey = String.format(LiveKeysConstant.LIVE_TAG_MARK_CACHE, live.getLiveId());
+                String tagMarkKey = String.format(LiveKeysConstant.LIVE_TAG_MARK_CACHE, exist.getLiveId());
                 redisCache.setCacheObject(tagMarkKey, JSON.toJSONString(tagMarkInfo), 24, TimeUnit.HOURS);
                 log.info("手动开直播间开启,已加入打标签缓存: liveId={}, startTime={}, videoDuration={}",
-                        live.getLiveId(), live.getStartTime(), videoDuration);
+                        exist.getLiveId(), exist.getStartTime(), videoDuration);
             }
         } catch (Exception e) {
             log.error("手动开写入直播间打标签缓存失败: liveId={}, error={}", live.getLiveId(), e.getMessage(), e);

+ 2 - 1
fs-service/src/main/java/com/fs/live/utils/redis/RedisBatchHandler.java

@@ -51,6 +51,7 @@ public class RedisBatchHandler {
         List<LiveTrafficLog> batchList = jsonList.stream()
                 .map(json -> JSON.parseObject(json, LiveTrafficLog.class))
                 .collect(Collectors.toList());
+        int size = batchList.size();
 
         Map<String, LiveTrafficLog> uniqueMap = batchList.stream()
                 .collect(Collectors.toMap(
@@ -72,7 +73,7 @@ public class RedisBatchHandler {
             // 批量写入数据库
             liveTrafficLogMapper.batchInsert(batchList);
             // 删除已消费的数据
-            redisTemplate.opsForList().trim(BATCH_QUEUE_KEY, batchList.size(), -1);
+            redisTemplate.opsForList().trim(BATCH_QUEUE_KEY, size, -1);
         } catch (Exception e) {
             // 消费失败:记录日志,不删除Redis数据(重试)
             log.error("Redis批量消费失败,将重试", e);

+ 6 - 0
fs-service/src/main/java/com/fs/qw/mapper/QwWatchLogMapper.java

@@ -115,6 +115,12 @@ public interface QwWatchLogMapper extends BaseMapper<QwWatchLog>{
             "<if test ='ids !=null and ids!=\"\"'>\n" +
             "   and qec.qw_user_id in (${ids})\n" +
             "</if>" +
+            "<if test = 'addWays != null and addWays.size()>0' >" +
+            "and qec.add_way in  " +
+            "<foreach collection=\"addWays\" item=\"item\" open=\"(\" close=\")\" separator=\",\">\n" +
+            "       ${item}\n" +
+            "                  </foreach>" +
+            "</if>" +
             "GROUP BY\n" +
             "    qec.qw_user_id, DATE(qec.create_time) \n" +
             "ORDER BY\n" +

+ 6 - 0
fs-service/src/main/java/com/fs/qw/param/QwWatchLogStatisticsListParam.java

@@ -45,6 +45,12 @@ public class QwWatchLogStatisticsListParam {
     private Long pageNum;
     private Long pageSize;
     private List<Long> filterDeptIds;
+
+    /**
+     * 添加方式
+     */
+    private List<Integer> addWays;
+
     /**
      * 今正要求把公司筛选条件优化到细分至部门,销售(前端判断,只有今正传)
      */

+ 1 - 1
fs-service/src/main/java/com/fs/statis/dto/AnalysisPreviewQueryDTO.java

@@ -10,7 +10,7 @@ import java.io.Serializable;
 public class AnalysisPreviewQueryDTO implements Serializable {
 
     /**
-     * 0 今日,1昨日,2本周,3本月,4上月
+     * 0 今日,1昨日,2本周,3本月,4上月,5指定日期(不走缓存,直接查)
      */
     private Integer type;
 

+ 7 - 0
fs-service/src/main/java/com/fs/statis/service/impl/StatisticsServiceImpl.java

@@ -1,5 +1,6 @@
 package com.fs.statis.service.impl;
 
+import cn.hutool.core.map.MapUtil;
 import com.alibaba.fastjson.JSONObject;
 import com.fs.common.constant.FsConstants;
 import com.fs.common.core.domain.R;
@@ -1107,6 +1108,12 @@ public class StatisticsServiceImpl implements IStatisticsService {
     @Override
     public List<WatchCourseStatisticsResultDTO> getWatchCourseStatisticsData(AnalysisPreviewQueryDTO param) {
 
+        if (param.getType().equals(5)){
+            HashMap<String, Object> map = MapUtil.newHashMap();
+            map.put("startTime", param.getStartTime());
+            map.put("endTime", param.getEndTime());
+            return fsCourseWatchLogMapper.watchCourseStatisticsGroupByCompany(map);
+        }
         String redisData = redisCache.getCacheObject(FsConstants.WATCH_COURSE_STATISTICS_GROUP_COMPANY + param.getType());
         List<WatchCourseStatisticsResultDTO> watchCourseStatisticsDTOS = new ArrayList<>();
         if (StringUtils.isNotBlank(redisData)) {

+ 2 - 2
fs-service/src/main/resources/application-druid-jzzx-test.yml

@@ -170,10 +170,10 @@ token:
 openIM:
     secret: openIM123
     userID: imAdmin
-    url: https://web.im.fbylive.com/api
+    url: https://web.im.jiuzhouzaixian.com/api
 #是否使用新im
 im:
-    type: NONE
+    type: OPENIM
 #是否为新商户,新商户不走mpOpenId
 isNewWxMerchant: true
 

+ 2 - 2
fs-service/src/main/resources/application-druid-jzzx.yml

@@ -170,10 +170,10 @@ token:
 openIM:
     secret: openIM123
     userID: imAdmin
-    url: https://web.im.fbylive.com/api
+    url: https://web.im.jiuzhouzaixian.com/api
 #是否使用新im
 im:
-    type: NONE
+    type: OPENIM
 #是否为新商户,新商户不走mpOpenId
 isNewWxMerchant: false
 

+ 3 - 3
fs-service/src/main/resources/application-druid-kyt.yml

@@ -41,9 +41,9 @@ spring:
         slave:
           # 从数据源开关/默认关闭
           enabled: false
-          url:
-          username:
-          password:
+          url: jdbc:mysql://sh-cdb-qyfybkwy.sql.tencentcdb.com:24529/fs_his?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+          username: root
+          password: Ylrztek250218!3@.
         # 初始连接数
         initialSize: 5
         # 最小连接池数量

+ 2 - 1
fs-service/src/main/resources/application-druid-sxjz.yml

@@ -165,9 +165,10 @@ openIM:
     secret: openIM123
     userID: imAdmin
     url: https://web.im.xianhthj.cn/api
+    pushUrl: https://fc-mp-d0421385-3496-42e7-b67f-59161a36a0e4.next.bspapp.com/push
 #是否使用新im
 im:
-    type: NONE
+    type: OPENIM
 #是否为新商户,新商户不走mpOpenId
 isNewWxMerchant: false
 

+ 5 - 1
fs-service/src/main/resources/mapper/his/FsAppVersionMapper.xml

@@ -17,10 +17,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="updateConfig"    column="update_config"    />
         <result property="baiduUrl"    column="baidu_url"    />
         <result property="h5Url"    column="h5_url"    />
+        <result property="wgtUrl"    column="wgt_url"    />
     </resultMap>
 
     <sql id="selectFsAppVersionVo">
-        select version_id,baidu_url,update_config, version_name, version_code, note, url, type, is_force, create_time, app_type,h5_url from fs_app_version
+        select version_id,baidu_url,update_config, version_name, version_code, note, url, type, is_force, create_time, app_type,h5_url,wgt_url from fs_app_version
     </sql>
 
     <select id="selectFsAppVersionList" parameterType="FsAppVersion" resultMap="FsAppVersionResult">
@@ -57,6 +58,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="updateConfig != null">update_config,</if>
             <if test="baiduUrl != null">baidu_url,</if>
             <if test="h5Url != null and h5Url !=''">h5_url,</if>
+            <if test="wgtUrl != null and wgtUrl !=''">wgt_url,</if>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="versionName != null">#{versionName},</if>
@@ -70,6 +72,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="updateConfig != null">#{updateConfig},</if>
             <if test="baiduUrl != null">#{baiduUrl},</if>
             <if test="h5Url != null and h5Url !=''">#{h5Url},</if>
+            <if test="wgtUrl != null and wgtUrl !=''">#{wgtUrl},</if>
          </trim>
     </insert>
 
@@ -87,6 +90,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="updateConfig != null">update_config = #{updateConfig},</if>
             <if test="baiduUrl != null">baidu_url = #{baiduUrl},</if>
             <if test="h5Url != null and h5Url !=''">h5_url = #{h5Url},</if>
+            <if test="wgtUrl != null and wgtUrl !=''">wgt_url = #{wgtUrl},</if>
         </trim>
         where version_id = #{versionId}
     </update>

+ 0 - 2
fs-service/src/main/resources/mapper/his/FsUserIntegralLogsMapper.xml

@@ -59,7 +59,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="createTime != null">create_time,</if>
             <if test="businessType != null">business_type,</if>
             <if test="status != null">status,</if>
-            <if test="remark != null">remark,</if>
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="userId != null">#{userId},</if>
@@ -70,7 +69,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="createTime != null">#{createTime},</if>
             <if test="businessType != null">#{businessType},</if>
             <if test="status != null">#{status},</if>
-            <if test="remark != null">#{remark},</if>
          </trim>
     </insert>
 

+ 22 - 0
fs-service/src/main/resources/mapper/his/FsUserMapper.xml

@@ -50,6 +50,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="qwUserId"    column="qw_user_id"    />
         <result property="appId"    column="app_id"    />
         <result property="level" column="level"/>
+        <result property="appOpenId"    column="app_open_id"    />
+        <result property="appleKey"    column="apple_key"    />
     </resultMap>
 
     <sql id="selectFsUserVo">
@@ -609,6 +611,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="payCount != null">pay_count,</if>
             <if test="spreadCount != null">spread_count,</if>
             <if test="appId != null">app_id,</if>
+            <if test="appOpenId != null">app_open_id,</if>
+            <if test="appleKey != null">apple_key,</if>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="nickName != null">#{nickName},</if>
@@ -659,6 +663,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="payCount != null">#{payCount},</if>
             <if test="spreadCount != null">#{spreadCount},</if>
             <if test="appId != null">#{appId},</if>
+            <if test="appOpenId != null">#{appOpenId},</if>
+            <if test="appleKey != null">#{appleKey},</if>
          </trim>
     </insert>
 
@@ -711,6 +717,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="orderCount != null">order_count = #{orderCount},</if>
             <if test="companyUserId != null">company_user_id = #{companyUserId},</if>
             <if test="appId != null">app_id = #{appId},</if>
+            <if test="appOpenId != null">app_open_id = #{appOpenId},</if>
+            <if test="appleKey != null">apple_key = #{appleKey},</if>
         </trim>
         where user_id = #{userId}
     </update>
@@ -2451,6 +2459,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     <select id="selectFsUserListByPhone" resultType="com.fs.his.domain.FsUser">
         select * from fs_user where phone=#{phone}
     </select>
+    <!-- 查询用户列表(用于积分管理) -->
+    <select id="selectFsUserListForIntegral" parameterType="FsUser" resultMap="FsUserResult">
+        select user_id, nick_name, phone, integral from fs_user
+        <where>
+            and is_del = 0
+            <if test="phone != null and phone != ''">
+                and phone like concat('%', #{phone}, '%')
+            </if>
+            <if test="nickName != null and nickName != ''">
+                and (nick_name like concat('%', #{nickName}, '%') or nickname like concat('%', #{nickName}, '%'))
+            </if>
+        </where>
+        order by user_id desc
+    </select>
 
     <!-- 查询被误封禁的用户(status=0且remark为null) -->
     <select id="selectMistakenlyDisabledUsers" resultMap="FsUserResult">

+ 3 - 3
fs-service/src/main/resources/mapper/statis/ConsumptionBalanceMapper.xml

@@ -174,7 +174,7 @@
                 DATE_FORMAT(create_time, '%H') AS start_date,
             </when>
             <!-- 按天分组 -->
-            <when test="type == 2 or type == 3 or type == 4">
+            <when test="type == 2 or type == 3 or type == 4 or type == 5">
                 DATE_FORMAT(create_time, '%Y-%m-%d') AS start_date,
             </when>
         </choose>
@@ -196,7 +196,7 @@
         GROUP BY
         <choose>
             <when test="type == 0 or type == 1">DATE_FORMAT(create_time, '%H')</when>
-            <when test="type == 2 or type == 3 or type == 4">DATE_FORMAT(create_time, '%Y-%m-%d')</when>
+            <when test="type == 2 or type == 3 or type == 4 or type == 5">DATE_FORMAT(create_time, '%Y-%m-%d')</when>
         </choose>
         ORDER BY
         start_date
@@ -447,7 +447,7 @@
             DATE_FORMAT(rpl.create_time, '%H') AS start_date,
         </if>
         --                 本周/本月/上月 天
-        <if test="type == 2 or type == 3 or type == 4">
+        <if test="type == 2 or type == 3 or type == 4 or type == 5">
             DATE_FORMAT(rpl.create_time, '%Y-%m-%d') AS start_date,
         </if>
             SUM(rpl.amount) as rewardMoney

+ 178 - 20
fs-user-app/src/main/java/com/fs/app/controller/AppLoginController.java

@@ -3,6 +3,7 @@ package com.fs.app.controller;
 
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.date.DateTime;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.fs.app.annotation.Login;
 import com.fs.app.param.*;
 import com.fs.app.utils.WxUtil;
@@ -14,10 +15,13 @@ import com.fs.common.exception.ServiceException;
 import com.fs.common.service.ISmsService;
 import com.fs.common.utils.sign.Md5Utils;
 import com.fs.core.config.WxOpenProperties;
+import com.fs.course.domain.FsCoursePlaySourceConfig;
+import com.fs.course.service.IFsCoursePlaySourceConfigService;
 import com.fs.his.config.FsSysConfig;
 import com.fs.his.domain.FsUser;
 import com.fs.his.domain.FsUserNewTask;
 import com.fs.his.mapper.FsUserMapper;
+import com.fs.his.service.IFsUserCouponService;
 import com.fs.his.service.IFsUserNewTaskService;
 import com.fs.his.service.IFsUserService;
 import com.fs.his.utils.ConfigUtil;
@@ -63,8 +67,14 @@ public class AppLoginController extends AppBaseController{
     @Autowired
     private RedisCache redisCache;
 
+    @Autowired
+    private IFsUserCouponService fsUserCouponService;
+
     @Autowired
     private ISmsService smsService;
+    @Autowired
+    private IFsCoursePlaySourceConfigService fsCoursePlaySourceConfigService;
+
     @ApiOperation("注册app用户")
     @PostMapping("/register")
     @RepeatSubmit
@@ -232,8 +242,29 @@ public class AppLoginController extends AppBaseController{
             if (StringUtils.isBlank(param.getCode())) {
                 return R.error("code不存在");
             }
-            logger.info("zyp app微信登录,param:{},输出appid,{},secret:{}", param, openProperties.getAppId(), openProperties.getSecret());
-            Map result = WxUtil.getAccessToken(param.getCode(), openProperties.getAppId(), openProperties.getSecret());
+
+            String appId = param.getAppId();
+            String appSecret = "";
+            if (StringUtils.isBlank(appId)) {
+                List<FsCoursePlaySourceConfig> list = fsCoursePlaySourceConfigService.list(new QueryWrapper<FsCoursePlaySourceConfig>().eq("name", "app").eq("is_del", 0));
+                if(!list.isEmpty()){
+                    FsCoursePlaySourceConfig fsCoursePlaySourceConfig = list.get(0);
+                    appId = fsCoursePlaySourceConfig.getAppid();
+                    appSecret =  fsCoursePlaySourceConfig.getSecret();
+                }
+            } else {
+                FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigService.getOne(new QueryWrapper<FsCoursePlaySourceConfig>().eq("appid", appId).eq("is_del", 0));
+                if(fsCoursePlaySourceConfig != null){
+                    appId = fsCoursePlaySourceConfig.getAppid();
+                    appSecret =  fsCoursePlaySourceConfig.getSecret();
+                }
+            }
+            if (StringUtils.isBlank(appId) || StringUtils.isBlank(appSecret)) {
+                appId = openProperties.getAppId();
+                appSecret = openProperties.getSecret();
+            }
+            logger.info("zyp app微信登录,param:{},输出appid,{},secret:{}", param, appId, appSecret);
+            Map result = WxUtil.getAccessToken(param.getCode(),appId,appSecret);
             String accessToken = result.get("access_token").toString();
             String unionid = result.get("unionid").toString();
 
@@ -253,12 +284,13 @@ public class AppLoginController extends AppBaseController{
                 user.setSource(param.getSource()!=null ? param.getSource() : null);
                 user.setNickName(nickname);
                 user.setAvatar(avatar);
+                user.setAppOpenId(openid);
                 if (sex!=0){
                     user.setSex(sex);
                 }
                 user.setUnionId(unionid);
                 // 新用户 - 添加 appId
-                user.setAppId(openProperties.getAppId());
+                user.setAppId(appId);
                 user.setCreateTime(new Date());
                 user.setStatus(1);
                 if (StringUtils.isNotEmpty(param.getJpushId())) {
@@ -270,7 +302,7 @@ public class AppLoginController extends AppBaseController{
                 return R.ok(map);
             } else {
                 // 老用户 - 检查并添加appId(不重复添加)
-                String updatedAppId = addAppIdIfNotExists(user.getAppId(), openProperties.getAppId());
+                String updatedAppId = addAppIdIfNotExists(user.getAppId(), appId);
                 if (!updatedAppId.equals(user.getAppId())) {
                     FsUser userMap = new FsUser();
                     userMap.setUserId(user.getUserId());
@@ -279,6 +311,7 @@ public class AppLoginController extends AppBaseController{
                 }
 
                 if (StringUtils.isNotEmpty(param.getJpushId())) {
+                    user.setAppOpenId(openid);
                     updateExistingUserJpushId(user, param.getJpushId());
                 }
                 if (StringUtils.isEmpty(user.getPhone())) {
@@ -301,6 +334,91 @@ public class AppLoginController extends AppBaseController{
 
     }
 
+    @ApiOperation("苹果登录")
+    @PostMapping("/loginByApple")
+    @Transactional
+    public R loginByApple(@Validated @RequestBody FsUserLoginByAppleParam param) {
+        try {
+            if (StringUtils.isEmpty(param.getAppleKey())) {
+                return R.error("获取苹果key失败");
+            }
+            // 根据苹果key查询用户
+            FsUser user = userMapper.findUserByAppleKey(param.getAppleKey());
+            Map<String, Object> map = new HashMap<>();
+            if (user == null) {
+                map.put("isNew", true);
+                return R.ok(map);
+            } else {
+                if (StringUtils.isNotEmpty(param.getJpushId())) {
+                    updateExistingUserJpushId(user, param.getJpushId());
+                }
+                if (StringUtils.isEmpty(user.getPhone())) {
+                    map.put("isNew", true);
+                    return R.ok(map);
+                }
+            }
+            /*if (user.getStatus()==0){
+                return R.error("登录失败,账户被禁用");
+            }*/
+            int isFirstLogin = userNewTaskService.performTaskOne(user.getUserId());
+            String token = jwtUtils.generateToken(user.getUserId());
+            redisCache.setCacheObject("userToken:" + user.getUserId(), token, 604800, TimeUnit.SECONDS);
+            map.put("token", token);
+            map.put("user", user);
+            map.put("isFirst",isFirstLogin);
+            return R.ok(map);
+        }catch (Exception e){
+            logger.error("zyp 苹果登录失败:{}", e.getMessage());
+            return R.error("登录失败");
+        }
+    }
+
+    private FsUser createNewAppleUser(FsUserEditPhoneParam param, String phoneNumber) {
+        FsUser newUser = new FsUser();
+        newUser.setLoginDevice(param.getLoginDevice()!=null ? param.getLoginDevice() : null);
+        newUser.setSource(param.getSource()!=null ? param.getSource() : null);
+        newUser.setAppleKey(param.getAppleKey());
+        newUser.setPhone(param.getPhone());
+        newUser.setPassword(Md5Utils.hash(param.getPassword()));
+        newUser.setNickName("苹果用户" + param.getPhone().substring(param.getPhone().length() - 4));
+        newUser.setCreateTime(new Date());
+        newUser.setStatus(1);
+        newUser.setAvatar("https://cos.his.cdwjyyh.com/fs/20240926/420728ee06e54575ba82665dedb4756b.png");
+        if (StringUtils.isNotEmpty(param.getJpushId())) {
+            newUser.setJpushId(param.getJpushId());
+        }
+        userService.insertFsUser(newUser);
+        return newUser;
+
+    }
+
+    @ApiOperation("绑定手机号")
+    @PostMapping("/setIPhoneNumber")
+    public R setIPhoneNumber(@Validated @RequestBody FsUserEditPhoneParam param) {
+        FsUser userMap = findUserByPhone(param.getPhone());
+        if (userMap != null) {
+            if (StringUtils.isNotEmpty(userMap.getAppleKey()) && !param.getAppleKey().equals(userMap.getAppleKey())) {
+                return R.error("该手机号已绑定其他账号");
+            }
+            if (param.getSimExist() == 0 && !Md5Utils.hash(param.getPassword()).equals(userMap.getPassword())) {
+                return R.error("密码不正确");
+            }
+        } else {
+            userMap = createNewAppleUser(param, param.getPhone());
+        }
+
+        userMap.setLoginDevice(param.getLoginDevice());
+        userMap.setSource(param.getSource());
+        if (userMap.getNickName().equals("匿名用户**")) {
+            userMap.setNickName("苹果用户" + param.getPhone().substring(param.getPhone().length() - 4));
+        }
+        userMap.setAppleKey(param.getAppleKey());
+        if (userService.updateFsUser(userMap)>0){
+            return generateTokenAndReturn(userMap);
+        }
+        return R.error("绑定手机号失败");
+    }
+
     @PostMapping("/loginByPhone")
     public R loginByPhone(@RequestBody Map<String,String> map){
         String phone = map.get("phone");
@@ -368,15 +486,33 @@ public class AppLoginController extends AppBaseController{
         FsUser userMap = findUserByPhone(param.getPhone());
         //绑定的手机号已存在用户的情况,将微信登录的时候创建的新号的UnionId移动到老号中,删除新号(将两个号合并)
         if (userMap!=null){
+            if (userMap.getUserId().equals(user.getUserId())) {
+                user.setPhone(param.getPhone());
+                user.setLoginDevice(param.getLoginDevice());
+                user.setSource(param.getSource());
+                userService.updateFsUser(user);
+                return generateTokenAndReturn(user);
+            }
             if (StringUtils.isNotEmpty(userMap.getUnionId())&&!userMap.getUnionId().equals(user.getUnionId())){
                 return R.error("该手机号已绑定其他微信");
             }
-            userMap.setLoginDevice(param.getLoginDevice() != null ? param.getLoginDevice() : null);
-            userMap.setSource(param.getSource());
-            userMap.setUnionId(user.getUnionId());
-            if (userService.updateFsUser(userMap)>0){
-                userService.realDeleteFsUserByUserId(user.getUserId());
-                return generateTokenAndReturn(userMap);
+            //如果存在手机号也有用户,微信也有用户,保留创建时间比较久的用户
+            FsUser keepUser;
+            FsUser deleteUser;
+            if (userMap.getCreateTime().before(user.getCreateTime())){
+                keepUser = userMap;
+                deleteUser = user;
+            }else {
+                keepUser = user;
+                deleteUser = userMap;
+            }
+            keepUser.setLoginDevice(param.getLoginDevice() != null ? param.getLoginDevice() : null);
+            keepUser.setSource(param.getSource());
+            keepUser.setUnionId(user.getUnionId());
+            keepUser.setPhone(param.getPhone());
+            if (userService.updateFsUser(keepUser)>0){
+                userService.realDeleteFsUserByUserId(deleteUser.getUserId());
+                return generateTokenAndReturn(keepUser);
             }
             return R.error("绑定手机号失败");
         }
@@ -414,20 +550,38 @@ public class AppLoginController extends AppBaseController{
             FsUser user = findUserByPhone(param.getPhone());
             if (user!=null && StringUtils.isEmpty(user.getUnionId())){
                 FsUser userByUnionId = userMapper.selectFsUserByUnionid(unionid);
-                //绑定的微信已存在用户的情况,将手机号一键登录的时候创建的新号的UnionId移动到老号中,删除新号(将两个号合并)
+                //绑定的微信已存在用户的情况,将手机号一键登录的时候创建的新号的手机号移动到老号中,删除新号(将两个号合并)
                 if (userByUnionId!=null){
                     if (StringUtils.isNotEmpty(userByUnionId.getPhone())&&!user.getPhone().equals(userByUnionId.getPhone())){
                         return R.error("该微信已绑定其他手机号");
                     }
-                    userByUnionId.setPhone(user.getPhone());
-                    userByUnionId.setSource(param.getSource() != null ? param.getSource() : null );
-                    userByUnionId.setLoginDevice(param.getLoginDevice() != null ? param.getLoginDevice() : null);
-                    userByUnionId.setNickName(nickname);
-                    userByUnionId.setAvatar(avatar);
-                    userByUnionId.setSex(sex);
-                    if (userService.updateFsUser(userByUnionId)>0){
-                        userService.realDeleteFsUserByUserId(user.getUserId());
-                        return generateTokenAndReturn(userByUnionId);
+                    if (userByUnionId.getUserId().equals(user.getUserId())) {
+                        user.setPhone(param.getPhone());
+                        user.setLoginDevice(param.getLoginDevice());
+                        user.setSource(param.getSource());
+                        user.setUnionId(unionid);
+                        userService.updateFsUser(user);
+                        return generateTokenAndReturn(user);
+                    }
+                    FsUser keepUser;
+                    FsUser deleteUser;
+                    if (user.getCreateTime().before(userByUnionId.getCreateTime())){
+                        keepUser = user;
+                        deleteUser = userByUnionId;
+                    } else {
+                        keepUser = userByUnionId;
+                        deleteUser = user;
+                    }
+                    keepUser.setUnionId(unionid);
+                    keepUser.setPhone(param.getPhone());
+                    keepUser.setSource(param.getSource() != null ? param.getSource() : null );
+                    keepUser.setLoginDevice(param.getLoginDevice() != null ? param.getLoginDevice() : null);
+                    keepUser.setNickName(nickname);
+                    keepUser.setAvatar(avatar);
+                    keepUser.setSex(sex);
+                    if (userService.updateFsUser(keepUser)>0){
+                        userService.realDeleteFsUserByUserId(deleteUser.getUserId());
+                        return generateTokenAndReturn(keepUser);
                     }
                     else {
                         return R.error("绑定微信失败");
@@ -439,6 +593,7 @@ public class AppLoginController extends AppBaseController{
                     user.setAvatar(avatar);
                     user.setSex(sex);
                     user.setUnionId(unionid);
+                    user.setAppOpenId(openid);
                     if (userService.updateFsUser(user)>0){
                         return generateTokenAndReturn(user);
                     }
@@ -458,6 +613,9 @@ public class AppLoginController extends AppBaseController{
         FsUser userMap = new FsUser();
         userMap.setUserId(user.getUserId());
         userMap.setJpushId(jpushId);
+        if (StringUtils.isNotEmpty(user.getAppOpenId())) {
+            userMap.setAppOpenId(user.getAppOpenId());
+        }
         userService.updateFsUser(userMap);
     }
 

+ 18 - 0
fs-user-app/src/main/java/com/fs/app/controller/store/H5ScrmController.java

@@ -35,6 +35,24 @@ public class H5ScrmController
         AgreementConfig config= JSONUtil.toBean(json, AgreementConfig.class);
         return config.getUserAgreement();
     }
+
+    @GetMapping("/newUserAgreement")
+    @ResponseBody
+    public R newUserAgreement(){
+        String json=configService.selectConfigByKey("his.agreementConfig");
+        AgreementConfig config= JSONUtil.toBean(json, AgreementConfig.class);
+        return R.ok().put("data", config.getUserRegister());
+    }
+
+    @GetMapping("/newPrivacyPolicy")
+    @ResponseBody
+    public R newPrivacyPolicy( )
+    {
+        String json=configService.selectConfigByKey("his.agreementConfig");
+        AgreementConfig config= JSONUtil.toBean(json, AgreementConfig.class);
+        return R.ok().put("data", config.getUserPrivacy());
+    }
+
     @GetMapping("/privacyPolicyNew")
     @ResponseBody
     public String privacyPolicyNew( )

+ 9 - 0
fs-user-app/src/main/java/com/fs/app/param/FsUserEditPhoneParam.java

@@ -21,4 +21,13 @@ public class FsUserEditPhoneParam implements Serializable {
     private String jpushId;
 
     private String source;
+
+    private String appleKey;
+
+    private String password;
+
+    /**
+     * 是否有SIM卡 0不存在 1存在
+     */
+    private Integer simExist;
 }

+ 17 - 0
fs-user-app/src/main/java/com/fs/app/param/FsUserLoginByAppleParam.java

@@ -0,0 +1,17 @@
+package com.fs.app.param;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class FsUserLoginByAppleParam implements Serializable {
+    private String jpushId;
+
+    private String loginDevice;//当前登陆设备
+
+    private String source; //app来源
+
+    private String appleKey;
+
+}

+ 2 - 0
fs-user-app/src/main/java/com/fs/app/param/FsUserLoginByWeChatParam.java

@@ -17,4 +17,6 @@ public class FsUserLoginByWeChatParam implements Serializable {
     private String source; //app来源
 
     private Long userId;
+
+    private String appId; //主要用于app微信登录
 }

+ 2 - 2
fs-user-app/src/main/java/com/fs/framework/config/DataSourceConfig.java

@@ -45,8 +45,8 @@ public class DataSourceConfig {
     @Primary
     public DynamicDataSource dataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("slaveDataSource") DataSource slaveDataSource, @Qualifier("sopDataSource") DataSource sopDataSource) {
         Map<Object, Object> targetDataSources = new HashMap<>();
-        targetDataSources.put(DataSourceType.MASTER, masterDataSource);
-        targetDataSources.put(DataSourceType.SLAVE, slaveDataSource);
+        targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
+        targetDataSources.put(DataSourceType.SLAVE.name(), slaveDataSource);
         targetDataSources.put(DataSourceType.SOP.name(), sopDataSource);
         return new DynamicDataSource(masterDataSource, targetDataSources);
     }