Przeglądaj źródła

课程设置迁移和sop 群发

吴树波 3 tygodni temu
rodzic
commit
c3a32e9aea
84 zmienionych plików z 3651 dodań i 848 usunięć
  1. 48 18
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseVideoController.java
  2. 4 4
      fs-admin/src/main/resources/application.yml
  3. 21 1
      fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java
  4. 66 0
      fs-service/src/main/java/com/fs/company/domain/CompanyTag.java
  5. 94 0
      fs-service/src/main/java/com/fs/company/domain/CompanyTagUser.java
  6. 83 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyTagMapper.java
  7. 82 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyTagUserMapper.java
  8. 2 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyUserMapper.java
  9. 80 0
      fs-service/src/main/java/com/fs/company/service/ICompanyTagService.java
  10. 87 0
      fs-service/src/main/java/com/fs/company/service/ICompanyTagUserService.java
  11. 129 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyTagServiceImpl.java
  12. 173 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyTagUserServiceImpl.java
  13. 15 0
      fs-service/src/main/java/com/fs/company/vo/CompanyTagUserVO.java
  14. 3 0
      fs-service/src/main/java/com/fs/course/domain/FsCourseRedPacketLog.java
  15. 3 0
      fs-service/src/main/java/com/fs/course/domain/FsCourseWatchLog.java
  16. 44 0
      fs-service/src/main/java/com/fs/course/domain/FsUserCompanyUser.java
  17. 9 7
      fs-service/src/main/java/com/fs/course/domain/FsUserCoursePeriodDays.java
  18. 2 1
      fs-service/src/main/java/com/fs/course/domain/FsUserCourseVideo.java
  19. 8 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java
  20. 79 0
      fs-service/src/main/java/com/fs/course/mapper/FsUserCompanyUserMapper.java
  21. 18 32
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseVideoMapper.java
  22. 2 2
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseVideoRedPackageMapper.java
  23. 11 0
      fs-service/src/main/java/com/fs/course/param/BatchRedUpdate.java
  24. 11 0
      fs-service/src/main/java/com/fs/course/param/BatchVideoSvae.java
  25. 23 0
      fs-service/src/main/java/com/fs/course/param/CourseVideoUpdates.java
  26. 2 3
      fs-service/src/main/java/com/fs/course/param/FsCourseSendRewardUParam.java
  27. 41 0
      fs-service/src/main/java/com/fs/course/param/newfs/FsCourseSortLinkParam.java
  28. 36 0
      fs-service/src/main/java/com/fs/course/param/newfs/FsUserCourseAddCompanyUserParam.java
  29. 33 0
      fs-service/src/main/java/com/fs/course/param/newfs/FsUserCourseBeMemberImageParam.java
  30. 28 0
      fs-service/src/main/java/com/fs/course/param/newfs/FsUserCourseBeMemberParam.java
  31. 34 0
      fs-service/src/main/java/com/fs/course/param/newfs/FsUserCourseVideoLinkParam.java
  32. 26 0
      fs-service/src/main/java/com/fs/course/param/newfs/FsUserCourseVideoUParam.java
  33. 5 2
      fs-service/src/main/java/com/fs/course/param/newfs/UserCourseVideoPageParam.java
  34. 62 0
      fs-service/src/main/java/com/fs/course/service/IFsUserCompanyUserService.java
  35. 44 7
      fs-service/src/main/java/com/fs/course/service/IFsUserCourseVideoService.java
  36. 91 0
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCompanyUserServiceImpl.java
  37. 444 247
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  38. 57 0
      fs-service/src/main/java/com/fs/course/vo/FsCourseFinishTempVO.java
  39. 67 0
      fs-service/src/main/java/com/fs/course/vo/FsUserCourseParticipationRecordVO.java
  40. 83 0
      fs-service/src/main/java/com/fs/course/vo/HyWatchLog.java
  41. 9 4
      fs-service/src/main/java/com/fs/course/vo/newfs/FsCourseAnalysisCountVO.java
  42. 10 4
      fs-service/src/main/java/com/fs/course/vo/newfs/FsUserCourseListVO.java
  43. 31 0
      fs-service/src/main/java/com/fs/course/vo/newfs/FsUserCourseVideoLinkDetailsVO.java
  44. 6 0
      fs-service/src/main/java/com/fs/course/vo/newfs/FsUserCourseVideoPageListVO.java
  45. 5 357
      fs-service/src/main/java/com/fs/his/domain/FsUser.java
  46. 2 0
      fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java
  47. 3 0
      fs-service/src/main/java/com/fs/his/service/IFsUserService.java
  48. 49 3
      fs-service/src/main/java/com/fs/his/service/impl/FsUserServiceImpl.java
  49. 5 0
      fs-service/src/main/java/com/fs/qw/domain/QwGroupChatUser.java
  50. 3 0
      fs-service/src/main/java/com/fs/qw/mapper/QwExternalContactMapper.java
  51. 3 0
      fs-service/src/main/java/com/fs/qw/mapper/QwUserMapper.java
  52. 12 0
      fs-service/src/main/java/com/fs/qw/vo/GroupUserExternalVo.java
  53. 2 0
      fs-service/src/main/java/com/fs/sop/params/SendUserLogsInfoMsgParam.java
  54. 257 117
      fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsInfoServiceImpl.java
  55. 41 0
      fs-service/src/main/java/com/fs/store/param/h5/CourseAnalysisParam.java
  56. 78 0
      fs-service/src/main/java/com/fs/store/param/h5/FsUserPageListParam.java
  57. 28 0
      fs-service/src/main/java/com/fs/store/param/h5/TagListParam.java
  58. 40 0
      fs-service/src/main/java/com/fs/store/param/h5/UserStatisticsCommonParam.java
  59. 26 0
      fs-service/src/main/java/com/fs/store/vo/h5/CompanyUserSummaryCountVO.java
  60. 19 0
      fs-service/src/main/java/com/fs/store/vo/h5/CompanyUserTagListVO.java
  61. 27 0
      fs-service/src/main/java/com/fs/store/vo/h5/FsCourseRankingVO.java
  62. 34 0
      fs-service/src/main/java/com/fs/store/vo/h5/FsUserCountVO.java
  63. 34 0
      fs-service/src/main/java/com/fs/store/vo/h5/FsUserGraphicStatisticsVO.java
  64. 94 0
      fs-service/src/main/java/com/fs/store/vo/h5/FsUserPageListVO.java
  65. 27 0
      fs-service/src/main/java/com/fs/store/vo/h5/FsUserRankingVO.java
  66. 62 0
      fs-service/src/main/java/com/fs/store/vo/h5/FsUserStatisticsVO.java
  67. 19 0
      fs-service/src/main/java/com/fs/store/vo/h5/FsUserSummaryCountTagVO.java
  68. 25 0
      fs-service/src/main/java/com/fs/store/vo/h5/FsUserSummaryCountVO.java
  69. 34 0
      fs-service/src/main/java/com/fs/store/vo/h5/UserDetailsVO.java
  70. 20 0
      fs-service/src/main/java/com/fs/store/vo/h5/UserListCountVO.java
  71. 20 0
      fs-service/src/main/java/com/fs/store/vo/h5/UserListPageVO.java
  72. 2 0
      fs-service/src/main/resources/application-config-dev.yml
  73. 2 0
      fs-service/src/main/resources/application-config-druid-hcl.yml
  74. 2 2
      fs-service/src/main/resources/application-config-druid-jzzx.yml
  75. 2 0
      fs-service/src/main/resources/application-config-druid.yml
  76. 98 0
      fs-service/src/main/resources/mapper/company/CompanyTagMapper.xml
  77. 117 0
      fs-service/src/main/resources/mapper/company/CompanyTagUserMapper.xml
  78. 10 0
      fs-service/src/main/resources/mapper/company/CompanyUserMapper.xml
  79. 28 0
      fs-service/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml
  80. 90 0
      fs-service/src/main/resources/mapper/course/FsUserCompanyUserMapper.xml
  81. 114 35
      fs-service/src/main/resources/mapper/course/FsUserCourseVideoMapper.xml
  82. 5 0
      fs-service/src/main/resources/mapper/his/FsUserMapper.xml
  83. 5 1
      fs-service/src/main/resources/mapper/qw/QwExternalContactMapper.xml
  84. 1 1
      fs-user-app/src/main/java/com/fs/app/controller/CourseController.java

+ 48 - 18
fs-admin/src/main/java/com/fs/course/controller/FsUserCourseVideoController.java

@@ -1,29 +1,28 @@
 package com.fs.course.controller;
 
-import java.util.List;
-
-import com.fs.common.core.domain.R;
-import com.fs.course.domain.FsUserVideo;
-import com.fs.course.mapper.FsUserCourseVideoMapper;
-import com.fs.course.service.IFsUserCourseService;
-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.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.course.domain.FsUserCourseVideo;
+import com.fs.course.mapper.FsUserCourseVideoMapper;
+import com.fs.course.param.BatchRedUpdate;
+import com.fs.course.param.BatchVideoSvae;
+import com.fs.course.param.CourseVideoUpdates;
 import com.fs.course.service.IFsUserCourseVideoService;
-import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.common.core.page.TableDataInfo;
+import com.fs.his.vo.OptionsVO;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 /**
  * 课堂视频Controller
@@ -127,4 +126,35 @@ public class FsUserCourseVideoController extends BaseController
     {
         return R.ok().put("data",fsUserCourseVideoService.selectCourseVideoSort(courseId));
     }
+
+    @PostMapping("/updates")
+    public R updates(@RequestBody CourseVideoUpdates vo){
+        fsUserCourseVideoService.updates(vo);
+        return R.ok();
+    }
+    @PostMapping("/batchSaveVideo")
+    public R batchSaveVideo(@RequestBody BatchVideoSvae vo){
+        fsUserCourseVideoService.batchSaveVideo(vo);
+        return R.ok();
+    }
+    @PostMapping("/batchUpdateRed")
+    public R batchUpdateRed(@RequestBody List<BatchRedUpdate> list){
+        fsUserCourseVideoService.batchUpdateRed(list);
+        return R.ok();
+    }
+
+
+    @GetMapping("/getVideoListLikeName")
+    public R getVideoListLikeName(@RequestParam(required = false) String name,
+                                   @RequestParam(required = false) String periodId,
+                                   @RequestParam(required = false, defaultValue = "1") Integer pageNum,
+                                   @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
+        Map<String,Object> params = new HashMap<>();
+        params.put("name", name);
+        params.put("periodId", periodId);
+
+        PageHelper.startPage(pageNum, pageSize);
+        List<OptionsVO> periodList = fsUserCourseVideoService.selectVideoListByMap(params);
+        return R.ok().put("data", new PageInfo<>(periodList));
+    }
 }

+ 4 - 4
fs-admin/src/main/resources/application.yml

@@ -4,9 +4,9 @@ server:
 # Spring配置
 spring:
   profiles:
-#    active: dev
-#    include: common,config-dev
+    active: dev
+    include: common,config-dev
 #    active: druid-hcl
 #    include: common,config-druid-hcl
-    active: druid-hdt
-    include: common,config-druid-hdt
+#    active: druid-hdt
+#    include: common,config-druid-hdt

+ 21 - 1
fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java

@@ -26,6 +26,7 @@ import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.service.IQwGroupChatService;
 import com.fs.qw.service.IQwGroupChatUserService;
 import com.fs.qw.service.impl.QwExternalContactServiceImpl;
+import com.fs.qw.vo.GroupUserExternalVo;
 import com.fs.qw.vo.QwSopCourseFinishTempSetting;
 import com.fs.qw.vo.QwSopRuleTimeVO;
 import com.fs.qw.vo.QwSopTempSetting;
@@ -287,6 +288,14 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
         if (array.length > 0) {
             List<QwGroupChat> qwGroupChatList = qwGroupChatService.selectQwGroupChatByChatIds(array);
             List<QwGroupChatUser> qwGroupChatUserList = qwGroupChatUserService.selectQwGroupChatUserByChatIds(array);
+            List<String> groupChatUserIds = PubFun.listToNewList(qwGroupChatUserList, QwGroupChatUser::getUserId);
+            if(!groupChatUserIds.isEmpty()){
+                List<GroupUserExternalVo> userList = qwExternalContactMapper.selectByGroupUser(groupChatUserIds);
+                Map<String, List<GroupUserExternalVo>> userMap = PubFun.listToMapByGroupList(userList, GroupUserExternalVo::getExternalUserId);
+                qwGroupChatUserList.forEach(e -> {
+                    e.setUserList(userMap.getOrDefault(e.getUserId(), Collections.emptyList()));
+                });
+            }
             Map<String, List<QwGroupChatUser>> chatUserMap = PubFun.listToMapByGroupList(qwGroupChatUserList, QwGroupChatUser::getChatId);
             qwGroupChatList.stream().filter(e -> chatUserMap.containsKey(e.getChatId())).forEach(e -> e.setChatUserList(chatUserMap.get(e.getChatId())));
             groupChatMap = PubFun.listToMapByGroupObject(qwGroupChatList, QwGroupChat::getChatId);
@@ -601,7 +610,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
 
 
     private List<QwSopTempSetting.Content> getDay(List<QwSopTempRules> tempSettings, long days){
-        List<QwSopTempRules> collect = tempSettings.stream().filter(e -> e.getDayNum() == days).collect(Collectors.toList());
+        List<QwSopTempRules> collect = tempSettings.stream().filter(e -> e.getDayNum() == days && e.getTime() != null).collect(Collectors.toList());
         AtomicInteger i = new AtomicInteger();
         return collect.stream().map(e -> {
             QwSopTempSetting.Content content = new QwSopTempSetting.Content();
@@ -653,6 +662,17 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
             ruleTimeVO.setType(2);
             if (content.getIndex() == 0) {
                 QwSopLogs sopLogs = createBaseLog(formattedSendTime, logVo, ruleTimeVO, groupChat.getChatId(), groupChat.getName(), null, isOfficial, null);
+                try {
+                    groupChat.getChatUserList().stream().filter(e -> e.getUserList() != null && !e.getUserList().isEmpty()).forEach(e -> {
+                        Map<String, GroupUserExternalVo> userMap = PubFun.listToMapByGroupObject(e.getUserList(), GroupUserExternalVo::getUserId);
+                        GroupUserExternalVo vo = userMap.get(groupChat.getOwner());
+                        if(vo != null && vo.getId() != null){
+                            addWatchLogIfNeeded(sopLogs, videoId, courseId, sendTime, qwUserId, companyUserId, companyId, vo.getId().toString(), logVo);
+                        }
+                    });
+                }catch (Exception e){
+                    log.error("群聊创建看课记录失败!", e);
+                }
                 handleLogBasedOnType(sopLogs, content, logVo, sendTime, courseId, videoId,
                         type, qwUserId, companyUserId, companyId, groupChat.getChatId(), welcomeText, qwUserName, null, true);
             } else {

+ 66 - 0
fs-service/src/main/java/com/fs/company/domain/CompanyTag.java

@@ -0,0 +1,66 @@
+package com.fs.company.domain;
+
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * company对象 company_tag
+ *
+ * @author fs
+ * @date 2025-04-02
+ */
+public class CompanyTag extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** $column.columnComment */
+    private Long tagId;
+
+    /** 企业id */
+    @Excel(name = "企业id")
+    private Long companyId;
+
+    /** 标签 */
+    @Excel(name = "标签")
+    private String tag;
+
+    public void setTagId(Long tagId)
+    {
+        this.tagId = tagId;
+    }
+
+    public Long getTagId()
+    {
+        return tagId;
+    }
+    public void setCompanyId(Long companyId)
+    {
+        this.companyId = companyId;
+    }
+
+    public Long getCompanyId()
+    {
+        return companyId;
+    }
+    public void setTag(String tag)
+    {
+        this.tag = tag;
+    }
+
+    public String getTag()
+    {
+        return tag;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+            .append("tagId", getTagId())
+            .append("companyId", getCompanyId())
+            .append("tag", getTag())
+            .append("createTime", getCreateTime())
+            .toString();
+    }
+}

+ 94 - 0
fs-service/src/main/java/com/fs/company/domain/CompanyTagUser.java

@@ -0,0 +1,94 @@
+package com.fs.company.domain;
+
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * company对象 company_tag_user
+ *
+ * @author fs
+ * @date 2025-04-02
+ */
+public class CompanyTagUser extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** $column.columnComment */
+    private Long id;
+
+    /** 标签id */
+    @Excel(name = "标签id")
+    private String tagIds;
+
+    /** 用户id */
+    @Excel(name = "用户id")
+    private Long userId;
+
+    /** 公司id */
+    @Excel(name = "公司id")
+    private Long companyId;
+
+    /** 员工id */
+    @Excel(name = "员工id")
+    private Long companyUserId;
+
+    public void setId(Long id)
+    {
+        this.id = id;
+    }
+
+    public Long getId()
+    {
+        return id;
+    }
+    public void setTagIds(String tagIds)
+    {
+        this.tagIds = tagIds;
+    }
+
+    public String getTagIds()
+    {
+        return tagIds;
+    }
+    public void setUserId(Long userId)
+    {
+        this.userId = userId;
+    }
+
+    public Long getUserId()
+    {
+        return userId;
+    }
+    public void setCompanyId(Long companyId)
+    {
+        this.companyId = companyId;
+    }
+
+    public Long getCompanyId()
+    {
+        return companyId;
+    }
+    public void setCompanyUserId(Long companyUserId)
+    {
+        this.companyUserId = companyUserId;
+    }
+
+    public Long getCompanyUserId()
+    {
+        return companyUserId;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+            .append("id", getId())
+            .append("tagIds", getTagIds())
+            .append("userId", getUserId())
+            .append("companyId", getCompanyId())
+            .append("companyUserId", getCompanyUserId())
+            .append("createTime", getCreateTime())
+            .toString();
+    }
+}

+ 83 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyTagMapper.java

@@ -0,0 +1,83 @@
+package com.fs.company.mapper;
+
+import com.fs.company.domain.CompanyTag;
+import org.apache.ibatis.annotations.MapKey;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * companyMapper接口
+ *
+ * @author fs
+ * @date 2025-04-02
+ */
+public interface CompanyTagMapper
+{
+    /**
+     * 查询company
+     *
+     * @param tagId companyID
+     * @return company
+     */
+    public CompanyTag selectCompanyTagById(Long tagId);
+
+    /**
+     * 查询company列表
+     *
+     * @param companyTag company
+     * @return company集合
+     */
+    public List<CompanyTag> selectCompanyTagList(CompanyTag companyTag);
+
+    /**
+     * 新增company
+     *
+     * @param companyTag company
+     * @return 结果
+     */
+    public int insertCompanyTag(CompanyTag companyTag);
+
+    /**
+     * 修改company
+     *
+     * @param companyTag company
+     * @return 结果
+     */
+    public int updateCompanyTag(CompanyTag companyTag);
+
+    /**
+     * 删除company
+     *
+     * @param tagId companyID
+     * @return 结果
+     */
+    public int deleteCompanyTagById(Long tagId);
+
+    /**
+     * 批量删除company
+     *
+     * @param tagIds 需要删除的数据ID
+     * @return 结果
+     */
+    public int deleteCompanyTagByIds(Long[] tagIds);
+
+    /**
+     * 查询标签列表
+     * @param params 条件
+     * @return list
+     */
+    List<CompanyTag> selectCompanyTagListByMap(@Param("params") Map<String, Object> params);
+
+    /**
+     * 查询用户标签列表
+     * @param userId    用户ID
+     * @return  list
+     */
+    List<CompanyTag> selectCompanyTagListByUserId(@Param("userId") Long userId);
+
+    String findUserTagByUserId(@Param("userId") Long userId);
+    @MapKey("tag_id")
+    Map<Long,String> queryAllTagMap();
+}

+ 82 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyTagUserMapper.java

@@ -0,0 +1,82 @@
+package com.fs.company.mapper;
+
+import com.fs.company.domain.CompanyTagUser;
+import com.fs.company.vo.CompanyTagUserVO;
+import com.fs.store.param.h5.TagListParam;
+import com.fs.store.vo.h5.CompanyUserTagListVO;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * companyMapper接口
+ *
+ * @author fs
+ * @date 2025-04-02
+ */
+public interface CompanyTagUserMapper
+{
+    /**
+     * 查询company
+     *
+     * @param id companyID
+     * @return company
+     */
+    public CompanyTagUser selectCompanyTagUserById(Long id);
+
+    /**
+     * 查询company列表
+     *
+     * @param companyTagUser company
+     * @return company集合
+     */
+    public List<CompanyTagUser> selectCompanyTagUserList(CompanyTagUser companyTagUser);
+
+    /**
+     * 新增company
+     *
+     * @param companyTagUser company
+     * @return 结果
+     */
+    public int insertCompanyTagUser(CompanyTagUser companyTagUser);
+
+    /**
+     * 修改company
+     *
+     * @param companyTagUser company
+     * @return 结果
+     */
+    public int updateCompanyTagUser(CompanyTagUser companyTagUser);
+
+    /**
+     * 删除company
+     *
+     * @param id companyID
+     * @return 结果
+     */
+    public int deleteCompanyTagUserById(Long id);
+
+    /**
+     * 批量删除company
+     *
+     * @param ids 需要删除的数据ID
+     * @return 结果
+     */
+    public int deleteCompanyTagUserByIds(Long[] ids);
+
+    List<CompanyUserTagListVO> getTagList(@Param("param") TagListParam param, @Param("keywords") String[] keywords, @Param("userIds") List<Long> userIds);
+
+    /**
+     * 根据条件查询标签下用户
+     * @param params    条件
+     * @return  list
+     */
+    List<CompanyTagUserVO> selectUserListByMap(@Param("params") Map<String, Object> params);
+
+    /**
+     * 删除用户标签
+     * @param params    条件
+     */
+    void deleteCompanyTagUserByMap(@Param("params") Map<String, Object> params);
+}

+ 2 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyUserMapper.java

@@ -231,4 +231,6 @@ public interface CompanyUserMapper
 
     @Select("select domain from company_user where user_id = #{userId}")
     String selectDomainByUserId(Long userId);
+
+    List<CompanyUser> selectAllCompanyUserAndSelf(@Param("userId") Long userId);
 }

+ 80 - 0
fs-service/src/main/java/com/fs/company/service/ICompanyTagService.java

@@ -0,0 +1,80 @@
+package com.fs.company.service;
+
+import com.fs.company.domain.CompanyTag;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * companyService接口
+ *
+ * @author fs
+ * @date 2025-04-02
+ */
+public interface ICompanyTagService
+{
+    /**
+     * 查询company
+     *
+     * @param tagId companyID
+     * @return company
+     */
+    public CompanyTag selectCompanyTagById(Long tagId);
+
+    /**
+     * 查询company列表
+     *
+     * @param companyTag company
+     * @return company集合
+     */
+    public List<CompanyTag> selectCompanyTagList(CompanyTag companyTag);
+
+    /**
+     * 新增company
+     *
+     * @param companyTag company
+     * @return 结果
+     */
+    public int insertCompanyTag(CompanyTag companyTag);
+
+    /**
+     * 修改company
+     *
+     * @param companyTag company
+     * @return 结果
+     */
+    public int updateCompanyTag(CompanyTag companyTag);
+
+    /**
+     * 批量删除company
+     *
+     * @param tagIds 需要删除的companyID
+     * @return 结果
+     */
+    public int deleteCompanyTagByIds(Long[] tagIds);
+
+    /**
+     * 删除company信息
+     *
+     * @param tagId companyID
+     * @return 结果
+     */
+    public int deleteCompanyTagById(Long tagId);
+
+    /**
+     * 删除标签
+     * @param tagIds 标签ID
+     */
+    void deleteCompanyTagByTagIds(List<Long> tagIds);
+
+    /**
+     * 查询标签列表
+     * @param params 条件
+     * @return list
+     */
+    List<CompanyTag> selectCompanyTagListByMap(Map<String, Object> params);
+
+    Map<Long,String> queryAllTagMap();
+
+    String findUserTagByUserId(Long key);
+}

+ 87 - 0
fs-service/src/main/java/com/fs/company/service/ICompanyTagUserService.java

@@ -0,0 +1,87 @@
+package com.fs.company.service;
+
+import com.fs.company.domain.CompanyTagUser;
+import com.fs.company.vo.CompanyTagUserVO;
+import com.fs.store.param.h5.TagListParam;
+import com.fs.store.vo.h5.CompanyUserTagListVO;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * companyService接口
+ *
+ * @author fs
+ * @date 2025-04-02
+ */
+public interface ICompanyTagUserService
+{
+    /**
+     * 查询company
+     *
+     * @param id companyID
+     * @return company
+     */
+    public CompanyTagUser selectCompanyTagUserById(Long id);
+
+    /**
+     * 查询company列表
+     *
+     * @param companyTagUser company
+     * @return company集合
+     */
+    public List<CompanyTagUser> selectCompanyTagUserList(CompanyTagUser companyTagUser);
+
+    /**
+     * 新增company
+     *
+     * @param companyTagUser company
+     * @return 结果
+     */
+    public int insertCompanyTagUser(CompanyTagUser companyTagUser);
+
+    /**
+     * 修改company
+     *
+     * @param companyTagUser company
+     * @return 结果
+     */
+    public int updateCompanyTagUser(CompanyTagUser companyTagUser);
+
+    /**
+     * 批量删除company
+     *
+     * @param ids 需要删除的companyID
+     * @return 结果
+     */
+    public int deleteCompanyTagUserByIds(Long[] ids);
+
+    /**
+     * 删除company信息
+     *
+     * @param id companyID
+     * @return 结果
+     */
+    public int deleteCompanyTagUserById(Long id);
+
+    /**
+     * 标签分页列表
+     * @param param 分页参数
+     * @return
+     */
+    List<CompanyUserTagListVO> getTagList(TagListParam param);
+
+    /**
+     * 根据条件查询标签下用户
+     * @param params    条件
+     * @return  list
+     */
+    List<CompanyTagUserVO> selectUserListByMap(Map<String, Object> params);
+
+    /**
+     * 修改用户标签
+     * @param fsUserIds 用户ID集合
+     * @param tagIds   标签ID集合
+     */
+    void changeUserTags(List<Long> fsUserIds, List<Long> tagIds);
+}

+ 129 - 0
fs-service/src/main/java/com/fs/company/service/impl/CompanyTagServiceImpl.java

@@ -0,0 +1,129 @@
+package com.fs.company.service.impl;
+
+import com.fs.common.utils.DateUtils;
+import com.fs.company.domain.CompanyTag;
+import com.fs.company.mapper.CompanyTagMapper;
+import com.fs.company.service.ICompanyTagService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * companyService业务层处理
+ *
+ * @author fs
+ * @date 2025-04-02
+ */
+@Service
+public class CompanyTagServiceImpl implements ICompanyTagService
+{
+    @Autowired
+    private CompanyTagMapper companyTagMapper;
+
+    /**
+     * 查询company
+     *
+     * @param tagId companyID
+     * @return company
+     */
+    @Override
+    public CompanyTag selectCompanyTagById(Long tagId)
+    {
+        return companyTagMapper.selectCompanyTagById(tagId);
+    }
+
+    /**
+     * 查询company列表
+     *
+     * @param companyTag company
+     * @return company
+     */
+    @Override
+    public List<CompanyTag> selectCompanyTagList(CompanyTag companyTag)
+    {
+        return companyTagMapper.selectCompanyTagList(companyTag);
+    }
+
+    /**
+     * 新增company
+     *
+     * @param companyTag company
+     * @return 结果
+     */
+    @Override
+    public int insertCompanyTag(CompanyTag companyTag)
+    {
+        companyTag.setCreateTime(DateUtils.getNowDate());
+        return companyTagMapper.insertCompanyTag(companyTag);
+    }
+
+    /**
+     * 修改company
+     *
+     * @param companyTag company
+     * @return 结果
+     */
+    @Override
+    public int updateCompanyTag(CompanyTag companyTag)
+    {
+        return companyTagMapper.updateCompanyTag(companyTag);
+    }
+
+    /**
+     * 批量删除company
+     *
+     * @param tagIds 需要删除的companyID
+     * @return 结果
+     */
+    @Override
+    public int deleteCompanyTagByIds(Long[] tagIds)
+    {
+        return companyTagMapper.deleteCompanyTagByIds(tagIds);
+    }
+
+    /**
+     * 删除company信息
+     *
+     * @param tagId companyID
+     * @return 结果
+     */
+    @Override
+    public int deleteCompanyTagById(Long tagId)
+    {
+        return companyTagMapper.deleteCompanyTagById(tagId);
+    }
+
+    /**
+     * 删除标签
+     * @param tagIds 标签ID
+     */
+    @Override
+    public void deleteCompanyTagByTagIds(List<Long> tagIds) {
+        if (tagIds.isEmpty()) {
+            return;
+        }
+        companyTagMapper.deleteCompanyTagByIds(tagIds.toArray(new Long[0]));
+    }
+
+    /**
+     * 查询标签列表
+     * @param params 条件
+     * @return list
+     */
+    @Override
+    public List<CompanyTag> selectCompanyTagListByMap(Map<String, Object> params) {
+        return companyTagMapper.selectCompanyTagListByMap(params);
+    }
+
+    @Override
+    public Map<Long, String> queryAllTagMap() {
+        return companyTagMapper.queryAllTagMap();
+    }
+
+    @Override
+    public String findUserTagByUserId(Long key) {
+        return companyTagMapper.findUserTagByUserId(key);
+    }
+}

+ 173 - 0
fs-service/src/main/java/com/fs/company/service/impl/CompanyTagUserServiceImpl.java

@@ -0,0 +1,173 @@
+package com.fs.company.service.impl;
+
+import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.company.domain.CompanyTagUser;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.mapper.CompanyTagUserMapper;
+import com.fs.company.mapper.CompanyUserMapper;
+import com.fs.company.service.ICompanyTagUserService;
+import com.fs.company.vo.CompanyTagUserVO;
+import com.fs.his.domain.FsUser;
+import com.fs.his.mapper.FsUserMapper;
+import com.fs.store.param.h5.TagListParam;
+import com.fs.store.vo.h5.CompanyUserTagListVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * companyService业务层处理
+ *
+ * @author fs
+ * @date 2025-04-02
+ */
+@Service
+public class CompanyTagUserServiceImpl implements ICompanyTagUserService
+{
+    @Autowired
+    private CompanyTagUserMapper companyTagUserMapper;
+
+    @Autowired
+    private CompanyUserMapper  companyUserMapper;
+    @Autowired
+    private FsUserMapper fsUserMapper;
+
+    /**
+     * 查询company
+     *
+     * @param id companyID
+     * @return company
+     */
+    @Override
+    public CompanyTagUser selectCompanyTagUserById(Long id)
+    {
+        return companyTagUserMapper.selectCompanyTagUserById(id);
+    }
+
+    /**
+     * 查询company列表
+     *
+     * @param companyTagUser company
+     * @return company
+     */
+    @Override
+    public List<CompanyTagUser> selectCompanyTagUserList(CompanyTagUser companyTagUser)
+    {
+        return companyTagUserMapper.selectCompanyTagUserList(companyTagUser);
+    }
+
+    /**
+     * 新增company
+     *
+     * @param companyTagUser company
+     * @return 结果
+     */
+    @Override
+    public int insertCompanyTagUser(CompanyTagUser companyTagUser)
+    {
+        companyTagUser.setCreateTime(DateUtils.getNowDate());
+        return companyTagUserMapper.insertCompanyTagUser(companyTagUser);
+    }
+
+    /**
+     * 修改company
+     *
+     * @param companyTagUser company
+     * @return 结果
+     */
+    @Override
+    public int updateCompanyTagUser(CompanyTagUser companyTagUser)
+    {
+        return companyTagUserMapper.updateCompanyTagUser(companyTagUser);
+    }
+
+    /**
+     * 批量删除company
+     *
+     * @param ids 需要删除的companyID
+     * @return 结果
+     */
+    @Override
+    public int deleteCompanyTagUserByIds(Long[] ids)
+    {
+        return companyTagUserMapper.deleteCompanyTagUserByIds(ids);
+    }
+
+    /**
+     * 删除company信息
+     *
+     * @param id companyID
+     * @return 结果
+     */
+    @Override
+    public int deleteCompanyTagUserById(Long id)
+    {
+        return companyTagUserMapper.deleteCompanyTagUserById(id);
+    }
+
+    @Override
+    public List<CompanyUserTagListVO> getTagList(TagListParam param) {
+        String[] keywords = new String[0];
+        if (param != null) {
+            if (StringUtils.isNotEmpty(param.getKeyword())) {
+                keywords = param.getKeyword().split(",");
+            }
+        }
+        //获取所有销售
+        List<CompanyUser> companyUsers = companyUserMapper.selectAllCompanyUserAndSelf(param != null ? param.getUserId() : null);
+        List<Long> userIds = Collections.emptyList();
+        if(companyUsers != null && !companyUsers.isEmpty()){
+            userIds = companyUsers.stream().map(CompanyUser::getUserId).collect(Collectors.toList());
+        }
+
+        return companyTagUserMapper.getTagList(param, keywords, userIds);
+    }
+
+    /**
+     * 根据条件查询标签下用户
+     * @param params    条件
+     * @return  list
+     */
+    @Override
+    public List<CompanyTagUserVO> selectUserListByMap(Map<String, Object> params) {
+        return companyTagUserMapper.selectUserListByMap(params);
+    }
+
+    /**
+     * 修改用户标签
+     * @param fsUserIds 用户ID
+     * @param tagIds   标签ID集合
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void changeUserTags(List<Long> fsUserIds, List<Long> tagIds) {
+        fsUserIds.forEach(fsUserId -> {
+            FsUser fsUser = fsUserMapper.selectFsUserById(fsUserId);
+            if (Objects.isNull(fsUser)) {
+                return;
+            }
+
+            // 删除原标签
+            Map<String, Object> params = new HashMap<>();
+            params.put("userId", fsUserId);
+            params.put("companyId", fsUser.getCompanyId());
+            params.put("companyUserId", fsUser.getCompanyUserId());
+            companyTagUserMapper.deleteCompanyTagUserByMap(params);
+
+            // 不为空则添加新标签
+            if (Objects.nonNull(tagIds) && !tagIds.isEmpty()) {
+                CompanyTagUser companyTagUser = new CompanyTagUser();
+                companyTagUser.setUserId(fsUserId);
+                companyTagUser.setCompanyId(fsUser.getCompanyId());
+                companyTagUser.setCompanyUserId(fsUser.getCompanyUserId());
+                companyTagUser.setTagIds(tagIds.stream().map(String::valueOf).collect(Collectors.joining(",")));
+                companyTagUser.setCreateTime(new Date());
+                companyTagUserMapper.insertCompanyTagUser(companyTagUser);
+            }
+        });
+    }
+}

+ 15 - 0
fs-service/src/main/java/com/fs/company/vo/CompanyTagUserVO.java

@@ -0,0 +1,15 @@
+package com.fs.company.vo;
+
+import lombok.Data;
+
+@Data
+public class CompanyTagUserVO {
+    /**
+     * 用户ID
+     */
+    private Long userId;
+    /**
+     * 用户昵称
+     */
+    private String userName;
+}

+ 3 - 0
fs-service/src/main/java/com/fs/course/domain/FsCourseRedPacketLog.java

@@ -54,4 +54,7 @@ public class FsCourseRedPacketLog extends BaseEntity
 
     private Long watchLogId;//观看记录 id
 
+    /** 营期id */
+    private Long periodId;
+
 }

+ 3 - 0
fs-service/src/main/java/com/fs/course/domain/FsCourseWatchLog.java

@@ -85,5 +85,8 @@ public class FsCourseWatchLog extends BaseEntity
     private Long project;
     private Long day;
 
+    /** 营期id */
+    private Long periodId;
+
 
 }

+ 44 - 0
fs-service/src/main/java/com/fs/course/domain/FsUserCompanyUser.java

@@ -0,0 +1,44 @@
+package com.fs.course.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 微信用户和销售关系对象 fs_user_company_user
+ *
+ * @author fs
+ * @date 2025-05-09
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsUserCompanyUser extends BaseEntity{
+
+    /** id */
+    private Long id;
+
+    /** 用户id(关联fs_user表user_id) */
+    @Excel(name = "用户id", readConverterExp = "关=联fs_user表user_id")
+    private Long userId;
+
+    /** 销售id */
+    @Excel(name = "销售id")
+    private Long companyUserId;
+
+    /** 公司ID */
+    @Excel(name = "公司ID")
+    private Long companyId;
+
+    /** 是否重粉,1-是;0-否 */
+    @Excel(name = "是否重粉,1-是;0-否")
+    private Integer isRepeatFans;
+
+    @TableField(exist = false)
+    @ApiModelProperty(value = "重粉所属销售,多个用逗号隔开")
+    private String repeatCompanyUserName;
+
+
+}

+ 9 - 7
fs-service/src/main/java/com/fs/course/domain/FsUserCoursePeriodDays.java

@@ -1,20 +1,22 @@
 package com.fs.course.domain;
 
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.Date;
+import java.util.List;
+
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
 import com.fasterxml.jackson.annotation.JsonFormat;
+import com.baomidou.mybatisplus.annotation.TableId;
 import com.fs.common.annotation.Excel;
 import com.fs.common.core.domain.BaseEntityTow;
 import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
 import lombok.EqualsAndHashCode;
 
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.util.List;
-
 /**
  * 营期课程对象 fs_user_course_period_days
  *

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

@@ -5,6 +5,7 @@ import com.fs.common.annotation.Excel;
 import com.fs.common.core.domain.BaseEntity;
 import lombok.Data;
 
+import java.math.BigDecimal;
 import java.time.LocalTime;
 
 /**
@@ -76,7 +77,7 @@ public class FsUserCourseVideo extends BaseEntity
     private String lineThree; //线路三 华为云obs
     private Integer uploadType;
 
-    private String redPacketMoney;
+    private BigDecimal redPacketMoney;
     private Long fileSize;//文件大小  字节
     private String fileKey;//文件key 对用存储桶
     private String round;//轮次

+ 8 - 0
fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java

@@ -10,6 +10,7 @@ import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 import org.apache.ibatis.annotations.Update;
 
+import javax.validation.constraints.NotNull;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -262,4 +263,11 @@ public interface FsCourseWatchLogMapper extends BaseMapper<FsCourseWatchLog> {
 
     @Select("SELECT qw_external_contact_id FROM fs_course_watch_log  WHERE log_type=2 and DATE(create_time) = CURDATE() ")
     List<Long> selectFsCourseWatchLogByFinish();
+    @Select("select * from fs_course_watch_log " +
+            "where video_id = #{videoId} " +
+            "and company_user_id = #{companyUserId} " +
+            "and user_id = #{userId} and send_type = 1 ")
+    FsCourseWatchLog getWatchCourseVideoByFsUser(@Param("userId") Long userId, @Param("videoId") Long videoId, @Param("companyUserId") Long companyUserId);
+
+    FsCourseWatchLog getWatchLogByFsUser(@Param("videoId") Long videoId, @Param("fsUserId") Long fsUserId, @Param("companyUserId") Long companyUserId);
 }

+ 79 - 0
fs-service/src/main/java/com/fs/course/mapper/FsUserCompanyUserMapper.java

@@ -0,0 +1,79 @@
+package com.fs.course.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.course.domain.FsUserCompanyUser;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+/**
+ * 微信用户和销售关系Mapper接口
+ *
+ * @author fs
+ * @date 2025-05-09
+ */
+public interface FsUserCompanyUserMapper extends BaseMapper<FsUserCompanyUser>{
+    /**
+     * 查询微信用户和销售关系
+     *
+     * @param id 微信用户和销售关系主键
+     * @return 微信用户和销售关系
+     */
+    FsUserCompanyUser selectFsUserCompanyUserById(Long id);
+
+    /**
+     * 查询微信用户和销售关系列表
+     *
+     * @param fsUserCompanyUser 微信用户和销售关系
+     * @return 微信用户和销售关系集合
+     */
+    List<FsUserCompanyUser> selectFsUserCompanyUserList(FsUserCompanyUser fsUserCompanyUser);
+
+    /**
+     * 新增微信用户和销售关系
+     *
+     * @param fsUserCompanyUser 微信用户和销售关系
+     * @return 结果
+     */
+    int insertFsUserCompanyUser(FsUserCompanyUser fsUserCompanyUser);
+
+    /**
+     * 修改微信用户和销售关系
+     *
+     * @param fsUserCompanyUser 微信用户和销售关系
+     * @return 结果
+     */
+    int updateFsUserCompanyUser(FsUserCompanyUser fsUserCompanyUser);
+
+    /**
+     * 删除微信用户和销售关系
+     *
+     * @param id 微信用户和销售关系主键
+     * @return 结果
+     */
+    int deleteFsUserCompanyUserById(Long id);
+
+    /**
+     * 批量删除微信用户和销售关系
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsUserCompanyUserByIds(Long[] ids);
+
+    /**
+     * 获取当前销售的所有重粉会员
+     * @param companyUserId
+     * @return
+     */
+    @Select("select user_id from fs_user_company_user where company_user_id = #{userId} and is_repeat_fans = 1 ")
+    List<FsUserCompanyUser> selectRepeatUser(Long companyUserId);
+
+    /**
+     * 获取会员的重粉的所属销售
+     * @param userIds 用户会员ids
+     * @return
+     */
+    List<FsUserCompanyUser> selectRepeatCompanyUserName(@Param("userIds") List<Long> userIds);
+}

+ 18 - 32
fs-service/src/main/java/com/fs/course/mapper/FsUserCourseVideoMapper.java

@@ -1,13 +1,10 @@
 package com.fs.course.mapper;
 
-import java.util.List;
 import com.fs.course.domain.FsUserCourseVideo;
-import com.fs.course.domain.FsUserVideo;
-import com.fs.course.param.FsUserCourseListUParam;
+import com.fs.course.param.CourseVideoUpdates;
 import com.fs.course.param.FsUserCourseVideoListUParam;
 import com.fs.course.param.FsUserCourseVideoParam;
 import com.fs.course.param.newfs.UserCourseVideoPageParam;
-import com.fs.course.vo.FsUserCourseCommentListUVO;
 import com.fs.course.vo.FsUserCourseVideoListUVO;
 import com.fs.course.vo.FsUserCourseVideoVO;
 import com.fs.course.vo.newfs.FsUserCourseVideoPageListVO;
@@ -15,6 +12,10 @@ import com.fs.his.vo.OptionsVO;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Map;
+
 /**
  * 课堂视频Mapper接口
  *
@@ -162,36 +163,21 @@ public interface FsUserCourseVideoMapper
             "where c.is_private = 1 and v.is_del = 0 and v.is_transcode = 1 and transcode_file_key is null ")
     List<FsUserCourseVideo> selectVideoIsTranscode();
 
+    @Select("select video_id from fs_user_course_video WHERE is_first=1")
+    List<Long> selectVideoByFirst();
 
-    @Select({"<script> " +
-            "SELECT\n" +
-            "        video.video_id,\n" +
-            "        video.title,\n" +
-            "        video.description,\n" +
-            "        video.video_url,\n" +
-            "        video.thumbnail,\n" +
-            "        video.duration,\n" +
-            "        video.create_time,\n" +
-            "        video.course_id,\n" +
-            "        video.STATUS,\n" +
-            "        video.course_sort,\n" +
-            "        course.course_name\n" +
-            "        FROM `fs_user_course_video` video\n" +
-            "        LEFT JOIN fs_user_course course ON video.course_id = course.course_id\n" +
-            "        where 1 = 1\n" +
-            "        and course.is_del = 0\n" +
-            "        AND FIND_IN_SET(#{companyId}, course.company_ids)\n" +
-            "        <if test=\"courseId != null \">\n" +
-            "            AND video.course_id = #{courseId}\n" +
-            "        </if>\n" +
-            "        <if test=\"keyword != null and keyword !='' \">\n" +
-            "            AND video.title LIKE concat('%',#{keyword},'%')\n" +
-            "        </if>\n" +
-            "        order by video.course_sort"+
-            "</script>"})
     List<FsUserCourseVideoPageListVO> selectFsUserCourseVideoPageList(UserCourseVideoPageParam param);
 
+    void updates(CourseVideoUpdates vo);
 
-    @Select("SELECT * FROM `fs_his`.`fs_user_course_video` WHERE `line_two` LIKE '%https://myhktcpv.ylrztop.com%' LIMIT 0,1000")
-    List<FsUserCourseVideo> selectVideoupdateUrl();
+    void insertBatchFsUserCourseVideo(@Param("collect") List<FsUserCourseVideo> collect);
+
+    void updateRedPacketMoney(@Param("videoId") Long videoId, @Param("redPacketMoney") BigDecimal redPacketMoney);
+
+    /**
+     * 获取选项列表
+     * @param params    参数
+     * @return  list
+     */
+    List<OptionsVO> selectVideoListByMap(@Param("params") Map<String, Object> params);
 }

+ 2 - 2
fs-service/src/main/java/com/fs/course/mapper/FsUserCourseVideoRedPackageMapper.java

@@ -69,8 +69,8 @@ public interface FsUserCourseVideoRedPackageMapper
             "ON DUPLICATE KEY UPDATE red_packet_money = VALUES(red_packet_money);")
     void insertOrUpdateFsUserCourseVideoRedPackage(FsUserCourseVideoParam fsUserCourseVideo);
 
-    @Select("select * from fs_user_course_video_red_package where video_id =#{videoId} and company_id = #{companyId}")
-    FsUserCourseVideoRedPackage selectRedPacketByCompanyId(@Param("videoId") Long videoId,@Param("companyId") Long companyId);
+    @Select("select * from fs_user_course_video_red_package where video_id =#{videoId} and company_id = #{companyId} and period_id = #{periodId}")
+    FsUserCourseVideoRedPackage selectRedPacketByCompanyId(@Param("videoId") Long videoId,@Param("companyId") Long companyId, @Param("periodId") Long periodId);
     /**
      * 批量查询匹配的红包数据
      *

+ 11 - 0
fs-service/src/main/java/com/fs/course/param/BatchRedUpdate.java

@@ -0,0 +1,11 @@
+package com.fs.course.param;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+public class BatchRedUpdate {
+    private Long videoId;
+    private BigDecimal redPacketMoney;
+}

+ 11 - 0
fs-service/src/main/java/com/fs/course/param/BatchVideoSvae.java

@@ -0,0 +1,11 @@
+package com.fs.course.param;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class BatchVideoSvae {
+    private Long courseId;
+    private List<Long> ids;
+}

+ 23 - 0
fs-service/src/main/java/com/fs/course/param/CourseVideoUpdates.java

@@ -0,0 +1,23 @@
+package com.fs.course.param;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.time.LocalTime;
+import java.util.List;
+
+@Data
+public class CourseVideoUpdates {
+
+    private List<Long> ids;
+
+    @JsonFormat(pattern = "HH:mm:ss")
+    private LocalTime viewStartTime;//转码的文件key
+
+    @JsonFormat(pattern = "HH:mm:ss")
+    private LocalTime viewEndTime;//转码的文件key
+
+    @JsonFormat(pattern = "HH:mm:ss")
+    private LocalTime lastJoinTime;//转码的文件key
+
+}

+ 2 - 3
fs-service/src/main/java/com/fs/course/param/FsCourseSendRewardUParam.java

@@ -1,10 +1,8 @@
 package com.fs.course.param;
 
-import com.fs.course.domain.FsCourseQuestionBank;
 import lombok.Data;
 
 import java.io.Serializable;
-import java.util.List;
 
 /**
  * 购买会员订单对象 fs_user_vip_order
@@ -22,10 +20,11 @@ public class FsCourseSendRewardUParam implements Serializable
     private Long companyId;
     private Long courseId;
     private String corpId;
-    private Integer rewardType; //奖励类型
     private Integer linkType;
     private Long qwExternalId;
     private Integer source=1;//来源 1:h5  2:小程序
     private Integer isRoom;
+    private Integer sendType;
+    private Long periodId;
 
 }

+ 41 - 0
fs-service/src/main/java/com/fs/course/param/newfs/FsCourseSortLinkParam.java

@@ -0,0 +1,41 @@
+package com.fs.course.param.newfs;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+@ApiModel(description = "生成课程短链/海报入参")
+public class FsCourseSortLinkParam {
+
+    @ApiModelProperty(value = "视频id")
+    private Long videoId;
+
+    @ApiModelProperty(value = "公司id")
+    private Long companyId;
+
+    @ApiModelProperty(value = "销售id")
+    private Long companyUserId;
+
+    @ApiModelProperty(value = "课程id")
+    private Long courseId;
+
+    @ApiModelProperty(value = "链接有效时长(分钟)")
+    private Integer effectiveDuration;
+
+    @ApiModelProperty(value = "课程封面,生成海报时必传")
+    private String imgUrl;
+
+    @ApiModelProperty(value = "标题,生成海报时必传")
+    private String title;
+
+    @ApiModelProperty(value = "视频时长,生成海报时必传")
+    private String duration;
+
+    @ApiModelProperty(value = "营期id")
+    private Long periodId;
+
+    @ApiModelProperty(value = "营期课程id")
+    private Long id;
+
+}

+ 36 - 0
fs-service/src/main/java/com/fs/course/param/newfs/FsUserCourseAddCompanyUserParam.java

@@ -0,0 +1,36 @@
+package com.fs.course.param.newfs;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+@Data
+public class FsUserCourseAddCompanyUserParam implements Serializable {
+
+    @NotNull(message = "视频id不能为空")
+    @ApiModelProperty(value = "视频id")
+    private Long videoId;
+
+//    @NotNull(message = "用户id不能为空")
+    @ApiModelProperty(value = "授权的用户id,不用传")
+    private Long userId;
+
+    @NotNull(message = "销售id不能为空")
+    @ApiModelProperty(value = "销售id")
+    private Long companyUserId;
+
+    @ApiModelProperty(value = "公司id")
+    private Long companyId;
+
+    @ApiModelProperty(value = "课程id")
+    private Long courseId;
+
+//    @ApiModelProperty(value = "归属发送方式:1 个微  2 企微 ,不用传")
+//    private Integer sendType; //归属发送方式:1 个微  2 企微
+
+    @ApiModelProperty(value = "营期id")
+    private Long periodId;
+
+}

+ 33 - 0
fs-service/src/main/java/com/fs/course/param/newfs/FsUserCourseBeMemberImageParam.java

@@ -0,0 +1,33 @@
+package com.fs.course.param.newfs;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+@Data
+@ApiModel(value = "邀请成为会员海报入参")
+public class FsUserCourseBeMemberImageParam implements Serializable {
+
+    @ApiModelProperty(value = "授权的用户id")
+    private Long userId;
+
+    @NotNull(message = "销售id不能为空")
+    @ApiModelProperty(value = "销售id")
+    private Long companyUserId;
+
+    @NotNull(message = "公司id不能为空")
+    @ApiModelProperty(value = "公司id")
+    private Long companyId;
+
+    @ApiModelProperty(value = "标签ids,多个用逗号隔开")
+    private String tagIds;
+
+    @NotNull(message = "链接不能为空")
+    @ApiModelProperty(value = "跳转链接")
+    private String realLink;
+
+
+}

+ 28 - 0
fs-service/src/main/java/com/fs/course/param/newfs/FsUserCourseBeMemberParam.java

@@ -0,0 +1,28 @@
+package com.fs.course.param.newfs;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+@Data
+public class FsUserCourseBeMemberParam implements Serializable {
+
+    @NotNull(message = "用户id不能为空")
+    @ApiModelProperty(value = "授权的用户id")
+    private Long userId;
+
+    @NotNull(message = "销售id不能为空")
+    @ApiModelProperty(value = "销售id")
+    private Long companyUserId;
+
+    @NotNull(message = "公司id不能为空")
+    @ApiModelProperty(value = "公司id")
+    private Long companyId;
+
+    @ApiModelProperty(value = "标签ids,数组格式")
+    private String[] tagIds;
+
+
+}

+ 34 - 0
fs-service/src/main/java/com/fs/course/param/newfs/FsUserCourseVideoLinkParam.java

@@ -0,0 +1,34 @@
+package com.fs.course.param.newfs;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+@Data
+public class FsUserCourseVideoLinkParam implements Serializable {
+    @NotNull(message = "销售id不能为空")
+    @ApiModelProperty(value = "视频id")
+    private Long videoId;
+
+    @ApiModelProperty(value = "用户id")
+    private Long fsUserId;
+
+    @ApiModelProperty(value = "课程id")
+    private Long courseId;
+
+    @ApiModelProperty(value = "链接类型,0:正常链接;1:应急链接")
+    private Integer linkType;
+
+    @NotNull(message = "销售id不能为空")
+    @ApiModelProperty(value = "销售id")
+    private Long companyUserId;
+
+    @ApiModelProperty(value = "营期课程ID")
+    private Long id;
+
+//    @ApiModelProperty(value = "营期id")
+//    private Long periodId;
+
+}

+ 26 - 0
fs-service/src/main/java/com/fs/course/param/newfs/FsUserCourseVideoUParam.java

@@ -0,0 +1,26 @@
+package com.fs.course.param.newfs;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+@Data
+@ApiModel(value = "更新看课时长的入参")
+public class FsUserCourseVideoUParam implements Serializable {
+    @NotNull(message = "时长不能为空")
+    private Long duration;
+
+    @NotNull(message = "视频id不能为空")
+    private Long videoId;
+
+    @NotNull(message = "用户id不能为空")
+    private Long userId;
+
+    private Integer linkType;
+
+    @NotNull(message = "销售id不能为空")
+    private Long companyUserId;
+
+}

+ 5 - 2
fs-service/src/main/java/com/fs/course/param/newfs/UserCourseVideoPageParam.java

@@ -20,8 +20,11 @@ public class UserCourseVideoPageParam implements Serializable {
     @ApiModelProperty(value = "模糊搜索,通过视频名称来匹配")
     private String keyword;
 
-    @ApiModelProperty(value = "课程id")
-    private Long courseId;
+//    @ApiModelProperty(value = "课程id")
+//    private Long courseId;
+
+    @ApiModelProperty(value = "营期id")
+    private Long periodId;
 
     @ApiModelProperty(value = "公司id")
     private Long companyId;

+ 62 - 0
fs-service/src/main/java/com/fs/course/service/IFsUserCompanyUserService.java

@@ -0,0 +1,62 @@
+package com.fs.course.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.course.domain.FsUserCompanyUser;
+
+import java.util.List;
+
+/**
+ * 微信用户和销售关系Service接口
+ * 
+ * @author fs
+ * @date 2025-05-09
+ */
+public interface IFsUserCompanyUserService extends IService<FsUserCompanyUser>{
+    /**
+     * 查询微信用户和销售关系
+     * 
+     * @param id 微信用户和销售关系主键
+     * @return 微信用户和销售关系
+     */
+    FsUserCompanyUser selectFsUserCompanyUserById(Long id);
+
+    /**
+     * 查询微信用户和销售关系列表
+     * 
+     * @param fsUserCompanyUser 微信用户和销售关系
+     * @return 微信用户和销售关系集合
+     */
+    List<FsUserCompanyUser> selectFsUserCompanyUserList(FsUserCompanyUser fsUserCompanyUser);
+
+    /**
+     * 新增微信用户和销售关系
+     * 
+     * @param fsUserCompanyUser 微信用户和销售关系
+     * @return 结果
+     */
+    int insertFsUserCompanyUser(FsUserCompanyUser fsUserCompanyUser);
+
+    /**
+     * 修改微信用户和销售关系
+     * 
+     * @param fsUserCompanyUser 微信用户和销售关系
+     * @return 结果
+     */
+    int updateFsUserCompanyUser(FsUserCompanyUser fsUserCompanyUser);
+
+    /**
+     * 批量删除微信用户和销售关系
+     * 
+     * @param ids 需要删除的微信用户和销售关系主键集合
+     * @return 结果
+     */
+    int deleteFsUserCompanyUserByIds(Long[] ids);
+
+    /**
+     * 删除微信用户和销售关系信息
+     * 
+     * @param id 微信用户和销售关系主键
+     * @return 结果
+     */
+    int deleteFsUserCompanyUserById(Long id);
+}

+ 44 - 7
fs-service/src/main/java/com/fs/course/service/IFsUserCourseVideoService.java

@@ -1,20 +1,24 @@
 package com.fs.course.service;
 
-import java.util.List;
-
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.ResponseResult;
 import com.fs.course.domain.FsUserCourseVideo;
-import com.fs.course.domain.FsUserVideo;
 import com.fs.course.param.*;
+import com.fs.course.param.newfs.FsUserCourseAddCompanyUserParam;
+import com.fs.course.param.newfs.FsUserCourseVideoLinkParam;
+import com.fs.course.param.newfs.FsUserCourseVideoUParam;
 import com.fs.course.param.newfs.UserCourseVideoPageParam;
 import com.fs.course.vo.FsUserCourseVideoListUVO;
 import com.fs.course.vo.FsUserCourseVideoQVO;
 import com.fs.course.vo.FsUserCourseVideoVO;
 import com.fs.course.vo.newfs.FsUserCourseVideoDetailsVO;
+import com.fs.course.vo.newfs.FsUserCourseVideoLinkDetailsVO;
 import com.fs.course.vo.newfs.FsUserCourseVideoPageListVO;
 import com.fs.course.vo.newfs.FsUserVideoListVO;
-import com.fs.his.domain.FsUser;
+import com.fs.his.vo.OptionsVO;
+
+import java.util.List;
+import java.util.Map;
 
 /**
  * 课堂视频Service接口
@@ -95,7 +99,7 @@ public interface IFsUserCourseVideoService
 
     R sendReward(FsCourseSendRewardUParam param);
 
-    R sendRewardNew(FsCourseSendRewardUParam param);
+    R sendRewardByFsUser(FsCourseSendRewardUParam param);
 
     /**
      * 获取课程视频分页列表
@@ -109,7 +113,7 @@ public interface IFsUserCourseVideoService
      */
     ResponseResult<FsUserCourseVideoDetailsVO> getVideoDetails(Long videoId);
 
-    R registerCourse(FsUserCourseRegisterParam param, FsUser fsUser);
+    R registerCourse(FsUserCourseRegisterParam param);
 
     /**
      * 获取下拉视频列表(有分页,仅返回两个字段)
@@ -118,6 +122,39 @@ public interface IFsUserCourseVideoService
      */
     List<FsUserVideoListVO> getListCourseVideo(UserCourseVideoPageParam param);
 
-    void updateVideoUrl();
+    /**
+     * 判断是否添加销售
+     * @param param 入参
+     * @return 是/否 成功
+     */
+    ResponseResult<Boolean> isAddCompanyUser(FsUserCourseAddCompanyUserParam param);
+
+    /**
+     * 获取链接用户课程详情
+     * @param param 入参
+     */
+    ResponseResult<FsUserCourseVideoLinkDetailsVO> getLinkCourseVideoDetails(FsUserCourseVideoLinkParam param);
+
+
+    R addWatchLogByLink(FsUserCourseAddCompanyUserParam param);
+
+    /**
+     * 更新看课时长
+     * @param param 入参
+     * @return
+     */
+    R updateWatchDurationWx(FsUserCourseVideoUParam param);
 
+    void updates(CourseVideoUpdates vo);
+
+    void batchSaveVideo(BatchVideoSvae vo);
+
+    void batchUpdateRed(List<BatchRedUpdate> list);
+
+    /**
+     * 获取选项列表
+     * @param params    参数
+     * @return  list
+     */
+    List<OptionsVO> selectVideoListByMap(Map<String, Object> params);
 }

+ 91 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsUserCompanyUserServiceImpl.java

@@ -0,0 +1,91 @@
+package com.fs.course.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.course.domain.FsUserCompanyUser;
+import com.fs.course.mapper.FsUserCompanyUserMapper;
+import com.fs.course.service.IFsUserCompanyUserService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 微信用户和销售关系Service业务层处理
+ * 
+ * @author fs
+ * @date 2025-05-09
+ */
+@Service
+public class FsUserCompanyUserServiceImpl extends ServiceImpl<FsUserCompanyUserMapper, FsUserCompanyUser> implements IFsUserCompanyUserService {
+
+    /**
+     * 查询微信用户和销售关系
+     * 
+     * @param id 微信用户和销售关系主键
+     * @return 微信用户和销售关系
+     */
+    @Override
+    public FsUserCompanyUser selectFsUserCompanyUserById(Long id)
+    {
+        return baseMapper.selectFsUserCompanyUserById(id);
+    }
+
+    /**
+     * 查询微信用户和销售关系列表
+     * 
+     * @param fsUserCompanyUser 微信用户和销售关系
+     * @return 微信用户和销售关系
+     */
+    @Override
+    public List<FsUserCompanyUser> selectFsUserCompanyUserList(FsUserCompanyUser fsUserCompanyUser)
+    {
+        return baseMapper.selectFsUserCompanyUserList(fsUserCompanyUser);
+    }
+
+    /**
+     * 新增微信用户和销售关系
+     * 
+     * @param fsUserCompanyUser 微信用户和销售关系
+     * @return 结果
+     */
+    @Override
+    public int insertFsUserCompanyUser(FsUserCompanyUser fsUserCompanyUser)
+    {
+        return baseMapper.insertFsUserCompanyUser(fsUserCompanyUser);
+    }
+
+    /**
+     * 修改微信用户和销售关系
+     * 
+     * @param fsUserCompanyUser 微信用户和销售关系
+     * @return 结果
+     */
+    @Override
+    public int updateFsUserCompanyUser(FsUserCompanyUser fsUserCompanyUser)
+    {
+        return baseMapper.updateFsUserCompanyUser(fsUserCompanyUser);
+    }
+
+    /**
+     * 批量删除微信用户和销售关系
+     * 
+     * @param ids 需要删除的微信用户和销售关系主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsUserCompanyUserByIds(Long[] ids)
+    {
+        return baseMapper.deleteFsUserCompanyUserByIds(ids);
+    }
+
+    /**
+     * 删除微信用户和销售关系信息
+     * 
+     * @param id 微信用户和销售关系主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsUserCompanyUserById(Long id)
+    {
+        return baseMapper.deleteFsUserCompanyUserById(id);
+    }
+}

+ 444 - 247
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -1,36 +1,30 @@
 package com.fs.course.service.impl;
 
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.time.LocalDateTime;
-import java.util.*;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-
 import cn.hutool.core.util.NumberUtil;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
-import com.fs.ad.enums.AdUploadType;
-import com.fs.ad.service.IAdHtmlClickLogService;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.fs.common.BeanCopyUtils;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.ResponseResult;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.date.DateUtil;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.*;
 import com.fs.course.dto.CoursePackageDTO;
 import com.fs.course.mapper.*;
 import com.fs.course.param.*;
-import com.fs.course.param.newfs.UserCourseVideoPageParam;
+import com.fs.course.param.newfs.*;
+import com.fs.course.service.IFsUserCourseVideoService;
+import com.fs.course.service.IFsVideoResourceService;
 import com.fs.course.vo.FsUserCourseVideoListUVO;
 import com.fs.course.vo.FsUserCourseVideoQVO;
 import com.fs.course.vo.FsUserCourseVideoVO;
-import com.fs.course.vo.newfs.FsUserCourseVideoDetailsVO;
-import com.fs.course.vo.newfs.FsUserCourseVideoPageListVO;
-import com.fs.course.vo.newfs.FsUserVideoListVO;
-import com.fs.course.vo.newfs.FsUserVideoQuestionVO;
+import com.fs.course.vo.newfs.*;
 import com.fs.his.domain.FsUser;
 import com.fs.his.domain.FsUserIntegralLogs;
 import com.fs.his.mapper.FsUserIntegralLogsMapper;
@@ -38,6 +32,7 @@ import com.fs.his.mapper.FsUserMapper;
 import com.fs.his.param.WxSendRedPacketParam;
 import com.fs.his.service.IFsStorePaymentService;
 import com.fs.his.service.IFsUserService;
+import com.fs.his.vo.OptionsVO;
 import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.mapper.QwExternalContactMapper;
@@ -49,21 +44,30 @@ import com.fs.sop.mapper.QwSopLogsMapper;
 import com.fs.sop.mapper.SopUserLogsInfoMapper;
 import com.fs.system.service.ISysConfigService;
 import com.github.binarywang.wxpay.bean.transfer.TransferBillsResult;
+import lombok.extern.slf4j.Slf4j;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
-import com.fs.course.service.IFsUserCourseVideoService;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.stream.Collectors;
+
 /**
  * 课堂视频Service业务层处理
  *
  * @author fs
  * @date 2024-05-17
  */
+@Slf4j
 @Service
 public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 {
@@ -91,8 +95,8 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     private FsCourseSopLogsMapper courseSopLogsMapper;
     @Autowired
     private QwApiService qwApiService;
-    @Autowired
-    private IAdHtmlClickLogService adHtmlClickLogService;
+    //    @Autowired
+//    private IAdHtmlClickLogService adHtmlClickLogService;
     @Autowired
     private QwUserMapper qwUserMapper;
     @Autowired
@@ -116,6 +120,29 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     private FsCourseLinkMapper courseLinkMapper;
     @Autowired
     RedisCache redisCache;
+    @Autowired
+    private ISysConfigService sysConfigService;
+
+    @Autowired
+    private CompanyUserMapper companyUserMapper;
+
+    @Autowired
+    private IFsVideoResourceService fsVideoResourceService;
+    @Autowired
+    private FsVideoResourceMapper fsVideoResourceMapper;
+
+    @Autowired
+    private FsUserCourseMapper fsUserCourseMapper;
+
+    @Autowired
+    private FsUserCoursePeriodMapper fsUserCoursePeriodMapper;
+
+    @Autowired
+    private FsUserCoursePeriodDaysMapper fsUserCoursePeriodDaysMapper;
+
+    @Autowired
+    private FsUserCompanyUserMapper fsUserCompanyUserMapper;
+
     /**
      * 查询课堂视频
      *
@@ -280,12 +307,14 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         if (param.getLinkType()!=null && param.getLinkType()==1){
             return R.ok();
         }
+
         if (param.getIsRoom()!=null&&param.getIsRoom()==1&&param.getQwExternalId()==null){
             return R.ok();
         }
 
         // 从Redis中获取观看时长
         String redisKey = "h5user:watch:duration:" + param.getQwUserId()+ ":" + param.getQwExternalId() + ":" + param.getVideoId();
+        log.info("看课redis-key:{}", redisKey);
         try {
             String durationStr = redisCache.getCacheObject(redisKey);
             Long duration = durationStr != null ? Long.parseLong(durationStr) : 0L;
@@ -323,9 +352,6 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         if (fsUser==null){
             return R.error(504,"未授权");
         }
-        if (fsUser.getStatus()==0){
-            return R.error("无权限!");
-        }
 
         String msg = "<div style=\"color: red;margin-bottom: 15px;font-weight: bold;\">本课程为会员独享<br>请长按二维码</div>\n" +
                 "\t\t\t\t\t<div style=\"color: #999;font-size: 14px;font-weight: bold;\">添加伴学助手免费领取会员权限</div>";
@@ -347,24 +373,22 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
     }
 
-    //群聊逻辑
     private R handleRoom(FsUserCourseVideoAddKfUParam param,FsUser user) {
-        if (user.getQwExtId()!=null){
-            param.setQwExternalId(user.getQwExtId());
-            //查询是否有添加客服
-            QwExternalContact externalContact = qwExternalContactMapper.selectQwExternalContactById(param.getQwExternalId());
-            if (externalContact==null){
-                return R.error("客户不存在!");
-            }
-            if (!externalContact.getQwUserId().equals(Long.parseLong(param.getQwUserId()))){
-                logger.error("zyp \n【无权观看参数】:{}",param);
-                return R.error("无权限观看,添加群主非本群主");
-            }
-            FsCourseWatchLog log = courseWatchLogMapper.getWatchCourseVideoByExt(param.getQwExternalId(), param.getVideoId(),param.getQwUserId());
-            if (log==null){
-                createWatchLog(param);
-            }
-            return R.ok().put("qwExternalId",user.getQwExtId());
+        if (user.getQwExtId()==null){
+            return R.error("未注册");
+        }
+        param.setQwExternalId(user.getQwExtId());
+        //查询是否有添加客服
+        QwExternalContact externalContact = qwExternalContactMapper.selectQwExternalContactById(param.getQwExternalId());
+        if (externalContact==null){
+            return R.error("客户不存在!");
+        }
+        if (!externalContact.getQwUserId().equals(param.getUserId())){
+            return R.error("无权限观看,添加群主非本群主");
+        }
+        FsCourseWatchLog log = courseWatchLogMapper.getWatchCourseVideoByExt(param.getQwExternalId(), param.getVideoId(),param.getQwUserId());
+        if (log==null){
+            createWatchLog(param);
         }
         return R.ok();
     }
@@ -457,6 +481,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             if (list!=null&& !list.isEmpty()){
                 sopUserLogsInfoMapper.updateSopUserLogsInfoFsUserIdById(list,param.getUserId());
             }
+
             //绑定上之后 更新观看记录
             //看课记录中userId为0绑定userId
             if (log.getUserId()==null||log.getUserId().equals(0L) || !log.getUserId().equals(param.getUserId())){
@@ -516,8 +541,10 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     public R getInternetTraffic(FsUserCourseVideoFinishUParam param) {
         try {
             FsCourseTrafficLog trafficLog = new FsCourseTrafficLog();
-            trafficLog.setQwExternalContactId(param.getQwExternalId() != null ? param.getQwExternalId() : 0L);
+            trafficLog.setQwExternalContactId(param.getQwExternalId());
+            trafficLog.setUserId(param.getUserId());
             trafficLog.setCreateTime(new Date());
+//            trafficLog.setTime(new Date());
             BeanUtils.copyProperties(param, trafficLog);
 
             FsUserCourseVideo video = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId(param.getVideoId());
@@ -535,6 +562,12 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             if (StringUtils.isNotEmpty(trafficLog.getUuId())) {
                 // 直接插入或更新
 //                logger.error("zyp \n【插入或更新流量】:{}",trafficLog);
+//                if(ObjectUtils.isNotNull(trafficLog.getCourseId())) {
+//                    FsUserCourse course = fsUserCourseCacheService.selectFsUserCourseByCourseId(trafficLog.getCourseId());
+//                    if(ObjectUtils.isNotNull(course)){
+//                        trafficLog.setProject(course.getProject());
+//                    }
+//                }
                 fsCourseTrafficLogMapper.insertOrUpdateTrafficLog(trafficLog);
             }
         } catch (Exception e) {
@@ -548,63 +581,63 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
     @Override
     public R getIntegralByH5Video(FsUserCourseVideoFinishUParam param) {
-        //临时短链不做处理
-        if (param.getLinkType()!=null&&param.getLinkType()==1){
-            return R.ok();
-        }
-        FsCourseWatchLog log = courseWatchLogMapper.getWatchCourseVideo(param.getUserId(),param.getVideoId(),param.getQwUserId(), param.getQwExternalId());
-        if (log==null){
-            return R.error("无记录");
-        }
-        if (log.getLogType()==2){
-            return R.error("已存在完课记录");
-        }
-        if (log.getLogType()==1){
-            FsUserCourseVideo video = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId(param.getVideoId());
-            if (video==null){
-                return R.error("课程视频不存在!");
-            }
-            FsUser user = fsUserMapper.selectFsUserByUserId(param.getUserId());
-            if (user!=null){
-                //判断该视频可增加积分的此时 (每十分钟增加积分)
-                Long count = video.getDuration()/600;
-                Long getIntegralCount = fsUserIntegralLogsMapper.selectH5VideoIntegralCount(param.getUserId(), param.getVideoId());
-                if (getIntegralCount.equals(count)){
-                    return R.error("该课堂或积分已达限制!");
-                }
-                String json = configService.selectConfigByKey("course.config");
-                CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-                //增加积分
-                FsUser userMap=new FsUser();
-                userMap.setUserId(user.getUserId());
-                userMap.setIntegral(user.getIntegral()+config.getVideoIntegral());
-                fsUserMapper.updateFsUser(userMap);
-                FsUserIntegralLogs integralLogs = new FsUserIntegralLogs();
-                integralLogs.setIntegral(config.getVideoIntegral().longValue());
-                integralLogs.setUserId(user.getUserId());
-                integralLogs.setBalance(userMap.getIntegral());
-                integralLogs.setLogType(16);
-                integralLogs.setBusinessId(log.getLogId().toString());
-                integralLogs.setCreateTime(new Date());
-                fsUserIntegralLogsMapper.insertFsUserIntegralLogs(integralLogs);
-
-                FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
-                redPacketLog.setCourseId(log.getCourseId());
-                redPacketLog.setOutBatchNo(integralLogs.getId().toString());
-                redPacketLog.setCompanyId(log.getCompanyId());
-                redPacketLog.setUserId(log.getUserId());
-                redPacketLog.setVideoId(log.getVideoId());
-                redPacketLog.setStatus(1);
-                redPacketLog.setQwUserId(log.getQwUserId() != null ? log.getQwUserId() : null );
-                redPacketLog.setCompanyUserId(log.getCompanyUserId());
-                redPacketLog.setCreateTime(new Date());
-                redPacketLog.setAmount(BigDecimal.valueOf(config.getVideoIntegral()).divide(BigDecimal.valueOf(1000)));
-                redPacketLog.setRemark("点播看课获得积分转");
-                redPacketLog.setWatchLogId(log.getLogId() !=null ? log.getLogId() : null);
-                redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
-                return R.ok();
-            }
-        }
+//        //临时短链不做处理
+//        if (param.getLinkType()!=null&&param.getLinkType()==1){
+//            return R.ok();
+//        }
+//        FsCourseWatchLog log = courseWatchLogMapper.getWatchCourseVideo(param.getUserId(),param.getVideoId(),param.getQwUserId(), param.getQwExternalId());
+//        if (log==null){
+//            return R.error("无记录");
+//        }
+//        if (log.getLogType()==2){
+//            return R.error("已存在完课记录");
+//        }
+//        if (log.getLogType()==1){
+//            FsUserCourseVideo video = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId(param.getVideoId());
+//            if (video==null){
+//                return R.error("课程视频不存在!");
+//            }
+//            FsUser user = fsUserMapper.selectFsUserByUserId(param.getUserId());
+//            if (user!=null){
+//                //判断该视频可增加积分的此时 (每十分钟增加积分)
+//                Long count = video.getDuration()/600;
+//                Long getIntegralCount = fsUserIntegralLogsMapper.selectH5VideoIntegralCount(param.getUserId(), param.getVideoId());
+//                if (getIntegralCount.equals(count)){
+//                    return R.error("该课堂或积分已达限制!");
+//                }
+//                String json = configService.selectConfigByKey("course.config");
+//                CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+//                //增加积分
+//                FsUser userMap=new FsUser();
+//                userMap.setUserId(user.getUserId());
+//                userMap.setIntegral(user.getIntegral()+config.getVideoIntegral());
+//                fsUserMapper.updateFsUser(userMap);
+//                FsUserIntegralLogs integralLogs = new FsUserIntegralLogs();
+//                integralLogs.setIntegral(config.getVideoIntegral().longValue());
+//                integralLogs.setUserId(user.getUserId());
+//                integralLogs.setBalance(userMap.getIntegral());
+//                integralLogs.setLogType(16);
+//                integralLogs.setBusinessId(log.getLogId().toString());
+//                integralLogs.setCreateTime(new Date());
+//                fsUserIntegralLogsMapper.insertFsUserIntegralLogs(integralLogs);
+//
+//                FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
+//                redPacketLog.setCourseId(log.getCourseId());
+//                redPacketLog.setOutBatchNo(integralLogs.getId().toString());
+//                redPacketLog.setCompanyId(log.getCompanyId());
+//                redPacketLog.setUserId(log.getUserId());
+//                redPacketLog.setVideoId(log.getVideoId());
+//                redPacketLog.setStatus(1);
+//                redPacketLog.setQwUserId(log.getQwUserId() != null ? log.getQwUserId() : null );
+//                redPacketLog.setCompanyUserId(log.getCompanyUserId());
+//                redPacketLog.setCreateTime(new Date());
+//                redPacketLog.setAmount(BigDecimal.valueOf(config.getVideoIntegral()).divide(BigDecimal.valueOf(1000)));
+//                redPacketLog.setRemark("点播看课获得积分转");
+//                redPacketLog.setWatchLogId(log.getLogId() !=null ? log.getLogId() : null);
+//                redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
+//                return R.ok();
+//            }
+//        }
         return R.error();
     }
 
@@ -649,7 +682,42 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
                 return sendRedPacketReward(param, user, log, video, config);
             // 积分奖励
             case 2:
-                return sendIntegralReward(param,user, log, config);
+                return sendIntegralReward(user, log, config);
+            default:
+                return R.error("参数错误!");
+        }
+    }
+
+    @Override
+    public R sendRewardByFsUser(FsCourseSendRewardUParam param) {
+        FsUser user = fsUserMapper.selectFsUserByUserId(param.getUserId());
+        if (user == null){
+            return R.error("未识别到用户信息");
+        }
+        FsCourseWatchLog log = courseWatchLogMapper.getWatchCourseVideoByFsUser(param.getUserId(), param.getVideoId(), param.getCompanyUserId());
+        if (log == null) {
+            return R.error("无记录");
+        }
+        if (log.getRewardType() != null) {
+            return R.error("奖励已发放");
+        }
+
+
+        // 获取视频信息
+        FsUserCourseVideo video = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId(param.getVideoId());
+
+        // 获取配置信息
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+
+        // 根据奖励类型发放不同奖励
+        switch (config.getRewardType()) {
+            // 红包奖励
+            case 1:
+                return sendRedPacketReward(param, user, log, video, config);
+            // 积分奖励
+            case 2:
+                return sendIntegralReward(user, log, config);
             default:
                 return R.error("参数错误!");
         }
@@ -666,14 +734,28 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
      * @return 处理结果
      */
     private R sendRedPacketReward(FsCourseSendRewardUParam param, FsUser user, FsCourseWatchLog log, FsUserCourseVideo video, CourseConfig config) {
+        // 判断是否属于领取红包时间(会员看课发放红包)
+        FsUserCoursePeriodDays periodDays = new FsUserCoursePeriodDays();
+        periodDays.setVideoId(param.getVideoId());
+        periodDays.setPeriodId(param.getPeriodId());
+        //正常情况是只能查询到一条,之前可能存在重复的脏数据,暂使用查询list的方式
+        List<FsUserCoursePeriodDays> fsUserCoursePeriodDays = fsUserCoursePeriodDaysMapper.selectFsUserCoursePeriodDaysList(periodDays);
+        if(fsUserCoursePeriodDays != null && !fsUserCoursePeriodDays.isEmpty()){
+            periodDays = fsUserCoursePeriodDays.get(0);
+        }
+
+        if(periodDays != null && periodDays.getLastJoinTime() !=null && LocalDateTime.now().isAfter(periodDays.getLastJoinTime())) {
+            return R.error(403,"已超过领取红包时间");
+        }
+
         // 确定红包金额
         BigDecimal amount = BigDecimal.ZERO;
-        FsUserCourseVideoRedPackage redPackage = fsUserCourseVideoRedPackageMapper.selectRedPacketByCompanyId(param.getVideoId(), param.getCompanyId());
+        FsUserCourseVideoRedPackage redPackage = fsUserCourseVideoRedPackageMapper.selectRedPacketByCompanyId(param.getVideoId(), param.getCompanyId(), param.getPeriodId());
 
         if (redPackage != null) {
             amount = redPackage.getRedPacketMoney();
         } else if (video != null) {
-            amount = new BigDecimal(video.getRedPacketMoney());
+            amount = video.getRedPacketMoney();
         }
 
         // 准备发送红包参数
@@ -681,7 +763,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         packetParam.setOpenId(user.getMpOpenId());
         // 来源是小程序切换openId
         if (param.getSource() == 2) {
-            packetParam.setOpenId(user.getCourseMaOpenId());
+            packetParam.setOpenId(user.getMaOpenId());
         }
         packetParam.setAmount(amount);
         packetParam.setSource(param.getSource());
@@ -702,6 +784,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             }
             // 添加红包记录
             redPacketLog.setCourseId(param.getCourseId());
+//            redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
             redPacketLog.setCompanyId(param.getCompanyId());
             redPacketLog.setUserId(param.getUserId());
             redPacketLog.setVideoId(param.getVideoId());
@@ -711,12 +794,14 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             redPacketLog.setCreateTime(new Date());
             redPacketLog.setAmount(amount);
             redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
+            redPacketLog.setPeriodId(param.getPeriodId());
             redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
 
-
+            // 更新观看记录的奖励类型
+//            if (param.getLinkType() == null || param.getLinkType() == 0) {
             log.setRewardType(config.getRewardType());
             courseWatchLogMapper.updateFsCourseWatchLog(log);
-
+//            }
             return sendRedPacket;
         } else {
             return R.error("奖励发送失败,请联系客服");
@@ -731,12 +816,14 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
      * @param config 配置信息
      * @return 处理结果
      */
-    private R sendIntegralReward(FsCourseSendRewardUParam param,FsUser user, FsCourseWatchLog log, CourseConfig config) {
+    private R sendIntegralReward(FsUser user, FsCourseWatchLog log, CourseConfig config) {
         // 更新用户积分
-        FsUser userMap=new FsUser();
+        FsUser userMap = new FsUser();
         userMap.setUserId(user.getUserId());
-        userMap.setIntegral(user.getIntegral()+config.getAnswerIntegral());
+        userMap.setIntegral(user.getIntegral() + config.getAnswerIntegral());
         fsUserMapper.updateFsUser(userMap);
+
+        // 记录积分日志
         FsUserIntegralLogs integralLogs = new FsUserIntegralLogs();
         integralLogs.setIntegral(config.getAnswerIntegral().longValue());
         integralLogs.setUserId(user.getUserId());
@@ -746,136 +833,14 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         integralLogs.setCreateTime(new Date());
         fsUserIntegralLogsMapper.insertFsUserIntegralLogs(integralLogs);
 
+        //更新看课记录的奖励类型
         log.setRewardType(config.getRewardType());
         courseWatchLogMapper.updateFsCourseWatchLog(log);
-        //转换红包
-        FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
-        redPacketLog.setCourseId(param.getCourseId());
-        redPacketLog.setOutBatchNo(integralLogs.getId().toString());
-        redPacketLog.setCompanyId(param.getCompanyId());
-        redPacketLog.setUserId(param.getUserId());
-        redPacketLog.setVideoId(param.getVideoId());
-        redPacketLog.setStatus(1);
-        redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null );
-        redPacketLog.setCompanyUserId(param.getCompanyUserId());
-        redPacketLog.setCreateTime(new Date());
-        redPacketLog.setAmount(BigDecimal.valueOf(config.getAnswerIntegral()).divide(BigDecimal.valueOf(1000)));
-        redPacketLog.setRemark("点播答题领取积分转");
-        redPacketLog.setWatchLogId(log.getLogId() !=null ? log.getLogId() : null);
-        redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
+        logger.info("发放奖励====================》看课记录,{}",log);
 
         return R.ok("奖励发放成功");
     }
 
-
-    @Override
-    @Transactional
-    public R sendRewardNew(FsCourseSendRewardUParam param) {
-        FsUser user = fsUserMapper.selectFsUserByUserId(param.getUserId());
-        if (StringUtils.isEmpty(user.getMpOpenId())){
-            return R.error("未识别到领取信息");
-        }
-        FsCourseWatchLog log = new FsCourseWatchLog();
-
-        //判断链接类型
-        if (param.getLinkType()!=null&&param.getLinkType()==1){
-            FsCourseRedPacketLog packetLog = redPacketLogMapper.selectFsCourseRedPacketLogByTemporary(param.getVideoId(),param.getUserId());
-            if (packetLog!=null){
-                return R.error("奖励已发放");
-            }
-        }else {
-            log = courseWatchLogMapper.getWatchCourseVideo(param.getUserId(),param.getVideoId(),param.getQwUserId(),param.getQwExternalId());
-            if (log==null){
-                return R.error("无记录");
-            }
-            if (log.getRewardType()!=null){
-                return R.error("奖励已发放");
-            }
-        }
-
-        FsUserCourseVideo video = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId(param.getVideoId());
-        //发放奖励
-        switch (param.getRewardType()){
-            //红包奖励
-            case 1:
-                BigDecimal amount = BigDecimal.ZERO;
-                FsUserCourseVideoRedPackage redPackage = fsUserCourseVideoRedPackageMapper.selectRedPacketByCompanyId(param.getVideoId(), param.getCompanyId());
-                WxSendRedPacketParam packetParam = new WxSendRedPacketParam();
-
-                if (redPackage!=null){
-                    amount = redPackage.getRedPacketMoney();
-                }else if (video!=null){
-                    amount = new BigDecimal(video.getRedPacketMoney());
-                }
-                packetParam.setOpenId(user.getMpOpenId());
-                packetParam.setAmount(amount);
-                R sendRedPacket = paymentService.sendRedPacketV3(packetParam);
-                if (sendRedPacket.get("code").equals(200)){
-                    TransferBillsResult transferBillsResult = (TransferBillsResult)sendRedPacket.get("data");
-                    //添加红包记录
-                    FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
-                    redPacketLog.setCourseId(param.getCourseId());
-                    redPacketLog.setOutBatchNo(transferBillsResult.getOutBillNo());
-                    redPacketLog.setCompanyId(param.getCompanyId());
-                    redPacketLog.setUserId(param.getUserId());
-                    redPacketLog.setVideoId(param.getVideoId());
-                    redPacketLog.setStatus(0);
-                    redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null );
-                    redPacketLog.setCompanyUserId(param.getCompanyUserId());
-                    redPacketLog.setCreateTime(new Date());
-                    redPacketLog.setAmount(amount);
-                    redPacketLog.setWatchLogId(log.getLogId() !=null ? log.getLogId() : null);
-                    redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
-                    if (param.getLinkType()==null || param.getLinkType()==0){
-                        log.setRewardType(param.getRewardType());
-                        courseWatchLogMapper.updateFsCourseWatchLog(log);
-                    }
-                    return R.ok("奖励发放成功").put("package",transferBillsResult.getPackageInfo());
-                }else {
-                    return R.error("奖励发送失败,请联系客服");
-                }
-                //积分奖励
-            case 2:
-                String json = configService.selectConfigByKey("course.config");
-                CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-                //增加积分
-                FsUser userMap=new FsUser();
-                userMap.setUserId(user.getUserId());
-                userMap.setIntegral(user.getIntegral()+config.getAnswerIntegral());
-                fsUserMapper.updateFsUser(userMap);
-                FsUserIntegralLogs integralLogs = new FsUserIntegralLogs();
-                integralLogs.setIntegral(config.getAnswerIntegral().longValue());
-                integralLogs.setUserId(user.getUserId());
-                integralLogs.setBalance(userMap.getIntegral());
-                integralLogs.setLogType(17);
-                integralLogs.setBusinessId(StringUtils.isNotEmpty(log.getLogId().toString()) ? log.getLogId().toString() : null);
-                integralLogs.setCreateTime(new Date());
-                fsUserIntegralLogsMapper.insertFsUserIntegralLogs(integralLogs);
-                if (param.getLinkType()==null || param.getLinkType()==0 ){
-                    log.setRewardType(param.getRewardType());
-                    courseWatchLogMapper.updateFsCourseWatchLog(log);
-                    //转换红包
-                    FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
-                    redPacketLog.setCourseId(param.getCourseId());
-                    redPacketLog.setOutBatchNo(integralLogs.getId().toString());
-                    redPacketLog.setCompanyId(param.getCompanyId());
-                    redPacketLog.setUserId(param.getUserId());
-                    redPacketLog.setVideoId(param.getVideoId());
-                    redPacketLog.setStatus(1);
-                    redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null );
-                    redPacketLog.setCompanyUserId(param.getCompanyUserId());
-                    redPacketLog.setCreateTime(new Date());
-                    redPacketLog.setAmount(BigDecimal.valueOf(config.getAnswerIntegral()).divide(BigDecimal.valueOf(1000)));
-                    redPacketLog.setRemark("点播答题领取积分转");
-                    redPacketLog.setWatchLogId(log.getLogId() !=null ? log.getLogId() : null);
-                    redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
-                }
-                return R.ok("奖励发放成功");
-            default:
-                return R.error("参数错误!");
-        }
-    }
-
     @Override
     public List<FsUserCourseVideoPageListVO> pageListCourseVideo(UserCourseVideoPageParam param) {
         return fsUserCourseVideoMapper.selectFsUserCourseVideoPageList(param);
@@ -908,7 +873,17 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     SopUserLogsInfoMapper sopUserLogsInfoMapper;
 
     @Override
-    public R registerCourse(FsUserCourseRegisterParam param,FsUser fsUser) {
+    public R registerCourse(FsUserCourseRegisterParam param) {
+
+
+        FsUser fsUser = fsUserMapper.selectFsUserById(param.getUserId());
+        if (fsUser==null){
+            return R.error("未登录成功");
+        }
+        logger.info(""+fsUser);
+        if (fsUser.getIsAddQw()==1){
+            return R.error("已经注册");
+        }
         QwExternalContact qwExternalContact = qwExternalContactMapper.selectQwExternalContactById(param.getQwExternalId());
         if (qwExternalContact==null){
             return R.error("注册信息错误");
@@ -940,27 +915,249 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     }
 
     @Override
-    public void updateVideoUrl() {
-        List<FsUserCourseVideo> videos = fsUserCourseVideoMapper.selectVideoupdateUrl();
-        for (FsUserCourseVideo video : videos) {
-            FsUserCourseVideo video1 = new FsUserCourseVideo();
-            video1.setVideoId(video.getVideoId());
-            String url = updateUrlPrefix(video.getLineTwo());
-            video1.setLineTwo(url);
-            fsUserCourseVideoMapper.updateFsUserCourseVideo(video1);
+    @Transactional
+    public ResponseResult<Boolean> isAddCompanyUser(FsUserCourseAddCompanyUserParam param) {
+        logger.info("=======================进入个微-判断是否添加客服===========================,入参:{}",param);
+        //查询用户
+        FsUser fsUser = fsUserMapper.selectFsUserById(param.getUserId());
+        if (fsUser == null){
+            return ResponseResult.fail(404,"当前用户信息不存在");
+        }
+
+        //判断该销售是否存在
+        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(param.getCompanyUserId());
+        if (companyUser == null){
+            return ResponseResult.fail(405,"当前销售不存在");
+        }
+
+        //判断:1、如果没有绑定销售,就提示;
+        //2、如果只绑定了当前销售,需要添加看课记录(正常流程);
+        //3、以上都不是,则标识重粉,需要加入关系表,并打上重粉标签
+        if(fsUser.getCompanyUserId() == null) {
+            return ResponseResult.fail(503, "暂时未绑定销售,请联系管理员");
+        }
+        if(companyUser.getUserId().equals(fsUser.getCompanyUserId())){
+            //查询看课记录
+            FsCourseWatchLog log = new FsCourseWatchLog();
+            log.setUserId(param.getUserId());
+            log.setCompanyUserId(param.getCompanyUserId());
+            log.setVideoId(param.getVideoId());
+            List<FsCourseWatchLog> fsCourseWatchLogs = courseWatchLogMapper.selectFsCourseWatchLogList(log);
+
+            // 获取课程所属项目id
+            FsUserCourse fsUserCourse = fsUserCourseMapper.selectFsUserCourseByCourseId(param.getCourseId());
+            Long courseProject = null;
+            if(fsUserCourse != null){
+                courseProject = fsUserCourse.getProject();
+            }
+            //如果存在,则更新
+            if (fsCourseWatchLogs != null && !fsCourseWatchLogs.isEmpty()){
+                FsCourseWatchLog updateLog = new FsCourseWatchLog();
+                updateLog.setPeriodId(param.getPeriodId());
+                updateLog.setProject(courseProject);
+                updateLog.setUpdateTime(new Date());
+                courseWatchLogMapper.updateFsCourseWatchLog(updateLog);
+            } else {
+                //如果是会员,则需要添加看课记录
+                FsCourseWatchLog fsCourseWatchLog = new FsCourseWatchLog();
+                BeanUtils.copyProperties(param, fsCourseWatchLog);
+                fsCourseWatchLog.setSendType(1);
+                fsCourseWatchLog.setDuration(0L);
+                fsCourseWatchLog.setCreateTime(new Date());
+                fsCourseWatchLog.setLogType(1);
+                fsCourseWatchLog.setProject(courseProject);
+                courseWatchLogMapper.insertFsCourseWatchLog(fsCourseWatchLog);
+            }
+        } else {
+            FsUserCompanyUser fsUserCompanyUser = new FsUserCompanyUser();
+            fsUserCompanyUser.setIsRepeatFans(1);
+            fsUserCompanyUser.setUserId(param.getUserId());
+            fsUserCompanyUser.setCompanyId(param.getCompanyId());
+            fsUserCompanyUser.setCompanyUserId(param.getCompanyUserId());
+            QueryWrapper<FsUserCompanyUser> queryWrapper = new QueryWrapper<FsUserCompanyUser>().eq("user_id", param.getUserId()).eq("company_user_id", param.getCompanyUserId());
+            Integer i = fsUserCompanyUserMapper.selectCount(queryWrapper);
+            if(i == 0) {
+                fsUserCompanyUserMapper.insertFsUserCompanyUser(fsUserCompanyUser);
+            }
+
+            // 打上重粉标签
+            FsUserCourseBeMemberParam fsUserCourseBeMemberParam = new FsUserCourseBeMemberParam();
+            fsUserCourseBeMemberParam.setUserId(param.getUserId());
+            fsUserCourseBeMemberParam.setCompanyId(param.getCompanyId());
+            fsUserCourseBeMemberParam.setCompanyUserId(param.getCompanyUserId());
+            fsUserService.setRepeatFansTag(fsUserCourseBeMemberParam);
+        }
+        return ResponseResult.ok(Boolean.TRUE);
+    }
+
+    @Override
+    public ResponseResult<FsUserCourseVideoLinkDetailsVO> getLinkCourseVideoDetails(FsUserCourseVideoLinkParam param) {
+//        FsUserCoursePeriodDays periodDays = new FsUserCoursePeriodDays();
+//        periodDays.setVideoId(param.getVideoId());
+//        periodDays.setPeriodId(param.getPeriodId());
+//        //正常情况是只能查询到一条,之前可能存在重复的脏数据,暂使用查询list的方式
+//        List<FsUserCoursePeriodDays> fsUserCoursePeriodDays = fsUserCoursePeriodDaysMapper.selectFsUserCoursePeriodDaysList(periodDays);
+//        if(fsUserCoursePeriodDays != null && !fsUserCoursePeriodDays.isEmpty()){
+//            periodDays = fsUserCoursePeriodDays.get(0);
+//        }
+//        if(periodDays.getStatus() != 1){
+//            return ResponseResult.fail(403, "当前课程未开始或已结束,暂不能看课");
+//        }
+
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+
+        // 1、获取视频详情、问题详情
+        ResponseResult<FsUserCourseVideoDetailsVO> videoDetails = this.getVideoDetails(param.getVideoId());
+        FsUserCourseVideoDetailsVO courseVideoDetails = videoDetails.getData() != null ? videoDetails.getData() : null;
+
+        Long duration = 0L;
+        long tipsTime = 0L;
+        int isFinish = 0;
+        FsUserCourseVideoLinkDetailsVO vo = new FsUserCourseVideoLinkDetailsVO();
+        vo.setCourseVideoDetails(courseVideoDetails);
+        vo.setCourseConfig(config);
+        vo.setIsFinish(isFinish);
+        vo.setPlayDuration(duration);
+
+        //2、判断链接类型
+        if (param.getLinkType() != null && param.getLinkType() == 1) {
+            ResponseResult.ok(vo);
+        }
+        // 从Redis中获取用户目前的观看时长
+        String redisKey = "h5wxuser:watch:duration:" + param.getFsUserId() + ":" + param.getVideoId() + ":" + param.getCompanyUserId();
+        String durationCurrent = redisCache.getCacheObject(redisKey);
+
+        //3、获取看课记录
+        FsCourseWatchLog watchLog = courseWatchLogMapper.getWatchLogByFsUser(param.getVideoId(), param.getFsUserId(), param.getCompanyUserId());
+        if (durationCurrent != null) {
+            duration = Long.parseLong(durationCurrent);
+        } else {
+            duration = Objects.isNull(watchLog) ? 0 : watchLog.getDuration();
+        }
+//
+//        if (course.getDuration()!=null){
+//            tipsTime = course.getDuration()/2;
+//        }
+        //判断是否完课
+        if (watchLog!=null && watchLog.getLogType() == 2) {
+            isFinish = 1;
+        }
+
+        //将视频时长也存到redis
+        String videoRedisKey = "h5wxuser:video:duration:" + param.getVideoId();
+        Long videoDuration = redisCache.getCacheObject(videoRedisKey);
+        if (videoDuration == null) {
+            redisCache.setCacheObject(videoRedisKey, courseVideoDetails != null ? courseVideoDetails.getDuration() != null ? courseVideoDetails.getDuration() : 0 : 0);
         }
+        vo.setIsFinish(isFinish);
+        vo.setPlayDuration(duration);
+        //判断营期的课程状态是否是进行中
+        if(param.getId() != null){
+            FsUserCoursePeriodDays days = fsUserCoursePeriodDaysMapper.selectById(param.getId());
+            vo.setStartDateTime(days.getStartDateTime());
+            vo.setEndDateTime(days.getEndDateTime());
+            vo.setRang(DateUtil.isWithinRangeSafe(LocalDateTime.now(), days.getStartDateTime(), days.getEndDateTime()) && days.getStatus() == 1);
+        }
+        return ResponseResult.ok(vo);
     }
 
-    public static String updateUrlPrefix(String url) {
-        final String oldPrefix = "https://myhktcpv.ylrztop.com";
-        final String newPrefix = "https://myhkobs.ylrztop.com";
+    @Override
+    public R addWatchLogByLink(FsUserCourseAddCompanyUserParam param) {
+
+        return null;
+    }
 
-        // 判断是否以 oldPrefix 开头,如果是,则进行替换
-        if (url.startsWith(oldPrefix)) {
-            // 去掉 oldPrefix 前缀,然后拼上 newPrefix
-            return newPrefix + url.substring(oldPrefix.length());
+    @Override
+    public R updateWatchDurationWx(FsUserCourseVideoUParam param) {
+        //临时短链不做记录
+        if (param.getLinkType() != null && param.getLinkType() == 1){
+            return R.ok();
         }
-        // 如果不是以 oldPrefix 开头,则原样返回
-        return url;
+
+        // 从Redis中获取观看时长
+        String redisKey = "h5wxuser:watch:duration:" + param.getUserId() + ":" + param.getVideoId() + ":" + param.getCompanyUserId();
+        log.info("看课redis缓存key:{}", redisKey);
+        try {
+            String durationStr = redisCache.getCacheObject(redisKey);
+            log.info("看课记录:{}", durationStr);
+            long duration = durationStr != null ? Long.parseLong(durationStr) : 0L;
+
+            // 更新Redis中的观看时长
+            if (param.getDuration() != null && param.getDuration() > duration) {
+                //24小时过期
+                redisCache.setCacheObject(redisKey, param.getDuration().toString(),2,TimeUnit.HOURS);
+            }
+
+            //更新缓存中的心跳时间
+            updateHeartbeatWx(param);
+            return R.ok();
+        } catch (Exception e) {
+            logger.error("更新看课时长失败:{}", redisKey, e.getMessage());
+            return R.error("更新看课时长失败");
+        }
+    }
+
+    @Override
+    public void updates(CourseVideoUpdates vo) {
+        fsUserCourseVideoMapper.updates(vo);
+    }
+
+    @Override
+    public void batchSaveVideo(BatchVideoSvae vo) {
+        List<FsVideoResource> videoResourceList = fsVideoResourceMapper.selectBatchIds(vo.getIds());
+        FsUserCourseVideo param = new FsUserCourseVideo();
+        param.setCourseId(vo.getCourseId());
+        List<FsUserCourseVideo> videoList = selectFsUserCourseVideoList(param);
+        AtomicLong i = new AtomicLong(videoList.size() + 1);
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+
+        List<FsUserCourseVideo> collect = videoResourceList.stream().map(e -> {
+            FsUserCourseVideo entity = new FsUserCourseVideo();
+            entity.setTitle(e.getFileName());
+            entity.setVideoUrl(e.getVideoUrl());
+            entity.setThumbnail(e.getThumbnail());
+            entity.setDuration(e.getDuration().longValue());
+            entity.setCourseId(vo.getCourseId());
+            entity.setStatus(3L);
+            entity.setCourseSort(i.getAndIncrement());
+            entity.setFileName(e.getFileName());
+            entity.setQuestionBankId(e.getProjectIds());
+            entity.setLineOne(e.getLine1());
+            entity.setLineTwo(e.getLine2());
+            entity.setLineThree(e.getLine3());
+            entity.setRedPacketMoney(config.getRedPackageMoney());
+            entity.setFileSize(e.getFileSize());
+            entity.setFileKey(e.getFileKey());
+            entity.setIsTranscode(0);
+            return entity;
+        }).collect(Collectors.toList());
+        fsUserCourseVideoMapper.insertBatchFsUserCourseVideo(collect);
+    }
+
+    @Override
+    public void batchUpdateRed(List<BatchRedUpdate> list) {
+        list.forEach(e -> {
+            fsUserCourseVideoMapper.updateRedPacketMoney(e.getVideoId(), e.getRedPacketMoney());
+        });
+    }
+
+    /**
+     * 获取选项列表
+     * @param params    参数
+     * @return  list
+     */
+    @Override
+    public List<OptionsVO> selectVideoListByMap(Map<String, Object> params) {
+        return fsUserCourseVideoMapper.selectVideoListByMap(params);
+    }
+
+    //会员-更新心跳时间
+    public void updateHeartbeatWx(FsUserCourseVideoUParam param) {
+        String redisKey = "h5wxuser:watch:heartbeat:" + param.getUserId() + ":" + param.getVideoId() + ":" + param.getCompanyUserId();
+        redisCache.setCacheObject(redisKey, LocalDateTime.now().toString());
+        // 设置 Redis 记录的过期时间(例如 5 分钟)
+        redisCache.expire(redisKey, 300, TimeUnit.SECONDS);
     }
 }

+ 57 - 0
fs-service/src/main/java/com/fs/course/vo/FsCourseFinishTempVO.java

@@ -0,0 +1,57 @@
+package com.fs.course.vo;
+
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import com.fs.qw.vo.QwUserVO;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class FsCourseFinishTempVO extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /** $column.columnComment */
+    private Long id;
+
+    /** 模板名称 */
+    @Excel(name = "模板名称")
+    private String name;
+
+    /** 状态 1正常 0停用 */
+    @Excel(name = "状态 1正常 0停用")
+    private Long status;
+
+    /** 规则 */
+    @Excel(name = "规则")
+    private String setting;
+
+    /** 公司id */
+    @Excel(name = "公司id")
+    private Long companyId;
+
+    /** 课程id */
+    @Excel(name = "课程id")
+    private Long courseId;
+
+    /** 小节视频id */
+    @Excel(name = "小节视频id")
+    private Long videoId;
+
+    /** 归属销售id(对多) */
+    @Excel(name = "归属销售id(对多)")
+    private String companyUserIds;
+
+    /** 删除标志 */
+    @Excel(name = "删除标志")
+    private Long isDel;
+
+    /** 是否整销售公司可用 */
+    @Excel(name = "是否整销售公司可用")
+    private Integer isAllCompanyUser;
+
+    private Integer type;
+    private String chatSetting;
+
+    public List<QwUserVO> userSelectList;
+}

+ 67 - 0
fs-service/src/main/java/com/fs/course/vo/FsUserCourseParticipationRecordVO.java

@@ -0,0 +1,67 @@
+package com.fs.course.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.company.domain.CompanyTag;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Data
+public class FsUserCourseParticipationRecordVO {
+    /**
+     * 用户ID
+     */
+    private Long userId;
+    /**
+     * 小节D
+     */
+    private Long videoId;
+    /**
+     * 用户昵称
+     */
+    private String nickName;
+    /**
+     * 用户名称
+     */
+    private String userName;
+    /**
+     * 头像
+     */
+    private String avatar;
+    /**
+     * 用户电话号码
+     */
+    private String phoneNumber;
+    /**
+     * 注册时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private LocalDateTime createTime;
+    /**
+     * 观看次数
+     */
+    private Long watchCount;
+    /**
+     * 完播次数
+     */
+    private Long finishCount;
+    /**
+     * 累计时长
+     */
+    private BigDecimal watchTime;
+    /**
+     * 红包领取状态
+     */
+    private Integer redStatus;
+    /**
+     * 观看时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private LocalDateTime watchDate;
+    /**
+     * 标签
+     */
+    private List<CompanyTag> tags;
+}

+ 83 - 0
fs-service/src/main/java/com/fs/course/vo/HyWatchLog.java

@@ -0,0 +1,83 @@
+package com.fs.course.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Date;
+
+/**
+ * 企微看课
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class HyWatchLog {
+
+    /**
+     * id
+     */
+    private Long id;
+
+    /**
+     * 外部联系人id
+     */
+    private Long extId;
+
+    /**
+     * qw用户id
+     */
+    private Long qwUserId;
+
+    /**
+     * 先导课  0 待看 1看课中/中断 2完课
+     */
+    private Integer status;
+
+    /**
+     * 天数
+     */
+    private Long day;
+
+    /**
+     * 项目
+     */
+    private Long project;
+
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+
+    /**
+     * 进线时间
+     */
+    private Date lineTime;
+
+    /**
+     * fs用户id (无注释)
+     */
+    private Long fsUserId;
+
+    /**
+     * 公司id (无注释)
+     */
+    private Long companyId;
+
+    /**
+     * 公司用户id (无注释)
+     */
+    private Long companyUserId;
+
+    /**
+     * 课程id (无注释)
+     */
+    private Long courseId;
+
+    /**
+     * 视频id (无注释)
+     */
+    private Long videoId;
+}

+ 9 - 4
fs-service/src/main/java/com/fs/course/vo/newfs/FsCourseAnalysisCountVO.java

@@ -38,17 +38,22 @@ public class FsCourseAnalysisCountVO implements Cloneable {
 
     @ApiModelProperty(value = "正确率")
     private BigDecimal answerRightRate;
-    @ApiModelProperty(value = "观看次数-管理端展示")
-    private int courseWatchTimes;
 
-    @ApiModelProperty(value = "完播次数-管理端展示")
-    private int courseCompleteTimes;
+    /**
+     * 以下是新增字段(PC端需要获取)
+     */
     @ApiModelProperty(value = "答题次数-管理端展示")
     private int answerTimes;
 
     @ApiModelProperty(value = "答题正确次数-管理端展示")
     private int answerRightTimes;
 
+    @ApiModelProperty(value = "观看次数-管理端展示")
+    private int courseWatchTimes;
+
+    @ApiModelProperty(value = "完播次数-管理端展示")
+    private int courseCompleteTimes;
+
     @Override
     public FsCourseAnalysisCountVO clone() {
         FsCourseAnalysisCountVO countVO;

+ 10 - 4
fs-service/src/main/java/com/fs/course/vo/newfs/FsUserCourseListVO.java

@@ -9,10 +9,16 @@ import lombok.Data;
 @Data
 public class FsUserCourseListVO {
 
-    @ApiModelProperty(value = "课程id")
-    private Long courseId;
+//    @ApiModelProperty(value = "课程id")
+//    private Long courseId;
+//
+//    @ApiModelProperty(value = "课程名称")
+//    private String courseName;
 
-    @ApiModelProperty(value = "课程名称")
-    private String courseName;
+    @ApiModelProperty(value = "营期id")
+    private Long periodId;
+
+    @ApiModelProperty(value = "营期名称")
+    private String periodName;
 
 }

+ 31 - 0
fs-service/src/main/java/com/fs/course/vo/newfs/FsUserCourseVideoLinkDetailsVO.java

@@ -0,0 +1,31 @@
+package com.fs.course.vo.newfs;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.course.config.CourseConfig;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+@ApiModel
+public class FsUserCourseVideoLinkDetailsVO {
+
+    @ApiModelProperty(value = "课程视频和题库详情")
+    private FsUserCourseVideoDetailsVO courseVideoDetails;
+
+    @ApiModelProperty(value = "课程相关配置信息(默认的)")
+    private CourseConfig courseConfig;
+
+    @ApiModelProperty(value = "是否完课,1-是,0-否")
+    private Integer isFinish;
+
+    @ApiModelProperty(value = "看课时长")
+    private Long playDuration;
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime startDateTime;
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime endDateTime;
+    private boolean isRang;
+}

+ 6 - 0
fs-service/src/main/java/com/fs/course/vo/newfs/FsUserCourseVideoPageListVO.java

@@ -43,5 +43,11 @@ public class FsUserCourseVideoPageListVO extends BaseEntity {
     @ApiModelProperty(value = "创建时间")
     private Date createTime;
 
+    @ApiModelProperty(value = "营期id")
+    private Long periodId;
+
+    @ApiModelProperty(value = "营期课程ID")
+    private Long id;
+
 
 }

+ 5 - 357
fs-service/src/main/java/com/fs/his/domain/FsUser.java

@@ -5,6 +5,7 @@ import com.fs.common.annotation.Excel;
 import com.fs.common.core.domain.BaseEntity;
 import com.vdurmont.emoji.EmojiParser;
 import io.swagger.models.auth.In;
+import lombok.Data;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
@@ -21,6 +22,7 @@ import java.util.Date;
  * @author fs
  * @date 2023-06-07
  */
+@Data
 public class FsUser extends BaseEntity
 {
     private static final long serialVersionUID = 1L;
@@ -81,6 +83,9 @@ public class FsUser extends BaseEntity
     @Excel(name = "邀请码")
     private String userCode;
 
+    private Long companyId;
+    private Long companyUserId;
+
     /** 最后一次登录ip */
     @Excel(name = "最后一次登录ip")
     private String lastIp;
@@ -128,361 +133,4 @@ public class FsUser extends BaseEntity
 
     private Long qwExtId;
 
-    public Long getQwExtId() {
-        return qwExtId;
-    }
-
-    public void setQwExtId(Long qwExtId) {
-        this.qwExtId = qwExtId;
-    }
-
-    public String getCourseMaOpenId() {
-        return courseMaOpenId;
-    }
-
-    public void setCourseMaOpenId(String courserMaOpenId) {
-        this.courseMaOpenId = courserMaOpenId;
-    }
-
-    public Integer getIsAddQw() {
-        return isAddQw;
-    }
-
-    public void setIsAddQw(Integer isAddQw) {
-        this.isAddQw = isAddQw;
-    }
-
-    public String getSource() {
-        return source;
-    }
-
-    public void setSource(String source) {
-        this.source = source;
-    }
-
-    public String getLoginDevice() {
-        return loginDevice;
-    }
-
-    public void setLoginDevice(String loginDevice) {
-        this.loginDevice = loginDevice;
-    }
-
-    public Integer getIsWeixinAuth() {
-        return isWeixinAuth;
-    }
-
-    public void setIsWeixinAuth(Integer isWeixinAuth) {
-        this.isWeixinAuth = isWeixinAuth;
-    }
-
-    public Integer getIsIndividuationPush() {
-        return isIndividuationPush;
-    }
-
-    public void setIsIndividuationPush(Integer isIndividuationPush) {
-        this.isIndividuationPush = isIndividuationPush;
-    }
-
-    public Integer getIsPush() {
-        return isPush;
-    }
-
-    public void setIsPush(Integer isPush) {
-        this.isPush = isPush;
-    }
-
-    public Integer getIsOfficialAccountAuth() {
-        return isOfficialAccountAuth;
-    }
-
-    public void setIsOfficialAccountAuth(Integer isOfficialAccountAuth) {
-        this.isOfficialAccountAuth = isOfficialAccountAuth;
-    }
-
-
-    public String getStoreOpenId() {
-        return storeOpenId;
-    }
-
-    public void setStoreOpenId(String storeOpenId) {
-        this.storeOpenId = storeOpenId;
-    }
-
-    public Integer getSex() {
-        return sex;
-    }
-
-    public void setSex(Integer sex) {
-        this.sex = sex;
-    }
-
-    public Integer getIsVip() {
-        return isVip;
-    }
-
-    public void setIsVip(Integer isVip) {
-        this.isVip = isVip;
-    }
-
-    public Date getVipStartDate() {
-        return vipStartDate;
-    }
-
-    public void setVipStartDate(Date vipStartDate) {
-        this.vipStartDate = vipStartDate;
-    }
-
-    public Date getVipEndDate() {
-        return vipEndDate;
-    }
-
-    public void setVipEndDate(Date vipEndDate) {
-        this.vipEndDate = vipEndDate;
-    }
-
-    public Integer getVipLevel() {
-        return vipLevel;
-    }
-
-    public void setVipLevel(Integer vipLevel) {
-        this.vipLevel = vipLevel;
-    }
-
-    public Integer getVipStatus() {
-        return vipStatus;
-    }
-
-    public void setVipStatus(Integer vipStatus) {
-        this.vipStatus = vipStatus;
-    }
-
-    public String getJpushId() {
-        return jpushId;
-    }
-
-    public void setJpushId(String jpushId) {
-        this.jpushId = jpushId;
-    }
-
-    public String getPassword() {
-        return password;
-    }
-
-    public void setPassword(String password) {
-        this.password = password;
-    }
-
-    public Integer getIsBuy() {
-        return isBuy;
-    }
-
-    public void setIsBuy(Integer isBuy) {
-        this.isBuy = isBuy;
-    }
-
-    public Integer getIntegralStatus() {
-        return integralStatus;
-    }
-
-    public void setIntegralStatus(Integer integralStatus) {
-        this.integralStatus = integralStatus;
-    }
-
-    public Long getSignNum() {
-        return signNum;
-    }
-
-    public void setSignNum(Long signNum) {
-        this.signNum = signNum;
-    }
-
-    public void setUserId(Long userId)
-    {
-        this.userId = userId;
-    }
-
-    public Long getUserId()
-    {
-        return userId;
-    }
-    public void setNickName(String nickname)
-    {
-        if(StringUtils.isNotEmpty(nickname)){
-            this.nickName= EmojiParser.parseToHtmlDecimal(nickname);
-        }
-        else{
-            this.nickName= nickname;
-        }
-    }
-
-    public String getNickName()
-    {
-        if(StringUtils.isNotEmpty(nickName)){
-            return EmojiParser.parseToUnicode(nickName);
-        }
-        else{
-            return nickName;
-        }
-    }
-    public void setAvatar(String avatar)
-    {
-        this.avatar = avatar;
-    }
-
-    public String getAvatar()
-    {
-        return avatar;
-    }
-
-    public String getPhone() {
-        return phone;
-    }
-
-    public void setPhone(String phone) {
-        this.phone = phone;
-    }
-
-    public void setIntegral(Long integral)
-    {
-        this.integral = integral;
-    }
-
-    public Long getIntegral()
-    {
-        return integral;
-    }
-    public void setStatus(Integer status)
-    {
-        this.status = status;
-    }
-
-    public Integer getStatus()
-    {
-        return status;
-    }
-    public void setTuiUserId(String tuiUserId)
-    {
-        this.tuiUserId = tuiUserId;
-    }
-
-    public String getTuiUserId()
-    {
-        return tuiUserId;
-    }
-    public void setTuiTime(Date tuiTime)
-    {
-        this.tuiTime = tuiTime;
-    }
-
-    public Date getTuiTime()
-    {
-        return tuiTime;
-    }
-    public void setTuiUserCount(Long tuiUserCount)
-    {
-        this.tuiUserCount = tuiUserCount;
-    }
-
-    public Long getTuiUserCount()
-    {
-        return tuiUserCount;
-    }
-    public void setMaOpenId(String maOpenId)
-    {
-        this.maOpenId = maOpenId;
-    }
-
-    public String getMaOpenId()
-    {
-        return maOpenId;
-    }
-    public void setMpOpenId(String mpOpenId)
-    {
-        this.mpOpenId = mpOpenId;
-    }
-
-    public String getMpOpenId()
-    {
-        return mpOpenId;
-    }
-    public void setUnionId(String unionId)
-    {
-        this.unionId = unionId;
-    }
-
-    public String getUnionId()
-    {
-        return unionId;
-    }
-    public void setIsDel(Integer isDel)
-    {
-        this.isDel = isDel;
-    }
-
-    public Integer getIsDel()
-    {
-        return isDel;
-    }
-    public void setUserCode(String userCode)
-    {
-        this.userCode = userCode;
-    }
-
-    public String getUserCode()
-    {
-        return userCode;
-    }
-    public void setLastIp(String lastIp)
-    {
-        this.lastIp = lastIp;
-    }
-
-    public String getLastIp()
-    {
-        return lastIp;
-    }
-    public void setBalance(BigDecimal balance)
-    {
-        this.balance = balance;
-    }
-
-    public BigDecimal getBalance()
-    {
-        return balance;
-    }
-
-    public Long getParentId() {
-        return parentId;
-    }
-
-    public void setParentId(Long parentId) {
-        this.parentId = parentId;
-    }
-
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
-            .append("userId", getUserId())
-            .append("nickName", getNickName())
-            .append("avatar", getAvatar())
-            .append("phone", getPhone())
-            .append("integral", getIntegral())
-            .append("status", getStatus())
-            .append("tuiUserId", getTuiUserId())
-            .append("tuiTime", getTuiTime())
-            .append("tuiUserCount", getTuiUserCount())
-            .append("maOpenId", getMaOpenId())
-            .append("mpOpenId", getMpOpenId())
-            .append("unionId", getUnionId())
-            .append("isDel", getIsDel())
-            .append("userCode", getUserCode())
-            .append("remark", getRemark())
-            .append("createTime", getCreateTime())
-            .append("updateTime", getUpdateTime())
-            .append("lastIp", getLastIp())
-            .append("balance", getBalance())
-            .append("parentId", getParentId())
-            .toString();
-    }
 }

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

@@ -241,4 +241,6 @@ public interface FsUserMapper
     List<FsCourseAnalysisCountVO> courseAnalysisWatchLog(CourseAnalysisParam param);
     List<FsCourseAnalysisCountVO> courseAnalysisRedPacketCount(CourseAnalysisParam param);
     List<FsCourseAnalysisCountVO> courseAnalysisAnswerCount(CourseAnalysisParam param);
+
+    FsUser selectFsUserById(@Param("userId") Long userId);
 }

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

@@ -4,6 +4,7 @@ import java.math.BigDecimal;
 import java.util.List;
 
 import com.fs.common.core.domain.R;
+import com.fs.course.param.newfs.FsUserCourseBeMemberParam;
 import com.fs.his.domain.FsUser;
 import com.fs.his.domain.FsUserAddress;
 import com.fs.his.param.FsUserParam;
@@ -115,4 +116,6 @@ public interface IFsUserService
     Long selectFsUserExportListVOCount(FsUserParam fsUser);
 
     FsUser selectFsUserByMpOpenId(String openId);
+
+    void setRepeatFansTag(FsUserCourseBeMemberParam param);
 }

+ 49 - 3
fs-service/src/main/java/com/fs/his/service/impl/FsUserServiceImpl.java

@@ -4,14 +4,18 @@ import java.lang.reflect.Field;
 import java.math.BigDecimal;
 import java.math.MathContext;
 import java.math.RoundingMode;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
+import java.util.*;
 
 import cn.hutool.json.JSONUtil;
 import com.fs.common.core.domain.R;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
+import com.fs.company.domain.CompanyTag;
+import com.fs.company.domain.CompanyTagUser;
+import com.fs.company.mapper.CompanyTagMapper;
+import com.fs.company.mapper.CompanyTagUserMapper;
+import com.fs.company.service.ICompanyTagService;
+import com.fs.course.param.newfs.FsUserCourseBeMemberParam;
 import com.fs.his.config.IntegralConfig;
 import com.fs.his.domain.FsUserAddress;
 import com.fs.his.domain.FsUserIntegralLogs;
@@ -57,6 +61,17 @@ public class FsUserServiceImpl implements IFsUserService
     private FsFollowMapper fsFollowMapper;
     @Autowired
     private WatchUserService watchUserService;
+
+    @Autowired
+    private ICompanyTagService companyTagService;
+
+    @Autowired
+    CompanyTagMapper companyTagMapper;
+
+    @Autowired
+    private CompanyTagUserMapper companyTagUserMapper;
+
+
     /**
      * 查询用户
      *
@@ -408,4 +423,35 @@ public class FsUserServiceImpl implements IFsUserService
         return fsUserMapper.selectFsUserByMpOpenId(openId);
     }
 
+    @Transactional(rollbackFor = Exception.class)
+    public void setRepeatFansTag(FsUserCourseBeMemberParam param) {
+        Map<String, Object> map = new HashMap<>();
+        map.put("tagName", "重粉");
+        List<CompanyTag> companyTags = companyTagMapper.selectCompanyTagListByMap(map);
+        Long tagId;
+        if(companyTags == null || companyTags.isEmpty()){
+            CompanyTag companyTag = new CompanyTag();
+            companyTag.setCompanyId(param.getCompanyId());
+            companyTag.setTag("重粉");
+            companyTagService.insertCompanyTag(companyTag);
+            tagId = companyTag.getTagId();
+        } else {
+            tagId = companyTags.get(0).getTagId();
+        }
+        //  查询
+        CompanyTagUser companyTagUserParam = new CompanyTagUser();
+        companyTagUserParam.setUserId(param.getUserId());
+        companyTagUserParam.setTagIds(tagId.toString());
+        List<CompanyTagUser> companyTagUsers = companyTagUserMapper.selectCompanyTagUserList(companyTagUserParam);
+        if(companyTagUsers == null || companyTagUsers.isEmpty()){
+            CompanyTagUser companyTagUser = new CompanyTagUser();
+            companyTagUser.setUserId(param.getUserId());
+            companyTagUser.setCompanyId(param.getCompanyId());
+            companyTagUser.setCompanyUserId(param.getCompanyUserId());
+            companyTagUser.setTagIds(tagId.toString());
+            companyTagUser.setCreateTime(new Date());
+            companyTagUserMapper.insertCompanyTagUser(companyTagUser);
+        }
+    }
+
 }

+ 5 - 0
fs-service/src/main/java/com/fs/qw/domain/QwGroupChatUser.java

@@ -4,8 +4,11 @@ import com.baomidou.mybatisplus.annotation.TableField;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fs.common.annotation.Excel;
 import com.fs.common.core.domain.BaseEntity;
+import com.fs.qw.vo.GroupUserExternalVo;
 import lombok.Data;
 
+import java.util.List;
+
 /**
  * 客户群成员列对象 qw_group_chat_user
  *
@@ -92,4 +95,6 @@ public class QwGroupChatUser extends BaseEntity
     private String tagIds;
     @TableField(exist = false)
     private String fsUserId;
+    @TableField(exist = false)
+    private List<GroupUserExternalVo> userList;
 }

+ 3 - 0
fs-service/src/main/java/com/fs/qw/mapper/QwExternalContactMapper.java

@@ -9,6 +9,7 @@ import com.fs.qw.param.QwExternalContactVOTime;
 import com.fs.qw.result.QwExternalContactByQwResult;
 import com.fs.qw.result.QwExternalContactLogVo;
 import com.fs.qw.result.QwExternalContactVo;
+import com.fs.qw.vo.GroupUserExternalVo;
 import com.fs.qw.vo.QwExternalContactFsCrmVO;
 import com.fs.qw.vo.QwExternalContactFsUserVO;
 import com.fs.qw.vo.QwExternalContactVO;
@@ -357,4 +358,6 @@ public interface QwExternalContactMapper extends BaseMapper<QwExternalContact> {
     QwExternalContact selectQwExternalContactTimeById(Long id);
 
     List<QwExternalContactVOTime> selectQwExternalContactListVOByUserIds(@Param("ids") List<String> ids);
+
+    List<GroupUserExternalVo> selectByGroupUser(@Param("ids") List<String> ids);
 }

+ 3 - 0
fs-service/src/main/java/com/fs/qw/mapper/QwUserMapper.java

@@ -46,6 +46,9 @@ public interface QwUserMapper extends BaseMapper<QwUser>
 
     @Select("select welcome_text,qw_user_name from qw_user where id = #{id}")
     public QwUser selectQwUserByIdByWeComeText(@Param("id") Long id);
+
+    @Select("select * from qw_user where qw_user_id = #{qwUserId} and corp_id = #{corpId} ")
+    public QwUser selectQwUserByIdByWeComeText(@Param("qwUserId") String qwUserId, @Param("corpId") String corpId);
     /**
      * 根据companyUserId查询企微用户
      */

+ 12 - 0
fs-service/src/main/java/com/fs/qw/vo/GroupUserExternalVo.java

@@ -0,0 +1,12 @@
+package com.fs.qw.vo;
+
+import lombok.Data;
+
+@Data
+public class GroupUserExternalVo {
+
+    private Long id;
+    private String userId;
+    private String externalUserId;
+
+}

+ 2 - 0
fs-service/src/main/java/com/fs/sop/params/SendUserLogsInfoMsgParam.java

@@ -9,6 +9,7 @@ import lombok.Data;
 public class SendUserLogsInfoMsgParam {
 
     private String[] ids;
+    private String[] chatIds;
     private Integer videoId;
     private Integer courseId;
     private Integer courseType;
@@ -17,6 +18,7 @@ public class SendUserLogsInfoMsgParam {
     private String userIdParam;
     private String startTime;
     private String corpId;
+    private Integer filterMode;
 
     //类型 1 营期详情中发 2 直接按营期发
     private Integer type;

+ 257 - 117
fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsInfoServiceImpl.java

@@ -4,7 +4,10 @@ import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.fs.common.core.domain.R;
+import com.fs.common.exception.base.BaseException;
+import com.fs.common.utils.PubFun;
 import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.date.DateUtil;
 import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.FsCourseDomainName;
@@ -14,17 +17,22 @@ import com.fs.course.domain.FsCourseWatchLog;
 import com.fs.course.mapper.FsCourseDomainNameMapper;
 import com.fs.course.mapper.FsCourseLinkMapper;
 import com.fs.course.mapper.FsCourseWatchLogMapper;
+import com.fs.course.param.FsCourseLinkCreateParam;
 import com.fs.course.service.IFsCourseLinkService;
 import com.fs.fastGpt.domain.FastGptChatReplaceWords;
 import com.fs.fastGpt.mapper.FastGptChatReplaceWordsMapper;
 import com.fs.qw.domain.QwCompany;
 import com.fs.qw.domain.QwExternalContact;
+import com.fs.qw.domain.QwGroupChat;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.mapper.QwExternalContactMapper;
+import com.fs.qw.mapper.QwGroupChatMapper;
 import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.service.IQwCompanyService;
 import com.fs.qw.service.impl.AsyncSopTestService;
+import com.fs.qw.vo.GroupUserExternalVo;
 import com.fs.qw.vo.QwSopCourseFinishTempSetting;
+import com.fs.qw.vo.QwSopRuleTimeVO;
 import com.fs.sop.domain.QwSop;
 import com.fs.sop.domain.QwSopLogs;
 import com.fs.sop.domain.SopUserLogs;
@@ -42,6 +50,7 @@ import com.fs.sop.service.ISopUserLogsInfoService;
 import com.fs.sop.service.ISopUserLogsService;
 import com.fs.sop.vo.QwCreateLinkByAppVO;
 import com.fs.sop.vo.SopUserLogsInfoVOE;
+import com.fs.sop.vo.SopUserLogsVo;
 import com.fs.system.service.ISysConfigService;
 import com.fs.voice.utils.StringUtil;
 import org.slf4j.Logger;
@@ -86,9 +95,13 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
 
     @Autowired
     private FsCourseLinkMapper fsCourseLinkMapper;
+    @Autowired
+    private QwGroupChatMapper qwGroupChatMapper;
 
     @Autowired
     private FastGptChatReplaceWordsMapper fastGptChatReplaceWordsMapper;
+    @Autowired
+    private IFsCourseLinkService courseLinkService;
 
     @Autowired
     private SopUserLogsMapper sopUserLogsMapper;
@@ -362,169 +375,296 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
         }
     }
 
+    private QwSopLogs createBaseLog(String formattedSendTime, SopUserLogsVo logVo,
+                                    QwSopRuleTimeVO ruleTimeVO, String externalContactId,
+                                    String externalUserName, Long fsUserId, Integer isOfficial,
+                                    Long externalId) {
+        QwSopLogs sopLogs = new QwSopLogs();
+        sopLogs.setSendTime(formattedSendTime);
+        sopLogs.setQwUserid(logVo.getQwUserId());
+        sopLogs.setCorpId(logVo.getCorpId());
+        sopLogs.setLogType(ruleTimeVO.getType());
+
+        sopLogs.setSendType(isOfficial == 1 ? 1 : ruleTimeVO.getSendType());
+
+
+        sopLogs.setSendStatus(3L);
+        sopLogs.setReceivingStatus(0L);
+
+        String[] userKey = logVo.getUserId().split("\\|");
+        sopLogs.setCompanyId(Long.valueOf(userKey[2].trim()));
+        sopLogs.setSopId(logVo.getSopId());
 
+        sopLogs.setExternalUserId(externalContactId);
+        sopLogs.setExternalId(externalId);
+        sopLogs.setExternalUserName(externalUserName);
+        sopLogs.setFsUserId(fsUserId);
+
+        return sopLogs;
+    }
     @Override
     public R sendUserLogsInfoMsg(SendUserLogsInfoMsgParam param) {
+        QwSop qwSop = qwSopMapper.selectQwSopById(param.getSopId());
+        List<FastGptChatReplaceWords> words = fastGptChatReplaceWordsMapper.selectAllFastGptChatReplaceWords();
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSON.parseObject(json, CourseConfig.class);
 
-        Date createTime=new Date();
+        if (config == null) {
+            return R.error().put("msg","课程默认配置为空,请联系管理员");
+        }
+        List<QwSopLogs> sopLogsList;
+        if(param.getFilterMode() != null && param.getFilterMode() == 2 && param.getChatIds() != null && param.getChatIds().length > 0){
+            List<QwGroupChat> groupList = qwGroupChatMapper.selectQwGroupChatByChatIds(param.getChatIds());
+            sopLogsList = groupList.stream().map(groupChat -> {
+                QwUser qwUser = qwUserMapper.selectQwUserByIdByWeComeText(groupChat.getOwner(), groupChat.getCorpId());
+                QwSopLogs sopLogs = new QwSopLogs();
+
+                sopLogs.setQwUserid(qwUser.getQwUserId());
+                sopLogs.setExternalUserId(groupChat.getChatId());
+                sopLogs.setLogType(2);
+                sopLogs.setContentJson(param.getSetting());
+                sopLogs.setSendStatus(3L);
+                sopLogs.setSendTime(DateUtil.formatLocalDateTime(LocalDateTime.now()));
+                sopLogs.setCompanyId(qwSop.getCompanyId());
+                sopLogs.setReceivingStatus(0L);
+                sopLogs.setSopId(param.getSopId());
+                sopLogs.setCorpId(groupChat.getCorpId());
+                sopLogs.setSort(2);
+                sopLogs.setSendType(6);
+                sopLogs.setExternalUserName(groupChat.getName());
+
+                QwSopCourseFinishTempSetting setting = new QwSopCourseFinishTempSetting();
+
+                List<QwSopCourseFinishTempSetting.Setting> list = JSONArray.parseArray(param.getSetting(), QwSopCourseFinishTempSetting.Setting.class);
+//
+//            List<QwSopCourseFinishTempSetting.Setting> list = parseSettings(param.getSetting());
 
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-        QwSop qwSop = qwSopMapper.selectQwSopById(param.getSopId());
+                for (QwSopCourseFinishTempSetting.Setting st : list) {
 
-        List<FastGptChatReplaceWords> words = fastGptChatReplaceWordsMapper.selectAllFastGptChatReplaceWords();
+                    //过滤违禁词
+                    if ("1".equals(st.getContentType())) {
+                        replaceContent(st.getContentType(), st.getValue(), st::setValue, words); // 替换 value
+                    }
+                    //过滤违禁词
+                    if ("3".equals(st.getContentType())) {
+                        replaceContent(st.getContentType(), st.getLinkTitle(), st::setLinkTitle, words); // 替换 linkTitle
+                        replaceContent(st.getContentType(), st.getLinkDescribe(), st::setLinkDescribe, words); // 替换 linkTitle
+                    }
 
-        List<SopUserLogsInfo> sopUserLogsInfos = sopUserLogsInfoMapper.selectSopUserLogsInfoByIds(param.getIds());
+                    switch (st.getContentType()) {
+                        //文字和短链一起
+                        case "1":
+                        case "3":
+                            if ("1".equals(st.getIsBindUrl())) {
+                                FsCourseLinkCreateParam createParam = new FsCourseLinkCreateParam();
+                                createParam.setCourseId(param.getCourseId().longValue());
+                                createParam.setVideoId(param.getVideoId().longValue());
+                                createParam.setCorpId(groupChat.getCorpId());
+                                createParam.setCompanyUserId(qwUser.getCompanyUserId());
+                                createParam.setCompanyId(qwUser.getCompanyId());
+                                createParam.setChatId(groupChat.getChatId());
+                                createParam.setQwUserId(qwUser.getQwUserId());
+                                createParam.setDays(st.getExpiresDays());
+                                R createLink = courseLinkService.createRoomLinkUrl(createParam);
+                                if (createLink.get("code").equals(500)) {
+                                    throw new BaseException("链接生成失败!");
+                                }
+                                String link = (String) createLink.get("url");
+                                if (StringUtils.isNotEmpty(link)) {
+                                    if ("3".equals(st.getContentType())) {
+                                        st.setLinkUrl(link);
+                                    } else {
+                                        String currentValue = st.getValue();
+                                        if (currentValue == null) {
+                                            st.setValue(link);
+                                        } else {
+//                                    setting.setValue(currentValue + "\n" + sortLink);
+                                            st.setValue(currentValue
+                                                    .replaceAll("#销售称呼#", StringUtil.strIsNullOrEmpty(qwUser.getWelcomeText()) ? "" : qwUser.getWelcomeText())
+                                                    + "\n" + link);
+                                        }
+                                    }
+                                } else {
+                                    log.error("生成短链失败,跳过设置 URL。");
+                                }
+                            }
 
-        String[] userKey = param.getUserIdParam().split("\\|");
-        String qwUserId = userKey[0].trim();
-        String companyUserId = userKey[1].trim();
-        String companyId = userKey[2].trim();
+                            break;
+                        //小程序单独
+                        case "4":
+                            String linkByMiniApp = createLinkByMiniApp(st, param.getCorpId(), new Date(), param.getCourseId(), param.getVideoId(),
+                                    qwUser.getQwUserId(), qwUser.getCompanyUserId().toString(), qwUser.getCompanyId().toString(), null, config);
 
+                            if (StringUtil.strIsNullOrEmpty(config.getMiniprogramAppid())) {
+                                log.error("配置中无小程序id,采用默认的");
+                                st.setMiniprogramAppid("wxc84c6f789ba7f176");
+                            } else {
+                                st.setMiniprogramAppid(config.getMiniprogramAppid());
+                            }
 
-        QwUser qwUser = qwUserMapper.selectQwUserByIdByWeComeText(Long.valueOf(qwUserId));
+                            st.setMiniprogramPage(linkByMiniApp);
+                            break;
+                    }
+                }
+                setting.setSetting(list);
+                setting.setType(2);
+                setting.setVideoId(param.getVideoId());
+                setting.setCourseId(param.getCourseId());
+                setting.setCourseType(param.getCourseType());
+                sopLogs.setContentJson(JSON.toJSONString(setting));
+                return sopLogs;
+            }).collect(Collectors.toList());
+
+        }else{
+            sopLogsList = new ArrayList<>();
+            Date createTime=new Date();
 
-        if (qwUser == null) {
-              return R.error().put("msg","企业微信用户不存在:"+qwUserId);
-        }
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 
-        String json = configService.selectConfigByKey("course.config");
-        CourseConfig config = JSON.parseObject(json, CourseConfig.class);
+            List<SopUserLogsInfo> sopUserLogsInfos = sopUserLogsInfoMapper.selectSopUserLogsInfoByIds(param.getIds());
 
-        if (config == null) {
-            return R.error().put("msg","课程默认配置为空,请联系管理员");
-        }
-        //域名
-        String domainName = companyUserMapper.selectDomainByUserId(Long.parseLong(companyUserId));
-        if (StringUtils.isEmpty(domainName)){
-            domainName = config.getRealLinkDomainName();
-        }
+            String[] userKey = param.getUserIdParam().split("\\|");
+            String qwUserId = userKey[0].trim();
+            String companyUserId = userKey[1].trim();
+            String companyId = userKey[2].trim();
+
+
+            QwUser qwUser = qwUserMapper.selectQwUserByIdByWeComeText(Long.valueOf(qwUserId));
+
+            if (qwUser == null) {
+                return R.error().put("msg","企业微信用户不存在:"+qwUserId);
+            }
+            //域名
+            String domainName = companyUserMapper.selectDomainByUserId(Long.parseLong(companyUserId));
+            if (StringUtils.isEmpty(domainName)){
+                domainName = config.getRealLinkDomainName();
+            }
 //        if (StringUtils.isEmpty(config.getMiniprogramPage())){
 //            return R.error().put("msg","课程默认配置小程序路径为空,请联系管理员");
 //        }
 
-        List<QwSopLogs> sopLogsList=new ArrayList<>();
+            String finalDomainName = domainName;
+            sopUserLogsInfos.forEach(item->{
 
-        String finalDomainName = domainName;
-        sopUserLogsInfos.forEach(item->{
+                QwSopLogs sopLogs=new QwSopLogs();
 
-            QwSopLogs sopLogs=new QwSopLogs();
+                sopLogs.setQwUserid(item.getQwUserId());
+                sopLogs.setExternalUserId(item.getExternalContactId());
+                sopLogs.setExternalId(item.getExternalId());
+                sopLogs.setLogType(2);
+                sopLogs.setContentJson(param.getSetting());
+                sopLogs.setSendStatus(3L);
+                sopLogs.setSendTime(sdf.format(new Date()));
+                sopLogs.setCompanyId(qwSop.getCompanyId());
+                sopLogs.setReceivingStatus(0L);
+                sopLogs.setSopId(param.getSopId());
+                sopLogs.setCorpId(item.getCorpId());
+                sopLogs.setFsUserId(item.getFsUserId());
+                sopLogs.setSort(2);
+                sopLogs.setSendType(5);
+                sopLogs.setExternalUserName(item.getExternalUserName());
 
-            sopLogs.setQwUserid(item.getQwUserId());
-            sopLogs.setExternalUserId(item.getExternalContactId());
-            sopLogs.setExternalId(item.getExternalId());
-            sopLogs.setLogType(2);
-            sopLogs.setContentJson(param.getSetting());
-            sopLogs.setSendStatus(3L);
-            sopLogs.setSendTime(sdf.format(new Date()));
-            sopLogs.setCompanyId(qwSop.getCompanyId());
-            sopLogs.setReceivingStatus(0L);
-            sopLogs.setSopId(param.getSopId());
-            sopLogs.setCorpId(item.getCorpId());
-            sopLogs.setFsUserId(item.getFsUserId());
-            sopLogs.setSort(2);
-            sopLogs.setSendType(5);
-            sopLogs.setExternalUserName(item.getExternalUserName());
+                QwExternalContact contact = qwExternalContactMapper.selectQwExternalContactByIdForStageStatus(item.getExternalId());
 
-            QwExternalContact contact = qwExternalContactMapper.selectQwExternalContactByIdForStageStatus(item.getExternalId());
+                QwSopCourseFinishTempSetting setting=new    QwSopCourseFinishTempSetting();
 
-            QwSopCourseFinishTempSetting setting=new    QwSopCourseFinishTempSetting();
-
-            List<QwSopCourseFinishTempSetting.Setting> list = JSONArray.parseArray(param.getSetting(),QwSopCourseFinishTempSetting.Setting.class);
+                List<QwSopCourseFinishTempSetting.Setting> list = JSONArray.parseArray(param.getSetting(),QwSopCourseFinishTempSetting.Setting.class);
 //
 //            List<QwSopCourseFinishTempSetting.Setting> list = parseSettings(param.getSetting());
 
-            for (QwSopCourseFinishTempSetting.Setting st : list) {
+                for (QwSopCourseFinishTempSetting.Setting st : list) {
 
-                //过滤违禁词
-                if ("1".equals(st.getContentType())){
-                    replaceContent(st.getContentType(), st.getValue(), st::setValue, words); // 替换 value
-                }
-                //过滤违禁词
-                if ("3".equals(st.getContentType())){
-                    replaceContent(st.getContentType(), st.getLinkTitle(), st::setLinkTitle, words); // 替换 linkTitle
-                    replaceContent(st.getContentType(), st.getLinkDescribe(), st::setLinkDescribe, words); // 替换 linkTitle
-                }
+                    //过滤违禁词
+                    if ("1".equals(st.getContentType())){
+                        replaceContent(st.getContentType(), st.getValue(), st::setValue, words); // 替换 value
+                    }
+                    //过滤违禁词
+                    if ("3".equals(st.getContentType())){
+                        replaceContent(st.getContentType(), st.getLinkTitle(), st::setLinkTitle, words); // 替换 linkTitle
+                        replaceContent(st.getContentType(), st.getLinkDescribe(), st::setLinkDescribe, words); // 替换 linkTitle
+                    }
 
-                switch (st.getContentType()){
-                    //文字和短链一起
-                    case "1":
-                    case "3":
-                        if ("1".equals(st.getIsBindUrl())) {
+                    switch (st.getContentType()){
+                        //文字和短链一起
+                        case "1":
+                        case "3":
+                            if ("1".equals(st.getIsBindUrl())) {
 
-                            addWatchLogIfNeeded(param.getSopId(), param.getVideoId(), param.getCourseId(),item.getFsUserId(), qwUserId, companyUserId, companyId, item.getExternalId(),param.getStartTime(),createTime );
+                                addWatchLogIfNeeded(param.getSopId(), param.getVideoId(), param.getCourseId(),item.getFsUserId(), qwUserId, companyUserId, companyId, item.getExternalId(),param.getStartTime(),createTime );
 
-                            String sortLink = generateShortLink(st, param.getCorpId(), createTime, param.getCourseId(), param.getVideoId(),
-                                    qwUserId, companyUserId, companyId, finalDomainName,item.getExternalId(),config);
+                                String sortLink = generateShortLink(st, param.getCorpId(), createTime, param.getCourseId(), param.getVideoId(),
+                                        qwUserId, companyUserId, companyId, finalDomainName,item.getExternalId(),config);
 
-                            if (StringUtils.isNotEmpty(sortLink)) {
-                                if ("3".equals(st.getContentType())) {
-                                    st.setLinkUrl(sortLink);
-                                } else {
-                                    String currentValue = st.getValue();
-                                    if (currentValue == null) {
-                                        st.setValue(sortLink);
+                                if (StringUtils.isNotEmpty(sortLink)) {
+                                    if ("3".equals(st.getContentType())) {
+                                        st.setLinkUrl(sortLink);
                                     } else {
-                                        st.setValue(currentValue
-                                                .replaceAll("#销售称呼#",StringUtil.strIsNullOrEmpty(qwUser.getWelcomeText())?"":qwUser.getWelcomeText())
-                                                .replaceAll("#客户称呼#",StringUtil.strIsNullOrEmpty(contact.getStageStatus())|| "0".equals(contact.getStageStatus())?"同学":contact.getStageStatus())
-                                                + "\n" + sortLink);
+                                        String currentValue = st.getValue();
+                                        if (currentValue == null) {
+                                            st.setValue(sortLink);
+                                        } else {
+                                            st.setValue(currentValue
+                                                    .replaceAll("#销售称呼#",StringUtil.strIsNullOrEmpty(qwUser.getWelcomeText())?"":qwUser.getWelcomeText())
+                                                    .replaceAll("#客户称呼#",StringUtil.strIsNullOrEmpty(contact.getStageStatus())|| "0".equals(contact.getStageStatus())?"同学":contact.getStageStatus())
+                                                    + "\n" + sortLink);
+                                        }
                                     }
+                                } else {
+                                    log.warn("生成短链失败,跳过设置 URL。");
+                                }
+                            }else {
+                                if ("1".equals(st.getContentType())) {
+                                    st.setValue(st.getValue()
+                                            .replaceAll("#销售称呼#",StringUtil.strIsNullOrEmpty(qwUser.getWelcomeText())?"":qwUser.getWelcomeText())
+                                            .replaceAll("#客户称呼#",StringUtil.strIsNullOrEmpty(contact.getStageStatus()) || "0".equals(contact.getStageStatus())?"同学":contact.getStageStatus()));
                                 }
-                            } else {
-                                log.warn("生成短链失败,跳过设置 URL。");
-                            }
-                        }else {
-                            if ("1".equals(st.getContentType())) {
-                                st.setValue(st.getValue()
-                                        .replaceAll("#销售称呼#",StringUtil.strIsNullOrEmpty(qwUser.getWelcomeText())?"":qwUser.getWelcomeText())
-                                        .replaceAll("#客户称呼#",StringUtil.strIsNullOrEmpty(contact.getStageStatus()) || "0".equals(contact.getStageStatus())?"同学":contact.getStageStatus()));
                             }
-                        }
 
-                        break;
-                    //小程序单独
-                    case "4":
-                        addWatchLogIfNeeded(param.getSopId(), param.getVideoId(), param.getCourseId(),item.getFsUserId(), qwUserId, companyUserId, companyId, item.getExternalId(),param.getStartTime(),createTime );
+                            break;
+                        //小程序单独
+                        case "4":
+                            addWatchLogIfNeeded(param.getSopId(), param.getVideoId(), param.getCourseId(),item.getFsUserId(), qwUserId, companyUserId, companyId, item.getExternalId(),param.getStartTime(),createTime );
 
-                        String linkByMiniApp = createLinkByMiniApp(st, param.getCorpId(), createTime, param.getCourseId(), param.getVideoId(),
-                                qwUserId, companyUserId, companyId, item.getExternalId(), config);
+                            String linkByMiniApp = createLinkByMiniApp(st, param.getCorpId(), createTime, param.getCourseId(), param.getVideoId(),
+                                    qwUserId, companyUserId, companyId, item.getExternalId(), config);
 
-                        if (StringUtil.strIsNullOrEmpty(config.getMiniprogramAppid())){
-                            log.error("配置中无小程序id,采用默认的");
-                            st.setMiniprogramAppid("wxc84c6f789ba7f176");
-                        }else {
-                            st.setMiniprogramAppid(config.getMiniprogramAppid());
-                        }
+                            if (StringUtil.strIsNullOrEmpty(config.getMiniprogramAppid())){
+                                log.error("配置中无小程序id,采用默认的");
+                                st.setMiniprogramAppid("wxc84c6f789ba7f176");
+                            }else {
+                                st.setMiniprogramAppid(config.getMiniprogramAppid());
+                            }
 
-                        st.setMiniprogramPage(linkByMiniApp);
-                        break;
-                    //app
-                    case "9":
-                        addWatchLogIfNeeded(param.getSopId(), param.getVideoId(), param.getCourseId(),item.getFsUserId(), qwUserId, companyUserId, companyId, item.getExternalId(),param.getStartTime(),createTime );
+                            st.setMiniprogramPage(linkByMiniApp);
+                            break;
+                        //app
+                        case "9":
+                            addWatchLogIfNeeded(param.getSopId(), param.getVideoId(), param.getCourseId(),item.getFsUserId(), qwUserId, companyUserId, companyId, item.getExternalId(),param.getStartTime(),createTime );
 
-                        QwCreateLinkByAppVO linkByApp = createLinkByApp(st, param.getCorpId(), createTime, param.getCourseId(), param.getVideoId(),
-                                qwUserId, companyUserId, companyId, item.getExternalId(), config,qwUser.getQwUserName(),contact.getFsUserId());
-                        st.setLinkUrl(linkByApp.getSortLink().replaceAll("^[\\s\\u2005]+", ""));
-                        st.setAppLinkUrl(linkByApp.getAppMsgLink().replaceAll("^[\\s\\u2005]+", ""));
+                            QwCreateLinkByAppVO linkByApp = createLinkByApp(st, param.getCorpId(), createTime, param.getCourseId(), param.getVideoId(),
+                                    qwUserId, companyUserId, companyId, item.getExternalId(), config,qwUser.getQwUserName(),contact.getFsUserId());
+                            st.setLinkUrl(linkByApp.getSortLink().replaceAll("^[\\s\\u2005]+", ""));
+                            st.setAppLinkUrl(linkByApp.getAppMsgLink().replaceAll("^[\\s\\u2005]+", ""));
 
-                        break;
-                    default:
-                        break;
+                            break;
+                        default:
+                            break;
 
+                    }
                 }
-            }
 
 
-            setting.setSetting(list);
-            setting.setType(2);
-            setting.setVideoId(param.getVideoId());
-            setting.setCourseId(param.getCourseId());
-            setting.setCourseType(param.getCourseType());
+                setting.setSetting(list);
+                setting.setType(2);
+                setting.setVideoId(param.getVideoId());
+                setting.setCourseId(param.getCourseId());
+                setting.setCourseType(param.getCourseType());
 
-            sopLogs.setContentJson(JSON.toJSONString(setting));
+                sopLogs.setContentJson(JSON.toJSONString(setting));
 
-            sopLogsList.add(sopLogs);
-        });
+                sopLogsList.add(sopLogs);
+            });
+        }
 
         //批量插入 发送记录
         if (!sopLogsList.isEmpty()) {

+ 41 - 0
fs-service/src/main/java/com/fs/store/param/h5/CourseAnalysisParam.java

@@ -0,0 +1,41 @@
+package com.fs.store.param.h5;
+
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 课程分析查询-入参
+ */
+@Data
+public class CourseAnalysisParam implements Serializable {
+
+    @ApiModelProperty(value = "页码,默认为1", required = true)
+    private Integer pageNum = 1;
+
+    @ApiModelProperty(value = "页大小,默认为10", required = true)
+    private Integer pageSize = 10;
+
+    @ApiModelProperty(value = "销售用户id")
+    private Long companyUserId;
+
+    @ApiModelProperty(value = "营期id")
+    private Long periodId;
+
+    @ApiModelProperty(value = "视频id")
+    private Long videoId;
+
+//    @ApiModelProperty(value = "登录用户id,不传")
+//    private Long userId;
+
+    @ApiModelProperty(value = "公司id,不传")
+    private Long companyId;
+
+    @ApiModelProperty(value = "视频id-管理端传参")
+    private List<Long> videoIdList;
+
+}
+

+ 78 - 0
fs-service/src/main/java/com/fs/store/param/h5/FsUserPageListParam.java

@@ -0,0 +1,78 @@
+package com.fs.store.param.h5;
+
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Set;
+
+
+@Data
+public class FsUserPageListParam implements Serializable {
+
+    @ApiModelProperty(value = "页码,默认为1", required = true)
+    private Integer pageNum = 1;
+
+    @ApiModelProperty(value = "页大小,默认为10", required = true)
+    private Integer pageSize = 10;
+
+    @ApiModelProperty(value = "模糊搜索,可以通过微信名称、电话来模糊匹配")
+    private String keyword;
+
+    @ApiModelProperty(value = "用户id,不用传")
+    private Long userId;
+
+    @ApiModelProperty(value = "是否是黑名单,默认是false", required = true)
+    private Boolean isBlack = false;
+
+    @ApiModelProperty(value = "销售id")
+    private String companyUserId;
+
+    @ApiModelProperty(value = "注册时间-开始")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private String registerStartTime;
+
+    @ApiModelProperty(value = "注册时间-结束")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private String registerEndTime;
+
+    @ApiModelProperty(value = "标签")
+    private String[] tagIds;
+
+    @ApiModelProperty(value = "tab序号,0全部;1今日新增;2今日完播;3未看过课")
+    private String tabValue;
+
+    @ApiModelProperty(value = "看课状态,0全部;1未看过课;2正常看课;3停止看课")
+    private String watchCourseType;
+
+    @ApiModelProperty(value = "缺课状态,0全部;1-已缺课;2-未缺课")
+    private String missCourseStatus;
+
+    @ApiModelProperty(value = "排序,0-按注册时间晚到早;1-会员姓名0-9-A-Z")
+    private String continueMissCourseSort;
+
+    @ApiModelProperty(value = "昵称 (PC端使用)")
+    private String nickname;
+
+    @ApiModelProperty(value = "电话 (PC端使用)")
+    private String phone;
+
+    /**
+     * 公司id
+     */
+    private Long companyId;
+
+    private Set<Long> companyUserIds;
+
+    /**
+     * 销售端登录用户id(该字段用于区分之前的登录用户)
+     */
+    private Long pcLoginUserId;
+
+
+
+
+}
+

+ 28 - 0
fs-service/src/main/java/com/fs/store/param/h5/TagListParam.java

@@ -0,0 +1,28 @@
+package com.fs.store.param.h5;
+
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 标签列表 入参对象
+ */
+@Data
+public class TagListParam implements Serializable {
+
+    @ApiModelProperty(value = "页码,默认为1", required = true)
+    private Integer pageNum =1;
+
+    @ApiModelProperty(value = "页大小,默认为10", required = true)
+    private Integer pageSize = 10;
+
+    @ApiModelProperty(value = "用户id,不用传")
+    private Long userId;
+
+    @ApiModelProperty(value = "模糊搜索名称,多个用逗号隔开")
+    private String keyword;
+
+}
+

+ 40 - 0
fs-service/src/main/java/com/fs/store/param/h5/UserStatisticsCommonParam.java

@@ -0,0 +1,40 @@
+package com.fs.store.param.h5;
+
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 课程分析查询-入参
+ */
+@Data
+@Accessors(chain = true)
+public class UserStatisticsCommonParam implements Serializable {
+
+    @ApiModelProperty(value = "登录用户id,不传")
+    private Long userId;
+
+    @ApiModelProperty(value = "开始时间")
+    private String startTime;
+
+    @ApiModelProperty(value = "结束时间")
+    private String endTime;
+
+    @ApiModelProperty(value = "营期id")
+    private String periodId;
+
+    @ApiModelProperty(value = "视频id")
+    private String videoId;
+
+    @ApiModelProperty(value = "公司id")
+    private Long companyId;
+
+    @ApiModelProperty(value = "群管(二级销售)id")
+    private String companyUserId;
+
+
+}
+

+ 26 - 0
fs-service/src/main/java/com/fs/store/vo/h5/CompanyUserSummaryCountVO.java

@@ -0,0 +1,26 @@
+package com.fs.store.vo.h5;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+/**
+ *
+ */
+@Data
+@ApiModel
+public class CompanyUserSummaryCountVO {
+
+    @ApiModelProperty(value = "会员总数")
+    private int userTotal;
+
+    @ApiModelProperty(value = "今日新增会员")
+    private int todayNewUser;
+
+    @ApiModelProperty(value = "会员红包数")
+    private int userRedPacketNum;
+
+    @ApiModelProperty(value = "新会员红包金额")
+    private int todayUserRedPacketAmount;
+
+
+}

+ 19 - 0
fs-service/src/main/java/com/fs/store/vo/h5/CompanyUserTagListVO.java

@@ -0,0 +1,19 @@
+package com.fs.store.vo.h5;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 用户标签 返回对象
+ */
+@Data
+@ApiModel
+public class CompanyUserTagListVO {
+    @ApiModelProperty(value = "标签id")
+    private Long tagId;
+
+    @ApiModelProperty(value = "标签名称")
+    private String tagName;
+
+}

+ 27 - 0
fs-service/src/main/java/com/fs/store/vo/h5/FsCourseRankingVO.java

@@ -0,0 +1,27 @@
+package com.fs.store.vo.h5;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.math.BigDecimal;
+
+/**
+ * 首页-销售数据排行榜
+ */
+@Data
+@ApiModel
+@Accessors(chain = true)
+public class FsCourseRankingVO {
+
+    @ApiModelProperty(value = "课程名称")
+    private String videoName;
+
+    @ApiModelProperty(value = "完播率")
+    private BigDecimal completeRate;
+
+    @ApiModelProperty(value = "正确率")
+    private BigDecimal answerRightRate;
+
+}

+ 34 - 0
fs-service/src/main/java/com/fs/store/vo/h5/FsUserCountVO.java

@@ -0,0 +1,34 @@
+package com.fs.store.vo.h5;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 用户相关数据统计
+ */
+@Data
+@ApiModel
+public class FsUserCountVO {
+
+    @ApiModelProperty(value = "答题次数")
+    private int answerTime;
+
+    @ApiModelProperty(value = "答题正确次数")
+    private int answerRightTime;
+
+    @ApiModelProperty(value = "答题红包数")
+    private int answerRedPacketTime;
+
+    @ApiModelProperty(value = "答题红包金额")
+    private int answerRedPacketAmount;
+
+    @ApiModelProperty(value = "完播次数")
+    private int completeWatchCount;
+
+    @ApiModelProperty(value = "观看次数")
+    private int watchTimes;
+
+
+
+}

+ 34 - 0
fs-service/src/main/java/com/fs/store/vo/h5/FsUserGraphicStatisticsVO.java

@@ -0,0 +1,34 @@
+package com.fs.store.vo.h5;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * 首页-漏斗图统计
+ */
+@Data
+@ApiModel
+@Accessors(chain = true)
+public class FsUserGraphicStatisticsVO {
+
+    @ApiModelProperty(value = "统计名称")
+    private String name;
+
+    @ApiModelProperty(value = "显示文本值")
+    private int contextValue;
+
+    @ApiModelProperty(value = "统计值")
+    private int value;
+
+    public FsUserGraphicStatisticsVO() {
+
+    }
+
+    public FsUserGraphicStatisticsVO(String name, int contextValue, int value) {
+        this.name = name;
+        this.contextValue = contextValue;
+        this.value = value;
+    }
+}

+ 94 - 0
fs-service/src/main/java/com/fs/store/vo/h5/FsUserPageListVO.java

@@ -0,0 +1,94 @@
+package com.fs.store.vo.h5;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 用户分页列表返回对象
+ */
+@Data
+@ApiModel
+public class FsUserPageListVO {
+
+    @ApiModelProperty(value = "用户id")
+    private Long userId;
+
+    @ApiModelProperty(value = "用户头像")
+    private String avatar;
+
+    @ApiModelProperty(value = "用户昵称")
+    private String nickname;
+
+    @ApiModelProperty(value = "手机号码")
+    private String phone;
+
+    @ApiModelProperty(value = "状态:1为正常,0为禁止")
+    private Integer status;
+
+    @ApiModelProperty(value = "公司id")
+    private Long companyId;
+
+    @ApiModelProperty(value = "销售id(目前的登录用户id)")
+    private Long companyUserId;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty(value = "注册时间")
+    private Date createTime;
+
+    @ApiModelProperty(value = "看课数量")
+    private Long watchCourseCount;
+
+    @ApiModelProperty(value = "缺课数量")
+    private Long missCourseCount;
+
+    @ApiModelProperty(value = "缺课状态,1-已缺课;2-未缺课")
+    private Long missCourseStatus;
+
+    @ApiModelProperty(value = "参与营期数量")
+    private Long partCourseCount;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty(value = "最后一次看课时间")
+    private Date lastWatchDate;
+
+    @ApiModelProperty(value = "用户状态,1-正常;2-停止;3-未看")
+    private Long courseCountStatus;
+
+    @ApiModelProperty(value = "停课天数")
+    private Long stopWatchDays;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty(value = "完播时间")
+    private Date completeWatchDate;
+
+    @ApiModelProperty(value = "标签ids,多个用逗号隔开")
+    private String tagIds;
+
+    @ApiModelProperty(value = "标签名称")
+    private String tag;
+
+    @ApiModelProperty(value = "销售名称")
+    private String companyUserNickName;
+
+    @ApiModelProperty(value = "备注")
+    private String remark;
+
+    @ApiModelProperty(value = "是否属于当前销售")
+    private int isCurrentCompanyUser;
+
+    /**
+     * 是否宠粉
+     */
+    private Integer isRepeat;
+
+    @ApiModelProperty(value = "是否是重粉,1-是,0-否")
+    private int isRepeatFans;
+
+    @ApiModelProperty(value = "重粉所属销售,多个用逗号隔开")
+    private String repeatCompanyUserName;
+
+}

+ 27 - 0
fs-service/src/main/java/com/fs/store/vo/h5/FsUserRankingVO.java

@@ -0,0 +1,27 @@
+package com.fs.store.vo.h5;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.math.BigDecimal;
+
+/**
+ * 首页-销售数据排行榜
+ */
+@Data
+@ApiModel
+@Accessors(chain = true)
+public class FsUserRankingVO {
+
+    @ApiModelProperty(value = "销售名称")
+    private String userName;
+
+    @ApiModelProperty(value = "完播率")
+    private BigDecimal completeRate;
+
+    @ApiModelProperty(value = "正确率")
+    private BigDecimal answerRightRate;
+
+}

+ 62 - 0
fs-service/src/main/java/com/fs/store/vo/h5/FsUserStatisticsVO.java

@@ -0,0 +1,62 @@
+package com.fs.store.vo.h5;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.math.BigDecimal;
+
+/**
+ * 用户数据 汇总统计(首页-课程/答题/红包等数据)
+ */
+@Data
+@ApiModel
+@Accessors(chain = true)
+public class FsUserStatisticsVO {
+
+    @ApiModelProperty(value = "课程统计-观看人数")
+    private int courseWatchNum;
+
+    @ApiModelProperty(value = "课程统计-完播人数")
+    private int courseCompleteNum;
+
+    @ApiModelProperty(value = "课程统计-完播率")
+    private int courseCompleteRate;
+
+
+    @ApiModelProperty(value = "答题人数")
+    private int answerNum;
+
+    @ApiModelProperty(value = "正确人数")
+    private int answerRightNum;
+
+    @ApiModelProperty(value = "正确率")
+    private int answerRightRate;
+
+
+    @ApiModelProperty(value = "答题红包数")
+    private int redPacketNum;
+
+    @ApiModelProperty(value = "答题红包金额")
+    private BigDecimal redPacketAmount;
+
+    @ApiModelProperty(value = "昨日数据,只有当开始时间和结束时间是今日时此对象才有值")
+    private FsUserStatisticsVO yesterdayVO;
+
+//    @ApiModelProperty(value = "新会员奖励数")
+//    private int newUserRedPacketNum;
+//
+//    @ApiModelProperty(value = "新会员奖励金额")
+//    private int newUserRedPacketAmount;
+
+    @ApiModelProperty(value = "详情-课程营期数")
+    private int courseNum;
+
+    @ApiModelProperty(value = "详情-课程数")
+    private int videoNum;
+
+    @ApiModelProperty(value = "详情-课程参与会员")
+    private int courseUserNum;
+
+}

+ 19 - 0
fs-service/src/main/java/com/fs/store/vo/h5/FsUserSummaryCountTagVO.java

@@ -0,0 +1,19 @@
+package com.fs.store.vo.h5;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 用户数据 汇总统计(首页-标签)
+ */
+@Data
+@ApiModel
+public class FsUserSummaryCountTagVO {
+
+    @ApiModelProperty(value = "标签统计")
+    private String tagName;
+
+    @ApiModelProperty(value = "相关人数")
+    private int number;
+}

+ 25 - 0
fs-service/src/main/java/com/fs/store/vo/h5/FsUserSummaryCountVO.java

@@ -0,0 +1,25 @@
+package com.fs.store.vo.h5;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 用户数据 汇总统计(首页)
+ */
+@Data
+@ApiModel
+public class FsUserSummaryCountVO {
+
+    @ApiModelProperty(value = "会员总数")
+    private int userTotal;
+
+    @ApiModelProperty(value = "今日新增会员")
+    private int todayNewUser;
+
+    @ApiModelProperty(value = "标签统计")
+    private List<FsUserSummaryCountTagVO> tagList;
+
+}

+ 34 - 0
fs-service/src/main/java/com/fs/store/vo/h5/UserDetailsVO.java

@@ -0,0 +1,34 @@
+package com.fs.store.vo.h5;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 用户会员详情 输出参数
+ */
+@Data
+@ApiModel
+public class UserDetailsVO {
+
+    @ApiModelProperty(value = "答题次数")
+    private int answerTime;
+
+    @ApiModelProperty(value = "答题正确次数")
+    private int answerRightTime;
+
+    @ApiModelProperty(value = "答题红包数")
+    private int answerRedPacketTime;
+
+    @ApiModelProperty(value = "答题红包金额")
+    private int answerRedPacketAmount;
+
+    @ApiModelProperty(value = "完播次数")
+    private int completeWatchCount;
+
+    @ApiModelProperty(value = "观看次数")
+    private int watchTimes;
+
+
+
+}

+ 20 - 0
fs-service/src/main/java/com/fs/store/vo/h5/UserListCountVO.java

@@ -0,0 +1,20 @@
+package com.fs.store.vo.h5;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 用户列表查询数量统计
+ */
+@Data
+@ApiModel
+public class UserListCountVO {
+
+    @ApiModelProperty(value = "人员状态")
+    private String status;
+
+    @ApiModelProperty(value = "人员状态对应的数量")
+    private Integer num;
+
+}

+ 20 - 0
fs-service/src/main/java/com/fs/store/vo/h5/UserListPageVO.java

@@ -0,0 +1,20 @@
+package com.fs.store.vo.h5;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 用户人员数量统计返回对象
+ */
+@Data
+@ApiModel
+public class UserListPageVO {
+
+    @ApiModelProperty(value = "会员数量")
+    private int number;
+
+    @ApiModelProperty(value = "黑名单数量")
+    private int blackNum;
+
+}

+ 2 - 0
fs-service/src/main/resources/application-config-dev.yml

@@ -64,4 +64,6 @@ tencent_cloud_config:
 cloud_host:
   company_name: 润天
 
+headerImg:
+  imgUrl: https://jz-cos-1356808054.cos.ap-chengdu.myqcloud.com/fs/20250515/0877754b59814ea8a428fa3697b20e68.png
 

+ 2 - 0
fs-service/src/main/resources/application-config-druid-hcl.yml

@@ -74,4 +74,6 @@ cloud_host:
 headerImg:
   imgUrl: https://jz-cos-1356808054.cos.ap-chengdu.myqcloud.com/fs/20250515/0877754b59814ea8a428fa3697b20e68.png
 
+headerImg:
+  imgUrl: https://jz-cos-1356808054.cos.ap-chengdu.myqcloud.com/fs/20250515/0877754b59814ea8a428fa3697b20e68.png
 

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

@@ -70,7 +70,7 @@ tmp_secret_config:
   proxy: fs
 cloud_host:
   company_name: 九州在线
-#看课授权时显示的头像
 headerImg:
-  imgUrl: https://jiuzhouzaixian.obs.cn-southwest-2.myhuaweicloud.com/fs/20250516/1747361877816.png
+  imgUrl: https://jz-cos-1356808054.cos.ap-chengdu.myqcloud.com/fs/20250515/0877754b59814ea8a428fa3697b20e68.png
+
 

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

@@ -53,6 +53,8 @@ nuonuo:
   key: 10924508
   secret: A2EB20764D304D16
 
+headerImg:
+  imgUrl: https://jz-cos-1356808054.cos.ap-chengdu.myqcloud.com/fs/20250515/0877754b59814ea8a428fa3697b20e68.png
 
 
 

+ 98 - 0
fs-service/src/main/resources/mapper/company/CompanyTagMapper.xml

@@ -0,0 +1,98 @@
+<?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.company.mapper.CompanyTagMapper">
+
+    <resultMap type="CompanyTag" id="CompanyTagResult">
+        <result property="tagId"    column="tag_id"    />
+        <result property="companyId"    column="company_id"    />
+        <result property="tag"    column="tag"    />
+        <result property="createTime"    column="create_time"    />
+    </resultMap>
+
+    <sql id="selectCompanyTagVo">
+        select tag_id, company_id, tag, create_time from company_tag
+    </sql>
+
+    <select id="selectCompanyTagList" parameterType="CompanyTag" resultMap="CompanyTagResult">
+        <include refid="selectCompanyTagVo"/>
+        <where>
+            <if test="companyId != null "> and company_id = #{companyId}</if>
+            <if test="tag != null  and tag != ''"> and tag = #{tag}</if>
+        </where>
+    </select>
+
+    <select id="selectCompanyTagById" parameterType="Long" resultMap="CompanyTagResult">
+        <include refid="selectCompanyTagVo"/>
+        where tag_id = #{tagId}
+    </select>
+
+    <!-- 查询标签列表 -->
+    <select id="selectCompanyTagListByMap" resultType="com.fs.company.domain.CompanyTag">
+        select ct.* from company_tag ct
+        <where>
+            <if test="params.keyword != null and params.keyword.length > 0">
+                and
+                <foreach collection="params.keyword" item="item"  open="(" separator="or" close=")">
+                    ct.tag like concat('%',#{item},'%')
+                </foreach>
+            </if>
+            <if test="params.companyId != null">
+                and ct.company_id = #{params.companyId}
+            </if>
+            <if test="params.tagName != null">
+                and ct.tag = #{params.tagName}
+            </if>
+        </where>
+    </select>
+
+    <!-- 查询用户标签列表 -->
+    <select id="selectCompanyTagListByUserId" resultType="com.fs.company.domain.CompanyTag">
+        select ct.* from company_tag ct
+        inner join company_tag_user ctu on ctu.company_id = ct.company_id and find_in_set(ct.tag_id, ctu.tag_ids) > 0
+        where ctu.user_id = #{userId}
+    </select>
+    <select id="findUserTagByUserId" resultType="java.lang.String">
+        select tag_ids from company_tag_user where user_id = ${userId} limit 1
+    </select>
+    <select id="queryAllTagMap" resultType="java.util.Map">
+        select tag_id,tag from company_tag
+    </select>
+
+    <insert id="insertCompanyTag" parameterType="CompanyTag" useGeneratedKeys="true" keyProperty="tagId">
+        insert into company_tag
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="companyId != null">company_id,</if>
+            <if test="tag != null">tag,</if>
+            <if test="createTime != null">create_time,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="companyId != null">#{companyId},</if>
+            <if test="tag != null">#{tag},</if>
+            <if test="createTime != null">#{createTime},</if>
+         </trim>
+    </insert>
+
+    <update id="updateCompanyTag" parameterType="CompanyTag">
+        update company_tag
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="companyId != null">company_id = #{companyId},</if>
+            <if test="tag != null">tag = #{tag},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+        </trim>
+        where tag_id = #{tagId}
+    </update>
+
+    <delete id="deleteCompanyTagById" parameterType="Long">
+        delete from company_tag where tag_id = #{tagId}
+    </delete>
+
+    <delete id="deleteCompanyTagByIds" parameterType="String">
+        delete from company_tag where tag_id in
+        <foreach item="tagId" collection="array" open="(" separator="," close=")">
+            #{tagId}
+        </foreach>
+    </delete>
+
+</mapper>

+ 117 - 0
fs-service/src/main/resources/mapper/company/CompanyTagUserMapper.xml

@@ -0,0 +1,117 @@
+<?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.company.mapper.CompanyTagUserMapper">
+
+    <resultMap type="CompanyTagUser" id="CompanyTagUserResult">
+        <result property="id"    column="id"    />
+        <result property="tagIds"    column="tag_ids"    />
+        <result property="userId"    column="user_id"    />
+        <result property="companyId"    column="company_id"    />
+        <result property="companyUserId"    column="company_user_id"    />
+        <result property="createTime"    column="create_time"    />
+    </resultMap>
+
+    <sql id="selectCompanyTagUserVo">
+        select id, tag_ids, user_id, company_id, company_user_id, create_time from company_tag_user
+    </sql>
+
+    <select id="selectCompanyTagUserList" parameterType="CompanyTagUser" resultMap="CompanyTagUserResult">
+        <include refid="selectCompanyTagUserVo"/>
+        <where>
+            <if test="tagIds != null  and tagIds != ''"> and tag_ids like concat('%',#{tagIds},'%')</if>
+            <if test="userId != null "> and user_id = #{userId}</if>
+            <if test="companyId != null "> and company_id = #{companyId}</if>
+            <if test="companyUserId != null "> and company_user_id = #{companyUserId}</if>
+        </where>
+    </select>
+
+    <select id="selectCompanyTagUserById" parameterType="Long" resultMap="CompanyTagUserResult">
+        <include refid="selectCompanyTagUserVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertCompanyTagUser" parameterType="CompanyTagUser" useGeneratedKeys="true" keyProperty="id">
+        insert into company_tag_user
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="tagIds != null">tag_ids,</if>
+            <if test="userId != null">user_id,</if>
+            <if test="companyId != null">company_id,</if>
+            <if test="companyUserId != null">company_user_id,</if>
+            <if test="createTime != null">create_time,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="tagIds != null">#{tagIds},</if>
+            <if test="userId != null">#{userId},</if>
+            <if test="companyId != null">#{companyId},</if>
+            <if test="companyUserId != null">#{companyUserId},</if>
+            <if test="createTime != null">#{createTime},</if>
+         </trim>
+    </insert>
+
+    <update id="updateCompanyTagUser" parameterType="CompanyTagUser">
+        update company_tag_user
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="tagIds != null">tag_ids = #{tagIds},</if>
+            <if test="userId != null">user_id = #{userId},</if>
+            <if test="companyId != null">company_id = #{companyId},</if>
+            <if test="companyUserId != null">company_user_id = #{companyUserId},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteCompanyTagUserById" parameterType="Long">
+        delete from company_tag_user where id = #{id}
+    </delete>
+
+    <delete id="deleteCompanyTagUserByIds" parameterType="String">
+        delete from company_tag_user where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+
+    <!-- 删除用户标签 -->
+    <delete id="deleteCompanyTagUserByMap">
+        delete from company_tag_user
+        where user_id = #{params.userId} and company_id = #{params.companyId} and company_user_id = #{params.companyUserId}
+    </delete>
+
+    <select id="getTagList" resultType="com.fs.store.vo.h5.CompanyUserTagListVO">
+        SELECT distinct
+        company_tag.tag as tagName,
+        company_tag.tag_id
+        FROM
+        company_tag_user
+        right JOIN company_tag ON FIND_IN_SET( company_tag.tag_id, company_tag_user.tag_ids ) > 0
+        WHERE 1 = 1
+        <if test="userIds != null and userIds.size() > 0 ">
+        AND company_tag_user.company_user_id in
+        <foreach item="item" collection="userIds" open="(" separator="," close=")">
+              #{item}
+        </foreach>
+        </if>
+        <if test="keywords != null and keywords.length > 0 ">
+            and
+            <foreach item="item" collection="keywords" open="(" separator="or" close=")">
+                company_tag.tag like concat('%',#{item},'%')
+            </foreach>
+        </if>
+    </select>
+
+    <!-- 根据条件查询标签下用户 -->
+    <select id="selectUserListByMap" resultType="com.fs.company.vo.CompanyTagUserVO">
+        select
+            fu.user_id,
+            fu.nickname as userName
+        from company_tag_user ctu
+        inner join fs_user fu on fu.user_id = ctu.user_id
+        where ctu.company_id = #{params.companyId} and
+        <foreach collection="params.tagIds" item="tagId" open="(" separator="or" close=")">
+            find_in_set(#{tagId}, ctu.tag_ids)
+        </foreach>
+    </select>
+
+</mapper>

+ 10 - 0
fs-service/src/main/resources/mapper/company/CompanyUserMapper.xml

@@ -250,6 +250,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         </foreach>
 
     </select>
+    <select id="selectAllCompanyUserAndSelf" resultType="CompanyUser">
+        SELECT
+            *
+        FROM
+            company_user
+        WHERE
+            del_flag = 0
+          AND (company_user.user_id = #{userId} or company_user.parent_id = #{userId})
+    </select>
+
 
 
     <sql id="selectUserVo">

+ 28 - 0
fs-service/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml

@@ -381,6 +381,34 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
           and fcwl.camp_period_time is not NULL
         ]]>
     </select>
+    <select id="getWatchLogByFsUser" resultType="com.fs.course.domain.FsCourseWatchLog">
+        SELECT
+            log_id,
+            user_id,
+            video_id,
+            log_type,
+            create_time,
+            update_time,
+            duration,
+            company_user_id,
+            company_id,
+            course_id,
+            send_type,
+            reward_type,
+            last_heartbeat_time,
+            sop_id,
+            finish_time,
+            send_finish_msg,
+            camp_period_time
+        FROM
+            fs_course_watch_log
+        WHERE
+            send_type = 1
+          AND video_id = #{videoId}
+          AND user_id = #{fsUserId}
+          AND company_user_id = #{companyUserId}
+    </select>
+
 
     <update id="batchUpdateWatchLog" parameterType="java.util.List">
         UPDATE fs_course_watch_log

+ 90 - 0
fs-service/src/main/resources/mapper/course/FsUserCompanyUserMapper.xml

@@ -0,0 +1,90 @@
+<?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.FsUserCompanyUserMapper">
+
+    <resultMap type="FsUserCompanyUser" id="FsUserCompanyUserResult">
+        <result property="id"    column="id"    />
+        <result property="userId"    column="user_id"    />
+        <result property="companyUserId"    column="company_user_id"    />
+        <result property="companyId"    column="company_id"    />
+        <result property="isRepeatFans"    column="is_repeat_fans"    />
+    </resultMap>
+
+    <sql id="selectFsUserCompanyUserVo">
+        select id, user_id, company_user_id, company_id, is_repeat_fans from fs_user_company_user
+    </sql>
+
+    <select id="selectFsUserCompanyUserList" parameterType="FsUserCompanyUser" resultMap="FsUserCompanyUserResult">
+        <include refid="selectFsUserCompanyUserVo"/>
+        <where>
+            <if test="userId != null "> and user_id = #{userId}</if>
+            <if test="companyUserId != null "> and company_user_id = #{companyUserId}</if>
+            <if test="companyId != null "> and company_id = #{companyId}</if>
+            <if test="isRepeatFans != null "> and is_repeat_fans = #{isRepeatFans}</if>
+        </where>
+    </select>
+
+    <select id="selectFsUserCompanyUserById" parameterType="Long" resultMap="FsUserCompanyUserResult">
+        <include refid="selectFsUserCompanyUserVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertFsUserCompanyUser" parameterType="FsUserCompanyUser" useGeneratedKeys="true" keyProperty="id">
+        insert into fs_user_company_user
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="id != null">id,</if>
+            <if test="userId != null">user_id,</if>
+            <if test="companyUserId != null">company_user_id,</if>
+            <if test="companyId != null">company_id,</if>
+            <if test="isRepeatFans != null">is_repeat_fans,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="id != null">#{id},</if>
+            <if test="userId != null">#{userId},</if>
+            <if test="companyUserId != null">#{companyUserId},</if>
+            <if test="companyId != null">#{companyId},</if>
+            <if test="isRepeatFans != null">#{isRepeatFans},</if>
+         </trim>
+    </insert>
+
+    <update id="updateFsUserCompanyUser" parameterType="FsUserCompanyUser">
+        update fs_user_company_user
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="userId != null">user_id = #{userId},</if>
+            <if test="companyUserId != null">company_user_id = #{companyUserId},</if>
+            <if test="companyId != null">company_id = #{companyId},</if>
+            <if test="isRepeatFans != null">is_repeat_fans = #{isRepeatFans},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteFsUserCompanyUserById" parameterType="Long">
+        delete from fs_user_company_user where id = #{id}
+    </delete>
+
+    <delete id="deleteFsUserCompanyUserByIds" parameterType="String">
+        delete from fs_user_company_user where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+
+    <select id="selectRepeatCompanyUserName" resultType="FsUserCompanyUser">
+        SELECT
+            GROUP_CONCAT( company_user.nick_name ) AS repeatCompanyUserName,
+            fs_user_company_user.user_id
+        FROM
+            fs_user_company_user
+                LEFT JOIN company_user ON company_user.user_id = fs_user_company_user.company_user_id
+        <where>
+            fs_user_company_user.user_id IN
+            <foreach item="userId" collection="userIds" open="(" separator="," close=")">
+                #{userId}
+            </foreach>
+        </where>
+        GROUP BY
+            fs_user_company_user.user_id
+    </select>
+</mapper>

+ 114 - 35
fs-service/src/main/resources/mapper/course/FsUserCourseVideoMapper.xml

@@ -1,7 +1,7 @@
 <?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">
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.fs.course.mapper.FsUserCourseVideoMapper">
 
     <resultMap type="FsUserCourseVideo" id="FsUserCourseVideoResult">
@@ -32,11 +32,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="packageJson"    column="package_json"    />
         <result property="isTranscode"    column="is_transcode"    />
         <result property="transcodeFileKey"    column="transcode_file_key"    />
-        <result property="isFirst"    column="is_first"    />
+        <result property="viewStartTime"    column="view_start_time"    />
+        <result property="viewEndTime"    column="view_end_time"    />
+        <result property="lastJoinTime"    column="last_join_time"    />
     </resultMap>
 
     <sql id="selectFsUserCourseVideoVo">
-        select video_id,line_one,package_json,is_first,is_transcode,transcode_file_key,file_size,file_key,round,red_packet_money,line_two,upload_type,line_three, file_id,file_name,is_del, title, description, video_url, thumbnail, duration, update_time, create_time, talent_id, course_id, status, course_sort, question_bank_id from fs_user_course_video
+        select * from fs_user_course_video
     </sql>
 
     <select id="selectFsUserCourseVideoList" parameterType="FsUserCourseVideo" resultMap="FsUserCourseVideoResult">
@@ -90,8 +92,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="packageJson != null">package_json,</if>
             <if test="isTranscode != null">is_transcode,</if>
             <if test="transcodeFileKey != null">transcode_file_key,</if>
-            <if test="isFirst != null">is_first,</if>
-         </trim>
+            <if test="viewStartTime != null">view_start_time,</if>
+            <if test="viewEndTime != null">view_end_time,</if>
+            <if test="lastJoinTime != null">last_join_time,</if>
+        </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="fileId != null">#{fileId},</if>
             <if test="title != null">#{title},</if>
@@ -119,8 +123,52 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="packageJson != null">#{packageJson},</if>
             <if test="isTranscode != null">#{isTranscode},</if>
             <if test="transcodeFileKey != null">#{transcodeFileKey},</if>
-            <if test="isFirst != null">#{isFirst},</if>
-         </trim>
+            <if test="viewStartTime != null">#{viewStartTime},</if>
+            <if test="viewEndTime != null">#{viewEndTime},</if>
+            <if test="lastJoinTime != null">#{lastJoinTime},</if>
+        </trim>
+    </insert>
+    <insert id="insertBatchFsUserCourseVideo" parameterType="FsUserCourseVideo" useGeneratedKeys="true" keyProperty="videoId">
+        insert into fs_user_course_video
+        (
+        title,
+        video_url,
+        thumbnail,
+        duration,
+        course_id,
+        status,
+        course_sort,
+        file_name,
+        question_bank_id,
+        line_one,
+        line_two,
+        line_three,
+        red_packet_money,
+        file_size,
+        file_key,
+        is_transcode
+        )
+        values
+        <foreach collection="collect" item="item" separator=",">
+            (
+            #{item.title},
+            #{item.videoUrl},
+            #{item.thumbnail},
+            #{item.duration},
+            #{item.courseId},
+            #{item.status},
+            #{item.courseSort},
+            #{item.fileName},
+            #{item.questionBankId},
+            #{item.lineOne},
+            #{item.lineTwo},
+            #{item.lineThree},
+            #{item.redPacketMoney},
+            #{item.fileSize},
+            #{item.fileKey},
+            #{item.isTranscode}
+            )
+        </foreach>
     </insert>
 
     <update id="updateFsUserCourseVideo" parameterType="FsUserCourseVideo">
@@ -152,7 +200,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="packageJson != null">package_json = #{packageJson},</if>
             <if test="isTranscode != null">is_transcode = #{isTranscode},</if>
             <if test="transcodeFileKey != null">transcode_file_key = #{transcodeFileKey},</if>
-            <if test="isFirst != null">is_first = #{isFirst},</if>
+            <if test="viewStartTime != null">view_start_time = #{viewStartTime},</if>
+            <if test="viewEndTime != null">view_end_time = #{viewEndTime},</if>
+            <if test="lastJoinTime != null">last_join_time = #{lastJoinTime},</if>
         </trim>
         where video_id = #{videoId}
     </update>
@@ -167,31 +217,60 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{videoId}
         </foreach>
     </update>
+    <update id="updates">
+        update fs_user_course_video set view_start_time = #{viewStartTime},view_end_time = #{viewEndTime},last_join_time = #{lastJoinTime} where video_id in
+        <foreach item="videoId" collection="ids" open="(" separator="," close=")">
+            #{videoId}
+        </foreach>
+    </update>
 
-<!--    <select id="selectFsUserCourseVideoPageList" resultType="com.fs.course.param.newfs.FsUserCourseVideoPageListVO">-->
-<!--        SELECT-->
-<!--        video.video_id,-->
-<!--        video.title,-->
-<!--        video.description,-->
-<!--        video.video_url,-->
-<!--        video.thumbnail,-->
-<!--        video.duration,-->
-<!--        video.create_time,-->
-<!--        video.course_id,-->
-<!--        video.STATUS,-->
-<!--        video.course_sort,-->
-<!--        course.course_name-->
-<!--        FROM `fs_user_course_video` video-->
-<!--        LEFT JOIN fs_user_course course ON video.course_id = course.course_id-->
-<!--        where 1 = 1-->
-<!--        and course.is_del = 0-->
-<!--        AND FIND_IN_SET(#{companyId}, course.company_ids)-->
-<!--        <if test="courseId != null and courseId !='' ">-->
-<!--            AND video.course_id = #{courseId}-->
-<!--        </if>-->
-<!--        <if test="keyword != null and keyword !='' ">-->
-<!--            AND video.title LIKE concat('%',#{keyword},'%')-->
-<!--        </if>-->
-<!--        order by video.course_sort-->
-<!--    </select>-->
+    <select id="selectFsUserCourseVideoPageList" resultType="com.fs.course.vo.newfs.FsUserCourseVideoPageListVO">
+        SELECT
+        DISTINCT video.video_id,
+        video.title,
+        video.description,
+        video.video_url,
+        video.thumbnail,
+        video.duration,
+        video.create_time,
+        video.course_id,
+        video.STATUS,
+        video.course_sort,
+        course.course_name,
+        fcpd.period_id,
+        fcpd.id
+        FROM `fs_user_course_video` video
+        left join fs_user_course_period_days fcpd on fcpd.video_id = video.video_id
+        left join fs_user_course_period fcp on fcp.period_id = fcpd.period_id
+        LEFT JOIN fs_user_course course ON video.course_id = course.course_id
+        where course.is_del = 0
+        AND FIND_IN_SET(#{companyId}, fcp.company_id)
+        <if test="periodId != null and periodId !='' ">
+            AND fcpd.period_id = #{periodId}
+        </if>
+        <if test="keyword != null and keyword !='' ">
+            AND video.title LIKE concat('%',#{keyword},'%')
+        </if>
+        order by video.course_sort
+    </select>
+
+    <select id="selectVideoListByMap" resultType="com.fs.his.vo.OptionsVO">
+        select distinct
+        ucv.video_id dictValue,
+        ucv.title dictLabel
+        from fs_user_course_video ucv
+        left join fs_user_course_period_days ucpd on ucpd.video_id = ucv.video_id
+        <where>
+            <if test="params.name != null and params.name != ''">
+                ucv.title like concat('%', #{params.name}, '%')
+            </if>
+            <if test="params.periodId != null">
+                and ucpd.period_id = #{params.periodId}
+            </if>
+        </where>
+    </select>
+
+    <update id="updateRedPacketMoney">
+        update fs_user_course_video set red_packet_money = #{redPacketMoney} where video_id = #{videoId}
+    </update>
 </mapper>

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

@@ -180,6 +180,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         GROUP BY
         fs_course_answer_logs.video_id
     </select>
+    <select id="selectFsUserById" parameterType="Long" resultMap="FsUserResult">
+        <include refid="selectFsUserVo"/>
+        where user_id = #{userId}
+    </select>
+
 
 
     <insert id="insertFsUser" parameterType="FsUser" useGeneratedKeys="true" keyProperty="userId">

+ 5 - 1
fs-service/src/main/resources/mapper/qw/QwExternalContactMapper.xml

@@ -317,5 +317,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         </foreach>
         group by external_user_id
     </select>
-
+    <select id="selectByGroupUser" resultType="com.fs.qw.vo.GroupUserExternalVo">
+        select id,user_id,external_user_id from qw_external_contact where external_user_id in
+        <foreach collection="ids" open="(" separator="," close=")" item="item">#{item}</foreach>
+        GROUP BY user_id,external_user_id
+    </select>
 </mapper>

+ 1 - 1
fs-user-app/src/main/java/com/fs/app/controller/CourseController.java

@@ -514,6 +514,6 @@ public class CourseController extends  AppBaseController{
     @GetMapping("/test2")
     public void test2() {
 
-        courseVideoService.updateVideoUrl();
+//        courseVideoService.updateVideoUrl();
     }
 }