Kaynağa Gözat

迁移手动发课营期

吴树波 3 gün önce
ebeveyn
işleme
c8dc67a3d9

+ 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("生成海报失败!");
+        }
     }
 
 }

+ 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;
+}

+ 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;

+ 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;
 
 }

+ 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;
 }

+ 35 - 0
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;
@@ -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);

+ 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;
 

+ 40 - 2
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;
@@ -296,4 +297,41 @@ 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);
+}

+ 31 - 1
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接口
  *
@@ -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);
 }

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

@@ -2,28 +2,42 @@ 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.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,8 +53,9 @@ 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;
@@ -72,8 +87,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;
@@ -639,4 +660,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;
+    }
+
 }

+ 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:

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

@@ -39,6 +39,7 @@ 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"    />
         <association property="dept"    column="dept_id" javaType="CompanyDept" resultMap="deptResult" />
         <collection  property="roles"   javaType="java.util.List"        resultMap="RoleResult" />
     </resultMap>
@@ -281,7 +282,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,
         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

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

@@ -282,6 +282,9 @@
         video.course_sort,
         course.course_name,
         fcpd.period_id,
+        fcpd.start_date_time,
+        fcpd.end_date_time,
+        fcpd.last_join_time,
         fcpd.id,
         if(ccut.start_date_time is null, fcpd.start_date_time, ccut.start_date_time) as startDateTime,
         if(ccut.end_date_time is null, fcpd.end_date_time, ccut.end_date_time) as endDateTime

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

@@ -557,4 +557,653 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         from fs_user u
         where u.company_user_id = #{companyUserId}
     </select>
+
+    <select id="getUserNumber" resultType="com.fs.store.vo.h5.UserListCountVO">
+        SELECT
+        fs_user.`status` as status,
+        count( DISTINCT fs_user.user_id ) AS num
+        FROM
+        fs_user
+        LEFT JOIN fs_user_company_user ON fs_user_company_user.user_id = fs_user.user_id
+        LEFT JOIN company_user ON company_user.user_id = fs_user_company_user.company_user_id
+        WHERE
+        (company_user.user_id = #{userId} OR company_user.parent_id = #{userId} )
+        and fs_user.is_del = 0
+        GROUP BY
+        fs_user.`status`
+    </select>
+
+    <select id="getRepeatUserNumber" resultType="int">
+        SELECT
+        count( DISTINCT fs_user.user_id ) AS num
+        FROM
+        fs_user
+        LEFT JOIN fs_user_company_user ON fs_user_company_user.user_id = fs_user.user_id
+        LEFT JOIN company_user ON company_user.user_id = fs_user_company_user.company_user_id
+        WHERE
+        ( company_user.user_id = #{userId} OR company_user.parent_id = #{userId} )
+        AND fs_user.is_del = 0
+        AND fs_user_company_user.is_repeat_fans = 1 and fs_user.`status` = 1
+    </select>
+
+    <select id="getCountWatchCourse" resultType="com.fs.store.vo.h5.UserDetailsVO">
+        SELECT
+        ifnull( complete_watch_count, 0 ) AS completeWatchCount ,
+        ifnull( watch_times, 0 ) AS watchTimes,
+        fs_user.user_id
+        FROM
+        fs_user_course_count
+        LEFT JOIN fs_user ON fs_user.user_id = fs_user_course_count.user_id
+        LEFT JOIN company_user ON company_user.user_id = fs_user.company_user_id
+        <where>
+            <if test="dateTag != null and dateTag !='' ">
+                <choose>
+                    <when test = "dateTag == '今天'">
+                        and to_days(fs_user_course_count.create_time) = to_days(now())
+                    </when>
+                    <when test = "dateTag == ' 昨天'">
+                        and to_days(now()) - to_days(fs_user_course_count.create_time) &lt;= 1
+                    </when>
+                    <when test = "dateTag == '前天'">
+                        and to_days(now()) - to_days(fs_user_course_count.create_time) &lt;= 2
+                    </when>
+                    <when test = "dateTag == '近七天'">
+                        and DATE_SUB(CURDATE(), INTERVAL 7 DAY) &lt;= date(fs_user_course_count.create_time)
+                    </when>
+                </choose>
+            </if>
+        </where>
+        GROUP BY
+        fs_user.user_id
+        HAVING
+        fs_user.user_id = #{fsUserId}
+    </select>
+
+    <select id="getCountAnswer" resultType="com.fs.store.vo.h5.UserDetailsVO">
+        SELECT
+        (
+        SELECT
+        ifnull(count( DISTINCT log_id ), 0) AS answerTime
+        FROM
+        fs_course_answer_logs
+        LEFT JOIN fs_user ON fs_user.user_id = fs_course_answer_logs.user_id
+        LEFT JOIN company_user ON company_user.user_id = fs_user.company_user_id
+        WHERE
+        company_user.parent_id = #{userId}
+        <if test="dateTag != null and dateTag !='' ">
+            <choose>
+                <when test = "dateTag == '今天'">
+                    and to_days(fs_course_answer_logs.create_time) = to_days(now())
+                </when>
+                <when test = "dateTag == ' 昨天'">
+                    and to_days(now()) - to_days(fs_course_answer_logs.create_time) &lt;= 1
+                </when>
+                <when test = "dateTag == '前天'">
+                    and to_days(now()) - to_days(fs_course_answer_logs.create_time) &lt;= 2
+                </when>
+                <when test = "dateTag == '近七天'">
+                    and DATE_SUB(CURDATE(), INTERVAL 7 DAY) &lt;= date(fs_course_answer_logs.create_time)
+                </when>
+            </choose>
+        </if>
+        GROUP BY
+        fs_user.user_id
+        HAVING
+        fs_user.user_id = #{fsUserId}
+        ) AS answerTime,
+        (
+        SELECT
+        ifnull(count( DISTINCT log_id ), 0) AS answerRightTime
+        FROM
+        fs_course_answer_logs
+        LEFT JOIN fs_user ON fs_user.user_id = fs_course_answer_logs.user_id
+        LEFT JOIN company_user ON company_user.user_id = fs_user.company_user_id
+        WHERE
+        company_user.parent_id = #{userId}
+        AND fs_course_answer_logs.is_right = 1
+        <if test="dateTag != null and dateTag !='' ">
+            <choose>
+                <when test = "dateTag == '今天'">
+                    and to_days(fs_course_answer_logs.create_time) = to_days(now())
+                </when>
+                <when test = "dateTag == ' 昨天'">
+                    and to_days(now()) - to_days(fs_course_answer_logs.create_time) &lt;= 1
+                </when>
+                <when test = "dateTag == '前天'">
+                    and to_days(now()) - to_days(fs_course_answer_logs.create_time) &lt;= 2
+                </when>
+                <when test = "dateTag == '近七天'">
+                    and DATE_SUB(CURDATE(), INTERVAL 7 DAY) &lt;= date(fs_course_answer_logs.create_time)
+                </when>
+            </choose>
+        </if>
+        GROUP BY
+        fs_user.user_id
+        HAVING
+        fs_user.user_id = #{fsUserId}
+        ) AS answerRightTime;
+    </select>
+
+    <select id="getCountRedPacket" resultType="com.fs.store.vo.h5.UserDetailsVO">
+        SELECT
+        ifnull( count( DISTINCT log_id ), 0 ) AS answerRedPacketTime,
+        ifnull( sum( amount ), 0 ) AS answerRedPacketAmount,
+        fs_user.user_id
+        FROM
+        fs_course_red_packet_log
+        LEFT JOIN fs_user ON fs_user.user_id = fs_course_red_packet_log.user_id
+        LEFT JOIN company_user ON company_user.user_id = fs_user.company_user_id
+        WHERE
+        company_user.parent_id = #{userId}
+        <if test="dateTag != null and dateTag !='' ">
+            <choose>
+                <when test = "dateTag == '今天'">
+                    and to_days(fs_course_red_packet_log.create_time) = to_days(now())
+                </when>
+                <when test = "dateTag == ' 昨天'">
+                    and to_days(now()) - to_days(fs_course_red_packet_log.create_time) &lt;= 1
+                </when>
+                <when test = "dateTag == '前天'">
+                    and to_days(now()) - to_days(fs_course_red_packet_log.create_time) &lt;= 2
+                </when>
+                <when test = "dateTag == '近七天'">
+                    and DATE_SUB(CURDATE(), INTERVAL 7 DAY) &lt;= date(fs_course_red_packet_log.create_time)
+                </when>
+            </choose>
+        </if>
+        GROUP BY
+        fs_user.user_id
+        HAVING
+        fs_user.user_id = #{fsUserId}
+    </select>
+
+    <select id="countUserSummary" resultType="com.fs.store.vo.h5.FsUserSummaryCountVO">
+        SELECT (SELECT count(fs_user.user_id)
+        FROM fs_user
+        LEFT JOIN company_user ON fs_user.company_user_id = company_user.user_id
+        WHERE (
+        company_user.user_id = #{userId}
+        OR company_user.parent_id = #{userId}
+        ) and fs_user.is_del = 0) as userTotal,
+        (SELECT count(fs_user.user_id)
+        FROM fs_user
+        LEFT JOIN company_user ON fs_user.company_user_id = company_user.user_id
+        WHERE (company_user.user_id = #{userId} OR company_user.parent_id = #{userId})
+        and fs_user.is_del = 0
+        AND to_days(fs_user.create_time) = to_days(now())) as todayNewUser
+    </select>
+
+    <select id="countTag" resultType="com.fs.store.vo.h5.FsUserSummaryCountTagVO">
+        SELECT
+        company_tag.tag AS tagName,
+        count( fs_user.user_id ) AS number
+        FROM
+        company_tag_user
+        LEFT JOIN fs_user ON fs_user.user_id = company_tag_user.user_id
+        LEFT JOIN company_tag ON FIND_IN_SET( company_tag.tag_id, company_tag_user.tag_ids ) > 0
+        LEFT JOIN company_user ON fs_user.company_user_id = company_user.user_id
+        where (company_user.user_id = #{userId} or company_user.parent_id = #{userId} ) and company_tag.tag_id is not null
+        GROUP BY
+        company_tag.tag_id
+    </select>
+
+    <select id="countUserCourse" resultType="Map">
+        SELECT
+        (
+        SELECT
+        count(distinct fcc.user_id )
+        FROM
+        fs_user_course_count fcc
+        LEFT JOIN fs_user ON fs_user.user_id = fcc.user_id
+        LEFT JOIN company_user ON fs_user.company_user_id = company_user.user_id
+        LEFT JOIN fs_user_course_period_days fcpd ON FIND_IN_SET(fcpd.period_id, fcc.course_ids) > 0
+        WHERE
+        ( company_user.user_id = #{userId}  OR company_user.parent_id = #{userId}  )
+        <if test="startTime != null and startTime !='' ">
+            and fcc.create_time &gt;= #{startTime}
+        </if>
+        <if test="endTime != null and endTime != ''">
+            and fcc.create_time &lt;= #{endTime}
+        </if>
+        <if test="periodId != null and periodId != ''">
+            AND fcpd.period_id = #{periodId}
+        </if>
+        <if test="videoId != null and videoId != ''">
+            AND fcpd.video_id = #{videoId}
+        </if>
+        -- 单独通过销售id查询
+        <if test="companyUserId != null and companyUserId != ''">
+            AND company_user.user_id = #{companyUserId}
+        </if>
+
+        ) as courseWatchNum,
+        (
+        SELECT
+        count(distinct fcc.user_id )
+        FROM
+        fs_user_course_count fcc
+        LEFT JOIN fs_user ON fs_user.user_id = fcc.user_id
+        LEFT JOIN company_user ON fs_user.company_user_id = company_user.user_id
+        LEFT JOIN fs_user_course_period_days fcpd ON FIND_IN_SET(fcpd.period_id, fcc.course_ids) > 0
+        WHERE
+        ( company_user.user_id = #{userId}  OR company_user.parent_id = #{userId}  )
+        AND fcc.complete_watch_count > 0
+        <if test="startTime != null and startTime !='' ">
+            and fcc.create_time &gt;= #{startTime}
+        </if>
+        <if test="endTime != null and endTime != ''">
+            and fcc.create_time &lt;= #{endTime}
+        </if>
+        <if test="periodId != null and periodId != ''">
+            AND fcpd.period_id = #{periodId}
+        </if>
+        <if test="videoId != null and videoId != ''">
+            AND fcpd.video_id = #{videoId}
+        </if>
+        -- 单独通过销售id查询
+        <if test="companyUserId != null and companyUserId != ''">
+            AND company_user.user_id = #{companyUserId}
+        </if>
+        ) as courseCompleteNum
+    </select>
+
+    <select id="countUserAnswer" resultType="Map">
+        SELECT
+        (
+        SELECT
+        count(distinct fs_user.user_id )
+        FROM
+        fs_course_answer_logs
+        LEFT JOIN fs_user ON fs_user.user_id = fs_course_answer_logs.user_id
+        LEFT JOIN company_user ON company_user.user_id = fs_user.company_user_id
+        WHERE
+        ( company_user.user_id = #{userId} OR company_user.parent_id = #{userId} )
+        <if test="startTime != null and startTime !='' ">
+            AND fs_course_answer_logs.create_time &gt;= #{startTime}
+        </if>
+        <if test="endTime != null and endTime != ''">
+            AND fs_course_answer_logs.create_time &lt;= #{endTime}
+        </if>
+        <if test="periodId != null and periodId != ''">
+            AND fs_course_answer_logs.period_id = #{periodId}
+        </if>
+        <if test="videoId != null and videoId != ''">
+            AND fs_course_answer_logs.video_id = #{videoId}
+        </if>
+        -- 单独通过销售id查询
+        <if test="companyUserId != null and companyUserId != ''">
+            AND company_user.user_id = #{companyUserId}
+        </if>
+        ) AS answerNum,
+        (
+        SELECT
+        count(distinct fs_user.user_id )
+        FROM
+        fs_course_answer_logs
+        LEFT JOIN fs_user ON fs_user.user_id = fs_course_answer_logs.user_id
+        LEFT JOIN company_user ON company_user.user_id = fs_user.company_user_id
+        WHERE
+        ( company_user.user_id = #{userId} OR company_user.parent_id = #{userId} )
+        AND fs_course_answer_logs.is_right = 1
+        <if test="startTime != null and startTime !='' ">
+            AND fs_course_answer_logs.create_time &gt;= #{startTime}
+        </if>
+        <if test="endTime != null and endTime != ''">
+            AND fs_course_answer_logs.create_time &lt;= #{endTime}
+        </if>
+        <if test="periodId != null and periodId != ''">
+            AND fs_course_answer_logs.period_id = #{periodId}
+        </if>
+        <if test="videoId != null and videoId != ''">
+            AND fs_course_answer_logs.video_id = #{videoId}
+        </if>
+        -- 单独通过销售id查询
+        <if test="companyUserId != null and companyUserId != ''">
+            AND company_user.user_id = #{companyUserId}
+        </if>
+        ) AS answerRightNum
+    </select>
+
+    <select id="countCourseDetails" resultType="Map">
+        select (SELECT
+        count( DISTINCT fcpd.period_id )
+        FROM
+        fs_user_course_period_days fcpd
+        LEFT JOIN fs_user_course_period fpd on fpd.period_id = fcpd.period_id
+        LEFT JOIN fs_user_course_count fcc ON FIND_IN_SET( fcpd.period_id, fcc.course_ids ) > 0
+        LEFT JOIN fs_user ON fs_user.user_id = fcc.user_id
+        WHERE 1=1
+        AND FIND_IN_SET(#{companyId}, fpd.company_id)
+        <if test="periodId != null and periodId != ''">
+            AND fcpd.period_id =  #{periodId}
+        </if>
+        -- 单独通过销售id查询
+        <if test="companyUserId != null and companyUserId != ''">
+            AND fs_user.company_user_id = #{companyUserId}
+        </if>
+        ) as courseNum,
+
+        (SELECT count(DISTINCT fcpd.video_id)
+        FROM fs_user_course_period_days fcpd
+        LEFT JOIN fs_user_course_period fpd on fpd.period_id = fcpd.period_id
+        LEFT JOIN fs_user_course_count fcc ON FIND_IN_SET( fcpd.period_id, fcc.course_ids ) > 0
+        LEFT JOIN fs_user ON fs_user.user_id = fcc.user_id
+        WHERE 1=1
+        AND FIND_IN_SET(#{companyId}, fpd.company_id)
+        <if test="periodId != null and periodId != ''">
+            AND fcpd.period_id =  #{periodId}
+        </if>
+        <if test="videoId != null and videoId != ''">
+            AND fcpd.video_id = #{videoId}
+        </if>
+        -- 单独通过销售id查询
+        <if test="companyUserId != null and companyUserId != ''">
+            AND fs_user.company_user_id = #{companyUserId}
+        </if>
+        ) as videoNum,
+
+        ( SELECT count(DISTINCT fs_user.user_id ) FROM fs_user_course_count fcc
+        LEFT JOIN fs_user_course_period_days fcpd ON FIND_IN_SET( fcpd.period_id, fcc.course_ids ) > 0
+        LEFT JOIN fs_user ON fs_user.user_id = fcc.user_id
+        <if test="periodId != null and periodId != ''">
+            AND fcpd.period_id =  #{periodId}
+        </if>
+        <if test="videoId != null and videoId != ''">
+            AND fcpd.video_id = #{videoId}
+        </if>
+        -- 单独通过销售id查询
+        <if test="companyUserId != null and companyUserId != ''">
+            AND fs_user.company_user_id = #{companyUserId}
+        </if>
+        ) as courseUserNum
+    </select>
+
+    <select id="countUserRankingByComplete" resultType="com.fs.store.vo.h5.FsUserRankingVO">
+        SELECT
+        company_user.nick_name as userName,
+        ifnull(
+        ROUND((COUNT(DISTINCT CASE WHEN fcc.complete_watch_count > 0 THEN 1 END ) / count(1))*100,2),0
+        ) as completeRate
+        FROM
+        fs_user_course_count fcc
+        LEFT JOIN fs_user ON fs_user.user_id = fcc.user_id
+        LEFT JOIN company_user ON fs_user.company_user_id = company_user.user_id
+        LEFT JOIN fs_user_course_period_days fcpd ON FIND_IN_SET( fcpd.period_id, fcc.course_ids ) > 0
+        WHERE
+        ( company_user.user_id = #{userId} OR company_user.parent_id = #{userId} )
+        <if test="startTime != null and startTime !='' ">
+            AND fcc.create_time &gt;= #{startTime}
+        </if>
+        <if test="endTime != null and endTime != ''">
+            AND fcc.create_time &lt;= #{endTime}
+        </if>
+        <if test="periodId != null and periodId != ''">
+            AND fcpd.period_id =  #{periodId}
+        </if>
+        <if test="videoId != null and videoId != ''">
+            AND fcpd.video_id = #{videoId}
+        </if>
+        group by fcc.user_id
+        <choose>
+            <when test="order != null and order == 'asc'">
+                order by completeRate asc
+            </when>
+            <when test="order != null and order == 'desc'">
+                order by completeRate desc
+            </when>
+            <otherwise>
+                order by completeRate desc
+            </otherwise>
+        </choose>
+        limit 20
+    </select>
+
+    <select id="countUserRankingByRight" resultType="com.fs.store.vo.h5.FsUserRankingVO">
+        SELECT
+        company_user.nick_name as userName,
+        ifnull(ROUND(
+        (COUNT(DISTINCT CASE WHEN fs_course_answer_logs.is_right = 1 THEN 1 END ) / count(1))
+        *100,2),0
+        ) as answerRightRate
+        FROM
+        fs_course_answer_logs
+        LEFT JOIN fs_user ON fs_user.user_id = fs_course_answer_logs.user_id
+        LEFT JOIN company_user ON company_user.user_id = fs_user.company_user_id
+        WHERE
+        ( company_user.user_id = #{userId} OR company_user.parent_id = #{userId} )
+        <if test="startTime != null and startTime !='' ">
+            AND fs_course_answer_logs.create_time &gt;= #{startTime}
+        </if>
+        <if test="endTime != null and endTime != ''">
+            AND fs_course_answer_logs.create_time &lt;= #{endTime}
+        </if>
+        <if test="periodId != null and periodId != ''">
+            AND fs_course_answer_logs.period_id =  #{periodId}
+        </if>
+        <if test="videoId != null and videoId != ''">
+            AND fs_course_answer_logs.video_id = #{videoId}
+        </if>
+        group by fs_user.user_id
+        <choose>
+            <when test="order != null and order == 'asc'">
+                order by answerRightRate asc
+            </when>
+            <when test="order != null and order == 'desc'">
+                order by answerRightRate desc
+            </when>
+            <otherwise>
+                order by answerRightRate desc
+            </otherwise>
+        </choose>
+        limit 20
+    </select>
+
+    <select id="countCourseRankingByComplete" resultType="com.fs.store.vo.h5.FsCourseRankingVO">
+        SELECT
+        fcv.title AS videoName,
+        ifnull(
+        ROUND((
+        COUNT( DISTINCT CASE WHEN fcc.complete_watch_count > 0 THEN 1 END ) / count(1))* 100,
+        2
+        ),
+        0
+        ) AS completeRate
+        FROM
+        fs_user_course_count fcc
+        LEFT JOIN fs_user ON fs_user.user_id = fcc.user_id
+        LEFT JOIN company_user ON fs_user.company_user_id = company_user.user_id
+        LEFT JOIN fs_user_course_period_days fcpd ON FIND_IN_SET( fcpd.period_id, fcc.course_ids ) > 0
+        LEFT JOIN fs_user_course_video fcv ON fcv.video_id = fcpd.video_id
+        WHERE
+        ( company_user.user_id = #{userId} OR company_user.parent_id = #{userId} )
+        <if test="startTime != null and startTime !='' ">
+            AND fcc.create_time &gt;= #{startTime}
+        </if>
+        <if test="endTime != null and endTime != ''">
+            AND fcc.create_time &lt;= #{endTime}
+        </if>
+        <if test="periodId != null and periodId != ''">
+            AND fcpd.period_id =  #{periodId}
+        </if>
+        <if test="videoId != null and videoId != ''">
+            AND fcpd.video_id = #{videoId}
+        </if>
+        GROUP BY
+        fcpd.video_id
+        <choose>
+            <when test="order != null and order == 'asc'">
+                ORDER BY completeRate asc
+            </when>
+            <when test="order != null and order == 'desc'">
+                ORDER BY completeRate desc
+            </when>
+            <otherwise>
+                ORDER BY completeRate desc
+            </otherwise>
+        </choose>
+        LIMIT 20
+    </select>
+
+    <select id="countCourseRankingByRight" resultType="com.fs.store.vo.h5.FsCourseRankingVO">
+        SELECT
+        fcv.title AS videoName,
+        ifnull(
+        ROUND(
+        (
+        COUNT( DISTINCT CASE WHEN fs_course_answer_logs.is_right = 1 THEN 1 END ) / count(1)) * 100,
+        2
+        ),
+        0
+        ) AS answerRightRate
+        FROM
+        fs_course_answer_logs
+        LEFT JOIN fs_user ON fs_user.user_id = fs_course_answer_logs.user_id
+        LEFT JOIN company_user ON company_user.user_id = fs_user.company_user_id
+        LEFT JOIN fs_user_course_video fcv ON fcv.video_id = fs_course_answer_logs.video_id
+        WHERE
+        ( company_user.user_id = #{userId} OR company_user.parent_id = #{userId} )
+        <if test="startTime != null and startTime !='' ">
+            AND fs_course_answer_logs.create_time &gt;= #{startTime}
+        </if>
+        <if test="endTime != null and endTime != ''">
+            AND fs_course_answer_logs.create_time &lt;= #{endTime}
+        </if>
+        <if test="periodId != null and periodId != ''">
+            AND fs_course_answer_logs.period_id = #{periodId}
+        </if>
+        <if test="videoId != null and videoId != ''">
+            AND fs_course_answer_logs.video_id = #{videoId}
+        </if>
+        GROUP BY
+        fs_course_answer_logs.video_id
+        <choose>
+            <when test="order != null and order == 'asc'">
+                ORDER BY answerRightRate asc
+            </when>
+            <when test="order != null and order == 'desc'">
+                ORDER BY answerRightRate desc
+            </when>
+            <otherwise>
+                ORDER BY answerRightRate desc
+            </otherwise>
+        </choose>
+        LIMIT 20
+    </select>
+
+    <select id="countUserRedPacket" resultType="Map">
+        SELECT
+        (
+        SELECT
+        count( flog.log_id )
+        FROM
+        fs_course_red_packet_log flog
+        LEFT JOIN fs_user ON fs_user.user_id = flog.user_id
+        LEFT JOIN company_user ON company_user.user_id = fs_user.company_user_id
+        WHERE
+        ( company_user.user_id = #{userId}  OR company_user.parent_id = #{userId}  )
+        <if test="startTime != null and startTime !='' ">
+            AND flog.create_time &gt;= #{startTime}
+        </if>
+        <if test="endTime != null and endTime != ''">
+            AND flog.create_time &lt;= #{endTime}
+        </if>
+        <if test="periodId != null and periodId != ''">
+            AND flog.period_id =  #{periodId}
+        </if>
+        <if test="videoId != null and videoId != ''">
+            AND flog.video_id = #{videoId}
+        </if>
+        -- 单独通过销售id查询
+        <if test="companyUserId != null and companyUserId != ''">
+            AND company_user.user_id = #{companyUserId}
+        </if>
+        ) AS redPacketNum,
+        (
+        SELECT
+        ifnull (sum( flog.amount ), 0)
+        FROM
+        fs_course_red_packet_log flog
+        LEFT JOIN fs_user ON fs_user.user_id = flog.user_id
+        LEFT JOIN company_user ON company_user.user_id = fs_user.company_user_id
+        WHERE
+        ( company_user.user_id = #{userId}  OR company_user.parent_id = #{userId}  )
+        <if test="startTime != null and startTime !='' ">
+            AND flog.create_time &gt;= #{startTime}
+        </if>
+        <if test="endTime != null and endTime != ''">
+            AND flog.create_time &lt;= #{endTime}
+        </if>
+        <if test="periodId != null and periodId != ''">
+            AND flog.period_id =  #{periodId}
+        </if>
+        <if test="videoId != null and videoId != ''">
+            AND flog.video_id = #{videoId}
+        </if>
+        -- 单独通过销售id查询
+        <if test="companyUserId != null and companyUserId != ''">
+            AND company_user.user_id = #{companyUserId}
+        </if>
+        ) AS redPacketAmount
+    </select>
+
+    <select id="courseAnalysisCourseCount" resultType="com.fs.course.vo.newfs.FsCourseAnalysisCountVO">
+        SELECT
+        count( DISTINCT fcc.user_id ) as courseWatchNum,
+        COUNT( DISTINCT CASE WHEN fcc.complete_watch_count > 0 THEN fcc.user_id END ) as courseCompleteNum,
+        ifnull(
+        ROUND(
+        (
+        COUNT( DISTINCT CASE WHEN fcc.complete_watch_count > 0 THEN fcc.user_id END ) / count( DISTINCT fcc.user_id )) * 100,
+        2
+        ),
+        0
+        ) as completeRate,
+        fcpd.video_id
+        FROM
+        fs_user_course_count fcc
+        LEFT JOIN fs_user ON fs_user.user_id = fcc.user_id
+        LEFT JOIN company_user ON fs_user.company_user_id = company_user.user_id
+        LEFT JOIN fs_user_course_period_days fcpd ON FIND_IN_SET( fcpd.period_id, fcc.course_ids ) > 0
+        WHERE
+        company_user.user_id = #{companyUserId}
+        <if test="periodId != null and periodId != ''">
+            AND fcpd.period_id =  #{periodId}
+        </if>
+        <if test="videoId != null and videoId != ''">
+            AND fcpd.video_id = #{videoId}
+        </if>
+        GROUP BY
+        fcpd.video_id
+    </select>
+
+    <select id="companyUserCount" resultType="com.fs.store.vo.h5.CompanyUserSummaryCountVO">
+        SELECT
+        (
+        SELECT count( fs_user.user_id ) FROM fs_user LEFT JOIN company_user ON fs_user.company_user_id = company_user.user_id
+        WHERE company_user.user_id = #{companyUserId}
+        ) AS userTotal,
+        (
+        SELECT
+        count( fs_user.user_id )
+        FROM
+        fs_user
+        LEFT JOIN company_user ON fs_user.company_user_id = company_user.user_id
+        WHERE
+        company_user.user_id = #{companyUserId}
+        and fs_user.is_del = 0
+        AND to_days( fs_user.create_time ) = to_days(
+        now())
+        ) AS todayNewUser
+    </select>
+
+    <select id="newUserRedPacketCount" resultType="com.fs.store.vo.h5.CompanyUserSummaryCountVO">
+        SELECT
+        count(flog.log_id) as userRedPacketNum,
+        ifnull ( sum(case when to_days( fs_user.create_time ) = to_days(now()) THEN IFNULL(flog.amount,0) END), 0) as todayUserRedPacketAmount
+        FROM
+        fs_course_red_packet_log flog
+        LEFT JOIN fs_user ON fs_user.user_id = flog.user_id
+        WHERE
+        fs_user.company_user_id = #{companyUserId}
+    </select>
 </mapper>