Bladeren bron

Merge remote-tracking branch 'origin/master'

ct 1 week geleden
bovenliggende
commit
2e271ab161
41 gewijzigde bestanden met toevoegingen van 492 en 463 verwijderingen
  1. 3 8
      fs-admin/src/main/java/com/fs/FSApplication.java
  2. 61 75
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseController.java
  3. 2 0
      fs-admin/src/main/java/com/fs/qw/controller/QwSopTempController.java
  4. 5 23
      fs-company/src/main/java/com/fs/company/controller/course/FsUserCoursePeriodController.java
  5. 1 0
      fs-company/src/main/java/com/fs/company/controller/qw/QwSopTempController.java
  6. 5 3
      fs-live-app/src/main/java/com/fs/live/websocket/service/WebSocketServer.java
  7. 1 1
      fs-service/src/main/java/com/fs/course/domain/FsCourseLink.java
  8. 0 49
      fs-service/src/main/java/com/fs/course/domain/FsProjectAddressConfig.java
  9. 2 4
      fs-service/src/main/java/com/fs/course/domain/FsUserCoursePeriod.java
  10. 0 14
      fs-service/src/main/java/com/fs/course/mapper/FsProjectAddressConfigMapper.java
  11. 0 12
      fs-service/src/main/java/com/fs/course/service/IFsProjectAddressConfigService.java
  12. 1 1
      fs-service/src/main/java/com/fs/course/service/IFsUserCoursePeriodService.java
  13. 6 9
      fs-service/src/main/java/com/fs/course/service/IFsUserCourseService.java
  14. 0 23
      fs-service/src/main/java/com/fs/course/service/impl/FsProjectAddressConfigServiceImpl.java
  15. 1 24
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCoursePeriodServiceImpl.java
  16. 18 45
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  17. 1 1
      fs-service/src/main/java/com/fs/course/vo/FsUserCoursePeriodVO.java
  18. 2 1
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStorePaymentScrmServiceImpl.java
  19. 11 0
      fs-service/src/main/java/com/fs/live/mapper/LiveWatchUserMapper.java
  20. 50 33
      fs-service/src/main/java/com/fs/live/service/impl/LiveWatchUserServiceImpl.java
  21. 2 1
      fs-service/src/main/java/com/fs/sop/mapper/QwSopTempMapper.java
  22. 6 1
      fs-service/src/main/java/com/fs/sop/mapper/QwSopTempRulesMapper.java
  23. 6 0
      fs-service/src/main/java/com/fs/sop/service/IQwSopTempContentService.java
  24. 5 1
      fs-service/src/main/java/com/fs/sop/service/IQwSopTempDayService.java
  25. 6 0
      fs-service/src/main/java/com/fs/sop/service/IQwSopTempRulesService.java
  26. 5 3
      fs-service/src/main/java/com/fs/sop/service/IQwSopTempService.java
  27. 1 0
      fs-service/src/main/java/com/fs/sop/service/impl/QwSopLogsServiceImpl.java
  28. 1 0
      fs-service/src/main/java/com/fs/sop/service/impl/QwSopServiceImpl.java
  29. 15 0
      fs-service/src/main/java/com/fs/sop/service/impl/QwSopTempContentServiceImpl.java
  30. 9 0
      fs-service/src/main/java/com/fs/sop/service/impl/QwSopTempDayServiceImpl.java
  31. 26 19
      fs-service/src/main/java/com/fs/sop/service/impl/QwSopTempRulesServiceImpl.java
  32. 140 62
      fs-service/src/main/java/com/fs/sop/service/impl/QwSopTempServiceImpl.java
  33. 1 1
      fs-service/src/main/resources/application-config-druid-kyt.yml
  34. 1 1
      fs-service/src/main/resources/application-config-druid-nmgyt.yml
  35. 1 1
      fs-service/src/main/resources/application-config-druid-qdtst.yml
  36. 1 1
      fs-service/src/main/resources/application-druid-nmgyt.yml
  37. 0 8
      fs-service/src/main/resources/mapper/course/FsProjectAddressConfigMapper.xml
  38. 1 0
      fs-service/src/main/resources/mapper/course/FsUserCoursePeriodDaysMapper.xml
  39. 53 11
      fs-service/src/main/resources/mapper/live/LiveDataMapper.xml
  40. 42 1
      fs-service/src/main/resources/mapper/live/LiveWatchUserMapper.xml
  41. 0 26
      fs-user-app/src/main/java/com/fs/app/controller/CommonController.java

+ 3 - 8
fs-admin/src/main/java/com/fs/FSApplication.java

@@ -1,11 +1,8 @@
 package com.fs;
 
-import com.qiniu.common.Zone;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
-import org.springframework.core.io.Resource;
-import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
 import org.springframework.scheduling.annotation.EnableAsync;
 import org.springframework.scheduling.annotation.EnableScheduling;
 import org.springframework.transaction.annotation.Transactional;
@@ -13,14 +10,12 @@ import org.springframework.transaction.annotation.Transactional;
 /**
  * 启动程序
  */
-@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
+@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
 @Transactional
 @EnableAsync
 @EnableScheduling
-public class FSApplication
-{
-    public static void main(String[] args)
-    {
+public class FSApplication {
+    public static void main(String[] args) {
         // System.setProperty("spring.devtools.restart.enabled", "false");
         SpringApplication.run(FSApplication.class, args);
         System.out.println("admin启动成功");

+ 61 - 75
fs-admin/src/main/java/com/fs/course/controller/FsUserCourseController.java

@@ -1,39 +1,33 @@
 package com.fs.course.controller;
 
-import java.util.List;
-
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.json.JSONUtil;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.core.page.TableDataInfo;
+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.FsUserCourse;
 import com.fs.course.params.FsUserCourseConfigParam;
+import com.fs.course.service.IFsUserCourseService;
 import com.fs.course.service.IFsUserCourseVideoService;
 import com.fs.course.vo.FsUserCourseListPVO;
 import com.fs.framework.web.service.TokenService;
 import com.fs.his.utils.RedisCacheUtil;
 import com.fs.his.vo.OptionsVO;
 import com.fs.qw.param.FsUserCourseRedPageParam;
+import com.fs.sop.service.IQwSopTempService;
 import com.fs.system.service.ISysConfigService;
-import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.fs.common.annotation.Log;
-import com.fs.common.core.controller.BaseController;
-import com.fs.common.core.domain.AjaxResult;
-import com.fs.common.enums.BusinessType;
-import com.fs.course.domain.FsUserCourse;
-import com.fs.course.service.IFsUserCourseService;
-import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.common.core.page.TableDataInfo;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * 课程Controller
@@ -43,8 +37,7 @@ import com.fs.common.core.page.TableDataInfo;
  */
 @RestController
 @RequestMapping("/course/userCourse")
-public class FsUserCourseController extends BaseController
-{
+public class FsUserCourseController extends BaseController {
     @Autowired
     private IFsUserCourseService fsUserCourseService;
 
@@ -60,19 +53,21 @@ public class FsUserCourseController extends BaseController
     @Autowired
     private ISysConfigService configService;
 
+    @Autowired
+    private IQwSopTempService sopTempService;
+
     /**
      * 查询课程列表
      */
     @PreAuthorize("@ss.hasPermi('course:userCourse:list')")
     @GetMapping("/list")
-    public TableDataInfo list(FsUserCourse fsUserCourse)
-    {
+    public TableDataInfo list(FsUserCourse fsUserCourse) {
         startPage();
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         Long userId = loginUser.getUser().getUserId();
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
+        if (ObjectUtil.isNotEmpty(config.getIsBound()) && config.getIsBound()) {
             fsUserCourse.setUserId(userId);
         }
         List<FsUserCourseListPVO> list = fsUserCourseService.selectFsUserCourseListPVO(fsUserCourse);
@@ -84,14 +79,13 @@ public class FsUserCourseController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('course:userCourse:publicList')")
     @GetMapping("/publicList")
-    public TableDataInfo publicList(FsUserCourse fsUserCourse)
-    {
+    public TableDataInfo publicList(FsUserCourse fsUserCourse) {
         startPage();
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         Long userId = loginUser.getUser().getUserId();
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
+        if (ObjectUtil.isNotEmpty(config.getIsBound()) && config.getIsBound()) {
             fsUserCourse.setUserId(userId);
         }
         List<FsUserCourseListPVO> list = fsUserCourseService.selectFsUserCourseListPVO(fsUserCourse);
@@ -104,13 +98,12 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:export')")
     @Log(title = "课程", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
-    public AjaxResult export(FsUserCourse fsUserCourse)
-    {
+    public AjaxResult export(FsUserCourse fsUserCourse) {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         Long userId = loginUser.getUser().getUserId();
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
+        if (ObjectUtil.isNotEmpty(config.getIsBound()) && config.getIsBound()) {
             fsUserCourse.setUserId(userId);
         }
         List<FsUserCourse> list = fsUserCourseService.selectFsUserCourseList(fsUserCourse);
@@ -124,13 +117,12 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:publicExport')")
     @Log(title = "课程", businessType = BusinessType.EXPORT)
     @GetMapping("/publicExport")
-    public AjaxResult publicExport(FsUserCourse fsUserCourse)
-    {
+    public AjaxResult publicExport(FsUserCourse fsUserCourse) {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         Long userId = loginUser.getUser().getUserId();
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
+        if (ObjectUtil.isNotEmpty(config.getIsBound()) && config.getIsBound()) {
             fsUserCourse.setUserId(userId);
         }
         List<FsUserCourse> list = fsUserCourseService.selectFsUserCourseList(fsUserCourse);
@@ -143,8 +135,7 @@ public class FsUserCourseController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('course:userCourse:query')")
     @GetMapping(value = "/{courseId}")
-    public AjaxResult getInfo(@PathVariable("courseId") Long courseId)
-    {
+    public AjaxResult getInfo(@PathVariable("courseId") Long courseId) {
         return AjaxResult.success(fsUserCourseService.selectFsUserCourseByCourseId(courseId));
     }
 
@@ -153,8 +144,7 @@ public class FsUserCourseController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('course:userCourse:publicQuery')")
     @GetMapping(value = "/public/{courseId}")
-    public AjaxResult publicGetInfo(@PathVariable("courseId") Long courseId)
-    {
+    public AjaxResult publicGetInfo(@PathVariable("courseId") Long courseId) {
         return AjaxResult.success(fsUserCourseService.selectFsUserCourseByCourseId(courseId));
     }
 
@@ -164,13 +154,12 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:add')")
     @Log(title = "课程", businessType = BusinessType.INSERT)
     @PostMapping
-    public AjaxResult add(@RequestBody FsUserCourse fsUserCourse)
-    {
+    public AjaxResult add(@RequestBody FsUserCourse fsUserCourse) {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         Long userId = loginUser.getUser().getUserId();
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
+        if (ObjectUtil.isNotEmpty(config.getIsBound()) && config.getIsBound()) {
             fsUserCourse.setUserId(userId);
         }
         fsUserCourseService.insertFsUserCourse(fsUserCourse);
@@ -185,13 +174,12 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:publicAdd')")
     @Log(title = "课程", businessType = BusinessType.INSERT)
     @PostMapping("/public")
-    public AjaxResult publicAdd(@RequestBody FsUserCourse fsUserCourse)
-    {
+    public AjaxResult publicAdd(@RequestBody FsUserCourse fsUserCourse) {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         Long userId = loginUser.getUser().getUserId();
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
+        if (ObjectUtil.isNotEmpty(config.getIsBound()) && config.getIsBound()) {
             fsUserCourse.setUserId(userId);
         }
         fsUserCourseService.insertFsUserCourse(fsUserCourse);
@@ -206,8 +194,7 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:edit')")
     @Log(title = "课程", businessType = BusinessType.UPDATE)
     @PutMapping
-    public AjaxResult edit(@RequestBody FsUserCourse fsUserCourse)
-    {
+    public AjaxResult edit(@RequestBody FsUserCourse fsUserCourse) {
         fsUserCourseService.updateFsUserCourse(fsUserCourse);
         redisCacheUtil.delRedisKey("getCourseList");
         return toAjax(1);
@@ -219,8 +206,7 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:editRedPage')")
     @Log(title = "修改课程红包", businessType = BusinessType.UPDATE)
     @PostMapping("/editRedPage")
-    public AjaxResult editRedPage(@RequestBody FsUserCourseRedPageParam redPageParam)
-    {
+    public AjaxResult editRedPage(@RequestBody FsUserCourseRedPageParam redPageParam) {
         courseVideoService.updateFsUserCourseRedPage(redPageParam);
         return toAjax(1);
     }
@@ -231,8 +217,7 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:publicEdit')")
     @Log(title = "课程", businessType = BusinessType.UPDATE)
     @PutMapping("/public")
-    public AjaxResult publicEdit(@RequestBody FsUserCourse fsUserCourse)
-    {
+    public AjaxResult publicEdit(@RequestBody FsUserCourse fsUserCourse) {
         fsUserCourseService.updateFsUserCourse(fsUserCourse);
         redisCacheUtil.delRedisKey("getCourseList");
         return toAjax(1);
@@ -244,8 +229,7 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:copy')")
     @Log(title = "课程", businessType = BusinessType.DELETE)
     @GetMapping("/copy/{courseId}")
-    public AjaxResult copy(@PathVariable Long courseId)
-    {
+    public AjaxResult copy(@PathVariable Long courseId) {
         int i = fsUserCourseService.copyFsUserCourse(courseId);
         return toAjax(i);
     }
@@ -255,8 +239,8 @@ public class FsUserCourseController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('course:userCourse:remove')")
     @Log(title = "课程", businessType = BusinessType.DELETE)
-	@DeleteMapping("/{courseIds}")
-    public AjaxResult remove(@PathVariable Long[] courseIds){
+    @DeleteMapping("/{courseIds}")
+    public AjaxResult remove(@PathVariable Long[] courseIds) {
         fsUserCourseService.deleteFsUserCourseByCourseIds(courseIds);
         redisCacheUtil.delRedisKey("getCourseList");
         return toAjax(1);
@@ -268,8 +252,7 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:publicRemove')")
     @Log(title = "课程", businessType = BusinessType.DELETE)
     @DeleteMapping("/public/{courseIds}")
-    public AjaxResult publicRemove(@PathVariable Long[] courseIds)
-    {
+    public AjaxResult publicRemove(@PathVariable Long[] courseIds) {
         fsUserCourseService.deleteFsUserCourseByCourseIds(courseIds);
         redisCacheUtil.delRedisKey("getCourseList");
         return toAjax(1);
@@ -277,8 +260,7 @@ public class FsUserCourseController extends BaseController
 
 
     @GetMapping("/getAllList")
-    public R getAllList()
-    {
+    public R getAllList() {
         List<OptionsVO> list = fsUserCourseService.selectFsUserCourseAllList();
         return R.ok().put("data", list);
     }
@@ -286,18 +268,16 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:updateIsShow')")
     @Log(title = "课程上架", businessType = BusinessType.UPDATE)
     @PostMapping("/updateIsShow")
-    public AjaxResult updateIsShow(@RequestBody FsUserCourse fsUserCourse)
-    {
+    public AjaxResult updateIsShow(@RequestBody FsUserCourse fsUserCourse) {
         fsUserCourseService.updateFsUserCourse(fsUserCourse);
         redisCacheUtil.delRedisKey("getCourseList");
-       return toAjax(1);
+        return toAjax(1);
     }
 
     @PreAuthorize("@ss.hasPermi('course:userCourse:publicUpdateIsShow')")
     @Log(title = "课程上架", businessType = BusinessType.UPDATE)
     @PostMapping("/publicUpdateIsShow")
-    public AjaxResult publicUpdateIsShow(@RequestBody FsUserCourse fsUserCourse)
-    {
+    public AjaxResult publicUpdateIsShow(@RequestBody FsUserCourse fsUserCourse) {
         fsUserCourseService.updateFsUserCourse(fsUserCourse);
         redisCacheUtil.delRedisKey("getCourseList");
         return toAjax(1);
@@ -306,9 +286,8 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:putOn')")
     @Log(title = "课程批量上架", businessType = BusinessType.UPDATE)
     @PostMapping("/putOn/{courseIds}")
-    public AjaxResult putOn(@PathVariable Long[] courseIds)
-    {
-        fsUserCourseService.updateFsUserCourseIsShow(courseIds,1);
+    public AjaxResult putOn(@PathVariable Long[] courseIds) {
+        fsUserCourseService.updateFsUserCourseIsShow(courseIds, 1);
         redisCacheUtil.delRedisKey("getCourseList");
         return toAjax(1);
     }
@@ -316,9 +295,8 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:publicPutOn')")
     @Log(title = "课程批量上架", businessType = BusinessType.UPDATE)
     @PostMapping("/publicPutOn/{courseIds}")
-    public AjaxResult publicPutOn(@PathVariable Long[] courseIds)
-    {
-        fsUserCourseService.updateFsUserCourseIsShow(courseIds,1);
+    public AjaxResult publicPutOn(@PathVariable Long[] courseIds) {
+        fsUserCourseService.updateFsUserCourseIsShow(courseIds, 1);
         redisCacheUtil.delRedisKey("getCourseList");
         return toAjax(1);
     }
@@ -326,9 +304,8 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:putOn')")
     @Log(title = "课程批量下架", businessType = BusinessType.UPDATE)
     @PostMapping("/pullOff/{courseIds}")
-    public AjaxResult pullOff(@PathVariable Long[] courseIds)
-    {
-        fsUserCourseService.updateFsUserCourseIsShow(courseIds,0);
+    public AjaxResult pullOff(@PathVariable Long[] courseIds) {
+        fsUserCourseService.updateFsUserCourseIsShow(courseIds, 0);
         redisCacheUtil.delRedisKey("getCourseList");
         return toAjax(1);
     }
@@ -336,9 +313,8 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:publicPutOff')")
     @Log(title = "课程批量下架", businessType = BusinessType.UPDATE)
     @PostMapping("/publicPutOff/{courseIds}")
-    public AjaxResult publicPutOff(@PathVariable Long[] courseIds)
-    {
-        fsUserCourseService.updateFsUserCourseIsShow(courseIds,0);
+    public AjaxResult publicPutOff(@PathVariable Long[] courseIds) {
+        fsUserCourseService.updateFsUserCourseIsShow(courseIds, 0);
         redisCacheUtil.delRedisKey("getCourseList");
         return toAjax(1);
     }
@@ -349,7 +325,7 @@ public class FsUserCourseController extends BaseController
     @PreAuthorize("@ss.hasPermi('course:userCourse:editConfig')")
     @Log(title = "课程配置", businessType = BusinessType.UPDATE)
     @PostMapping("/editConfig")
-    public R editConfig(@RequestBody FsUserCourseConfigParam params){
+    public R editConfig(@RequestBody FsUserCourseConfigParam params) {
         fsUserCourseService.editConfig(params.getId(), params.getConfigJson());
         redisCacheUtil.delRedisKey("getCourseList");
         redisCacheUtil.delRedisKey("h5user:course:video:list:all");
@@ -357,4 +333,14 @@ public class FsUserCourseController extends BaseController
         redisCacheUtil.delRedisKey("cache:video");
         return R.ok();
     }
+
+    /**
+     * 同步课程模板
+     */
+    @Log(title = "同步课程模板", businessType = BusinessType.UPDATE)
+    @PostMapping("/syncTemplate/{courseId}")
+    public AjaxResult syncTemplate(@PathVariable Long courseId) {
+        sopTempService.syncTemplate(courseId);
+        return toAjax(1);
+    }
 }

+ 2 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwSopTempController.java

@@ -1,5 +1,6 @@
 package com.fs.qw.controller;
 
+import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
@@ -9,6 +10,7 @@ import com.fs.common.core.domain.model.LoginUser;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.TimeUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.framework.web.service.TokenService;
 import com.fs.qw.vo.SortDayVo;

+ 5 - 23
fs-company/src/main/java/com/fs/company/controller/course/FsUserCoursePeriodController.java

@@ -10,7 +10,6 @@ import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.exception.CustomException;
 import com.fs.common.utils.ServletUtils;
-import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.course.domain.FsUserCoursePeriod;
 import com.fs.course.domain.FsUserCoursePeriodDays;
@@ -38,7 +37,10 @@ import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
 import java.time.LocalDate;
-import java.util.*;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 
 /**
@@ -102,20 +104,6 @@ public class FsUserCoursePeriodController extends BaseController {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         fsUserCoursePeriod.setCompanyIdList(Collections.singletonList(loginUser.getCompany().getCompanyId()));
         List<FsUserCoursePeriodVO> list = fsUserCoursePeriodService.selectFsUserCoursePeriodPage(fsUserCoursePeriod);
-        // 使用Stream API的简洁写法
-        Long currentCompanyId = loginUser.getCompany().getCompanyId();
-        for (FsUserCoursePeriodVO vo : list) {
-            String isNeedRegisterMember = vo.getIsNeedRegisterMember();
-
-            if (StringUtils.isNotEmpty(isNeedRegisterMember)) {
-                boolean containsCurrentCompany = Arrays.stream(isNeedRegisterMember.split(","))
-                        .map(String::trim)
-                        .anyMatch(id -> id.equals(String.valueOf(currentCompanyId)));
-                vo.setIsNeedRegisterMember(containsCurrentCompany ? "1" : "0");
-            } else {
-                vo.setIsNeedRegisterMember("0");
-            }
-        }
         PageInfo<FsUserCoursePeriodVO> pageInfo = new PageInfo<>(list);
         Map<String, Object> result = new HashMap<>();
         result.put("rows", pageInfo.getList());
@@ -185,13 +173,7 @@ public class FsUserCoursePeriodController extends BaseController {
     @PutMapping("/editIsNeedRegisterMember")
     public AjaxResult editIsNeedRegisterMember(@RequestBody FsUserCoursePeriod fsUserCoursePeriod)
     {
-        FsUserCoursePeriod fsUserCoursePeriod1 = fsUserCoursePeriodService.selectFsUserCoursePeriodById(fsUserCoursePeriod.getPeriodId());
-        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-        if (ObjectUtil.isEmpty(fsUserCoursePeriod.getIsNeedRegisterMember())){
-            throw new CustomException("修改失败!");
-        }
-
-        return toAjax(fsUserCoursePeriodService.editIsNeedRegisterMember(fsUserCoursePeriod,loginUser.getCompany().getCompanyId().toString()));
+        return toAjax(fsUserCoursePeriodService.editIsNeedRegisterMember(fsUserCoursePeriod));
     }
 
     /**

+ 1 - 0
fs-company/src/main/java/com/fs/company/controller/qw/QwSopTempController.java

@@ -1,5 +1,6 @@
 package com.fs.company.controller.qw;
 
+import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;

+ 5 - 3
fs-live-app/src/main/java/com/fs/live/websocket/service/WebSocketServer.java

@@ -7,6 +7,8 @@ import com.fs.common.constant.LiveKeysConstant;
 import com.fs.common.exception.base.BaseException;
 import com.fs.his.domain.FsUser;
 import com.fs.his.service.IFsUserService;
+import com.fs.hisStore.domain.FsUserScrm;
+import com.fs.hisStore.service.IFsUserScrmService;
 import com.fs.live.config.ProductionWordFilter;
 import com.fs.live.mapper.LiveCouponMapper;
 import com.fs.live.websocket.auth.WebSocketConfigurator;
@@ -51,7 +53,7 @@ public class WebSocketServer {
     private final ILiveMsgService liveMsgService = SpringUtils.getBean(ILiveMsgService.class);
     private final ILiveService liveService = SpringUtils.getBean(ILiveService.class);
     private final ILiveWatchUserService liveWatchUserService = SpringUtils.getBean(ILiveWatchUserService.class);
-    private final IFsUserService fsUserService = SpringUtils.getBean(IFsUserService.class);
+    private final IFsUserScrmService fsUserService = SpringUtils.getBean(IFsUserScrmService.class);
     private final ILiveDataService liveDataService = SpringUtils.getBean(ILiveDataService.class);
     private final ProductionWordFilter productionWordFilter = SpringUtils.getBean(ProductionWordFilter.class);
     private final ILiveRedConfService liveRedConfService =  SpringUtils.getBean(ILiveRedConfService.class);
@@ -94,7 +96,7 @@ public class WebSocketServer {
 
         // 记录连接信息 管理员不记录
         if (userType == 0) {
-            FsUser fsUser = fsUserService.selectFsUserByUserId(userId);
+            FsUserScrm fsUser = fsUserService.selectFsUserByUserId(userId);
             if (Objects.isNull(fsUser)) {
                 throw new BaseException("用户信息错误");
             }
@@ -193,7 +195,7 @@ public class WebSocketServer {
         ConcurrentHashMap<Long, Session> room = getRoom(liveId);
         List<Session> adminRoom = getAdminRoom(liveId);
         if (userType == 0) {
-            FsUser fsUser = fsUserService.selectFsUserByUserId(userId);
+            FsUserScrm fsUser = fsUserService.selectFsUserByUserId(userId);
             if (Objects.isNull(fsUser)) {
                 throw new BaseException("用户信息错误");
             }

+ 1 - 1
fs-service/src/main/java/com/fs/course/domain/FsCourseLink.java

@@ -53,7 +53,7 @@ public class FsCourseLink extends BaseEntity
     */
     private Long qwExternalId;
 
-    private Integer linkType; //链接类型 0:正常链接  1:应急链接  2:小程序链接
+    private Integer linkType; //链接类型 0:正常链接  1:应急链接  3:小程序链接 4:APP
 
     private Integer isRoom;//是否发群
     private String chatId;//是否发群

+ 0 - 49
fs-service/src/main/java/com/fs/course/domain/FsProjectAddressConfig.java

@@ -1,49 +0,0 @@
-package com.fs.course.domain;
-
-import lombok.Data;
-
-import java.time.LocalDateTime;
-
-@Data
-public class FsProjectAddressConfig {
-
-    /**
-     * 主键ID
-     */
-    private Long id;
-
-    /**
-     * 项目名称
-     */
-    private String name;
-
-    /**
-     * 唯一编码
-     */
-    private String code;
-
-    /**
-     * api接口地址
-     */
-    private String addressUrl;
-
-    /**
-     * 存储桶地址
-     */
-    private String bucketPath;
-
-    /**
-     * 创建时间
-     */
-    private LocalDateTime createTime;
-
-    /**
-     * 修改时间
-     */
-    private LocalDateTime updateTime;
-
-    /**
-     * 发送类型 1个微 2企微
-     */
-    private Integer sendType;
-}

+ 2 - 4
fs-service/src/main/java/com/fs/course/domain/FsUserCoursePeriod.java

@@ -117,8 +117,6 @@ public class FsUserCoursePeriod
      * 营期线,即营期首次播放课程的日期
      */
     private Date periodLine;
-    /**
-     * 是否单独注册会员的绑定公司,存在就是开启,不存在就是关闭
-     */
-    private String isNeedRegisterMember;
+    /** 是否需要单独注册会员,1-是,0-否(用于个微销售分享看课) */
+    private Integer isNeedRegisterMember;
 }

+ 0 - 14
fs-service/src/main/java/com/fs/course/mapper/FsProjectAddressConfigMapper.java

@@ -1,14 +0,0 @@
-package com.fs.course.mapper;
-
-import com.fs.course.domain.FsProjectAddressConfig;
-import org.apache.ibatis.annotations.Param;
-import org.apache.ibatis.annotations.Select;
-
-public interface FsProjectAddressConfigMapper {
-
-    /**
-     * 根据code查询url
-     */
-    @Select("select * from fs_project_address_config where code = #{code}")
-    FsProjectAddressConfig selectDomainByCode(@Param("code") String code);
-}

+ 0 - 12
fs-service/src/main/java/com/fs/course/service/IFsProjectAddressConfigService.java

@@ -1,12 +0,0 @@
-package com.fs.course.service;
-
-
-import com.fs.course.domain.FsProjectAddressConfig;
-
-public interface IFsProjectAddressConfigService {
-
-    /**
-     * 根据code查询url
-     */
-    FsProjectAddressConfig selectDomainByCode(String code);
-}

+ 1 - 1
fs-service/src/main/java/com/fs/course/service/IFsUserCoursePeriodService.java

@@ -102,7 +102,7 @@ public interface IFsUserCoursePeriodService
 
     List<Long> selectFsUserCoursePeriodListByPeriodId(List<Long> periodIds,Long companyId);
 
-    int editIsNeedRegisterMember(FsUserCoursePeriod fsUserCoursePeriod, String s);
+    int editIsNeedRegisterMember(FsUserCoursePeriod fsUserCoursePeriod);
 
     List<SysDictData> selectFsUserCoursePeriodListLabel(FsUserCoursePeriod fsUserCoursePeriod);
 }

+ 6 - 9
fs-service/src/main/java/com/fs/course/service/IFsUserCourseService.java

@@ -1,10 +1,5 @@
 package com.fs.course.service;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.List;
-import java.util.Map;
-
 import com.fs.common.core.domain.R;
 import com.fs.course.domain.FsUserCourse;
 import com.fs.course.param.*;
@@ -13,8 +8,11 @@ import com.fs.course.vo.*;
 import com.fs.course.vo.newfs.FsUserCourseListVO;
 import com.fs.his.vo.OptionsVO;
 
-import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.NotNull;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
 
 /**
  * 课程Service接口
@@ -22,8 +20,7 @@ import javax.validation.constraints.NotNull;
  * @author fs
  * @date 2024-05-15
  */
-public interface IFsUserCourseService
-{
+public interface IFsUserCourseService {
     /**
      * 查询课程
      *
@@ -110,7 +107,7 @@ public interface IFsUserCourseService
 
     List<FsUserCourseListVO> getFsUserCourseList(FsUserCourseListParam param);
 
-    void  processQwSopCourseMaterialTimer();
+    void processQwSopCourseMaterialTimer();
 
     List<FsCourseListBySidebarVO> getFsCourseListBySidebar(FsCourseListBySidebarParam param);
 

+ 0 - 23
fs-service/src/main/java/com/fs/course/service/impl/FsProjectAddressConfigServiceImpl.java

@@ -1,23 +0,0 @@
-package com.fs.course.service.impl;
-
-import com.fs.course.domain.FsProjectAddressConfig;
-import com.fs.course.mapper.FsProjectAddressConfigMapper;
-import com.fs.course.service.IFsProjectAddressConfigService;
-import org.springframework.stereotype.Service;
-
-import javax.annotation.Resource;
-
-@Service
-public class FsProjectAddressConfigServiceImpl implements IFsProjectAddressConfigService {
-
-    @Resource
-    private FsProjectAddressConfigMapper fsProjectAddressConfigMapper;
-
-    /**
-     * 根据code查询url
-     */
-    @Override
-    public FsProjectAddressConfig selectDomainByCode(String code) {
-        return fsProjectAddressConfigMapper.selectDomainByCode(code);
-    }
-}

+ 1 - 24
fs-service/src/main/java/com/fs/course/service/impl/FsUserCoursePeriodServiceImpl.java

@@ -313,30 +313,7 @@ public class FsUserCoursePeriodServiceImpl implements IFsUserCoursePeriodService
     }
 
     @Override
-    public int editIsNeedRegisterMember(FsUserCoursePeriod fsUserCoursePeriod, String companyId) {
-        String currentValue = fsUserCoursePeriod.getIsNeedRegisterMember();
-
-        if (currentValue.equals("0")) {
-            // 移除指定的 companyId
-            String updatedValue = Arrays.stream(currentValue.split(","))
-                    .map(String::trim)
-                    .filter(id -> !id.equals(companyId))
-                    .collect(Collectors.joining(","));
-            fsUserCoursePeriod.setIsNeedRegisterMember(updatedValue);
-        } else {
-            // 添加 companyId,并过滤掉 "0"
-            String updatedValue = Arrays.stream(currentValue.split(","))
-                    .map(String::trim)
-                    .filter(id -> !id.equals("0")) // 清除 "0"
-                    .collect(Collectors.collectingAndThen(
-                            Collectors.toCollection(LinkedHashSet::new),
-                            set -> {
-                                set.add(companyId);
-                                return String.join(",", set);
-                            }
-                    ));
-            fsUserCoursePeriod.setIsNeedRegisterMember(updatedValue);
-        }
+    public int editIsNeedRegisterMember(FsUserCoursePeriod fsUserCoursePeriod) {
         return fsUserCoursePeriodMapper.updateFsUserCoursePeriod(fsUserCoursePeriod);
     }
 

+ 18 - 45
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -604,49 +604,26 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         if(qwGroupChatUsers == null || qwGroupChatUsers.isEmpty()){
             return R.error("群参数异常");
         }
-        //群聊寻找用户新逻辑
-        QwExternalContact qwExternalContact = null;
-        if( null != param.getUserId() && null == qwExternalContact){
-            try {
-                qwExternalContact =  qwExternalContactMapper.selectOne(new QueryWrapper<QwExternalContact>()
+        QwExternalContact qwExternalContact =
+                qwExternalContactMapper.selectOne(new QueryWrapper<QwExternalContact>()
                         .eq("user_id", qwGroupChat.getOwner())
                         .eq("fs_user_id", param.getUserId())
                         .eq("corp_id", param.getCorpId())
                         .eq("status",0));
-            } catch (Exception e){
-                log.error("群聊用户id匹配异常,参数user_id:{},fs_user_id:{},corp_id:{}",qwGroupChat.getOwner(),param.getUserId(),param.getCorpId(),e);
-            }
-        }
-        //找当前群中的用户匹配
-        if(StringUtils.isNotBlank(param.getChatId()) && null == qwExternalContact){
-            List<QwExternalContact> groupChatUserByChatIdAndUserName = qwExternalContactMapper.getGroupChatUserByChatIdAndUserName(qwGroupChat.getOwner(), user.getNickName(), param.getCorpId(), param.getChatId());
-            //没找到用户 || 找到的用户数量大于1 使用userid查询匹配
-            if(null == groupChatUserByChatIdAndUserName || groupChatUserByChatIdAndUserName.isEmpty() || groupChatUserByChatIdAndUserName.size() > 1){
-                log.error("群聊用户昵称匹配异常,参数user_id:{},name:{},corp_id:{},chatId:{}",qwGroupChat.getOwner(),user.getNickName(),param.getCorpId(),param.getChatId());
-            } else {
-                qwExternalContact =  groupChatUserByChatIdAndUserName.get(0);
+        if(null == qwExternalContact){
+            try{
+                //修改成通过昵称匹配
+                qwExternalContact =
+                        qwExternalContactMapper.selectOne(new QueryWrapper<QwExternalContact>()
+                                .eq("user_id", qwGroupChat.getOwner())
+                                .eq("name", user.getNickName())
+                                .eq("corp_id", param.getCorpId())
+                                .eq("status",0));
+            } catch(Exception e){
+                log.error("群聊用户昵称匹配异常,参数user_id:{},name:{},corp_id:{}",qwGroupChat.getOwner(),user.getNickName(),param.getCorpId(),e);
             }
+
         }
-//        QwExternalContact qwExternalContact =  qwExternalContactMapper.selectOne(new QueryWrapper<QwExternalContact>()
-//                            .eq("user_id", qwGroupChat.getOwner())
-//                            .eq("fs_user_id", param.getUserId())
-//                            .eq("corp_id", param.getCorpId())
-//                            .eq("status",0));
-//
-//        if(null == qwExternalContact){
-//            try{
-//                //修改成通过昵称匹配
-//                qwExternalContact =
-//                        qwExternalContactMapper.selectOne(new QueryWrapper<QwExternalContact>()
-//                                .eq("user_id", qwGroupChat.getOwner())
-//                                .eq("name", user.getNickName())
-//                                .eq("corp_id", param.getCorpId())
-//                                .eq("status",0));
-//            } catch(Exception e){
-//                log.error("群聊用户昵称匹配异常,参数user_id:{},name:{},corp_id:{}",qwGroupChat.getOwner(),user.getNickName(),param.getCorpId(),e);
-//            }
-//
-//        }
         if(qwExternalContact==null){
             return addCustomerService(param.getQwUserId(),msg);
         }
@@ -2193,15 +2170,11 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
                 if((companyUser.getIsAllowedAllRegister() !=null && companyUser.getIsAllowedAllRegister() != 1)){
                     return ResponseResult.fail(504,"当前销售禁止绑定会员,请联系销售!");
                 }
-                // 使用 Stream API 检查是否包含 companyId
-                // 修正类型转换问题
                 if (companyUser.getIsNeedRegisterMember() == null || companyUser.getIsNeedRegisterMember() == 1
-                        || (ObjectUtils.isNotEmpty(fsUserCoursePeriod)
-                        && ObjectUtils.isNotEmpty(fsUserCoursePeriod.getIsNeedRegisterMember())
-                        && Arrays.stream(fsUserCoursePeriod.getIsNeedRegisterMember().split(","))
-                        .map(String::trim)
-                        .anyMatch(id -> id.equals(String.valueOf(company.getCompanyId()))))) {
-                    return ResponseResult.fail(504, "请联系销售发送邀请链接成为会员!");
+                        ||(ObjectUtils.isNotEmpty(fsUserCoursePeriod)
+                        &&ObjectUtils.isNotEmpty(fsUserCoursePeriod.getIsNeedRegisterMember())
+                        &&fsUserCoursePeriod.getIsNeedRegisterMember().equals(1))){
+                    return ResponseResult.fail(504,"请联系销售发送邀请链接成为会员!");
                 }
                 int defaultStatus = (company != null ? company.getFsUserIsDefaultBlack() : 0) == 1 ? 0 : 1;
                 userCompanyUser = userCompanyUserService.bindRelationship(param.getUserId(), courseProject, companyUser.getCompanyId(), companyUser.getUserId(), defaultStatus);

+ 1 - 1
fs-service/src/main/java/com/fs/course/vo/FsUserCoursePeriodVO.java

@@ -89,5 +89,5 @@ public class FsUserCoursePeriodVO implements Serializable {
     @Excel(name = "营期线", width = 31, dateFormat = "yyyy-MM-dd")
     private Date periodLine;
     /** 是否需要单独注册会员,1-是,0-否(用于个微销售分享看课) */
-    private String isNeedRegisterMember;
+    private Integer isNeedRegisterMember;
 }

+ 2 - 1
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStorePaymentScrmServiceImpl.java

@@ -788,7 +788,7 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
             }
         }
         return R.ok();
-        }
+    }
 
 
     @Override
@@ -890,6 +890,7 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
         storePayment.setOpenId(user.getMaOpenId());
         storePayment.setUserId(user.getUserId());
         storePayment.setPayMode("hf");//目前微信收款仅支持汇付
+        storePayment.setAppId(param.getAppId());
         fsStorePaymentMapper.insertFsStorePayment(storePayment);
 
         //汇付支付

+ 11 - 0
fs-service/src/main/java/com/fs/live/mapper/LiveWatchUserMapper.java

@@ -107,6 +107,17 @@ public interface LiveWatchUserMapper {
     @Select("select * from live_watch_user where live_id = #{liveId} and user_id = #{userId}")
     LiveWatchUser selectUserByLiveIdAndUserId(@Param("liveId") long liveId,@Param("userId")  long userId);
 
+    /**
+     * 根据唯一索引查询:live_id, user_id, live_flag, replay_flag
+     */
+    LiveWatchUser selectByUniqueIndex(@Param("liveId") Long liveId, @Param("userId") Long userId, 
+                                      @Param("liveFlag") Integer liveFlag, @Param("replayFlag") Integer replayFlag);
+
+    /**
+     * 根据唯一索引更新或插入(ON DUPLICATE KEY UPDATE)
+     */
+    int insertOrUpdateByUniqueIndex(LiveWatchUser liveWatchUser);
+
     @Select("SELECT " +
             "    SUM(CASE WHEN lwu.online = 0 and lwu.msg_status = 0 THEN 1 ELSE 0 END) AS online, " +
             "    SUM(CASE WHEN lwu.online = 1 and lwu.msg_status = 0 THEN 1 ELSE 0 END) AS offline, " +

+ 50 - 33
fs-service/src/main/java/com/fs/live/service/impl/LiveWatchUserServiceImpl.java

@@ -12,6 +12,8 @@ import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.his.domain.FsUser;
 import com.fs.his.service.IFsUserService;
+import com.fs.hisStore.domain.FsUserScrm;
+import com.fs.hisStore.service.IFsUserScrmService;
 import com.fs.live.domain.Live;
 import com.fs.live.domain.LiveVideo;
 import com.fs.live.domain.LiveWatchUser;
@@ -43,7 +45,7 @@ public class LiveWatchUserServiceImpl implements ILiveWatchUserService {
     @Autowired
     private RedisCache redisCache;
     @Autowired
-    private IFsUserService fsUserService;
+    private IFsUserScrmService fsUserService;
     @Autowired
     private LiveWatchUserMapper baseMapper;
     @Autowired
@@ -153,38 +155,60 @@ public class LiveWatchUserServiceImpl implements ILiveWatchUserService {
 
     @Override
     public LiveWatchUser join(long liveId, long userId, String location) {
-        LiveWatchUser liveWatchUser = getByLiveIdAndUserId(liveId, userId);
-        FsUser fsUserVO = fsUserService.selectFsUserByUserId(userId);
+        FsUserScrm fsUserVO = fsUserService.selectFsUserByUserId(userId);
         Date now = DateUtils.getNowDate();
 
         // 查询直播间信息
         Live live = liveMapper.selectLiveByLiveId(liveId);
+        if (live == null) {
+            throw new RuntimeException("直播间不存在");
+        }
 
-        // 判断用户进入时间:如果进入时间大于直播结束时间,说明是回放
-        boolean isReplay = false;
-        if (live != null && live.getFinishTime() != null) {
-            Date finishTime = java.sql.Timestamp.valueOf(live.getFinishTime());
-            isReplay = now.after(finishTime);
+        // 查询直播间录播视频时长(video_type IN (1, 2))
+        List<LiveVideo> videos = liveVideoMapper.selectByLiveIdAndType(liveId,1);
+        long totalDuration = 0L;
+        if (videos != null && !videos.isEmpty()) {
+            totalDuration = videos.stream()
+                    .filter(v -> v.getVideoType() != null && (v.getVideoType() == 1 || v.getVideoType() == 2))
+                    .filter(v -> v.getDuration() != null)
+                    .mapToLong(LiveVideo::getDuration)
+                    .sum();
         }
 
-        if(liveWatchUser != null) {
-            liveWatchUser.setUpdateTime(now);
-            liveWatchUser.setOnline(0);
+        // 判断是直播还是回放:开播时间 + 视频时长
+        Integer liveFlag = 0;
+        Integer replayFlag = 0;
 
-            // 更新location
-            if (StringUtils.isNotEmpty(location)) {
-                liveWatchUser.setLocation(location);
-            }
+        if (live.getStartTime() != null) {
+            // 将 LocalDateTime 转换为 Date
+            Date startTime = java.sql.Timestamp.valueOf(live.getStartTime());
+            // 计算结束时间:开播时间 + 视频时长(秒)
+            Date endTime = new Date(startTime.getTime() + totalDuration * 1000);
 
-            // 更新进入标记
-            if (isReplay) {
-                liveWatchUser.setReplayFlag(1);
+            if (now.before(endTime)) {
+                // 当前时间 < 开播时间 + 视频时长,说明是直播
+                liveFlag = 1;
+                replayFlag = 0;
             } else {
-                liveWatchUser.setLiveFlag(1);
+                // 当前时间 >= 开播时间 + 视频时长,说明是回放
+                liveFlag = 0;
+                replayFlag = 1;
             }
+        }
+
+        // 使用唯一索引查询:live_id, user_id, live_flag, replay_flag
+        LiveWatchUser liveWatchUser = baseMapper.selectByUniqueIndex(liveId, userId, liveFlag, replayFlag);
 
+        if (liveWatchUser != null) {
+            // 存在则更新
+            liveWatchUser.setUpdateTime(now);
+            liveWatchUser.setOnline(0);
+            if (StringUtils.isNotEmpty(location)) {
+                liveWatchUser.setLocation(location);
+            }
             baseMapper.updateLiveWatchUser(liveWatchUser);
-        }else{
+        } else {
+            // 不存在则插入
             liveWatchUser = new LiveWatchUser();
             liveWatchUser.setLiveId(liveId);
             liveWatchUser.setUserId(userId);
@@ -192,23 +216,16 @@ public class LiveWatchUserServiceImpl implements ILiveWatchUserService {
             liveWatchUser.setMsgStatus(0);
             liveWatchUser.setOnline(0);
             liveWatchUser.setLocation(location);
-
-            // 设置进入标记
-            if (isReplay) {
-                liveWatchUser.setReplayFlag(1);
-                liveWatchUser.setLiveFlag(0);
-            } else {
-                liveWatchUser.setLiveFlag(1);
-                liveWatchUser.setReplayFlag(0);
-            }
-
+            liveWatchUser.setLiveFlag(liveFlag);
+            liveWatchUser.setReplayFlag(replayFlag);
             liveWatchUser.setCreateTime(now);
             liveWatchUser.setUpdateTime(now);
             baseMapper.insertLiveWatchUser(liveWatchUser);
         }
+
         liveWatchUser.setAvatar(fsUserVO.getAvatar());
         liveWatchUser.setNickName(fsUserVO.getNickname());
-        String hashKey  = String.format(LiveKeysConstant.LIVE_WATCH_USERS, liveId);
+        String hashKey = String.format(LiveKeysConstant.LIVE_WATCH_USERS, liveId);
         redisCache.hashPut(hashKey, String.valueOf(userId), JSON.toJSONString(liveWatchUser));
         return liveWatchUser;
     }
@@ -216,7 +233,7 @@ public class LiveWatchUserServiceImpl implements ILiveWatchUserService {
     @Override
     public LiveWatchUser joinWithoutLocation(long liveId, long userId) {
         LiveWatchUser liveWatchUser = getByLiveIdAndUserId(liveId, userId);
-        FsUser fsUserVO = fsUserService.selectFsUserByUserId(userId);
+        FsUserScrm fsUserVO = fsUserService.selectFsUserByUserId(userId);
         Date now = DateUtils.getNowDate();
 
         // 查询直播间信息
@@ -337,7 +354,7 @@ public class LiveWatchUserServiceImpl implements ILiveWatchUserService {
 
     @Override
     public int blockUser(Long userId) {
-        FsUser fsUser = new FsUser();
+        FsUserScrm fsUser = new FsUserScrm();
         fsUser.setUserId(userId);
         fsUser.setStatus(0);
         return fsUserService.updateFsUser(fsUser);

+ 2 - 1
fs-service/src/main/java/com/fs/sop/mapper/QwSopTempMapper.java

@@ -6,6 +6,7 @@ import com.fs.common.enums.DataSourceType;
 import com.fs.sop.domain.QwSopTemp;
 import org.apache.ibatis.annotations.Param;
 
+import java.util.Collection;
 import java.util.List;
 
 /**
@@ -70,5 +71,5 @@ public interface QwSopTempMapper extends BaseMapper<QwSopTemp> {
 
     List<QwSopTemp> listTemp();
 
-    List<QwSopTemp> selectListByIds(@Param("ids") List<String> ids);
+    List<QwSopTemp> selectListByIds(@Param("ids") Collection<String> ids);
 }

+ 6 - 1
fs-service/src/main/java/com/fs/sop/mapper/QwSopTempRulesMapper.java

@@ -6,6 +6,7 @@ import com.fs.common.enums.DataSourceType;
 import com.fs.sop.domain.QwSopTempRules;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
+import org.springframework.stereotype.Repository;
 
 import java.util.List;
 
@@ -16,7 +17,8 @@ import java.util.List;
  * @date 2025-02-06
  */
 @DataSource(DataSourceType.SOP)
-public interface QwSopTempRulesMapper extends BaseMapper<QwSopTempRules>{
+@Repository
+public interface QwSopTempRulesMapper extends BaseMapper<QwSopTempRules> {
     /**
      * 查询sop任务模板规则
      *
@@ -78,4 +80,7 @@ public interface QwSopTempRulesMapper extends BaseMapper<QwSopTempRules>{
     List<QwSopTempRules> listByTempIdAndNameAndDayNum(@Param("id") String id, @Param("dayNum") Integer dayNum);
 
     void deleteByIdList(@Param("ids") List<String> ids);
+
+    @Select("select * from qw_sop_temp_rules where course_id = #{courseId} ")
+    List<QwSopTempRules> selectQwSopTempRulesListByCourseId(@Param("courseId")Long courseId);
 }

+ 6 - 0
fs-service/src/main/java/com/fs/sop/service/IQwSopTempContentService.java

@@ -5,7 +5,9 @@ import com.fs.common.annotation.DataSource;
 import com.fs.common.enums.DataSourceType;
 import com.fs.sop.domain.QwSopTempContent;
 
+import java.util.Collection;
 import java.util.List;
+import java.util.Set;
 
 /**
  * sop任务模板内容Service接口
@@ -84,4 +86,8 @@ public interface IQwSopTempContentService extends IService<QwSopTempContent>{
     void updateDay(QwSopTempContent content);
 
     List<QwSopTempContent> selectQwSopTempContentByTempId(String tempId);
+
+    void removeByTempIds(Collection<String> tempIds);
+
+    List<QwSopTempContent> listByTempIds(Collection<String> tempIds);
 }

+ 5 - 1
fs-service/src/main/java/com/fs/sop/service/IQwSopTempDayService.java

@@ -3,6 +3,7 @@ package com.fs.sop.service;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.fs.sop.domain.QwSopTempDay;
 
+import java.util.Collection;
 import java.util.List;
 
 /**
@@ -11,7 +12,7 @@ import java.util.List;
  * @author fs
  * @date 2025-02-06
  */
-public interface IQwSopTempDayService extends IService<QwSopTempDay>{
+public interface IQwSopTempDayService extends IService<QwSopTempDay> {
 
     void saveList(List<QwSopTempDay> list);
 
@@ -26,9 +27,12 @@ public interface IQwSopTempDayService extends IService<QwSopTempDay>{
     boolean saveOrUpdate(QwSopTempDay day);
 
     void addOrUpdateBatch(List<QwSopTempDay> days);
+
     void removeById(Long id);
 
     List<QwSopTempDay> listById(List<Long> dayIds);
 
     int getDayNumByIdLimitOne(String tempId);
+
+    void removeByTempIds(Collection<String> tempIds);
 }

+ 6 - 0
fs-service/src/main/java/com/fs/sop/service/IQwSopTempRulesService.java

@@ -6,7 +6,9 @@ import com.fs.common.enums.DataSourceType;
 import com.fs.sop.domain.QwSopTempDay;
 import com.fs.sop.domain.QwSopTempRules;
 
+import java.util.Collection;
 import java.util.List;
+import java.util.Set;
 
 /**
  * sop任务模板规则Service接口
@@ -88,4 +90,8 @@ public interface IQwSopTempRulesService extends IService<QwSopTempRules>{
     List<QwSopTempRules> listById(List<Long> rulesIds);
 
     void updateSiFenTemp();
+
+    List<QwSopTempRules> listByCourseId(Long courseId);
+
+    void removeByTempIds(Collection<String> tempIds);
 }

+ 5 - 3
fs-service/src/main/java/com/fs/sop/service/IQwSopTempService.java

@@ -6,6 +6,7 @@ import com.fs.sop.domain.QwSopTempDay;
 import com.fs.sop.params.QwSopShareTempParam;
 import com.fs.sop.vo.QwSopTempRedPackageVo;
 
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 
@@ -15,8 +16,7 @@ import java.util.Map;
  * @author fs
  * @date 2024-09-26
  */
-public interface IQwSopTempService
-{
+public interface IQwSopTempService {
     /**
      * 查询sop模板
      *
@@ -58,7 +58,7 @@ public interface IQwSopTempService
     public int deleteQwSopTempByIds(String[] ids);
 
     /**
-     *分享sop模板
+     * 分享sop模板
      */
     public int shareQwSopTemp(QwSopShareTempParam param);
 
@@ -99,4 +99,6 @@ public interface IQwSopTempService
     void updateRedPackage(List<QwSopTempRedPackageVo> list);
 
     List<String> getSelectableRange();
+
+    void syncTemplate(Long courseId);
 }

+ 1 - 0
fs-service/src/main/java/com/fs/sop/service/impl/QwSopLogsServiceImpl.java

@@ -95,6 +95,7 @@ public class QwSopLogsServiceImpl extends ServiceImpl<QwSopLogsMapper, QwSopLogs
     private QwExternalContactServiceImpl qwExternalContactService;
 
     @Autowired
+    @Lazy
     private IFsCourseWatchLogService watchLogService;
 
     @Autowired

+ 1 - 0
fs-service/src/main/java/com/fs/sop/service/impl/QwSopServiceImpl.java

@@ -137,6 +137,7 @@ public class QwSopServiceImpl implements IQwSopService
     private IFsUserService fsUserService;
 
     @Autowired
+    @Lazy
     private IFsCourseWatchLogService fsCourseWatchLogService;
 
     @Autowired

+ 15 - 0
fs-service/src/main/java/com/fs/sop/service/impl/QwSopTempContentServiceImpl.java

@@ -5,10 +5,13 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fs.common.annotation.DataSource;
 import com.fs.common.enums.DataSourceType;
 import com.fs.sop.domain.QwSopTempContent;
+import com.fs.sop.domain.QwSopTempDay;
 import com.fs.sop.mapper.QwSopTempContentMapper;
 import com.fs.sop.service.IQwSopTempContentService;
 import org.springframework.stereotype.Service;
 
+import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -148,4 +151,16 @@ public class QwSopTempContentServiceImpl extends ServiceImpl<QwSopTempContentMap
     public List<QwSopTempContent> selectQwSopTempContentByTempId(String tempId) {
         return baseMapper.selectQwSopTempContentByTempId(tempId);
     }
+
+    @Override
+    @DataSource(DataSourceType.SOP)
+    public void removeByTempIds(Collection<String> tempIds) {
+        this.remove(new QueryWrapper<QwSopTempContent>().in("temp_id", tempIds));
+    }
+
+    @Override
+    @DataSource(DataSourceType.SOP)
+    public List<QwSopTempContent> listByTempIds(Collection<String> tempIds) {
+        return baseMapper.selectList(new QueryWrapper<QwSopTempContent>().in("temp_id", tempIds));
+    }
 }

+ 9 - 0
fs-service/src/main/java/com/fs/sop/service/impl/QwSopTempDayServiceImpl.java

@@ -1,6 +1,8 @@
 package com.fs.sop.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fs.common.annotation.DataSource;
 import com.fs.common.enums.DataSourceType;
@@ -11,6 +13,7 @@ import lombok.AllArgsConstructor;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.util.Collection;
 import java.util.List;
 
 /**
@@ -83,4 +86,10 @@ public class QwSopTempDayServiceImpl extends ServiceImpl<QwSopTempDayMapper, QwS
     public int getDayNumByIdLimitOne(String tempId) {
         return  qwSopTempDayMapper.getDayNumByIdLimitOne(tempId);
     }
+
+    @Override
+    @DataSource(DataSourceType.SOP)
+    public void removeByTempIds(Collection<String> tempIds) {
+        this.remove(new QueryWrapper<QwSopTempDay>().in("temp_id", tempIds));
+    }
 }

+ 26 - 19
fs-service/src/main/java/com/fs/sop/service/impl/QwSopTempRulesServiceImpl.java

@@ -25,6 +25,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -59,8 +60,7 @@ public class QwSopTempRulesServiceImpl extends ServiceImpl<QwSopTempRulesMapper,
      * @return sop任务模板规则
      */
     @Override
-    public QwSopTempRules selectQwSopTempRulesById(String id)
-    {
+    public QwSopTempRules selectQwSopTempRulesById(String id) {
         return baseMapper.selectQwSopTempRulesById(id);
     }
 
@@ -71,8 +71,7 @@ public class QwSopTempRulesServiceImpl extends ServiceImpl<QwSopTempRulesMapper,
      * @return sop任务模板规则
      */
     @Override
-    public List<QwSopTempRules> selectQwSopTempRulesList(QwSopTempRules qwSopTempRules)
-    {
+    public List<QwSopTempRules> selectQwSopTempRulesList(QwSopTempRules qwSopTempRules) {
         return baseMapper.selectQwSopTempRulesList(qwSopTempRules);
     }
 
@@ -83,8 +82,7 @@ public class QwSopTempRulesServiceImpl extends ServiceImpl<QwSopTempRulesMapper,
      * @return 结果
      */
     @Override
-    public int insertQwSopTempRules(QwSopTempRules qwSopTempRules)
-    {
+    public int insertQwSopTempRules(QwSopTempRules qwSopTempRules) {
         return baseMapper.insertQwSopTempRules(qwSopTempRules);
     }
 
@@ -95,8 +93,7 @@ public class QwSopTempRulesServiceImpl extends ServiceImpl<QwSopTempRulesMapper,
      * @return 结果
      */
     @Override
-    public int updateQwSopTempRules(QwSopTempRules qwSopTempRules)
-    {
+    public int updateQwSopTempRules(QwSopTempRules qwSopTempRules) {
         return baseMapper.updateQwSopTempRules(qwSopTempRules);
     }
 
@@ -107,8 +104,7 @@ public class QwSopTempRulesServiceImpl extends ServiceImpl<QwSopTempRulesMapper,
      * @return 结果
      */
     @Override
-    public int deleteQwSopTempRulesByIds(String[] ids)
-    {
+    public int deleteQwSopTempRulesByIds(String[] ids) {
         return baseMapper.deleteQwSopTempRulesByIds(ids);
     }
 
@@ -119,8 +115,7 @@ public class QwSopTempRulesServiceImpl extends ServiceImpl<QwSopTempRulesMapper,
      * @return 结果
      */
     @Override
-    public int deleteQwSopTempRulesById(String id)
-    {
+    public int deleteQwSopTempRulesById(String id) {
         return baseMapper.deleteQwSopTempRulesById(id);
     }
 
@@ -140,7 +135,7 @@ public class QwSopTempRulesServiceImpl extends ServiceImpl<QwSopTempRulesMapper,
     @DataSource(DataSourceType.SOP)
     public List<QwSopTempRules> listByTempId(String id) {
         List<QwSopTempDay> dayList = qwSopTempDayService.list(new QueryWrapper<QwSopTempDay>().eq("temp_id", id).orderByAsc("day_num"));
-        if(dayList.isEmpty()) return Collections.emptyList();
+        if (dayList.isEmpty()) return Collections.emptyList();
         Map<Long, Integer> collect = dayList.stream().collect(Collectors.toMap(QwSopTempDay::getId, QwSopTempDay::getDayNum));
         List<QwSopTempRules> rulesList = list(new QueryWrapper<QwSopTempRules>().in("day_id", PubFun.listToNewList(dayList, QwSopTempDay::getId)));
         rulesList.forEach(r -> {
@@ -148,7 +143,7 @@ public class QwSopTempRulesServiceImpl extends ServiceImpl<QwSopTempRulesMapper,
         });
         List<QwSopTempContent> ts = qwSopTempContentService.list(new QueryWrapper<QwSopTempContent>().in("rules_id", PubFun.listToNewList(rulesList, QwSopTempRules::getId)));
         Map<Long, List<QwSopTempContent>> map = PubFun.listToMapByGroupList(ts, QwSopTempContent::getRulesId);
-        rulesList.stream().filter( e -> map.containsKey(e.getId())).forEach(e -> e.setSettingList(map.get(e.getId())));
+        rulesList.stream().filter(e -> map.containsKey(e.getId())).forEach(e -> e.setSettingList(map.get(e.getId())));
         return rulesList;
     }
 
@@ -202,9 +197,9 @@ public class QwSopTempRulesServiceImpl extends ServiceImpl<QwSopTempRulesMapper,
     public void updateRulesDayNumIsNull() {
         List<QwSopTempRules> rules = qwSopTempRulesMapper.rulesNull();
         log.info("时间为空的有:{}", rules.size());
-        for (QwSopTempRules rule : rules){
+        for (QwSopTempRules rule : rules) {
             QwSopTempDay day = dayMapper.info(rule.getDayId());
-            if (day!=null){
+            if (day != null) {
                 QwSopTempRules rules1 = new QwSopTempRules();
                 rules1.setDayNum(day.getDayNum());
                 rules1.setId(rule.getId());
@@ -226,14 +221,14 @@ public class QwSopTempRulesServiceImpl extends ServiceImpl<QwSopTempRulesMapper,
     @Override
     public void updateSiFenTemp() {
         List<QwSopTempContentVO> contents = contentMapper.updateSiFenTemp();
-        for(QwSopTempContentVO content : contents){
-            if (content.getVideoId()==null){
+        for (QwSopTempContentVO content : contents) {
+            if (content.getVideoId() == null) {
                 continue;
             }
             QwSopTempContent content1 = new QwSopTempContent();
             FsUserCourseVideo video = videoMapper.selectFsUserCourseVideoByVideoId(content.getVideoId());
             QwSopTempSetting.Content.Setting settingMap = new QwSopTempSetting.Content.Setting();
-            QwSopTempSetting.Content.Setting setting = JSON.parseObject(content.getContent(),QwSopTempSetting.Content.Setting.class);
+            QwSopTempSetting.Content.Setting setting = JSON.parseObject(content.getContent(), QwSopTempSetting.Content.Setting.class);
             settingMap.setContentType("4");
             settingMap.setMiniprogramAppid("wx73f85f8d62769119");
             settingMap.setMiniprogramPicUrl(setting.getLinkImageUrl());
@@ -245,4 +240,16 @@ public class QwSopTempRulesServiceImpl extends ServiceImpl<QwSopTempRulesMapper,
             contentMapper.updateQwSopTempContent(content1);
         }
     }
+
+    @Override
+    @DataSource(DataSourceType.SOP)
+    public List<QwSopTempRules> listByCourseId(Long courseId) {
+        return qwSopTempRulesMapper.selectQwSopTempRulesListByCourseId(courseId);
+    }
+
+    @Override
+    @DataSource(DataSourceType.SOP)
+    public void removeByTempIds(Collection<String> tempIds) {
+        this.remove(new QueryWrapper<QwSopTempRules>().in("temp_id", tempIds));
+    }
 }

+ 140 - 62
fs-service/src/main/java/com/fs/sop/service/impl/QwSopTempServiceImpl.java

@@ -9,7 +9,6 @@ import com.fs.common.exception.base.BaseException;
 import com.fs.common.utils.PubFun;
 import com.fs.company.domain.Company;
 import com.fs.company.service.ICompanyService;
-import com.fs.company.service.impl.CompanyServiceImpl;
 import com.fs.config.cloud.CloudHostProper;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.FsUserCourse;
@@ -30,16 +29,16 @@ import com.fs.sop.mapper.QwSopTempMapper;
 import com.fs.sop.params.QwSopShareTempParam;
 import com.fs.sop.service.*;
 import com.fs.sop.vo.QwSopTempRedPackageVo;
-import com.fs.sop.vo.VoiceVo;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.service.ISysConfigService;
 import io.netty.util.internal.StringUtil;
 import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.beanutils.ConvertUtils;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.rocketmq.spring.core.RocketMQTemplate;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
@@ -47,6 +46,7 @@ import java.text.SimpleDateFormat;
 import java.time.LocalTime;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
@@ -59,8 +59,8 @@ import java.util.stream.Collectors;
  */
 @Service
 @AllArgsConstructor
-public class QwSopTempServiceImpl implements IQwSopTempService
-{
+@Slf4j
+public class QwSopTempServiceImpl implements IQwSopTempService {
 
     @Autowired
     private CloudHostProper cloudHostProper;
@@ -79,6 +79,7 @@ public class QwSopTempServiceImpl implements IQwSopTempService
     private final IQwSopService qwSopService;
     private final IQwUserService qwUserService;
     private final ICompanyService companyService;
+    private final ThreadPoolTaskExecutor threadPoolTaskExecutor;
 
     /**
      * 查询sop模板
@@ -87,7 +88,7 @@ public class QwSopTempServiceImpl implements IQwSopTempService
      * @return sop模板
      */
     @Override
-    public QwSopTemp selectQwSopTempById(String id){
+    public QwSopTemp selectQwSopTempById(String id) {
 //        QwSopTemp qwSopTemp = qwSopTempMapper.selectQwSopTempById(id);
         QwSopTemp qwSopTemp = qwSopTempMapper.selectQwSopTempById(id);
         List<QwSopTempDay> qwSopTempDays = qwSopTempDayService.listByTempId(id);
@@ -117,8 +118,7 @@ public class QwSopTempServiceImpl implements IQwSopTempService
      * @return sop模板
      */
     @Override
-    public List<QwSopTemp> selectQwSopTempList(QwSopTemp qwSopTemp)
-    {
+    public List<QwSopTemp> selectQwSopTempList(QwSopTemp qwSopTemp) {
         return qwSopTempMapper.selectQwSopTempList(qwSopTemp);
     }
 
@@ -129,7 +129,7 @@ public class QwSopTempServiceImpl implements IQwSopTempService
      * @return 结果
      */
     @Override
-    public int insertQwSopTemp(QwSopTemp qwSopTemp){
+    public int insertQwSopTemp(QwSopTemp qwSopTemp) {
         qwSopTemp.setId(UUID.randomUUID().toString());
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         qwSopTemp.setCreateTime(sdf.format(new Date()));
@@ -155,7 +155,7 @@ public class QwSopTempServiceImpl implements IQwSopTempService
      * @return 结果
      */
     @Override
-    public int updateQwSopTemp(QwSopTemp qwSopTemp){
+    public int updateQwSopTemp(QwSopTemp qwSopTemp) {
         return qwSopTempMapper.updateQwSopTemp(qwSopTemp);
     }
 
@@ -166,8 +166,7 @@ public class QwSopTempServiceImpl implements IQwSopTempService
      * @return 结果
      */
     @Override
-    public int deleteQwSopTempByIds(String[] ids)
-    {
+    public int deleteQwSopTempByIds(String[] ids) {
         return qwSopTempMapper.deleteQwSopTempByIds(ids);
     }
 
@@ -196,8 +195,7 @@ public class QwSopTempServiceImpl implements IQwSopTempService
      * @return 结果
      */
     @Override
-    public int deleteQwSopTempById(String id)
-    {
+    public int deleteQwSopTempById(String id) {
         return qwSopTempMapper.deleteQwSopTempById(id);
     }
 
@@ -214,7 +212,7 @@ public class QwSopTempServiceImpl implements IQwSopTempService
     public int update(QwSopTemp qwSopTemp) {
         QwSopTemp temp = qwSopTempMapper.selectById(qwSopTemp.getId());
         int i = qwSopTempMapper.updateById(qwSopTemp);
-        if(!Objects.equals(temp.getGap(), qwSopTemp.getGap())){
+        if (!Objects.equals(temp.getGap(), qwSopTemp.getGap())) {
             // 重新排序
             reorder(qwSopTemp.getId());
         }
@@ -233,7 +231,7 @@ public class QwSopTempServiceImpl implements IQwSopTempService
         qwSopTempRulesService.removeByDayId(day.getId());
         qwSopTempContentService.removeByDayId(day.getId());
 
-        list.forEach(item-> item.setDayId(day.getId()));
+        list.forEach(item -> item.setDayId(day.getId()));
         processAndReplaceContent(list);
         QwSopTempRules rules = list.get(0);
         String tempId = rules.getTempId();
@@ -251,29 +249,29 @@ public class QwSopTempServiceImpl implements IQwSopTempService
         reorder(day.getTempId());
         Map<String, Object> map = new HashMap<>();
         map.put("id", day.getId());
-        if(!voiceList.isEmpty()){
+        if (!voiceList.isEmpty()) {
             for (QwSopTempContent qwSopTempContent : voiceList) {
                 String content = qwSopTempContent.getContent();
                 JSONObject jsonObject = JSONObject.parseObject(content);
                 String text = jsonObject.getString("value");
                 List<QwSop> qwSopList = qwSopService.selectQwSopByTempId(tempId);//通过tempId查询出所有sop
-                if(qwSopList != null && !qwSopList.isEmpty()){
+                if (qwSopList != null && !qwSopList.isEmpty()) {
                     for (QwSop qwSop : qwSopList) {
-                        if(qwSop != null && qwSop.getQwUserIds() != null){
+                        if (qwSop != null && qwSop.getQwUserIds() != null) {
                             //查询出所有的tempContent来筛选文字
                             List<QwSopTempContent> qwSopTempContentList = qwSopTempContentService.selectQwSopTempContentByTempId(tempId);
-                            if(qwSopTempContentList != null && !qwSopTempContentList.isEmpty()){
+                            if (qwSopTempContentList != null && !qwSopTempContentList.isEmpty()) {
                                 for (QwSopTempContent qwSopTemp : qwSopTempContentList) {
-                                    if(qwSopTemp != null && qwSopTemp.getContentType() == 7){
+                                    if (qwSopTemp != null && qwSopTemp.getContentType() == 7) {
                                         String[] split = qwSop.getQwUserIds().split(",");
                                         Long[] qwUserIds = (Long[]) ConvertUtils.convert(split, Long.class);
                                         List<QwUserVO> qwUserVOS = qwUserService.selectQwUserVOByIds(qwUserIds);
-                                        if(qwUserVOS != null){
+                                        if (qwUserVOS != null) {
                                             for (QwUserVO qwUserVO : qwUserVOS) {
                                                 Long companyUserId = qwUserVO.getCompanyUserId();
-                                                QwSopTempVoice qwSopTempVoice = qwSopTempVoiceService.selectQwSopTempVoiceByCompanyUserIdAndVoiceTxt(companyUserId,text);
-                                                if(qwSopTempVoice == null){
-                                                    if(companyUserId != null && text != null){
+                                                QwSopTempVoice qwSopTempVoice = qwSopTempVoiceService.selectQwSopTempVoiceByCompanyUserIdAndVoiceTxt(companyUserId, text);
+                                                if (qwSopTempVoice == null) {
+                                                    if (companyUserId != null && text != null) {
                                                         QwSopTempVoice sopTempVoice = new QwSopTempVoice();
                                                         sopTempVoice.setCompanyUserId(companyUserId);
                                                         sopTempVoice.setVoiceTxt(text);
@@ -298,12 +296,12 @@ public class QwSopTempServiceImpl implements IQwSopTempService
         return map;
     }
 
-    private void processAndReplaceContent(List<QwSopTempRules> tempSettings){
+    private void processAndReplaceContent(List<QwSopTempRules> tempSettings) {
         List<FastGptChatReplaceWords> words = fastGptChatReplaceWordsMapper.selectAllFastGptChatReplaceWords();
         //循环天
-        tempSettings.forEach(settingList->{
+        tempSettings.forEach(settingList -> {
             //循环单日
-            settingList.getSettingList().forEach(item->{
+            settingList.getSettingList().forEach(item -> {
                 JSONObject obj = JSON.parseObject(item.getContent());
                 List<String> list = Arrays.asList("linkTitle", "linkDescribe", "desc", "nickname", "value");
                 list.stream().filter(obj::containsKey).forEach(key -> {
@@ -316,23 +314,24 @@ public class QwSopTempServiceImpl implements IQwSopTempService
 
     @Override
     public void delRules(Long id) {
-        if(id == null) return;
+        if (id == null) return;
         QwSopTempDay day = qwSopTempDayService.info(id);
-        if(day == null) return;
+        if (day == null) return;
         qwSopTempDayService.removeById(day.getId());
         qwSopTempContentService.removeByDayId(day.getId());
         reorder(day.getTempId());
     }
+
     @Override
     public QwSopTempDay selectRulesInfo(Long id) {
         QwSopTempDay day = qwSopTempDayService.info(id);
         List<QwSopTempRules> rulesList = qwSopTempRulesService.listByDayId(id);
-        if(!rulesList.isEmpty()){
+        if (!rulesList.isEmpty()) {
             List<QwSopTempContent> contentList = qwSopTempContentService.listByRulesIds(PubFun.listToNewList(rulesList, QwSopTempRules::getId));
             Map<Long, List<QwSopTempContent>> contentMap = PubFun.listToMapByGroupList(contentList, QwSopTempContent::getRulesId);
             rulesList.forEach(e -> {
                 List<QwSopTempContent> contents = contentMap.get(e.getId());
-                if (CollectionUtils.isNotEmpty(contents)){
+                if (CollectionUtils.isNotEmpty(contents)) {
                     e.setSetting(contents.stream().map(c -> JSON.parseObject(c.getContent())).collect(Collectors.toList()));
                 }
             });
@@ -353,14 +352,14 @@ public class QwSopTempServiceImpl implements IQwSopTempService
         qwSopTemp.setId(newId);
         qwSopTempMapper.insertQwSopTemp(qwSopTemp);
         List<QwSopTempDay> dayList = qwSopTempRulesService.listByTempIdAll(oldId);
-        if(dayList.isEmpty()) return;
+        if (dayList.isEmpty()) return;
 //        List<QwSopTempRules> rulesList = qwSopTempRulesService.listByTempId(oldId);
         dayList.forEach(day -> {
             day.setTempId(newId);
-            if(day.getList() != null && !day.getList().isEmpty()){
+            if (day.getList() != null && !day.getList().isEmpty()) {
                 day.getList().forEach(e -> {
                     e.setTempId(newId);
-                    if(e.getSettingList() != null && !e.getSettingList().isEmpty()){
+                    if (e.getSettingList() != null && !e.getSettingList().isEmpty()) {
                         e.getSettingList().forEach(item -> {
                             item.setTempId(newId);
                         });
@@ -376,7 +375,7 @@ public class QwSopTempServiceImpl implements IQwSopTempService
             item.setRulesId(e.getId());
             item.setDayId(e.getDayId());
         }));
-        qwSopTempContentService.insertBatch(collect.stream().flatMap(e ->e.getSettingList().stream()).collect(Collectors.toList()));
+        qwSopTempContentService.insertBatch(collect.stream().flatMap(e -> e.getSettingList().stream()).collect(Collectors.toList()));
     }
 
     @Override
@@ -390,7 +389,7 @@ public class QwSopTempServiceImpl implements IQwSopTempService
     public void sortDay(List<SortDayVo> list) {
         Collection<QwSopTempDay> days = qwSopTempDayService.listByIds(PubFun.listToNewList(list, SortDayVo::getId));
         Map<Long, Integer> dayMap = list.stream().collect(Collectors.toMap(SortDayVo::getId, SortDayVo::getDayNum));
-        if(days.stream().anyMatch(e -> !dayMap.containsKey(e.getId()))){
+        if (days.stream().anyMatch(e -> !dayMap.containsKey(e.getId()))) {
             throw new BaseException("数据错误!");
         }
         days.forEach(day -> day.setDayNum(dayMap.get(day.getId())));
@@ -404,10 +403,10 @@ public class QwSopTempServiceImpl implements IQwSopTempService
 
 
     @DataSource(DataSourceType.SOP)
-    private void reorder(String tempId){
+    private void reorder(String tempId) {
         QwSopTemp qwSopTemp = qwSopTempMapper.selectQwSopTempById(tempId);
         List<QwSopTempDay> days = qwSopTempDayService.listByTempId(tempId);
-        if(days.isEmpty()) return;
+        if (days.isEmpty()) return;
         for (int i = 0; i < days.size(); i++) {
             QwSopTempDay entity = days.get(i);
             entity.setSorts(i);
@@ -418,7 +417,7 @@ public class QwSopTempServiceImpl implements IQwSopTempService
 
     @Override
     public void createSopTempRules(QwSopTemp temp) {
-        if(temp.getTime() == null){
+        if (temp.getTime() == null) {
             return;
         }
 
@@ -436,11 +435,11 @@ public class QwSopTempServiceImpl implements IQwSopTempService
             day.setSorts(day.getDayNum());
             day.setList(new ArrayList<>());
             List<String> timeList = new ArrayList<>();
-            if(temp.getTimeList() != null){
+            if (temp.getTimeList() != null) {
                 timeList = JSON.parseArray(JSON.toJSONString(temp.getTimeList()), String.class);
             }
             DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm");
-            if(temp.getTime() != null){
+            if (temp.getTime() != null) {
                 timeList.add(0, temp.getTime().format(formatter));
             }
             AtomicInteger sorts = new AtomicInteger(0);
@@ -448,15 +447,15 @@ public class QwSopTempServiceImpl implements IQwSopTempService
                 QwSopTempRules rules = new QwSopTempRules();
                 rules.setTempId(temp.getId());
                 rules.setName(day.getName());
-                if (temp.getOpenOfficial().equals("1")){
+                if (temp.getOpenOfficial().equals("1")) {
                     rules.setIsOfficial(sorts.get() == 0 ? "1" : "0");
-                }else {
+                } else {
                     rules.setIsOfficial("0");
                 }
 
-                if (day.getDayNum()==1 && sorts.get() == 0 && temp.getOpenOfficial().equals("1")){
+                if (day.getDayNum() == 1 && sorts.get() == 0 && temp.getOpenOfficial().equals("1")) {
                     rules.setTime("01:05");
-                }else {
+                } else {
                     rules.setTime(time);
                 }
 
@@ -475,10 +474,10 @@ public class QwSopTempServiceImpl implements IQwSopTempService
                 setting.setMiniprogramTitle(e.getTitle());
 
                 //用课节图片做封面
-                if("今正科技".equals(cloudHostProper.getCompanyName())){
-                    setting.setMiniprogramPicUrl(!StringUtil.isNullOrEmpty(e.getThumbnail())?e.getThumbnail():fsUserCourse.getImgUrl());
-                    setting.setLinkImageUrl(!StringUtil.isNullOrEmpty(e.getThumbnail())?e.getThumbnail():fsUserCourse.getImgUrl());
-                }else {
+                if ("今正科技".equals(cloudHostProper.getCompanyName())) {
+                    setting.setMiniprogramPicUrl(!StringUtil.isNullOrEmpty(e.getThumbnail()) ? e.getThumbnail() : fsUserCourse.getImgUrl());
+                    setting.setLinkImageUrl(!StringUtil.isNullOrEmpty(e.getThumbnail()) ? e.getThumbnail() : fsUserCourse.getImgUrl());
+                } else {
                     setting.setMiniprogramPicUrl(fsUserCourse.getImgUrl());
                     setting.setLinkImageUrl(fsUserCourse.getImgUrl());
 
@@ -489,7 +488,7 @@ public class QwSopTempServiceImpl implements IQwSopTempService
                 setting.setContentType("4");
                 content.setContent(JSON.toJSONString(setting));
                 content.setIsBindUrl(1);
-                List<QwSopTempContent> qwSopTempContents = new ArrayList<>() ;
+                List<QwSopTempContent> qwSopTempContents = new ArrayList<>();
                 qwSopTempContents.add(content);
                 if (sorts.get() == 0 && !StringUtil.isNullOrEmpty(temp.getModeContent())) {
                     QwSopTempContent content2 = new QwSopTempContent();
@@ -501,13 +500,13 @@ public class QwSopTempServiceImpl implements IQwSopTempService
                     content2.setContent(JSON.toJSONString(setting2));
                     qwSopTempContents.add(content2);
                 }
-                if (sorts.get() > 0){
+                if (sorts.get() > 0) {
 
                     QwSopTempContent content3 = new QwSopTempContent();
                     content3.setTempId(temp.getId());
                     content3.setContentType(3);
                     QwSopTempSetting2.Content.Setting setting3 = new QwSopTempSetting2.Content.Setting();
-                    setting3.setValue(temp.getTimeDesc().get(sorts.get()-1));
+                    setting3.setValue(temp.getTimeDesc().get(sorts.get() - 1));
                     setting3.setContentType("1");
                     content3.setContent(JSON.toJSONString(setting3));
                     qwSopTempContents.add(content3);
@@ -515,11 +514,11 @@ public class QwSopTempServiceImpl implements IQwSopTempService
                 }
 
                 rules.setSorts(sorts.getAndIncrement());
-                if(rules.getSorts() == 0){
+                if (rules.getSorts() == 0) {
                     rules.setCourseType(0);
-                }else if(rules.getSorts() == 1){
+                } else if (rules.getSorts() == 1) {
                     rules.setCourseType(1);
-                }else{
+                } else {
                     rules.setCourseType(4);
                 }
                 rules.setList(qwSopTempContents);
@@ -540,10 +539,10 @@ public class QwSopTempServiceImpl implements IQwSopTempService
         CourseConfig courseConfig = JSON.parseObject(sysConfig.getConfigValue(), CourseConfig.class);
         List<Long> videoIdList = PubFun.listToNewList(ruleList, QwSopTempRules::getVideoId);
         Map<Long, Optional<BigDecimal>> redMap;
-        if(!videoIdList.isEmpty()){
+        if (!videoIdList.isEmpty()) {
             List<FsUserCourseVideoRedPackage> redPackageList = fsUserCourseVideoRedPackageService.listByCompanyIdAndVideoIds(temp.getCompanyId(), videoIdList);
             redMap = redPackageList.stream().collect(Collectors.groupingBy(FsUserCourseVideoRedPackage::getVideoId, Collectors.mapping(FsUserCourseVideoRedPackage::getRedPacketMoney, Collectors.reducing((e1, e2) -> e1))));
-        }else{
+        } else {
             redMap = new HashMap<>();
         }
 
@@ -562,15 +561,15 @@ public class QwSopTempServiceImpl implements IQwSopTempService
     @Override
     public List<QwSopTempRedPackageVo> redList(String id) {
         List<QwSopTempDay> dayList = qwSopTempRulesService.listByTempIdAll(id);
-        if(CollectionUtils.isEmpty(dayList)){
+        if (CollectionUtils.isEmpty(dayList)) {
             return Collections.emptyList();
         }
         List<QwSopTempRules> rules = dayList.stream()
-                .filter(e->e!= null && e.getList()!=null)
+                .filter(e -> e != null && e.getList() != null)
                 .flatMap(e -> e.getList().stream())
                 .filter(Objects::nonNull)
                 .collect(Collectors.toList());
-        if(rules.isEmpty()){
+        if (rules.isEmpty()) {
             return Collections.emptyList();
         }
         List<FsUserCourseVideoRedPackage> redPackageList = fsUserCourseVideoRedPackageService.listByRuleIds(PubFun.listToNewList(rules, QwSopTempRules::getId));
@@ -608,14 +607,93 @@ public class QwSopTempServiceImpl implements IQwSopTempService
         }).collect(Collectors.toList());
         fsUserCourseVideoRedPackageService.batchSaveFsUserCourseVideoRedPackage(redPackage);
     }
+
     @Override
     public List<String> getSelectableRange() {
         SysConfig sysConfig = sysConfigService.selectConfigByConfigKey("course.config");
         CourseConfig courseConfig = JSON.parseObject(sysConfig.getConfigValue(), CourseConfig.class);
         List<CourseConfig.DisabledTimeVo> disabledTimeList = courseConfig.getDisabledTimeList();
-        if(disabledTimeList == null){
+        if (disabledTimeList == null) {
             return Collections.emptyList();
         }
         return TimeCalculator.calculateAvailableTimes(disabledTimeList);
     }
+
+
+    @Override
+    public void syncTemplate(Long courseId) {
+        // 根据courseId查询所有相关的sop模板规则
+        List<QwSopTempRules> rulesList = qwSopTempRulesService.listByCourseId(courseId);
+        if (CollectionUtils.isEmpty(rulesList)) {
+            return;
+        }
+
+        // 获取这些规则关联的模板ID集合
+        Set<String> tempIds = rulesList.stream()
+                .map(QwSopTempRules::getTempId)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toSet());
+
+        // 查询相关联的sop模板
+        if (CollectionUtils.isEmpty(tempIds)) {
+            return;
+        }
+        List<QwSopTemp> tempList = qwSopTempMapper.selectListByIds(tempIds);
+        tempList = tempList.stream().filter(f -> Objects.equals(f.getStatus(), "1")).collect(Collectors.toList());
+        if (CollectionUtils.isEmpty(tempList)) {
+            return;
+        }
+        List<QwSopTempContent> contentList = qwSopTempContentService.listByTempIds(tempIds);
+
+        CountDownLatch latch = new CountDownLatch(tempList.size());
+        // 对每个模板执行同步操作
+        for (QwSopTemp temp : tempList) {
+            // 构造timeList timeDesc time
+            rulesList.stream().filter(e -> e.getTempId().equals(temp.getId())).findFirst()
+                    .ifPresent(first -> temp.setTime(LocalTime.parse(first.getTime() + ":00")));
+
+            temp.setTimeList(rulesList.stream()
+                    .filter(e -> e.getTempId().equals(temp.getId()) && Objects.equals(e.getIsOfficial(), "0")
+                            && Objects.equals(e.getName(), "第1天")).map(QwSopTempRules::getTime)
+                    .collect(Collectors.toList()));
+            // 过滤并找到 dayId 最小的元素
+            Optional<QwSopTempContent> minDayEntity = contentList.stream()
+                    // 1. 过滤条件:tempId匹配 + isBindUrl为null
+                    .filter(e -> e.getTempId().equals(temp.getId())
+                            && Objects.isNull(e.getIsBindUrl()))
+                    // 2. 按 dayId 升序排序,取第一个(最小)
+                    .min(Comparator.comparingLong(QwSopTempContent::getDayId)); // 若dayId是Long,用comparingLong
+
+            if (minDayEntity.isPresent()) {
+                QwSopTempContent qwSopTempContent = minDayEntity.get();
+                temp.setTimeDesc(contentList.stream().filter(e -> e.getTempId().equals(temp.getId())
+                                && Objects.isNull(e.getIsBindUrl())
+                                && Objects.equals(qwSopTempContent.getDayId(), e.getDayId())
+                        )
+                        .map(m -> JSONObject.parseObject(m.getContent()).getString("value")).collect(Collectors.toList()));
+            }
+
+            // 插入课程id
+            temp.setCourseId(courseId);
+            temp.setOpenOfficial("1");
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            temp.setCreateTime(sdf.format(new Date()));
+            temp.setId(UUID.randomUUID().toString());
+            qwSopTempMapper.insertQwSopTemp(temp);
+            // 重新生成该模板的规则和内容
+            threadPoolTaskExecutor.execute(() -> createSopTempRules(temp));
+            latch.countDown();
+        }
+
+        try {
+            latch.await();
+            qwSopTempMapper.deleteQwSopTempByIds(tempIds.toArray(new String[0]));
+            qwSopTempDayService.removeByTempIds(tempIds);
+            qwSopTempRulesService.removeByTempIds(tempIds);
+            qwSopTempContentService.removeByTempIds(tempIds);
+        } catch (InterruptedException e) {
+            log.error("等待线程执行完成时被中断", e);
+        }
+    }
+
 }

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

@@ -64,7 +64,7 @@ fs :
   h5CommonApi: http://172.17.0.10:8010
   jwt:
     # 加密秘钥
-    secret: f4e2e52034348f86b67cde581c0f9eb5
+    secret: f4k2y52034348t86b67cde581c0f9eb5
     # token有效时长,7天,单位秒
     expire: 31536000
     header: AppToken

+ 1 - 1
fs-service/src/main/resources/application-config-druid-nmgyt.yml

@@ -96,6 +96,6 @@ ipad:
 wx_miniapp_temp:
   pay_order_temp_id: V
   inquiry_temp_id: 9
-enableRedPackAccount: 0
+enableRedPackAccount: 1
 
 

+ 1 - 1
fs-service/src/main/resources/application-config-druid-qdtst.yml

@@ -64,7 +64,7 @@ fs :
   h5CommonApi: http://10.206.0.16:8010
   jwt:
     # 加密秘钥
-    secret: f4q2d52034348t86b678s1581c0f9eb5
+    secret: f4e2e52034348f86b67cde581c0f9eb5
     # token有效时长,7天,单位秒
     expire: 31536000
     header: AppToken

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

@@ -156,4 +156,4 @@ openIM:
 im:
     type: NONE
 #是否为新商户,新商户不走mpOpenId
-isNewWxMerchant: true
+isNewWxMerchant: false

+ 0 - 8
fs-service/src/main/resources/mapper/course/FsProjectAddressConfigMapper.xml

@@ -1,8 +0,0 @@
-<?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.course.mapper.FsProjectAddressConfigMapper">
-
-
-</mapper>

+ 1 - 0
fs-service/src/main/resources/mapper/course/FsUserCoursePeriodDaysMapper.xml

@@ -34,6 +34,7 @@
             <if test="periodId != null "> and period_id = #{periodId}</if>
             <if test="courseId != null "> and a.course_id = #{courseId}</if>
             <if test="videoId != null "> and a.video_id = #{videoId}</if>
+            <if test="videoName != null "> and c.title like concat('%', #{videoName}, '%')</if>
             <if test="maxDate != null "> and a.day_date &lt;= #{maxDate}</if>
             <if test="videoIds != null and videoIds.size > 0">
                 and a.video_id in

+ 53 - 11
fs-service/src/main/resources/mapper/live/LiveDataMapper.xml

@@ -300,10 +300,42 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                 WHEN l.live_type = 3 AND lwu.online_seconds >= COALESCE(video_duration.total_duration, 0) AND video_duration.total_duration > 0 
                 THEN lwu.user_id 
             END) AS playbackCompletedCourses,
-            COALESCE(SUM(lo.pay_price), 0) AS gmv,
-            COUNT(DISTINCT CASE WHEN lo.is_pay = '1' THEN lo.user_id END) AS paidUsers,
-            COUNT(DISTINCT CASE WHEN lo.is_pay = '1' THEN lo.order_id END) AS paidOrders,
-            COUNT(DISTINCT CASE WHEN lo.is_pay = '1' THEN lo.order_id END) AS salesCount
+            COALESCE((
+                SELECT SUM(pay_price) 
+                FROM live_order 
+                WHERE live_id IN 
+                <foreach collection="liveIds" item="liveId" open="(" separator="," close=")">
+                    #{liveId}
+                </foreach>
+                AND is_pay = '1'
+            ), 0) AS gmv,
+            COALESCE((
+                SELECT COUNT(DISTINCT user_id) 
+                FROM live_order 
+                WHERE live_id IN 
+                <foreach collection="liveIds" item="liveId" open="(" separator="," close=")">
+                    #{liveId}
+                </foreach>
+                AND is_pay = '1'
+            ), 0) AS paidUsers,
+            COALESCE((
+                SELECT COUNT(DISTINCT order_id) 
+                FROM live_order 
+                WHERE live_id IN 
+                <foreach collection="liveIds" item="liveId" open="(" separator="," close=")">
+                    #{liveId}
+                </foreach>
+                AND is_pay = '1'
+            ), 0) AS paidOrders,
+            COALESCE((
+                SELECT COUNT(DISTINCT order_id) 
+                FROM live_order 
+                WHERE live_id IN 
+                <foreach collection="liveIds" item="liveId" open="(" separator="," close=")">
+                    #{liveId}
+                </foreach>
+                AND is_pay = '1'
+            ), 0) AS salesCount
         FROM live l
         LEFT JOIN live_watch_user lwu ON l.live_id = lwu.live_id
         LEFT JOIN (
@@ -312,7 +344,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             WHERE video_type IN (1, 2)
             GROUP BY live_id
         ) video_duration ON l.live_id = video_duration.live_id
-        LEFT JOIN live_order lo ON l.live_id = lo.live_id
         WHERE l.live_id IN
         <foreach collection="liveIds" item="liveId" open="(" separator="," close=")">
             #{liveId}
@@ -345,10 +376,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                 WHEN l.live_type = 3 AND lwu.online_seconds >= COALESCE(video_duration.total_duration, 0) AND video_duration.total_duration > 0 
                 THEN lwu.user_id 
             END) AS playbackCompletedCourses,
-            COALESCE(SUM(lo.pay_price), 0) AS gmv,
-            COUNT(DISTINCT CASE WHEN lo.is_pay = '1' THEN lo.user_id END) AS paidUsers,
-            COUNT(DISTINCT CASE WHEN lo.is_pay = '1' THEN lo.order_id END) AS paidOrders,
-            COUNT(DISTINCT CASE WHEN lo.is_pay = '1' THEN lo.order_id END) AS salesCount
+            COALESCE(order_stats.gmv, 0) AS gmv,
+            COALESCE(order_stats.paidUsers, 0) AS paidUsers,
+            COALESCE(order_stats.paidOrders, 0) AS paidOrders,
+            COALESCE(order_stats.salesCount, 0) AS salesCount
         FROM live l
         LEFT JOIN live_watch_user lwu ON l.live_id = lwu.live_id
         LEFT JOIN (
@@ -357,12 +388,23 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             WHERE video_type IN (1, 2)
             GROUP BY live_id
         ) video_duration ON l.live_id = video_duration.live_id
-        LEFT JOIN live_order lo ON l.live_id = lo.live_id
+        LEFT JOIN (
+            SELECT 
+                live_id,
+                SUM(pay_price) AS gmv,
+                COUNT(DISTINCT user_id) AS paidUsers,
+                COUNT(DISTINCT order_id) AS paidOrders,
+                COUNT(DISTINCT order_id) AS salesCount
+            FROM live_order
+            WHERE is_pay = '1'
+            GROUP BY live_id
+        ) order_stats ON l.live_id = order_stats.live_id
         WHERE l.live_id IN
         <foreach collection="liveIds" item="liveId" open="(" separator="," close=")">
             #{liveId}
         </foreach>
-        GROUP BY l.live_id, l.live_name, l.live_type, l.status, l.start_time, l.finish_time
+        GROUP BY l.live_id, l.live_name, l.live_type, l.status, l.start_time, l.finish_time, 
+                 order_stats.gmv, order_stats.paidUsers, order_stats.paidOrders, order_stats.salesCount
         ORDER BY l.start_time DESC
     </select>
 </mapper>

+ 42 - 1
fs-service/src/main/resources/mapper/live/LiveWatchUserMapper.xml

@@ -18,10 +18,13 @@
         <result property="onlineSeconds"    column="online_seconds"    />
         <result property="globalVisible"    column="global_visible"    />
         <result property="singleVisible"    column="single_visible"    />
+        <result property="liveFlag"    column="live_flag"    />
+        <result property="replayFlag"    column="replay_flag"    />
+        <result property="location"    column="location"    />
     </resultMap>
 
     <sql id="selectLiveWatchUserVo">
-        select id, live_id,user_id, msg_status, online, create_time, create_by, update_by, update_time, remark,online_seconds,global_visible,single_visible from live_watch_user
+        select id, live_id,user_id, msg_status, online, create_time, create_by, update_by, update_time, remark,online_seconds,global_visible,single_visible,live_flag,replay_flag,location from live_watch_user
     </sql>
 
     <select id="selectLiveWatchUserList" parameterType="LiveWatchUser" resultMap="LiveWatchUserResult">
@@ -125,6 +128,9 @@
             <if test="onlineSeconds != null">online_seconds,</if>
             <if test="globalVisible != null">global_visible,</if>
             <if test="singleVisible != null">single_visible,</if>
+            <if test="liveFlag != null">live_flag,</if>
+            <if test="replayFlag != null">replay_flag,</if>
+            <if test="location != null">location,</if>
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="liveId != null">#{liveId},</if>
@@ -139,6 +145,9 @@
             <if test="onlineSeconds != null">#{onlineSeconds},</if>
             <if test="globalVisible != null">#{globalVisible},</if>
             <if test="singleVisible != null">#{singleVisible},</if>
+            <if test="liveFlag != null">#{liveFlag},</if>
+            <if test="replayFlag != null">#{replayFlag},</if>
+            <if test="location != null">#{location},</if>
         </trim>
     </insert>
 
@@ -157,6 +166,9 @@
             <if test="onlineSeconds != null">online_seconds = #{onlineSeconds},</if>
             <if test="globalVisible != null">global_visible = #{globalVisible},</if>
             <if test="singleVisible != null">single_visible = #{singleVisible},</if>
+            <if test="liveFlag != null">live_flag = #{liveFlag},</if>
+            <if test="replayFlag != null">replay_flag = #{replayFlag},</if>
+            <if test="location != null">location = #{location},</if>
         </trim>
         where id = #{id}
     </update>
@@ -186,4 +198,33 @@
               AND DATE(lrr.create_time) = DATE(#{now})
         )
     </select>
+
+    <!-- 根据唯一索引查询:live_id, user_id, live_flag, replay_flag -->
+    <select id="selectByUniqueIndex" resultMap="LiveWatchUserResult">
+        <include refid="selectLiveWatchUserVo"/>
+        WHERE live_id = #{liveId}
+          AND user_id = #{userId}
+          AND live_flag = #{liveFlag}
+          AND replay_flag = #{replayFlag}
+        LIMIT 1
+    </select>
+
+    <!-- 根据唯一索引插入或更新(ON DUPLICATE KEY UPDATE) -->
+    <insert id="insertOrUpdateByUniqueIndex" parameterType="LiveWatchUser">
+        INSERT INTO live_watch_user (
+            live_id, user_id, live_flag, replay_flag,
+             msg_status, online, location,
+            create_time, update_time
+        ) VALUES (
+            #{liveId}, #{userId}, #{liveFlag}, #{replayFlag},
+             #{msgStatus}, #{online}, #{location},
+            #{createTime}, #{updateTime}
+        )
+        ON DUPLICATE KEY UPDATE
+
+            msg_status = VALUES(msg_status),
+            online = VALUES(online),
+            location = VALUES(location),
+            update_time = VALUES(update_time)
+    </insert>
 </mapper>

+ 0 - 26
fs-user-app/src/main/java/com/fs/app/controller/CommonController.java

@@ -33,8 +33,6 @@ import com.fs.company.domain.CompanyMoneyLogs;
 import com.fs.company.service.ICompanyMoneyLogsService;
 import com.fs.core.utils.OrderCodeUtils;
 import com.fs.course.config.CourseConfig;
-import com.fs.course.domain.FsProjectAddressConfig;
-import com.fs.course.service.IFsProjectAddressConfigService;
 import com.fs.course.service.IHuaweiVodService;
 import com.fs.event.TemplateBean;
 import com.fs.event.TemplateEvent;
@@ -80,7 +78,6 @@ import org.springframework.web.multipart.MultipartFile;
 import java.io.*;
 import java.math.BigDecimal;
 import java.util.*;
-import java.util.concurrent.TimeUnit;
 
 import static com.fs.common.utils.SecurityUtils.getUserId;
 
@@ -137,8 +134,6 @@ public class CommonController {
 
 	@Autowired
 	private IQwAppContactWayService qwAppContactWayService;
-	@Autowired
-	private IFsProjectAddressConfigService projectAddressConfigService;
 
 //	@Autowired
 //	private RocketMQTemplate rocketMQTemplate;
@@ -641,25 +636,4 @@ public class CommonController {
 		return ResponseResult.ok(config.getIsOpenIM());
 	}
 
-	@ApiOperation("获取项目对应api请求域名地址")
-	@GetMapping("/getDomain")
-	public R getDomain(@RequestParam String projectCode) {
-		String redisKey = "projectCode:" + projectCode;
-		FsProjectAddressConfig config = redisCache.getCacheObject(redisKey);
-		if (Objects.isNull(config)) {
-			config = projectAddressConfigService.selectDomainByCode(projectCode);
-			redisCache.setCacheObject(redisKey, config, 5, TimeUnit.MINUTES);
-		}
-		String addressUrl = "";
-		String imgPath = "";
-		Integer sendType = null;
-
-		if (Objects.nonNull(config)) {
-			addressUrl = config.getAddressUrl();
-			imgPath = config.getBucketPath();
-			sendType = config.getSendType();
-		}
-
-		return R.ok().put("addressUrl", addressUrl).put("imgpath", imgPath).put("sendType", sendType);
-	}
 }