瀏覽代碼

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	fs-service/src/main/resources/mapper/company/CompanyUserMapper.xml
yjwang 1 天之前
父節點
當前提交
6579c637f3
共有 100 個文件被更改,包括 2310 次插入791 次删除
  1. 2 1
      fs-common/src/main/java/com/fs/common/enums/BizResponseEnum.java
  2. 209 43
      fs-company-app/src/main/java/com/fs/app/controller/CommonController.java
  3. 249 251
      fs-company-app/src/main/java/com/fs/app/controller/FsUserController.java
  4. 15 1
      fs-company-app/src/main/java/com/fs/app/controller/WxCompanyUserController.java
  5. 24 0
      fs-company-app/src/main/java/com/fs/app/controller/WxH5MpController.java
  6. 22 0
      fs-company-app/src/main/java/com/fs/app/param/FsUserTagUpdateParam.java
  7. 26 0
      fs-company-app/src/main/java/com/fs/app/param/FsUserUpdateParam.java
  8. 53 0
      fs-company-app/src/main/java/com/fs/app/service/impl/AppServiceImpl.java
  9. 1 2
      fs-company-app/src/main/resources/application.yml
  10. 10 0
      fs-company/src/main/java/com/fs/company/controller/company/CompanyController.java
  11. 6 2
      fs-company/src/main/java/com/fs/company/controller/course/FsCourseAnswerLogsController.java
  12. 1 1
      fs-company/src/main/java/com/fs/user/FsUserAdminController.java
  13. 1 1
      fs-company/src/main/resources/application.yml
  14. 26 22
      fs-qw-task/src/main/java/com/fs/app/task/CourseWatchLogScheduler.java
  15. 37 0
      fs-qw-task/src/main/java/com/fs/app/task/UserCourseWatchCountTask.java
  16. 5 5
      fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java
  17. 1 20
      fs-qwhook-sop/src/main/java/com/fs/app/controller/ApisFsUserCourseVideoController.java
  18. 1 45
      fs-qwhook-sop/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java
  19. 2 21
      fs-qwhook/src/main/java/com/fs/app/controller/ApisFsUserCourseVideoController.java
  20. 63 42
      fs-qwhook/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java
  21. 49 0
      fs-service/src/main/java/com/fs/common/param/LoginMaWxParam.java
  22. 4 2
      fs-service/src/main/java/com/fs/company/cache/ICompanyTagCacheService.java
  23. 33 5
      fs-service/src/main/java/com/fs/company/cache/impl/CompanyTagCacheServiceImpl.java
  24. 2 0
      fs-service/src/main/java/com/fs/company/domain/Company.java
  25. 2 0
      fs-service/src/main/java/com/fs/company/domain/CompanyTag.java
  26. 23 0
      fs-service/src/main/java/com/fs/company/domain/CompanyUser.java
  27. 9 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyPostMapper.java
  28. 16 8
      fs-service/src/main/java/com/fs/company/mapper/CompanyRoleMapper.java
  29. 2 2
      fs-service/src/main/java/com/fs/company/mapper/CompanyTagMapper.java
  30. 1 23
      fs-service/src/main/java/com/fs/company/mapper/CompanyUserMapper.java
  31. 19 9
      fs-service/src/main/java/com/fs/company/service/ICompanyPostService.java
  32. 16 8
      fs-service/src/main/java/com/fs/company/service/ICompanyRoleService.java
  33. 2 0
      fs-service/src/main/java/com/fs/company/service/ICompanyService.java
  34. 2 2
      fs-service/src/main/java/com/fs/company/service/ICompanyTagService.java
  35. 10 8
      fs-service/src/main/java/com/fs/company/service/ICompanyUserPostService.java
  36. 10 8
      fs-service/src/main/java/com/fs/company/service/ICompanyUserRoleService.java
  37. 11 7
      fs-service/src/main/java/com/fs/company/service/impl/CompanyPostServiceImpl.java
  38. 11 7
      fs-service/src/main/java/com/fs/company/service/impl/CompanyRoleServiceImpl.java
  39. 9 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java
  40. 3 3
      fs-service/src/main/java/com/fs/company/service/impl/CompanyTagServiceImpl.java
  41. 12 7
      fs-service/src/main/java/com/fs/company/service/impl/CompanyUserPostServiceImpl.java
  42. 13 7
      fs-service/src/main/java/com/fs/company/service/impl/CompanyUserRoleServiceImpl.java
  43. 5 0
      fs-service/src/main/java/com/fs/core/config/WxMaConfiguration.java
  44. 3 0
      fs-service/src/main/java/com/fs/course/config/CourseConfig.java
  45. 5 0
      fs-service/src/main/java/com/fs/course/config/CourseMaConfig.java
  46. 1 1
      fs-service/src/main/java/com/fs/course/domain/FsCourseLink.java
  47. 1 1
      fs-service/src/main/java/com/fs/course/domain/FsCourseRealLink.java
  48. 1 1
      fs-service/src/main/java/com/fs/course/domain/FsCourseWatchLog.java
  49. 2 0
      fs-service/src/main/java/com/fs/course/domain/FsUserCoursePeriod.java
  50. 3 2
      fs-service/src/main/java/com/fs/course/mapper/FsCourseRedPacketLogMapper.java
  51. 5 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java
  52. 11 12
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseMapper.java
  53. 2 2
      fs-service/src/main/java/com/fs/course/param/FsCourseLinkCreateParam.java
  54. 1 0
      fs-service/src/main/java/com/fs/course/param/FsCourseLinkMiniParam.java
  55. 2 2
      fs-service/src/main/java/com/fs/course/param/newfs/FsUserCourseVideoLinkParam.java
  56. 1 0
      fs-service/src/main/java/com/fs/course/service/IFsCourseLinkService.java
  57. 1 1
      fs-service/src/main/java/com/fs/course/service/IFsCourseQuestionBankService.java
  58. 3 0
      fs-service/src/main/java/com/fs/course/service/IFsCourseWatchLogService.java
  59. 4 0
      fs-service/src/main/java/com/fs/course/service/IFsUserCourseService.java
  60. 61 10
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseLinkServiceImpl.java
  61. 7 2
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseQuestionBankServiceImpl.java
  62. 131 3
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseWatchLogServiceImpl.java
  63. 36 1
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseServiceImpl.java
  64. 160 61
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  65. 6 0
      fs-service/src/main/java/com/fs/course/vo/newfs/FsUserCourseVideoLinkDetailsVO.java
  66. 12 0
      fs-service/src/main/java/com/fs/course/vo/newfs/FsUserCourseVideoPageListVO.java
  67. 4 4
      fs-service/src/main/java/com/fs/fastGpt/service/impl/AiHookServiceImpl.java
  68. 4 4
      fs-service/src/main/java/com/fs/fastGpt/service/impl/AiNewServiceImpl.java
  69. 4 4
      fs-service/src/main/java/com/fs/fastGpt/service/impl/AiServiceImpl.java
  70. 44 4
      fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java
  71. 6 0
      fs-service/src/main/java/com/fs/his/mapper/FsUserWxMapper.java
  72. 32 2
      fs-service/src/main/java/com/fs/his/service/IFsUserService.java
  73. 6 0
      fs-service/src/main/java/com/fs/his/service/IFsUserWxService.java
  74. 14 1
      fs-service/src/main/java/com/fs/his/service/impl/FsInquiryOrderServiceImpl.java
  75. 1 1
      fs-service/src/main/java/com/fs/his/service/impl/FsIntegralGoodsServiceImpl.java
  76. 6 1
      fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java
  77. 1 1
      fs-service/src/main/java/com/fs/his/service/impl/FsUserInvitedServiceImpl.java
  78. 341 13
      fs-service/src/main/java/com/fs/his/service/impl/FsUserServiceImpl.java
  79. 9 0
      fs-service/src/main/java/com/fs/his/service/impl/FsUserWxServiceImpl.java
  80. 2 2
      fs-service/src/main/java/com/fs/qw/service/impl/QwContactWayServiceImpl.java
  81. 4 4
      fs-service/src/main/java/com/fs/qw/service/impl/QwExternalContactServiceImpl.java
  82. 4 4
      fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsInfoServiceImpl.java
  83. 2 2
      fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsServiceImpl.java
  84. 2 0
      fs-service/src/main/java/com/fs/store/vo/h5/FsUserPageListVO.java
  85. 3 2
      fs-service/src/main/resources/application-common.yml
  86. 1 1
      fs-service/src/main/resources/application-config-dev.yml
  87. 5 19
      fs-service/src/main/resources/application-config-druid-fcky.yml
  88. 10 10
      fs-service/src/main/resources/application-config-druid-hzyy.yml
  89. 1 1
      fs-service/src/main/resources/application-config-druid-sxjz.yml
  90. 10 28
      fs-service/src/main/resources/application-config-druid-zsjk.yml
  91. 150 0
      fs-service/src/main/resources/application-druid-fcky-test.yml
  92. 2 1
      fs-service/src/main/resources/mapper/company/CompanyMapper.xml
  93. 18 6
      fs-service/src/main/resources/mapper/company/CompanyPostMapper.xml
  94. 15 6
      fs-service/src/main/resources/mapper/company/CompanyRoleMapper.xml
  95. 6 2
      fs-service/src/main/resources/mapper/company/CompanyTagMapper.xml
  96. 1 1
      fs-service/src/main/resources/mapper/company/CompanyTagUserMapper.xml
  97. 72 1
      fs-service/src/main/resources/mapper/company/CompanyUserMapper.xml
  98. 1 1
      fs-service/src/main/resources/mapper/course/FsCourseWatchCommentMapper.xml
  99. 49 0
      fs-service/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml
  100. 3 3
      fs-service/src/main/resources/mapper/course/FsUserCourseMapper.xml

+ 2 - 1
fs-common/src/main/java/com/fs/common/enums/BizResponseEnum.java

@@ -8,7 +8,8 @@ public enum BizResponseEnum {
     SUCCESS(200, "操作成功"),
     FAIL(500, "操作失败"),
     PARAM_ERROR(400, "参数错误"),
-    DATA_NOT_EXIST(1002, "数据不存在");
+    DATA_NOT_EXIST(1002, "数据不存在"),
+    WAIT_APPROVAL(505, "等待审核");
 
     private final Integer code;
     private final String msg;

+ 209 - 43
fs-company-app/src/main/java/com/fs/app/controller/CommonController.java

@@ -1,65 +1,231 @@
 package com.fs.app.controller;
 
 
-
-import cn.hutool.core.util.IdUtil;
-import cn.hutool.core.util.XmlUtil;
-import cn.hutool.json.JSONUtil;
-import com.baidubce.appbuilder.model.agentbuilder.AgentBuilderResult;
-import com.fs.ai.service.IBaiduAIService;
+import cn.jiguang.common.resp.APIConnectionException;
+import cn.jiguang.common.resp.APIRequestException;
+import com.fs.app.annotation.Login;
+import com.fs.app.utils.CityTreeUtil;
 import com.fs.app.utils.JwtUtils;
+import com.fs.app.vo.CityVO;
+import com.fs.common.config.FSConfig;
 
-import com.fs.chat.config.QwConfig;
-import com.fs.chat.config.WxConfig;
-import com.fs.chat.domain.*;
-import com.fs.chat.service.*;
-import com.fs.common.core.redis.RedisCache;
-import com.fs.company.domain.CompanyConfig;
-import com.fs.company.service.ICompanyConfigService;
-import com.fs.his.service.*;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.exception.file.OssException;
+import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.file.FileUploadUtils;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.service.ICompanySmsLogsService;
+import com.fs.company.service.ICompanyUserService;
+import com.fs.company.service.ICompanyVoiceLogsService;
+import com.fs.core.config.ServerConfig;
+import com.fs.crm.service.*;
+import com.fs.his.domain.FsCity;
+import com.fs.his.service.IFsAppVersionService;
+import com.fs.his.service.IFsCityService;
+import com.fs.jpush.service.JpushService;
 
-import com.fs.his.utils.ConfigUtil;
+import com.fs.system.oss.CloudStorageService;
+import com.fs.system.oss.OSSFactory;
 import com.fs.system.service.ISysConfigService;
 import com.fs.system.service.ISysDictDataService;
-import com.fs.voice.utils.StringUtil;
-import com.fs.wx.kf.dto.*;
-import com.fs.wx.kf.service.IWeixinKfService;
-import com.fs.wx.kf.vo.WeixinKfMsgItemVO;
-import com.fs.wx.kf.vo.WeixinKfMsgVO;
-import com.fs.wx.kf.vo.WeixinKfUserItemVO;
-import com.fs.wx.kf.vo.WeixinKfUserVO;
-import com.google.code.kaptcha.Producer;
-import com.qq.weixin.mp.aes.AesException;
-import com.qq.weixin.mp.aes.WXBizMsgCrypt;
+import com.fs.system.vo.DictVO;
+import com.fs.voice.service.IVoiceService;
+import com.google.common.collect.Lists;
 import io.swagger.annotations.Api;
-import org.apache.commons.lang3.StringUtils;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cache.annotation.Cacheable;
 import org.springframework.web.bind.annotation.*;
-import org.w3c.dom.Element;
+import org.springframework.web.multipart.MultipartFile;
 
-import javax.annotation.Resource;
-import java.util.ArrayList;
+import javax.servlet.http.HttpServletRequest;
+import java.util.HashMap;
 import java.util.List;
-import java.util.concurrent.TimeUnit;
-import java.util.logging.Logger;
-import java.util.stream.Collectors;
-
-import static com.fs.common.constant.FsConstants.REDIS_CHAT_NEXTCURSOR;
-import static com.fs.common.constant.FsConstants.REDIS_CHAT_SESSION;
+import java.util.Map;
 
 
 @Api("公共接口")
 @RestController
 @RequestMapping(value="/app/common")
-public class CommonController {
-
-    @Autowired
+public class CommonController extends AppBaseController {
+	@Autowired
     JwtUtils jwtUtils;
-    @Autowired
-    private ISysDictDataService dictDataService;
-    @Autowired
-    ConfigUtil configUtil;
+	@Autowired
+	private ServerConfig serverConfig;
+	@Autowired
+	private ISysDictDataService dictDataService;
+
+	@Autowired
+	ICrmCustomerUserService crmCustomerUserService;
+	@Autowired
+	ICrmCustomerService crmCustomerService;
+
+	@Autowired
+	private ICrmMsgService msgService;
+
+	@Autowired
+	private ISysConfigService configService;
+
+	@Autowired
+	private ICrmEventService eventService;
+
+	@Autowired
+	private IVoiceService voiceService;
+
+	@Autowired
+	ICompanyUserService userService;
+	@Autowired
+	private IFsAppVersionService fsAppVersionService;
+	@Autowired
+	private IFsCityService fsCityService;
+	@Autowired
+	private JpushService jpushService;
+
+	@Autowired
+	private ICrmCustomerHisOrderService crmCustomerHisOrderService;
+
+
+
+	@Autowired
+	private ICompanySmsLogsService smsLogsService;
+
+	@Autowired
+	private ICompanyVoiceLogsService voiceLogsService;
+
+	@Autowired
+	private ICompanyUserService companyUserService;
+
+	@Autowired
+	private ICrmCustomerContactsService crmCustomerContactsService;
+
+	public static final Logger LOGGER = LoggerFactory.getLogger(CommonController.class);
+
+
+	@ApiOperation("获取城市数据")
+	@GetMapping("/getCitys")
+	@Cacheable("cityData")
+	public R getCitys(){
+		List<FsCity> list=fsCityService.selectFsCityList(new FsCity());
+		List<CityVO> cityVOS = Lists.newArrayList();
+		for (FsCity city : list){
+			CityVO cityVO = new CityVO();
+			cityVO.setV(city.getCityId());
+			cityVO.setN(city.getCityName());
+			cityVO.setPid(city.getParentId());
+			cityVOS.add(cityVO);
+		}
+		return R.ok().put("data", CityTreeUtil.list2TreeConverter(cityVOS, "0"));
+
+	}
+
+	/**
+	 * 通用上传请求
+	 */
+	@ApiOperation("上传")
+	@PostMapping("/upload")
+	public R uploadFile(MultipartFile file) throws Exception
+	{
+		try
+		{
+			// 上传文件路径
+			String filePath = FSConfig.getUploadPath();
+			// 上传并返回新文件名称
+			String fileName = FileUploadUtils.upload(filePath, file);
+			String url = serverConfig.getUrl() + fileName;
+			AjaxResult ajax = AjaxResult.success();
+			ajax.put("fileName", fileName);
+			ajax.put("url", url);
+			return R.ok().put("fileName",fileName).put("url",url);
+		}
+		catch (Exception e)
+		{
+			return R.error(e.getMessage());
+		}
+	}
+
+
+	@ApiOperation("获取数据字典")
+	@GetMapping("/getDicts")
+//	@Cacheable(value= "dicts")
+	public R getDicts(
+	){
+		return R.ok();
+
+
+	}
+	@ApiOperation("获取数据字典")
+	@GetMapping("/getDictByKey")
+	public R getDictByKey(@ApiParam(required = false, name = "key", value = "key") @RequestParam(value = "key", required = false) String key){
+		List<DictVO> dictVOS=dictDataService.selectDictDataListByType(key);
+		return R.ok().put("data",dictVOS);
+	}
+
+	@Login
+	@ApiOperation("推送测试")
+	@GetMapping(value = "/pushText")
+	public R pushText()
+	{
+		CompanyUser companyUser=userService.selectCompanyUserById(Long.parseLong(getUserId()));
+		if(StringUtils.isEmpty(companyUser.getJpushId())){
+			return R.error("推送ID不存在");
+		}
+		Map<String, String> extrasMap=new HashMap<>();
+		extrasMap.put("customerId","1111");
+		extrasMap.put("type","1");
+		try {
+			jpushService.sendRegisterIdPush("客户消息","您有一个客户消息",extrasMap,companyUser.getJpushId());
+		} catch (APIConnectionException e) {
+			e.printStackTrace();
+			return R.error(e.getMessage());
+		} catch (APIRequestException e) {
+			e.printStackTrace();
+			return R.error(e.getMessage());
+		}
+		return R.ok();
+	}
+
+	@ApiOperation("获取系统配置")
+	@GetMapping(value = "/getConfig")
+	public R getConfig()
+	{
+		String sysConfig=configService.selectConfigByKey("sys:config");
+		return R.ok().put("sysConfig",sysConfig);
+	}
+	@ApiOperation("获取选择员工")
+	@GetMapping("/getSelectUserList")
+	public R getSelectUserList(HttpServletRequest request,
+	@ApiParam(required = false, name = "nickName", value = "nickName") @RequestParam(value = "nickName", required = false) String nickName
+	)
+	{
+		CompanyUser map=new CompanyUser();
+		map.setNickName(nickName);
+		map.setCompanyId(getCompanyId());
+		map.setIsDel(0);
+		map.setStatus("0");
+		List<CompanyUser> list = userService.selectCompanyUserList(map);
+		return R.ok().put("data",list);
+	}
+
+	@ApiOperation("上传")
+	@PostMapping("uploadOSS")
+	public R uploadOSS(@RequestParam("file") MultipartFile file) throws Exception
+	{
+
+		if (file.isEmpty())
+		{
+			throw new OssException("上传文件不能为空");
+		}
+		// 上传文件
+		String fileName = file.getOriginalFilename();
+		String suffix = fileName.substring(fileName.lastIndexOf("."));
+		CloudStorageService storage = OSSFactory.build();
+		String url = storage.uploadSuffix(file.getBytes(), suffix);
+		return R.ok().put("url",url);
+	}
 
 
 

+ 249 - 251
fs-company-app/src/main/java/com/fs/app/controller/FsUserController.java

@@ -6,18 +6,22 @@ import com.alibaba.fastjson.JSONObject;
 import com.fs.app.annotation.Login;
 import com.fs.app.config.ImageStorageConfig;
 
+import com.fs.app.param.FsUserTagUpdateParam;
+import com.fs.app.param.FsUserUpdateParam;
+import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.ResponseResult;
 import com.fs.common.exception.ServiceException;
 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.param.CourseAnalysisParam;
 import com.fs.course.param.newfs.FsUserCourseBeMemberImageParam;
 import com.fs.course.param.newfs.FsUserCourseBeMemberParam;
 import com.fs.course.service.IFsUserCourseService;
 import com.fs.course.vo.newfs.FsCourseAnalysisVO;
+import com.fs.his.domain.FsUser;
 import com.fs.his.service.IFsUserService;
-import com.fs.store.param.h5.CourseAnalysisParam;
 import com.fs.store.param.h5.FsUserPageListParam;
 import com.fs.store.param.h5.TagListParam;
 import com.fs.store.param.h5.UserStatisticsCommonParam;
@@ -85,257 +89,251 @@ public class FsUserController extends AppBaseController {
         return ResponseResult.ok(companyUsers);
     }
 
-//    @Login
-//    @GetMapping("/totalNumber")
-//    @ApiOperation("用户会员数量统计")
-//    public ResponseResult<UserListPageVO> getTotalNumber() {
-//        UserListPageVO userNumber = fsUserService.getUserNumber(Long.parseLong(getUserId()));
-//        return ResponseResult.ok(userNumber);
-//    }
-//
-//    @Login
-//    @GetMapping("/details")
-//    @ApiOperation("用户会员详情")
-//    public ResponseResult<UserDetailsVO> getUserDetails(@ApiParam(value = "用户id", required = true) @RequestParam Long userId,
-//                                                        @ApiParam(value = "时间tab,不传表示查询全部,分别是:今天、昨天、前天、近七天", required = true) @RequestParam(required = false) String dateTag) {
-//        UserDetailsVO userDetails = fsUserService.getUserDetails(Long.parseLong(getUserId()), userId, dateTag);
-//        return ResponseResult.ok(userDetails);
-//    }
-//
-//    @Login
-//    @GetMapping("/tagList")
-//    @ApiOperation("用户会员标签列表")
-//    public ResponseResult<PageInfo<CompanyUserTagListVO>> getTagList(TagListParam param) {
-//        param.setUserId(Long.parseLong(getUserId()));
-//        PageHelper.startPage(param.getPageNum(), param.getPageSize());
-//        List<CompanyUserTagListVO> tagList = companyTagUserService.getTagList(param);
-//        PageInfo<CompanyUserTagListVO> pageInfo = new PageInfo<>(tagList);
-//        return ResponseResult.ok(pageInfo);
-//    }
-//
-//    @Login
-//    @PostMapping("/disabled")
-//    @ApiOperation("批量禁用会员")
-//    public ResponseResult<Boolean> disabledUser(@ApiParam(value = "联系人id集合", required = true) @RequestBody String[] ids) {
-//        Boolean r = fsUserService.disabledUser(ids, false);
-//        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);
-//        return ResponseResult.ok(r);
-//    }
-//
-//    @Login
-//    @GetMapping("/firstPage/summaryCount")
-//    @ApiOperation("首页数据-顶部汇总统计")
-//    public ResponseResult<FsUserSummaryCountVO> userSummaryCount() {
-//        long userId = Long.parseLong(getUserId());
-//        return ResponseResult.ok(fsUserService.userSummaryCount(userId));
-//    }
-//
-//    @Login
-//    @GetMapping("/firstPage/statistics")
-//    @ApiOperation("首页数据-课程/答题/红包统计")
-//    public ResponseResult<FsUserStatisticsVO> userStatistics(@ApiParam(value = "开始时间", required = true) @RequestParam String startTime,
-//                                                             @ApiParam(value = "结束时间", required = true) @RequestParam String endTime) {
-//        long userId = Long.parseLong(getUserId());
-//        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-//        String nowDate = dateFormat.format(new Date());
-//        /*---------- 如果传入的日期是今天 ----------*/
-//        UserStatisticsCommonParam param = new UserStatisticsCommonParam();
-//        param.setUserId(userId).setStartTime(startTime).setEndTime(endTime);
-//        FsUserStatisticsVO vo = fsUserService.userStatistics(param);
-//        if (nowDate.compareTo(startTime) > 0 && nowDate.compareTo(endTime) < 0) {
-//            String yesterday = LocalDate.now().minusDays(1).toString();
-//            UserStatisticsCommonParam paramYes = new UserStatisticsCommonParam();
-//            paramYes.setUserId(userId).setStartTime(yesterday + " 00:00:00").setEndTime(yesterday + " 23:59:59");
-//            FsUserStatisticsVO fsUserStatisticsVO = fsUserService.userStatistics(paramYes);
-//            vo.setYesterdayVO(fsUserStatisticsVO);
-//        }
-//        return ResponseResult.ok(vo);
-//    }
-//
-//    @Login
-//    @GetMapping("/statistics/details")
-//    @ApiOperation("数据统计详情-课程/答题/红包统计")
-//    public ResponseResult<FsUserStatisticsVO> userStatisticsDetails(@ApiParam(value = "营期id") @RequestParam(required = false) String periodId,
-//                                                                    @ApiParam(value = "视频id") @RequestParam(required = false) String videoId) {
-//        long userId = Long.parseLong(getUserId());
-//        long companyId = getCompanyId();
-//        UserStatisticsCommonParam param = new UserStatisticsCommonParam();
-//        param.setUserId(userId).setPeriodId(periodId).setVideoId(videoId).setCompanyId(companyId);
-//        FsUserStatisticsVO fsUserStatisticsVO = fsUserService.userStatisticsDetails(param);
-//        return ResponseResult.ok(fsUserStatisticsVO);
-//    }
-//
-//    @Login
-//    @GetMapping("/firstPage/userRanking")
-//    @ApiOperation("首页数据/详情-销售排行榜统计")
-//    public ResponseResult<List<FsUserRankingVO>> userRanking(
-//            @ApiParam(value = "开始时间") @RequestParam(required = false) String startTime,
-//            @ApiParam(value = "结束时间") @RequestParam(required = false) String endTime,
-//            @ApiParam(value = "营期id") @RequestParam(required = false) String periodId,
-//            @ApiParam(value = "视频id") @RequestParam(required = false) String videoId,
-//            @ApiParam(value = "asc-正序,desc-倒序", required = true) @RequestParam String order,
-//            @ApiParam(value = "类型,1-按完播率,2-按正确率", required = true) @RequestParam Integer type
-//    ) {
-//        long userId = Long.parseLong(getUserId());
-//        return ResponseResult.ok(fsUserService.userRanking(userId, startTime, endTime, periodId, videoId, order, type));
-//    }
-//
-//    @Login
-//    @GetMapping("/firstPage/courseRanking")
-//    @ApiOperation("首页数据/详情-课程排行榜统计")
-//    public ResponseResult<List<FsCourseRankingVO>> courseRanking(
-//            @ApiParam(value = "开始时间") @RequestParam(required = false) String startTime,
-//            @ApiParam(value = "结束时间") @RequestParam(required = false) String endTime,
-//            @ApiParam(value = "课程id") @RequestParam(required = false) String courseId,
-//            @ApiParam(value = "视频id") @RequestParam(required = false) String videoId,
-//            @ApiParam(value = "asc-正序,desc-倒序", required = true) @RequestParam String order,
-//            @ApiParam(value = "类型,1-按完播率,2-按正确率", required = true) @RequestParam Integer type
-//    ) {
-//        long userId = Long.parseLong(getUserId());
-//        return ResponseResult.ok(fsUserService.courseRanking(userId, startTime, endTime, courseId, videoId, order, type));
-//    }
-//
-//    @Login
-//    @GetMapping("/firstPage/graphic")
-//    @ApiOperation("首页数据-转化漏斗图")
-//    public ResponseResult<List<FsUserGraphicStatisticsVO>> graphicStatistics(@ApiParam(value = "开始时间", required = true) @RequestParam String startTime,
-//                                                                             @ApiParam(value = "结束时间", required = true) @RequestParam String endTime) {
-//        long userId = Long.parseLong(getUserId());
-//        UserStatisticsCommonParam param = new UserStatisticsCommonParam();
-//        param.setUserId(userId).setStartTime(startTime).setEndTime(endTime);
-//        List<FsUserGraphicStatisticsVO> list = fsUserService.graphicStatistics(param);
-//        return ResponseResult.ok(list);
-//    }
-//
-//    @Login
-//    @GetMapping("/graphic/details")
-//    @ApiOperation("详情-转化漏斗图")
-//    public ResponseResult<List<FsUserGraphicStatisticsVO>> graphicStatisticsDetails(@ApiParam(value = "营期id") @RequestParam(required = false) String periodId,
-//                                                                                    @ApiParam(value = "视频id") @RequestParam(required = false) String videoId) {
-//        long userId = Long.parseLong(getUserId());
-//        UserStatisticsCommonParam param = new UserStatisticsCommonParam();
-//        param.setUserId(userId).setPeriodId(periodId).setVideoId(videoId);
-//        List<FsUserGraphicStatisticsVO> list = fsUserService.graphicStatistics(param);
-//        return ResponseResult.ok(list);
-//    }
-//
-//    @Login
-//    @ApiOperation("修改用户备注、姓名")
-//    @PostMapping("/changeUserInfo")
-//    public ResponseResult<Object> changeUserInfo(@Valid @RequestBody FsUserUpdateParam param) {
-//        log.debug("修改用户备注、姓名 param:{}", JSON.toJSONString(param));
-//        FsUser fsUser = fsUserService.selectFsUserById(param.getFsUserId());
-//        if (Objects.isNull(fsUser)) {
-//            throw new ServiceException("用户不存在");
-//        }
-//
-//        fsUser.setNickname(param.getNickName());
-//        fsUser.setRemark(param.getRemark());
-//        fsUserService.updateFsUser(fsUser);
-//        return ResponseResult.ok();
-//    }
-//
-//    @Login
-//    @ApiOperation("修改用户标签")
-//    @PostMapping("/changeUserTags")
-//    public ResponseResult<Object> changeUserTags(@Valid @RequestBody FsUserTagUpdateParam param) {
-//        companyTagUserService.changeUserTags(param.getFsUserIds(), param.getTagIds());
-//        return ResponseResult.ok();
-//    }
-//
-//    @Login
-//    @GetMapping("/courseAnalysis")
-//    @ApiOperation("管理-课程分析-分页列表查询")
-//    public ResponseResult<PageInfo<FsCourseAnalysisVO>> courseAnalysisList(CourseAnalysisParam param) {
-//        param.setCompanyId(getCompanyId());
-//        PageHelper.startPage(param.getPageNum(), param.getPageSize());
-//        List<FsCourseAnalysisVO> list = fsUserService.courseAnalysis(param);
-//        PageInfo<FsCourseAnalysisVO> pageInfo = new PageInfo<>(list);
-//        return ResponseResult.ok(pageInfo);
-//    }
-//
-//    @Login
-//    @GetMapping("/companyUser/details")
-//    @ApiOperation("管理-群管数据-根据销售id,群管数据统计")
-//    public ResponseResult<FsUserStatisticsVO> companyUserStatistics(@ApiParam(value = "营期id") @RequestParam(required = false) String periodId,
-//                                                                    @ApiParam(value = "视频id") @RequestParam(required = false) String videoId,
-//                                                                    @ApiParam(value = "销售用户id", required = true) @RequestParam String companyUserId) {
-//        UserStatisticsCommonParam param = new UserStatisticsCommonParam();
-//        param.setUserId(Long.parseLong(getUserId()))
-//                .setPeriodId(periodId).setVideoId(videoId)
-//                .setCompanyId(getCompanyId())
-//                .setCompanyUserId(companyUserId);
-//        FsUserStatisticsVO fsUserStatisticsVO = fsUserService.userStatisticsDetails(param);
-//        return ResponseResult.ok(fsUserStatisticsVO);
-//    }
-//
-//    @Login
-//    @GetMapping("/companyUser/summaryCount")
-//    @ApiOperation("管理-群管数据-顶部会员统计")
-//    public ResponseResult<CompanyUserSummaryCountVO> companyUserSummaryCount(@ApiParam(value = "销售用户id", required = true) @RequestParam String companyUserId) {
-//        long userId = Long.parseLong(getUserId());
-//        return ResponseResult.ok(fsUserService.companyUserSummaryCount(userId, companyUserId));
-//    }
-//
-//    @Login
-//    @ApiOperation("会员关联绑定销售")
-//    @PostMapping("/beMember")
-//    public ResponseResult<Boolean> becomeMember(@Valid @RequestBody FsUserCourseBeMemberParam param) {
-//        return fsUserService.becomeMember(param);
-//    }
-//
-//    @Login
-//    @PostMapping("/userImage")
-//    @ApiOperation("生成分享会员海报")
-//    public R createCourseImage(@RequestBody FsUserCourseBeMemberImageParam param) {
-//        try {
-//            //获取用户头像
-////            FsUser fsUser = fsUserService.selectFsUserById(param.getUserId());
-////            String url = "";
-////            if(fsUser != null) {
-////                url = fsUser.getAvatar();
-////            }
-//            String path = imageConfig.getServerPath();
-//            InputStream inputStream = fsUserCourseService.handleImage("", path);
-//
-//            // 背景图片使用的后台商城配置的会员海报,如果没有配置则使用默认的logo图片
-//            String config = configService.selectConfigByKey("store.config");
-//            JSONObject jsonObject = JSONObject.parseObject(config);
-//            String userPosterImage = jsonObject.getString("userPosterImage");
-//            String backgroundImagePath;
-//            if(StringUtils.isEmpty(userPosterImage)){
-//                backgroundImagePath = "https://fbylive.obs.cn-southwest-2.myhuaweicloud.com/fs/20250430/1745980979886.png";
-//            } else {
-//                backgroundImagePath = userPosterImage;
+    @Login
+    @GetMapping("/totalNumber")
+    @ApiOperation("用户会员数量统计")
+    public ResponseResult<UserListPageVO> getTotalNumber() {
+        UserListPageVO userNumber = fsUserService.getUserNumber(Long.parseLong(getUserId()));
+        return ResponseResult.ok(userNumber);
+    }
+
+    @Login
+    @GetMapping("/details")
+    @ApiOperation("用户会员详情")
+    public ResponseResult<UserDetailsVO> getUserDetails(@ApiParam(value = "用户id", required = true) @RequestParam Long userId,
+                                                        @ApiParam(value = "时间tab,不传表示查询全部,分别是:今天、昨天、前天、近七天", required = true) @RequestParam(required = false) String dateTag) {
+        UserDetailsVO userDetails = fsUserService.getUserDetails(Long.parseLong(getUserId()), userId, dateTag);
+        return ResponseResult.ok(userDetails);
+    }
+
+    @Login
+    @GetMapping("/tagList")
+    @ApiOperation("用户会员标签列表")
+    public ResponseResult<PageInfo<CompanyUserTagListVO>> getTagList(TagListParam param) {
+        param.setUserId(Long.parseLong(getUserId()));
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<CompanyUserTagListVO> tagList = companyTagUserService.getTagList(param);
+        PageInfo<CompanyUserTagListVO> pageInfo = new PageInfo<>(tagList);
+        return ResponseResult.ok(pageInfo);
+    }
+
+    @Login
+    @PostMapping("/disabled")
+    @ApiOperation("批量禁用会员")
+    public ResponseResult<Boolean> disabledUser(@ApiParam(value = "联系人id集合", required = true) @RequestBody String[] ids) {
+        Boolean r = fsUserService.disabledUser(ids, false);
+        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);
+        return ResponseResult.ok(r);
+    }
+
+    @Login
+    @GetMapping("/firstPage/summaryCount")
+    @ApiOperation("首页数据-顶部汇总统计")
+    public ResponseResult<FsUserSummaryCountVO> userSummaryCount() {
+        long userId = Long.parseLong(getUserId());
+        return ResponseResult.ok(fsUserService.userSummaryCount(userId));
+    }
+
+    @Login
+    @GetMapping("/firstPage/statistics")
+    @ApiOperation("首页数据-课程/答题/红包统计")
+    public ResponseResult<FsUserStatisticsVO> userStatistics(@ApiParam(value = "开始时间", required = true) @RequestParam String startTime,
+                                                             @ApiParam(value = "结束时间", required = true) @RequestParam String endTime) {
+        long userId = Long.parseLong(getUserId());
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        String nowDate = dateFormat.format(new Date());
+        /*---------- 如果传入的日期是今天 ----------*/
+        UserStatisticsCommonParam param = new UserStatisticsCommonParam();
+        param.setUserId(userId).setStartTime(startTime).setEndTime(endTime);
+        FsUserStatisticsVO vo = fsUserService.userStatistics(param);
+        if (nowDate.compareTo(startTime) > 0 && nowDate.compareTo(endTime) < 0) {
+            String yesterday = LocalDate.now().minusDays(1).toString();
+            UserStatisticsCommonParam paramYes = new UserStatisticsCommonParam();
+            paramYes.setUserId(userId).setStartTime(yesterday + " 00:00:00").setEndTime(yesterday + " 23:59:59");
+            FsUserStatisticsVO fsUserStatisticsVO = fsUserService.userStatistics(paramYes);
+            vo.setYesterdayVO(fsUserStatisticsVO);
+        }
+        return ResponseResult.ok(vo);
+    }
+
+    @Login
+    @GetMapping("/statistics/details")
+    @ApiOperation("数据统计详情-课程/答题/红包统计")
+    public ResponseResult<FsUserStatisticsVO> userStatisticsDetails(@ApiParam(value = "营期id") @RequestParam(required = false) String periodId,
+                                                                    @ApiParam(value = "视频id") @RequestParam(required = false) String videoId) {
+        long userId = Long.parseLong(getUserId());
+        long companyId = getCompanyId();
+        UserStatisticsCommonParam param = new UserStatisticsCommonParam();
+        param.setUserId(userId).setPeriodId(periodId).setVideoId(videoId).setCompanyId(companyId);
+        FsUserStatisticsVO fsUserStatisticsVO = fsUserService.userStatisticsDetails(param);
+        return ResponseResult.ok(fsUserStatisticsVO);
+    }
+
+    @Login
+    @GetMapping("/firstPage/userRanking")
+    @ApiOperation("首页数据/详情-销售排行榜统计")
+    public ResponseResult<List<FsUserRankingVO>> userRanking(
+            @ApiParam(value = "开始时间") @RequestParam(required = false) String startTime,
+            @ApiParam(value = "结束时间") @RequestParam(required = false) String endTime,
+            @ApiParam(value = "营期id") @RequestParam(required = false) String periodId,
+            @ApiParam(value = "视频id") @RequestParam(required = false) String videoId,
+            @ApiParam(value = "asc-正序,desc-倒序", required = true) @RequestParam String order,
+            @ApiParam(value = "类型,1-按完播率,2-按正确率", required = true) @RequestParam Integer type
+    ) {
+        long userId = Long.parseLong(getUserId());
+        return ResponseResult.ok(fsUserService.userRanking(userId, startTime, endTime, periodId, videoId, order, type));
+    }
+
+    @Login
+    @GetMapping("/firstPage/courseRanking")
+    @ApiOperation("首页数据/详情-课程排行榜统计")
+    public ResponseResult<List<FsCourseRankingVO>> courseRanking(
+            @ApiParam(value = "开始时间") @RequestParam(required = false) String startTime,
+            @ApiParam(value = "结束时间") @RequestParam(required = false) String endTime,
+            @ApiParam(value = "课程id") @RequestParam(required = false) String courseId,
+            @ApiParam(value = "视频id") @RequestParam(required = false) String videoId,
+            @ApiParam(value = "asc-正序,desc-倒序", required = true) @RequestParam String order,
+            @ApiParam(value = "类型,1-按完播率,2-按正确率", required = true) @RequestParam Integer type
+    ) {
+        long userId = Long.parseLong(getUserId());
+        return ResponseResult.ok(fsUserService.courseRanking(userId, startTime, endTime, courseId, videoId, order, type));
+    }
+
+    @Login
+    @GetMapping("/firstPage/graphic")
+    @ApiOperation("首页数据-转化漏斗图")
+    public ResponseResult<List<FsUserGraphicStatisticsVO>> graphicStatistics(@ApiParam(value = "开始时间", required = true) @RequestParam String startTime,
+                                                                             @ApiParam(value = "结束时间", required = true) @RequestParam String endTime) {
+        long userId = Long.parseLong(getUserId());
+        UserStatisticsCommonParam param = new UserStatisticsCommonParam();
+        param.setUserId(userId).setStartTime(startTime).setEndTime(endTime);
+        List<FsUserGraphicStatisticsVO> list = fsUserService.graphicStatistics(param);
+        return ResponseResult.ok(list);
+    }
+
+    @Login
+    @GetMapping("/graphic/details")
+    @ApiOperation("详情-转化漏斗图")
+    public ResponseResult<List<FsUserGraphicStatisticsVO>> graphicStatisticsDetails(@ApiParam(value = "营期id") @RequestParam(required = false) String periodId,
+                                                                                    @ApiParam(value = "视频id") @RequestParam(required = false) String videoId) {
+        long userId = Long.parseLong(getUserId());
+        UserStatisticsCommonParam param = new UserStatisticsCommonParam();
+        param.setUserId(userId).setPeriodId(periodId).setVideoId(videoId);
+        List<FsUserGraphicStatisticsVO> list = fsUserService.graphicStatistics(param);
+        return ResponseResult.ok(list);
+    }
+
+    @Login
+    @ApiOperation("修改用户备注、姓名")
+    @PostMapping("/changeUserInfo")
+    public ResponseResult<Object> changeUserInfo(@Valid @RequestBody FsUserUpdateParam param) {
+        log.debug("修改用户备注、姓名 param:{}", JSON.toJSONString(param));
+        FsUser fsUser = fsUserService.selectFsUserById(param.getFsUserId());
+        if (Objects.isNull(fsUser)) {
+            throw new ServiceException("用户不存在");
+        }
+
+        fsUser.setNickName(param.getNickName());
+        fsUser.setRemark(param.getRemark());
+        fsUserService.updateFsUser(fsUser);
+        return ResponseResult.ok();
+    }
+
+    @Login
+    @ApiOperation("修改用户标签")
+    @PostMapping("/changeUserTags")
+    public ResponseResult<Object> changeUserTags(@Valid @RequestBody FsUserTagUpdateParam param) {
+        companyTagUserService.changeUserTags(param.getFsUserIds(), param.getTagIds());
+        return ResponseResult.ok();
+    }
+
+    @Login
+    @GetMapping("/courseAnalysis")
+    @ApiOperation("管理-课程分析-分页列表查询")
+    public ResponseResult<PageInfo<FsCourseAnalysisVO>> courseAnalysisList(CourseAnalysisParam param) {
+        param.setCompanyId(getCompanyId());
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<FsCourseAnalysisVO> list = fsUserService.courseAnalysis(param);
+        PageInfo<FsCourseAnalysisVO> pageInfo = new PageInfo<>(list);
+        return ResponseResult.ok(pageInfo);
+    }
+
+    @Login
+    @GetMapping("/companyUser/details")
+    @ApiOperation("管理-群管数据-根据销售id,群管数据统计")
+    public ResponseResult<FsUserStatisticsVO> companyUserStatistics(@ApiParam(value = "营期id") @RequestParam(required = false) String periodId,
+                                                                    @ApiParam(value = "视频id") @RequestParam(required = false) String videoId,
+                                                                    @ApiParam(value = "销售用户id", required = true) @RequestParam String companyUserId) {
+        UserStatisticsCommonParam param = new UserStatisticsCommonParam();
+        param.setUserId(Long.parseLong(getUserId()))
+                .setPeriodId(periodId).setVideoId(videoId)
+                .setCompanyId(getCompanyId())
+                .setCompanyUserId(companyUserId);
+        FsUserStatisticsVO fsUserStatisticsVO = fsUserService.userStatisticsDetails(param);
+        return ResponseResult.ok(fsUserStatisticsVO);
+    }
+
+    @Login
+    @GetMapping("/companyUser/summaryCount")
+    @ApiOperation("管理-群管数据-顶部会员统计")
+    public ResponseResult<CompanyUserSummaryCountVO> companyUserSummaryCount(@ApiParam(value = "销售用户id", required = true) @RequestParam String companyUserId) {
+        long userId = Long.parseLong(getUserId());
+        return ResponseResult.ok(fsUserService.companyUserSummaryCount(userId, companyUserId));
+    }
+
+    @Login
+    @ApiOperation("会员关联绑定销售")
+    @PostMapping("/beMember")
+    public ResponseResult<Boolean> becomeMember(@Valid @RequestBody FsUserCourseBeMemberParam param) {
+        return fsUserService.becomeMember(param);
+    }
+
+    @Login
+    @PostMapping("/userImage")
+    @ApiOperation("生成分享会员海报")
+    public R createCourseImage(@RequestBody FsUserCourseBeMemberImageParam param) {
+        try {
+            //获取用户头像
+//            FsUser fsUser = fsUserService.selectFsUserById(param.getUserId());
+//            String url = "";
+//            if(fsUser != null) {
+//                url = fsUser.getAvatar();
 //            }
-//            String base64Image = fsUserCourseService.createUserImageQR(param.getRealLink(), backgroundImagePath, inputStream, "png", param.getCompanyUserId());
-//            // 返回Base64编码的图片字符串
-//            Map<String, Object> map = new HashMap<>();
-//            map.put("url", base64Image);
-//            return R.ok().put("posterImage", map);
-//        } catch (Exception e) {
-//            log.error("生成海报失败,param:{}", param);
-//            return R.error("生成海报失败!");
-//        }
-//    }
-
-    @PostMapping("/test")
-    @ApiOperation("测试定时任务")
-    public void userCourseCountTask() {
-        userCourseCountService.insertFsUserCourseCountTask();
+            String path = imageConfig.getServerPath();
+            InputStream inputStream = fsUserCourseService.handleImage("", path);
+
+            // 背景图片使用的后台商城配置的会员海报,如果没有配置则使用默认的logo图片
+            String config = configService.selectConfigByKey("store.config");
+            JSONObject jsonObject = JSONObject.parseObject(config);
+            String userPosterImage = jsonObject.getString("userPosterImage");
+            String backgroundImagePath;
+            if(StringUtils.isEmpty(userPosterImage)){
+                backgroundImagePath = "https://fbylive.obs.cn-southwest-2.myhuaweicloud.com/fs/20250430/1745980979886.png";
+            } else {
+                backgroundImagePath = userPosterImage;
+            }
+            String base64Image = fsUserCourseService.createUserImageQR(param.getRealLink(), backgroundImagePath, inputStream, "png", param.getCompanyUserId());
+            // 返回Base64编码的图片字符串
+            Map<String, Object> map = new HashMap<>();
+            map.put("url", base64Image);
+            return R.ok().put("posterImage", map);
+        } catch (Exception e) {
+            log.error("生成海报失败,param:{}", param);
+            return R.error("生成海报失败!");
+        }
     }
 
 }

+ 15 - 1
fs-company-app/src/main/java/com/fs/app/controller/WxCompanyUserController.java

@@ -5,6 +5,7 @@ import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
 import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
 import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
 import cn.hutool.core.date.DateTime;
+import com.alibaba.fastjson.JSON;
 import com.fs.app.annotation.Login;
 import com.fs.app.param.LoginMaWxParam;
 import com.fs.app.utils.JwtUtils;
@@ -15,8 +16,11 @@ import com.fs.company.domain.CompanyUser;
 import com.fs.company.service.ICompanyDeptService;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.core.config.WxMaConfiguration;
+import com.fs.course.config.CourseMaConfig;
 import com.fs.his.domain.FsUser;
 import com.fs.his.service.IFsUserService;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.mapper.SysConfigMapper;
 import com.fs.wx.miniapp.config.WxMaProperties;
 import io.jsonwebtoken.Claims;
 import io.swagger.annotations.Api;
@@ -30,6 +34,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.Date;
+import java.util.List;
 
 @Api("微信小程序相关接口(暂废弃,后面再删除)")
 @RestController
@@ -56,14 +61,23 @@ public class WxCompanyUserController extends AppBaseController {
     @Autowired
     private IFsUserService userService;
 
+    @Autowired
+    private SysConfigMapper sysConfigMapper;
+
     @ApiOperation("小程序-授权登录")
     @PostMapping("/loginByMa")
     public R login(@RequestBody LoginMaWxParam 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("小程序配置为空");
+        }
+        CourseMaConfig courseMaConfig = courseMaConfigs.get(0);
         //获取第二个小程序配置,序号从0开始
-        final WxMaService wxService = WxMaConfiguration.getMaService(maProperties.getConfigs().get(1).getAppid());
+        final WxMaService wxService = WxMaConfiguration.getMaService(courseMaConfig.getAppid());
         try {
             WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(param.getCode());
             this.logger.info(session.getSessionKey());

+ 24 - 0
fs-company-app/src/main/java/com/fs/app/controller/WxH5MpController.java

@@ -106,5 +106,29 @@ public class WxH5MpController {
 
     }
 
+    @ApiOperation("单独返回用户头像和昵称的接口,不保存用户数据")
+    @PostMapping("/userInfo")
+    public R mpGetUserInfo(@Valid @RequestBody FsUserLoginByMpParam param) {
+        try {
+            //获取微信用户信息
+            WxOAuth2AccessToken wxMpOAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(param.getCode());
+            WxOAuth2UserInfo wxMpUser = wxMpService.getOAuth2Service().getUserInfo(wxMpOAuth2AccessToken, null);
+            String nickname = wxMpUser.getNickname();
+            String headImgUrl = wxMpUser.getHeadImgUrl();
+            log.info("仅仅获取用户昵称和头像,nickname: {},headImgUrl:{}", nickname, headImgUrl);
+            Map<String, Object> map = new HashMap<>();
+            map.put("nickname", nickname);
+            map.put("headImgUrl", headImgUrl);
+            return R.ok(map);
+        } catch (WxErrorException e) {
+            if (e.getError().getErrorCode() == 40163) {
+                return R.error(40163, e.getError().getErrorMsg());
+            } else {
+                return R.error("获取用户信息失败," + e.getMessage());
+            }
+        }
+
+    }
+
 
 }

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

@@ -0,0 +1,22 @@
+package com.fs.app.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import java.util.List;
+
+@Data
+public class FsUserTagUpdateParam {
+    /**
+     * 用户ID
+     */
+    @ApiModelProperty("用户ID集合")
+    @NotEmpty(message = "用户ID不能为空")
+    private List<Long> fsUserIds;
+    /**
+     * 标签ID
+     */
+    @ApiModelProperty("标签ID集合")
+    private List<Long> tagIds;
+}

+ 26 - 0
fs-company-app/src/main/java/com/fs/app/param/FsUserUpdateParam.java

@@ -0,0 +1,26 @@
+package com.fs.app.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class FsUserUpdateParam {
+    /**
+     * 用户ID
+     */
+    @ApiModelProperty("用户ID")
+    @NotNull(message = "用户ID不能为空")
+    private Long fsUserId;
+    /**
+     * 用户昵称
+     */
+    @ApiModelProperty("用户昵称")
+    private String nickName;
+    /**
+     * 用户备注
+     */
+    @ApiModelProperty("用户备注")
+    private String remark;
+}

+ 53 - 0
fs-company-app/src/main/java/com/fs/app/service/impl/AppServiceImpl.java

@@ -35,7 +35,60 @@ public class AppServiceImpl implements IAppService {
 
     @Override
     public void changeUserDeptAndPost(ChangeUserDeptAndPostParam param) {
+        log.debug("change user dept and post param: {}", JSON.toJSONString(param));
+        Set<Long> companyUserIds = Arrays.stream(param.getCompanyUserIds().split(",")).map(Long::new).collect(Collectors.toSet());
 
+        List<CompanyUser> companyUsers = companyUserService.selectCompanyUserByIds(companyUserIds);
+        if (Objects.isNull(companyUsers) || companyUsers.isEmpty()) {
+            throw new CustomException("销售不存在");
+        }
+
+        // 修改部门
+        if (Objects.nonNull(param.getDeptId())) {
+            CompanyDept companyDept = companyDeptService.selectCompanyDeptById(param.getDeptId());
+            if (Objects.isNull(companyDept)) {
+                throw new CustomException("部门不存在");
+            }
+
+            companyUsers.forEach(companyUser -> {
+                companyUser.setDeptId(param.getDeptId());
+                companyUserService.updateCompanyUser(companyUser);
+            });
+        }
+
+        // 修改岗位
+        if (StringUtils.isNotBlank(param.getPostIds())) {
+            List<Long> postIds = Arrays.stream(param.getPostIds().split(",")).map(Long::new).collect(Collectors.toList());
+            List<CompanyPost> companyPosts =  companyPostService.selectCompanyPostByIds(postIds);
+            if (Objects.nonNull(companyPosts) && !companyPosts.isEmpty()) {
+                companyUsers.forEach(companyUser -> {
+                    companyUserPostService.deleteCompanyUserPostById(companyUser.getUserId());
+                    companyUserPostService.batchInsertCompanyUserPost(companyPosts.stream().map(p -> {
+                        CompanyUserPost companyUserPost = new CompanyUserPost();
+                        companyUserPost.setPostId(p.getPostId());
+                        companyUserPost.setUserId(companyUser.getUserId());
+                        return companyUserPost;
+                    }).collect(Collectors.toList()));
+                });
+            }
+        }
+
+        // 修改角色
+        if (StringUtils.isNotBlank(param.getRoleIds())) {
+            List<Long> roleIds = Arrays.stream(param.getRoleIds().split(",")).map(Long::new).collect(Collectors.toList());
+            List<CompanyRole> CompanyRoles =  companyRoleService.selectCompanyRoleByIds(roleIds);
+            if (Objects.nonNull(CompanyRoles) && !CompanyRoles.isEmpty()) {
+                companyUsers.forEach(companyUser -> {
+                    companyUserRoleService.deleteCompanyUserRoleById(companyUser.getUserId());
+                    companyUserRoleService.batchInsertCompanyUserRole(CompanyRoles.stream().map(p -> {
+                        CompanyUserRole companyUserRole = new CompanyUserRole();
+                        companyUserRole.setRoleId(p.getRoleId());
+                        companyUserRole.setUserId(companyUser.getUserId());
+                        return companyUserRole;
+                    }).collect(Collectors.toList()));
+                });
+            }
+        }
     }
 
     /**

+ 1 - 2
fs-company-app/src/main/resources/application.yml

@@ -5,5 +5,4 @@ server:
 # Spring配置
 spring:
   profiles:
-    active: dev
-#    active: druid-sxjz
+    active: druid-fcky-test

+ 10 - 0
fs-company/src/main/java/com/fs/company/controller/company/CompanyController.java

@@ -15,8 +15,10 @@ import com.fs.company.vo.CompanyNameVO;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
 import com.fs.his.vo.OptionsVO;
+import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
@@ -109,4 +111,12 @@ public class CompanyController extends BaseController
         return getDataTable(list);
     }
 
+    @ApiOperation("配置销售审核")
+    @PostMapping(value = "/configUserCheck")
+    public R configUserCheck(boolean userIsDefaultBlack) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        companyService.configUserCheck(loginUser.getCompany().getCompanyId(), userIsDefaultBlack ? 1 : 0);
+        return R.ok();
+    }
+
 }

+ 6 - 2
fs-company/src/main/java/com/fs/company/controller/course/FsCourseAnswerLogsController.java

@@ -44,11 +44,14 @@ public class FsCourseAnswerLogsController extends BaseController
     @GetMapping("/list")
     public TableDataInfo list(FsCourseAnswerLogsParam param)
     {
-        startPage();
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         if (param.getPhoneMk() != null && param.getPhoneMk() != "") {
             param.setPhone(encryptPhone(param.getPhoneMk()));
         }
+        param.setCompanyId( loginUser.getCompany().getCompanyId());
 
+        startPage();
         List<FsCourseAnswerLogsListVO> list = fsCourseAnswerLogsService.selectFsCourseAnswerLogsListVO(param);
         return getDataTable(list);
     }
@@ -60,7 +63,7 @@ public class FsCourseAnswerLogsController extends BaseController
     @GetMapping("/myList")
     public TableDataInfo myList(FsCourseAnswerLogsParam param)
     {
-        startPage();
+
 
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         param.setCompanyId( loginUser.getCompany().getCompanyId());
@@ -68,6 +71,7 @@ public class FsCourseAnswerLogsController extends BaseController
         if (param.getPhoneMk() != null && param.getPhoneMk() != "") {
             param.setPhone(encryptPhone(param.getPhoneMk()));
         }
+        startPage();
 
         List<FsCourseAnswerLogsListVO> list = fsCourseAnswerLogsService.selectFsCourseAnswerLogsListVO(param);
         return getDataTable(list);

+ 1 - 1
fs-company/src/main/java/com/fs/user/FsUserAdminController.java

@@ -38,7 +38,7 @@ public class FsUserAdminController extends BaseController {
     @PostMapping("/list")
     @ApiOperation("会员列表(与移动端使用的相同查询)")
     public TableDataInfo pageList(@RequestBody FsUserPageListParam param) {
-//        startPage();
+        //startPage();
 
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         param.setCompanyId(loginUser.getCompany().getCompanyId());

+ 1 - 1
fs-company/src/main/resources/application.yml

@@ -3,7 +3,7 @@ server:
 # Spring配置
 spring:
   profiles:
-    active: dev
+    active: druid-fcky-test
 #    active: druid-jzzx
 #    active: druid-hdt
 #    active: druid-sxjz

+ 26 - 22
fs-qw-task/src/main/java/com/fs/app/task/CourseWatchLogScheduler.java

@@ -23,6 +23,9 @@ public class CourseWatchLogScheduler {
     private final AtomicBoolean isRunning2 = new AtomicBoolean(false);
 
     private final AtomicBoolean isRunning3 = new AtomicBoolean(false);
+
+    private final AtomicBoolean isRunning4 = new AtomicBoolean(false);
+
     @Autowired
     private FsCourseWatchLogMapper courseWatchLogMapper;
 
@@ -44,9 +47,6 @@ public class CourseWatchLogScheduler {
     @Autowired
     private SopLogsTaskService sopLogsTaskService;
 
-//    @Autowired
-//    private IFsCourseRedPacketRetryService redPacketRetryService;
-
 //    // 定时任务批量更新到数据库
 //    @Scheduled(fixedRate = 60000) // 每分钟执行一次
 //    public void scheduleBatchUpdateToDatabase() {
@@ -56,9 +56,9 @@ public class CourseWatchLogScheduler {
 
 
     /**
-     * 检查看课状态(先导课只有30秒)
+     * 检查看课状态
      */
-    @Scheduled(fixedRate = 20000) // 每15秒执行一次
+    @Scheduled(fixedRate = 60000) // 每分钟执行一次
     public void checkWatchStatus() {
         // 尝试设置标志为 true,表示任务开始执行
         if (!isRunning1.compareAndSet(false, true)) {
@@ -84,7 +84,7 @@ public class CourseWatchLogScheduler {
     /**
      * 创建完课消息
      */
-    @Scheduled(cron = "0 */5 * * * ?") // 每五分钟执行一次
+    @Scheduled(fixedRate = 300000) // 每五分钟执行一次
     public void createCourseFinishMsg() {
         // 尝试设置标志为 true,表示任务开始执行
         if (!isRunning3.compareAndSet(false, true)) {
@@ -101,7 +101,6 @@ public class CourseWatchLogScheduler {
         } finally {
             // 重置标志为 false,表示任务已完成
             isRunning3.set(false);
-
         }
 
     }
@@ -115,7 +114,7 @@ public class CourseWatchLogScheduler {
     /**
      * 每天删除过期短链
      */
-    @Scheduled(cron = "0 5 0 * * ?")  // 0点5分0秒执行
+    @Scheduled(cron = "0 0 0 * * ?")  // 0点0分0秒执行
     public void delCourseExpireLink() {
         try {
             log.info("删除过期短链 - 定时任务开始");
@@ -127,21 +126,26 @@ public class CourseWatchLogScheduler {
 
     }
 
-    /**
-     * 红包补发定时任务
-     */
-//    @Scheduled(cron = "0 */5 * * * ?")  //每5分钟执行一次
-//    public void redPacketRetry() {
-//        try {
-//            log.info("红包补发任务开始");
-//            redPacketRetryService.redPacketRetry();
-//            log.info("红包补发任务开始");
-//        } catch (Exception e) {
-//            log.error("红包补发 - 定时任务执行失败", e);
-//        }
-
-//    }
+    @Scheduled(fixedRate = 60000) // 每分钟执行一次
+    public void checkFsUserWatchStatus() {
+        // 尝试设置标志为 true,表示任务开始执行
+        if (!isRunning4.compareAndSet(false, true)) {
+            log.warn("WXH5-检查会员看课中任务执行 - 上一个任务尚未完成,跳过此次执行");
+            return;
+        }
+        try {
+            log.info("WXH5-检查会员看课中任务执行>>>>>>>>>>>>");
+            courseWatchLogService.scheduleUpdateDurationToDatabase();
+            courseWatchLogService.checkFsUserWatchStatus();
+            log.info("WXH5-检查会员看课中任务执行完成>>>>>>>>>>>>");
+        }catch (Exception e) {
+            log.error("WXH5-检查会员看课中任务执行完成 - 定时任务执行失败", e);
+        } finally {
+            // 重置标志为 false,表示任务已完成
+            isRunning4.set(false);
+        }
 
+    }
 
 
 

+ 37 - 0
fs-qw-task/src/main/java/com/fs/app/task/UserCourseWatchCountTask.java

@@ -0,0 +1,37 @@
+package com.fs.app.task;
+
+import com.fs.store.service.IFsUserCourseCountService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+@Component
+@Slf4j
+public class UserCourseWatchCountTask {
+    @Autowired
+    private IFsUserCourseCountService userCourseCountService;
+
+
+    /**
+     * 每天两点进行会员看课统计
+     */
+    @Scheduled(cron = "0 0 2 * * ?")  // 2点0分0秒执行
+    public void userCourseCountTask() {
+        try {
+            log.info("==============会员看课统计任务执行===============开始");
+            long startTime = System.currentTimeMillis();
+
+            userCourseCountService.insertFsUserCourseCountTask();
+
+            log.info("会员看课统计任务执行==============结束");
+            long endTime = System.currentTimeMillis();
+            log.info("会员看课统计任务执行----------执行时长:{}", (endTime - startTime));
+        } catch (Exception e) {
+            log.error("会员看课统计任务执行----------定时任务执行失败", e);
+        }
+
+    }
+
+
+}

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

@@ -889,7 +889,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                             createParam.setCompanyUserId(Long.parseLong(companyUserId));
                             createParam.setCompanyId(Long.parseLong(companyId));
                             createParam.setChatId(logVo.getChatId());
-                            createParam.setQwUserId(qwUserId);
+                            createParam.setQwUserId(Long.parseLong(qwUserId));
                             createParam.setDays(setting.getExpiresDays());
                             R createLink = courseLinkService.createRoomLinkUrl(createParam);
                             if (createLink.get("code").equals(500)) {
@@ -1016,7 +1016,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
         // 手动创建 FsCourseLink 对象,避免使用 BeanUtils.copyProperties
         FsCourseLink link = new FsCourseLink();
         link.setCompanyId(Long.parseLong(companyId));
-        link.setQwUserId(qwUserId);
+        link.setQwUserId(Long.parseLong(qwUserId));
         link.setCompanyUserId(Long.parseLong(companyUserId));
         link.setVideoId(videoId.longValue());
         link.setCorpId(logVo.getCorpId());
@@ -1174,7 +1174,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
         // 手动创建 FsCourseLink 对象,避免使用 BeanUtils.copyProperties
         FsCourseLink link = new FsCourseLink();
         link.setCompanyId(Long.parseLong(companyId));
-        link.setQwUserId(qwUserId);
+        link.setQwUserId(Long.parseLong(qwUserId));
         link.setCompanyUserId(Long.parseLong(companyUserId));
         link.setVideoId(videoId.longValue());
         link.setCorpId(corpId);
@@ -1230,7 +1230,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
         // 手动创建 FsCourseLink 对象,避免使用 BeanUtils.copyProperties
         FsCourseLink link = new FsCourseLink();
         link.setCompanyId(Long.parseLong(companyId));
-        link.setQwUserId(qwUserId);
+        link.setQwUserId(Long.parseLong(qwUserId));
         link.setCompanyUserId(Long.parseLong(companyUserId));
         link.setVideoId(videoId.longValue());
         link.setCorpId(logVo.getCorpId());
@@ -1293,7 +1293,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
         watchLog.setVideoId(videoId != null ? videoId.longValue() : null);
         watchLog.setQwExternalContactId(externalId != null ? Long.valueOf(externalId) : null);
         watchLog.setSendType(2);
-        watchLog.setQwUserId(qwUserId);
+        watchLog.setQwUserId(Long.parseLong(qwUserId));
         watchLog.setSopId(sopLogs.getSopId());
         watchLog.setDuration(0L);
         watchLog.setCourseId(courseId != null ? courseId.longValue() : null);

+ 1 - 20
fs-qwhook-sop/src/main/java/com/fs/app/controller/ApisFsUserCourseVideoController.java

@@ -54,25 +54,6 @@ public class ApisFsUserCourseVideoController extends BaseController {
 
 
 
-    @PostMapping("/pageList")
-    @ApiOperation("课程分页列表")
-    public R list(@RequestBody UserCourseVideoPageParam param) {
-
-        QwUser qwUser = qwExternalContactService.getQwUserByRedis(param.getCorpId().trim(), param.getQwUserId().trim());
-
-        if (qwUser == null || qwUser.getCompanyId() == null) {
-            return R.error("员工未绑定 销售公司 或 未获取到员工信息,请重试!");
-        }
-        param.setCompanyId(qwUser.getCompanyId());
-
-
-        PageHelper.startPage(param.getPageNum(), param.getPageSize());
-        List<FsUserCourseVideoPageListVO> list = fsUserCourseVideoService.pageListCourseVideo(param);
-        PageInfo<FsUserCourseVideoPageListVO> pageInfo = new PageInfo<>(list);
-        return R.ok().put("data",pageInfo);
-    }
-
-
     @ApiOperation("课程视频详情")
     @GetMapping(value = "/videoDetails")
     public R getVideoDetails(Long videoId) {
@@ -179,7 +160,7 @@ public class ApisFsUserCourseVideoController extends BaseController {
         createParam.setCorpId(param.getCorpId());
         createParam.setCompanyUserId(qwUser.getCompanyUserId());
         createParam.setCompanyId(qwUser.getCompanyId());
-        createParam.setQwUserId(qwUser.getId().toString());
+        createParam.setQwUserId(qwUser.getId());
         String linkUrl;
         R createLink = courseLinkService.createRoomLinkUrl(createParam);
         if (createLink.get("code").equals(500)){

+ 1 - 45
fs-qwhook-sop/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java

@@ -53,21 +53,6 @@ public class FsUserCourseVideoController {
     @Autowired
     private IQwExternalContactService qwExternalContactService;
 
-    @GetMapping("/pageList")
-    @ApiOperation("课程分页列表")
-    public ResponseResult<PageInfo<FsUserCourseVideoPageListVO>> list(UserCourseVideoPageParam param) {
-
-        QwUser qwUser = qwExternalContactService.getQwUserByRedis(param.getCorpId().trim(), param.getQwUserId().trim());
-
-        if (qwUser==null||qwUser.getCompanyId()==null){
-            return ResponseResult.fail(500,"无权限");
-        }
-        PageHelper.startPage(param.getPageNum(), param.getPageSize());
-        param.setCompanyId(qwUser.getCompanyId());
-        List<FsUserCourseVideoPageListVO> list = fsUserCourseVideoService.pageListCourseVideo(param);
-        PageInfo<FsUserCourseVideoPageListVO> pageInfo = new PageInfo<>(list);
-        return ResponseResult.ok(pageInfo);
-    }
 
     @ApiOperation("课程视频详情")
     @GetMapping(value = "/videoDetails")
@@ -75,35 +60,6 @@ public class FsUserCourseVideoController {
         return fsUserCourseVideoService.getVideoDetails(videoId);
     }
 
-    @GetMapping("/courseList")
-    @ApiOperation("获取课程下拉列表")
-    public ResponseResult<PageInfo<FsUserCourseListVO>> getAllCourseList(FsUserCourseListParam param) {
-        QwUser qwUser = qwUserService.getByQwUserIdAndCorId(param.getQwUserId(), param.getCorpId());
-        if (qwUser==null||qwUser.getCompanyId()==null){
-            return ResponseResult.fail(500,"无权限");
-        }
-        PageHelper.startPage(param.getPageNum(), param.getPageSize());
-        param.setCompanyId(qwUser.getCompanyId());
-        List<FsUserCourseListVO> fsUserCourseList = fsUserCourseService.getFsUserCourseList(param);
-        PageInfo<FsUserCourseListVO> pageInfo = new PageInfo<>(fsUserCourseList);
-        return ResponseResult.ok(pageInfo);
-    }
-
-    @GetMapping("/videoList")
-    @ApiOperation("获取视频下拉列表")
-    public ResponseResult<PageInfo<FsUserVideoListVO>> getAllVideoList(UserCourseVideoPageParam param) {
-        QwUser qwUser = qwUserService.getByQwUserIdAndCorId(param.getQwUserId(), param.getCorpId());
-        if (qwUser==null||qwUser.getCompanyId()==null){
-            return ResponseResult.fail(500,"无权限");
-        }
-        PageHelper.startPage(param.getPageNum(), param.getPageSize());
-        param.setCompanyId(qwUser.getCompanyId());
-        List<FsUserVideoListVO> listCourseVideo = fsUserCourseVideoService.getListCourseVideo(param);
-        PageInfo<FsUserVideoListVO> result = new PageInfo<>(listCourseVideo);
-        return ResponseResult.ok(result);
-    }
-
-
     @PostMapping("/getFsCourseListBySidebar")
     @ApiOperation("获取视频课程下拉列表 侧边栏")
     public R getFsCourseListBySidebar(@RequestBody FsCourseListBySidebarParam param) {
@@ -151,7 +107,7 @@ public class FsUserCourseVideoController {
         createParam.setCorpId(param.getCorpId());
         createParam.setCompanyUserId(qwUser.getCompanyUserId());
         createParam.setCompanyId(qwUser.getCompanyId());
-        createParam.setQwUserId(qwUser.getId().toString());
+        createParam.setQwUserId(qwUser.getId());
         String linkUrl;
         R createLink = courseLinkService.createRoomLinkUrl(createParam);
         if (createLink.get("code").equals(500)){

+ 2 - 21
fs-qwhook/src/main/java/com/fs/app/controller/ApisFsUserCourseVideoController.java

@@ -53,26 +53,6 @@ public class ApisFsUserCourseVideoController extends BaseController {
     private IFsCourseLinkService courseLinkService;
 
 
-
-    @PostMapping("/pageList")
-    @ApiOperation("课程分页列表")
-    public R list(@RequestBody UserCourseVideoPageParam param) {
-
-        QwUser qwUser = qwExternalContactService.getQwUserByRedis(param.getCorpId().trim(), param.getQwUserId().trim());
-
-        if (qwUser == null || qwUser.getCompanyId() == null) {
-            return R.error("员工未绑定 销售公司 或 未获取到员工信息,请重试!");
-        }
-        param.setCompanyId(qwUser.getCompanyId());
-
-
-        PageHelper.startPage(param.getPageNum(), param.getPageSize());
-        List<FsUserCourseVideoPageListVO> list = fsUserCourseVideoService.pageListCourseVideo(param);
-        PageInfo<FsUserCourseVideoPageListVO> pageInfo = new PageInfo<>(list);
-        return R.ok().put("data",pageInfo);
-    }
-
-
     @ApiOperation("课程视频详情")
     @GetMapping(value = "/videoDetails")
     public R getVideoDetails(Long videoId) {
@@ -164,6 +144,7 @@ public class ApisFsUserCourseVideoController extends BaseController {
         }
 
         return fsUserCourseVideoService.createCartLink(param);
+
     }
 
     @GetMapping("/createRoomLink")
@@ -179,7 +160,7 @@ public class ApisFsUserCourseVideoController extends BaseController {
         createParam.setCorpId(param.getCorpId());
         createParam.setCompanyUserId(qwUser.getCompanyUserId());
         createParam.setCompanyId(qwUser.getCompanyId());
-        createParam.setQwUserId(qwUser.getId().toString());
+        createParam.setQwUserId(qwUser.getId());
         String linkUrl;
         R createLink = courseLinkService.createRoomLinkUrl(createParam);
         if (createLink.get("code").equals(500)){

+ 63 - 42
fs-qwhook/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java

@@ -1,10 +1,12 @@
 package com.fs.app.controller;
 
 import com.alibaba.fastjson.JSONObject;
+import com.fs.common.annotation.RepeatSubmit;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.ResponseResult;
 import com.fs.course.domain.FsUserCourse;
 import com.fs.course.param.FsCourseLinkCreateParam;
+import com.fs.course.param.FsCourseLinkMiniParam;
 import com.fs.course.param.FsCourseLinkRoomParam;
 import com.fs.course.param.FsCourseListBySidebarParam;
 import com.fs.course.param.newfs.FsUserCourseListParam;
@@ -21,6 +23,7 @@ import com.fs.course.vo.newfs.FsUserVideoListVO;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.service.IQwExternalContactService;
 import com.fs.qw.service.IQwUserService;
+import com.fs.voice.utils.StringUtil;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.Api;
@@ -50,19 +53,6 @@ public class FsUserCourseVideoController {
     @Autowired
     private IQwExternalContactService qwExternalContactService;
 
-    @GetMapping("/pageList")
-    @ApiOperation("课程分页列表")
-    public ResponseResult<PageInfo<FsUserCourseVideoPageListVO>> list(UserCourseVideoPageParam param) {
-        QwUser qwUser = qwUserService.getByQwUserIdAndCorId(param.getQwUserId(), param.getCorpId());
-        if (qwUser==null||qwUser.getCompanyId()==null){
-            return ResponseResult.fail(500,"无权限");
-        }
-        PageHelper.startPage(param.getPageNum(), param.getPageSize());
-        param.setCompanyId(qwUser.getCompanyId());
-        List<FsUserCourseVideoPageListVO> list = fsUserCourseVideoService.pageListCourseVideo(param);
-        PageInfo<FsUserCourseVideoPageListVO> pageInfo = new PageInfo<>(list);
-        return ResponseResult.ok(pageInfo);
-    }
 
     @ApiOperation("课程视频详情")
     @GetMapping(value = "/videoDetails")
@@ -70,34 +60,6 @@ public class FsUserCourseVideoController {
         return fsUserCourseVideoService.getVideoDetails(videoId);
     }
 
-    @GetMapping("/courseList")
-    @ApiOperation("获取课程下拉列表")
-    public ResponseResult<PageInfo<FsUserCourseListVO>> getAllCourseList(FsUserCourseListParam param) {
-        QwUser qwUser = qwUserService.getByQwUserIdAndCorId(param.getQwUserId(), param.getCorpId());
-        if (qwUser==null||qwUser.getCompanyId()==null){
-            return ResponseResult.fail(500,"无权限");
-        }
-        PageHelper.startPage(param.getPageNum(), param.getPageSize());
-        param.setCompanyId(qwUser.getCompanyId());
-        List<FsUserCourseListVO> fsUserCourseList = fsUserCourseService.getFsUserCourseList(param);
-        PageInfo<FsUserCourseListVO> pageInfo = new PageInfo<>(fsUserCourseList);
-        return ResponseResult.ok(pageInfo);
-    }
-
-    @GetMapping("/videoList")
-    @ApiOperation("获取视频下拉列表")
-    public ResponseResult<PageInfo<FsUserVideoListVO>> getAllVideoList(UserCourseVideoPageParam param) {
-        QwUser qwUser = qwUserService.getByQwUserIdAndCorId(param.getQwUserId(), param.getCorpId());
-        if (qwUser==null||qwUser.getCompanyId()==null){
-            return ResponseResult.fail(500,"无权限");
-        }
-        PageHelper.startPage(param.getPageNum(), param.getPageSize());
-        param.setCompanyId(qwUser.getCompanyId());
-        List<FsUserVideoListVO> listCourseVideo = fsUserCourseVideoService.getListCourseVideo(param);
-        PageInfo<FsUserVideoListVO> result = new PageInfo<>(listCourseVideo);
-        return ResponseResult.ok(result);
-    }
-
 
     @PostMapping("/getFsCourseListBySidebar")
     @ApiOperation("获取视频课程下拉列表 侧边栏")
@@ -130,9 +92,68 @@ public class FsUserCourseVideoController {
         return R.ok().put("data", result);
     }
 
+
+
     @Autowired
     private IFsCourseLinkService courseLinkService;
 
+
+    /**
+     * 创建 发客户小程序
+     */
+
+    @RepeatSubmit
+    @PostMapping("/createMiniLink")
+    public R createMiniLink(@RequestBody FsCourseLinkMiniParam param) {
+
+        if (param.getCourseId()==null){
+            return R.error("课程id不能为空");
+        }
+        if (param.getVideoId()==null){
+            return R.error("视频id不能为空");
+        }
+        if (StringUtil.strIsNullOrEmpty(param.getQwUserId())){
+            return R.error("用户id不能为空");
+        }
+        if (StringUtil.strIsNullOrEmpty(param.getCorpId())){
+            return R.error("企业id不能为空");
+        }
+
+        if (param.getExternalUserId()==null){
+            return R.error("客户id不能为空");
+        }
+
+        return fsUserCourseVideoService.createMiniLink(param);
+    }
+
+    /**
+     * 创建发卡片
+     */
+    @RepeatSubmit
+    @PostMapping("/createCartLink")
+    public R createCartLink(@RequestBody  FsCourseLinkMiniParam param) {
+
+        if (param.getCourseId()==null){
+            return R.error("课程id不能为空");
+        }
+        if (param.getVideoId()==null){
+            return R.error("视频id不能为空");
+        }
+        if (StringUtil.strIsNullOrEmpty(param.getQwUserId())){
+            return R.error("用户id不能为空");
+        }
+        if (StringUtil.strIsNullOrEmpty(param.getCorpId())){
+            return R.error("企业id不能为空");
+        }
+
+        if (param.getExternalUserId()==null){
+            return R.error("客户id不能为空");
+        }
+
+        return fsUserCourseVideoService.createCartLink(param);
+
+    }
+
     @GetMapping("/createRoomLink")
     @ApiOperation("创建发群链接")
     public R createRoomLink(FsCourseLinkRoomParam param) {
@@ -146,7 +167,7 @@ public class FsUserCourseVideoController {
         createParam.setCorpId(param.getCorpId());
         createParam.setCompanyUserId(qwUser.getCompanyUserId());
         createParam.setCompanyId(qwUser.getCompanyId());
-        createParam.setQwUserId(qwUser.getId().toString());
+        createParam.setQwUserId(qwUser.getId());
         String linkUrl;
         R createLink = courseLinkService.createRoomLinkUrl(createParam);
         if (createLink.get("code").equals(500)){

+ 49 - 0
fs-service/src/main/java/com/fs/common/param/LoginMaWxParam.java

@@ -0,0 +1,49 @@
+package com.fs.common.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+@Data
+public class LoginMaWxParam implements Serializable {
+
+    @NotBlank(message = "code参数缺失")
+    @ApiModelProperty(value = "小程序登陆code")
+    private String code;
+
+    @ApiModelProperty(value = "小程序完整用户信息的加密数据")
+    private String encryptedData;
+
+    @ApiModelProperty(value = "小程序加密算法的初始向量")
+    private String iv;
+
+    @NotNull(message = "公司id不能为空")
+    @ApiModelProperty(value = "公司id")
+    private Long companyId;
+
+    @NotNull(message = "销售id不能为空")
+    @ApiModelProperty(value = "销售id")
+    private Long companyUserId;
+
+    @ApiModelProperty(value = "用户昵称")
+    private String nickname;
+
+    @ApiModelProperty(value = "用户头像")
+    private String avatar;
+
+//    @ApiModelProperty(value = "公司id,如果不是第一位销售,都需要传")
+//    private Long companyId;
+
+//    @ApiModelProperty(value = "电话号码")
+//    private String phoneNumber;
+
+//    @ApiModelProperty(value = "上级销售id,如果没有则不传")
+//    private Long parentCompanyUseId;
+//
+//    @ApiModelProperty(value = "用户密码")
+//    private String password;
+
+}

+ 4 - 2
fs-service/src/main/java/com/fs/company/cache/ICompanyTagCacheService.java

@@ -1,9 +1,11 @@
 package com.fs.company.cache;
 
+import com.fs.company.domain.CompanyTag;
+
 import java.util.Map;
 
 public interface ICompanyTagCacheService {
-    String findUserTagByUserId(Long userId);
+    String findUserTagByUserId(Long userId,Long companyUserId);
 
-    Map<Long, String> queryAllTagMap();
+    Map<Long, CompanyTag> queryAllTagMap();
 }

+ 33 - 5
fs-service/src/main/java/com/fs/company/cache/impl/CompanyTagCacheServiceImpl.java

@@ -1,13 +1,17 @@
 package com.fs.company.cache.impl;
 
 import com.fs.company.cache.ICompanyTagCacheService;
+import com.fs.company.domain.CompanyTag;
 import com.fs.company.service.ICompanyTagService;
 import com.github.benmanes.caffeine.cache.Cache;
 import com.github.benmanes.caffeine.cache.Caffeine;
+import lombok.Data;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.io.Serializable;
 import java.util.Map;
+import java.util.Objects;
 import java.util.concurrent.TimeUnit;
 
 @Service
@@ -15,22 +19,46 @@ public class CompanyTagCacheServiceImpl implements ICompanyTagCacheService {
 
     @Autowired
     private ICompanyTagService companyTagService;
-    private static final Cache<Long,String> COMPANY_TAG_CACHE = Caffeine.newBuilder()
+    private static final Cache<TagConbKey,String> COMPANY_TAG_CACHE = Caffeine.newBuilder()
             .maximumSize(1000)
             .expireAfterWrite(5, TimeUnit.MINUTES)
             .build();
 
-    private static final Cache<Long,Map<Long, String>> COMPANY_USER_TAG_CACHE = Caffeine.newBuilder()
+    private static final Cache<Long,Map<Long, CompanyTag>> COMPANY_USER_TAG_CACHE = Caffeine.newBuilder()
             .maximumSize(1000)
             .expireAfterWrite(5, TimeUnit.MINUTES)
             .build();
+
+
+    @Data
+    static class TagConbKey implements Serializable {
+        private Long userId;
+        private Long companyUserId;
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            TagConbKey that = (TagConbKey) o;
+            return Objects.equals(userId, that.userId) && Objects.equals(companyUserId, that.companyUserId);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(userId, companyUserId);
+        }
+    }
     @Override
-    public String findUserTagByUserId(Long key) {
-        return COMPANY_TAG_CACHE.get(key,e-> companyTagService.findUserTagByUserId(key));
+    public String findUserTagByUserId(Long userId,Long companyUserId) {
+        TagConbKey tagConbKey = new TagConbKey();
+        tagConbKey.setUserId(userId);
+        tagConbKey.setCompanyUserId(companyUserId);
+        return COMPANY_TAG_CACHE.get(tagConbKey,e->
+                companyTagService.findUserTagByUserId(tagConbKey.getUserId(),tagConbKey.getCompanyUserId()));
     }
 
     @Override
-    public Map<Long, String> queryAllTagMap() {
+    public Map<Long, CompanyTag> queryAllTagMap() {
         return COMPANY_USER_TAG_CACHE.get(0L, e-> companyTagService.queryAllTagMap());
     }
 }

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

@@ -110,6 +110,8 @@ public class Company extends BaseEntity
      * 点播配置-小程序appId
      */
     private String courseMiniAppId;
+    /** 会员是否默认黑名单,1-是;0-否(用于销售分享成为会员的操作) */
+    private Integer fsUserIsDefaultBlack;
 
 //    public String getDoctorIds() {
 //        return doctorIds;

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

@@ -1,5 +1,7 @@
 package com.fs.company.domain;
 
+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 org.apache.commons.lang3.builder.ToStringBuilder;

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

@@ -148,6 +148,29 @@ public class CompanyUser extends BaseEntity
     /** 是否审核 */
     private Integer isAudit;
 
+    /** 用户上级id */
+    private Long parentId;
+
+    /** 是否需要单独注册会员,1-是,0-否(用于个微销售分享看课) */
+    private Integer isNeedRegisterMember;
+
+
+    public Long getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(Long parentId) {
+        this.parentId = parentId;
+    }
+
+    public Integer getIsNeedRegisterMember() {
+        return isNeedRegisterMember;
+    }
+
+    public void setIsNeedRegisterMember(Integer isNeedRegisterMember) {
+        this.isNeedRegisterMember = isNeedRegisterMember;
+    }
+
     public String getDomain() {
         return domain;
     }

+ 9 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyPostMapper.java

@@ -74,4 +74,13 @@ public interface CompanyPostMapper
 
     @Select("select p.post_id, p.post_name from company_user_post up inner join company_post p on p.post_id=up.post_id where up.user_id = #{userId}")
     List<CompanyPost> selectCompanyPostByUserId(@Param("userId") Long userId);
+
+
+    /**
+     * 根据ID集合查询岗位列表
+     * @param postIds   id集合
+     * @return  list
+     */
+    List<CompanyPost> selectCompanyPostByIds(@Param("postIds") List<Long> postIds);
+
 }

+ 16 - 8
fs-service/src/main/java/com/fs/company/mapper/CompanyRoleMapper.java

@@ -1,20 +1,21 @@
 package com.fs.company.mapper;
 
 import com.fs.company.domain.CompanyRole;
+import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 
 /**
  * 角色信息Mapper接口
- * 
+ *
  * @author fs
  * @date 2021-05-25
  */
-public interface CompanyRoleMapper 
+public interface CompanyRoleMapper
 {
     /**
      * 查询角色信息
-     * 
+     *
      * @param roleId 角色信息ID
      * @return 角色信息
      */
@@ -22,7 +23,7 @@ public interface CompanyRoleMapper
 
     /**
      * 查询角色信息列表
-     * 
+     *
      * @param companyRole 角色信息
      * @return 角色信息集合
      */
@@ -30,7 +31,7 @@ public interface CompanyRoleMapper
 
     /**
      * 新增角色信息
-     * 
+     *
      * @param companyRole 角色信息
      * @return 结果
      */
@@ -38,7 +39,7 @@ public interface CompanyRoleMapper
 
     /**
      * 修改角色信息
-     * 
+     *
      * @param companyRole 角色信息
      * @return 结果
      */
@@ -46,7 +47,7 @@ public interface CompanyRoleMapper
 
     /**
      * 删除角色信息
-     * 
+     *
      * @param roleId 角色信息ID
      * @return 结果
      */
@@ -54,7 +55,7 @@ public interface CompanyRoleMapper
 
     /**
      * 批量删除角色信息
-     * 
+     *
      * @param roleIds 需要删除的数据ID
      * @return 结果
      */
@@ -69,4 +70,11 @@ public interface CompanyRoleMapper
     CompanyRole checkRoleKeyUnique(String roleKey);
 
     List<Integer> selectRoleListByUserId(Long userId);
+
+    /**
+     * 根据ID集合查询角色列表
+     * @param roleIds  ID集合
+     * @return  list
+     */
+    List<CompanyRole> selectRoleListByIds(@Param("roleIds") List<Long> roleIds);
 }

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

@@ -77,7 +77,7 @@ public interface CompanyTagMapper
      */
     List<CompanyTag> selectCompanyTagListByUserId(@Param("userId") Long userId);
 
-    String findUserTagByUserId(@Param("userId") Long userId);
+    String findUserTagByUserId(@Param("userId") Long userId,@Param("companyUserId") Long companyUserId);
     @MapKey("tag_id")
-    Map<Long,String> queryAllTagMap();
+    Map<Long,CompanyTag> queryAllTagMap();
 }

+ 1 - 23
fs-service/src/main/java/com/fs/company/mapper/CompanyUserMapper.java

@@ -92,29 +92,7 @@ public interface CompanyUserMapper
     int resetUserPwdByUserId( @Param("userId")Long userId, @Param("password") String encryptPassword);
 
     List<CompanyUser> selectAllUsersList(CompanyUser user);
-    @Select({"<script> " +
-            "select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark,u.open_id,u.id_card, d.dept_name, d.leader from company_user u\n" +
-            "        left join company_dept d on u.dept_id = d.dept_id\n" +
-            "        where u.del_flag = '0' and u.status=0\n" +
-            "        <if test=\"companyId != null  \">\n" +
-            "            AND u.company_id = #{companyId}\n" +
-            "        </if>\n" +
-            "        <if test=\"nickName != null and nickName != ''\">\n" +
-            "            AND u.nick_name like concat(#{nickName}, '%')\n" +
-            "        </if>\n" +
-            "        <if test=\"phonenumber != null and phonenumber != ''\">\n" +
-            "            AND u.phonenumber like concat('%', #{phonenumber}, '%')\n" +
-            "        </if>\n" +
-            "        <if test=\"beginTime != null and beginTime != ''\"><!-- 开始时间检索 -->\n" +
-            "            AND date_format(u.create_time,'%y%m%d') &gt;= date_format(#{beginTime},'%y%m%d')\n" +
-            "        </if>\n" +
-            "        <if test=\"endTime != null and endTime != ''\"><!-- 结束时间检索 -->\n" +
-            "            AND date_format(u.create_time,'%y%m%d') &lt;= date_format(#{endTime},'%y%m%d')\n" +
-            "        </if>\n" +
-            "        <if test=\"deptId != null and deptId != 0\">\n" +
-            "            AND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM company_dept t WHERE find_in_set(#{deptId}, ancestors) ))\n" +
-            "        </if>"+
-            "</script>"})
+
     List<CompanyUserVO> selectMyUserList(CompanyUser user);
     @Select("select u.* from company_user u where u.dept_id in ( SELECT dept_id FROM company_dept WHERE dept_id = #{maps.deptId} or find_in_set( #{maps.deptId} , ancestors ) ) ${maps.params.dataScope}")
     List<CompanyUser> getUserListByDeptId(@Param("maps") CompanyUser user);

+ 19 - 9
fs-service/src/main/java/com/fs/company/service/ICompanyPostService.java

@@ -6,15 +6,14 @@ import java.util.List;
 
 /**
  * 岗位信息Service接口
- * 
+ *
  * @author fs
  * @date 2021-05-25
  */
-public interface ICompanyPostService 
-{
+public interface ICompanyPostService {
     /**
      * 查询岗位信息
-     * 
+     *
      * @param postId 岗位信息ID
      * @return 岗位信息
      */
@@ -22,7 +21,7 @@ public interface ICompanyPostService
 
     /**
      * 查询岗位信息列表
-     * 
+     *
      * @param companyPost 岗位信息
      * @return 岗位信息集合
      */
@@ -30,7 +29,7 @@ public interface ICompanyPostService
 
     /**
      * 新增岗位信息
-     * 
+     *
      * @param companyPost 岗位信息
      * @return 结果
      */
@@ -38,7 +37,7 @@ public interface ICompanyPostService
 
     /**
      * 修改岗位信息
-     * 
+     *
      * @param companyPost 岗位信息
      * @return 结果
      */
@@ -46,7 +45,7 @@ public interface ICompanyPostService
 
     /**
      * 批量删除岗位信息
-     * 
+     *
      * @param postIds 需要删除的岗位信息ID
      * @return 结果
      */
@@ -54,7 +53,7 @@ public interface ICompanyPostService
 
     /**
      * 删除岗位信息信息
-     * 
+     *
      * @param postId 岗位信息ID
      * @return 结果
      */
@@ -67,4 +66,15 @@ public interface ICompanyPostService
     List<String> selectPostNameListByUserId(Long userId);
 
     List<CompanyPost> selectCompanyPostListByUserId(Long userId);
+
+
+    /**
+     * 根据id集合查询岗位列表
+     *
+     * @param postIds id集合
+     * @return list
+     */
+    List<CompanyPost> selectCompanyPostByIds(List<Long> postIds);
+
 }
+

+ 16 - 8
fs-service/src/main/java/com/fs/company/service/ICompanyRoleService.java

@@ -7,15 +7,15 @@ import java.util.List;
 
 /**
  * 角色信息Service接口
- * 
+ *
  * @author fs
  * @date 2021-05-25
  */
-public interface ICompanyRoleService 
+public interface ICompanyRoleService
 {
     /**
      * 查询角色信息
-     * 
+     *
      * @param roleId 角色信息ID
      * @return 角色信息
      */
@@ -23,7 +23,7 @@ public interface ICompanyRoleService
 
     /**
      * 查询角色信息列表
-     * 
+     *
      * @param companyRole 角色信息
      * @return 角色信息集合
      */
@@ -31,7 +31,7 @@ public interface ICompanyRoleService
 
     /**
      * 新增角色信息
-     * 
+     *
      * @param companyRole 角色信息
      * @return 结果
      */
@@ -39,7 +39,7 @@ public interface ICompanyRoleService
 
     /**
      * 修改角色信息
-     * 
+     *
      * @param companyRole 角色信息
      * @return 结果
      */
@@ -47,7 +47,7 @@ public interface ICompanyRoleService
 
     /**
      * 批量删除角色信息
-     * 
+     *
      * @param roleIds 需要删除的角色信息ID
      * @return 结果
      */
@@ -55,7 +55,7 @@ public interface ICompanyRoleService
 
     /**
      * 删除角色信息信息
-     * 
+     *
      * @param roleId 角色信息ID
      * @return 结果
      */
@@ -86,4 +86,12 @@ public interface ICompanyRoleService
     public int countUserRoleByRoleId(Long roleId);
 
     List<Integer> selectRoleListByUserId(Long userId);
+
+
+    /**
+     * 根据ID集合查询角色列表
+     * @param roleIds  ID集合
+     * @return  list
+     */
+    List<CompanyRole> selectCompanyRoleByIds(List<Long> roleIds);
 }

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

@@ -114,4 +114,6 @@ public interface ICompanyService
     public void subtractCompanyMoney(BigDecimal money, Long companyId);
 
     List<Long> selectCompanyIds();
+
+    void configUserCheck(Long companyId, Integer userIsDefaultBlack);
 }

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

@@ -74,7 +74,7 @@ public interface ICompanyTagService
      */
     List<CompanyTag> selectCompanyTagListByMap(Map<String, Object> params);
 
-    Map<Long,String> queryAllTagMap();
+    Map<Long,CompanyTag> queryAllTagMap();
 
-    String findUserTagByUserId(Long key);
+    String findUserTagByUserId(Long userId,Long companyUserId);
 }

+ 10 - 8
fs-service/src/main/java/com/fs/company/service/ICompanyUserPostService.java

@@ -6,15 +6,15 @@ import java.util.List;
 
 /**
  * 用户与岗位关联Service接口
- * 
+ *
  * @author fs
  * @date 2021-05-25
  */
-public interface ICompanyUserPostService 
+public interface ICompanyUserPostService
 {
     /**
      * 查询用户与岗位关联
-     * 
+     *
      * @param userId 用户与岗位关联ID
      * @return 用户与岗位关联
      */
@@ -22,7 +22,7 @@ public interface ICompanyUserPostService
 
     /**
      * 查询用户与岗位关联列表
-     * 
+     *
      * @param companyUserPost 用户与岗位关联
      * @return 用户与岗位关联集合
      */
@@ -30,7 +30,7 @@ public interface ICompanyUserPostService
 
     /**
      * 新增用户与岗位关联
-     * 
+     *
      * @param companyUserPost 用户与岗位关联
      * @return 结果
      */
@@ -38,7 +38,7 @@ public interface ICompanyUserPostService
 
     /**
      * 修改用户与岗位关联
-     * 
+     *
      * @param companyUserPost 用户与岗位关联
      * @return 结果
      */
@@ -46,7 +46,7 @@ public interface ICompanyUserPostService
 
     /**
      * 批量删除用户与岗位关联
-     * 
+     *
      * @param userIds 需要删除的用户与岗位关联ID
      * @return 结果
      */
@@ -54,9 +54,11 @@ public interface ICompanyUserPostService
 
     /**
      * 删除用户与岗位关联信息
-     * 
+     *
      * @param userId 用户与岗位关联ID
      * @return 结果
      */
     public int deleteCompanyUserPostById(Long userId);
+
+    void batchInsertCompanyUserPost(List<CompanyUserPost> collect);
 }

+ 10 - 8
fs-service/src/main/java/com/fs/company/service/ICompanyUserRoleService.java

@@ -6,15 +6,15 @@ import java.util.List;
 
 /**
  * 用户和角色关联Service接口
- * 
+ *
  * @author fs
  * @date 2021-05-25
  */
-public interface ICompanyUserRoleService 
+public interface ICompanyUserRoleService
 {
     /**
      * 查询用户和角色关联
-     * 
+     *
      * @param userId 用户和角色关联ID
      * @return 用户和角色关联
      */
@@ -22,7 +22,7 @@ public interface ICompanyUserRoleService
 
     /**
      * 查询用户和角色关联列表
-     * 
+     *
      * @param companyUserRole 用户和角色关联
      * @return 用户和角色关联集合
      */
@@ -30,7 +30,7 @@ public interface ICompanyUserRoleService
 
     /**
      * 新增用户和角色关联
-     * 
+     *
      * @param companyUserRole 用户和角色关联
      * @return 结果
      */
@@ -38,7 +38,7 @@ public interface ICompanyUserRoleService
 
     /**
      * 修改用户和角色关联
-     * 
+     *
      * @param companyUserRole 用户和角色关联
      * @return 结果
      */
@@ -46,7 +46,7 @@ public interface ICompanyUserRoleService
 
     /**
      * 批量删除用户和角色关联
-     * 
+     *
      * @param userIds 需要删除的用户和角色关联ID
      * @return 结果
      */
@@ -54,9 +54,11 @@ public interface ICompanyUserRoleService
 
     /**
      * 删除用户和角色关联信息
-     * 
+     *
      * @param userId 用户和角色关联ID
      * @return 结果
      */
     public int deleteCompanyUserRoleById(Long userId);
+
+    void batchInsertCompanyUserRole(List<CompanyUserRole> collect);
 }

+ 11 - 7
fs-service/src/main/java/com/fs/company/service/impl/CompanyPostServiceImpl.java

@@ -12,7 +12,7 @@ import java.util.List;
 
 /**
  * 岗位信息Service业务层处理
- * 
+ *
  * @author fs
  * @date 2021-05-25
  */
@@ -24,7 +24,7 @@ public class CompanyPostServiceImpl implements ICompanyPostService
 
     /**
      * 查询岗位信息
-     * 
+     *
      * @param postId 岗位信息ID
      * @return 岗位信息
      */
@@ -36,7 +36,7 @@ public class CompanyPostServiceImpl implements ICompanyPostService
 
     /**
      * 查询岗位信息列表
-     * 
+     *
      * @param companyPost 岗位信息
      * @return 岗位信息
      */
@@ -48,7 +48,7 @@ public class CompanyPostServiceImpl implements ICompanyPostService
 
     /**
      * 新增岗位信息
-     * 
+     *
      * @param companyPost 岗位信息
      * @return 结果
      */
@@ -61,7 +61,7 @@ public class CompanyPostServiceImpl implements ICompanyPostService
 
     /**
      * 修改岗位信息
-     * 
+     *
      * @param companyPost 岗位信息
      * @return 结果
      */
@@ -74,7 +74,7 @@ public class CompanyPostServiceImpl implements ICompanyPostService
 
     /**
      * 批量删除岗位信息
-     * 
+     *
      * @param postIds 需要删除的岗位信息ID
      * @return 结果
      */
@@ -86,7 +86,7 @@ public class CompanyPostServiceImpl implements ICompanyPostService
 
     /**
      * 删除岗位信息信息
-     * 
+     *
      * @param postId 岗位信息ID
      * @return 结果
      */
@@ -116,4 +116,8 @@ public class CompanyPostServiceImpl implements ICompanyPostService
         return companyPostMapper.selectCompanyPostByUserId(userId);
     }
 
+    @Override
+    public List<CompanyPost> selectCompanyPostByIds(List<Long> postIds) {
+        return companyPostMapper.selectCompanyPostByIds(postIds);
+    }
 }

+ 11 - 7
fs-service/src/main/java/com/fs/company/service/impl/CompanyRoleServiceImpl.java

@@ -20,7 +20,7 @@ import java.util.*;
 
 /**
  * 角色信息Service业务层处理
- * 
+ *
  * @author fs
  * @date 2021-05-25
  */
@@ -37,7 +37,7 @@ public class CompanyRoleServiceImpl implements ICompanyRoleService
     private CompanyUserRoleMapper userRoleMapper;
     /**
      * 查询角色信息
-     * 
+     *
      * @param roleId 角色信息ID
      * @return 角色信息
      */
@@ -49,7 +49,7 @@ public class CompanyRoleServiceImpl implements ICompanyRoleService
 
     /**
      * 查询角色信息列表
-     * 
+     *
      * @param companyRole 角色信息
      * @return 角色信息
      */
@@ -61,7 +61,7 @@ public class CompanyRoleServiceImpl implements ICompanyRoleService
 
     /**
      * 新增角色信息
-     * 
+     *
      * @param companyRole 角色信息
      * @return 结果
      */
@@ -74,7 +74,7 @@ public class CompanyRoleServiceImpl implements ICompanyRoleService
 
     /**
      * 修改角色信息
-     * 
+     *
      * @param companyRole 角色信息
      * @return 结果
      */
@@ -87,7 +87,7 @@ public class CompanyRoleServiceImpl implements ICompanyRoleService
 
     /**
      * 批量删除角色信息
-     * 
+     *
      * @param roleIds 需要删除的角色信息ID
      * @return 结果
      */
@@ -99,7 +99,7 @@ public class CompanyRoleServiceImpl implements ICompanyRoleService
 
     /**
      * 删除角色信息信息
-     * 
+     *
      * @param roleId 角色信息ID
      * @return 结果
      */
@@ -267,4 +267,8 @@ public class CompanyRoleServiceImpl implements ICompanyRoleService
         return companyRoleMapper.selectRoleListByUserId(userId);
     }
 
+    @Override
+    public List<CompanyRole> selectCompanyRoleByIds(List<Long> roleIds) {
+        return companyRoleMapper.selectRoleListByIds(roleIds);
+    }
 }

+ 9 - 0
fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java

@@ -160,6 +160,7 @@ public class CompanyServiceImpl implements ICompanyService
             user.setSex("0");
             user.setStatus("0");
             user.setIsDel(0);
+            user.setIsAudit(1);
             userMapper.insertCompanyUser(user);
             //添加用户角色表
             CompanyUserRole userRole=new CompanyUserRole();
@@ -579,4 +580,12 @@ public class CompanyServiceImpl implements ICompanyService
     }
 
 
+    @Override
+    public void configUserCheck(Long companyId, Integer userIsDefaultBlack) {
+        Company company = companyMapper.selectCompanyById(companyId);
+        if(company != null) {
+            company.setFsUserIsDefaultBlack(userIsDefaultBlack);
+            companyMapper.updateCompany(company);
+        }
+    }
 }

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

@@ -118,12 +118,12 @@ public class CompanyTagServiceImpl implements ICompanyTagService
     }
 
     @Override
-    public Map<Long, String> queryAllTagMap() {
+    public Map<Long, CompanyTag> queryAllTagMap() {
         return companyTagMapper.queryAllTagMap();
     }
 
     @Override
-    public String findUserTagByUserId(Long key) {
-        return companyTagMapper.findUserTagByUserId(key);
+    public String findUserTagByUserId(Long key,Long companyUserId) {
+        return companyTagMapper.findUserTagByUserId(key,companyUserId);
     }
 }

+ 12 - 7
fs-service/src/main/java/com/fs/company/service/impl/CompanyUserPostServiceImpl.java

@@ -10,7 +10,7 @@ import java.util.List;
 
 /**
  * 用户与岗位关联Service业务层处理
- * 
+ *
  * @author fs
  * @date 2021-05-25
  */
@@ -22,7 +22,7 @@ public class CompanyUserPostServiceImpl implements ICompanyUserPostService
 
     /**
      * 查询用户与岗位关联
-     * 
+     *
      * @param userId 用户与岗位关联ID
      * @return 用户与岗位关联
      */
@@ -34,7 +34,7 @@ public class CompanyUserPostServiceImpl implements ICompanyUserPostService
 
     /**
      * 查询用户与岗位关联列表
-     * 
+     *
      * @param companyUserPost 用户与岗位关联
      * @return 用户与岗位关联
      */
@@ -46,7 +46,7 @@ public class CompanyUserPostServiceImpl implements ICompanyUserPostService
 
     /**
      * 新增用户与岗位关联
-     * 
+     *
      * @param companyUserPost 用户与岗位关联
      * @return 结果
      */
@@ -58,7 +58,7 @@ public class CompanyUserPostServiceImpl implements ICompanyUserPostService
 
     /**
      * 修改用户与岗位关联
-     * 
+     *
      * @param companyUserPost 用户与岗位关联
      * @return 结果
      */
@@ -70,7 +70,7 @@ public class CompanyUserPostServiceImpl implements ICompanyUserPostService
 
     /**
      * 批量删除用户与岗位关联
-     * 
+     *
      * @param userIds 需要删除的用户与岗位关联ID
      * @return 结果
      */
@@ -82,7 +82,7 @@ public class CompanyUserPostServiceImpl implements ICompanyUserPostService
 
     /**
      * 删除用户与岗位关联信息
-     * 
+     *
      * @param userId 用户与岗位关联ID
      * @return 结果
      */
@@ -91,4 +91,9 @@ public class CompanyUserPostServiceImpl implements ICompanyUserPostService
     {
         return companyUserPostMapper.deleteCompanyUserPostById(userId);
     }
+
+    @Override
+    public void batchInsertCompanyUserPost(List<CompanyUserPost> companyUserPosts) {
+        companyUserPostMapper.batchUserPost(companyUserPosts);
+    }
 }

+ 13 - 7
fs-service/src/main/java/com/fs/company/service/impl/CompanyUserRoleServiceImpl.java

@@ -10,7 +10,7 @@ import java.util.List;
 
 /**
  * 用户和角色关联Service业务层处理
- * 
+ *
  * @author fs
  * @date 2021-05-25
  */
@@ -22,7 +22,7 @@ public class CompanyUserRoleServiceImpl implements ICompanyUserRoleService
 
     /**
      * 查询用户和角色关联
-     * 
+     *
      * @param userId 用户和角色关联ID
      * @return 用户和角色关联
      */
@@ -34,7 +34,7 @@ public class CompanyUserRoleServiceImpl implements ICompanyUserRoleService
 
     /**
      * 查询用户和角色关联列表
-     * 
+     *
      * @param companyUserRole 用户和角色关联
      * @return 用户和角色关联
      */
@@ -46,7 +46,7 @@ public class CompanyUserRoleServiceImpl implements ICompanyUserRoleService
 
     /**
      * 新增用户和角色关联
-     * 
+     *
      * @param companyUserRole 用户和角色关联
      * @return 结果
      */
@@ -58,7 +58,7 @@ public class CompanyUserRoleServiceImpl implements ICompanyUserRoleService
 
     /**
      * 修改用户和角色关联
-     * 
+     *
      * @param companyUserRole 用户和角色关联
      * @return 结果
      */
@@ -70,7 +70,7 @@ public class CompanyUserRoleServiceImpl implements ICompanyUserRoleService
 
     /**
      * 批量删除用户和角色关联
-     * 
+     *
      * @param userIds 需要删除的用户和角色关联ID
      * @return 结果
      */
@@ -82,7 +82,7 @@ public class CompanyUserRoleServiceImpl implements ICompanyUserRoleService
 
     /**
      * 删除用户和角色关联信息
-     * 
+     *
      * @param userId 用户和角色关联ID
      * @return 结果
      */
@@ -91,4 +91,10 @@ public class CompanyUserRoleServiceImpl implements ICompanyUserRoleService
     {
         return companyUserRoleMapper.deleteCompanyUserRoleById(userId);
     }
+
+
+    @Override
+    public void batchInsertCompanyUserRole(List<CompanyUserRole> collect) {
+        companyUserRoleMapper.batchUserRole(collect);
+    }
 }

+ 5 - 0
fs-service/src/main/java/com/fs/core/config/WxMaConfiguration.java

@@ -21,6 +21,7 @@ import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Configuration;
+import org.yaml.snakeyaml.events.Event;
 
 import javax.annotation.PostConstruct;
 import java.io.File;
@@ -49,6 +50,7 @@ public class WxMaConfiguration {
         if (StringUtil.isNotEmpty(config.getAppid())){
             c.add(config);
         }
+        String appid = config.getAppid();
 //        SysConfig sysConfig2 = sysConfigMapper.selectConfigByConfigKey("store.config");
 //        if (sysConfig2!=null&&sysConfig2.getConfigValue()!=null&&sysConfig2.getConfigValue()!="") {
 //            String configValue2 = sysConfig2.getConfigValue();
@@ -60,6 +62,9 @@ public class WxMaConfiguration {
         List<CourseMaConfig> courseMaConfigs = JSON.parseArray(sysConfig3.getConfigValue(), CourseMaConfig.class);
         if (courseMaConfigs!=null&& !courseMaConfigs.isEmpty()){
             for (CourseMaConfig courseMaConfig : courseMaConfigs) {
+                if (appid.equals(courseMaConfig.getAppid())) {
+                    continue;
+                }
                 WxMaConfig.Config wxMaConfig = new WxMaConfig.Config();
                 BeanUtils.copyProperties(courseMaConfig, wxMaConfig);
                 c.add(wxMaConfig);

+ 3 - 0
fs-service/src/main/java/com/fs/course/config/CourseConfig.java

@@ -33,6 +33,9 @@ public class CourseConfig implements Serializable {
     private Integer openCommentStatus; //开启评论/弹幕
     private Integer viewCommentNum; // 查看历史评论数量
 
+    private String companyUserQRCode;// 默认客服二维码图片
+    private String courseLogo;//课程Logo
+
 
     @Data
     public static class DisabledTimeVo{

+ 5 - 0
fs-service/src/main/java/com/fs/course/config/CourseMaConfig.java

@@ -35,4 +35,9 @@ public class CourseMaConfig {
      */
     private String msgDataFormat;
 
+    /**
+     * 类型 1小程序 2公众号
+     */
+    private String type;
+
 }

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

@@ -36,7 +36,7 @@ public class FsCourseLink extends BaseEntity
 
     /** 企微userId */
     @Excel(name = "企微userId")
-    private String qwUserId;
+    private Long qwUserId;
 
     /** 课节id */
     @Excel(name = "课节id")

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

@@ -15,7 +15,7 @@ public class FsCourseRealLink implements Serializable
 
     private Long companyUserId;
 
-    private String qwUserId;
+    private Long qwUserId;
 
 
     private Long videoId;

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

@@ -49,7 +49,7 @@ public class FsCourseWatchLog extends BaseEntity
 
     /** 分享人企微userId */
     @Excel(name = "分享人企微userId")
-    private String qwUserId;
+    private Long qwUserId;
 
     /** 销售id */
     @Excel(name = "销售id")

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

@@ -101,5 +101,7 @@ public class FsUserCoursePeriod
 
     @Excel(name = "开启评论或者弹幕,1-开启评论;2-开启弹幕;3-都关闭")
     private Integer openCommentStatus;
+    @Excel(name = "开启评论或者弹幕,1-开启评论;2-开启弹幕;3-都关闭")
+    private String courseLogo;
 
 }

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

@@ -103,9 +103,10 @@ public interface FsCourseRedPacketLogMapper
     List<FsCourseRedPacketLogListPVO> selectRedPacketLogListVO(@Param("maps") FsCourseRedPacketLogParam param);
 
     @Select({"<script> " +
-            "select l.*,v.title,u.nick_name as fsNickName,u.avatar as fsAvatar,u.phone,cu.nick_name company_user_name,c.company_name,qu.qw_user_name  from fs_course_red_packet_log l  \n" +
+            "select l.*,v.title,u.nick_name as fsNickName,u.avatar as fsAvatar,u.phone,cu.nick_name company_user_name,c.company_name,qu.qw_user_name,fuc.course_name,u.phone as phoneNumber   from fs_course_red_packet_log l  \n" +
             "left join fs_user_course_video v on v.video_id = l.video_id \n" +
             "left join fs_user u on u.user_id = l.user_id \n" +
+            "left join fs_user_course fuc on fuc.course_id = l.course_id \n" +
             "left join company_user cu on cu.user_id=l.company_user_id \n" +
             "left join company c on c.company_id=l.company_id \n" +
             "LEFT JOIN qw_user qu on qu.id= l.qw_user_id  " +
@@ -118,7 +119,7 @@ public interface FsCourseRedPacketLogMapper
             "<if test = ' maps.courseId !=null '> and l.course_id = #{maps.courseId} </if>" +
             "<if test = ' maps.videoId !=null '> and l.video_id = #{maps.videoId} </if>" +
             "<if test = ' maps.status !=null '> and l.status = #{maps.status} </if>" +
-            "<if test = ' maps.phone !=null '> and u.phone = #{maps.phone} </if>" +
+            "<if test = \"maps.phone !=null and maps.phone != '' \"> and u.phone = #{maps.phone} </if>" +
             "<if test = ' maps.qwUserId !=null '> and l.qw_user_id = #{maps.qwUserId} </if>" +
             "<if test=\"maps.sTime != null \">  and DATE(l.create_time) &gt;= DATE(#{maps.sTime})</if>\n" +
             "<if test=\"maps.eTime != null \">  and DATE(l.create_time) &lt;= DATE(#{maps.eTime})</if>\n" +

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

@@ -391,4 +391,9 @@ public interface FsCourseWatchLogMapper extends BaseMapper<FsCourseWatchLog> {
 
     @Select("select count(log_id) AS watchCount, count(case when log_type = 2 then log_id end) AS finishCount, sum(duration) AS watchTime from fs_course_watch_log where user_id = #{userId} and video_id = #{videoId}")
     Map<String, Object> selectSumByUserIdAndVideoId(@Param("userId") Long userId, @Param("videoId") Long videoId);
+
+    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")
+    FsCourseWatchLog getCourseWatchLogByUser(@Param("userId") Long userId, @Param("videoId") Long videoId);
 }

+ 11 - 12
fs-service/src/main/java/com/fs/course/mapper/FsUserCourseMapper.java

@@ -228,23 +228,22 @@ public interface FsUserCourseMapper
     List<FsUserCourse> selectFsUserCourseAllCourse();
 
     @Select({"<script> " +
-            "SELECT\n" +
-            "        c.*,\n" +
-            "        cc.cate_name,\n" +
-            "        ucc.cate_name AS sub_cate_name\n" +
+            "SELECT DISTINCT\n" +
+            "        fcp.period_id,\n" +
+            "        fcp.period_name\n" +
             "        FROM\n" +
-            "        fs_user_course c\n" +
-            "        LEFT JOIN fs_user_course_category cc ON c.cate_id = cc.cate_id\n" +
-            "        LEFT JOIN fs_user_course_category ucc ON ucc.cate_id = c.sub_cate_id\n" +
+            "        fs_user_course_period fcp\n" +
+            "        LEFT JOIN fs_user_course_period_days fcpd ON fcpd.period_id = fcp.period_id\n" +
+            "        LEFT JOIN fs_user_course c ON c.course_id = fcpd.course_id\n" +
             "        WHERE\n" +
             "        c.is_del = 0\n" +
-            "        AND FIND_IN_SET(#{companyId}, c.company_ids)\n" +
-            "<if test = ' keyword!=null and keyword != \"\" '> " +
-            "            AND c.course_name LIKE concat('%',#{keyword},'%'\n" +
+            "        AND FIND_IN_SET(#{companyId}, fcp.company_id)\n" +
+            "        <if test=\"keyword != null and keyword !='' \">\n" +
+            "            AND fcp.period_name LIKE concat('%',#{keyword},'%'\n" +
             "            )\n" +
-            "        </if>" +
+            "        </if>\n" +
             "        ORDER BY\n" +
-            "        c.course_id" +
+            "        fcp.create_time desc, fcp.period_status asc"+
             "</script>"})
     List<FsUserCourseListVO> getFsUserCourseList(FsUserCourseListParam param);
 

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

@@ -12,8 +12,8 @@ public class FsCourseLinkCreateParam {
 
     private Integer days;
 
-    private Long qwUserIdLong;
-    private String qwUserId;
+//    private Long qwUserIdLong;
+    private Long qwUserId;
 
     private String corpId;
 

+ 1 - 0
fs-service/src/main/java/com/fs/course/param/FsCourseLinkMiniParam.java

@@ -15,6 +15,7 @@ public class FsCourseLinkMiniParam {
 
     private String title;//视频标题
 
+    private Integer type;
     /**
     * 客户表的主键
     */

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

@@ -28,7 +28,7 @@ public class FsUserCourseVideoLinkParam implements Serializable {
     @ApiModelProperty(value = "营期课程ID")
     private Long id;
 
-//    @ApiModelProperty(value = "营期id")
-//    private Long periodId;
+    @ApiModelProperty(value = "营期id")
+    private Long periodId;
 
 }

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

@@ -78,4 +78,5 @@ public interface IFsCourseLinkService
 
     R createRoomLinkUrl(FsCourseLinkCreateParam param);
 
+    R getRealLinkH5(String link);
 }

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

@@ -64,7 +64,7 @@ public interface IFsCourseQuestionBankService
      */
     public int deleteFsCourseQuestionBankById(Long id);
 
-    R courseAnswer(FsCourseQuestionAnswerUParam param);
+    R courseAnswer(FsCourseQuestionAnswerUParam param,Boolean isH5User);
 
     /**
      * 题目导入

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

@@ -118,4 +118,7 @@ public interface IFsCourseWatchLogService extends IService<FsCourseWatchLog> {
      */
     int countByMap(Map<String, Object> params);
 
+    void scheduleUpdateDurationToDatabase();
+
+    void checkFsUserWatchStatus();
 }

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

@@ -13,6 +13,8 @@ import com.fs.course.vo.*;
 import com.fs.course.vo.newfs.FsUserCourseListVO;
 import com.fs.his.vo.OptionsVO;
 
+import javax.validation.constraints.NotNull;
+
 /**
  * 课程Service接口
  *
@@ -118,4 +120,6 @@ public interface IFsUserCourseService
     InputStream handleImage(String s, String path) throws IOException;
 
     String createCourseImageQR(String url, String backgroundImagePath, InputStream file, String outputFormat, String title, String duration) throws Exception;
+
+    String createUserImageQR(@NotNull(message = "链接不能为空") String realLink, String backgroundImagePath, InputStream inputStream, String png, @NotNull(message = "销售id不能为空") Long companyUserId) throws Exception;
 }

+ 61 - 10
fs-service/src/main/java/com/fs/course/service/impl/FsCourseLinkServiceImpl.java

@@ -203,15 +203,13 @@ public class FsCourseLinkServiceImpl implements IFsCourseLinkService
 
     @Override
     public R createRoomLinkUrl(FsCourseLinkCreateParam param) {
-        QwUser qwUser;
-        if(param.getQwUserIdLong() != null){
-            qwUser = qwUserMapper.selectById(param.getQwUserIdLong());
-        }else{
-            qwUser = qwUserMapper.selectOne(new QueryWrapper<QwUser>().eq("qw_user_id", param.getQwUserId()).eq("corp_id", param.getCorpId()));
-        }
-        if(qwUser == null){
-            return R.error("未找到企微账号");
-        }
+//        QwUser qwUser;
+//        if(param.getQwUserId() != null){
+//            qwUser = qwUserMapper.selectById(param.getQwUserIdLong());
+//        }
+//        if(qwUser == null){
+//            return R.error("未找到企微账号");
+//        }
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
         FsCourseLink link = new FsCourseLink();
@@ -313,7 +311,7 @@ public class FsCourseLinkServiceImpl implements IFsCourseLinkService
     }
 
 
-    public FsCourseLink createFsCourseLink(String corpId, Date sendTime,Long courseId,Long videoId, String qwUserId,
+    public FsCourseLink createFsCourseLink(String corpId, Date sendTime,Long courseId,Long videoId, Long qwUserId,
                                            Long companyUserId, Long companyId,Long externalId,Integer type){
         // 手动创建 FsCourseLink 对象,避免使用 BeanUtils.copyProperties
         FsCourseLink link = new FsCourseLink();
@@ -508,4 +506,57 @@ public class FsCourseLinkServiceImpl implements IFsCourseLinkService
         }
         return R.error("短链生成失败!");
     }
+
+    @Override
+    public R getRealLinkH5(String link) {
+        try {
+            // URL解码
+            String sLink = URLDecoder.decode(link, "UTF-8");
+
+            // 从数据库中查找短链对应的真实链接
+            FsCourseLink courseLink = fsCourseLinkMapper.selectFsCourseLinkByLink(sLink);
+            if (courseLink != null) {
+                // 获取当前时间
+                Date currentTime = new Date();
+                // 获取链接的更新时间(假设这个字段代表过期时间)
+                Date updateTime = courseLink.getUpdateTime();
+
+                // 判断是否过期
+                if (currentTime.after(updateTime)) {
+                    // 链接已过期
+                    log.info("链接已过期: {}", sLink);
+                    return R.error("链接已过期").put("realLink", sLink);
+                } else {
+                    // 链接仍然有效,返回真实链接
+                    if (courseLink.getRealLink() == null) {
+                        log.error("真实链接不存在, link: {}", sLink);
+                        return R.error("真实链接不存在").put("realLink", sLink);
+                    }
+                    log.info("链接仍然有效: {}", sLink);
+                    String json = configService.selectConfigByKey("h5.course.config");
+                    CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+                    String domainName = companyUserMapper.selectDomainByUserId(courseLink.getCompanyUserId());
+                    if (StringUtils.isEmpty(domainName)){
+                        domainName = config.getRealLinkDomainName();
+                    }
+                    String realLink = domainName+courseLink.getRealLink();
+                    String imgUrl = "";
+                    return R.ok().put("realLink",realLink ).put("config",config).put("headerImg",imgUrl);
+                }
+            } else {
+                // 链接不存在或解析失败
+                log.warn("URL解析错误或链接不存在: {}", sLink);
+                return R.error("URL 解析错误或链接不存在").put("realLink", sLink);
+            }
+
+        } catch (UnsupportedEncodingException e) {
+            // URL解码异常
+            log.error("URL 解码失败: {}", e.getMessage(), e);
+            return R.error("URL 解码失败").put("realLink", link);
+        } catch (Exception e) {
+            // 捕获其他异常并记录
+            log.error("发生未知错误: {}", e.getMessage(), e);
+            return R.error("发生未知错误,请稍后再试").put("realLink", link);
+        }
+    }
 }

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

@@ -136,7 +136,7 @@ public class FsCourseQuestionBankServiceImpl implements IFsCourseQuestionBankSer
 
     @Override
     @Transactional
-    public R courseAnswer(FsCourseQuestionAnswerUParam param) {
+    public R courseAnswer(FsCourseQuestionAnswerUParam param,Boolean isH5User) {
         //获取配置参数
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
@@ -159,7 +159,12 @@ public class FsCourseQuestionBankServiceImpl implements IFsCourseQuestionBankSer
             errorCount = courseAnswerLogsMapper.selectErrorCountByCourseVideo(param.getVideoId(), param.getUserId(),null);
 
         }else {
-            FsCourseWatchLog log = courseWatchLogMapper.getWatchCourseVideo(param.getUserId(),param.getVideoId(),param.getQwUserId(),param.getQwExternalId());
+            FsCourseWatchLog log;
+            if(isH5User){
+                log = courseWatchLogMapper.getWatchLogByFsUser(param.getVideoId(), param.getUserId(), param.getCompanyUserId());
+            } else {
+                log = courseWatchLogMapper.getWatchCourseVideo(param.getUserId(), param.getVideoId(), param.getQwUserId(), param.getQwExternalId());
+            }
             if (log==null){
                 return R.error("无记录");
             }

+ 131 - 3
fs-service/src/main/java/com/fs/course/service/impl/FsCourseWatchLogServiceImpl.java

@@ -348,6 +348,134 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
         return 0;
     }
 
+    @Override
+    public void scheduleUpdateDurationToDatabase() {
+        log.info("WXH5-开始更新会员看课时长,检查完课>>>>>>");
+        //读取所有的key
+        Collection<String> keys = redisCache.keys("h5wxuser:watch:duration:*");
+
+        //读取看课配置
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+
+        List<FsCourseWatchLog> logs = new ArrayList<>();
+        for (String key : keys) {
+            //取key中数据
+            String[] parts = key.split(":");
+            Long userId = Long.parseLong(parts[3]);
+            Long videoId = Long.parseLong(parts[4]);
+            Long companyUserId = Long.parseLong(parts[5]);
+            String durationStr = redisCache.getCacheObject(key);
+            if(durationStr==null){
+                log.error("key中数据为null:{}",key);
+                continue;  // 如果 Redis 中没有记录,跳过
+            }
+            Long duration = Long.valueOf(durationStr);
+
+            FsCourseWatchLog watchLog = new FsCourseWatchLog();
+            watchLog.setVideoId(videoId);
+            watchLog.setUserId(userId);
+            watchLog.setCompanyUserId(companyUserId);
+            watchLog.setDuration(duration);
+
+            //取对应视频的时长
+            Long videoDuration = getFsUserVideoDuration(videoId);
+            if (videoDuration != null && videoDuration != 0) {
+                //判断是否完课
+                long percentage = (duration * 100 / videoDuration);
+                if (percentage >= config.getAnswerRate()) {
+                    watchLog.setLogType(2); // 设置状态为“已完成”checkFsUserWatchStatus
+                    watchLog.setFinishTime(new Date());
+                    String heartbeatKey ="h5wxuser:watch:heartbeat:" + userId+ ":" + videoId + ":" + companyUserId;
+                    // 完课删除心跳记录
+                    redisCache.deleteObject(heartbeatKey);
+                    // 完课删除看课时长记录
+                    redisCache.deleteObject(key);
+                }
+            }
+            //集合中增加
+            logs.add(watchLog);
+        }
+        batchUpdateFsUserCourseWatchLog(logs,100);
+    }
+    public Long getFsUserVideoDuration(Long videoId){
+        //将视频时长也存到redis
+        String videoRedisKey = "h5wxuser:video:duration:" + videoId;
+        Long videoDuration = redisCache.getCacheObject(videoRedisKey);
+        if (videoDuration==null){
+            FsUserCourseVideo video = courseVideoMapper.selectFsUserCourseVideoByVideoId(videoId);
+            videoDuration=video.getDuration();
+            redisCache.setCacheObject(videoRedisKey,video.getDuration().toString());
+        }
+        return videoDuration;
+    }
+    @Override
+    public void checkFsUserWatchStatus() {
+        log.info("WXH5-开始更新会员看课中断记录>>>>>");
+        // 从 Redis 中获取所有正在看课的用户记录
+        Collection<String> keys = redisCache.keys("h5wxuser:watch:heartbeat:*");
+        LocalDateTime now = LocalDateTime.now();
+        List<FsCourseWatchLog> logs = new ArrayList<>();
+        for (String key : keys) {
+            FsCourseWatchLog watchLog = new FsCourseWatchLog();
+            String[] parts = key.split(":");
+            Long userId = Long.parseLong(parts[3]);
+            Long videoId = Long.parseLong(parts[4]);
+            Long companyUserId = Long.parseLong(parts[5]);
+            // 获取最后心跳时间
+            String lastHeartbeatStr = redisCache.getCacheObject(key);
+            if (lastHeartbeatStr == null) {
+                continue; // 如果 Redis 中没有记录,跳过
+            }
+            LocalDateTime lastHeartbeatTime = LocalDateTime.parse(lastHeartbeatStr);
+            Duration duration = Duration.between(lastHeartbeatTime, now);
+
+            watchLog.setVideoId(videoId);
+            watchLog.setUserId(userId);
+            watchLog.setCompanyUserId(companyUserId);
+            // 如果超过一分钟没有心跳,标记为“观看中断”
+            if (duration.getSeconds() >= 60) {
+                watchLog.setLogType(4);
+                // 从 Redis 中删除该记录
+                redisCache.deleteObject(key);
+            }else {
+                watchLog.setLogType(1);
+            }
+            logs.add(watchLog);
+        }
+        batchUpdateFsUserCourseWatchLog(logs,100);
+
+    }
+
+
+    public void batchUpdateFsUserCourseWatchLog(List<FsCourseWatchLog> logs, int batchSize) {
+        if (logs == null || logs.isEmpty()) {
+            log.info("待更新的日志列表为空,无需处理");
+            return;
+        }
+
+        // 记录总日志数量
+        log.info("开始批量更新日志,总日志数量: {}", logs.size());
+
+        // 分批处理
+        for (int i = 0; i < logs.size(); i += batchSize) {
+            int end = Math.min(i + batchSize, logs.size());
+            List<FsCourseWatchLog> batchList = logs.subList(i, end);
+
+            // 记录当前批次的数量
+            log.info("正在更新第 {} 批日志,数量: {}", (i / batchSize) + 1, batchList.size());
+
+            // 执行批量更新
+            fsCourseWatchLogMapper.batchUpdateFsUserWatchLog(batchList);
+
+            // 记录当前批次更新完成
+            log.info("第 {} 批日志更新完成,数量: {}", (i / batchSize) + 1, batchList.size());
+        }
+
+        // 记录全部更新完成
+        log.info("所有日志更新完成,总日志数量: {}", logs.size());
+    }
+
     @Override
     public FsCourseWatchLog getWatchCourseLogVideoBySop(Long videoId,String qwUserId,Long externalId )
     {
@@ -381,7 +509,7 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
     @Override
     public void testFinishMsg() {
         FsCourseWatchLog finishLog = fsCourseWatchLogMapper.selectFsCourseWatchLogByLogId(341170L);
-        QwUser qwUser = qwUserMapper.selectQwUserById(Long.parseLong(finishLog.getQwUserId()));
+        QwUser qwUser = qwUserMapper.selectQwUserById(finishLog.getQwUserId());
         QwExternalContact externalContact = qwExternalContactMapper.selectQwExternalContactById(finishLog.getQwExternalContactId());
         FsCourseFinishTemp finishTemp = fsCourseFinishTempMapper.selectFsCourseFinishTempByCompanyUserId(finishLog.getCompanyUserId(),finishLog.getVideoId());
         QwSopCourseFinishTempSetting setting = new QwSopCourseFinishTempSetting();
@@ -492,7 +620,7 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
 
             FsCourseWatchLog watchLog = new FsCourseWatchLog();
             watchLog.setVideoId(videoId);
-            watchLog.setQwUserId(qwUserId.toString());
+            watchLog.setQwUserId(qwUserId);
             watchLog.setQwExternalContactId(externalId);
             watchLog.setDuration(duration);
 
@@ -560,7 +688,7 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
             Duration duration = Duration.between(lastHeartbeatTime, now);
 
             watchLog.setVideoId(videoId);
-            watchLog.setQwUserId(qwUserId.toString());
+            watchLog.setQwUserId(qwUserId);
             watchLog.setQwExternalContactId(externalId);
             // 如果超过一分钟没有心跳,标记为“观看中断”
             if (duration.getSeconds() >= 60) {

+ 36 - 1
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseServiceImpl.java

@@ -17,6 +17,7 @@ import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.company.domain.CompanyTag;
+import com.fs.company.domain.CompanyUser;
 import com.fs.company.mapper.CompanyTagMapper;
 import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.course.config.CourseConfig;
@@ -487,7 +488,7 @@ public class FsUserCourseServiceImpl implements IFsUserCourseService
 
     @Override
     public R createCourseSortLink(FsCourseLinkCreateParam param) {
-        String json = configService.selectConfigByKey("h5.course.config");
+        String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
 
         //新增链接表信息
@@ -573,6 +574,40 @@ public class FsUserCourseServiceImpl implements IFsUserCourseService
         return convertToBase64(combined, outputFormat);
     }
 
+    @Override
+    public String createUserImageQR(String url, String backgroundImagePath, InputStream file, String outputFormat, Long companyUserId) throws Exception {
+        // 读取并缩放背景图片
+        BufferedImage backgroundImage = createScaledBackgroundImage(backgroundImagePath);
+        int scaledWidth = backgroundImage.getWidth();
+        int scaledHeight = backgroundImage.getHeight();
+
+        // 创建最终的合成图片,确保底部区域有足够空间
+        int bottomHeight = 200; // 增加底部区域高度,确保内容完全显示
+        int totalHeight = scaledHeight + bottomHeight;
+        BufferedImage combined = new BufferedImage(scaledWidth, totalHeight, BufferedImage.TYPE_INT_ARGB);
+        Graphics2D graphics = initializeGraphics(combined);
+
+        // 绘制背景和底部白色区域
+        graphics.drawImage(backgroundImage, 0, 0, null);
+        graphics.setColor(Color.WHITE);
+        graphics.fillRect(0, scaledHeight, scaledWidth, bottomHeight);
+
+        //获取销售名称
+        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(companyUserId);
+
+        // 绘制推荐区域(图片和文字)
+        drawRecommendationArea(graphics, file, scaledHeight, companyUser != null ? companyUser.getNickName(): "云联融智", "邀请您成为会员");
+
+        // 绘制二维码
+        drawQRCode(graphics, url, scaledWidth, totalHeight);
+
+        graphics.dispose();
+
+        // 转换为Base64
+        return convertToBase64(combined, outputFormat);
+    }
+
+
     private Graphics2D initializeGraphics(BufferedImage combined) {
         Graphics2D graphics = combined.createGraphics();
         graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

+ 160 - 61
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -11,6 +11,7 @@ import com.fs.common.BeanCopyUtils;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.ResponseResult;
 import com.fs.common.core.redis.RedisCache;
+import com.fs.common.enums.BizResponseEnum;
 import com.fs.common.exception.CustomException;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
@@ -71,6 +72,7 @@ import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.time.Instant;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
 import java.util.*;
@@ -402,10 +404,17 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         String msg = "<div style=\"color: red;margin-bottom: 15px;font-weight: bold;\">本课程为会员独享<br>请长按二维码</div>\n" +
                 "\t\t\t\t\t<div style=\"color: #999;font-size: 14px;font-weight: bold;\">添加伴学助手免费领取会员权限</div>";
         try {
-            new Thread(() -> rocketMQTemplate.syncSend("repeat-upload", JSON.toJSONString(RepeatUploadVo.builder().type(1).fsUserId(param.getUserId()).build()))).start();
+            new Thread(() -> {
+                try {
+                    rocketMQTemplate.syncSend("repeat-upload", JSON.toJSONString(RepeatUploadVo.builder().type(1).fsUserId(param.getUserId()).build()));
+                }catch (Exception e){
+                    logger.error("看课重粉提交mq失败", e);
+                }
+            }).start();
         }catch (Exception e){
             logger.error("看课重粉提交mq失败", e);
         }
+
         Integer isRoom = param.getIsRoom();
 
         // 处理逻辑
@@ -854,7 +863,13 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
         // 准备发送红包参数
         WxSendRedPacketParam packetParam = new WxSendRedPacketParam();
-        packetParam.setOpenId(getOpenId(user.getUserId(), param.getCompanyId(), param.getSource()));
+//        packetParam.setOpenId(getOpenId(user.getUserId(), param.getCompanyId(), param.getSource()));
+        packetParam.setOpenId(user.getMpOpenId());
+        // 来源是小程序切换openId
+        if (param.getSource() == 2) {
+            System.out.println("小程序id"+user.getCourseMaOpenId());
+            packetParam.setOpenId(user.getCourseMaOpenId());
+        }
         packetParam.setAmount(amount);
         packetParam.setSource(param.getSource());
         packetParam.setRedPacketMode(config.getRedPacketMode());
@@ -1065,64 +1080,102 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             return ResponseResult.fail(405,"当前销售不存在");
         }
 
-        //判断:1、如果没有绑定销售,就提示;
+        //判断:1、如果没有绑定销售,就返回给客服的微信图片;
         //2、如果只绑定了当前销售,需要添加看课记录(正常流程);
         //3、以上都不是,则标识重粉,需要加入关系表,并打上重粉标签
         if(fsUser.getCompanyUserId() == null) {
-            return ResponseResult.fail(503, "暂时未绑定销售,请联系管理员");
-        }
-        if(companyUser.getUserId().equals(fsUser.getCompanyUserId())){
-            //查询看课记录
-            FsCourseWatchLog log = new FsCourseWatchLog();
-            log.setUserId(param.getUserId());
-            log.setCompanyUserId(param.getCompanyUserId());
-            log.setVideoId(param.getVideoId());
-            List<FsCourseWatchLog> fsCourseWatchLogs = courseWatchLogMapper.selectFsCourseWatchLogList(log);
-
-            // 获取课程所属项目id
-            FsUserCourse fsUserCourse = fsUserCourseMapper.selectFsUserCourseByCourseId(param.getCourseId());
-            Long courseProject = null;
-            if(fsUserCourse != null){
-                courseProject = fsUserCourse.getProject();
-            }
-            //如果存在,则更新
-            if (fsCourseWatchLogs != null && !fsCourseWatchLogs.isEmpty()){
-                FsCourseWatchLog updateLog = new FsCourseWatchLog();
-                updateLog.setPeriodId(param.getPeriodId());
-                updateLog.setProject(courseProject);
-                updateLog.setUpdateTime(new Date());
-                courseWatchLogMapper.updateFsCourseWatchLog(updateLog);
-            } else {
-                //如果是会员,则需要添加看课记录
-                FsCourseWatchLog fsCourseWatchLog = new FsCourseWatchLog();
-                BeanUtils.copyProperties(param, fsCourseWatchLog);
-                fsCourseWatchLog.setSendType(1);
-                fsCourseWatchLog.setDuration(0L);
-                fsCourseWatchLog.setCreateTime(new Date());
-                fsCourseWatchLog.setLogType(1);
-                fsCourseWatchLog.setProject(courseProject);
-                courseWatchLogMapper.insertFsCourseWatchLog(fsCourseWatchLog);
+            return ResponseResult.fail(BizResponseEnum.DATA_NOT_EXIST, getCompanyUserQRCode(companyUser));
+        }
+
+        // 逻辑调整:如果会员已经绑定了销售,直接提示,不添加重粉数据了-2025年6月16日14点53分
+        if (fsUser.getCompanyUserId() != null && !param.getCompanyUserId().equals(fsUser.getCompanyUserId())){
+            return ResponseResult.fail(406,"该用户已成为其他销售会员");
+        }
+
+        // 如果开启了黑名单审核,需要提示
+        if(fsUser.getStatus() == 0) {
+//            return ResponseResult.fail(505, "管理开启了会员审核,请等待审核");
+            return ResponseResult.fail(BizResponseEnum.WAIT_APPROVAL,getCompanyUserQRCode(companyUser));
+        }
+
+        //查询看课记录
+//        FsCourseWatchLog watchCourseVideo = courseWatchLogMapper.getWatchCourseVideoByFsUser(param.getUserId(), param.getVideoId(), param.getCompanyUserId());
+        FsCourseWatchLog watchCourseVideo = courseWatchLogMapper.getCourseWatchLogByUser(param.getUserId(), param.getVideoId());
+        // 获取课程所属项目id
+        FsUserCourse fsUserCourse = fsUserCourseMapper.selectFsUserCourseByCourseId(param.getCourseId());
+        Long courseProject = null;
+        if(fsUserCourse != null){
+            courseProject = fsUserCourse.getProject();
+        }
+
+        //添加判断:该用户是否已经存在此课程的看课记录,并且看课记录的销售id不是传入的销售id
+        if(watchCourseVideo != null){
+            if(!watchCourseVideo.getCompanyUserId().equals(param.getCompanyUserId())) {
+                //提示
+                return ResponseResult.fail(504, "已看过其他销售分享的此课程,不能重复观看");
             }
+
+            FsCourseWatchLog updateLog = new FsCourseWatchLog();
+            updateLog.setPeriodId(param.getPeriodId());
+            updateLog.setProject(courseProject);
+            updateLog.setUpdateTime(new Date());
+            courseWatchLogMapper.updateFsCourseWatchLog(updateLog);
         } else {
-            FsUserCompanyUser fsUserCompanyUser = new FsUserCompanyUser();
+            FsCourseWatchLog fsCourseWatchLog = new FsCourseWatchLog();
+            BeanUtils.copyProperties(param, fsCourseWatchLog);
+            fsCourseWatchLog.setSendType(1);
+            fsCourseWatchLog.setDuration(0L);
+            fsCourseWatchLog.setCreateTime(new Date());
+            fsCourseWatchLog.setLogType(1);
+            fsCourseWatchLog.setProject(courseProject);
+            courseWatchLogMapper.insertFsCourseWatchLog(fsCourseWatchLog);
+        }
+
+        // 添加会员销售关系表数据
+        // 逻辑调整:如果会员已经绑定了销售,直接提示,不添加重粉数据了-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);
+        }
+
+//        // 如果重粉需要打上重粉标签
+//        if(1 == fsUserCompanyUser.getIsRepeatFans()){
+//            FsUserCourseBeMemberParam fsUserCourseBeMemberParam = new FsUserCourseBeMemberParam();
+//            fsUserCourseBeMemberParam.setUserId(param.getUserId());
+//            fsUserCourseBeMemberParam.setCompanyId(param.getCompanyId());
+//            fsUserCourseBeMemberParam.setCompanyUserId(param.getCompanyUserId());
+//            fsUserService.setRepeatFansTag(fsUserCourseBeMemberParam);
+//        }
+        return ResponseResult.ok(Boolean.TRUE);
+    }
+
+    // 添加关系表数据
+    public static FsUserCompanyUser getFsUserCompanyUser(FsUserCourseAddCompanyUserParam param, FsUser fsUser) {
+        FsUserCompanyUser fsUserCompanyUser = new FsUserCompanyUser();
+        // 判断是否绑定了销售,如果已绑定,则需要标识为重粉,且放黑名单
+        if (fsUser.getCompanyUserId() != null && !fsUser.getCompanyUserId().equals(param.getCompanyUserId())) {
             fsUserCompanyUser.setIsRepeatFans(1);
-            fsUserCompanyUser.setUserId(param.getUserId());
-            fsUserCompanyUser.setCompanyId(param.getCompanyId());
-            fsUserCompanyUser.setCompanyUserId(param.getCompanyUserId());
-            QueryWrapper<FsUserCompanyUser> queryWrapper = new QueryWrapper<FsUserCompanyUser>().eq("user_id", param.getUserId()).eq("company_user_id", param.getCompanyUserId());
-            Integer i = fsUserCompanyUserMapper.selectCount(queryWrapper);
-            if(i == 0) {
-                fsUserCompanyUserMapper.insertFsUserCompanyUser(fsUserCompanyUser);
-            }
+        } else {
+            fsUserCompanyUser.setIsRepeatFans(0);
+        }
+        fsUserCompanyUser.setUserId(param.getUserId());
+        fsUserCompanyUser.setCompanyId(param.getCompanyId());
+        fsUserCompanyUser.setCompanyUserId(param.getCompanyUserId());
+        return fsUserCompanyUser;
+    }
 
-            // 打上重粉标签
-            FsUserCourseBeMemberParam fsUserCourseBeMemberParam = new FsUserCourseBeMemberParam();
-            fsUserCourseBeMemberParam.setUserId(param.getUserId());
-            fsUserCourseBeMemberParam.setCompanyId(param.getCompanyId());
-            fsUserCourseBeMemberParam.setCompanyUserId(param.getCompanyUserId());
-            fsUserService.setRepeatFansTag(fsUserCourseBeMemberParam);
+    private String getCompanyUserQRCode(CompanyUser companyUser) {
+        String companyUserQRCode;
+        if(StringUtils.isNotEmpty(companyUser.getQrCodeWeixin())){
+            companyUserQRCode = companyUser.getQrCodeWeixin();
+        } else {
+            String json = configService.selectConfigByKey("course.config");
+            CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+            companyUserQRCode = config.getCompanyUserQRCode();
         }
-        return ResponseResult.ok(Boolean.TRUE);
+        return companyUserQRCode;
     }
 
     @Override
@@ -1146,8 +1199,17 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         ResponseResult<FsUserCourseVideoDetailsVO> videoDetails = this.getVideoDetails(param.getVideoId());
         FsUserCourseVideoDetailsVO courseVideoDetails = videoDetails.getData() != null ? videoDetails.getData() : null;
 
-        Long duration = 0L;
+        //课程logo
+        if (param.getPeriodId()!=null){
+            FsUserCoursePeriod fsUserCoursePeriod = fsUserCoursePeriodMapper.selectFsUserCoursePeriodById(param.getPeriodId());
+            if (fsUserCoursePeriod!=null){
+                config.setCourseLogo(fsUserCoursePeriod.getCourseLogo());
+            }
+        }
+
+        long duration = 0L;
         long tipsTime = 0L;
+        long tipsTime2 = 0L;
         int isFinish = 0;
         FsUserCourseVideoLinkDetailsVO vo = new FsUserCourseVideoLinkDetailsVO();
         vo.setCourseVideoDetails(courseVideoDetails);
@@ -1171,9 +1233,12 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             duration = Objects.isNull(watchLog) ? 0 : watchLog.getDuration();
         }
 //
-//        if (course.getDuration()!=null){
-//            tipsTime = course.getDuration()/2;
-//        }
+        if (courseVideoDetails != null && courseVideoDetails.getDuration() != null){
+            tipsTime = courseVideoDetails.getDuration() / 3;
+            tipsTime2 = (courseVideoDetails.getDuration() * 2) / 3;
+        }
+        vo.setTipsTime(tipsTime);
+        vo.setTipsTime2(tipsTime2);
         //判断是否完课
         if (watchLog!=null && watchLog.getLogType() == 2) {
             isFinish = 1;
@@ -1190,9 +1255,43 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         //判断营期的课程状态是否是进行中
         if(param.getId() != null){
             FsUserCoursePeriodDays days = fsUserCoursePeriodDaysMapper.selectById(param.getId());
-            vo.setStartDateTime(days.getStartDateTime());
-            vo.setEndDateTime(days.getEndDateTime());
-            vo.setRang(DateUtil.isWithinRangeSafe(LocalDateTime.now(), days.getStartDateTime(), days.getEndDateTime()) && days.getStatus() == 1);
+
+            // 查询销售设置的看课时间
+            LocalDateTime companyUserStartDateTime = null;
+            LocalDateTime companyUserEndDateTime = null;
+
+            List<CompanyUserTimeQueryParam> queryList = new ArrayList<>();
+            CompanyUserTimeQueryParam query = new CompanyUserTimeQueryParam();
+            query.setPeriodId(param.getPeriodId());
+            query.setCourseId(param.getCourseId());
+            query.setVideoId(param.getVideoId());
+            query.setCompanyUserId(param.getCompanyUserId());
+            queryList.add(query);
+            List<FsUserCourseCompanyUserTime> fsUserCourseCompanyUserTimes = companyUserTimeMapper.batchSelectByParams(queryList);
+
+            if(CollectionUtils.isNotEmpty(fsUserCourseCompanyUserTimes)){
+                FsUserCourseCompanyUserTime fsUserCourseCompanyUserTime = fsUserCourseCompanyUserTimes.get(0);
+                Date cuStartDateTime = fsUserCourseCompanyUserTime.getStartDateTime();
+                Date cuEndDateTime = fsUserCourseCompanyUserTime.getEndDateTime();
+
+                if(cuStartDateTime != null){
+                    Instant instant = cuStartDateTime.toInstant();
+                    ZoneId zoneId = ZoneId.systemDefault();
+                    companyUserStartDateTime = instant.atZone(zoneId).toLocalDateTime();
+                }
+
+                if(cuEndDateTime != null){
+                    Instant instant = cuEndDateTime.toInstant();
+                    ZoneId zoneId = ZoneId.systemDefault();
+                    companyUserEndDateTime = instant.atZone(zoneId).toLocalDateTime();
+                }
+            }
+            vo.setStartDateTime(companyUserStartDateTime != null ? companyUserStartDateTime : days.getStartDateTime());
+            vo.setEndDateTime(companyUserEndDateTime != null ? companyUserEndDateTime : days.getEndDateTime());
+            vo.setRang(DateUtil.isWithinRangeSafe(LocalDateTime.now(),
+                    companyUserStartDateTime != null ? companyUserStartDateTime : days.getStartDateTime(),
+                    companyUserEndDateTime != null ? companyUserEndDateTime : days.getEndDateTime())
+                    && days.getStatus() == 1);
         }
         return ResponseResult.ok(vo);
     }
@@ -1378,7 +1477,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             watchLog.setVideoId(videoId);
             watchLog.setQwExternalContactId(externalId);
             watchLog.setSendType(2);
-            watchLog.setQwUserId(String.valueOf(qwUser.getId()));
+            watchLog.setQwUserId(qwUser.getId());
             watchLog.setDuration(0L);
             watchLog.setCourseId(courseId);
             watchLog.setCompanyUserId(qwUser.getCompanyUserId());
@@ -1407,7 +1506,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
         FsCourseLink link = new FsCourseLink();
         link.setCompanyId(qwUser.getCompanyId());
-        link.setQwUserId(String.valueOf(qwUser.getId()));
+        link.setQwUserId(qwUser.getId());
         link.setCompanyUserId(qwUser.getCompanyUserId());
         link.setVideoId(videoId);
         link.setCorpId(qwUser.getCorpId());

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

@@ -28,4 +28,10 @@ public class FsUserCourseVideoLinkDetailsVO {
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private LocalDateTime endDateTime;
     private boolean isRang;
+
+    @ApiModelProperty(value = "视频提示时间-第一阶段")
+    private Long tipsTime;
+
+    @ApiModelProperty(value = "视频提示时间-第二阶段")
+    private Long tipsTime2;
 }

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

@@ -43,6 +43,18 @@ public class FsUserCourseVideoPageListVO extends BaseEntity {
     @ApiModelProperty(value = "创建时间")
     private Date createTime;
 
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty(value = "创建时间")
+    private Date startDateTime;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty(value = "创建时间")
+    private Date endDateTime;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty(value = "创建时间")
+    private Date lastJoinTime;
+
     @ApiModelProperty(value = "营期id")
     private Long periodId;
 

+ 4 - 4
fs-service/src/main/java/com/fs/fastGpt/service/impl/AiHookServiceImpl.java

@@ -772,7 +772,7 @@ public class AiHookServiceImpl implements AiHookService {
             if (fsCourseWatchLogVO!=null){
                 FsCourseLinkCreateParam param = new FsCourseLinkCreateParam();
                 param.setVideoId(fsCourseWatchLogVO.getVideoId());
-                param.setQwUserId(String.valueOf(user.getId()));
+                param.setQwUserId(user.getId());
                 param.setDays(1);
                 param.setCorpId(user.getCorpId());
                 param.setCourseId(fsCourseWatchLogVO.getCourseId());
@@ -803,7 +803,7 @@ public class AiHookServiceImpl implements AiHookService {
                     if (fsUserCourseVideo==null){
                         FsCourseLinkCreateParam param = new FsCourseLinkCreateParam();
                         param.setVideoId(fsUserCourseVideo.getVideoId());
-                        param.setQwUserId(String.valueOf(user.getId()));
+                        param.setQwUserId(user.getId());
                         param.setDays(1);
                         param.setCorpId(user.getCorpId());
                         param.setCourseId(fsUserCourseVideo.getCourseId());
@@ -1282,7 +1282,7 @@ public class AiHookServiceImpl implements AiHookService {
             if (fsCourseWatchLogVO!=null){
                 FsCourseLinkCreateParam param = new FsCourseLinkCreateParam();
                 param.setVideoId(fsCourseWatchLogVO.getVideoId());
-                param.setQwUserId(String.valueOf(user.getId()));
+                param.setQwUserId(user.getId());
                 param.setDays(1);
                 param.setCorpId(user.getCorpId());
                 param.setCourseId(fsCourseWatchLogVO.getCourseId());
@@ -1313,7 +1313,7 @@ public class AiHookServiceImpl implements AiHookService {
                     System.out.println("课程:"+fsUserCourseVideo);
                     FsCourseLinkCreateParam param = new FsCourseLinkCreateParam();
                     param.setVideoId(fsUserCourseVideo.getVideoId());
-                    param.setQwUserId(String.valueOf(user.getId()));
+                    param.setQwUserId(user.getId());
                     param.setDays(1);
                     param.setCorpId(user.getCorpId());
                     param.setCourseId(fsUserCourseVideo.getCourseId());

+ 4 - 4
fs-service/src/main/java/com/fs/fastGpt/service/impl/AiNewServiceImpl.java

@@ -534,7 +534,7 @@ public class AiNewServiceImpl implements AiNewService {
             if (fsCourseWatchLogVO!=null){
                 FsCourseLinkCreateParam param = new FsCourseLinkCreateParam();
                 param.setVideoId(fsCourseWatchLogVO.getVideoId());
-                param.setQwUserId(String.valueOf(user.getId()));
+                param.setQwUserId(user.getId());
                 param.setDays(1);
                 param.setCorpId(user.getCorpId());
                 param.setCourseId(fsCourseWatchLogVO.getCourseId());
@@ -565,7 +565,7 @@ public class AiNewServiceImpl implements AiNewService {
                     if (fsUserCourseVideo==null){
                         FsCourseLinkCreateParam param = new FsCourseLinkCreateParam();
                         param.setVideoId(fsUserCourseVideo.getVideoId());
-                        param.setQwUserId(String.valueOf(user.getId()));
+                        param.setQwUserId(user.getId());
                         param.setDays(1);
                         param.setCorpId(user.getCorpId());
                         param.setCourseId(fsUserCourseVideo.getCourseId());
@@ -1052,7 +1052,7 @@ public class AiNewServiceImpl implements AiNewService {
             if (fsCourseWatchLogVO!=null){
                 FsCourseLinkCreateParam param = new FsCourseLinkCreateParam();
                 param.setVideoId(fsCourseWatchLogVO.getVideoId());
-                param.setQwUserId(String.valueOf(user.getId()));
+                param.setQwUserId(user.getId());
                 param.setDays(1);
                 param.setCorpId(user.getCorpId());
                 param.setCourseId(fsCourseWatchLogVO.getCourseId());
@@ -1083,7 +1083,7 @@ public class AiNewServiceImpl implements AiNewService {
                     System.out.println("课程:"+fsUserCourseVideo);
                     FsCourseLinkCreateParam param = new FsCourseLinkCreateParam();
                     param.setVideoId(fsUserCourseVideo.getVideoId());
-                    param.setQwUserId(String.valueOf(user.getId()));
+                    param.setQwUserId(user.getId());
                     param.setDays(1);
                     param.setCorpId(user.getCorpId());
                     param.setCourseId(fsUserCourseVideo.getCourseId());

+ 4 - 4
fs-service/src/main/java/com/fs/fastGpt/service/impl/AiServiceImpl.java

@@ -511,7 +511,7 @@ public class AiServiceImpl implements AiService {
             if (fsCourseWatchLogVO!=null){
                 FsCourseLinkCreateParam param = new FsCourseLinkCreateParam();
                 param.setVideoId(fsCourseWatchLogVO.getVideoId());
-                param.setQwUserId(String.valueOf(user.getId()));
+                param.setQwUserId(user.getId());
                 param.setDays(1);
                 param.setCorpId(user.getCorpId());
                 param.setCourseId(fsCourseWatchLogVO.getCourseId());
@@ -542,7 +542,7 @@ public class AiServiceImpl implements AiService {
                     if (fsUserCourseVideo==null){
                         FsCourseLinkCreateParam param = new FsCourseLinkCreateParam();
                         param.setVideoId(fsUserCourseVideo.getVideoId());
-                        param.setQwUserId(String.valueOf(user.getId()));
+                        param.setQwUserId(user.getId());
                         param.setDays(1);
                         param.setCorpId(user.getCorpId());
                         param.setCourseId(fsUserCourseVideo.getCourseId());
@@ -1029,7 +1029,7 @@ public class AiServiceImpl implements AiService {
             if (fsCourseWatchLogVO!=null){
                 FsCourseLinkCreateParam param = new FsCourseLinkCreateParam();
                 param.setVideoId(fsCourseWatchLogVO.getVideoId());
-                param.setQwUserId(String.valueOf(user.getId()));
+                param.setQwUserId(user.getId());
                 param.setDays(1);
                 param.setCorpId(user.getCorpId());
                 param.setCourseId(fsCourseWatchLogVO.getCourseId());
@@ -1060,7 +1060,7 @@ public class AiServiceImpl implements AiService {
                     System.out.println("课程:"+fsUserCourseVideo);
                     FsCourseLinkCreateParam param = new FsCourseLinkCreateParam();
                     param.setVideoId(fsUserCourseVideo.getVideoId());
-                    param.setQwUserId(String.valueOf(user.getId()));
+                    param.setQwUserId(user.getId());
                     param.setDays(1);
                     param.setCorpId(user.getCorpId());
                     param.setCourseId(fsUserCourseVideo.getCourseId());

+ 44 - 4
fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java

@@ -14,7 +14,8 @@ import com.fs.qw.dto.FsUserTransferParamDTO;
 import com.fs.qw.param.QwFsUserParam;
 import com.fs.qw.vo.QwFsUserVO;
 import com.fs.store.param.h5.FsUserPageListParam;
-import com.fs.store.vo.h5.FsUserPageListVO;
+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;
@@ -240,8 +241,6 @@ public interface FsUserMapper
     @Select("select * from fs_user where phone=#{phone}")
     FsUser selectFsUserByMpOpenId(@Param("phone") String phone);
 
-    @Select("select * from fs_user where chhy_ma_open_id=#{openId}")
-    FsUser selectFsUserByChhyOpenId(String openId);
 
     List<FsCourseAnalysisCountVO> courseAnalysisWatchLog(CourseAnalysisParam param);
     List<FsCourseAnalysisCountVO> courseAnalysisRedPacketCount(CourseAnalysisParam param);
@@ -296,4 +295,45 @@ public interface FsUserMapper
     Map<String, Long> getUserVipCountByCompanyUserId(@Param("companyUserId") Long companyUserId);
 
     @Select("select * from fs_user where union_id=#{unionId}")
-    FsUser selectFsUserByUnionId(String unionId);}
+    FsUser selectFsUserByUnionId(String unionId);
+
+    List<UserListCountVO> getUserNumber(@Param("userId") Long userId);
+
+    int getRepeatUserNumber(@Param("userId") Long userId);
+
+    UserDetailsVO getCountWatchCourse(@Param("userId") Long userId, @Param("fsUserId") Long fsUserId, @Param("dateTag") String dateTag);
+
+    UserDetailsVO getCountAnswer(@Param("userId") Long userId, @Param("fsUserId") Long fsUserId, @Param("dateTag") String dateTag);
+
+    UserDetailsVO getCountRedPacket(@Param("userId") Long userId, @Param("fsUserId") Long fsUserId, @Param("dateTag") String dateTag);
+
+    FsUserSummaryCountVO countUserSummary(@Param("userId") Long userId);
+
+    List<FsUserSummaryCountTagVO> countTag(@Param("userId") Long userId);
+
+    Map<String, Long> countUserCourse(UserStatisticsCommonParam param);
+
+    Map<String, Long> countUserAnswer(UserStatisticsCommonParam param);
+
+    Map<String, Long> countCourseDetails(UserStatisticsCommonParam param);
+
+    List<FsUserRankingVO> countUserRankingByComplete(@Param("userId") Long userId, @Param("startTime") String startTime, @Param("endTime") String endTime, @Param("periodId") String periodId, @Param("videoId") String videoId, @Param("order") String order);
+
+    List<FsUserRankingVO> countUserRankingByRight(@Param("userId") Long userId, @Param("startTime") String startTime, @Param("endTime") String endTime, @Param("periodId") String periodId, @Param("videoId") String videoId, @Param("order") String order);
+
+    List<FsCourseRankingVO> countCourseRankingByComplete(@Param("userId") Long userId, @Param("startTime") String startTime, @Param("endTime") String endTime, @Param("periodId") String periodId, @Param("videoId") String videoId, @Param("order") String order);
+
+    List<FsCourseRankingVO> countCourseRankingByRight(@Param("userId") Long userId, @Param("startTime") String startTime, @Param("endTime") String endTime, @Param("periodId") String periodId, @Param("videoId") String videoId, @Param("order") String order);
+
+    Map<String, Object> countUserRedPacket(UserStatisticsCommonParam param);
+
+    List<FsCourseAnalysisCountVO> courseAnalysisCourseCount(CourseAnalysisParam param);
+
+    CompanyUserSummaryCountVO companyUserCount(@Param("companyUserId") String companyUserId);
+
+    CompanyUserSummaryCountVO newUserRedPacketCount(@Param("companyUserId") String companyUserId);
+
+
+    @Select("select * from fs_user where course_ma_open_id=#{openId}")
+    FsUser selectFsUserByCourseMaOpenId(String openId);
+}

+ 6 - 0
fs-service/src/main/java/com/fs/his/mapper/FsUserWxMapper.java

@@ -4,4 +4,10 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.fs.his.domain.FsUserWx;
 
 public interface FsUserWxMapper extends BaseMapper<FsUserWx> {
+
+    /**
+     * 根据FsUserId和AppId唯一键保存或更新
+     * @param wx    配置信息
+     */
+    void insertOrUpdateByUniqueKey(FsUserWx wx);
 }

+ 32 - 2
fs-service/src/main/java/com/fs/his/service/IFsUserService.java

@@ -5,8 +5,11 @@ import java.util.List;
 import java.util.Map;
 
 import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.ResponseResult;
 import com.fs.common.core.page.TableDataInfo;
+import com.fs.course.param.CourseAnalysisParam;
 import com.fs.course.param.newfs.FsUserCourseBeMemberParam;
+import com.fs.course.vo.newfs.FsCourseAnalysisVO;
 import com.fs.his.domain.FsUser;
 import com.fs.his.domain.FsUserAddress;
 import com.fs.his.param.FsUserParam;
@@ -18,9 +21,12 @@ import com.fs.qw.dto.FsUserTransferParamDTO;
 import com.fs.qw.param.QwFsUserParam;
 import com.fs.qw.vo.QwFsUserVO;
 import com.fs.store.param.h5.FsUserPageListParam;
-import com.fs.store.vo.h5.FsUserPageListVO;
+import com.fs.store.param.h5.UserStatisticsCommonParam;
+import com.fs.store.vo.h5.*;
 import com.github.pagehelper.PageInfo;
 
+import javax.validation.Valid;
+
 /**
  * 用户Service接口
  *
@@ -82,7 +88,7 @@ public interface IFsUserService
     FsUser selectFsUserByOpenId(String openId);
 
 
-    FsUser selectFsUserByChhyOpenId(String openId);
+    FsUser selectFsUserByCourseMaOpenId(String openId);
 
 
     FsUser selectFsUserByPhone(String phone);
@@ -141,4 +147,28 @@ public interface IFsUserService
     Map<String, Long> getUserVipCountByCompanyUserId(Long userId);
 
     FsUser selectFsUserByUnionId(String unionId);
+
+    UserListPageVO getUserNumber(Long l);
+
+    UserDetailsVO getUserDetails(Long l, Long userId, String dateTag);
+
+    Integer selectFsUserByUserIds(String[] ids, Long companyUserId);
+
+    FsUserSummaryCountVO userSummaryCount(Long userId);
+
+    FsUserStatisticsVO userStatistics(UserStatisticsCommonParam param);
+
+    FsUserStatisticsVO userStatisticsDetails(UserStatisticsCommonParam param);
+
+    List<FsUserRankingVO> userRanking(Long userId, String startTime, String endTime, String periodId, String videoId, String order, Integer type);
+
+    List<FsCourseRankingVO> courseRanking(Long userId, String startTime, String endTime, String courseId, String videoId, String order, Integer type);
+
+    List<FsUserGraphicStatisticsVO> graphicStatistics(UserStatisticsCommonParam param);
+
+    List<FsCourseAnalysisVO> courseAnalysis(CourseAnalysisParam param);
+
+    CompanyUserSummaryCountVO companyUserSummaryCount(Long userId, String companyUserId);
+
+    ResponseResult<Boolean> becomeMember(@Valid FsUserCourseBeMemberParam param);
 }

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

@@ -4,4 +4,10 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.fs.his.domain.FsUserWx;
 
 public interface IFsUserWxService extends IService<FsUserWx> {
+
+    /**
+     * 根据FsUserId和AppId唯一键保存或更新
+     * @param wx    配置信息
+     */
+    void saveOrUpdateByUniqueKey(FsUserWx wx);
 }

+ 14 - 1
fs-service/src/main/java/com/fs/his/service/impl/FsInquiryOrderServiceImpl.java

@@ -810,7 +810,20 @@ public class FsInquiryOrderServiceImpl implements IFsInquiryOrderService
                 String redisKey = String.valueOf(StrUtil.format("{}{}", FsConstants.REDIS_INQUIRY_ORDER_OUTTIME_UNRECEIVE, order.getOrderId()));
                 redisCache.setCacheObject(redisKey,order.getOrderId(),configDTO.getUnReceiveCancelTime(), TimeUnit.MINUTES);
             }
-            new Thread(() -> rocketMQTemplate.syncSend("repeat-upload", JSON.toJSONString(RepeatUploadVo.builder().type(2).fsUserId(order.getUserId()).build()))).start();
+            try {
+                new Thread(() -> {
+                    try {
+                        rocketMQTemplate.syncSend("repeat-upload", JSON.toJSONString(RepeatUploadVo.builder().type(2).fsUserId(order.getUserId()).build()));
+                    }catch (Exception e){
+                        logger.error("看课重粉提交mq失败", e);
+                    }
+                }).start();
+
+            }catch (Exception e){
+                logger.error("看课重粉提交mq失败", e);
+            }
+
+
             return R.ok();
         }catch (Exception e){
             TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

+ 1 - 1
fs-service/src/main/java/com/fs/his/service/impl/FsIntegralGoodsServiceImpl.java

@@ -191,7 +191,7 @@ public class FsIntegralGoodsServiceImpl implements IFsIntegralGoodsService
         List<FsIntegralGoods> stageGoods = selectRandomStageGoods(param);
 
         if (stageGoods.size()<3){
-            param.setMinPoints(currentStage);
+            param.setMinPoints(stageMaxPoints-5000);
             param.setMaxPoints(stageMaxPoints);
             stageGoods = selectRandomStageGoods(param);
         }

+ 6 - 1
fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java

@@ -533,7 +533,12 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
         TransferService transferService = wxPayService.getTransferService();
 
         TransferBatchesRequest request = new TransferBatchesRequest();
-        request.setAppid(config.getAppId());
+        if (param.getSource() == 2){
+            request.setAppid(config.getMiniappId());
+        }else {
+            request.setAppid(config.getAppId());
+        }
+
         String code = IdUtil.getSnowflake(0, 0).nextIdStr();
         request.setOutBatchNo("fsCourse" + code);
         request.setBatchRemark("课堂答题奖励");

+ 1 - 1
fs-service/src/main/java/com/fs/his/service/impl/FsUserInvitedServiceImpl.java

@@ -21,7 +21,7 @@ import com.fs.his.service.IFsAppVersionService;
 import com.fs.his.service.IFsUserIntegralLogsService;
 import com.fs.his.service.IFsUserInvitedService;
 import com.fs.his.service.IFsUserService;
-import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;

+ 341 - 13
fs-service/src/main/java/com/fs/his/service/impl/FsUserServiceImpl.java

@@ -2,28 +2,44 @@ package com.fs.his.service.impl;
 
 import java.lang.reflect.Field;
 import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.math.MathContext;
 import java.math.RoundingMode;
 import java.util.*;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.fs.common.constant.HttpStatus;
 import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.ResponseResult;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.DictUtils;
+import com.fs.common.utils.ParseUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.company.cache.ICompanyTagCacheService;
 import com.fs.company.cache.ICompanyUserCacheService;
+import com.fs.company.domain.Company;
 import com.fs.company.domain.CompanyTag;
 import com.fs.company.domain.CompanyTagUser;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.mapper.CompanyMapper;
 import com.fs.company.mapper.CompanyTagMapper;
 import com.fs.company.mapper.CompanyTagUserMapper;
+import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.company.service.ICompanyTagService;
 import com.fs.course.domain.FsUserCompanyUser;
 import com.fs.course.mapper.FsUserCompanyUserMapper;
+import com.fs.course.mapper.FsUserCourseVideoMapper;
+import com.fs.course.param.CourseAnalysisParam;
 import com.fs.course.param.newfs.FsUserCourseBeMemberParam;
+import com.fs.course.param.newfs.UserCourseVideoPageParam;
+import com.fs.course.vo.newfs.FsCourseAnalysisCountVO;
+import com.fs.course.vo.newfs.FsCourseAnalysisVO;
+import com.fs.course.vo.newfs.FsUserCourseVideoPageListVO;
 import com.fs.his.config.IntegralConfig;
 import com.fs.his.domain.FsUserAddress;
 import com.fs.his.domain.FsUserIntegralLogs;
@@ -39,11 +55,13 @@ import com.fs.qw.param.QwFsUserParam;
 import com.fs.qw.vo.QwFsUserVO;
 import com.fs.store.domain.FsUserCourseCount;
 import com.fs.store.param.h5.FsUserPageListParam;
+import com.fs.store.param.h5.UserStatisticsCommonParam;
 import com.fs.store.service.cache.IFsUserCourseCountCacheService;
-import com.fs.store.vo.h5.FsUserPageListVO;
+import com.fs.store.vo.h5.*;
 import com.fs.system.service.ISysConfigService;
 import com.fs.watch.domain.WatchUser;
 import com.fs.watch.service.WatchUserService;
+import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.http.util.Asserts;
@@ -72,8 +90,14 @@ public class FsUserServiceImpl implements IFsUserService
     @Autowired
     private FsUserMapper fsUserMapper;
     @Autowired
+    private CompanyUserMapper companyUserMapper;
+    @Autowired
+    private CompanyMapper companyMapper;
+    @Autowired
     private FsUserAddressMapper fsUserAddressMapper;
     @Autowired
+    private FsUserCourseVideoMapper userCourseVideoMapper;
+    @Autowired
     private FsStoreOrderMapper fsStoreOrderMapper;
     @Autowired
     private FsFollowMapper fsFollowMapper;
@@ -207,8 +231,8 @@ public class FsUserServiceImpl implements IFsUserService
     }
 
     @Override
-    public FsUser selectFsUserByChhyOpenId(String openId) {
-        return fsUserMapper.selectFsUserByChhyOpenId(openId);
+    public FsUser selectFsUserByCourseMaOpenId(String openId) {
+        return fsUserMapper.selectFsUserByCourseMaOpenId(openId);
     }
 
     @Override
@@ -566,6 +590,7 @@ public class FsUserServiceImpl implements IFsUserService
         }
 
         List<FsUserPageListVO> fsUserPageListVOS = fsUserMapper.selectFsUserPageListNew(param);
+        Map<Long, CompanyTag> tagMap = companyTagCacheService.queryAllTagMap();
         for (FsUserPageListVO item : fsUserPageListVOS) {
             if(item.getCompanyUserId() != null) {
                 String companyUserName = companyUserCacheService.selectCompanyUserNameUserById(item.getCompanyUserId());
@@ -573,6 +598,15 @@ public class FsUserServiceImpl implements IFsUserService
                     item.setCompanyUserNickName(companyUserName);
                 }
             }
+            if(item.getPhone() != null) {
+                item.setPhone(ParseUtils.parsePhone(item.getPhone()));
+            }
+            if(item.getStatus() != null) {
+                String userStatus = DictUtils.getDictLabel("user_status", String.valueOf(item.getStatus()));
+                if(StringUtils.isNotBlank(userStatus)){
+                    item.setStatusText(userStatus);
+                }
+            }
             if(item.getUserId() != null) {
                 FsUserCourseCount byUserId = fsUserCourseCountCacheService.findByUserId(item.getUserId());
                 if(byUserId != null) {
@@ -586,17 +620,18 @@ public class FsUserServiceImpl implements IFsUserService
                     item.setStopWatchDays(byUserId.getStopWatchDays());
                     item.setCompleteWatchDate(byUserId.getCompleteWatchDate());
                 }
-
-                String userTagByUserId = companyTagCacheService.findUserTagByUserId(item.getUserId());
+                String userTagByUserId = companyTagCacheService
+                        .findUserTagByUserId(item.getUserId(),item.getCompanyUserId());
                 if(StringUtils.isNotEmpty(userTagByUserId)) {
                     String[] split = userTagByUserId.split(",");
-                    Map<Long, String> tagMap = companyTagCacheService.queryAllTagMap();
                     Set<String> tagNames = new HashSet<>();
                     for (String tag : split) {
-                        if(tag != null) {
+                        if(StringUtils.isNotBlank(tag)) {
                             Long tagL = Long.parseLong(tag);
-                            String tagName = tagMap.get(tagL);
-                            tagNames.add(tagName);
+                            CompanyTag companyTag = tagMap.get(tagL);
+                            if(companyTag != null) {
+                                tagNames.add(companyTag.getTag());
+                            }
                         }
                     }
                     item.setTagIds(userTagByUserId);
@@ -604,10 +639,10 @@ public class FsUserServiceImpl implements IFsUserService
                 }
 
                 // 是否宠粉
-                Integer isRepeat = qwExternalContactCacheService.selectQwIsRepeat(item.getUserId());
-                if(isRepeat != null) {
-                    item.setIsRepeat(isRepeat);
-                }
+//                Integer isRepeat = qwExternalContactCacheService.selectQwIsRepeat(item.getUserId());
+//                if(isRepeat != null) {
+//                    item.setIsRepeat(isRepeat);
+//                }
             }
         }
 
@@ -639,4 +674,297 @@ public class FsUserServiceImpl implements IFsUserService
         return fsUserMapper.selectFsUserByUnionId(unionId);
     }
 
+    @Override
+    public UserListPageVO getUserNumber(Long userId) {
+        List<UserListCountVO> list = fsUserMapper.getUserNumber(userId);
+        Map<String, Integer> map = list.stream()
+                .collect(Collectors.toMap(UserListCountVO::getStatus, UserListCountVO::getNum, (v1, v2) -> v1));
+        UserListPageVO pageVO = new UserListPageVO();
+        Integer normalNum = map.getOrDefault("1", 0);
+        Integer blackNum = map.getOrDefault("0", 0);
+
+        // 黑名单人数加上重粉的数量,正常人数去掉重粉数量
+        int repeatUserNumber = fsUserMapper.getRepeatUserNumber(userId);
+        pageVO.setNumber(normalNum - repeatUserNumber);
+        pageVO.setBlackNum(blackNum + repeatUserNumber);
+
+        return pageVO;
+    }
+
+    @Override
+    public UserDetailsVO getUserDetails(Long userId, Long fsUserId, String dateTag) {
+        UserDetailsVO countWatchCourse = fsUserMapper.getCountWatchCourse(userId, fsUserId, dateTag);
+        UserDetailsVO countAnswer = fsUserMapper.getCountAnswer(userId, fsUserId, dateTag);
+        UserDetailsVO countRedPacket = fsUserMapper.getCountRedPacket(userId, fsUserId, dateTag);
+        UserDetailsVO vo = new UserDetailsVO();
+        if (countWatchCourse != null){
+            BeanUtils.copyProperties(countWatchCourse, vo);
+        }
+        if (countRedPacket != null) {
+            vo.setAnswerRedPacketTime(countRedPacket.getAnswerRedPacketTime());
+            vo.setAnswerRedPacketAmount(countRedPacket.getAnswerRedPacketAmount());
+        }
+        if (countAnswer != null) {
+            vo.setAnswerTime(countAnswer.getAnswerTime());
+            vo.setAnswerRightTime(countAnswer.getAnswerRightTime());
+        }
+        return vo;
+    }
+
+    @Override
+    public Integer selectFsUserByUserIds(String[] userIds, Long companyUserId) {
+        return fsUserMapper.selectFsUserByUserIds(userIds, companyUserId);
+    }
+
+    @Override
+    public FsUserSummaryCountVO userSummaryCount(Long userId) {
+        FsUserSummaryCountVO fsUserSummaryCountVO = fsUserMapper.countUserSummary(userId);
+        List<FsUserSummaryCountTagVO> countTagList = fsUserMapper.countTag(userId);
+        fsUserSummaryCountVO.setTagList(countTagList);
+        return fsUserSummaryCountVO;
+    }
+
+    @Override
+    public FsUserStatisticsVO userStatistics(UserStatisticsCommonParam param) {
+        return getUserStatistics(param);
+    }
+
+    @Override
+    public FsUserStatisticsVO userStatisticsDetails(UserStatisticsCommonParam param) {
+        FsUserStatisticsVO userStatisticsVO = getUserStatistics(param);
+
+        //统计课程数据详情,在查询统计详情的时候需要显示
+        Map<String, Long> courseDetailsMap = fsUserMapper.countCourseDetails(param);
+        if(courseDetailsMap != null && courseDetailsMap.get("courseNum") != null && courseDetailsMap.get("videoNum") != null && courseDetailsMap.get("courseUserNum") != null){
+            userStatisticsVO.setCourseNum(Integer.parseInt(courseDetailsMap.get("courseNum").toString()))
+                    .setVideoNum(Integer.parseInt(courseDetailsMap.get("videoNum").toString()))
+                    .setCourseUserNum(Integer.parseInt(courseDetailsMap.get("courseUserNum").toString()));
+        }
+        return userStatisticsVO;
+    }
+
+    @Override
+    public List<FsUserRankingVO> userRanking(Long userId, String startTime, String endTime, String periodId, String videoId, String order, Integer type) {
+        List<FsUserRankingVO> listVO = Collections.emptyList();
+        if(type == 1){
+            //按完播率
+            listVO = fsUserMapper.countUserRankingByComplete(userId, startTime, endTime, periodId, videoId, order);
+        }
+        if(type == 2){
+            //按正确率
+            listVO = fsUserMapper.countUserRankingByRight(userId, startTime, endTime, periodId, videoId, order);
+        }
+        return listVO;
+    }
+
+    @Override
+    public List<FsCourseRankingVO> courseRanking(Long userId, String startTime, String endTime, String periodId, String videoId, String order, Integer type) {
+        List<FsCourseRankingVO> list = Collections.emptyList();
+        if(type == 1){
+            list = fsUserMapper.countCourseRankingByComplete(userId, startTime, endTime, periodId, videoId, order);
+        }
+        if(type == 2){
+            list = fsUserMapper.countCourseRankingByRight(userId, startTime, endTime, periodId, videoId, order);
+        }
+
+        return list;
+    }
+
+    @Override
+    public List<FsUserGraphicStatisticsVO> graphicStatistics(UserStatisticsCommonParam param) {
+        FsUserStatisticsVO userStatistics = getUserStatistics(param);
+        List<FsUserGraphicStatisticsVO> list = new ArrayList<>();
+        list.add(new FsUserGraphicStatisticsVO("观看人数",userStatistics.getCourseWatchNum(), userStatistics.getCourseWatchNum()));
+        list.add(new FsUserGraphicStatisticsVO("完播人数", userStatistics.getCourseCompleteNum(), userStatistics.getCourseCompleteNum()));
+        list.add(new FsUserGraphicStatisticsVO("答题人数", userStatistics.getAnswerNum(), userStatistics.getAnswerNum()));
+        list.add(new FsUserGraphicStatisticsVO("正确人数", userStatistics.getAnswerRightNum(), userStatistics.getAnswerRightNum()));
+        list.add(new FsUserGraphicStatisticsVO("答题红包数", userStatistics.getRedPacketNum(), userStatistics.getRedPacketNum()));
+        list.sort(Comparator.comparingInt(FsUserGraphicStatisticsVO::getValue).reversed());
+        return list;
+    }
+
+    @Override
+    public List<FsCourseAnalysisVO> courseAnalysis(CourseAnalysisParam param) {
+        //1、查询课程视频信息
+        UserCourseVideoPageParam userCourseVideoPageParam = new UserCourseVideoPageParam();
+        BeanUtils.copyProperties(param, userCourseVideoPageParam);
+        List<FsUserCourseVideoPageListVO> videoList = userCourseVideoMapper.selectFsUserCourseVideoPageList(userCourseVideoPageParam);
+
+        //2、查询统计
+        List<FsCourseAnalysisCountVO> courseCountList = fsUserMapper.courseAnalysisCourseCount(param);
+
+        List<FsCourseAnalysisCountVO> redPacketCountList = fsUserMapper.courseAnalysisRedPacketCount(param);
+        List<FsCourseAnalysisCountVO> answerCountList = fsUserMapper.courseAnalysisAnswerCount(param);
+
+        //3、转化为map
+        Map<Long, FsCourseAnalysisCountVO> courseMap = courseCountList.stream()
+                .collect(Collectors.toMap(
+                        FsCourseAnalysisCountVO::getVideoId,
+                        Function.identity()
+                ));
+        Map<Long, FsCourseAnalysisCountVO> redPacketMap = redPacketCountList.stream()
+                .collect(Collectors.toMap(
+                        FsCourseAnalysisCountVO::getVideoId,
+                        Function.identity()
+                ));
+        Map<Long, FsCourseAnalysisCountVO> answerMap = answerCountList.stream()
+                .collect(Collectors.toMap(
+                        FsCourseAnalysisCountVO::getVideoId,
+                        Function.identity()
+                ));
+
+        //4、处理数据
+        return videoList.stream().map(v -> {
+            FsCourseAnalysisVO allVO = new FsCourseAnalysisVO();
+            BeanUtils.copyProperties(v, allVO);
+
+            FsCourseAnalysisCountVO countVO = new FsCourseAnalysisCountVO();
+            FsCourseAnalysisCountVO courseVO = courseMap.getOrDefault(v.getVideoId(), countVO);
+            FsCourseAnalysisCountVO redPacketVO = redPacketMap.getOrDefault(v.getVideoId(), countVO);
+            FsCourseAnalysisCountVO answerVO = answerMap.getOrDefault(v.getVideoId(), countVO);
+            //单独赋值
+            countVO.setVideoId(v.getVideoId()).setCourseWatchNum(courseVO.getCourseWatchNum()).setCourseCompleteNum(courseVO.getCourseWatchNum())
+                    .setCompleteRate(courseVO.getCompleteRate() != null ? courseVO.getCompleteRate() : new BigDecimal(BigInteger.ZERO));
+            countVO.setRedPacketNum(redPacketVO.getRedPacketNum())
+                    .setRedPacketAmount(redPacketVO.getRedPacketAmount() != null ? redPacketVO.getRedPacketAmount() : new BigDecimal(BigInteger.ZERO));
+            countVO.setAnswerNum(answerVO.getAnswerNum()).setAnswerRightNum(answerVO.getAnswerRightNum())
+                    .setAnswerRightRate(answerVO.getAnswerRightRate()!=null ? answerVO.getAnswerRightRate() : new BigDecimal(BigInteger.ZERO));
+            allVO.setCountVO(countVO);
+            return allVO;
+        }).collect(Collectors.toList());
+    }
+
+    @Override
+    public CompanyUserSummaryCountVO companyUserSummaryCount(Long userId, String companyUserId) {
+        CompanyUserSummaryCountVO companyUserCount = fsUserMapper.companyUserCount(companyUserId);
+        CompanyUserSummaryCountVO newUserRedPacketCount = fsUserMapper.newUserRedPacketCount(companyUserId);
+        CompanyUserSummaryCountVO vo = new CompanyUserSummaryCountVO();
+        BeanUtils.copyProperties(companyUserCount, vo);
+        vo.setUserRedPacketNum(newUserRedPacketCount.getUserRedPacketNum());
+        vo.setTodayUserRedPacketAmount(newUserRedPacketCount.getTodayUserRedPacketAmount());
+        return vo;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public ResponseResult<Boolean> becomeMember(FsUserCourseBeMemberParam param) {
+        //查询用户
+        FsUser fsUser = fsUserMapper.selectFsUserById(param.getUserId());
+        if (Objects.isNull(fsUser)){
+            return ResponseResult.fail(404,"当前用户信息不存在");
+        }
+
+        //判断该销售是否存在
+        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(param.getCompanyUserId());
+        if (Objects.isNull(companyUser)){
+            return ResponseResult.fail(405,"销售不存在");
+        }
+
+        // 判断是否绑定了销售
+        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(fsUser.getCompanyUserId() == null) {
+            fsUser.setCompanyId(param.getCompanyId());
+            fsUser.setCompanyUserId(param.getCompanyUserId());
+        }
+        // 特殊(需求设计:需要根据公司是否开启黑名单来设置会员初始化的状态)
+        Company company = null;
+        if(param.getCompanyId() != null) {
+            company = companyMapper.selectCompanyById(param.getCompanyId());
+        }
+        // isDefaultBlack 值为1 ,表示需要加入小黑屋,否则不加
+        int isDefaultBlack = company != null ? company.getFsUserIsDefaultBlack() : 0;
+        fsUser.setStatus(isDefaultBlack == 1 ? 0 : 1);
+        fsUserMapper.updateFsUser(fsUser);
+
+        // 不为空则添加新标签
+        if (Objects.nonNull(param.getTagIds()) && param.getTagIds().length > 0) {
+            //关联会员标签,先删除再新增
+            Map<String, Object> map = new HashMap<>();
+            map.put("userId", param.getUserId());
+            map.put("companyId", fsUser.getCompanyId());
+            map.put("companyUserId", fsUser.getCompanyUserId());
+            companyTagUserMapper.deleteCompanyTagUserByMap(map);
+
+            CompanyTagUser companyTagUser = new CompanyTagUser();
+            companyTagUser.setUserId(param.getUserId());
+            companyTagUser.setCompanyId(fsUser.getCompanyId());
+            companyTagUser.setCompanyUserId(fsUser.getCompanyUserId());
+            companyTagUser.setTagIds(String.join(",", param.getTagIds()));
+            companyTagUser.setCreateTime(new Date());
+            companyTagUserMapper.insertCompanyTagUser(companyTagUser);
+        }
+
+        // 如果是重粉,直接打上重粉的标签
+        if(1 == fsUserCompanyUser.getIsRepeatFans()){
+            this.setRepeatFansTag(param);
+        }
+
+        //如果是设置了需要进入小黑屋,则需要返回提示,否则正常返回
+        if(isDefaultBlack == 1){
+            return ResponseResult.fail(402, "已成功注册,待管理审核");
+        }
+        return ResponseResult.ok(Boolean.TRUE);
+    }
+
+
+    private FsUserStatisticsVO getUserStatistics(UserStatisticsCommonParam param) {
+        FsUserStatisticsVO fsUserStatisticsVO = new FsUserStatisticsVO();
+
+        // 获取课程统计
+        Map<String, Long> couserMap = fsUserMapper.countUserCourse(param);
+        if (couserMap != null) {
+            fsUserStatisticsVO.setCourseWatchNum(couserMap.get("courseWatchNum").intValue()).setCourseCompleteNum(couserMap.get("courseCompleteNum").intValue());
+
+            if (couserMap.get("courseCompleteNum") != null && couserMap.get("courseWatchNum") > 0) {
+                int courseCompleteRate = BigDecimal.valueOf(couserMap.get("courseCompleteNum"))
+                        .divide(BigDecimal.valueOf(couserMap.get("courseWatchNum")), 2, RoundingMode.HALF_UP)
+                        .multiply(BigDecimal.valueOf(100))
+                        .intValue();
+                fsUserStatisticsVO.setCourseCompleteRate(courseCompleteRate);
+            }
+        }
+
+        // 获取答题统计
+        Map<String, Long> answerMap = fsUserMapper.countUserAnswer(param);
+        if (answerMap != null) {
+            fsUserStatisticsVO.setAnswerNum(answerMap.get("answerNum").intValue()).setAnswerRightNum(answerMap.get("answerRightNum").intValue());
+
+            if (answerMap.get("answerRightNum") != null && answerMap.get("answerNum") > 0) {
+                int answerCompleteRate = BigDecimal.valueOf(answerMap.get("answerRightNum"))
+                        .divide(BigDecimal.valueOf(answerMap.get("answerNum")), 2, RoundingMode.HALF_UP)
+                        .multiply(BigDecimal.valueOf(100))
+                        .intValue();
+                fsUserStatisticsVO.setAnswerRightRate(answerCompleteRate);
+            }
+        }
+
+        // 获取红包统计
+        Map<String, Object> redPacketMap = fsUserMapper.countUserRedPacket(param);
+        if(redPacketMap != null && redPacketMap.get("redPacketNum") != null && redPacketMap.get("redPacketAmount") != null) {
+            fsUserStatisticsVO.setRedPacketNum(Integer.parseInt(redPacketMap.get("redPacketNum").toString()))
+                    .setRedPacketAmount(new BigDecimal(redPacketMap.get("redPacketAmount").toString()));
+        }
+        return fsUserStatisticsVO;
+    }
+    private static FsUserCompanyUser getFsUserCompanyUser(FsUserCourseBeMemberParam param, FsUser fsUser) {
+        FsUserCompanyUser fsUserCompanyUser = new FsUserCompanyUser();
+        // 判断是否绑定了销售,如果已绑定,则需要标识为重粉,且放黑名单
+        if (fsUser.getCompanyUserId() != null && !fsUser.getCompanyUserId().equals(param.getCompanyUserId())) {
+            fsUserCompanyUser.setIsRepeatFans(1);
+        } else {
+            fsUserCompanyUser.setIsRepeatFans(0);
+        }
+        fsUserCompanyUser.setUserId(param.getUserId());
+        fsUserCompanyUser.setCompanyId(param.getCompanyId());
+        fsUserCompanyUser.setCompanyUserId(param.getCompanyUserId());
+        return fsUserCompanyUser;
+    }
+
 }

+ 9 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsUserWxServiceImpl.java

@@ -10,4 +10,13 @@ import org.springframework.stereotype.Service;
 @Service
 @Slf4j
 public class FsUserWxServiceImpl extends ServiceImpl<FsUserWxMapper, FsUserWx> implements IFsUserWxService {
+
+    /**
+     * 根据FsUserId和AppId唯一键保存或更新
+     * @param wx    配置信息
+     */
+    @Override
+    public void saveOrUpdateByUniqueKey(FsUserWx wx) {
+        baseMapper.insertOrUpdateByUniqueKey(wx);
+    }
 }

+ 2 - 2
fs-service/src/main/java/com/fs/qw/service/impl/QwContactWayServiceImpl.java

@@ -445,7 +445,7 @@ public class QwContactWayServiceImpl implements IQwContactWayService
                 try {
                     FsCourseLinkCreateParam param = new FsCourseLinkCreateParam();
                     param.setVideoId(Long.valueOf(att.getLink().getVideoId()));
-                    param.setQwUserId(String.valueOf(qwUser.getId()));
+                    param.setQwUserId(qwUser.getId());
                     param.setDays(att.getLink().getExpiresDays());
                     param.setCorpId(corpId);
                     param.setCourseId(Long.valueOf(att.getLink().getCourseId()));
@@ -485,7 +485,7 @@ public class QwContactWayServiceImpl implements IQwContactWayService
         watchLog.setVideoId(videoId != null ? videoId.longValue() : null);
         watchLog.setQwExternalContactId(externalId != null ? Long.valueOf(externalId) : null);
         watchLog.setSendType(2);
-        watchLog.setQwUserId(qwUserId);
+        watchLog.setQwUserId(Long.valueOf(qwUserId));
         watchLog.setSopId(null);
         watchLog.setCourseId(courseId != null ? courseId.longValue() : null);
         watchLog.setCompanyUserId(companyUserId != null ? Long.valueOf(companyUserId) : null);

+ 4 - 4
fs-service/src/main/java/com/fs/qw/service/impl/QwExternalContactServiceImpl.java

@@ -1710,10 +1710,10 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
             new Thread(() -> {
                 try {
                     Thread.sleep(3000);
+                    rocketMQTemplate.syncSend("repeat-upload", JSON.toJSONString(RepeatUploadVo.builder().type(0).externalUserId(externalUserID).build()));
                 } catch (InterruptedException e) {
                     logger.error("添加等待时长错误", e);
                 }
-                rocketMQTemplate.syncSend("repeat-upload", JSON.toJSONString(RepeatUploadVo.builder().type(0).externalUserId(externalUserID).build()));
             }).start();
         }catch (Exception e){
             logger.error("重粉提交mq失败", e);
@@ -3127,7 +3127,7 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
                 try {
                     FsCourseLinkCreateParam param = new FsCourseLinkCreateParam();
                     param.setVideoId(Long.valueOf(att.getLink().getVideoId()));
-                    param.setQwUserId(String.valueOf(qwUser.getId()));
+                    param.setQwUserId(qwUser.getId());
                     param.setDays(att.getLink().getExpiresDays());
                     param.setCorpId(corpId);
                     param.setCourseId(Long.valueOf(att.getLink().getCourseId()));
@@ -3166,7 +3166,7 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
 
                         FsCourseLinkCreateParam param = new FsCourseLinkCreateParam();
                         param.setVideoId(Long.valueOf(att.getMiniprogram().getVideoId()));
-                        param.setQwUserId(String.valueOf(qwUser.getId()));
+                        param.setQwUserId(qwUser.getId());
                         param.setDays(att.getMiniprogram().getExpiresDays());
                         param.setCorpId(corpId);
                         param.setCourseId(Long.valueOf(att.getMiniprogram().getCourseId()));
@@ -3224,7 +3224,7 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
         watchLog.setVideoId(videoId != null ? videoId.longValue() : null);
         watchLog.setQwExternalContactId(externalId != null ? Long.valueOf(externalId) : null);
         watchLog.setSendType(2);
-        watchLog.setQwUserId(qwUserId);
+        watchLog.setQwUserId(Long.valueOf(qwUserId));
         watchLog.setSopId(null);
         watchLog.setCourseId(courseId != null ? courseId.longValue() : null);
         watchLog.setCompanyUserId(companyUserId != null ? Long.valueOf(companyUserId) : null);

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

@@ -543,7 +543,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                                     createParam.setCompanyUserId(Long.parseLong(companyUserId));
                                     createParam.setCompanyId(Long.parseLong(companyId));
                                     createParam.setChatId(groupUser.getChatId());
-                                    createParam.setQwUserId(qwUser.getQwUserId());
+                                    createParam.setQwUserId(Long.parseLong(qwUser.getQwUserId()));
                                     createParam.setDays(st.getExpiresDays());
                                     R createLink = courseLinkService.createRoomLinkUrl(createParam);
                                     if (createLink.get("code").equals(500)) {
@@ -639,7 +639,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                                     createParam.setCompanyUserId(qwUser.getCompanyUserId());
                                     createParam.setCompanyId(qwUser.getCompanyId());
                                     createParam.setChatId(groupChat.getChatId());
-                                    createParam.setQwUserId(qwUser.getQwUserId());
+                                    createParam.setQwUserId(Long.parseLong(qwUser.getQwUserId()));
                                     createParam.setDays(st.getExpiresDays());
                                     R createLink = courseLinkService.createRoomLinkUrl(createParam);
                                     if (createLink.get("code").equals(500)) {
@@ -1197,7 +1197,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
             watchLog.setVideoId(videoId != null ? videoId.longValue() : null);
             watchLog.setQwExternalContactId(externalId);
             watchLog.setSendType(2);
-            watchLog.setQwUserId(qwUserId);
+            watchLog.setQwUserId(Long.parseLong(qwUserId));
             watchLog.setSopId(sopId);
             watchLog.setDuration(0L);
             watchLog.setCourseId(courseId != null ? courseId.longValue() : null);
@@ -1336,7 +1336,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
         // 手动创建 FsCourseLink 对象,避免使用 BeanUtils.copyProperties
         FsCourseLink link = new FsCourseLink();
         link.setCompanyId(Long.parseLong(companyId));
-        link.setQwUserId(qwUserId);
+        link.setQwUserId(Long.parseLong(qwUserId));
         link.setCompanyUserId(Long.parseLong(companyUserId));
         link.setVideoId(videoId.longValue());
         link.setCorpId(corpId);

+ 2 - 2
fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsServiceImpl.java

@@ -550,7 +550,7 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
                         if (item.getIsBindUrl() != null && item.getIsBindUrl().equals("1")) {
                             FsCourseLinkCreateParam param = new FsCourseLinkCreateParam();
                             param.setVideoId((long) videoId);
-                            param.setQwUserId(String.valueOf(qwUserId));
+                            param.setQwUserId(Long.valueOf(qwUserId));
 //                            param.setDays(item.getExpiresDays());
                             param.setCorpId(log.getCorpId());
                             param.setCourseId(Long.valueOf(courseId));
@@ -578,7 +578,7 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
                                 watchLog.setVideoId(Long.valueOf(videoId));
                                 watchLog.setQwExternalContactId(contactId.getExternalId());
                                 watchLog.setSendType(2);
-                                watchLog.setQwUserId(String.valueOf(qwUserId));
+                                watchLog.setQwUserId(Long.parseLong(qwUserId));
                                 watchLog.setCourseId(Long.valueOf(courseId));
                                 watchLog.setCompanyUserId(Long.valueOf(companyUserId));
                                 watchLog.setCompanyId(Long.valueOf(companyId));

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

@@ -29,6 +29,8 @@ public class FsUserPageListVO {
     @ApiModelProperty(value = "状态:1为正常,0为禁止")
     private Integer status;
 
+    private String statusText;
+
     @ApiModelProperty(value = "公司id")
     private Long companyId;
 

+ 3 - 2
fs-service/src/main/resources/application-common.yml

@@ -110,7 +110,8 @@ mybatis:
 # PageHelper分页插件
 pagehelper:
   helperDialect: mysql
-  supportMethodsArguments: true
+  reasonable: false #超出后不显示
+  supportMethodsArguments: false
   params: count=countSql
 
 # Swagger配置
@@ -134,4 +135,4 @@ zhyf:
 image:
   storage:
     local-path: C:\logoFile\logo.jpg
-    server-path: C:\logoFile\logo.jpg
+    server-path: C:\logoFile\logo.jpg

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

@@ -4,7 +4,7 @@ baidu:
 #配置
 logging:
   level:
-    org.springframework.web: INFO
+    org.springframework.web: debug
     com.github.binarywang.demo.wx.cp: DEBUG
     me.chanjar.weixin: DEBUG
 wx:

+ 5 - 19
fs-service/src/main/resources/application-config-druid-fcky.yml

@@ -10,31 +10,17 @@ logging:
 wx:
   miniapp:
     configs:
-      - appid: wx4115995705bb0ea0   #中康智慧
-        secret: 58910ae743005c396012b029c7def579
-        token: Ncbnd7lJvkripVOpyTFAna6NAWCxCrvC
-        aesKey: HlEiBB55eaWUaeBVAQO3cWKWPYv1vOVQSq7nFNICw4E
-        msgDataFormat: JSON
-      - appid: wxedde588767b358b1   #中康未来智慧药房
-        secret: 928d2961c81610d8f64b019597212fcd
-        token: Ncbnd7lJvkripVOpyTFAna6NAWCxCrvC
-        aesKey: HlEiBB55eaWUaeBVAQO3cWKWPYv1vOVQSq7nFNICw4E
-        msgDataFormat: JSON
   cp:
-    corpId: wwb2a1055fb6c9a7c2
+    corpId:
     appConfigs:
-      - agentId: 1000005
-        secret: ec7okROXJqkNafq66-L6aKNv0asTzQIG0CYrj3vyBbo
-        token: PPKOdAlCoMO
-        aesKey: PKvaxtpSv8NGpfTDm7VUHIK8Wok2ESyYX24qpXJAdMP
   pay:
     appId:  #微信公众号或者小程序等的appid
     mchId:  #微信支付商户号
     mchKey:  #微信支付商户密钥
     subAppId:  #服务商模式下的子商户公众账号ID
     subMchId:  #服务商模式下的子商户号
-    keyPath: c:\\cert\\apiclient_cert.p12 # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)
-    notifyUrl: https://userapp.his.runtzh.com/app/wxpay/wxPayNotify
+    keyPath:  # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)
+    notifyUrl:
   mp:
     useRedis: false
     redisConfig:
@@ -42,8 +28,8 @@ wx:
       port: 6379
       timeout: 2000
     configs:
-      - appId: wx5d3096e20e4bd8ba # 第一个公众号的appid  //公众号名称:成都九州在线互联网医院
-        secret: 1afa05f0c71beff0d52fb849c62e479a # 公众号的appsecret
+      - appId: wxea1da2b708ab3c2f # 第一个公众号的appid  //公众号名称:爱尚佳园
+        secret: 981c60b03292f572039402d7ae09f91f # 公众号的appsecret
         token: PPKOdAlCoMO # 接口配置里的Token值
         aesKey: Eswa6VjwtVMCcw03qZy6fWllgrv5aytIA1SZPEU0kU2 # 接口配置里的EncodingAESKey值
 aifabu:  #爱链接

+ 10 - 10
fs-service/src/main/resources/application-config-druid-hzyy.yml

@@ -10,13 +10,13 @@ logging:
 wx:
   miniapp:
     configs:
-      - appid: wx4115995705bb0ea0   #中康智慧
-        secret: 58910ae743005c396012b029c7def579
+      - appid: wxb   #金悦澜湾药房
+        secret: 00
         token: Ncbnd7lJvkripVOpyTFAna6NAWCxCrvC
         aesKey: HlEiBB55eaWUaeBVAQO3cWKWPYv1vOVQSq7nFNICw4E
         msgDataFormat: JSON
-      - appid: wxedde588767b358b1   #中康未来智慧药房
-        secret: 928d2961c81610d8f64b019597212fcd
+      - appid: wxb48fe0acfdc70a92   #金悦澜湾药房
+        secret: 009e1c9f55071c1fd9c45f707356f2fb
         token: Ncbnd7lJvkripVOpyTFAna6NAWCxCrvC
         aesKey: HlEiBB55eaWUaeBVAQO3cWKWPYv1vOVQSq7nFNICw4E
         msgDataFormat: JSON
@@ -75,17 +75,17 @@ tencent_cloud_config:
   region: ap-chongqing
   proxy: hzyy
 tmp_secret_config:
-  secret_id: AKIDCj7NSNAovtqeJpBau8GZ4CGB71thXIxX
-  secret_key: lTB5zwqqz7CNhzDOWivFWedgfTBgxgBT
-  bucket: fs-1319721001
-  app_id: 1319721001
-  region: ap-chongqing
+  secret_id: AKIDCj7NSN
+  secret_key: lTB5zwqqz
+  bucket: fs-131
+  app_id: 131
+  region: ap-
   proxy: fs
 cloud_host:
   company_name: 弘珍医药
 #看课授权时显示的头像
 headerImg:
-  imgUrl: https://jz-cos-1356808054.cos.ap-chengdu.myqcloud.com/fs/20250515/0877754b59814ea8a428fa3697b20e68.png
+  imgUrl: https://hzyy.obs.cn-north-4.myhuaweicloud.com/fs/20250616/1750067609692.png
 ipad:
   ipadUrl: http://ipad.cdwjyyh.com
 wx_miniapp_temp:

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

@@ -74,7 +74,7 @@ tencent_cloud_config:
   region: ap-chongqing
   proxy: sxjz
 cloud_host:
-  company_name: 今正
+  company_name: 今正科技
 #看课授权时显示的头像
 headerImg:
   imgUrl: https://jz-cos-1356808054.cos.ap-chengdu.myqcloud.com/fs/20250515/0877754b59814ea8a428fa3697b20e68.png

+ 10 - 28
fs-service/src/main/resources/application-config-druid-zsjk.yml

@@ -1,5 +1,6 @@
 baidu:
   token: 12313231232
+  back-domain: https://www.xxxx.com
 #配置
 logging:
   level:
@@ -7,18 +8,6 @@ logging:
     com.github.binarywang.demo.wx.cp: DEBUG
     me.chanjar.weixin: DEBUG
 wx:
-  miniapp:
-    configs:
-      - appid: wx4115995705bb0ea0   #中康智慧
-        secret: 58910ae743005c396012b029c7def579
-        token: Ncbnd7lJvkripVOpyTFAna6NAWCxCrvC
-        aesKey: HlEiBB55eaWUaeBVAQO3cWKWPYv1vOVQSq7nFNICw4E
-        msgDataFormat: JSON
-      - appid: wxedde588767b358b1   #中康未来智慧药房
-        secret: 928d2961c81610d8f64b019597212fcd
-        token: Ncbnd7lJvkripVOpyTFAna6NAWCxCrvC
-        aesKey: HlEiBB55eaWUaeBVAQO3cWKWPYv1vOVQSq7nFNICw4E
-        msgDataFormat: JSON
   cp:
     corpId:
     appConfigs:
@@ -42,10 +31,10 @@ wx:
       timeout: 2000
       password: F&C6SI@w
     configs:
-      - appId:  # 第一个公众号的appid  //公众号名称:成都九州在线互联网医院
-        secret:  # 公众号的appsecret
-        token:  # 接口配置里的Token值
-        aesKey:  # 接口配置里的EncodingAESKey值
+      - appId: wx21eb60f1670b30fb # 第一个公众号的appid  //公众号名称:中食健康CFSH
+        secret: ce4dbc601a9c1d7944f6c75467e43aa0 # 公众号的appsecret
+        token: PPKOdAlCoMO # 接口配置里的Token值
+        aesKey: Eswa6VjwtVcw03qZy6Wllgrv5aytIA1SZPEU0kU2 # 接口配置里的EncodingAESKey值
 aifabu:  #爱链接
   appKey:
 watch:
@@ -68,23 +57,16 @@ nuonuo:
 
 # 存储捅配置
 tencent_cloud_config:
-  secret_id:
-  secret_key:
-  bucket:
-  app_id:
+  secret_id: AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT
+  secret_key: u5SuS80342xzx8FRBukza9lVNHKNMSaB
+  bucket: zsjk-1323137866
+  app_id: 1323137866
   region: ap-chongqing
   proxy: zsjk
-tmp_secret_config:
-  secret_id:
-  secret_key:
-  bucket:
-  app_id: 1319721001
-  region: ap-chongqing
-  proxy: fs
 cloud_host:
   company_name: 中食健康
 headerImg:
-  imgUrl: https
+  imgUrl: https://zs-1362480099.cos.ap-beijing.myqcloud.com/fs/20250618/4839e2ff3bdb4908b459abea45a04f4b.png
 ipad:
   ipadUrl: http://ipad.cdwjyyh.com
 wx_miniapp_temp:

+ 150 - 0
fs-service/src/main/resources/application-druid-fcky-test.yml

@@ -0,0 +1,150 @@
+# 数据源配置
+spring:
+    profiles:
+        include: config-druid-fcky,common
+    # redis 配置
+    redis:
+        # 地址
+        host: 127.0.0.1
+        # 端口,默认为6379
+        port: 6379
+        # 数据库索引
+        database: 0
+        # 密码
+        password:
+        # 连接超时时间
+        timeout: 20s
+        lettuce:
+            pool:
+                # 连接池中的最小空闲连接
+                min-idle: 0
+                # 连接池中的最大空闲连接
+                max-idle: 8
+                # 连接池的最大数据库连接数
+                max-active: 8
+                # #连接池最大阻塞等待时间(使用负值表示没有限制)
+                max-wait: -1ms
+    datasource:
+        #        clickhouse:
+        #            type: com.alibaba.druid.pool.DruidDataSource
+        #            driverClassName: com.clickhouse.jdbc.ClickHouseDriver
+        #            url: jdbc:clickhouse://cc-2vc8zzo26w0l7m2l6.public.clickhouse.ads.aliyuncs.com/sop?compress=0&use_server_time_zone=true&use_client_time_zone=false&timezone=Asia/Shanghai
+        #            username: rt_2024
+        #            password: Yzx_19860213
+        #            initialSize: 10
+        #            maxActive: 100
+        #            minIdle: 10
+        #            maxWait: 6000
+        mysql:
+            type: com.alibaba.druid.pool.DruidDataSource
+            driverClassName: com.mysql.cj.jdbc.Driver
+            druid:
+                # 主库数据源
+                master:
+                    url: jdbc:mysql://119.45.165.149:2345/fs_his?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                    username: root
+                    password: Ylrz_1q2w3e4r5t6y
+                # 从库数据源
+                slave:
+                    # 从数据源开关/默认关闭
+                    enabled: false
+                    url:
+                    username:
+                    password:
+                # 初始连接数
+                initialSize: 5
+                # 最小连接池数量
+                minIdle: 10
+                # 最大连接池数量
+                maxActive: 20
+                # 配置获取连接等待超时的时间
+                maxWait: 60000
+                # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+                timeBetweenEvictionRunsMillis: 60000
+                # 配置一个连接在池中最小生存的时间,单位是毫秒
+                minEvictableIdleTimeMillis: 300000
+                # 配置一个连接在池中最大生存的时间,单位是毫秒
+                maxEvictableIdleTimeMillis: 900000
+                # 配置检测连接是否有效
+                validationQuery: SELECT 1 FROM DUAL
+                testWhileIdle: true
+                testOnBorrow: false
+                testOnReturn: false
+                webStatFilter:
+                    enabled: true
+                statViewServlet:
+                    enabled: true
+                    # 设置白名单,不填则允许所有访问
+                    allow:
+                    url-pattern: /druid/*
+                    # 控制台管理用户名和密码
+                    login-username: fs
+                    login-password: 123456
+                filter:
+                    stat:
+                        enabled: true
+                        # 慢SQL记录
+                        log-slow-sql: true
+                        slow-sql-millis: 1000
+                        merge-sql: true
+                    wall:
+                        config:
+                            multi-statement-allow: true
+        sop:
+            type: com.alibaba.druid.pool.DruidDataSource
+            driverClassName: com.mysql.cj.jdbc.Driver
+            druid:
+                # 主库数据源
+                master:
+                    url: jdbc:mysql://119.45.165.149:2345/sop?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                    username: root
+                    password: Ylrz_1q2w3e4r5t6y
+                # 初始连接数
+                initialSize: 5
+                # 最小连接池数量
+                minIdle: 10
+                # 最大连接池数量
+                maxActive: 20
+                # 配置获取连接等待超时的时间
+                maxWait: 60000
+                # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+                timeBetweenEvictionRunsMillis: 60000
+                # 配置一个连接在池中最小生存的时间,单位是毫秒
+                minEvictableIdleTimeMillis: 300000
+                # 配置一个连接在池中最大生存的时间,单位是毫秒
+                maxEvictableIdleTimeMillis: 900000
+                # 配置检测连接是否有效
+                validationQuery: SELECT 1 FROM DUAL
+                testWhileIdle: true
+                testOnBorrow: false
+                testOnReturn: false
+                webStatFilter:
+                    enabled: true
+                statViewServlet:
+                    enabled: true
+                    # 设置白名单,不填则允许所有访问
+                    allow:
+                    url-pattern: /druid/*
+                    # 控制台管理用户名和密码
+                    login-username: fs
+                    login-password: 123456
+                filter:
+                    stat:
+                        enabled: true
+                        # 慢SQL记录
+                        log-slow-sql: true
+                        slow-sql-millis: 1000
+                        merge-sql: true
+                    wall:
+                        config:
+                            multi-statement-allow: true
+rocketmq:
+    name-server: rmq-1243b25nj.rocketmq.gz.public.tencenttdmq.com:8080 # RocketMQ NameServer 地址
+    producer:
+        group: my-producer-group
+        access-key: ak1243b25nj17d4b2dc1a03 # 替换为实际的 accessKey
+        secret-key: sk08a7ea1f9f4b0237 # 替换为实际的 secretKey
+    consumer:
+        group: test-group
+        access-key: ak1243b25nj17d4b2dc1a03 # 替换为实际的 accessKey
+        secret-key: sk08a7ea1f9f4b0237 # 替换为实际的 secretKey

+ 2 - 1
fs-service/src/main/resources/mapper/company/CompanyMapper.xml

@@ -38,7 +38,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </resultMap>
 
     <sql id="selectCompanyVo">
-        select company_id,follow_doctor_ids,doctor_ids, company_name,manager, company_mobile, company_address, create_time, update_time, status, start_time, limit_time, money ,tui_money, voice_api_id,company_type,user_id,app_id,app_key,remark,link_name,limit_user_count,is_del,voice_caller_number,oms_code,restart_time,package_cate_ids,course_ma_app_id,course_mini_app_id from company
+        select * from company
     </sql>
 
     <select id="selectCompanyList" parameterType="Company" resultMap="CompanyResult">
@@ -156,6 +156,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="packageCateIds != null">package_cate_ids = #{packageCateIds},</if>
             <if test="courseMaAppId != null">course_ma_app_id = #{courseMaAppId},</if>
             <if test="courseMiniAppId != null">course_mini_app_id = #{courseMiniAppId},</if>
+            <if test="fsUserIsDefaultBlack != null ">fs_user_is_default_black = #{fsUserIsDefaultBlack},</if>
         </trim>
         where company_id = #{companyId}
     </update>

+ 18 - 6
fs-service/src/main/resources/mapper/company/CompanyPostMapper.xml

@@ -3,7 +3,7 @@
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.fs.company.mapper.CompanyPostMapper">
-    
+
     <resultMap type="CompanyPost" id="CompanyPostResult">
         <result property="postId"    column="post_id"    />
         <result property="companyId"    column="company_id"    />
@@ -24,7 +24,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 
     <select id="selectCompanyPostList" parameterType="CompanyPost" resultMap="CompanyPostResult">
         <include refid="selectCompanyPostVo"/>
-        <where>  
+        <where>
             <if test="companyId != null "> and company_id = #{companyId}</if>
             <if test="postCode != null  and postCode != ''"> and post_code = #{postCode}</if>
             <if test="postName != null  and postName != ''"> and post_name like concat('%', #{postName}, '%')</if>
@@ -32,12 +32,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="status != null  and status != ''"> and status = #{status}</if>
         </where>
     </select>
-    
+
     <select id="selectCompanyPostById" parameterType="Long" resultMap="CompanyPostResult">
         <include refid="selectCompanyPostVo"/>
         where post_id = #{postId}
     </select>
-        
+
     <insert id="insertCompanyPost" parameterType="CompanyPost" useGeneratedKeys="true" keyProperty="postId">
         insert into company_post
         <trim prefix="(" suffix=")" suffixOverrides=",">
@@ -88,7 +88,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </delete>
 
     <delete id="deleteCompanyPostByIds" parameterType="String">
-        delete from company_post where post_id in 
+        delete from company_post where post_id in
         <foreach item="postId" collection="array" open="(" separator="," close=")">
             #{postId}
         </foreach>
@@ -117,4 +117,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 			 left join company_user u on u.user_id = up.user_id
 		where u.user_id = #{user_id}
 	</select>
-</mapper>
+
+    <select id="selectCompanyPostByIds" resultType="com.fs.company.domain.CompanyPost">
+        <include refid="selectCompanyPostVo"/>
+        <where>
+            <if test="postIds != null">
+                post_id in
+                <foreach collection="postIds" item="id" open="(" close=")" separator=",">
+                    #{id}
+                </foreach>
+            </if>
+        </where>
+    </select>
+</mapper>

+ 15 - 6
fs-service/src/main/resources/mapper/company/CompanyRoleMapper.xml

@@ -3,7 +3,7 @@
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.fs.company.mapper.CompanyRoleMapper">
-    
+
     <resultMap type="CompanyRole" id="CompanyRoleResult">
         <result property="roleId"    column="role_id"    />
         <result property="companyId"    column="company_id"    />
@@ -28,7 +28,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 
     <select id="selectCompanyRoleList" parameterType="CompanyRole" resultMap="CompanyRoleResult">
         <include refid="selectCompanyRoleVo"/>
-        <where>  
+        <where>
             <if test="companyId != null "> and company_id = #{companyId}</if>
             <if test="roleName != null  and roleName != ''"> and role_name like concat('%', #{roleName}, '%')</if>
             <if test="roleKey != null  and roleKey != ''"> and role_key = #{roleKey}</if>
@@ -39,12 +39,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="status != null  and status != ''"> and status = #{status}</if>
         </where>
     </select>
-    
+
     <select id="selectCompanyRoleById" parameterType="Long" resultMap="CompanyRoleResult">
         <include refid="selectCompanyRoleVo"/>
         where role_id = #{roleId}
     </select>
-        
+
     <insert id="insertCompanyRole" parameterType="CompanyRole" useGeneratedKeys="true" keyProperty="roleId">
         insert into company_role
         <trim prefix="(" suffix=")" suffixOverrides=",">
@@ -107,7 +107,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </delete>
 
     <delete id="deleteCompanyRoleByIds" parameterType="String">
-        delete from company_role where role_id in 
+        delete from company_role where role_id in
         <foreach item="roleId" collection="array" open="(" separator="," close=")">
             #{roleId}
         </foreach>
@@ -152,4 +152,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 	        left join company_user u on u.user_id = ur.user_id
 	    where u.user_id = #{userId}
 	</select>
-</mapper>
+
+    <select id="selectRoleListByIds" resultType="com.fs.company.domain.CompanyRole">
+        select * from company_role
+        where del_flag = '0' and status = '0'
+        and role_id in
+        <foreach collection="roleIds" item="roleId" separator="," open="(" close=")">
+            #{roleId}
+        </foreach>
+    </select>
+</mapper>

+ 6 - 2
fs-service/src/main/resources/mapper/company/CompanyTagMapper.xml

@@ -54,9 +54,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         where ctu.user_id = #{userId}
     </select>
     <select id="findUserTagByUserId" resultType="java.lang.String">
-        select tag_ids from company_tag_user where user_id = ${userId} limit 1
+        select tag_ids from company_tag_user where user_id = ${userId} and company_user_id=${companyUserId} limit 1
     </select>
-    <select id="queryAllTagMap" resultType="java.util.Map">
+    <resultMap id="companyTagMap" type="com.fs.company.domain.CompanyTag">
+        <id column="tag_id" property="tagId" jdbcType="BIGINT" javaType="java.lang.Long"/>
+        <id column="tag" property="tag" jdbcType="VARCHAR" javaType="java.lang.String"/>
+    </resultMap>
+    <select id="queryAllTagMap" resultMap="companyTagMap">
         select tag_id,tag from company_tag
     </select>
 

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

@@ -105,7 +105,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     <select id="selectUserListByMap" resultType="com.fs.company.vo.CompanyTagUserVO">
         select
             fu.user_id,
-            fu.nickname as userName
+            fu.nick_name as userName
         from company_tag_user ctu
         inner join fs_user fu on fu.user_id = ctu.user_id
         where ctu.company_id = #{params.companyId} and

+ 72 - 1
fs-service/src/main/resources/mapper/company/CompanyUserMapper.xml

@@ -39,6 +39,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="voicePrintUrl"    column="voice_print_url"    />
         <result property="addressId"    column="address_id"    />
         <result property="domain"    column="domain"    />
+        <result property="isAudit"    column="is_audit"    />
+        <result property="isNeedRegisterMember"    column="is_need_register_member"    />
         <association property="dept"    column="dept_id" javaType="CompanyDept" resultMap="deptResult" />
         <collection  property="roles"   javaType="java.util.List"        resultMap="RoleResult" />
     </resultMap>
@@ -203,6 +205,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="voicePrintUrl != null">voice_print_url = #{voicePrintUrl},</if>
             <if test="addressId != null">address_id = #{addressId},</if>
             <if test="domain != null">domain = #{domain},</if>
+            <if test="isAudit != null">`is_audit` = #{isAudit},</if>
         </trim>
         where user_id = #{userId}
     </update>
@@ -281,7 +284,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         select u.user_id,u.qw_user_id,u.company_id,u.voice_print_url, u.dept_id, u.user_name, u.nick_name,
                u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip,
                u.login_date, u.create_by, u.create_time,u.id_card, u.remark,u.user_type,u.open_id,
-               u.qr_code_weixin,u.qr_code_wecom,u.jpush_id,u.address_id,u.domain,
+               u.qr_code_weixin,u.qr_code_wecom,u.jpush_id,u.address_id,u.domain,u.is_audit,u.is_need_register_member,
         d.dept_id, d.parent_id, d.dept_name, d.order_num, d.leader, d.status as dept_status,
         r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status
         from company_user u
@@ -329,6 +332,74 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         </foreach>
     </update>
 
+
+    <select id="selectMyUserList" parameterType="com.fs.company.vo.CompanyUserVO" resultMap="CompanyUserVOResult">
+        select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark,u.open_id,u.id_card, d.dept_name, d.leader, u.is_audit,
+        cr.role_id, cr.role_name
+        from company_user u
+        left join company_user_role cur on cur.user_id = u.user_id
+        left join company_role cr on cr.role_id = cur.role_id
+        left join company_dept d on u.dept_id = d.dept_id
+        where u.del_flag = '0' and u.status=0
+        <if test="companyId != null  ">
+            AND u.company_id = #{companyId}
+        </if>
+        <if test="nickName != null and nickName != ''">
+            AND u.nick_name like concat('%', #{nickName}, '%')
+        </if>
+        <if test="phonenumber != null and phonenumber != ''">
+            AND u.phonenumber like concat('%', #{phonenumber}, '%')
+        </if>
+        <if test="beginTime != null and beginTime != ''"><!-- 开始时间检索 -->
+            AND date_format(u.create_time,'%y%m%d') &gt;= date_format(#{beginTime},'%y%m%d')
+        </if>
+        <if test="endTime != null and endTime != ''"><!-- 结束时间检索 -->
+            AND date_format(u.create_time,'%y%m%d') &lt;= date_format(#{endTime},'%y%m%d')
+        </if>
+        <if test="deptId != null and deptId != 0">
+            AND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM company_dept t WHERE find_in_set(#{deptId}, ancestors) ))
+        </if>
+        <if test="isAudit != null">
+            AND u.is_audit = #{isAudit}
+        </if>
+
+    </select>
+
+    <resultMap type="com.fs.company.vo.CompanyUserVO" id="CompanyUserVOResult">
+        <result property="userId"    column="user_id"    />
+        <result property="companyId"    column="company_id"    />
+        <result property="deptId"    column="dept_id"    />
+        <result property="userName"    column="user_name"    />
+        <result property="nickName"    column="nick_name"    />
+        <result property="userType"    column="user_type"    />
+        <result property="email"    column="email"    />
+        <result property="phonenumber"    column="phonenumber"    />
+        <result property="sex"    column="sex"    />
+        <result property="avatar"    column="avatar"    />
+        <result property="idCard"    column="id_card"    />
+        <result property="password"    column="password"    />
+        <result property="status"    column="status"    />
+        <result property="delFlag"    column="del_flag"    />
+        <result property="loginIp"    column="login_ip"    />
+        <result property="loginDate"    column="login_date"    />
+        <result property="createBy"    column="create_by"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateBy"    column="update_by"    />
+        <result property="updateTime"    column="update_time"    />
+        <result property="token"    column="token"    />
+        <result property="remark"    column="remark"    />
+        <result property="openId"    column="open_id"    />
+        <result property="nowDayCustomerCount"    column="now_day_customer_count"    />
+        <result property="domain"    column="domain"    />
+        <result property="isAudit"    column="is_audit"    />
+        <result property="addressId"    column="address_id"    />
+        <association property="dept"    column="dept_id" javaType="CompanyDept" resultMap="deptResult" />
+        <collection  property="roles"   javaType="java.util.List"        resultMap="RoleResult" />
+        <collection property="posts" javaType="java.util.ArrayList" ofType="com.fs.company.domain.CompanyPost"
+                    select="com.fs.company.mapper.CompanyPostMapper.selectPostsByUserId" column="{user_id=user_id}" />
+
+    </resultMap>
+
     <select id="getUserInfoByUserIds" resultType="com.fs.company.domain.CompanyUser">
         SELECT user_id,user_name FROM company_user WHERE user_id IN <foreach collection="ids" item="item" index="index" open="(" separator="," close=")">
         #{item}

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

@@ -60,7 +60,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="videoId != null "> and fs_course_watch_comment.video_id = #{videoId}</if>
             <if test="nickName != null and nickName != '' ">and fs_user.nick_name like concat('%', #{nickName}, '%')</if>
             <if test="isAll != null and isAll == true and keywords != null and keywords !='' ">
-                AND (fs_user.nickname LIKE concat('%',#{keywords},'%')
+                AND (fs_user.nick_name LIKE concat('%',#{keywords},'%')
                 or  fs_user_course.course_name LIKE concat('%',#{keywords},'%')
                 or  fs_user_course_video.title LIKE concat('%',#{keywords},'%')
                 )

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

@@ -51,6 +51,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <include refid="selectFsCourseWatchLogVo"/>
         where log_id = #{logId}
     </select>
+
     <select id="selectFsCourseWatchLogListVO" resultType="com.fs.course.vo.FsCourseWatchLogListVO">
         select l.log_id,l.user_id,uc.course_name,v.title as video_name,qec.avatar as external_user_avatar,
         l.log_type,SEC_TO_TIME(l.duration) as duration,c.company_name,l.camp_period_time,l.finish_time,
@@ -552,4 +553,52 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{item.logId}
         </foreach>
     </update>
+
+    <update id="batchUpdateFsUserWatchLog" parameterType="java.util.List">
+        UPDATE fs_course_watch_log
+        SET
+        duration = CASE
+        <foreach collection="list" item="item" index="index">
+            WHEN video_id = #{item.videoId} AND user_id = #{item.userId} AND company_user_id = #{item.companyUserId} THEN
+            CASE
+            <!-- 仅当传入的duration > 当前值时才更新 -->
+            WHEN #{item.duration} IS NOT NULL AND #{item.duration} > duration THEN #{item.duration}
+            ELSE duration <!-- 如果 duration 为 null,保持原值 -->
+            END
+        </foreach>
+        END,
+        last_heartbeat_time = CASE
+        <foreach collection="list" item="item" index="index">
+            WHEN video_id = #{item.videoId} AND user_id = #{item.userId} AND company_user_id = #{item.companyUserId} THEN
+            CASE
+            WHEN #{item.lastHeartbeatTime} IS NOT NULL THEN #{item.lastHeartbeatTime}
+            ELSE last_heartbeat_time <!-- 如果 last_heartbeat_time 为 null,保持原值 -->
+            END
+        </foreach>
+        END,
+        finish_time = CASE
+        <foreach collection="list" item="item" index="index">
+            WHEN video_id = #{item.videoId} AND user_id = #{item.userId} AND company_user_id = #{item.companyUserId} THEN
+            CASE
+            WHEN finish_time IS NULL THEN #{item.finishTime} <!-- 如果表中 finish_time 为 null,更新为传入的值 -->
+            ELSE finish_time <!-- 如果表中 finish_time 不为 null,保持原值 -->
+            END
+        </foreach>
+        END,
+        log_type = CASE
+        <foreach collection="list" item="item" index="index">
+            WHEN video_id = #{item.videoId} AND user_id = #{item.userId} AND company_user_id = #{item.companyUserId} THEN
+            CASE
+            WHEN log_type = 2 THEN log_type <!-- 如果 log_type 已经是 2,保持原值 -->
+            WHEN #{item.logType} IS NOT NULL AND log_type != 2 THEN #{item.logType} <!-- 如果 log_type 不是 2,更新为传入的值 -->
+            ELSE log_type <!-- 其他情况保持原值 -->
+            END
+        </foreach>
+        END
+        WHERE
+        (video_id, user_id, company_user_id) IN
+        <foreach collection="list" item="item" index="index" open="(" separator="," close=")">
+            (#{item.videoId}, #{item.userId}, #{item.companyUserId})
+        </foreach>
+    </update>
 </mapper>

+ 3 - 3
fs-service/src/main/resources/mapper/course/FsUserCourseMapper.xml

@@ -96,7 +96,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         select
         fu.user_id,
         fucv.video_id,
-        fu.nickname as nickName,
+        fu.nick_name as nickName,
         fu.username as userName,
         fu.avatar,
         fu.phone as phoneNumber,
@@ -109,7 +109,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <if test="params.keyword != null and params.keyword != ''">
             and (
             fu.user_id = #{params.keyword}
-            or fu.nickname like concat('%', #{params.keyword}, '%')
+            or fu.nick_name like concat('%', #{params.keyword}, '%')
             or fu.username like concat('%', #{params.keyword}, '%')
             or fu.phone = #{params.keyword}
             )
@@ -132,7 +132,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                 and fcwl.log_type = 3
             </otherwise>
         </choose>
-        group by fu.user_id, fucv.video_id, fu.nickname, fu.username, fu.avatar, fu.phone, fu.create_time
+        group by fu.user_id, fucv.video_id, fu.nick_name, fu.username, fu.avatar, fu.phone, fu.create_time
     </select>
 
 

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