Browse Source

Merge remote-tracking branch 'origin/master'

yjwang 1 week ago
parent
commit
f955122c05
100 changed files with 2559 additions and 299 deletions
  1. 3 2
      fs-admin/src/main/java/com/fs/company/controller/CompanyUserController.java
  2. 12 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseVideoController.java
  3. 6 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserTalentController.java
  4. 59 2
      fs-admin/src/main/java/com/fs/his/controller/FsUserController.java
  5. 1 0
      fs-common/src/main/java/com/fs/common/constant/FsConstants.java
  6. 6 0
      fs-company-app/src/main/java/com/fs/app/controller/AppBaseController.java
  7. 29 12
      fs-company-app/src/main/java/com/fs/app/controller/CompanyTagController.java
  8. 100 17
      fs-company-app/src/main/java/com/fs/app/controller/CompanyUserController.java
  9. 41 14
      fs-company-app/src/main/java/com/fs/app/controller/FsUserController.java
  10. 153 124
      fs-company-app/src/main/java/com/fs/app/controller/WxCompanyUserController.java
  11. 14 1
      fs-company-app/src/main/java/com/fs/app/param/CompanyUserChangeApplyParam.java
  12. 5 3
      fs-company-app/src/main/java/com/fs/app/param/CompanyUserParam.java
  13. 17 0
      fs-company-app/src/main/java/com/fs/app/param/FsUserProjectUpdateParam.java
  14. 3 3
      fs-company-app/src/main/java/com/fs/app/param/FsUserTagUpdateParam.java
  15. 22 0
      fs-company-app/src/main/java/com/fs/app/param/LoginMaWxParam.java
  16. 23 0
      fs-company-app/src/main/java/com/fs/app/param/TagProjectParam.java
  17. 76 0
      fs-company/src/main/java/com/fs/company/controller/company/CompanyUserChangeApplyController.java
  18. 23 0
      fs-company/src/main/java/com/fs/company/controller/param/CompanyUserChangeApplyAuditParam.java
  19. 10 2
      fs-company/src/main/java/com/fs/company/controller/store/FsUserController.java
  20. 8 5
      fs-doctor-app/src/main/java/com/fs/app/controller/InquiryOrderController.java
  21. 18 0
      fs-redis/src/main/java/com/fs/app/redis/RedisKeyExpirationListener.java
  22. 12 0
      fs-redis/src/main/resources/application.yml
  23. 21 0
      fs-service/src/main/java/com/fs/company/domain/CompanyUser.java
  24. 4 0
      fs-service/src/main/java/com/fs/company/domain/CompanyUserChangeApplyUser.java
  25. 2 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyTagMapper.java
  26. 2 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyTagUserMapper.java
  27. 2 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyUserMapper.java
  28. 2 0
      fs-service/src/main/java/com/fs/company/service/ICompanyTagService.java
  29. 5 0
      fs-service/src/main/java/com/fs/company/service/ICompanyTagUserService.java
  30. 2 1
      fs-service/src/main/java/com/fs/company/service/ICompanyUserChangeApplyService.java
  31. 5 2
      fs-service/src/main/java/com/fs/company/service/ICompanyUserService.java
  32. 11 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyTagServiceImpl.java
  33. 23 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyTagUserServiceImpl.java
  34. 14 9
      fs-service/src/main/java/com/fs/company/service/impl/CompanyUserChangeApplyServiceImpl.java
  35. 26 1
      fs-service/src/main/java/com/fs/company/service/impl/CompanyUserChangeApplyUserServiceImpl.java
  36. 14 2
      fs-service/src/main/java/com/fs/company/service/impl/CompanyUserServiceImpl.java
  37. 4 0
      fs-service/src/main/java/com/fs/company/vo/CompanyTagUserVO.java
  38. 9 0
      fs-service/src/main/java/com/fs/company/vo/CompanyUserChangeApplyUserVO.java
  39. 15 0
      fs-service/src/main/java/com/fs/core/config/WxOpenProperties.java
  40. 18 4
      fs-service/src/main/java/com/fs/course/domain/FsUserCompanyUser.java
  41. 6 0
      fs-service/src/main/java/com/fs/course/domain/FsUserCourseVideo.java
  42. 74 0
      fs-service/src/main/java/com/fs/course/domain/FsVideoBarrage.java
  43. 18 1
      fs-service/src/main/java/com/fs/course/mapper/FsCourseSopAppLinkMapper.java
  44. 1 1
      fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java
  45. 14 0
      fs-service/src/main/java/com/fs/course/mapper/FsUserCompanyUserMapper.java
  46. 14 6
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseCommentMapper.java
  47. 5 0
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseMapper.java
  48. 1 1
      fs-service/src/main/java/com/fs/course/mapper/FsUserTalentMapper.java
  49. 85 0
      fs-service/src/main/java/com/fs/course/mapper/FsVideoBarrageMapper.java
  50. 3 0
      fs-service/src/main/java/com/fs/course/param/BatchVideoSvae.java
  51. 46 0
      fs-service/src/main/java/com/fs/course/param/FsVideoBarrageQueryParam.java
  52. 1 3
      fs-service/src/main/java/com/fs/course/param/newfs/FsUserCourseBeMemberParam.java
  53. 4 0
      fs-service/src/main/java/com/fs/course/service/IFsCourseSopAppLinkService.java
  54. 35 7
      fs-service/src/main/java/com/fs/course/service/IFsUserCompanyUserService.java
  55. 1 1
      fs-service/src/main/java/com/fs/course/service/IFsUserCourseCommentService.java
  56. 77 0
      fs-service/src/main/java/com/fs/course/service/IFsVideoBarrageService.java
  57. 10 0
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseSopAppLinkServiceImpl.java
  58. 58 9
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCompanyUserServiceImpl.java
  59. 2 2
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseCommentServiceImpl.java
  60. 14 1
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseOrderServiceImpl.java
  61. 31 19
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseServiceImpl.java
  62. 33 13
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  63. 172 0
      fs-service/src/main/java/com/fs/course/service/impl/FsVideoBarrageServiceImpl.java
  64. 2 0
      fs-service/src/main/java/com/fs/course/vo/FsSopMyCourseLinkVO.java
  65. 2 1
      fs-service/src/main/java/com/fs/course/vo/FsUserCourseCommentReplyListUVO.java
  66. 61 0
      fs-service/src/main/java/com/fs/course/vo/FsVideoBarrageExcelVo.java
  67. 63 0
      fs-service/src/main/java/com/fs/course/vo/FsVideoBarrageVO.java
  68. 83 0
      fs-service/src/main/java/com/fs/gtPush/domain/UniPushLog.java
  69. 72 0
      fs-service/src/main/java/com/fs/gtPush/mapper/PushLogMapper.java
  70. 80 0
      fs-service/src/main/java/com/fs/gtPush/param/UniPushLogParam.java
  71. 80 0
      fs-service/src/main/java/com/fs/gtPush/service/UniPushLogService.java
  72. 178 0
      fs-service/src/main/java/com/fs/gtPush/service/impl/UniPushLogServiceImpl.java
  73. 47 0
      fs-service/src/main/java/com/fs/gtPush/vo/UniPushLogAppVo.java
  74. 8 0
      fs-service/src/main/java/com/fs/gtPush/vo/UniPushLogLastAndReadStatusVo.java
  75. 6 0
      fs-service/src/main/java/com/fs/his/config/IntegralConfig.java
  76. 54 0
      fs-service/src/main/java/com/fs/his/domain/FsIntegralCart.java
  77. 9 0
      fs-service/src/main/java/com/fs/his/domain/FsIntegralGoods.java
  78. 18 1
      fs-service/src/main/java/com/fs/his/domain/FsIntegralOrder.java
  79. 14 0
      fs-service/src/main/java/com/fs/his/domain/FsUser.java
  80. 30 0
      fs-service/src/main/java/com/fs/his/domain/FsUserProjectTag.java
  81. 15 0
      fs-service/src/main/java/com/fs/his/enums/BusinessTypeEnum.java
  82. 7 1
      fs-service/src/main/java/com/fs/his/enums/FsUserIntegralLogTypeEnum.java
  83. 15 0
      fs-service/src/main/java/com/fs/his/enums/PaymentMethodEnum.java
  84. 5 2
      fs-service/src/main/java/com/fs/his/mapper/FsArticleCateMapper.java
  85. 2 14
      fs-service/src/main/java/com/fs/his/mapper/FsArticleMapper.java
  86. 2 0
      fs-service/src/main/java/com/fs/his/mapper/FsDoctorMapper.java
  87. 2 0
      fs-service/src/main/java/com/fs/his/mapper/FsHealthTongueMapper.java
  88. 31 0
      fs-service/src/main/java/com/fs/his/mapper/FsIntegralCartMapper.java
  89. 9 2
      fs-service/src/main/java/com/fs/his/mapper/FsIntegralGoodsMapper.java
  90. 5 1
      fs-service/src/main/java/com/fs/his/mapper/FsIntegralOrderMapper.java
  91. 2 1
      fs-service/src/main/java/com/fs/his/mapper/FsUserIntegralLogsMapper.java
  92. 12 5
      fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java
  93. 19 0
      fs-service/src/main/java/com/fs/his/mapper/FsUserProjectTagMapper.java
  94. 20 0
      fs-service/src/main/java/com/fs/his/param/FsIntegralCartOrderCreateParam.java
  95. 26 0
      fs-service/src/main/java/com/fs/his/param/FsIntegralCartParam.java
  96. 0 3
      fs-service/src/main/java/com/fs/his/param/FsIntegralOrderCreateParam.java
  97. 13 0
      fs-service/src/main/java/com/fs/his/param/FsIntegralOrderDoPayParam.java
  98. 18 0
      fs-service/src/main/java/com/fs/his/param/FsIntegralOrderParam.java
  99. 5 0
      fs-service/src/main/java/com/fs/his/param/FsUserAddIntegralTemplateParam.java
  100. 19 0
      fs-service/src/main/java/com/fs/his/param/FsUserAddPointsParam.java

+ 3 - 2
fs-admin/src/main/java/com/fs/company/controller/CompanyUserController.java

@@ -11,6 +11,7 @@ import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.service.ICompanyUserService;
+import com.fs.qw.dto.UserProjectDTO;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
@@ -145,9 +146,9 @@ public class CompanyUserController extends BaseController
     @PreAuthorize("@ss.hasPermi('company:companyUser:change')")
     @Log(title = "更换会员归属", businessType = BusinessType.OTHER)
     @PostMapping("/changeCompanyUser")
-    public AjaxResult changeCompanyUser(@RequestBody List<Long> userIds, @RequestParam Long companyUserId, @RequestParam Long companyId)
+    public AjaxResult changeCompanyUser(@RequestBody List<UserProjectDTO> users, @RequestParam Long companyUserId, @RequestParam Long companyId)
     {
-        return toAjax(companyUserService.changeCompanyUser(userIds, companyUserId, companyId));
+        return toAjax(companyUserService.changeCompanyUser(users, companyUserId, companyId));
     }
     /**
      * 根据登录的用户公司获取所有的销售

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

@@ -7,11 +7,13 @@ 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.FsUserCourse;
 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.IFsUserCourseService;
 import com.fs.course.service.IFsUserCourseVideoService;
 import com.fs.his.vo.OptionsVO;
 import com.github.pagehelper.PageHelper;
@@ -39,6 +41,8 @@ public class FsUserCourseVideoController extends BaseController
 
     @Autowired
     private FsUserCourseVideoMapper fsUserCourseVideoMapper;
+    @Autowired
+    private IFsUserCourseService fsUserCourseService;
 
     /**
      * 查询课堂视频列表
@@ -87,6 +91,10 @@ public class FsUserCourseVideoController extends BaseController
         if (count>0){
             return AjaxResult.error("课程排序重复");
         }
+
+        // 设置项目ID
+        FsUserCourse fsUserCourse = fsUserCourseService.selectFsUserCourseByCourseId(fsUserCourseVideo.getCourseId());
+        fsUserCourseVideo.setProjectId(fsUserCourse.getProject());
         return toAjax(fsUserCourseVideoService.insertFsUserCourseVideo(fsUserCourseVideo));
     }
 
@@ -134,6 +142,10 @@ public class FsUserCourseVideoController extends BaseController
     }
     @PostMapping("/batchSaveVideo")
     public R batchSaveVideo(@RequestBody BatchVideoSvae vo){
+        // 设置项目ID
+        FsUserCourse fsUserCourse = fsUserCourseService.selectFsUserCourseByCourseId(vo.getCourseId());
+        vo.setProjectId(fsUserCourse.getProject());
+
         fsUserCourseVideoService.batchSaveVideo(vo);
         return R.ok();
     }

+ 6 - 0
fs-admin/src/main/java/com/fs/course/controller/FsUserTalentController.java

@@ -2,9 +2,12 @@ package com.fs.course.controller;
 
 import java.math.BigDecimal;
 import java.util.List;
+import java.util.Objects;
 
 import com.fs.common.core.domain.R;
 import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.his.utils.PhoneUtil;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -121,6 +124,9 @@ public class FsUserTalentController extends BaseController
     @GetMapping("/listBySearch")
     public R listBySearCh(FsUserTalent fsUserTalent)
     {
+        if (Objects.nonNull(fsUserTalent) && StringUtils.isNotBlank(fsUserTalent.getPhone())){
+            fsUserTalent.setPhone(PhoneUtil.encryptPhone(fsUserTalent.getPhone()));
+        }
         List<FsUserTalent> list = fsUserTalentService.selectFsUserTalentList(fsUserTalent);
         return R.ok().put("data",list);
     }

+ 59 - 2
fs-admin/src/main/java/com/fs/his/controller/FsUserController.java

@@ -3,25 +3,37 @@ package com.fs.his.controller;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
+import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.ResponseResult;
+import com.fs.common.exception.CustomException;
 import com.fs.common.utils.ParseUtils;
 import com.fs.common.utils.SecurityUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.course.service.IFsUserCompanyUserService;
 import com.fs.his.domain.FsUserAddress;
+import com.fs.his.enums.FsUserIntegralLogTypeEnum;
+import com.fs.his.param.FsUserAddIntegralTemplateParam;
+import com.fs.his.param.FsUserAddPointsParam;
 import com.fs.his.param.FsUserParam;
+import com.fs.his.service.IFsUserIntegralLogsService;
 import com.fs.his.utils.PhoneUtil;
 import com.fs.his.vo.FsUserExportListVO;
 import com.fs.his.vo.FsUserVO;
 import com.fs.his.vo.UserVo;
+import com.fs.qw.dto.UserProjectDTO;
 import com.fs.store.param.h5.FsUserPageListParam;
 import com.fs.store.vo.h5.FsUserPageListVO;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PutMapping;
@@ -47,12 +59,17 @@ import static com.fs.his.utils.PhoneUtil.*;
  * @author fs
  * @date 2023-06-07
  */
+@Slf4j
 @RestController
 @RequestMapping("/his/user")
 public class FsUserController extends BaseController
 {
     @Autowired
     private IFsUserService fsUserService;
+    @Autowired
+    private IFsUserIntegralLogsService userIntegralLogsService;
+    @Autowired
+    private IFsUserCompanyUserService userCompanyUserService;
 
     /**
      * 查询用户列表
@@ -80,6 +97,18 @@ public class FsUserController extends BaseController
         return getDataTable(list);
     }
 
+    @PreAuthorize("@ss.hasPermi('his:user:list')")
+    @GetMapping("/listProject")
+    public TableDataInfo listProject(FsUser fsUser)
+    {
+        startPage();
+        List<FsUserVO> list = fsUserService.selectFsUserVOListByProject(fsUser);
+        for (FsUserVO vo : list){
+            vo.setPhone(ParseUtils.parsePhone(vo.getPhone()));
+        }
+        return getDataTable(list);
+    }
+
     /**
      * 导出用户列表
      */
@@ -171,6 +200,17 @@ public class FsUserController extends BaseController
         return toAjax(fsUserService.deleteFsUserByUserIds(userIds));
     }
 
+    /**
+     * 删除微信用户和销售关系信息
+     */
+    @PreAuthorize("@ss.hasPermi('his:userCompanyUser:remove')")
+    @Log(title = "微信用户和销售关系", businessType = BusinessType.DELETE)
+    @DeleteMapping("/delete/{id}")
+    public AjaxResult delete(@PathVariable Long id)
+    {
+        return toAjax(userCompanyUserService.deleteFsUserCompanyUserById(id));
+    }
+
     /**
      * 查询用户
      */
@@ -188,6 +228,9 @@ public class FsUserController extends BaseController
     @GetMapping("/listBySearch")
     public R listBySearch(FsUser user)
     {
+        if (Objects.nonNull(user) && StringUtils.isNotBlank(user.getPhone())){
+            user.setPhone(PhoneUtil.encryptPhone(user.getPhone()));
+        }
         List<FsUser> list = fsUserService.selectFsUserList(user);
         return R.ok().put("data",list);
     }
@@ -211,9 +254,23 @@ public class FsUserController extends BaseController
     @PreAuthorize("@ss.hasPermi('his:user:enabledUsers')")
     @PostMapping("/enabledUsers")
     @ApiOperation("批量启用会员")
-    public ResponseResult<Boolean> enabledUsers(@RequestBody String[] ids) {
-        Boolean r = fsUserService.disabledUser(ids, true);
+    public ResponseResult<Boolean> enabledUsers(@RequestBody List<UserProjectDTO> ids) {
+        log.debug("批量启用会员 ids: {}", JSON.toJSONString(ids));
+        Boolean r = userCompanyUserService.batchUpdateUserProjectStatus(ids, 1);
         return ResponseResult.ok(r);
     }
 
+    @PreAuthorize("@ss.hasPermi('his:user:addPoints')")
+    @PostMapping("/addPoints")
+    @ApiOperation("添加积分")
+    public R addPoints(@RequestBody @Validated FsUserAddPointsParam param) {
+        FsUserAddIntegralTemplateParam integralTemplateParam = new FsUserAddIntegralTemplateParam();
+        integralTemplateParam.setUserId(param.getUserId());
+        integralTemplateParam.setLogType(FsUserIntegralLogTypeEnum.TYPE_23.getValue());
+        integralTemplateParam.setBusinessId(SecurityUtils.getUserId().toString());
+        integralTemplateParam.setPoints(param.getPoint());
+        integralTemplateParam.setRemark(param.getRemark());
+        return userIntegralLogsService.addIntegralTemplate(integralTemplateParam);
+    }
+
 }

+ 1 - 0
fs-common/src/main/java/com/fs/common/constant/FsConstants.java

@@ -10,4 +10,5 @@ public interface FsConstants {
     String REDIS_QW_appKey_Active = "qwActive:";
 
     String FRIEND_WELCOME_VIDEO_KEY = "friend:welcome:";
+    String REDIS_INTEGRAL_ORDER_UNPAY = "integral:order:unpay:";
 }

+ 6 - 0
fs-company-app/src/main/java/com/fs/app/controller/AppBaseController.java

@@ -37,6 +37,12 @@ public class AppBaseController {
 		String userId = claims.getSubject().toString();
 		return userId;
 	}
+	public Long getCompanyUserId() {
+		String headValue =  ServletUtils.getRequest().getHeader("APPToken");
+		Claims claims=jwtUtils.getClaimByToken(headValue);
+		String userId = claims.getSubject();
+		return Long.parseLong(userId);
+	}
 	//获取商城手机号
 	public Long getUserId(Long companyUserId)
 	{

+ 29 - 12
fs-company-app/src/main/java/com/fs/app/controller/CompanyTagController.java

@@ -1,7 +1,9 @@
 package com.fs.app.controller;
 
+import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSON;
 import com.fs.app.annotation.Login;
+import com.fs.app.param.TagProjectParam;
 import com.fs.common.core.domain.R;
 import com.fs.common.exception.CustomException;
 import com.fs.common.utils.StringUtils;
@@ -17,6 +19,7 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.HashMap;
@@ -41,8 +44,9 @@ public class CompanyTagController extends AppBaseController {
     @ApiOperation("查询公司标签列表")
     public R list(@RequestParam(required = false) String keyword,
                   @RequestParam(required = false, defaultValue = "1") Integer pageNum,
-                  @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
-        log.debug("查询公司标签列表 keyword: {}, pageNum: {}, pageSize: {}", keyword, pageNum, pageSize);
+                  @RequestParam(required = false, defaultValue = "10") Integer pageSize,
+                  @RequestParam(required = false) Long companyUserId) {
+        log.debug("查询公司标签列表 keyword: {}, pageNum: {}, pageSize: {}", keyword, pageNum, pageSize, companyUserId);
 
         Map<String, Object> params = new HashMap<>();
         params.put("companyId", getCompanyId());
@@ -51,13 +55,19 @@ public class CompanyTagController extends AppBaseController {
         }
 
         PageHelper.startPage(pageNum, pageSize);
-        List<CompanyTag> list = companyTagService.selectCompanyTagListByMap(params);
-        return R.ok().put("data", new PageInfo<>(list));
+        if (ObjectUtil.isNotEmpty(companyUserId)) {
+            params.put("companyUserId", companyUserId);
+            List<CompanyTag> list = companyTagService.selectCompanyTagByList(params);
+            return R.ok().put("data", new PageInfo<>(list));
+        } else {
+            List<CompanyTag> list = companyTagService.selectCompanyTagListByMap(params);
+            return R.ok().put("data", new PageInfo<>(list));
+        }
     }
 
-    /**
-     * 新增公司标签
-     */
+        /**
+         * 新增公司标签
+         */
     @Login
     @PostMapping("/add")
     @ApiOperation("新增公司标签")
@@ -81,13 +91,20 @@ public class CompanyTagController extends AppBaseController {
     }
 
     @Login
-    @GetMapping("/tagSubUsers")
+    @PostMapping("/tagSubUsers")
     @ApiOperation("标签下会员列表")
-    public R tagSubUsers(@RequestParam List<Long> tagId) {
+    public R tagSubUsers(@RequestBody TagProjectParam tagProjectParam) {
         Map<String, Object> params = new HashMap<>();
-        params.put("tagIds", tagId);
-        params.put("companyId", getCompanyId());
-        return R.ok().put("data", companyTagUserService.selectUserListByMap(params));
+        params.put("tagIds", tagProjectParam.getTagIds());
+        if (CollectionUtils.isNotEmpty(tagProjectParam.getProjectIds())){
+            params.put("projectIds", tagProjectParam.getProjectIds());
+        }
+        if (ObjectUtil.isEmpty(tagProjectParam.getCompanyUserId())){
+            params.put("companyUserId", getCompanyUserId());
+        }else {
+            params.put("companyUserId", tagProjectParam.getCompanyUserId());
+        }
+        return R.ok().put("data", companyTagUserService.selectUserByMap(params));
     }
 
     @Login

+ 100 - 17
fs-company-app/src/main/java/com/fs/app/controller/CompanyUserController.java

@@ -1,13 +1,11 @@
 package com.fs.app.controller;
 
+import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fs.app.annotation.Login;
-import com.fs.app.param.ChangeUserDeptAndPostParam;
-import com.fs.app.param.CompanyUserChangeApplyParam;
-import com.fs.app.param.CompanyUserParam;
-import com.fs.app.param.CompanyUserUpdateParam;
+import com.fs.app.param.*;
 import com.fs.app.service.IAppService;
 import com.fs.app.vo.CompanySubUserVO;
 import com.fs.common.annotation.RepeatSubmit;
@@ -18,14 +16,16 @@ import com.fs.common.utils.PatternUtils;
 import com.fs.common.utils.bean.BeanUtils;
 import com.fs.company.domain.*;
 import com.fs.company.mapper.CompanyRoleMapper;
-import com.fs.company.service.ICompanyDeptService;
-import com.fs.company.service.ICompanyService;
-import com.fs.company.service.ICompanyUserChangeApplyService;
-import com.fs.company.service.ICompanyUserService;
+import com.fs.company.service.*;
+import com.fs.company.vo.CompanyTagUserVO;
 import com.fs.company.vo.CompanyUserChangeApplyVO;
 import com.fs.core.security.SecurityUtils;
 import com.fs.course.service.IFsCourseRedPacketLogService;
 import com.fs.course.service.IFsCourseWatchLogService;
+import com.fs.course.service.IFsUserCompanyUserService;
+import com.fs.qw.dto.UserProjectDTO;
+import com.fs.system.service.ISysDictDataService;
+import com.fs.system.vo.DictVO;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.Api;
@@ -33,6 +33,8 @@ import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
 import javax.validation.Valid;
@@ -57,6 +59,12 @@ public class CompanyUserController extends AppBaseController {
     private final ICompanyUserChangeApplyService companyUserChangeApplyService;
     private final CompanyRoleMapper companyRoleMapper;
     private final IAppService appService;
+    @Autowired
+    private ISysDictDataService dictDataService;
+    @Autowired
+    private IFsUserCompanyUserService fsUserCompanyUserService;
+    @Autowired
+    private ICompanyTagUserService companyTagUserService;
 
     @Login
     @ApiOperation("查询用户列表")
@@ -165,13 +173,18 @@ public class CompanyUserController extends AppBaseController {
     @ApiOperation("注册")
     @PostMapping("/resisterCompanyUser")
     public R resisterCompanyUser(@Valid @RequestBody CompanyUserParam param) {
-        Company company = companyService.selectCompanyById(param.getCompanyId());
+        CompanyUser upCompanyUser = companyUserService.selectCompanyUserById(param.getCompanyUserId());
+        if (Objects.isNull(upCompanyUser)) {
+            return R.error("邀请销售不存在");
+        }
+
+        Company company = companyService.selectCompanyById(upCompanyUser.getCompanyId());
         if (Objects.isNull(company)) {
             return R.error("公司不存在");
         }
 
         // 判断用户数量是否已达到上线
-        Integer count = companyUserService.selectCompanyUserCountByCompanyId(param.getCompanyId());
+        Integer count = companyUserService.selectCompanyUserCountByCompanyId(upCompanyUser.getCompanyId());
         if(count > company.getLimitUserCount()) {
             return R.error("用户数量已达到上限");
         }
@@ -195,9 +208,10 @@ public class CompanyUserController extends AppBaseController {
         companyUser.setPassword(SecurityUtils.encryptPassword(companyUser.getPassword()));
         companyUser.setCreateTime(new Date());
         companyUser.setIsAudit(0);
+        companyUser.setParentId(upCompanyUser.getUserId());
 
         // 部门
-        CompanyDept dept = companyDeptService.getDefaultCompanyDeptByCompanyId(param.getCompanyId());
+        CompanyDept dept = companyDeptService.getDefaultCompanyDeptByCompanyId(upCompanyUser.getCompanyId());
         if (Objects.nonNull(dept)) {
             companyUser.setDeptId(dept.getDeptId());
         }
@@ -221,7 +235,7 @@ public class CompanyUserController extends AppBaseController {
     @RepeatSubmit
     @ApiOperation("更换会员归属申请")
     @PostMapping("/changeUserParentApply")
-    public R changeVipUser(@Valid @RequestBody CompanyUserChangeApplyParam param) {
+    public R changeVipUser(@RequestBody CompanyUserChangeApplyParam param) {
         // 参数校验
         CompanyUser fromUser = companyUserService.selectCompanyUserById(param.getFrom());
         if (Objects.isNull(fromUser)) {
@@ -233,12 +247,18 @@ public class CompanyUserController extends AppBaseController {
             throw new ServiceException("申请更换归属销售不存在");
         }
 
+        if (Objects.equals(fromUser.getUserId(), toUser.getUserId())) {
+            throw new ServiceException("申请更换归属销售不能与原归属销售相同");
+        }
+
         if (param.getType() != 0 && param.getType() != 1) {
             throw new ServiceException("类型不正确");
         }
 
-        if (param.getType() == 1 && (Objects.isNull(param.getIds()) || param.getIds().isEmpty())) {
-            throw new ServiceException("请先选择会员");
+        if (param.getType() == 1 && (CollectionUtils.isEmpty(param.getIds()))
+                &&(CollectionUtils.isEmpty(param.getProject()))
+                &&(CollectionUtils.isEmpty(param.getTagList()))) {
+            throw new ServiceException("请先选择会员!");
         }
 
         // 存在待审核的申请不能再次申请
@@ -248,14 +268,58 @@ public class CompanyUserController extends AppBaseController {
         if (companyUserChangeApplyService.count(applyWrapper) > 0) {
             throw new ServiceException("存在待审核申请");
         }
-
         CompanyUser companyUser = companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
-
+        List<UserProjectDTO> list = param.getIds();
+        if(CollectionUtils.isEmpty(list)){
+            List<UserProjectDTO> userProjectDTOS = addUserId(param.getProject(),param.getTagList(),param.getFrom());
+            if (CollectionUtils.isNotEmpty(userProjectDTOS)){
+                list.addAll(userProjectDTOS);
+            }
+        }
         // 添加申请
-        companyUserChangeApplyService.apply(param.getFrom(), param.getTo(), param.getType(), param.getIds(), companyUser.getCompanyId(), companyUser.getUserName());
+        companyUserChangeApplyService.apply(param.getFrom(), param.getTo(), param.getType(),list, companyUser.getCompanyId(), companyUser.getUserName());
         return R.ok();
     }
 
+    /**
+     * 查询标签和项目中的会员添加
+     * @param tagList
+     * @param companyUserId
+     * @return
+     */
+    private List<UserProjectDTO> addUserId(List<Long> projects, List<Long> tagList, Long companyUserId) {
+        // Prepare parameters map
+        Map<String, Object> params = new HashMap<>();
+
+        if (CollectionUtils.isNotEmpty(projects)) {
+            params.put("projectIds", projects);
+        } else {
+            params.put("tagIds", tagList);
+        }
+
+        // Set company user ID
+        Long effectiveCompanyUserId = ObjectUtil.isNotEmpty(companyUserId)
+                ? companyUserId
+                : getCompanyUserId();
+        params.put("companyUserId", effectiveCompanyUserId);
+
+        // Get data from service
+        List<CompanyTagUserVO> voList = companyTagUserService.selectUserByMap(params);
+        if (CollectionUtils.isEmpty(voList)) {
+            return Collections.emptyList();
+        }
+
+        // Transform data
+        return voList.stream()
+                .map(vo -> {
+                    UserProjectDTO dto = new UserProjectDTO();
+                    dto.setUserId(vo.getUserId());
+                    dto.setProjectId(vo.getProjectId());
+                    return dto;
+                })
+                .collect(Collectors.toList());
+    }
+
     @Login
     @ApiOperation("申请列表")
     @GetMapping("/applyList")
@@ -309,4 +373,23 @@ public class CompanyUserController extends AppBaseController {
         appService.changeUserDeptAndPost(param);
         return R.ok();
     }
+
+    @ApiOperation("查询指定公司中存在会员的项目")
+    @PostMapping("/getDictByKeyByProject")
+    public R getDictByKey(
+            @RequestBody TagProjectParam tagProjectParam){
+        List<DictVO> dictVOS=dictDataService.selectDictDataListByType("sys_course_project");
+        Map<String,Object> param = new HashMap<>();
+        param.put("tagIds",tagProjectParam.getTagIds());
+        param.put("companyUserId",tagProjectParam.getCompanyUserId());
+        List<Long> projectIds =fsUserCompanyUserService.selectFsUserCompanyUserList(param);
+        if (CollectionUtils.isEmpty(projectIds)){
+            return R.ok().put("data",new ArrayList<DictVO>());
+        }
+
+        List<DictVO> filteredDictVOS = dictVOS.stream()
+                .filter(dictVO -> projectIds.contains(Long.parseLong(dictVO.getDictValue())))
+                .collect(Collectors.toList());
+        return R.ok().put("data",filteredDictVOS);
+    }
 }

+ 41 - 14
fs-company-app/src/main/java/com/fs/app/controller/FsUserController.java

@@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.fs.app.annotation.Login;
 import com.fs.app.config.ImageStorageConfig;
+import com.fs.app.param.FsUserProjectUpdateParam;
 import com.fs.app.param.FsUserTagUpdateParam;
 import com.fs.app.param.FsUserUpdateParam;
 import com.fs.common.core.domain.R;
@@ -14,12 +15,15 @@ import com.fs.common.utils.StringUtils;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.service.ICompanyTagUserService;
 import com.fs.company.service.ICompanyUserService;
+import com.fs.course.domain.FsUserCompanyUser;
 import com.fs.course.param.CourseAnalysisParam;
 import com.fs.course.param.newfs.FsUserCourseBeMemberImageParam;
 import com.fs.course.param.newfs.FsUserCourseBeMemberParam;
+import com.fs.course.service.IFsUserCompanyUserService;
 import com.fs.course.service.IFsUserCourseService;
 import com.fs.course.vo.newfs.FsCourseAnalysisVO;
 import com.fs.his.domain.FsUser;
+import com.fs.his.service.IFsUserProjectTagService;
 import com.fs.his.service.IFsUserService;
 import com.fs.store.param.h5.FsUserPageListParam;
 import com.fs.store.param.h5.TagListParam;
@@ -72,11 +76,16 @@ public class FsUserController extends AppBaseController {
 
     @Autowired
     private ISysConfigService configService;
+    @Autowired
+    private IFsUserCompanyUserService userCompanyUserService;
+    @Autowired
+    private IFsUserProjectTagService userProjectTagService;
 
     @Login
     @PostMapping("/pageList")
     @ApiOperation("用户会员分页列表")
     public ResponseResult<PageInfo<FsUserPageListVO>> pageList(@RequestBody FsUserPageListParam param) {
+        log.debug("用户会员分页列表 param: {}", JSON.toJSONString(param));
         param.setUserId(Long.parseLong(getUserId()));
 //        PageHelper.startPage(param.getPageNum(), param.getPageSize());
         PageInfo<FsUserPageListVO> fsUserPageListVOPageInfo = fsUserService.selectFsUserPageList(param);
@@ -104,8 +113,9 @@ public class FsUserController extends AppBaseController {
     @GetMapping("/details")
     @ApiOperation("用户会员详情")
     public ResponseResult<UserDetailsVO> getUserDetails(@ApiParam(value = "用户id", required = true) @RequestParam Long userId,
+                                                        @ApiParam(value = "用户项目关联id", required = true) @RequestParam Long userCompanyId,
                                                         @ApiParam(value = "时间tab,不传表示查询全部,分别是:今天、昨天、前天、近七天", required = true) @RequestParam(required = false) String dateTag) {
-        UserDetailsVO userDetails = fsUserService.getUserDetails(Long.parseLong(getUserId()), userId, dateTag);
+        UserDetailsVO userDetails = fsUserService.getUserDetails(Long.parseLong(getUserId()), userId, dateTag,userCompanyId);
         return ResponseResult.ok(userDetails);
     }
 
@@ -113,9 +123,14 @@ public class FsUserController extends AppBaseController {
     @GetMapping("/tagList")
     @ApiOperation("用户会员标签列表")
     public ResponseResult<PageInfo<CompanyUserTagListVO>> getTagList(TagListParam param) {
+        log.debug("用户会员标签列表 param: {}", JSON.toJSONString(param));
         param.setUserId(Long.parseLong(getUserId()));
         PageHelper.startPage(param.getPageNum(), param.getPageSize());
-        List<CompanyUserTagListVO> tagList = companyTagUserService.getTagList(param);
+        List<CompanyUserTagListVO> tagList = userProjectTagService.getTagList(param);
+        CompanyUserTagListVO noTag = new CompanyUserTagListVO();
+        noTag.setTagId(0L);
+        noTag.setTagName("无标签");
+        tagList.add(0, noTag);
         PageInfo<CompanyUserTagListVO> pageInfo = new PageInfo<>(tagList);
         return ResponseResult.ok(pageInfo);
     }
@@ -123,22 +138,18 @@ public class FsUserController extends AppBaseController {
     @Login
     @PostMapping("/disabled")
     @ApiOperation("批量禁用会员")
-    public ResponseResult<Boolean> disabledUser(@ApiParam(value = "联系人id集合", required = true) @RequestBody String[] ids) {
-        Boolean r = fsUserService.disabledUser(ids, false);
+    public ResponseResult<Boolean> disabledUser(@ApiParam(value = "联系人id集合", required = true) @RequestBody List<Long> userCompanyUserIds) {
+        log.debug("批量禁用会员 ids: {}", JSON.toJSONString(userCompanyUserIds));
+        Boolean r = userCompanyUserService.batchUpdateStatus(userCompanyUserIds, 2);
         return ResponseResult.ok(r);
     }
 
     @Login
     @PostMapping("/enabled")
     @ApiOperation("批量启用会员")
-    public ResponseResult<Boolean> enabledUser(@ApiParam(value = "联系人id集合", required = true) @RequestBody String[] ids) {
-        // 如果存在重粉的数据,则禁止启用,需要提示
-        long companyUserId = Long.parseLong(getUserId());
-        Integer count = fsUserService.selectFsUserByUserIds(ids, companyUserId);
-        if(count > 0){
-            return ResponseResult.fail(400, "重粉会员不能移除小黑屋");
-        }
-        Boolean r = fsUserService.disabledUser(ids, true);
+    public ResponseResult<Boolean> enabledUser(@ApiParam(value = "联系人id集合", required = true) @RequestBody List<Long> userCompanyUserIds) {
+        log.debug("批量启用会员 ids: {}", JSON.toJSONString(userCompanyUserIds));
+        Boolean r = userCompanyUserService.batchUpdateStatus(userCompanyUserIds, 1);
         return ResponseResult.ok(r);
     }
 
@@ -260,11 +271,27 @@ public class FsUserController extends AppBaseController {
         return ResponseResult.ok();
     }
 
+    @Login
+    @ApiOperation("修改用户项目备注")
+    @PostMapping("/changeUserRemark")
+    public ResponseResult<Object> changeUserProjectRemark(@Valid @RequestBody FsUserProjectUpdateParam param) {
+        log.debug("修改用户备注 param:{}", JSON.toJSONString(param));
+        FsUserCompanyUser userCompanyUser = userCompanyUserService.selectFsUserCompanyUserById(param.getUserCompanyUserId());
+        if (Objects.isNull(userCompanyUser)) {
+            throw new ServiceException("用户不存在");
+        }
+
+        userCompanyUser.setRemark(param.getRemark());
+        userCompanyUserService.updateFsUserCompanyUser(userCompanyUser);
+        return ResponseResult.ok();
+    }
+
     @Login
     @ApiOperation("修改用户标签")
     @PostMapping("/changeUserTags")
     public ResponseResult<Object> changeUserTags(@Valid @RequestBody FsUserTagUpdateParam param) {
-        companyTagUserService.changeUserTags(param.getFsUserIds(), param.getTagIds());
+        log.debug("修改用户标签 param:{}", JSON.toJSONString(param));
+        userProjectTagService.addUserProjectTag(param.getUserCompanyUserIds(), param.getTagIds());
         return ResponseResult.ok();
     }
 
@@ -302,10 +329,10 @@ public class FsUserController extends AppBaseController {
         return ResponseResult.ok(fsUserService.companyUserSummaryCount(userId, companyUserId));
     }
 
-//    @Login
     @ApiOperation("会员关联绑定销售")
     @PostMapping("/beMember")
     public ResponseResult<Boolean> becomeMember(@Valid @RequestBody FsUserCourseBeMemberParam param) {
+        log.debug("会员关联绑定销售 param:{}", JSON.toJSONString(param));
         return fsUserService.becomeMember(param);
     }
 

+ 153 - 124
fs-company-app/src/main/java/com/fs/app/controller/WxCompanyUserController.java

@@ -11,14 +11,21 @@ import com.fs.app.param.LoginMaWxParam;
 import com.fs.app.utils.JwtUtils;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
+import com.fs.common.utils.IpUtil;
 import com.fs.common.utils.ServletUtils;
+import com.fs.company.domain.Company;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.service.ICompanyDeptService;
+import com.fs.company.service.ICompanyService;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.core.config.WxMaConfiguration;
 import com.fs.course.config.CourseMaConfig;
+import com.fs.course.domain.FsUserCompanyUser;
+import com.fs.course.service.IFsUserCompanyUserService;
 import com.fs.his.domain.FsUser;
+import com.fs.his.domain.FsUserWx;
 import com.fs.his.service.IFsUserService;
+import com.fs.his.service.IFsUserWxService;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.mapper.SysConfigMapper;
 import com.fs.wx.miniapp.config.WxMaProperties;
@@ -35,6 +42,9 @@ import org.springframework.web.bind.annotation.*;
 
 import java.util.Date;
 import java.util.List;
+import java.util.Objects;
+
+import static com.fs.his.utils.PhoneUtil.encryptPhone;
 
 @Api("微信小程序相关接口(暂废弃,后面再删除)")
 @RestController
@@ -43,164 +53,183 @@ import java.util.List;
 public class WxCompanyUserController extends AppBaseController {
     private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
-    @Autowired
-    private WxMaProperties maProperties;
-
     @Autowired
     JwtUtils jwtUtils;
-
-    @Autowired
-    RedisCache redisCache;
-
     @Autowired
     private ICompanyUserService companyUserService;
-
-    @Autowired
-    private ICompanyDeptService companyDeptService;
-
     @Autowired
     private IFsUserService userService;
-
     @Autowired
-    private SysConfigMapper sysConfigMapper;
+    private ICompanyService companyService;
+    @Autowired
+    private IFsUserCompanyUserService userCompanyUserService;
+    @Autowired
+    private IFsUserWxService fsUserWxService;
 
     @ApiOperation("小程序-授权登录")
     @PostMapping("/loginByMa")
     public R login(@RequestBody LoginMaWxParam param) {
+        log.info("=====================进入小程序授权登录, 入参: {}", param);
         if (StringUtils.isBlank(param.getCode())) {
             return R.error("code不存在");
         }
-        SysConfig sysConfig3 = sysConfigMapper.selectConfigByConfigKey("courseMa.config");
-        List<CourseMaConfig> courseMaConfigs = JSON.parseArray(sysConfig3.getConfigValue(), CourseMaConfig.class);
-        if (courseMaConfigs.isEmpty()){
-            return R.error("小程序配置为空");
+
+        // 特殊(需求设计:需要根据公司是否开启黑名单来设置会员初始化的状态)
+        Company company = companyService.selectCompanyById(param.getCompanyId());
+        if (company==null || company.getStatus()==0){
+            return R.error("注册失败团队已停用,或不存在!");
+        }
+
+        // 根据销售后台设置的  是否需要单独注册会员 来判断是否需要设置销售的值
+        CompanyUser companyUser = companyUserService.selectCompanyUserById(param.getCompanyUserId());;
+        if(companyUser == null || companyUser.getStatus().equals("1")){
+            return R.error("注册失败客服已停用,或不存在!");
         }
-        CourseMaConfig courseMaConfig = courseMaConfigs.get(0);
-        //获取第二个小程序配置,序号从0开始
-        final WxMaService wxService = WxMaConfiguration.getMaService(courseMaConfig.getAppid());
+//        if (company.getCourseMiniAppId() == null) {
+//            return R.error("小程序参数错误!");
+//        }
+//        if (!param.getAppId().equals(company.getCourseMiniAppId())){
+//            return R.error("无权限,");
+//        }
+
+        final WxMaService wxService = WxMaConfiguration.getMaService(param.getAppId());
         try {
             WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(param.getCode());
             this.logger.info(session.getSessionKey());
             this.logger.info(session.getOpenid());
-            // 解密
-            WxMaPhoneNumberInfo phoneNoInfo = wxService.getUserService().getPhoneNoInfo(session.getSessionKey(), param.getEncryptedData(), param.getIv());
-            WxMaUserInfo userInfo = wxService.getUserService().getUserInfo(session.getSessionKey(), param.getEncryptedData(), param.getIv());
-
-            //以下暂时注释,不需要往销售表添加数据
-//            CompanyUser companyUser = companyUserService.getCompanyUserByOpenId(session.getOpenid());
-//            String ip = IpUtil.getRequestIp();
-//
-////            // 如果公司id为空(表示可能是该公司的第一位销售管理员),则需要根据电话号码判断是否存在销售,如果不存在则提示
-////            if (param.getCompanyId() == null) {
-////                if (checkPhone == null) {
-////                    throw new CustomException("由于不是管理员,不能直接登录", 401);
-////                }
-////            }
-//            if (companyUser == null) {
-//                CompanyUser checkPhone = companyUserService.getCompanyUserByPhone(phoneNoInfo.getPhoneNumber());
-//                if (checkPhone != null) {
-//                    if (checkPhone.getMaOpenId() == null) {
-//                        companyUser = checkPhone;
-//                        companyUser.setMaOpenId(session.getOpenid());
-//                        companyUser.setUserId(companyUser.getUserId());
-//                        companyUser.setUpdateTime(new DateTime());
-//                        companyUser.setLoginIp(ip);
-//                        companyUserService.updateUserProfile(companyUser);
-//                    } else {
-//                        throw new CustomException("此手机号用户已存在");
-//                    }
-//                } else {
-//                    //新增
-//                    companyUser = new CompanyUser();
-//                    companyUser.setUserName(phoneNoInfo.getPhoneNumber());
-//                    companyUser.setNickName(userInfo.getNickName() == null ? "微信用户" : userInfo.getNickName());
-//                    companyUser.setPhonenumber(phoneNoInfo.getPhoneNumber());
-//                    companyUser.setSex(userInfo.getGender());
-//                    //密码初始化为123456
-//                    String pw = "123456";
-//                    companyUser.setPassword(SecurityUtils.encryptPassword(param.getPassword() == null ? pw : param.getPassword()));
-//                    companyUser.setCreateTime(new Date());
-//                    companyUser.setCompanyId(param.getCompanyId());
-//                    companyUser.setParentId(param.getParentCompanyUseId());
-//                    companyUser.setMaOpenId(session.getOpenid());
-//
-//                    //部门信息
-//                    CompanyDept dept = companyDeptService.getDefaultCompanyDeptByCompanyId(param.getCompanyId());
-//                    if (Objects.nonNull(dept)) {
-//                        companyUser.setDeptId(dept.getDeptId());
-//                    }
-//                    companyUserService.insertUser(companyUser);
-//                }
-//            } else {
-//                CompanyUser companyUserMp = new CompanyUser();
-//                companyUserMp.setPhonenumber(phoneNoInfo.getPhoneNumber());
-//                companyUserMp.setUserId(companyUser.getUserId());
-//                companyUserMp.setUpdateTime(new DateTime());
-//                companyUserMp.setLoginIp(ip);
-//                companyUserService.updateUserProfile(companyUser);
-//            }
-
-            // 添加会员表数据
-            FsUser user = userService.selectFsUserByMpOpenId(session.getOpenid());
-            if (user != null) {
-                //修改
-                FsUser userMap = new FsUser();
-                userMap.setUserId(user.getUserId());
-                userMap.setMpOpenId(session.getOpenid());
-                userMap.setUnionId(session.getUnionid());
-                userMap.setUpdateTime(new DateTime());
-                userMap.setNickName(userInfo.getNickName() != null ? userInfo.getNickName() : "微信用户");
-                userMap.setAvatar(userInfo.getAvatarUrl() != null ? userInfo.getAvatarUrl() : null);
-                userMap.setPhone(phoneNoInfo.getPhoneNumber());
-                userService.updateFsUser(userMap);
-            } else {
-                //新增
-                user = new FsUser();
-                user.setNickName(userInfo.getNickName() != null ? userInfo.getNickName() : "微信用户");
-                user.setAvatar(userInfo.getAvatarUrl() != null ? userInfo.getAvatarUrl() : null);
-                user.setStatus(1);
-                user.setMpOpenId(session.getOpenid());
-                user.setUnionId(session.getUnionid());
-                user.setCreateTime(new Date());
-                user.setPhone(phoneNoInfo.getPhoneNumber());
-                userService.insertFsUser(user);
+            this.logger.info(session.getUnionid());
+            if (StringUtils.isEmpty(session.getOpenid())){
+                return R.error("登陆失败,openid未授权,请稍后再试!");
+            }
+
+            if (param.getAuthType() == 2 && StringUtils.isEmpty(session.getUnionid())){
+                return R.error("未绑定开发平台,请联系管理员!");
+            }
+
+            // 手机号信息
+            WxMaPhoneNumberInfo phoneNoInfo = new WxMaPhoneNumberInfo();;
+            if (param.getAuthType()==1){
+                phoneNoInfo = wxService.getUserService().getPhoneNoInfo(session.getSessionKey(), param.getEncryptedData(), param.getIv());
+                if (StringUtils.isEmpty(phoneNoInfo.getPhoneNumber())){
+                    return R.error("授权失败,请联系客服!");
+                }
+            }
+
+            FsUser user = getUserByAuthType(param, wxService, session, phoneNoInfo);
+
+            // 3. 处理用户注册或更新
+            String ip = IpUtil.getRequestIp();
+            user = handleUserRegisterOrUpdate(user, param, session, phoneNoInfo, company, companyUser, ip);
+
+            FsUserCompanyUser userCompanyUser = userCompanyUserService.selectByUserIdAndProjectId(user.getUserId(), param.getProjectId());
+            if (Objects.nonNull(userCompanyUser) && !param.getCompanyUserId().equals(userCompanyUser.getCompanyUserId())){
+                return R.error(500, "该用户("+user.getUserId() + ")已成为其他销售会员");
             }
-            log.info("保存成功的用户信息user: {}, 用户id: {}", user, user.getUserId());
+
+            // 4. 处理用户与小程序的绑定
+            handleFsUserWx(user, param, session);
+
+            log.info("保存成功的用户信息user: {}, 用户id: {},小程序AppId:{}", user, user.getUserId(), param.getAppId());
             String token = jwtUtils.generateToken(user.getUserId());
-            // 返回一个写死的数据到前端
-            return R.ok("登录成功").put("token", token).put("phoneNumber", phoneNoInfo.getPhoneNumber()).put("nickName", "微信用户").put("user", user);
+            // 返回TOKEN和user
+            return R.ok("登录成功").put("token", token).put("user", user);
         } catch (WxErrorException e) {
             this.logger.error(e.getMessage(), e);
             return R.error("授权失败," + e.getMessage());
         }
     }
 
-    @Login(isMiniLogin = true)
-    @ApiOperation("获取销售通过小程序登录后的用户信息")
-    @GetMapping("/getMaUser")
-    public R getUserInfo() {
-        try {
-            CompanyUser companyUser = companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
-            if (companyUser == null) {
-                return R.error(401, "用户信息不存在");
+    /**
+     * 根据authType获取用户信息
+     */
+    private FsUser getUserByAuthType(LoginMaWxParam param, WxMaService wxService, WxMaJscode2SessionResult session, WxMaPhoneNumberInfo phoneNoInfo) throws WxErrorException {
+        FsUser user = null;
+        if (param.getAuthType() == 1) {
+            user = userService.selectFsUserByPhone(encryptPhone(phoneNoInfo.getPhoneNumber()));
+        } else {
+            // unionid判定唯一
+            if (StringUtils.isNotEmpty(session.getUnionid())) {
+                user = userService.selectFsUserByUnionId(session.getUnionid());
             }
-            return R.ok().put("user", companyUser);
-        } catch (Exception e) {
-            return R.error("操作异常");
         }
+        return user;
     }
 
     /**
-     * 特殊要求:销售小程序临时登录,登录后页面中还有一个之前常用的登录,所以为了区分,token名称不能跟之前的一样
-     *
-     * @return 用户id
+     * 处理用户注册或更新
      */
-    public String getUserId() {
-        String headValue = ServletUtils.getRequest().getHeader("UserToken");
-        Claims claims = jwtUtils.getClaimByToken(headValue);
-        String userId = claims.getSubject().toString();
-        return userId;
+    private FsUser handleUserRegisterOrUpdate(FsUser user, LoginMaWxParam param, WxMaJscode2SessionResult session, WxMaPhoneNumberInfo phoneNoInfo, Company company, CompanyUser companyUser, String ip) {
+        if (user == null) {
+            return createUser(param, session, phoneNoInfo, company, companyUser);
+        } else {
+            return updateUser(user, param, session, phoneNoInfo, company, companyUser);
+        }
+    }
+
+    /**
+     * 新增用户
+     */
+    private FsUser createUser(LoginMaWxParam param, WxMaJscode2SessionResult session, WxMaPhoneNumberInfo phoneNoInfo, Company company, CompanyUser companyUser) {
+        FsUser user = new FsUser();
+        user.setStatus((company != null ? company.getFsUserIsDefaultBlack() : 0) == 1 ? 0 : 1);
+        user.setUnionId(session.getUnionid() == null ? "" : session.getUnionid());
+        user.setCreateTime(new Date());
+        if (param.getAuthType() == 1 && phoneNoInfo != null) {
+            user.setPhone(phoneNoInfo.getPhoneNumber());
+        }
+        userService.insertFsUser(user);
+
+        if((companyUser.getIsAllowedAllRegister() == null || companyUser.getIsAllowedAllRegister() == 1)
+                && companyUser.getIsNeedRegisterMember() != null && companyUser.getIsNeedRegisterMember() != 1){
+            int defaultStatus = (company != null ? company.getFsUserIsDefaultBlack() : 0) == 1 ? 0 : 1;
+            userCompanyUserService.bindRelationship(user.getUserId(), param.getProjectId(), companyUser.getCompanyId(), companyUser.getUserId(), defaultStatus);
+        }
+        return user;
     }
 
+    /**
+     * 修改用户
+     */
+    private FsUser updateUser(FsUser user, LoginMaWxParam param, WxMaJscode2SessionResult session, WxMaPhoneNumberInfo phoneNoInfo, Company company, CompanyUser companyUser) {
+        FsUser userMap = new FsUser();
+        userMap.setUserId(user.getUserId());
+        userMap.setUnionId(session.getUnionid() == null ? "" : session.getUnionid());
+        userMap.setUpdateTime(new DateTime());
+        if (param.getAuthType() == 1 && phoneNoInfo != null) {
+            userMap.setPhone(phoneNoInfo.getPhoneNumber());
+        }
 
+        userService.updateFsUser(userMap);
+        return userMap;
+    }
+
+    /**
+     * 处理用户与小程序的绑定
+     */
+    private void handleFsUserWx(FsUser user, LoginMaWxParam param, WxMaJscode2SessionResult session) {
+        if (user == null) return;
+        // 尝试更新
+        boolean updated = fsUserWxService.lambdaUpdate()
+                .eq(FsUserWx::getFsUserId, user.getUserId())
+                .eq(FsUserWx::getAppId, param.getAppId())
+                .eq(FsUserWx::getOpenId, session.getOpenid())
+                .set(FsUserWx::getCompanyId, param.getCompanyId())
+                .set(FsUserWx::getUnionId, session.getUnionid() == null ? "" : session.getUnionid())
+                .set(FsUserWx::getUpdateTime, new Date())
+                .update();
+
+        // 如果更新失败(记录不存在),则插入
+        if (!updated) {
+            FsUserWx fsUserWx = new FsUserWx();
+            fsUserWx.setType(1);
+            fsUserWx.setFsUserId(user.getUserId());
+            fsUserWx.setCompanyId(param.getCompanyId());
+            fsUserWx.setAppId(param.getAppId());
+            fsUserWx.setOpenId(session.getOpenid());
+            fsUserWx.setUnionId(session.getUnionid() == null ? "" : session.getUnionid());
+            fsUserWx.setCreateTime(new Date());
+            fsUserWx.setUpdateTime(new Date());
+            fsUserWxService.save(fsUserWx);
+        }
+    }
 }

+ 14 - 1
fs-company-app/src/main/java/com/fs/app/param/CompanyUserChangeApplyParam.java

@@ -1,5 +1,6 @@
 package com.fs.app.param;
 
+import com.fs.qw.dto.UserProjectDTO;
 import lombok.Data;
 
 import javax.validation.constraints.NotNull;
@@ -22,8 +23,20 @@ public class CompanyUserChangeApplyParam {
      */
     @NotNull(message = "类型不能为空")
     private Integer type;
+
+    /**
+     * 项目id
+     */
+    private List<Long> project;
+
+
+    /**
+     * 标签id
+     */
+    private List<Long> tagList;
+
     /**
      * 需更换归属会员id集合
      */
-    private List<Long> ids;
+    private List<UserProjectDTO> ids;
 }

+ 5 - 3
fs-company-app/src/main/java/com/fs/app/param/CompanyUserParam.java

@@ -1,5 +1,6 @@
 package com.fs.app.param;
 
+import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import javax.validation.constraints.NotBlank;
@@ -9,10 +10,11 @@ import javax.validation.constraints.NotNull;
 public class CompanyUserParam {
 
     /**
-     * 公司ID
+     * 上级销售
      */
-    @NotNull(message = "公司ID不能为空")
-    private Long companyId;
+    @NotNull(message = "上级销售不能为空")
+    @ApiModelProperty("上级销售不能为空")
+    private Long companyUserId;
     /**
      * 手机号码
      */

+ 17 - 0
fs-company-app/src/main/java/com/fs/app/param/FsUserProjectUpdateParam.java

@@ -0,0 +1,17 @@
+package com.fs.app.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class FsUserProjectUpdateParam {
+
+    @ApiModelProperty("用户项目ID")
+    @NotNull(message = "用户项目ID不能为空")
+    private Long userCompanyUserId;
+
+    @ApiModelProperty("备注")
+    private String remark;
+}

+ 3 - 3
fs-company-app/src/main/java/com/fs/app/param/FsUserTagUpdateParam.java

@@ -11,9 +11,9 @@ public class FsUserTagUpdateParam {
     /**
      * 用户ID
      */
-    @ApiModelProperty("用户ID集合")
-    @NotEmpty(message = "用户ID不能为空")
-    private List<Long> fsUserIds;
+    @ApiModelProperty("用户项目ID集合")
+    @NotEmpty(message = "用户项目ID不能为空")
+    private List<Long> userCompanyUserIds;
     /**
      * 标签ID
      */

+ 22 - 0
fs-company-app/src/main/java/com/fs/app/param/LoginMaWxParam.java

@@ -4,6 +4,7 @@ import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
 import java.io.Serializable;
 
 @Data
@@ -19,6 +20,18 @@ public class LoginMaWxParam implements Serializable {
     @ApiModelProperty(value = "小程序加密算法的初始向量")
     private String iv;
 
+    @NotNull(message = "公司id不能为空")
+    @ApiModelProperty(value = "公司id")
+    private Long companyId;
+
+    @NotNull(message = "销售id不能为空")
+    @ApiModelProperty(value = "销售id")
+    private Long companyUserId;
+
+    @NotNull(message = "项目id不能为空")
+    @ApiModelProperty(value = "课程归属项目id")
+    private Long projectId;
+
 //    @ApiModelProperty(value = "公司id,如果不是第一位销售,都需要传")
 //    private Long companyId;
 
@@ -31,4 +44,13 @@ public class LoginMaWxParam implements Serializable {
 //    @ApiModelProperty(value = "用户密码")
 //    private String password;
 
+    /**
+     * 0:静默授权  1:手机号授权
+     */
+    @NotNull(message = "授权类型缺失")
+    @ApiModelProperty(value = "小程序授权类型")
+    private Integer authType;
+
+    private String appId;
+
 }

+ 23 - 0
fs-company-app/src/main/java/com/fs/app/param/TagProjectParam.java

@@ -0,0 +1,23 @@
+package com.fs.app.param;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class TagProjectParam {
+    /**
+     * 销售id
+     */
+    private Long companyUserId;
+
+    /**
+     * 标签id
+     */
+    private List<Long> tagIds;
+
+    /**
+     * 项目id
+     */
+    private List<Long> projectIds;
+}

+ 76 - 0
fs-company/src/main/java/com/fs/company/controller/company/CompanyUserChangeApplyController.java

@@ -0,0 +1,76 @@
+package com.fs.company.controller.company;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.exception.ServiceException;
+import com.fs.common.utils.StringUtils;
+import com.fs.company.controller.param.CompanyUserChangeApplyAuditParam;
+import com.fs.company.service.ICompanyUserChangeApplyService;
+import com.fs.company.vo.CompanyUserChangeApplyVO;
+import com.fs.framework.security.SecurityUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 更换会员归属申请Controller
+ */
+@RestController
+@RequestMapping("/company/apply")
+public class CompanyUserChangeApplyController extends BaseController
+{
+    @Autowired
+    private ICompanyUserChangeApplyService companyUserChangeApplyService;
+
+    /**
+     * 查询更换会员归属申请列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:apply:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(@RequestParam(required = false) Integer status)
+    {
+        Map<String, Object> map = new HashMap<>();
+        map.put("status", status);
+        map.put("companyId", SecurityUtils.getLoginUser().getCompany().getCompanyId());
+
+        startPage();
+        List<CompanyUserChangeApplyVO> list = companyUserChangeApplyService.selectApplyListByMap(map);
+        return getDataTable(list);
+    }
+
+    /**
+     * 获取更换会员归属申请详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:apply:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(companyUserChangeApplyService.selectApplyDetailById(id));
+    }
+
+    /**
+     * 获取更换会员归属申请详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:apply:audit')")
+    @PostMapping(value = "/audit")
+    public AjaxResult audit(@Valid @RequestBody CompanyUserChangeApplyAuditParam param)
+    {
+        if (param.getStatus() != 1 && param.getStatus() != 2) {
+            throw new ServiceException("审核类型不正确");
+        }
+
+        if (param.getStatus() == 2 && StringUtils.isBlank(param.getReason())) {
+            throw new ServiceException("拒绝理由不能为空");
+        }
+
+        companyUserChangeApplyService.audit(param.getId(), param.getStatus(), param.getReason(), SecurityUtils.getUsername());
+        return AjaxResult.success();
+    }
+
+}

+ 23 - 0
fs-company/src/main/java/com/fs/company/controller/param/CompanyUserChangeApplyAuditParam.java

@@ -0,0 +1,23 @@
+package com.fs.company.controller.param;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class CompanyUserChangeApplyAuditParam {
+    /**
+     * 申请记录ID
+     */
+    @NotNull(message = "申请记录ID不能为空")
+    private Long id;
+    /**
+     * 状态 0通过 1拒绝
+     */
+    @NotNull(message = "审核状态不能为空")
+    private Integer status;
+    /**
+     * 原因
+     */
+    private String reason;
+}

+ 10 - 2
fs-company/src/main/java/com/fs/company/controller/store/FsUserController.java

@@ -1,5 +1,6 @@
 package com.fs.company.controller.store;
 
+import com.alibaba.fastjson.JSON;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
@@ -9,6 +10,7 @@ import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.course.service.IFsUserCompanyUserService;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.security.SecurityUtils;
 import com.fs.framework.service.TokenService;
@@ -19,11 +21,13 @@ import com.fs.his.service.IFsUserService;
 import com.fs.his.vo.FsUserExportListVO;
 import com.fs.his.vo.FsUserVO;
 import com.fs.his.vo.UserVo;
+import com.fs.qw.dto.UserProjectDTO;
 import com.fs.store.param.h5.FsUserPageListParam;
 import com.fs.store.vo.h5.FsUserPageListVO;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
@@ -41,6 +45,7 @@ import static com.fs.his.utils.PhoneUtil.encryptPhone;
  * @author fs
  * @date 2023-06-07
  */
+@Slf4j
 @RestController
 @RequestMapping("/store/user")
 public class FsUserController extends BaseController
@@ -49,6 +54,8 @@ public class FsUserController extends BaseController
     private IFsUserService fsUserService;
     @Autowired
     private TokenService tokenService;
+    @Autowired
+    private IFsUserCompanyUserService userCompanyUserService;
 
     /**
      * 查询用户列表
@@ -247,8 +254,9 @@ public class FsUserController extends BaseController
     @PreAuthorize("@ss.hasPermi('users:user:enabledUsers')")
     @PostMapping("/enabledUsers")
     @ApiOperation("批量启用会员")
-    public ResponseResult<Boolean> enabledUsers(@RequestBody String[] ids) {
-        Boolean r = fsUserService.disabledUser(ids, true);
+    public ResponseResult<Boolean> enabledUsers(@RequestBody List<UserProjectDTO> ids) {
+        log.debug("批量启用会员 ids: {}", JSON.toJSONString(ids));
+        Boolean r = userCompanyUserService.batchUpdateUserProjectStatus(ids, 1);
         return ResponseResult.ok(r);
     }
 

+ 8 - 5
fs-doctor-app/src/main/java/com/fs/app/controller/InquiryOrderController.java

@@ -48,10 +48,7 @@ import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 import static com.fs.his.utils.PhoneUtil.decryptPhone;
 
@@ -94,7 +91,13 @@ public class InquiryOrderController extends  AppBaseController {
     {
         FsDoctor doctor=doctorService.selectFsDoctorByDoctorId(Long.parseLong(getDoctorId()));
         PageHelper.startPage(param.getPageNum(), param.getPageSize());
-        param.setDoctorId(Long.parseLong(getDoctorId()));
+
+        if (Objects.nonNull(param.getUserId())) {
+            param.setDoctorId(null);
+        } else if (Objects.nonNull(param.getDoctorId())) {
+            param.setDoctorId(Long.parseLong(getDoctorId()));
+        }
+
         param.setIsAccept(doctor.getIsAccept());
         param.setIsSelf(doctor.getIsSelf());
         List<FsInquiryOrderListPDVO> list = inquiryOrderService.selectFsInquiryOrderListPDVO(param);

+ 18 - 0
fs-redis/src/main/java/com/fs/app/redis/RedisKeyExpirationListener.java

@@ -6,10 +6,12 @@ import com.fs.event.TemplateBean;
 import com.fs.event.TemplateEvent;
 import com.fs.event.TemplateListenEnum;
 import com.fs.his.domain.FsInquiryOrder;
+import com.fs.his.domain.FsIntegralOrder;
 import com.fs.his.domain.FsPackageOrder;
 import com.fs.his.param.FsInquiryOrderCancelParam;
 import com.fs.his.service.IFsInquiryOrderLogsService;
 import com.fs.his.service.IFsInquiryOrderService;
+import com.fs.his.service.IFsIntegralOrderService;
 import com.fs.his.service.IFsPackageOrderService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -97,5 +99,21 @@ public class RedisKeyExpirationListener extends KeyExpirationEventMessageListene
             }
 
         }
+        // 积分订单
+        else if (key.contains(FsConstants.REDIS_INTEGRAL_ORDER_UNPAY)) {
+            key = key.replace(FsConstants.REDIS_INTEGRAL_ORDER_UNPAY, "");
+            log.info("body:{}",key);
+
+            Long orderId = Long.parseLong(key);
+            IFsIntegralOrderService orderService = SpringUtils.getBean(IFsIntegralOrderService.class);
+            FsIntegralOrder order = orderService.selectFsIntegralOrderByOrderId(orderId);
+            if (!order.getStatus().equals(4)){
+                return;
+            }
+
+            // 取消订单
+            orderService.cannelOrder(orderId);
+            log.info("积分订单id:{},超时未支付取消成功",orderId);
+        }
     }
 }

+ 12 - 0
fs-redis/src/main/resources/application.yml

@@ -0,0 +1,12 @@
+server:
+  # 服务器的HTTP端口,默认为8080
+  port: 18004
+# Spring配置
+spring:
+  profiles:
+    active: dev
+#    active: druid-hdt
+#    active: druid-yzt
+#    active: druid-sxjz
+#    active: druid-sft
+

+ 21 - 0
fs-service/src/main/java/com/fs/company/domain/CompanyUser.java

@@ -151,9 +151,30 @@ public class CompanyUser extends BaseEntity
     /** 用户上级id */
     private Long parentId;
 
+    /** 微信小程序OPENID(如果有小程序授权) */
+    private String  maOpenId;
+
     /** 是否需要单独注册会员,1-是,0-否(用于个微销售分享看课) */
     private Integer isNeedRegisterMember;
 
+    /** 是否允许所有方式注册会员,1-是,0-否,默认1(用于个微注册会员) */
+    private Integer isAllowedAllRegister;
+
+    public String getMaOpenId() {
+        return maOpenId;
+    }
+
+    public void setMaOpenId(String maOpenId) {
+        this.maOpenId = maOpenId;
+    }
+
+    public Integer getIsAllowedAllRegister() {
+        return isAllowedAllRegister;
+    }
+
+    public void setIsAllowedAllRegister(Integer isAllowedAllRegister) {
+        this.isAllowedAllRegister = isAllowedAllRegister;
+    }
 
     public Long getParentId() {
         return parentId;

+ 4 - 0
fs-service/src/main/java/com/fs/company/domain/CompanyUserChangeApplyUser.java

@@ -21,4 +21,8 @@ public class CompanyUserChangeApplyUser {
      * 用户ID
      */
     private Long userId;
+    /**
+     * 项目ID
+     */
+    private Long projectId;
 }

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

@@ -80,4 +80,6 @@ public interface CompanyTagMapper
     String findUserTagByUserId(@Param("userId") Long userId,@Param("companyUserId") Long companyUserId);
     @MapKey("tagId")
     Map<Long,CompanyTag> queryAllTagMap();
+
+    List<CompanyTag> selectCompanyTagByList(@Param("params") Map<String, Object> params);
 }

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

@@ -81,4 +81,6 @@ public interface CompanyTagUserMapper
     void deleteCompanyTagUserByMap(@Param("params") Map<String, Object> params);
 
     List<CompanyUserTagListVO> getTagByUser(@Param("params")CompanyTagUser param);
+
+    List<CompanyTagUserVO> selectUserByMap(@Param("params") Map<String, Object> params);
 }

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

@@ -301,4 +301,6 @@ public interface CompanyUserMapper
      * @param companyUserList 用户信息
      * **/
     void batchUpdateUserDept(@Param("companyUserList") List<CompanyUser> companyUserList);
+
+    String selectCompanyUserNameByIds(@Param("companyUserIds")String companyUserIds);
 }

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

@@ -77,4 +77,6 @@ public interface ICompanyTagService
     Map<Long,CompanyTag> queryAllTagMap();
 
     String findUserTagByUserId(Long userId,Long companyUserId);
+
+    List<CompanyTag> selectCompanyTagByList(Map<String, Object> params);
 }

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

@@ -91,4 +91,9 @@ public interface ICompanyTagUserService
      * @return
      */
     List<CompanyUserTagListVO> getTagByUser(CompanyTagUser param);
+
+    /**
+     * 根据条件查询标签下用户
+     */
+    List<CompanyTagUserVO> selectUserByMap(Map<String, Object> params);
 }

+ 2 - 1
fs-service/src/main/java/com/fs/company/service/ICompanyUserChangeApplyService.java

@@ -3,6 +3,7 @@ package com.fs.company.service;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.fs.company.domain.CompanyUserChangeApply;
 import com.fs.company.vo.CompanyUserChangeApplyVO;
+import com.fs.qw.dto.UserProjectDTO;
 
 import java.util.List;
 import java.util.Map;
@@ -19,7 +20,7 @@ public interface ICompanyUserChangeApplyService extends IService<CompanyUserChan
      * @param companyId 公司ID
      * @param userName  操作用户
      */
-    void apply(Long from, Long to, Integer type, List<Long> ids, Long companyId, String userName);
+    void apply(Long from, Long to, Integer type, List<UserProjectDTO> ids, Long companyId, String userName);
 
     /**
      * 查询申请列表

+ 5 - 2
fs-service/src/main/java/com/fs/company/service/ICompanyUserService.java

@@ -10,6 +10,7 @@ import com.fs.company.vo.CompanyUserVO;
 import com.fs.company.vo.DocCompanyUserVO;
 import com.fs.his.vo.CitysAreaVO;
 import com.fs.his.vo.OptionsVO;
+import com.fs.qw.dto.UserProjectDTO;
 import com.fs.qw.vo.CompanyUserQwVO;
 import com.fs.qw.vo.QwOptionsVO;
 import com.fs.qw.vo.QwUserVO;
@@ -174,10 +175,10 @@ public interface ICompanyUserService {
 
     /**
      * 更改会员归属
-     * @param userIds
+     * @param users 需更换归属会员
      * @return
      */
-    int changeCompanyUser(List<Long> userIds, Long companyUserId, Long companyId);
+    int changeCompanyUser(List<UserProjectDTO> users, Long companyUserId, Long companyId);
 
     /**
      * 查询销售选项列表
@@ -209,4 +210,6 @@ public interface ICompanyUserService {
     List<CompanyUser> getCompanyUserList(CompanyUser companyUser);
 
     List<QwOptionsVO> selectQwUserListLikeName(Map<String, Object> params);
+
+    String selectCompanyUserByStrIds(String companyUserIds);
 }

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

@@ -7,6 +7,7 @@ import com.fs.company.service.ICompanyTagService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
@@ -126,4 +127,14 @@ public class CompanyTagServiceImpl implements ICompanyTagService
     public String findUserTagByUserId(Long key,Long companyUserId) {
         return companyTagMapper.findUserTagByUserId(key,companyUserId);
     }
+
+    /**
+     * 查询标签列表
+     * @param params 条件
+     * @return list
+     */
+    @Override
+    public List<CompanyTag> selectCompanyTagByList(Map<String, Object> params) {
+        return companyTagMapper.selectCompanyTagByList(params);
+    }
 }

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

@@ -1,5 +1,6 @@
 package com.fs.company.service.impl;
 
+import com.fs.common.core.domain.entity.SysDictData;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.company.domain.CompanyTagUser;
@@ -12,6 +13,7 @@ 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 com.fs.system.mapper.SysDictDataMapper;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -35,6 +37,8 @@ public class CompanyTagUserServiceImpl implements ICompanyTagUserService
     private CompanyUserMapper  companyUserMapper;
     @Autowired
     private FsUserMapper fsUserMapper;
+    @Autowired
+    private SysDictDataMapper dictDataMapper;
 
     /**
      * 查询company
@@ -187,4 +191,23 @@ public class CompanyTagUserServiceImpl implements ICompanyTagUserService
 
         return companyTagUserMapper.getTagByUser(param);
     }
+
+    /**
+     * 根据条件查询标签下用户
+     * @param params    条件
+     * @return  list
+     */
+    @Override
+    public List<CompanyTagUserVO> selectUserByMap(Map<String, Object> params) {
+        List<CompanyTagUserVO> companyTagUserVOS = companyTagUserMapper.selectUserByMap(params);
+
+        // 项目
+        List<SysDictData> courseProject = dictDataMapper.selectDictDataByType("sys_course_project");
+        companyTagUserVOS.forEach(vo -> courseProject.stream()
+                .filter(c -> c.getDictValue().equals(vo.getProjectId().toString()))
+                .findFirst()
+                .ifPresent(c -> vo.setUserName(vo.getUserName() + "-" + (c.getDictLabel()))));
+
+        return companyTagUserVOS;
+    }
 }

+ 14 - 9
fs-service/src/main/java/com/fs/company/service/impl/CompanyUserChangeApplyServiceImpl.java

@@ -8,8 +8,11 @@ import com.fs.company.mapper.CompanyUserChangeApplyMapper;
 import com.fs.company.service.ICompanyUserChangeApplyService;
 import com.fs.company.service.ICompanyUserChangeApplyUserService;
 import com.fs.company.vo.CompanyUserChangeApplyVO;
+import com.fs.course.domain.FsUserCompanyUser;
+import com.fs.course.service.IFsUserCompanyUserService;
 import com.fs.his.domain.FsUser;
 import com.fs.his.mapper.FsUserMapper;
+import com.fs.qw.dto.UserProjectDTO;
 import lombok.AllArgsConstructor;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -25,7 +28,7 @@ import java.util.Objects;
 public class CompanyUserChangeApplyServiceImpl extends ServiceImpl<CompanyUserChangeApplyMapper, CompanyUserChangeApply> implements ICompanyUserChangeApplyService {
 
     private final ICompanyUserChangeApplyUserService companyUserChangeApplyUserService;
-    private final FsUserMapper userMapper;
+    private final IFsUserCompanyUserService userCompanyUserService;
 
     /**
      * 申请更换会员归属
@@ -39,30 +42,32 @@ public class CompanyUserChangeApplyServiceImpl extends ServiceImpl<CompanyUserCh
      */
     @Transactional(rollbackFor = Exception.class)
     @Override
-    public void apply(Long from, Long to, Integer type, List<Long> ids, Long companyId, String userName) {
+    public void apply(Long from, Long to, Integer type, List<UserProjectDTO> ids, Long companyId, String userName) {
         List<CompanyUserChangeApplyUser> users = new ArrayList<>();
 
         // 全部
         if (type == 0) {
-            FsUser param = new FsUser();
-            param.setCompanyUserId(from);
-            List<FsUser> userList = userMapper.selectFsUserList(param);
-            for (FsUser user : userList) {
+            FsUserCompanyUser params = new FsUserCompanyUser();
+            params.setCompanyUserId(from);
+            List<FsUserCompanyUser> userList = userCompanyUserService.selectFsUserCompanyUserList(params);
+            for (FsUserCompanyUser user : userList) {
                 CompanyUserChangeApplyUser uu = new CompanyUserChangeApplyUser();
                 uu.setUserId(user.getUserId());
+                uu.setProjectId(user.getProjectId());
                 users.add(uu);
             }
         }
         // 部分
         else {
-            for (Long id : ids) {
-                FsUser user = userMapper.selectFsUserById(id);
+            for (UserProjectDTO id : ids) {
+                FsUserCompanyUser user = userCompanyUserService.selectByUserIdAndProjectId(id.getUserId(), id.getProjectId());
                 if (Objects.isNull(user)) {
-                    throw new ServiceException("会员不存在");
+                    throw new ServiceException("会员关系不存在");
                 }
 
                 CompanyUserChangeApplyUser uu = new CompanyUserChangeApplyUser();
                 uu.setUserId(user.getUserId());
+                uu.setProjectId(user.getProjectId());
                 users.add(uu);
             }
         }

+ 26 - 1
fs-service/src/main/java/com/fs/company/service/impl/CompanyUserChangeApplyUserServiceImpl.java

@@ -5,13 +5,21 @@ import com.fs.company.domain.CompanyUserChangeApplyUser;
 import com.fs.company.mapper.CompanyUserChangeApplyUserMapper;
 import com.fs.company.service.ICompanyUserChangeApplyUserService;
 import com.fs.company.vo.CompanyUserChangeApplyUserVO;
+import com.fs.system.mapper.SysDictDataMapper;
+import com.fs.system.vo.DictVO;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 @Service
 public class CompanyUserChangeApplyUserServiceImpl extends ServiceImpl<CompanyUserChangeApplyUserMapper, CompanyUserChangeApplyUser> implements ICompanyUserChangeApplyUserService {
 
+    @Autowired
+    private SysDictDataMapper sysDictDataMapper;
+
     /**
      * 查询申请记录关联用户
      * @param applyId   申请记录ID
@@ -19,7 +27,24 @@ public class CompanyUserChangeApplyUserServiceImpl extends ServiceImpl<CompanyUs
      */
     @Override
     public List<CompanyUserChangeApplyUserVO> getApplyUsers(Long applyId) {
-        return baseMapper.getApplyUsers(applyId);
+        List<CompanyUserChangeApplyUserVO> list = baseMapper.getApplyUsers(applyId);
+        List<DictVO> dictVOS = sysDictDataMapper.selectDictDataListByType("sys_course_project");
+
+        // Create a map for faster lookup (dictValue -> dictVO)
+        Map<String, String> projectMap = dictVOS.stream()
+                .collect(Collectors.toMap(DictVO::getDictValue, DictVO::getDictLabel));
+
+        // Iterate through the list and set projectName where projectId matches dictValue
+        for (CompanyUserChangeApplyUserVO vo : list) {
+            if (vo.getProjectId() != null) {
+                String projectName = projectMap.get(vo.getProjectId().toString());
+                if (projectName != null) {
+                    vo.setProjectName(projectName);
+                }
+            }
+        }
+
+        return list;
     }
 
     /**

+ 14 - 2
fs-service/src/main/java/com/fs/company/service/impl/CompanyUserServiceImpl.java

@@ -17,10 +17,12 @@ import com.fs.company.vo.CompanyQwUserByIdsVo;
 import com.fs.company.vo.CompanyUserQwListVO;
 import com.fs.company.vo.CompanyUserVO;
 import com.fs.company.vo.DocCompanyUserVO;
+import com.fs.course.service.IFsUserCompanyUserService;
 import com.fs.his.mapper.FsUserMapper;
 import com.fs.his.service.IFsCityService;
 import com.fs.his.vo.CitysAreaVO;
 import com.fs.his.vo.OptionsVO;
+import com.fs.qw.dto.UserProjectDTO;
 import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.vo.CompanyUserQwVO;
 import com.fs.qw.vo.QwOptionsVO;
@@ -75,6 +77,8 @@ public class CompanyUserServiceImpl implements ICompanyUserService
 
     @Autowired
     private FsUserMapper fsUserMapper;
+    @Autowired
+    private IFsUserCompanyUserService userCompanyUserService;
 
     /**
      * 查询物业公司管理员信息
@@ -491,13 +495,16 @@ public class CompanyUserServiceImpl implements ICompanyUserService
     }
 
     @Override
-    public int changeCompanyUser(List<Long> userIds, Long companyUserId, Long companyId) {
+    public int changeCompanyUser(List<UserProjectDTO> users, Long companyUserId, Long companyId) {
 
         CompanyUser toUser = companyUserMapper.selectCompanyUserById(companyUserId);
         if (Objects.isNull(toUser)) {
             throw new ServiceException("需要更换归属的销售不存在");
         }
-        return fsUserMapper.batchUpdateUserCompanyUser(userIds, companyUserId, companyId);
+        for (UserProjectDTO u : users) {
+            userCompanyUserService.changeRelationship(u.getUserId(), u.getProjectId(), toUser.getCompanyId(), toUser.getUserId());
+        }
+        return 1;
     }
 
     /**
@@ -601,4 +608,9 @@ public class CompanyUserServiceImpl implements ICompanyUserService
     public List<QwOptionsVO> selectQwUserListLikeName(Map<String, Object> params) {
         return companyUserMapper.selectQwUserListLikeName(params);
     }
+
+    @Override
+    public String selectCompanyUserByStrIds(String companyUserIds) {
+        return companyUserMapper.selectCompanyUserNameByIds(companyUserIds);
+    }
 }

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

@@ -12,4 +12,8 @@ public class CompanyTagUserVO {
      * 用户昵称
      */
     private String userName;
+    /**
+     * 项目ID
+     */
+    private Long projectId;
 }

+ 9 - 0
fs-service/src/main/java/com/fs/company/vo/CompanyUserChangeApplyUserVO.java

@@ -8,6 +8,15 @@ public class CompanyUserChangeApplyUserVO {
      * 用户ID
      */
     private Long userId;
+    /**
+     * 项目ID
+     */
+    private Long projectId;
+
+    /**
+     * 项目名称
+     */
+    private String projectName;
     /**
      * 用户名称
      */

+ 15 - 0
fs-service/src/main/java/com/fs/core/config/WxOpenProperties.java

@@ -0,0 +1,15 @@
+package com.fs.core.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@Data
+@Configuration
+@ConfigurationProperties("wx.open")
+public class WxOpenProperties {
+
+    private String appId = "wx703c4bd07bbd1695";
+
+    private String secret = "034f5cc8d9b5151f9d25da9628541e35";
+}

+ 18 - 4
fs-service/src/main/java/com/fs/course/domain/FsUserCompanyUser.java

@@ -1,11 +1,13 @@
 package com.fs.course.domain;
 
+import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
 import com.fs.common.annotation.Excel;
-import com.fs.common.core.domain.BaseEntity;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
-import lombok.EqualsAndHashCode;
+
+import java.time.LocalDateTime;
 
 /**
  * 微信用户和销售关系对象 fs_user_company_user
@@ -14,10 +16,10 @@ import lombok.EqualsAndHashCode;
  * @date 2025-05-09
  */
 @Data
-@EqualsAndHashCode(callSuper = true)
-public class FsUserCompanyUser extends BaseEntity{
+public class FsUserCompanyUser {
 
     /** id */
+    @TableId(type = IdType.AUTO)
     private Long id;
 
     /** 用户id(关联fs_user表user_id) */
@@ -56,6 +58,18 @@ public class FsUserCompanyUser extends BaseEntity{
      * 企微主体ID
      */
     private Long qwCompanyId;
+    /**
+     * 状态 0小黑屋 1正常 2拉黑
+     */
+    private Integer status;
+    /**
+     * 备注
+     */
+    private String remark;
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
 
 
 }

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

@@ -98,4 +98,10 @@ public class FsUserCourseVideo extends BaseEntity
     @JsonFormat(pattern = "HH:mm:ss")
     private LocalTime lastJoinTime;
 
+    private Long userId;
+
+    /**
+     * 项目ID
+     */
+    private Long projectId;
 }

+ 74 - 0
fs-service/src/main/java/com/fs/course/domain/FsVideoBarrage.java

@@ -0,0 +1,74 @@
+package com.fs.course.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 视频弹幕对象 fs_video_barrage
+ *
+ * @author fs
+ * @date 2025-04-07
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class FsVideoBarrage extends BaseEntity{
+    private String cmd;
+    /** 弹幕ID */
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /** 视频ID */
+    @Excel(name = "视频ID")
+    private Long videoId;
+
+    /** 弹幕内容 */
+    @Excel(name = "弹幕内容")
+    private String content;
+
+    /** 弹幕对应视频时间点(毫秒) */
+    @Excel(name = "弹幕对应视频时间点", readConverterExp = "秒")
+    private Long timePoint;
+
+    /** 用户ID */
+    @Excel(name = "用户ID")
+    private Long userId;
+
+    /** 用户名 */
+    @Excel(name = "用户名")
+    private String username;
+
+    /** 发送平台(app / mini_app) */
+    @Excel(name = "发送平台", readConverterExp = "app,mini_app")
+    private String platform;
+
+    /** 状态:1-正常 0-隐藏 */
+    @Excel(name = "状态:1-正常 0-隐藏")
+    private String status;
+
+    /** 弹幕持续时间 */
+    @Excel(name = "弹幕持续时间")
+    private Long duration;
+
+    /** 是否优先显示1是0否,默认为0 */
+    @Excel(name = "是否优先显示1是0否,默认为0")
+    private String isPrior;
+
+    /** 是否彩色弹幕1是0否,默认为0 */
+    @Excel(name = "是否彩色弹幕1是0否,默认为0")
+    private String isColor;
+    // 例:'top',显示模式,top顶部居中,bottom底部居中,scroll滚动,默认为scroll
+    private String mode;
+    //颜色
+    private String color;
+    //字号
+    private String fontSize;
+
+
+
+}

+ 18 - 1
fs-service/src/main/java/com/fs/course/mapper/FsCourseSopAppLinkMapper.java

@@ -6,6 +6,7 @@ import com.fs.course.domain.FsCourseSopAppLink;
 import com.fs.course.vo.FsSopMyCourseLinkVO;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
 
 import java.util.List;
 
@@ -68,6 +69,7 @@ public interface FsCourseSopAppLinkMapper extends BaseMapper<FsCourseSopAppLink>
 
     @Select("SELECT\n" +
             "al.id," +
+            "al.link," +
             "\tal.create_time," +
             "\tal.update_time,\n" +
             "\tal.qw_user_name,\n" +
@@ -81,6 +83,21 @@ public interface FsCourseSopAppLinkMapper extends BaseMapper<FsCourseSopAppLink>
             "\tLEFT JOIN qw_external_contact ec ON al.qw_external_id = ec.id \n" +
             "WHERE\n" +
             "\tec.fs_user_id = #{userId} \n" +
-            "\tAND al.update_time >= NOW() ")
+            "\tAND al.update_time >= NOW() " +
+            "ORDER BY al.is_read asc,al.create_time desc ")
     List<FsSopMyCourseLinkVO> getSopCourseStudyList(@Param("userId") Long userId);
+
+    @Select("SELECT\n" +
+            "\tcount(1) as isNotRead\n" +
+            "FROM\n" +
+            "\tfs_course_sop_app_link al\n" +
+            "\tLEFT JOIN qw_external_contact ec ON al.qw_external_id = ec.id \n" +
+            "WHERE\n" +
+            "\tec.fs_user_id = #{userId} \n" +
+            "\tAND al.is_read = 0 \n" +
+            "\tAND al.update_time >= NOW() ")
+    Integer selectSopCountIsNotRead(@Param("userId") Long userId);
+
+    @Update("update fs_course_sop_app_link set is_read = 1 where link = #{id}")
+    int updateFsCourseSopAppLinkByLink(@Param("id") String id);
 }

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

@@ -398,7 +398,7 @@ public interface FsCourseWatchLogMapper extends BaseMapper<FsCourseWatchLog> {
 
     void batchUpdateFsUserWatchLog(@Param("list") List<FsCourseWatchLog> list);
 
-    @Select("select * from fs_course_watch_log where user_id = #{userId} and video_id = #{videoId} and send_type = 1")
+    @Select("select * from fs_course_watch_log where user_id = #{userId} and video_id = #{videoId} and send_type = 1 order by log_id desc limit 1")
     FsCourseWatchLog getCourseWatchLogByUser(@Param("userId") Long userId, @Param("videoId") Long videoId);
 
     /**

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

@@ -3,10 +3,12 @@ package com.fs.course.mapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.fs.course.domain.FsUserCompanyUser;
 import com.fs.qw.dto.FsUserTransferParamDTO;
+import com.fs.qw.dto.UserProjectDTO;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * 微信用户和销售关系Mapper接口
@@ -79,4 +81,16 @@ public interface FsUserCompanyUserMapper extends BaseMapper<FsUserCompanyUser>{
     List<FsUserCompanyUser> selectRepeatCompanyUserName(@Param("userIds") List<Long> userIds);
 
     void transfer(@Param("param") FsUserTransferParamDTO transferParam);
+
+    /**
+     * 批量修改用户-项目状态
+     * @param ids       参数
+     * @param status    状态
+     * @return  count
+     */
+    int changeUserProjectStatus(@Param("ids") List<UserProjectDTO> ids, @Param("status") int status);
+
+    int batchUpdateStatus(@Param("ids") List<Long> ids, @Param("status") int status);
+
+    List<Long> selectFsUserCompanyUserListByMap(@Param("param") Map<String, Object> param);
 }

+ 14 - 6
fs-service/src/main/java/com/fs/course/mapper/FsUserCourseCommentMapper.java

@@ -8,6 +8,7 @@ import com.fs.course.vo.FsUserCourseCommentListUVO;
 import com.fs.course.vo.FsUserCourseCommentListVO;
 import com.fs.course.vo.FsUserCourseCommentReplyListUVO;
 import com.fs.course.vo.FsUserCourseCommentVO;
+import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 import org.apache.ibatis.annotations.Update;
 
@@ -118,13 +119,20 @@ public interface FsUserCourseCommentMapper
     List<FsUserCourseCommentListUVO> selectFsUserCourseCommentListVOByCourseId(Long courseId);
 
     @Select({"<script> " +
-            "select c.*,u.nick_name,u.avatar,tu.nick_name to_nick_name  from fs_user_course_comment c " +
-            " LEFT JOIN fs_user u ON c.user_id=u.user_id " +
-            " LEFT  JOIN fs_user tu ON tu.user_id =c.to_user_id " +
-            " where c.is_del = 0 and c.type = 2 and c.parent_id = #{commentId} " +
-            " order by c.comment_id desc "+
+            "SELECT c.*, u.nick_name, u.avatar, tu.nick_name to_nick_name, " +
+            "<if test='userId != null and userId != \"\"'>" +
+            "   IFNULL(l.id, 0) AS is_like " +
+            "</if>" +
+            "FROM fs_user_course_comment c " +
+            "LEFT JOIN fs_user u ON c.user_id = u.user_id " +
+            "LEFT JOIN fs_user tu ON tu.user_id = c.to_user_id " +
+            "<if test='userId != null and userId != \"\"'>" +
+            "   LEFT JOIN fs_user_course_comment_like l ON c.comment_id = l.comment_id AND #{userId} = l.user_id " +
+            "</if>" +
+            "WHERE c.is_del = 0 AND c.type = 2 AND c.parent_id = #{commentId} " +
+            "ORDER BY c.comment_id DESC" +
             "</script>"})
-    List<FsUserCourseCommentReplyListUVO> selectFsUserCourseCommentReplyListUVO(Long commentId);
+    List<FsUserCourseCommentReplyListUVO> selectFsUserCourseCommentReplyListUVO(@Param("commentId") Long commentId, @Param("userId") String userId);
 
     @Select({"<script> " +
             "select c.*,u.nick_name,u.avatar,tu.nick_name to_nick_name from fs_user_course_comment c " +

+ 5 - 0
fs-service/src/main/java/com/fs/course/mapper/FsUserCourseMapper.java

@@ -271,4 +271,9 @@ public interface FsUserCourseMapper
     List<FsCourseListBySidebarVO> getFsCourseListBySidebar(@Param("data") FsCourseListBySidebarParam param);
 
     List<FsUserCourseParticipationRecordVO> getParticipationRecordByMap(@Param("params") Map<String, Object> params);
+
+    /**
+     * 查询当天用户-项目看课记录条数
+     */
+    Integer selectTodayCourseWatchLogCountByUserIdAndProjectId(@Param("userId") Long userId, @Param("projectId") Long projectId);
 }

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

@@ -60,7 +60,7 @@ public interface FsUserTalentMapper
      */
     public int deleteFsUserTalentByTalentIds(Long[] talentIds);
 
-    @Update("update fs_user_talent set fans=fans+1 where talent_id=#{talentId}")
+    @Update("update fs_user_talent set fans=ifnull(fans,0)+1 where talent_id=#{talentId}")
     int addFans(Long talentId);
 
 

+ 85 - 0
fs-service/src/main/java/com/fs/course/mapper/FsVideoBarrageMapper.java

@@ -0,0 +1,85 @@
+package com.fs.course.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.common.annotation.DataSource;
+import com.fs.common.enums.DataSourceType;
+import com.fs.course.domain.FsVideoBarrage;
+import com.fs.course.param.FsVideoBarrageQueryParam;
+import com.fs.course.vo.FsVideoBarrageVO;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 视频弹幕Mapper接口
+ *
+ * @author fs
+ * @date 2025-04-07
+ */
+@Repository
+public interface FsVideoBarrageMapper extends BaseMapper<FsVideoBarrage>{
+    /**
+     * 查询视频弹幕
+     *
+     * @param id 视频弹幕主键
+     * @return 视频弹幕
+     */
+    FsVideoBarrage selectFsVideoBarrageById(String id);
+
+    /**
+     * 查询视频弹幕列表
+     *
+     * @param fsVideoBarrage 视频弹幕
+     * @return 视频弹幕集合
+     */
+    @DataSource(DataSourceType.SLAVE)
+    List<FsVideoBarrageVO> selectFsVideoBarrageList(FsVideoBarrageQueryParam fsVideoBarrage);
+
+    /**
+     * 新增视频弹幕
+     *
+     * @param fsVideoBarrage 视频弹幕
+     * @return 结果
+     */
+    int insertFsVideoBarrage(FsVideoBarrage fsVideoBarrage);
+
+    /**
+     * 修改视频弹幕
+     *
+     * @param fsVideoBarrage 视频弹幕
+     * @return 结果
+     */
+    int updateFsVideoBarrage(FsVideoBarrage fsVideoBarrage);
+
+    /**
+     * 删除视频弹幕
+     *
+     * @param id 视频弹幕主键
+     * @return 结果
+     */
+    int deleteFsVideoBarrageById(String id);
+
+    /**
+     * 批量删除视频弹幕
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsVideoBarrageByIds(String[] ids);
+
+
+    int insertBarrage(FsVideoBarrage barrage);
+
+
+    List<FsVideoBarrage> selectByVideoId(@Param("videoId") Long videoId);
+
+
+    List<FsVideoBarrage> selectBySegment(@Param("videoId") Long videoId, @Param("start") int start, @Param("end") int end);
+
+    int updateStatus(@Param("id") Long id, @Param("status") String status);
+
+    int batchUpdateStatus(@Param("ids") ArrayList ids, @Param("status")String status);
+
+}

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

@@ -8,4 +8,7 @@ import java.util.List;
 public class BatchVideoSvae {
     private Long courseId;
     private List<Long> ids;
+
+    // 项目ID
+    private Long projectId;
 }

+ 46 - 0
fs-service/src/main/java/com/fs/course/param/FsVideoBarrageQueryParam.java

@@ -0,0 +1,46 @@
+package com.fs.course.param;
+
+import com.fs.watch.param.BaseQueryParam;
+import lombok.Data;
+
+@Data
+public class FsVideoBarrageQueryParam extends BaseQueryParam {
+    private String cmd;
+    private Long id;
+
+    /** 视频ID */
+    private Long videoId;
+
+    /** 弹幕内容 */
+    private String content;
+
+    /** 弹幕对应视频时间点(毫秒) */
+    private Long timePoint;
+
+    /** 用户ID */
+    private Long userId;
+
+    /** 用户名 */
+    private String username;
+
+    /** 发送平台(app / mini_app) */
+    private String platform;
+
+    /** 状态:1-正常 0-隐藏 */
+    private String status;
+
+    /** 弹幕持续时间 */
+    private Long duration;
+
+    /** 是否优先显示1是0否,默认为0 */
+    private String isPrior;
+
+    /** 是否彩色弹幕1是0否,默认为0 */
+    private String isColor;
+    // 例:'top',显示模式,top顶部居中,bottom底部居中,scroll滚动,默认为scroll
+    private String mode;
+    //颜色
+    private String color;
+    //字号
+    private String fontSize;
+}

+ 1 - 3
fs-service/src/main/java/com/fs/course/param/newfs/FsUserCourseBeMemberParam.java

@@ -24,9 +24,7 @@ public class FsUserCourseBeMemberParam implements Serializable {
     @ApiModelProperty(value = "标签ids,数组格式")
     private String[] tagIds;
 
-//    @NotNull(message = "项目id不能为空")
+    @NotNull(message = "项目id不能为空")
     @ApiModelProperty(value = "课程归属项目id")
     private Long projectId;
-
-
 }

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

@@ -64,4 +64,8 @@ public interface IFsCourseSopAppLinkService extends IService<FsCourseSopAppLink>
 
 
     List<FsSopMyCourseLinkVO>  getSopCourseStudyList(Long userId);
+
+    Integer selectSopCountIsNotRead(Long userId);
+
+    int updateFsCourseSopAppLinkByLink(String id);
 }

+ 35 - 7
fs-service/src/main/java/com/fs/course/service/IFsUserCompanyUserService.java

@@ -2,8 +2,10 @@ package com.fs.course.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.fs.course.domain.FsUserCompanyUser;
+import com.fs.qw.dto.UserProjectDTO;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * 微信用户和销售关系Service接口
@@ -14,7 +16,7 @@ import java.util.List;
 public interface IFsUserCompanyUserService extends IService<FsUserCompanyUser>{
     /**
      * 查询微信用户和销售关系
-     * 
+     *
      * @param id 微信用户和销售关系主键
      * @return 微信用户和销售关系
      */
@@ -22,15 +24,22 @@ public interface IFsUserCompanyUserService extends IService<FsUserCompanyUser>{
 
     /**
      * 查询微信用户和销售关系列表
-     * 
+     *
      * @param fsUserCompanyUser 微信用户和销售关系
      * @return 微信用户和销售关系集合
      */
     List<FsUserCompanyUser> selectFsUserCompanyUserList(FsUserCompanyUser fsUserCompanyUser);
 
+    /**
+     * 根据销售id查询出项目id
+     * @param param
+     * @return
+     */
+    List<Long> selectFsUserCompanyUserList(Map<String,Object> param );
+
     /**
      * 新增微信用户和销售关系
-     * 
+     *
      * @param fsUserCompanyUser 微信用户和销售关系
      * @return 结果
      */
@@ -38,7 +47,7 @@ public interface IFsUserCompanyUserService extends IService<FsUserCompanyUser>{
 
     /**
      * 修改微信用户和销售关系
-     * 
+     *
      * @param fsUserCompanyUser 微信用户和销售关系
      * @return 结果
      */
@@ -46,7 +55,7 @@ public interface IFsUserCompanyUserService extends IService<FsUserCompanyUser>{
 
     /**
      * 批量删除微信用户和销售关系
-     * 
+     *
      * @param ids 需要删除的微信用户和销售关系主键集合
      * @return 结果
      */
@@ -54,11 +63,12 @@ public interface IFsUserCompanyUserService extends IService<FsUserCompanyUser>{
 
     /**
      * 删除微信用户和销售关系信息
-     * 
+     *
      * @param id 微信用户和销售关系主键
      * @return 结果
      */
     int deleteFsUserCompanyUserById(Long id);
+
     /**
      * 根据用户ID和项目ID查询微信用户与销售的关系
      * @param userId            用户ID
@@ -91,12 +101,14 @@ public interface IFsUserCompanyUserService extends IService<FsUserCompanyUser>{
 
     /**
      * 绑定会员-项目-销售关系
+     *
      * @param userId        会员ID
      * @param projectId     项目ID
      * @param companyId     公司ID
      * @param companyUserId 销售ID
+     * @param status        状态 1正常 0小黑屋
      */
-    void bindRelationship(Long userId, Long projectId, Long companyId, Long companyUserId);
+    FsUserCompanyUser bindRelationship(Long userId, Long projectId, Long companyId, Long companyUserId, int status);
 
     /**
      * 修改会员-项目-销售关系
@@ -106,4 +118,20 @@ public interface IFsUserCompanyUserService extends IService<FsUserCompanyUser>{
      * @param companyUserId 销售ID
      */
     void changeRelationship(Long userId, Long projectId, Long companyId, Long companyUserId);
+
+    /**
+     * 修改会员-项目关系 状态
+     * @param ids       参数
+     * @param status    状态 0小黑屋 1正常 2拉黑
+     * @return Boolean
+     */
+    Boolean batchUpdateUserProjectStatus(List<UserProjectDTO> ids, int status);
+
+    /**
+     * 修改会员-项目关系 状态
+     * @param ids       参数
+     * @param status    状态 0小黑屋 1正常 2拉黑
+     * @return Boolean
+     */
+    Boolean batchUpdateStatus(List<Long> ids, int status);
 }

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

@@ -73,7 +73,7 @@ public interface IFsUserCourseCommentService
 
     List<FsUserCourseCommentListUVO> selectFsUserCourseCommentListUVO(FsUserCourseCommentUParam param);
 
-    List<FsUserCourseCommentReplyListUVO> selectFsUserCourseCommentReplyListUVO(Long commentId);
+    List<FsUserCourseCommentReplyListUVO> selectFsUserCourseCommentReplyListUVO(Long commentId, String userId);
 
     List<FsUserCourseCommentListUVO> selectFsUserCourseCommentMyListUVO(Long userId);
 

+ 77 - 0
fs-service/src/main/java/com/fs/course/service/IFsVideoBarrageService.java

@@ -0,0 +1,77 @@
+package com.fs.course.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.course.domain.FsVideoBarrage;
+import com.fs.course.param.FsVideoBarrageQueryParam;
+import com.fs.course.vo.FsVideoBarrageExcelVo;
+import com.fs.course.vo.FsVideoBarrageVO;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 视频弹幕Service接口
+ *
+ * @author fs
+ * @date 2025-04-07
+ */
+public interface IFsVideoBarrageService extends IService<FsVideoBarrage>{
+    /**
+     * 查询视频弹幕
+     *
+     * @param id 视频弹幕主键
+     * @return 视频弹幕
+     */
+    FsVideoBarrage selectFsVideoBarrageById(String id);
+
+    /**
+     * 查询视频弹幕列表
+     *
+     * @param fsVideoBarrage 视频弹幕
+     * @return 视频弹幕集合
+     */
+    List<FsVideoBarrageVO> selectFsVideoBarrageList(FsVideoBarrageQueryParam fsVideoBarrage);
+
+    /**
+     * 新增视频弹幕
+     *
+     * @param fsVideoBarrage 视频弹幕
+     * @return 结果
+     */
+    int insertFsVideoBarrage(FsVideoBarrage fsVideoBarrage);
+
+    /**
+     * 修改视频弹幕
+     *
+     * @param fsVideoBarrage 视频弹幕
+     * @return 结果
+     */
+    int updateFsVideoBarrage(FsVideoBarrage fsVideoBarrage);
+
+    /**
+     * 批量删除视频弹幕
+     *
+     * @param ids 需要删除的视频弹幕主键集合
+     * @return 结果
+     */
+    int deleteFsVideoBarrageByIds(String[] ids);
+
+    /**
+     * 删除视频弹幕信息
+     *
+     * @param id 视频弹幕主键
+     * @return 结果
+     */
+    int deleteFsVideoBarrageById(String id);
+
+    int saveBarrage(FsVideoBarrage barrage);
+    List<FsVideoBarrage> getBarrageByVideoId(Long videoId);
+    List<FsVideoBarrage> getSegmentBarrage(Long videoId, int start, int end);
+    int updateStatus(FsVideoBarrage barrage);
+    int batchUpdateStatus(ArrayList ids, String status);
+    R importBarrageData(List<FsVideoBarrageExcelVo> list, boolean updateSupport, LoginUser loginUser);
+
+
+}

+ 10 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsCourseSopAppLinkServiceImpl.java

@@ -97,4 +97,14 @@ public class FsCourseSopAppLinkServiceImpl extends ServiceImpl<FsCourseSopAppLin
     public List<FsSopMyCourseLinkVO> getSopCourseStudyList(Long userId) {
         return baseMapper.getSopCourseStudyList(userId);
     }
+
+    @Override
+    public Integer selectSopCountIsNotRead(Long userId) {
+        return baseMapper.selectSopCountIsNotRead(userId);
+    }
+
+    @Override
+    public int updateFsCourseSopAppLinkByLink(String id) {
+        return baseMapper.updateFsCourseSopAppLinkByLink(id);
+    }
 }

+ 58 - 9
fs-service/src/main/java/com/fs/course/service/impl/FsUserCompanyUserServiceImpl.java

@@ -3,12 +3,16 @@ package com.fs.course.service.impl;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.exception.CustomException;
 import com.fs.course.domain.FsUserCompanyUser;
 import com.fs.course.mapper.FsUserCompanyUserMapper;
 import com.fs.course.service.IFsUserCompanyUserService;
+import com.fs.qw.dto.UserProjectDTO;
 import org.springframework.stereotype.Service;
 
+import java.time.LocalDateTime;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -22,7 +26,7 @@ public class FsUserCompanyUserServiceImpl extends ServiceImpl<FsUserCompanyUserM
 
     /**
      * 查询微信用户和销售关系
-     * 
+     *
      * @param id 微信用户和销售关系主键
      * @return 微信用户和销售关系
      */
@@ -34,7 +38,7 @@ public class FsUserCompanyUserServiceImpl extends ServiceImpl<FsUserCompanyUserM
 
     /**
      * 查询微信用户和销售关系列表
-     * 
+     *
      * @param fsUserCompanyUser 微信用户和销售关系
      * @return 微信用户和销售关系
      */
@@ -44,9 +48,18 @@ public class FsUserCompanyUserServiceImpl extends ServiceImpl<FsUserCompanyUserM
         return baseMapper.selectFsUserCompanyUserList(fsUserCompanyUser);
     }
 
+    /**
+     * 根据销售id查询出项目id
+     * @return 微信用户和销售关系
+     */
+    @Override
+    public List<Long> selectFsUserCompanyUserList(Map<String,Object> param) {
+
+        return baseMapper.selectFsUserCompanyUserListByMap(param);
+    }
     /**
      * 新增微信用户和销售关系
-     * 
+     *
      * @param fsUserCompanyUser 微信用户和销售关系
      * @return 结果
      */
@@ -58,7 +71,7 @@ public class FsUserCompanyUserServiceImpl extends ServiceImpl<FsUserCompanyUserM
 
     /**
      * 修改微信用户和销售关系
-     * 
+     *
      * @param fsUserCompanyUser 微信用户和销售关系
      * @return 结果
      */
@@ -70,7 +83,7 @@ public class FsUserCompanyUserServiceImpl extends ServiceImpl<FsUserCompanyUserM
 
     /**
      * 批量删除微信用户和销售关系
-     * 
+     *
      * @param ids 需要删除的微信用户和销售关系主键
      * @return 结果
      */
@@ -82,7 +95,7 @@ public class FsUserCompanyUserServiceImpl extends ServiceImpl<FsUserCompanyUserM
 
     /**
      * 删除微信用户和销售关系信息
-     * 
+     *
      * @param id 微信用户和销售关系主键
      * @return 结果
      */
@@ -142,21 +155,27 @@ public class FsUserCompanyUserServiceImpl extends ServiceImpl<FsUserCompanyUserM
 
     /**
      * 绑定会员-项目-销售关系
+     *
      * @param userId        会员ID
      * @param projectId     项目ID
      * @param companyId     公司ID
      * @param companyUserId 销售ID
+     * @param status        状态 0小黑屋 1正常
      */
     @Override
-    public void bindRelationship(Long userId, Long projectId, Long companyId, Long companyUserId) {
+    public FsUserCompanyUser bindRelationship(Long userId, Long projectId, Long companyId, Long companyUserId, int status) {
         FsUserCompanyUser userCompanyUser = new FsUserCompanyUser();
         userCompanyUser.setUserId(userId);
         userCompanyUser.setProjectId(projectId);
         userCompanyUser.setCompanyId(companyId);
         userCompanyUser.setCompanyUserId(companyUserId);
-        boolean hasBind = hasBind(userId, companyUserId);
-        userCompanyUser.setIsRepeatFans(hasBind ? 1 : 0);
+//        boolean hasBind = hasBind(userId, companyUserId);
+//        userCompanyUser.setIsRepeatFans(hasBind ? 1 : 0);
+        userCompanyUser.setIsRepeatFans(0);
+        userCompanyUser.setStatus(status);
+        userCompanyUser.setCreateTime(LocalDateTime.now());
         save(userCompanyUser);
+        return userCompanyUser;
     }
 
     /**
@@ -179,4 +198,34 @@ public class FsUserCompanyUserServiceImpl extends ServiceImpl<FsUserCompanyUserM
             updateById(userCompanyUser);
         }
     }
+
+    /**
+     * 修改会员-项目关系 状态
+     * @param ids       参数
+     * @param status    状态 0小黑屋 1正常 2拉黑
+     * @return Boolean
+     */
+    @Override
+    public Boolean batchUpdateUserProjectStatus(List<UserProjectDTO> ids, int status) {
+        if (Objects.isNull(ids) || ids.isEmpty()) {
+            throw new CustomException("请先选择会员");
+        }
+        return baseMapper.changeUserProjectStatus(ids, status) > 0;
+    }
+
+
+
+    /**
+     * 修改会员-项目关系 状态
+     * @param ids       参数
+     * @param status    状态 0小黑屋 1正常 2拉黑
+     * @return Boolean
+     */
+    @Override
+    public Boolean batchUpdateStatus(List<Long> ids, int status) {
+        if (Objects.isNull(ids) || ids.isEmpty()) {
+            throw new CustomException("请先选择会员");
+        }
+        return baseMapper.batchUpdateStatus(ids, status) > 0;
+    }
 }

+ 2 - 2
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseCommentServiceImpl.java

@@ -150,7 +150,7 @@ public class FsUserCourseCommentServiceImpl implements IFsUserCourseCommentServi
     }
 
     @Override
-    public List<FsUserCourseCommentReplyListUVO> selectFsUserCourseCommentReplyListUVO(Long commentId) {
-        return fsUserCourseCommentMapper.selectFsUserCourseCommentReplyListUVO(commentId);
+    public List<FsUserCourseCommentReplyListUVO> selectFsUserCourseCommentReplyListUVO(Long commentId, String userId) {
+        return fsUserCourseCommentMapper.selectFsUserCourseCommentReplyListUVO(commentId, userId);
     }
 }

+ 14 - 1
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseOrderServiceImpl.java

@@ -23,14 +23,17 @@ import com.fs.course.vo.FsUserCourseOrderListUVO;
 import com.fs.his.domain.*;
 import com.fs.his.dto.PayConfigDTO;
 import com.fs.his.enums.FsPackageOrderStatusEnum;
+import com.fs.his.enums.FsUserIntegralLogTypeEnum;
 import com.fs.his.mapper.FsStorePaymentErrorMapper;
 import com.fs.his.mapper.FsStorePaymentMapper;
 import com.fs.his.mapper.FsUserIntegralLogsMapper;
 import com.fs.his.mapper.FsUserMapper;
 import com.fs.his.param.FsPackageOrderDoPayParam;
+import com.fs.his.param.FsUserAddIntegralTemplateParam;
 import com.fs.his.service.IFsCouponService;
 import com.fs.his.service.IFsStorePaymentService;
 import com.fs.his.service.IFsUserCouponService;
+import com.fs.his.service.IFsUserIntegralLogsService;
 import com.fs.huifuPay.domain.HuiFuCreateOrder;
 import com.fs.huifuPay.domain.HuifuCreateOrderResult;
 import com.fs.huifuPay.service.HuiFuService;
@@ -123,7 +126,8 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
     private WxPayProperties wxPayProperties;
     @Autowired
     private TzBankService tzBankService;
-
+    @Autowired
+    private IFsUserIntegralLogsService userIntegralLogsService;
 
 
 
@@ -645,6 +649,15 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
                     fsUserCourseStudyLogMapper.insertFsUserCourseStudyLog(log);
                 }
             }
+
+            // 付费课程订阅
+            FsUserAddIntegralTemplateParam integralParam = new FsUserAddIntegralTemplateParam();
+            integralParam.setUserId(order.getUserId());
+            integralParam.setLogType(FsUserIntegralLogTypeEnum.TYPE_24.getValue());
+            integralParam.setBusinessId(order.getOrderId().toString());
+            integralParam.setPoints(order.getPayMoney().intValue());
+            userIntegralLogsService.addIntegralTemplate(integralParam);
+
             return R.ok();
         }catch (Exception e){
             logger.info("支付错误:"+e.getMessage());

+ 31 - 19
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseServiceImpl.java

@@ -31,8 +31,11 @@ import com.fs.course.vo.newfs.FsUserCourseListVO;
 import com.fs.his.config.IntegralConfig;
 import com.fs.his.domain.FsUser;
 import com.fs.his.domain.FsUserIntegralLogs;
+import com.fs.his.enums.FsUserIntegralLogTypeEnum;
 import com.fs.his.mapper.FsUserIntegralLogsMapper;
 import com.fs.his.mapper.FsUserMapper;
+import com.fs.his.param.FsUserAddIntegralTemplateParam;
+import com.fs.his.service.IFsUserIntegralLogsService;
 import com.fs.his.service.IFsUserNewTaskService;
 import com.fs.his.vo.OptionsVO;
 import com.fs.qw.domain.QwCompany;
@@ -115,6 +118,8 @@ public class FsUserCourseServiceImpl implements IFsUserCourseService
 
     @Autowired
     private AsyncUploadQwCourseImageService asyncUploadQwCourseImageService;
+    @Autowired
+    private IFsUserIntegralLogsService userIntegralLogsService;
 
     private static final String realLink = "/courseH5/pages/course/learning?course=";
     public static final String shortLink = "/courseH5/pages/course/learning?s=";
@@ -301,9 +306,9 @@ public class FsUserCourseServiceImpl implements IFsUserCourseService
             return R.error("课堂不存在");
         }
 
-        if (param.getDuration()>=600){
-            fsUserNewTaskService.performTaskTwo(param.getUserId());
-        }
+//        if (param.getDuration()>=600){
+//            fsUserNewTaskService.performTaskTwo(param.getUserId());
+//        }
         FsUserCourseStudyLog log = getOrCreateStudyLog(param, course, courseVideo);
 
         FsUserCourseStudy courseStudy = fsUserCourseStudyMapper.selectFsUserCourseStudyByAddStudy(param.getUserId(), param.getCourseId());
@@ -355,27 +360,34 @@ public class FsUserCourseServiceImpl implements IFsUserCourseService
             return R.error("当天芳华币已达限额");
         }
         int rate = (int)((double)param.getDuration() / video.getDuration() * 100);
-        if (rate>=50){
+        if (rate>=90){
             FsUserIntegralLogs integralLogs = fsUserIntegralLogsMapper.selectFsUserIntegralByCourseVideo(param.getVideoId(),param.getUserId());
             if (integralLogs!=null){
                 return R.error("该用户已获取此小节积分");
             }
-            FsUser userMap = new FsUser();
-            userMap.setIntegral(user.getIntegral()+config.getIntegralCourse());
-            userMap.setUserId(user.getUserId());
-            fsUserMapper.updateFsUser(userMap);
-            integralLogs = new FsUserIntegralLogs();
-            //写入日志
-            integralLogs.setIntegral(config.getIntegralCourse().longValue());
-            integralLogs.setUserId(param.getUserId());
-            integralLogs.setBalance(userMap.getIntegral());
-            integralLogs.setLogType(10);
-            integralLogs.setBusinessId(video.getVideoId().toString());
-            integralLogs.setCreateTime(new Date());
-            fsUserIntegralLogsMapper.insertFsUserIntegralLogs(integralLogs);
-            return R.ok("恭喜您获得"+config.getIntegralCourse()+"芳华币");
+
+            FsUserAddIntegralTemplateParam integralTemplateParam = new FsUserAddIntegralTemplateParam();
+            integralTemplateParam.setUserId(param.getUserId());
+            integralTemplateParam.setLogType(FsUserIntegralLogTypeEnum.TYPE_10.getValue());
+            integralTemplateParam.setBusinessId(video.getVideoId().toString());
+            return userIntegralLogsService.addIntegralTemplate(integralTemplateParam);
+
+//            FsUser userMap = new FsUser();
+//            userMap.setIntegral(user.getIntegral()+config.getIntegralCourse());
+//            userMap.setUserId(user.getUserId());
+//            fsUserMapper.updateFsUser(userMap);
+//            integralLogs = new FsUserIntegralLogs();
+//            //写入日志
+//            integralLogs.setIntegral(config.getIntegralCourse().longValue());
+//            integralLogs.setUserId(param.getUserId());
+//            integralLogs.setBalance(userMap.getIntegral());
+//            integralLogs.setLogType(10);
+//            integralLogs.setBusinessId(video.getVideoId().toString());
+//            integralLogs.setCreateTime(new Date());
+//            fsUserIntegralLogsMapper.insertFsUserIntegralLogs(integralLogs);
+//            return R.ok("恭喜您获得"+config.getIntegralCourse()+"芳华币");
         }
-        return R.error("观看进度不满百分之五十");
+        return R.error("观看进度不满百分之十");
     }
 
     private FsUserCourseStudyLog getOrCreateStudyLog(FsUserCourseAddStudyCourseParam param, FsUserCourse course, FsUserCourseVideo courseVideo) {

+ 33 - 13
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -29,6 +29,7 @@ import com.fs.course.dto.CoursePackageDTO;
 import com.fs.course.mapper.*;
 import com.fs.course.param.*;
 import com.fs.course.param.newfs.*;
+import com.fs.course.service.IFsUserCompanyUserService;
 import com.fs.course.service.IFsUserCourseVideoService;
 import com.fs.course.service.IFsVideoResourceService;
 import com.fs.course.vo.FsCourseVideoListBySidebarVO;
@@ -199,6 +200,8 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     private CompanyMapper companyMapper;
     @Autowired
     private IFsUserWxService fsUserWxService;
+    @Autowired
+    private IFsUserCompanyUserService userCompanyUserService;
 
 
     /**
@@ -1402,7 +1405,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     @Override
     @Transactional
     public ResponseResult<Boolean> isAddCompanyUser(FsUserCourseAddCompanyUserParam param) {
-        logger.info("=======================进入个微-判断是否添加客服===========================,入参:{}",param);
+        logger.info("\n 【进入个微-判断是否添加客服】,入参:{}",param);
         //查询用户
         FsUser fsUser = fsUserMapper.selectFsUserById(param.getUserId());
         if (fsUser == null){
@@ -1418,19 +1421,24 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         //判断:1、如果没有绑定销售,就返回给客服的微信图片;
         //2、如果只绑定了当前销售,需要添加看课记录(正常流程);
         //3、以上都不是,则标识重粉,需要加入关系表,并打上重粉标签
-        if(fsUser.getCompanyUserId() == null) {
+        FsUserCompanyUser userCompanyUser = userCompanyUserService.selectByUserIdAndProjectId(fsUser.getUserId(), param.getProjectId());
+        if(Objects.isNull(userCompanyUser)) {
             return ResponseResult.fail(BizResponseEnum.DATA_NOT_EXIST, getCompanyUserQRCode(companyUser));
         }
 
         // 逻辑调整:如果会员已经绑定了销售,直接提示,不添加重粉数据了-2025年6月16日14点53分
-        if (!param.getCompanyUserId().equals(fsUser.getCompanyUserId())){
-            return ResponseResult.fail(406,"该用户已成为其他销售会员");
+        if (!param.getCompanyUserId().equals(userCompanyUser.getCompanyUserId())){
+            return ResponseResult.fail(500,"该用户("+fsUser.getUserId() + ")已成为其他销售会员");
         }
 
         // 如果开启了黑名单审核,需要提示
-        if(fsUser.getStatus() == 0) {
-            return ResponseResult.fail(505, "请微信联系您的群主~");
-//            return ResponseResult.fail(BizResponseEnum.WAIT_APPROVAL,getCompanyUserQRCode(companyUser));
+        if(userCompanyUser.getStatus() == 0) {
+//            return ResponseResult.fail(505, "管理开启了会员审核,请等待审核");
+            return ResponseResult.fail(BizResponseEnum.WAIT_APPROVAL,getCompanyUserQRCode(companyUser));
+        }
+
+        if (userCompanyUser.getStatus() == 2) {
+            return ResponseResult.fail(504, "已被拉黑,请联系管理员");
         }
 
         //查询看课记录
@@ -1443,6 +1451,17 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             courseProject = fsUserCourse.getProject();
         }
 
+        // 项目校验
+        if (Objects.isNull(courseProject) || !courseProject.equals(param.getProjectId())) {
+            return ResponseResult.fail(504, "课程项目不匹配");
+        }
+
+        // 项目看课数限制
+        Integer logCount = fsUserCourseMapper.selectTodayCourseWatchLogCountByUserIdAndProjectId(param.getUserId(), param.getProjectId());
+        if (Objects.isNull(watchCourseVideo) && logCount > 0) {
+            return ResponseResult.fail(504, "超过项目看课数量限制");
+        }
+
         //添加判断:该用户是否已经存在此课程的看课记录,并且看课记录的销售id不是传入的销售id
         if(watchCourseVideo != null){
             if(!watchCourseVideo.getCompanyUserId().equals(param.getCompanyUserId())) {
@@ -1473,12 +1492,12 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
         // 添加会员销售关系表数据
         // 逻辑调整:如果会员已经绑定了销售,直接提示,不添加重粉数据了-2025年6月16日14点58分
-        FsUserCompanyUser fsUserCompanyUser = getFsUserCompanyUser(param, fsUser);
-        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);
-        }
+//        FsUserCompanyUser fsUserCompanyUser = getFsUserCompanyUser(param, fsUser);
+//        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);
+//        }
 
 //        // 如果重粉需要打上重粉标签
 //        if(1 == fsUserCompanyUser.getIsRepeatFans()){
@@ -1708,6 +1727,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             entity.setFileSize(e.getFileSize());
             entity.setFileKey(e.getFileKey());
             entity.setIsTranscode(0);
+            entity.setProjectId(vo.getProjectId());
             return entity;
         }).collect(Collectors.toList());
         fsUserCourseVideoMapper.insertBatchFsUserCourseVideo(collect);

+ 172 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsVideoBarrageServiceImpl.java

@@ -0,0 +1,172 @@
+package com.fs.course.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.BeanCopyUtils;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.exception.ServiceException;
+import com.fs.common.utils.DateUtils;
+import com.fs.course.domain.FsUserCourseVideo;
+import com.fs.course.domain.FsVideoBarrage;
+import com.fs.course.mapper.FsVideoBarrageMapper;
+import com.fs.course.param.FsVideoBarrageQueryParam;
+import com.fs.course.service.IFsUserCourseVideoService;
+import com.fs.course.service.IFsVideoBarrageService;
+import com.fs.course.vo.FsVideoBarrageExcelVo;
+import com.fs.course.vo.FsVideoBarrageVO;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 视频弹幕Service业务层处理
+ *
+ * @author fs
+ * @date 2025-04-07
+ */
+@Service
+@Slf4j
+public class FsVideoBarrageServiceImpl extends ServiceImpl<FsVideoBarrageMapper, FsVideoBarrage> implements IFsVideoBarrageService {
+
+
+    @Autowired
+    private FsVideoBarrageMapper barrageMapper;
+    @Autowired
+    private IFsUserCourseVideoService courseVideoService;
+    /**
+     * 查询视频弹幕
+     *
+     * @param id 视频弹幕主键
+     * @return 视频弹幕
+     */
+    @Override
+    public FsVideoBarrage selectFsVideoBarrageById(String id)
+    {
+        return baseMapper.selectFsVideoBarrageById(id);
+    }
+
+    /**
+     * 查询视频弹幕列表
+     *
+     * @param fsVideoBarrage 视频弹幕
+     * @return 视频弹幕
+     */
+    @Override
+    public List<FsVideoBarrageVO> selectFsVideoBarrageList(FsVideoBarrageQueryParam fsVideoBarrage)
+    {
+        return baseMapper.selectFsVideoBarrageList(fsVideoBarrage);
+    }
+
+    /**
+     * 新增视频弹幕
+     *
+     * @param fsVideoBarrage 视频弹幕
+     * @return 结果
+     */
+    @Override
+    public int insertFsVideoBarrage(FsVideoBarrage fsVideoBarrage)
+    {
+        FsUserCourseVideo fsUserCourseVideo = courseVideoService.selectFsUserCourseVideoByVideoId(fsVideoBarrage.getVideoId());
+        if (null==fsUserCourseVideo.getDuration()||0>fsUserCourseVideo.getDuration()){
+            throw new ServiceException("视频时长异常,请检查");
+        }
+        if (fsVideoBarrage.getTimePoint()>fsUserCourseVideo.getDuration()){
+            throw new ServiceException("弹幕时间节点不能大于视频时长,视频时长:"+fsUserCourseVideo.getDuration()+"秒");
+        }
+        fsVideoBarrage.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertFsVideoBarrage(fsVideoBarrage);
+    }
+
+    /**
+     * 修改视频弹幕
+     *
+     * @param fsVideoBarrage 视频弹幕
+     * @return 结果
+     */
+    @Override
+    public int updateFsVideoBarrage(FsVideoBarrage fsVideoBarrage)
+    {
+        FsUserCourseVideo fsUserCourseVideo = courseVideoService.selectFsUserCourseVideoByVideoId(fsVideoBarrage.getVideoId());
+        if (fsUserCourseVideo != null && fsUserCourseVideo.getDuration() != null){
+            if (fsVideoBarrage.getTimePoint()>fsUserCourseVideo.getDuration()){
+                throw new ServiceException("弹幕时间节点不能大于视频时长,视频时长:"+fsUserCourseVideo.getDuration()+"秒");
+            }
+        }
+        return baseMapper.updateFsVideoBarrage(fsVideoBarrage);
+    }
+
+    /**
+     * 批量删除视频弹幕
+     *
+     * @param ids 需要删除的视频弹幕主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsVideoBarrageByIds(String[] ids)
+    {
+        return baseMapper.deleteFsVideoBarrageByIds(ids);
+    }
+
+    /**
+     * 删除视频弹幕信息
+     *
+     * @param id 视频弹幕主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsVideoBarrageById(String id)
+    {
+        return baseMapper.deleteFsVideoBarrageById(id);
+    }
+
+    @Override
+    public int saveBarrage(FsVideoBarrage barrage) {
+        return barrageMapper.insertBarrage(barrage);
+    }
+
+    @Override
+    public List<FsVideoBarrage> getBarrageByVideoId(Long videoId) {
+        return barrageMapper.selectByVideoId(videoId);
+    }
+
+    @Override
+    public List<FsVideoBarrage> getSegmentBarrage(Long videoId, int start, int end) {
+        return barrageMapper.selectBySegment(videoId, start, end);
+    }
+
+    @Override
+    public int updateStatus(FsVideoBarrage barrage) {
+        return barrageMapper.updateStatus(barrage.getId(), barrage.getStatus());
+    }
+
+    @Override
+    public int batchUpdateStatus(ArrayList ids, String status) {
+        return barrageMapper.batchUpdateStatus(ids,status);
+    }
+
+    @Override
+    public R importBarrageData(List<FsVideoBarrageExcelVo> list, boolean updateSupport, LoginUser loginUser) {
+        if (com.fs.common.utils.StringUtils.isNull(list) || list.size() == 0)
+        {
+            throw new ServiceException("导入弹幕数据不能为空!");
+        }
+            for (FsVideoBarrageExcelVo barrageExcelVo : list) {
+                try {
+                FsVideoBarrage fsVideoBarrage = new FsVideoBarrage();
+                BeanCopyUtils.copy(barrageExcelVo,fsVideoBarrage);
+                fsVideoBarrage.setUserId(loginUser.getUserId());
+                fsVideoBarrage.setUsername(loginUser.getUsername());
+                fsVideoBarrage.setMode("scroll");
+                barrageMapper.insertBarrage(fsVideoBarrage);
+                log.info("复制到实体类:{}",fsVideoBarrage);
+                }catch (Exception e){
+                    throw new ServiceException("导入失败");
+                }
+            }
+        return R.ok("导入成功");
+    }
+
+}

+ 2 - 0
fs-service/src/main/java/com/fs/course/vo/FsSopMyCourseLinkVO.java

@@ -13,6 +13,8 @@ public class FsSopMyCourseLinkVO {
     /** 主键Id */
     private Long id;
 
+    private String link;
+
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private String createTime;
 

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

@@ -45,5 +45,6 @@ public class FsUserCourseCommentReplyListUVO {
     private Date createTime;
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date updateTime;
-
+    //是否点赞 1是 0否
+    private Integer isLike;
 }

+ 61 - 0
fs-service/src/main/java/com/fs/course/vo/FsVideoBarrageExcelVo.java

@@ -0,0 +1,61 @@
+package com.fs.course.vo;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+
+@Data
+public class FsVideoBarrageExcelVo extends BaseEntity {
+
+    /** 弹幕ID */
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /** 视频ID */
+    @Excel(name = "视频ID")
+    private Long videoId;
+    /** 视频名称 */
+    /** 弹幕内容 */
+    @Excel(name = "弹幕内容")
+    private String content;
+
+    /** 弹幕对应视频时间点(毫秒) */
+    @Excel(name = "对应时间")
+    private Long timePoint;
+
+    /** 用户ID */
+    //@Excel(name = "用户ID")
+    private Long userId;
+
+    /** 用户名 */
+    //@Excel(name = "用户名")
+    private String username;
+
+    /** 发送平台(app / uniapp) */
+    @Excel(name = "发送平台", combo = {"app", "uniapp"},defaultValue="app")
+    private String platform;
+
+    /** 状态:1-正常 0-隐藏 */
+    @Excel(name = "状态",combo = {"正常", "隐藏"},defaultValue="正常",readConverterExp = "0=隐藏,1=正常")
+    private String status;
+
+    /** 弹幕持续时间 */
+    @Excel(name = "持续时间")
+    private Long duration;
+
+    /** 是否优先显示1是0否,默认为0 */
+    @Excel(name = "是否优先显示", combo = {"是", "否"},defaultValue="否",readConverterExp = "0=否,1=是")
+    private String isPrior;
+
+    /** 是否彩色弹幕1是0否,默认为0 */
+    @Excel(name = "是否彩色弹幕", combo = {"是", "否"},defaultValue="否",readConverterExp = "0=否,1=是")
+    private String isColor;
+    // 例:'top',显示模式,top顶部居中,bottom底部居中,scroll滚动,默认为scroll
+    private String mode;
+    //颜色
+    private String color;
+    //字号
+    private String fontSize;
+}

+ 63 - 0
fs-service/src/main/java/com/fs/course/vo/FsVideoBarrageVO.java

@@ -0,0 +1,63 @@
+package com.fs.course.vo;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+@Data
+public class FsVideoBarrageVO {
+    private String cmd;
+    /** 弹幕ID */
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /** 视频ID */
+
+    private Long videoId;
+
+    @Excel(name = "视频ID")
+    private String videoTitle;
+
+    /** 弹幕内容 */
+    @Excel(name = "弹幕内容")
+    private String content;
+
+    /** 弹幕对应视频时间点(毫秒) */
+    @Excel(name = "弹幕对应视频时间点", readConverterExp = "秒")
+    private Long timePoint;
+
+    /** 用户ID */
+    @Excel(name = "用户ID")
+    private Long userId;
+
+    /** 用户名 */
+    @Excel(name = "用户名")
+    private String username;
+
+    /** 发送平台(app / mini_app) */
+    @Excel(name = "发送平台", readConverterExp = "app,mini_app")
+    private String platform;
+
+    /** 状态:1-正常 0-隐藏 */
+    @Excel(name = "状态:1-正常 0-隐藏")
+    private String status;
+
+    /** 弹幕持续时间 */
+    @Excel(name = "弹幕持续时间")
+    private Long duration;
+
+    /** 是否优先显示1是0否,默认为0 */
+    @Excel(name = "是否优先显示1是0否,默认为0")
+    private String isPrior;
+
+    /** 是否彩色弹幕1是0否,默认为0 */
+    @Excel(name = "是否彩色弹幕1是0否,默认为0")
+    private String isColor;
+    // 例:'top',显示模式,top顶部居中,bottom底部居中,scroll滚动,默认为scroll
+    private String mode;
+    //颜色
+    private String color;
+    //字号
+    private String fontSize;
+}

+ 83 - 0
fs-service/src/main/java/com/fs/gtPush/domain/UniPushLog.java

@@ -0,0 +1,83 @@
+package com.fs.gtPush.domain;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+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.fs.common.annotation.Excel;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * uni推送消息记录对象 uni_push_log
+ *
+ * @author fs
+ * @date 2025-03-12
+ */
+@Data
+@Getter
+@Setter
+@EqualsAndHashCode(callSuper = false)
+public class UniPushLog {
+
+    /** id */
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /** 推送id */
+    @Excel(name = "推送id")
+    private String jpushId;
+
+    /** 推送类型:0 订单通知 1健康管理 2营销 */
+    @Excel(name = "推送类型:0 订单通知(0.1药品 0.2服务包) 1健康管理 2营销")
+    private Float type;
+
+    /** 详细类型:
+     type:1 0:未支付 1:支付成功 2:发货 3:派送 4:签收 */
+    @Excel(name = "详细类型:")
+    private Integer desType;
+
+    /** 关联用户id */
+    @Excel(name = "关联用户id")
+    private Long userId;
+
+
+    /** 关联事件id */
+    @Excel(name = "关联事件id")
+    private Long businessId;
+
+
+
+    /** 推送内容 */
+    @Excel(name = "推送内容")
+    private String pushMsg;
+
+    /** 推送结果 1:成功 0:失败 */
+    @Excel(name = "推送结果 1:成功 0:失败")
+    private Integer pushRes;
+
+    /** 返回结果详情 */
+    @Excel(name = "返回结果详情")
+    private String returnMsg;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @TableField(fill = FieldFill.INSERT)
+    private Date createTime;
+
+
+    /** 更新时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Date updateTime;
+
+    /** app是否已读 0:否 1:是 */
+    private Integer isRead;
+
+
+
+}

+ 72 - 0
fs-service/src/main/java/com/fs/gtPush/mapper/PushLogMapper.java

@@ -0,0 +1,72 @@
+package com.fs.gtPush.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.gtPush.domain.UniPushLog;
+import com.fs.gtPush.param.UniPushLogParam;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * uni推送消息记录Mapper接口
+ *
+ * @author fs
+ * @date 2025-03-12
+ */
+public interface PushLogMapper extends BaseMapper<UniPushLog>{
+    /**
+     * 查询uni推送消息记录
+     *
+     * @param id uni推送消息记录主键
+     * @return uni推送消息记录
+     */
+    UniPushLog selectPushLogById(String id);
+
+    /**
+     * 查询uni推送消息记录列表
+     *
+     * @param UniPushLog uni推送消息记录
+     * @return uni推送消息记录集合
+     */
+    List<UniPushLog> selectPushLogList(UniPushLogParam UniPushLog);
+
+    /**
+     * 新增uni推送消息记录
+     *
+     * @param UniPushLog uni推送消息记录
+     * @return 结果
+     */
+    int insertPushLog(UniPushLog UniPushLog);
+
+    /**
+     * 修改uni推送消息记录
+     *
+     * @param UniPushLog uni推送消息记录
+     * @return 结果
+     */
+    int updatePushLog(UniPushLog UniPushLog);
+
+    /**
+     * 删除uni推送消息记录
+     *
+     * @param id uni推送消息记录主键
+     * @return 结果
+     */
+    int deletePushLogById(String id);
+
+    /**
+     * 批量删除uni推送消息记录
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deletePushLogByIds(String[] ids);
+
+    UniPushLog getLast(@Param("userId") Long userId);
+
+    Integer getNumByIsRead(@Param("userId") Long userId);
+
+    Integer setIsRead(@Param("logIds")List<Long> logIds,@Param("userId") Long userId);
+
+    void insertLogBatch(@Param("uniPushLogs") List<UniPushLog> uniPushLogs);
+}

+ 80 - 0
fs-service/src/main/java/com/fs/gtPush/param/UniPushLogParam.java

@@ -0,0 +1,80 @@
+package com.fs.gtPush.param;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+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.fs.common.annotation.Excel;
+import com.fs.watch.param.BaseQueryParam;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+
+/**
+ * uni推送消息记录对象 uni_push_log
+ *
+ * @author fs
+ * @date 2025-03-12
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class UniPushLogParam extends BaseQueryParam {
+
+    /** id */
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /** 推送id */
+    @Excel(name = "推送id")
+    private String jpushId;
+
+    /** 推送类型:0 订单通知 1健康管理 2营销 */
+    @Excel(name = "推送类型:0 订单通知(0.1药品 0.2服务包) 1健康管理 2营销")
+    private Float type;
+
+    /** 详细类型:
+     type:1 0:未支付 1:支付成功 2:发货 3:派送 4:签收 */
+    @Excel(name = "详细类型:")
+    private Integer desType;
+
+    /** 关联用户id */
+    @Excel(name = "关联用户id")
+    private Long userId;
+
+
+    /** 关联事件id */
+    @Excel(name = "关联事件id")
+    private Long businessId;
+
+
+
+    /** 推送内容 */
+    @Excel(name = "推送内容")
+    private String pushMsg;
+
+    /** 推送结果 1:成功 0:失败 */
+    @Excel(name = "推送结果 1:成功 0:失败")
+    private Integer pushRes;
+
+    /** 返回结果详情 */
+    @Excel(name = "返回结果详情")
+    private String returnMsg;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @TableField(fill = FieldFill.INSERT)
+    private Date createTime;
+
+
+    /** 更新时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Date updateTime;
+
+    /** app是否已读 0:否 1:是 */
+    private Integer isRead;
+
+
+
+}

+ 80 - 0
fs-service/src/main/java/com/fs/gtPush/service/UniPushLogService.java

@@ -0,0 +1,80 @@
+package com.fs.gtPush.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.gtPush.domain.UniPushLog;
+import com.fs.gtPush.param.UniPushLogParam;
+import com.fs.gtPush.vo.UniPushLogAppVo;
+import com.fs.gtPush.vo.UniPushLogLastAndReadStatusVo;
+
+import java.util.List;
+
+/**
+ * uni推送消息记录Service接口
+ *
+ * @author fs
+ * @date 2025-03-12
+ */
+public interface UniPushLogService extends IService<UniPushLog>{
+    /**
+     * 查询uni推送消息记录
+     *
+     * @param id uni推送消息记录主键
+     * @return uni推送消息记录
+     */
+    UniPushLog selectUniPushLogById(String id);
+
+    /**
+     * 查询uni推送消息记录列表
+     *
+     * @param uniPushLog uni推送消息记录
+     * @return uni推送消息记录集合
+     */
+    List<UniPushLog> selectUniPushLogList(UniPushLogParam uniPushLog);
+
+    /**
+     * 新增uni推送消息记录
+     *
+     * @param uniPushLog uni推送消息记录
+     * @return 结果
+     */
+    int insertUniPushLog(UniPushLog uniPushLog);
+
+    /**
+     * 修改uni推送消息记录
+     *
+     * @param uniPushLog uni推送消息记录
+     * @return 结果
+     */
+    int updateUniPushLog(UniPushLog uniPushLog);
+
+    /**
+     * 批量删除uni推送消息记录
+     *
+     * @param ids 需要删除的uni推送消息记录主键集合
+     * @return 结果
+     */
+    int deleteUniPushLogByIds(String[] ids);
+
+    /**
+     * 删除uni推送消息记录信息
+     *
+     * @param id uni推送消息记录主键
+     * @return 结果
+     */
+    int deleteUniPushLogById(String id);
+
+    /**
+     * 查询uni推送消息记录最新记录,且是否含有未读消息
+     * @param userId
+     * @return
+     */
+    UniPushLogLastAndReadStatusVo getLastAndReadStatus(Long userId);
+
+    Integer setIsRead(List<Long> logIds,Long userId);
+
+    List<UniPushLogAppVo> selectUniPushLogListApp(UniPushLogParam uniPushLog);
+
+    void insertLogBatch(List<UniPushLog> uniPushLogs);
+
+
+}

+ 178 - 0
fs-service/src/main/java/com/fs/gtPush/service/impl/UniPushLogServiceImpl.java

@@ -0,0 +1,178 @@
+package com.fs.gtPush.service.impl;
+
+import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.bean.BeanUtils;
+import com.fs.gtPush.domain.PushReqBean;
+import com.fs.gtPush.domain.UniPushLog;
+import com.fs.gtPush.mapper.PushLogMapper;
+import com.fs.gtPush.param.UniPushLogParam;
+import com.fs.gtPush.service.UniPushLogService;
+import com.fs.gtPush.vo.UniPushLogAppVo;
+import com.fs.gtPush.vo.UniPushLogLastAndReadStatusVo;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * uni推送消息记录Service业务层处理
+ *
+ * @author fs
+ * @date 2025-03-12
+ */
+@Service
+@Slf4j
+public class UniPushLogServiceImpl extends ServiceImpl<PushLogMapper, UniPushLog> implements UniPushLogService {
+    @Autowired
+    private PushLogMapper pushLogMapper;
+    /**
+     * 查询uni推送消息记录
+     *
+     * @param id uni推送消息记录主键
+     * @return uni推送消息记录
+     */
+    @Override
+    public UniPushLog selectUniPushLogById(String id) {
+        return baseMapper.selectPushLogById(id);
+    }
+
+    /**
+     * 查询uni推送消息记录列表
+     *
+     * @param UniPushLog uni推送消息记录
+     * @return uni推送消息记录
+     */
+    @Override
+    public List<UniPushLog> selectUniPushLogList(UniPushLogParam UniPushLog) {
+        return baseMapper.selectPushLogList(UniPushLog);
+    }
+
+    /**
+     * 新增uni推送消息记录
+     *
+     * @param UniPushLog uni推送消息记录
+     * @return 结果
+     */
+    @Override
+    public int insertUniPushLog(UniPushLog UniPushLog) {
+        UniPushLog.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertPushLog(UniPushLog);
+    }
+
+    /**
+     * 修改uni推送消息记录
+     *
+     * @param UniPushLog uni推送消息记录
+     * @return 结果
+     */
+    @Override
+    public int updateUniPushLog(UniPushLog UniPushLog) {
+        UniPushLog.setUpdateTime(DateUtils.getNowDate());
+        return baseMapper.updatePushLog(UniPushLog);
+    }
+
+    /**
+     * 批量删除uni推送消息记录
+     *
+     * @param ids 需要删除的uni推送消息记录主键
+     * @return 结果
+     */
+    @Override
+    public int deleteUniPushLogByIds(String[] ids) {
+        return baseMapper.deletePushLogByIds(ids);
+    }
+
+    /**
+     * 删除uni推送消息记录信息
+     *
+     * @param id uni推送消息记录主键
+     * @return 结果
+     */
+    @Override
+    public int deleteUniPushLogById(String id) {
+        return baseMapper.deletePushLogById(id);
+    }
+
+    /**
+     * 查询uni推送消息记录最新记录,且是否含有未读消息
+     *
+     * @param userId
+     * @return vo
+     */
+    @Override
+    public UniPushLogLastAndReadStatusVo getLastAndReadStatus(Long userId) {
+        UniPushLogLastAndReadStatusVo vo = new UniPushLogLastAndReadStatusVo();
+        if (userId == null) {
+            vo.setUnReadNum(0);
+        } else {
+            UniPushLog log = baseMapper.getLast(userId);
+            if (log != null) {
+                BeanUtils.copyProperties(log, vo);
+                analysisParam(log, vo);
+                //查询未读条数
+                Integer num = baseMapper.getNumByIsRead(userId);
+                vo.setUnReadNum(num);
+            }
+        }
+        return vo;
+    }
+
+    private static void analysisParam(UniPushLog pushLog, UniPushLogAppVo vo) {
+        //解析内容
+        String pushMsg = pushLog.getPushMsg();
+        if (StringUtils.isNotBlank(pushMsg)) {
+            try {
+                PushReqBean pushParam = JSONUtil.toBean(pushMsg, PushReqBean.class);
+                vo.setTitle(pushParam.getTitle());
+                vo.setContent(pushParam.getContent());
+                Map<String, Object> payload = pushParam.getPayload();
+                if (payload != null && !payload.isEmpty()) {
+                    if (payload.get("url") != null) {
+                        vo.setUrl(payload.get("url").toString());
+                    }
+                    if (payload.get("imgUrl") != null) {
+                        String[] imgUrls = payload.get("imgUrl").toString().split(",");
+                        vo.setImgUrl(imgUrls[0]);
+                    }
+                }
+            } catch (Exception e) {
+                log.info("解析推送参数错误,id为{}", pushLog.getId());
+            }
+        }
+    }
+
+    /**
+     * 设置已读
+     *
+     * @param logIds
+     * @return num
+     */
+    @Override
+    public Integer setIsRead(List<Long> logIds, Long userId) {
+        return baseMapper.setIsRead(logIds, userId);
+    }
+
+    @Override
+    public List<UniPushLogAppVo> selectUniPushLogListApp(UniPushLogParam uniPushLog) {
+        List<UniPushLog> uniPushLogs = selectUniPushLogList(uniPushLog);
+        ArrayList<UniPushLogAppVo> res = new ArrayList<>();
+        for (UniPushLog log : uniPushLogs) {
+            UniPushLogAppVo vo = new UniPushLogAppVo();
+            BeanUtils.copyProperties(log, vo);
+            analysisParam(log, vo);
+            res.add(vo);
+        }
+        return res;
+    }
+
+    @Override
+    public void insertLogBatch(List<UniPushLog> uniPushLogs) {
+        pushLogMapper.insertLogBatch(uniPushLogs);
+    }
+}

+ 47 - 0
fs-service/src/main/java/com/fs/gtPush/vo/UniPushLogAppVo.java

@@ -0,0 +1,47 @@
+package com.fs.gtPush.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class UniPushLogAppVo {
+    /** id */
+    private Long id;
+
+    /** 推送id */
+    private String jpushId;
+
+    /** 推送类型:0 订单通知(0.1药品 0.2服务包) 1健康管理  */
+    private Float type;
+
+    /** 详细类型:
+     type:1 0:未支付 1:支付成功 2:发货 3:派送 4:签收 */
+    private Integer desType;
+
+    /** 关联用户id */
+    private Long userId;
+
+
+    /** 关联事件id */
+    private Long businessId;
+
+
+
+    /** 推送内容 */
+//    private String pushMsg;
+    private String title; //标题
+    private String content; //内容
+    private String url; //跳转链接
+    private String imgUrl; //图片
+
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+
+    /** app是否已读 0:否 1:是 */
+    private Integer isRead;
+
+}

+ 8 - 0
fs-service/src/main/java/com/fs/gtPush/vo/UniPushLogLastAndReadStatusVo.java

@@ -0,0 +1,8 @@
+package com.fs.gtPush.vo;
+
+import lombok.Data;
+
+@Data
+public class UniPushLogLastAndReadStatusVo extends UniPushLogAppVo {
+    private Integer unReadNum;
+}

+ 6 - 0
fs-service/src/main/java/com/fs/his/config/IntegralConfig.java

@@ -20,4 +20,10 @@ public class IntegralConfig implements Serializable {
     private Integer integralInvite;//邀请新用户获得积分
 
     private Integer integralInvited;//填写邀请码获得积分
+    private Integer integralRegister;//完成手机号绑定注册
+    private Integer integralFinishConsultation;//完成专家问诊
+    private Integer integralFirstOrderPoint;//首次积分商城下单
+    private Integer integralAddPatient;//新用户完善就诊人获得积分
+    private Integer integralAddUserAddress;//新用户填写收货地址获取积分
+    private Integer integralSubscriptCourse;//付费课程订阅积分比例
 }

+ 54 - 0
fs-service/src/main/java/com/fs/his/domain/FsIntegralCart.java

@@ -0,0 +1,54 @@
+package com.fs.his.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@TableName("fs_integral_cart")
+@Data
+public class FsIntegralCart {
+    /**
+     * 主键ID
+     */
+    @TableId(type = IdType.AUTO)
+    private Long id;
+    /**
+     * 用户ID
+     */
+    private Long userId;
+    /**
+     * 积分商品ID
+     */
+    private Long goodsId;
+    /**
+     * 所需积分-单价
+     */
+    private Long integral;
+    /**
+     * 所需金额-单价
+     */
+    private BigDecimal cash;
+    /**
+     * 数量
+     */
+    private Integer cartNum;
+    /**
+     * 添加时间
+     */
+    private LocalDateTime createTime;
+    /**
+     * 修改时间
+     */
+    private LocalDateTime updateTime;
+
+    /**
+     * 是否追加数量
+     */
+    @TableField(exist = false)
+    private Boolean addToExist;
+}

+ 9 - 0
fs-service/src/main/java/com/fs/his/domain/FsIntegralGoods.java

@@ -47,6 +47,10 @@ public class FsIntegralGoods extends BaseEntity
     @Excel(name = "所需积分")
     private Long integral;
 
+    /** 支付金额 */
+    @Excel(name = "支付金额")
+    private BigDecimal cash;
+
     /** 排序 */
     @Excel(name = "排序")
     private Long sort;
@@ -61,4 +65,9 @@ public class FsIntegralGoods extends BaseEntity
 
     @Excel(name = "产品编码")
     private String barCode;
+
+    /**
+     * 非数据库字段 仅用于订单信息存储购买数量
+     */
+    private Integer num;
 }

+ 18 - 1
fs-service/src/main/java/com/fs/his/domain/FsIntegralOrder.java

@@ -6,6 +6,7 @@ import com.fs.common.core.domain.BaseEntity;
 import lombok.Data;
 
 import java.math.BigDecimal;
+import java.time.LocalDateTime;
 import java.util.Date;
 
 /**
@@ -56,7 +57,23 @@ public class FsIntegralOrder extends BaseEntity
     @Excel(name = "支付积分")
     private String integral;
 
-    /** 1:待发货;2:待收货;3:已完成 */
+    /** 支付金额 */
+    @Excel(name = "支付金额")
+    private BigDecimal payMoney;
+
+    /** 是否支付 0未支付 1已支付 */
+    @Excel(name = "是否支付 0未支付 1已支付")
+    private Integer isPay;
+
+    /** 支付时间 */
+    @Excel(name = "支付时间")
+    private LocalDateTime payTime;
+
+    /** 支付类型 1积分 2现金 3积分+现金 */
+    @Excel(name = "支付类型 1积分 2现金 3积分+现金")
+    private Integer payType;
+
+    /** 1:待发货;2:待收货;3:已完成 4待支付 5取消 */
     @Excel(name = "状态",dictType="sys_integral_order_status")
     private Integer status;
     @Excel(name = "商品编号")

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

@@ -1,5 +1,6 @@
 package com.fs.his.domain;
 
+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;
@@ -169,4 +170,17 @@ public class FsUser extends BaseEntity
             return nickName;
         }
     }
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @TableField(exist = false)
+    private Date startCreateTime;
+
+    @TableField(exist = false)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date endCreateTime;
+
+    /**
+     * 项目ID
+     */
+    private Long projectId;
 }

+ 30 - 0
fs-service/src/main/java/com/fs/his/domain/FsUserProjectTag.java

@@ -0,0 +1,30 @@
+package com.fs.his.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+@TableName("fs_user_project_tag")
+public class FsUserProjectTag {
+    /**
+     * 主键ID
+     */
+    @TableId(type = IdType.AUTO)
+    private Long id;
+    /**
+     * 用户项目ID
+     */
+    private Long userCompanyUserId;
+    /**
+     * 标签ID
+     */
+    private Long tagId;
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+}

+ 15 - 0
fs-service/src/main/java/com/fs/his/enums/BusinessTypeEnum.java

@@ -0,0 +1,15 @@
+package com.fs.his.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum BusinessTypeEnum {
+    INTEGRAL_ORDER("integral", 6, "积分商城订单支付"),
+    ;
+
+    private final String prefix;
+    private final Integer code;
+    private final String desc;
+}

+ 7 - 1
fs-service/src/main/java/com/fs/his/enums/FsUserIntegralLogTypeEnum.java

@@ -26,7 +26,13 @@ public enum FsUserIntegralLogTypeEnum {
     TYPE_16(16,"点播看课获得积分"),
     TYPE_17(17,"点播答题获得积分"),
     TYPE_18(18,"邀请新用户获取积分"),
-    TYPE_19(19,"填写邀请码获取积分");
+    TYPE_19(19,"填写邀请码获取积分"),
+    TYPE_20(20,"首次完成手机号绑定注册"),
+    TYPE_21(21,"首次完成专家咨询"),
+    TYPE_22(22,"首次完成积分商城下单"),
+    TYPE_23(23,"管理员添加"),
+    TYPE_24(24, "付费课程订阅"),
+    ;
 
 
     private Integer value;

+ 15 - 0
fs-service/src/main/java/com/fs/his/enums/PaymentMethodEnum.java

@@ -0,0 +1,15 @@
+package com.fs.his.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum PaymentMethodEnum {
+    MINIAPP_WECHAT("weixin"), // 小程序微信支付
+    H5_WECHAT("微信"),      // H5微信支付
+    ALIPAY("alipay"),         // 支付宝支付
+    H5_ALIPAY("alipay");       // H5支付宝支付
+
+    private final String desc;
+}

+ 5 - 2
fs-service/src/main/java/com/fs/his/mapper/FsArticleCateMapper.java

@@ -1,8 +1,11 @@
 package com.fs.his.mapper;
 
 import java.util.List;
+import java.util.Map;
+
 import com.fs.his.domain.FsArticleCate;
 import com.fs.his.vo.OptionsVO;
+import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 
 /**
@@ -63,6 +66,6 @@ public interface FsArticleCateMapper
 
     @Select("select cate_id dictValue,cate_name dictLabel FROM fs_article_cate")
     List<OptionsVO> selectFsArticleCateAllList();
-    @Select("select * FROM fs_article_cate where is_del=0")
-    List<FsArticleCate> selectFsArticleCateAllListVO();
+
+    List<FsArticleCate> selectFsArticleCateAllListVO(@Param("params") Map<String, Object> params);
 }

+ 2 - 14
fs-service/src/main/java/com/fs/his/mapper/FsArticleMapper.java

@@ -65,21 +65,9 @@ public interface FsArticleMapper
      * @return 结果
      */
     public int deleteFsArticleByArticleIds(Long[] articleIds);
-    @Select({"<script> " +
-            "select a.*  from fs_article a    " +
-            "where 1=1  " +
-            "<if test = 'maps.keyword != null     '> " +
-            "and a.title like CONCAT(#{maps.keyword},'%')" +
-            "</if>" +
-            "<if test = 'maps.isTui != null     '> " +
-            "and a.is_tui = #{maps.isTui} " +
-            "</if>" +
-            "<if test = 'maps.cateId != null and maps.cateId !=0    '> " +
-            "and a.cate_id = #{maps.cateId} " +
-            "</if>" +
-            " order by a.article_id desc "+
-            "</script>"})
+
     List<FsArticleListUVO> selectFsArticleListUVO(@Param("maps")FsArticleListUParam param);
+
     @Update("update fs_article set views=views+1 where article_id=#{articleId}")
     int updateFsArticleViews(Long articleId);
 

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

@@ -200,4 +200,6 @@ public interface FsDoctorMapper
 
     @Select("SELECT doctor_id id,doctor_name name  FROM fs_doctor WHERE FIND_IN_SET(doctor_id, (select doctor_ids from company where company_id=#{companyId})); ")
     List<UserVo> selectUserDocVoListByCompany(Long companyId);
+
+    String selectDoctorNameByIds(List<Long> doctorIds);
 }

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

@@ -10,6 +10,7 @@ import com.fs.his.param.FsHealthTongueUParam;
 import com.fs.his.vo.FsHealthTongueListUVO;
 import com.fs.his.vo.FsHealthTongueListVO;
 import com.fs.his.vo.FsHealthTongueUVO;
+import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 
 /**
@@ -93,4 +94,5 @@ public interface FsHealthTongueMapper
     @Select("select  t.*,u.avatar from fs_health_tongue t LEFT JOIN fs_user u on u.user_id=t.user_id where t.id=#{id} ")
     FsHealthTongueUVO selectFsHealthTongueUVOById(Long id);
 
+    List<String> selectListByDateAndUserId(@Param("startDate") String startDate, @Param("endDate") String endDate, @Param("userId") Long userId);
 }

+ 31 - 0
fs-service/src/main/java/com/fs/his/mapper/FsIntegralCartMapper.java

@@ -0,0 +1,31 @@
+package com.fs.his.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.his.domain.FsIntegralCart;
+import com.fs.his.vo.FsIntegralCartVO;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+public interface FsIntegralCartMapper extends BaseMapper<FsIntegralCart> {
+
+    /**
+     * 新增或修改购物车
+     */
+    void insertOrUpdate(FsIntegralCart cart);
+
+    /**
+     * 获取购物车商品数量
+     * @param params    参数
+     * @return num      数量
+     */
+    Integer getCartCountByMap(@Param("params") Map<String, Object> params);
+
+    /**
+     * 获取购物车列表
+     * @param params    参数
+     * @return  list
+     */
+    List<FsIntegralCartVO> getCartsByMap(@Param("params") Map<String, Object> params);
+}

+ 9 - 2
fs-service/src/main/java/com/fs/his/mapper/FsIntegralGoodsMapper.java

@@ -6,6 +6,7 @@ import com.fs.his.vo.FsIntegralGoodsListUVO;
 import com.fs.his.vo.FsIntegralGoodsListVO;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
 
 import java.util.List;
 
@@ -65,7 +66,7 @@ public interface FsIntegralGoodsMapper
      */
     public int deleteFsIntegralGoodsByGoodsIds(Long[] goodsIds);
 
-    @Select({"<script> select goods_id, img_url, images, goods_name, ot_price, goods_type, status, integral, sort, stock, descs, create_time from fs_integral_goods" +
+    @Select({"<script> select goods_id, img_url, images, goods_name, ot_price, goods_type, status, integral, cash, sort, stock, descs, create_time from fs_integral_goods" +
             "<where>  \n" +
             "            <if test=\"goodsName != null  and goodsName != ''\"> and goods_name like concat('%', #{goodsName}, '%')</if>\n" +
             "            <if test=\"goodsType != null \"> and goods_type = #{goodsType}</if>\n" +
@@ -75,7 +76,7 @@ public interface FsIntegralGoodsMapper
             "</script>"})
     List<FsIntegralGoodsListVO> selectFsIntegralGoodsListVO(FsIntegralGoods fsIntegralGoods);
     @Select({"<script> " +
-            "select g.goods_id,g.img_url,g.images,g.goods_name,g.ot_price,g.goods_type,g.integral,g.sort  from fs_integral_goods g  " +
+            "select g.goods_id,g.img_url,g.images,g.goods_name,g.ot_price,g.goods_type,g.integral,g.cash,g.sort  from fs_integral_goods g  " +
             "where g.status=1  " +
             "<if test = 'maps.goodsType != null and maps.goodsType != 0     '> " +
             "and g.goods_type = #{maps.goodsType}  " +
@@ -90,4 +91,10 @@ public interface FsIntegralGoodsMapper
      * @return 商品列表
      */
     List<FsIntegralGoods> selectFsIntegralGoodsByStage(FsIntegralGoodsListUParam param);
+
+    @Update("update fs_integral_goods set stock = stock - #{num} where goods_id = #{goodsId} and stock >= #{num}")
+    int subStock(@Param("goodsId") Long goodsId, @Param("num") int num);
+
+    @Update("update fs_integral_goods set stock = stock + #{num} where goods_id = #{goodsId}")
+    int addStock(@Param("goodsId") Long goodsId, @Param("num") int num);
 }

+ 5 - 1
fs-service/src/main/java/com/fs/his/mapper/FsIntegralOrderMapper.java

@@ -66,12 +66,16 @@ public interface FsIntegralOrderMapper
      * @return 结果
      */
     public int deleteFsIntegralOrderByOrderIds(Long[] orderIds);
-    @Select({"<script> select order_id, order_code, user_id, user_name, user_phone, user_address, item_json, integral, status, delivery_code, delivery_name, delivery_sn, delivery_time, create_time,qw_user_id,company_user_id,company_id, remark from fs_integral_order " +
+    @Select({"<script> select order_id, order_code, user_id, user_name, user_phone, user_address, item_json, integral,pay_money,is_pay,pay_time,pay_type, status, delivery_code, delivery_name, delivery_sn, delivery_time, create_time,qw_user_id,company_user_id,company_id, remark from fs_integral_order " +
             "<where>  \n" +
             "            <if test=\"orderCode != null  and orderCode != ''\"> and order_code = #{orderCode}</if>\n" +
             "            <if test=\"userName != null  and userName != ''\"> and user_name like concat('%', #{userName}, '%')</if>\n" +
             "            <if test=\"userPhone != null  and userPhone != ''\"> and user_phone = #{userPhone}</if>\n" +
             "            <if test=\"integral != null  and integral != ''\"> and integral = #{integral}</if>\n" +
+            "            <if test=\"payMoney != null  and payMoney != ''\"> and pay_money = #{payMoney}</if>\n" +
+            "            <if test=\"isPay != null  and isPay != ''\"> and is_pay = #{isPay}</if>\n" +
+            "            <if test=\"payTime != null  and payTime != ''\"> and pay_time = #{payTime}</if>\n" +
+            "            <if test=\"payType != null  and payType != ''\"> and pay_type = #{payType}</if>\n" +
             "            <if test=\"status != null  and status != ''\"> and status = #{status}</if>\n" +
             "            <if test=\"deliverySn != null  and deliverySn != ''\"> and delivery_sn like concat('%', #{deliverySn}, '%')</if>\n" +
             "            <if test=\"qwUserId != null  and qwUserId != ''\"> and qw_user_id = #{qwUserId}</if>\n" +

+ 2 - 1
fs-service/src/main/java/com/fs/his/mapper/FsUserIntegralLogsMapper.java

@@ -1,6 +1,5 @@
 package com.fs.his.mapper;
 
-import com.fs.company.vo.RedPacketMoneyVO;
 import com.fs.his.domain.FsUserIntegralLogs;
 import com.fs.his.param.FsUserIntegralLogsListUParam;
 import com.fs.his.param.FsUserIntegralLogsParam;
@@ -11,6 +10,7 @@ import org.apache.ibatis.annotations.Delete;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 
+import java.time.LocalDate;
 import java.util.List;
 
 /**
@@ -138,4 +138,5 @@ public interface FsUserIntegralLogsMapper
     @Select("select count(1) from fs_user_integral_logs where log_type = 16 and user_id =#{userId} and business_id = #{videoId} ")
     Long selectH5VideoIntegralCount(@Param("userId") Long userId,@Param("videoId") Long videoId);
 
+    List<FsUserIntegralLogs> selectFsUserIntegralLogsByUserIdAndLogType(@Param("userId") Long userId, @Param("logType") Integer logType, @Param("date") LocalDate date);
 }

+ 12 - 5
fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java

@@ -16,9 +16,8 @@ import com.fs.qw.vo.QwFsUserVO;
 import com.fs.store.param.h5.FsUserPageListParam;
 import com.fs.store.param.h5.UserStatisticsCommonParam;
 import com.fs.store.vo.h5.*;
-import org.apache.ibatis.annotations.Param;
-import org.apache.ibatis.annotations.Select;
-import org.apache.ibatis.annotations.Update;
+import com.fs.watch.domain.vo.FsUserAndCompanyAndDoctorVo;
+import org.apache.ibatis.annotations.*;
 
 /**
  * 用户Mapper接口
@@ -98,6 +97,9 @@ public interface FsUserMapper
             "            <if test=\"companyUserId != null \">and f1.company_user_id = #{companyUserId}</if>\n" +
             "order by f1.user_id desc"+
             "</script>"})
+    @Results({
+            @Result(property = "nickName", column = "nick_name")
+    })
     List<FsUserVO> selectFsUserListVO(FsUserParam fsUser);
 
     @Update("update fs_user set is_del=1 where user_id=#{userId}")
@@ -303,14 +305,14 @@ public interface FsUserMapper
      */
     Map<String, Long> getUserVipCountByCompanyUserId(@Param("companyUserId") Long companyUserId);
 
-    @Select("select * from fs_user where union_id=#{unionId}")
+    @Select("select * from fs_user where union_id=#{unionId} order by user_id desc limit 1")
     FsUser selectFsUserByUnionId(String unionId);
 
     List<UserListCountVO> getUserNumber(@Param("userId") Long userId, @Param("companyId") Long companyId);
 
     int getRepeatUserNumber(@Param("userId") Long userId);
 
-    UserDetailsVO getCountWatchCourse(@Param("userId") Long userId, @Param("fsUserId") Long fsUserId, @Param("dateTag") String dateTag);
+    UserDetailsVO getCountWatchCourse (@Param("userId") Long userId, @Param("fsUserId") Long fsUserId, @Param("dateTag") String dateTag,@Param("userCompanyId")  Long userCompanyId);
 
     UserDetailsVO getCountAnswer(@Param("userId") Long userId, @Param("fsUserId") Long fsUserId, @Param("dateTag") String dateTag);
 
@@ -350,4 +352,9 @@ public interface FsUserMapper
 
     Map<String, Long> countCourseDetailsNew(UserStatisticsCommonParam param);
 
+    List<FsUserVO> selectFsUserVOListByProject(@Param("maps") FsUser fsUser);
+
+    FsUserAndCompanyAndDoctorVo selectCompanyAndDoctor(@Param("userId")Long userId);
+
+    List<FsUser> selectUserNameByIds(@Param("userIds") String userIds);
 }

+ 19 - 0
fs-service/src/main/java/com/fs/his/mapper/FsUserProjectTagMapper.java

@@ -0,0 +1,19 @@
+package com.fs.his.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.his.domain.FsUserProjectTag;
+import com.fs.store.vo.h5.CompanyUserTagListVO;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+public interface FsUserProjectTagMapper extends BaseMapper<FsUserProjectTag> {
+
+    /**
+     * 查询用户项目标签列表
+     * @param params     参数
+     * @return  list
+     */
+    List<CompanyUserTagListVO> getTagList(@Param("params") Map<String, Object> params);
+}

+ 20 - 0
fs-service/src/main/java/com/fs/his/param/FsIntegralCartOrderCreateParam.java

@@ -0,0 +1,20 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+import java.util.List;
+
+
+@Data
+public class FsIntegralCartOrderCreateParam {
+
+
+    /** 用户id */
+    private Long userId;
+
+    private Long addressId;
+
+    private List<Long> ids;
+
+
+}

+ 26 - 0
fs-service/src/main/java/com/fs/his/param/FsIntegralCartParam.java

@@ -0,0 +1,26 @@
+package com.fs.his.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+
+@Data
+public class FsIntegralCartParam {
+
+    @NotNull(message = "商品ID不能为空")
+    @ApiModelProperty("积分商品ID")
+    private Long goodsId;
+
+    @NotNull(message = "添加数量不能为空")
+    @Min(value = 1, message = "数量不再合法范围内")
+    @Max(value = 999, message = "数量不再合法范围内")
+    @ApiModelProperty("数量")
+    private Integer cartNum;
+
+    @NotNull(message = "添加类型不能为空")
+    @ApiModelProperty("是否购物车 0否 1是")
+    private Integer isCart;
+}

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

@@ -1,10 +1,7 @@
 package com.fs.his.param;
 
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fs.common.annotation.Excel;
 import lombok.Data;
 
-import java.util.Date;
 
 @Data
 public class FsIntegralOrderCreateParam {

+ 13 - 0
fs-service/src/main/java/com/fs/his/param/FsIntegralOrderDoPayParam.java

@@ -0,0 +1,13 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class FsIntegralOrderDoPayParam {
+    @NotNull(message = "订单号不能为空")
+    private Long orderId;
+
+    private Long userId;
+}

+ 18 - 0
fs-service/src/main/java/com/fs/his/param/FsIntegralOrderParam.java

@@ -4,6 +4,8 @@ import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fs.common.annotation.Excel;
 import lombok.Data;
 
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
 import java.util.Date;
 
 @Data
@@ -39,6 +41,22 @@ public class FsIntegralOrderParam {
     @Excel(name = "支付积分")
     private String integral;
 
+    /** 支付金额 */
+    @Excel(name = "支付金额")
+    private BigDecimal payMoney;
+
+    /** 是否支付 0未支付 1已支付 */
+    @Excel(name = "是否支付 0未支付 1已支付")
+    private Integer isPay;
+
+    /** 支付时间 */
+    @Excel(name = "支付时间")
+    private LocalDateTime payTime;
+
+    /** 支付类型 1积分 2现金 3积分+现金 */
+    @Excel(name = "支付类型 1积分 2现金 3积分+现金")
+    private Integer payType;
+
     /** 1:待发货;2:待收货;3:已完成 */
     @Excel(name = "1:待发货;2:待收货;3:已完成")
     private String status;

+ 5 - 0
fs-service/src/main/java/com/fs/his/param/FsUserAddIntegralTemplateParam.java

@@ -3,6 +3,7 @@ package com.fs.his.param;
 
 import lombok.Data;
 
+
 @Data
 public class FsUserAddIntegralTemplateParam {
     private Long userId;
@@ -10,4 +11,8 @@ public class FsUserAddIntegralTemplateParam {
     private Integer logType; //类型1浏览商品 2刷视频 3邀请奖励 4被邀请奖励
 
     private String businessId;
+
+    private Integer points;
+
+    private String remark;
 }

+ 19 - 0
fs-service/src/main/java/com/fs/his/param/FsUserAddPointsParam.java

@@ -0,0 +1,19 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+
+@Data
+public class FsUserAddPointsParam {
+
+    @NotNull(message = "会员ID不能为空")
+    private Long userId;
+
+    @NotNull(message = "积分不能为空")
+    @Min(value = 1, message = "允许添加积分最小为1")
+    private Integer point;
+
+    private String remark;
+}

Some files were not shown because too many files changed in this diff