Sfoglia il codice sorgente

销售端 看课报表

wangxy 5 giorni fa
parent
commit
44e8e45828

+ 12 - 0
fs-company/src/main/java/com/fs/company/controller/company/CompanyDeptController.java

@@ -13,6 +13,7 @@ import com.fs.framework.security.LoginUser;
 import com.fs.framework.security.SecurityUtils;
 import com.fs.framework.service.TokenService;
 import org.apache.commons.lang3.ArrayUtils;
+import org.checkerframework.checker.units.qual.A;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
@@ -108,6 +109,17 @@ public class CompanyDeptController extends BaseController
         List<CompanyDept> depts = deptService.selectCompanyDeptList(dept);
         return AjaxResult.success(deptService.buildDeptTreeSelect(depts));
     }
+
+    /**
+     * 获取部门列表树
+     */
+    @GetMapping("/selectDeptTree")
+    public AjaxResult selectDeptTree(CompanyDept dept)
+    {
+        dept.setStatus("0");
+        List<CompanyDept> depts = deptService.selectCompanyDeptList(dept);
+        return AjaxResult.success(deptService.buildDeptTreeSelect(depts));
+    }
     /**
      * 加载对应角色部门列表树
      */

+ 58 - 58
fs-company/src/main/java/com/fs/hisStore/controller/FsStoreStatisticsScrmController.java

@@ -36,8 +36,7 @@ import java.util.stream.Collectors;
  */
 @RestController
 @RequestMapping("/store/store/statistics")
-public class FsStoreStatisticsScrmController extends BaseController
-{
+public class FsStoreStatisticsScrmController extends BaseController {
 
     @Autowired
     private ICompanyUserService userService;
@@ -51,30 +50,29 @@ public class FsStoreStatisticsScrmController extends BaseController
 
     @Autowired
     private IFsCourseWatchLogService courseWatchLogService;
+
     @PreAuthorize("@ss.hasPermi('store:statistics:storeOrder')")
     @GetMapping("/storeOrder")
-    public R storeOrder(FsStoreStatisticsParam param)
-    {
-        if(StringUtils.isNotEmpty(param.getUserIds())){
-            String[] userIds=param.getUserIds().split(",");
-            Long[] ids=new Long[userIds.length];
-            for(int i=0;i<ids.length; i++){
-                ids[i]=Long.parseLong(userIds[i]);
+    public R storeOrder(FsStoreStatisticsParam param) {
+        if (StringUtils.isNotEmpty(param.getUserIds())) {
+            String[] userIds = param.getUserIds().split(",");
+            Long[] ids = new Long[userIds.length];
+            for (int i = 0; i < ids.length; i++) {
+                ids[i] = Long.parseLong(userIds[i]);
             }
             param.setUsers(ids);
-        }
-        else{
+        } else {
             //获取部门下的所有用户
-            CompanyUser usermap=new CompanyUser();
+            CompanyUser usermap = new CompanyUser();
             usermap.setDeptId(param.getDeptId());
             List<CompanyUser> users = userService.getUserListByDeptId(usermap);
             List<Long> userIds = users.stream().map(element -> element.getUserId()).collect(Collectors.toList());
             param.setUsers(userIds.toArray(new Long[userIds.size()]));
         }
-        if(param.getUsers()!=null&&param.getUsers().length>0){
-            List<FsStoreOrderStatisticsVO> list= storeOrderService.selectFsStoreOrderStatisticsList(param);
+        if (param.getUsers() != null && param.getUsers().length > 0) {
+            List<FsStoreOrderStatisticsVO> list = storeOrderService.selectFsStoreOrderStatisticsList(param);
 
-            TimeUtils.TimeEntity timeEntity=TimeUtils.parseTime(param.getType().toString(),param.getStartTime(),param.getEndTime());
+            TimeUtils.TimeEntity timeEntity = TimeUtils.parseTime(param.getType().toString(), param.getStartTime(), param.getEndTime());
             timeEntity.setUserIds(param.getUsers());
             Integer cycleNum = timeEntity.getCycleNum();
             Integer beginTime = timeEntity.getBeginTime();
@@ -87,34 +85,32 @@ public class FsStoreStatisticsScrmController extends BaseController
             List<String> dates = jsonObjectList.stream().map(jsonObject -> jsonObject.getString("type")).collect(Collectors.toList());
             List<Integer> orderCount = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("orderCount")).collect(Collectors.toList());
             List<Integer> payPrice = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("payPrice")).collect(Collectors.toList());
-            return R.ok().put("list",list).put("dates",dates).put("orderCount",orderCount).put("payPrice",payPrice);
-        }
-        else {
+            return R.ok().put("list", list).put("dates", dates).put("orderCount", orderCount).put("payPrice", payPrice);
+        } else {
             return R.ok("未查找到数据");
         }
     }
+
     @PreAuthorize("@ss.hasPermi('store:statistics:exportStoreOrder')")
     @GetMapping("/exportStoreOrder")
-    public AjaxResult exportStoreOrder(FsStoreStatisticsParam param)
-    {
-        if(StringUtils.isNotEmpty(param.getUserIds())){
-            String[] userIds=param.getUserIds().split(",");
-            Long[] ids=new Long[userIds.length];
-            for(int i=0;i<ids.length; i++){
-                ids[i]=Long.parseLong(userIds[i]);
+    public AjaxResult exportStoreOrder(FsStoreStatisticsParam param) {
+        if (StringUtils.isNotEmpty(param.getUserIds())) {
+            String[] userIds = param.getUserIds().split(",");
+            Long[] ids = new Long[userIds.length];
+            for (int i = 0; i < ids.length; i++) {
+                ids[i] = Long.parseLong(userIds[i]);
             }
             param.setUsers(ids);
-        }
-        else{
+        } else {
             //获取所有员工
-            CompanyUser usermap=new CompanyUser();
+            CompanyUser usermap = new CompanyUser();
             usermap.setDeptId(param.getDeptId());
             List<CompanyUser> users = userService.getUserListByDeptId(usermap);
             List<Long> userIds = users.stream().map(element -> element.getUserId()).collect(Collectors.toList());
             param.setUsers(userIds.toArray(new Long[userIds.size()]));
         }
 
-        List<FsStoreOrderStatisticsVO> list= storeOrderService.selectFsStoreOrderStatisticsList(param);
+        List<FsStoreOrderStatisticsVO> list = storeOrderService.selectFsStoreOrderStatisticsList(param);
 
         ExcelUtil<FsStoreOrderStatisticsVO> util = new ExcelUtil<FsStoreOrderStatisticsVO>(FsStoreOrderStatisticsVO.class);
         return util.exportExcel(list, "orderLogs");
@@ -123,27 +119,25 @@ public class FsStoreStatisticsScrmController extends BaseController
 
     @PreAuthorize("@ss.hasPermi('store:statistics:storePayment')")
     @GetMapping("/storePayment")
-    public R storePayment(FsStoreStatisticsParam param)
-    {
-        if(StringUtils.isNotEmpty(param.getUserIds())){
-            String[] userIds=param.getUserIds().split(",");
-            Long[] ids=new Long[userIds.length];
-            for(int i=0;i<ids.length; i++){
-                ids[i]=Long.parseLong(userIds[i]);
+    public R storePayment(FsStoreStatisticsParam param) {
+        if (StringUtils.isNotEmpty(param.getUserIds())) {
+            String[] userIds = param.getUserIds().split(",");
+            Long[] ids = new Long[userIds.length];
+            for (int i = 0; i < ids.length; i++) {
+                ids[i] = Long.parseLong(userIds[i]);
             }
             param.setUsers(ids);
-        }
-        else{
+        } else {
             //获取部门下的所有用户
-            CompanyUser usermap=new CompanyUser();
+            CompanyUser usermap = new CompanyUser();
             usermap.setDeptId(param.getDeptId());
             List<CompanyUser> users = userService.getUserListByDeptId(usermap);
             List<Long> userIds = users.stream().map(element -> element.getUserId()).collect(Collectors.toList());
             param.setUsers(userIds.toArray(new Long[userIds.size()]));
         }
-        if(param.getUsers()!=null&&param.getUsers().length>0){
-            List<FsStorePaymentStatisticsVO> list= storePaymentService.selectFsStorePaymentStatisticsList(param);
-            TimeUtils.TimeEntity timeEntity=TimeUtils.parseTime(param.getType().toString(),param.getStartTime(),param.getEndTime());
+        if (param.getUsers() != null && param.getUsers().length > 0) {
+            List<FsStorePaymentStatisticsVO> list = storePaymentService.selectFsStorePaymentStatisticsList(param);
+            TimeUtils.TimeEntity timeEntity = TimeUtils.parseTime(param.getType().toString(), param.getStartTime(), param.getEndTime());
             timeEntity.setUserIds(param.getUsers());
             Integer cycleNum = timeEntity.getCycleNum();
             Integer beginTime = timeEntity.getBeginTime();
@@ -156,34 +150,32 @@ public class FsStoreStatisticsScrmController extends BaseController
             List<String> dates = jsonObjectList.stream().map(jsonObject -> jsonObject.getString("type")).collect(Collectors.toList());
             List<Integer> orderCount = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("orderCount")).collect(Collectors.toList());
             List<Integer> payMoney = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("payMoney")).collect(Collectors.toList());
-            return R.ok().put("list",list).put("dates",dates).put("orderCount",orderCount).put("payMoney",payMoney);
-        }
-        else {
+            return R.ok().put("list", list).put("dates", dates).put("orderCount", orderCount).put("payMoney", payMoney);
+        } else {
             return R.ok("未查找到数据");
         }
     }
+
     @PreAuthorize("@ss.hasPermi('store:statistics:exportStorePayment')")
     @GetMapping("/exportStorePayment")
-    public AjaxResult exportStorePayment(FsStoreStatisticsParam param)
-    {
-        if(StringUtils.isNotEmpty(param.getUserIds())){
-            String[] userIds=param.getUserIds().split(",");
-            Long[] ids=new Long[userIds.length];
-            for(int i=0;i<ids.length; i++){
-                ids[i]=Long.parseLong(userIds[i]);
+    public AjaxResult exportStorePayment(FsStoreStatisticsParam param) {
+        if (StringUtils.isNotEmpty(param.getUserIds())) {
+            String[] userIds = param.getUserIds().split(",");
+            Long[] ids = new Long[userIds.length];
+            for (int i = 0; i < ids.length; i++) {
+                ids[i] = Long.parseLong(userIds[i]);
             }
             param.setUsers(ids);
-        }
-        else{
+        } else {
             //获取所有员工
-            CompanyUser usermap=new CompanyUser();
+            CompanyUser usermap = new CompanyUser();
             usermap.setDeptId(param.getDeptId());
             List<CompanyUser> users = userService.getUserListByDeptId(usermap);
             List<Long> userIds = users.stream().map(element -> element.getUserId()).collect(Collectors.toList());
             param.setUsers(userIds.toArray(new Long[userIds.size()]));
         }
 
-        List<FsStorePaymentStatisticsVO> list= storePaymentService.selectFsStorePaymentStatisticsList(param);
+        List<FsStorePaymentStatisticsVO> list = storePaymentService.selectFsStorePaymentStatisticsList(param);
 
         ExcelUtil<FsStorePaymentStatisticsVO> util = new ExcelUtil<FsStorePaymentStatisticsVO>(FsStorePaymentStatisticsVO.class);
         return util.exportExcel(list, "paymentLogs");
@@ -194,10 +186,18 @@ public class FsStoreStatisticsScrmController extends BaseController
      * 会员统计报表
      */
     @GetMapping("/userReport")
-    public TableDataInfo userReport(FsCourseWatchLogStatisticsListParam  param){
+    public TableDataInfo userReport(FsCourseWatchLogStatisticsListParam param) {
         startPage();
-        return getDataTable(courseWatchLogService.selectFsUserReportVO( param));
+        return getDataTable(courseWatchLogService.selectFsUserReportVO(param));
     }
 
+    /**
+     * 看课统计报表
+     */
+    @GetMapping("/watchLogReport")
+    public TableDataInfo watchLogReport(FsCourseWatchLogStatisticsListParam param) {
+        startPage();
+        return getDataTable(courseWatchLogService.selectWatchLogReportVO(param));
+    }
 
 }

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

@@ -7,6 +7,7 @@ import com.fs.course.param.*;
 import com.fs.course.vo.*;
 import com.fs.his.vo.FsCourseReportVO;
 import com.fs.his.vo.FsUserReportVO;
+import com.fs.his.vo.WatchLogReportVO;
 import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.param.QwSidebarStatsParam;
 import com.fs.sop.vo.QwRatingVO;
@@ -571,6 +572,9 @@ public interface FsCourseWatchLogMapper extends BaseMapper<FsCourseWatchLog> {
 
     List<FsUserReportVO>  selectFsUserReportVO(FsCourseWatchLogStatisticsListParam param);
 
+
+    List<WatchLogReportVO>  selectWatchLogReportVO(FsCourseWatchLogStatisticsListParam param);
+
     /**
      * 查询看课记录
      */

+ 10 - 0
fs-service/src/main/java/com/fs/course/param/FsCourseWatchLogStatisticsListParam.java

@@ -64,5 +64,15 @@ public class FsCourseWatchLogStatisticsListParam extends BaseEntity {
      */
     private Long deptId;
 
+    /**
+     * 标识('user','sales',company)
+     */
+    private  String dimension ;
+
+    /**
+     * 销售
+     */
+    private  Long salesId;
+
 
 }

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

@@ -6,6 +6,7 @@ import com.fs.course.param.*;
 import com.fs.course.vo.*;
 import com.fs.his.vo.FsCourseReportVO;
 import com.fs.his.vo.FsUserReportVO;
+import com.fs.his.vo.WatchLogReportVO;
 import com.fs.qw.param.QwSidebarStatsParam;
 import com.fs.qw.vo.QwWatchLogStatisticsListVO;
 
@@ -155,4 +156,11 @@ public interface IFsCourseWatchLogService extends IService<FsCourseWatchLog> {
      * @return
      */
     List<FsUserReportVO> selectFsUserReportVO(FsCourseWatchLogStatisticsListParam param);
+
+    /**
+     * 销售端看课统计报表
+     * @param param
+     * @return
+     */
+    List<WatchLogReportVO> selectWatchLogReportVO(FsCourseWatchLogStatisticsListParam param);
 }

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

@@ -32,6 +32,7 @@ import com.fs.his.utils.ConfigUtil;
 import com.fs.his.utils.PhoneUtil;
 import com.fs.his.vo.FsCourseReportVO;
 import com.fs.his.vo.FsUserReportVO;
+import com.fs.his.vo.WatchLogReportVO;
 import com.fs.qw.Bean.MsgBean;
 import com.fs.qw.cache.IQwExternalContactCacheService;
 import com.fs.qw.cache.IQwUserCacheService;
@@ -1299,5 +1300,14 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
         return fsCourseWatchLogMapper.selectFsUserReportVO(param);
     }
 
+    @Override
+    public List<WatchLogReportVO> selectWatchLogReportVO(FsCourseWatchLogStatisticsListParam param) {
+        if(StringUtils.isNotEmpty(param.getUserPhone())){
+            //加密手机号
+            param.setUserPhone(PhoneUtil.encryptPhone(param.getUserPhone()));
+        }
+        return fsCourseWatchLogMapper.selectWatchLogReportVO(param);
+    }
+
 
 }

+ 122 - 0
fs-service/src/main/java/com/fs/his/vo/WatchLogReportVO.java

@@ -0,0 +1,122 @@
+package com.fs.his.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+public class WatchLogReportVO {
+
+    private Long userId;
+    /**
+     * 昵称
+     */
+    private String nickName;
+
+    /**
+     * 会员数
+     */
+    private  Integer userCount;
+
+
+    /**
+     * 销售数
+     */
+    private  Integer salesCount;
+
+    /**
+     * 所属销售数
+     */
+    private  String salesName;
+
+    /**
+     * 所属销售部门
+     */
+    private  String salesDept;
+
+    /**
+     * 所属销售公司
+     */
+    private  String salesCompany;
+
+    /**
+     * 在线会员数
+     */
+    private  Integer onlineUserCount;
+
+    /**
+     * 培训营名称
+     */
+    private String trainingCampName;
+
+    /**
+     * 营期
+     */
+    private  String periodName;
+
+    /**
+     * 视频名称
+     */
+    private  String videoTitle;
+
+    /**
+     * 观看状态
+     */
+    private  String watchStatus;
+
+    /**
+     * 观看时长
+     */
+    private  String duration;
+
+    /**
+     * 观看完成数
+     */
+    private  Integer finishedCount;
+
+    /**
+     * 观看未完成数
+     */
+    private  Integer unfinishedCount;
+
+    /**
+     * 观看完成率
+     */
+    private BigDecimal completionRate;
+
+    /**
+     * 看课时间
+     */
+    private Date courseTime;
+
+    /**
+     * 观看完成时间
+     */
+    private  Date  finishTime;
+
+    /**
+     * 未看课数
+     */
+    private  Integer notWatchedCount;
+
+    /**
+     * 未回答数
+     */
+    private  Integer notAnsweredCount;
+
+    /**
+     * 回答状态
+     */
+    private  String answerStatus;
+
+    /**
+     * 领取红包金额
+     */
+    private  BigDecimal redPacketAmount;
+
+    /**
+     * 历史订单数
+     */
+    private  Integer historyOrderCount;
+}

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

@@ -1315,5 +1315,183 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         GROUP BY u.user_id
         ORDER BY u.register_date DESC
     </select>
+    <select id="selectWatchLogReportVO" resultType="com.fs.his.vo.WatchLogReportVO">
+        <choose>
+            <when test="dimension == 'user'">
+                SELECT
+                u.user_id AS userId,
+                u.nick_name AS nickName,
+                cu.nick_name AS salesName,
+                c.company_name AS salesCompany,
+                dept.dept_name AS salesDept,
+                camp.training_camp_name trainingCampName,
+                cp.period_name periodName,
+                cv.title videoTitle,
+                CASE
+                WHEN (SELECT log_type FROM fs_course_watch_log w2 WHERE w2.user_id = u.user_id ORDER BY create_time DESC LIMIT 1) = '1' THEN '看课中'
+                WHEN (SELECT log_type FROM fs_course_watch_log w2 WHERE w2.user_id = u.user_id ORDER BY create_time DESC LIMIT 1) = '2' THEN '完课'
+                WHEN (SELECT log_type FROM fs_course_watch_log w2 WHERE w2.user_id = u.user_id ORDER BY create_time DESC LIMIT 1) = '3' THEN '待看课'
+                WHEN (SELECT log_type FROM fs_course_watch_log w2 WHERE w2.user_id = u.user_id ORDER BY create_time DESC LIMIT 1) = '4' THEN '看课中断'
+                ELSE '无'
+                END AS watchStatus,
+                watch_log.duration,
+                watch_log.create_time courseTime,
+                watch_log.finish_time finishTime,
+                CASE
+                WHEN answer.log_id IS NOT NULL THEN '已答题'
+                ELSE '未答题'
+                END AS answerStatus,
+                COALESCE(SUM(red_packet.amount), 0) AS redPacketAmount,
+                COUNT(DISTINCT CASE WHEN po.`status` = 3 THEN po.order_id END) AS historyOrderCount
+                FROM fs_user u
+                LEFT JOIN fs_package_order po ON po.user_id = u.user_id
+                LEFT JOIN fs_user_company_user cuu ON u.user_id = cuu.user_id
+                LEFT JOIN company_user cu ON cuu.company_user_id = cu.user_id
+                LEFT JOIN company c ON cuu.company_id = c.company_id
+                LEFT JOIN company_dept dept ON cu.dept_id = dept.dept_id
+                LEFT JOIN fs_course_watch_log watch_log ON u.user_id = watch_log.user_id AND watch_log.send_type = 1
+                LEFT JOIN fs_user_course_video cv ON cv.video_id = watch_log.video_id
+                LEFT JOIN fs_user_course_period cp ON watch_log.period_id = cp.period_id AND cp.del_flag = 0
+                LEFT JOIN fs_user_course_training_camp camp ON cp.training_camp_id = camp.training_camp_id
+                LEFT JOIN fs_course_red_packet_log red_packet ON watch_log.log_id = red_packet.watch_log_id
+                LEFT JOIN fs_course_answer_logs answer ON watch_log.log_id = answer.log_id
+                WHERE u.user_id IS NOT NULL
+                <include refid="commonConditions"/>
+                GROUP BY u.user_id
+                ORDER BY u.register_date DESC, watch_log.create_time DESC
+            </when>
+            <!-- 销售维度 -->
+            <when test="dimension == 'sales'">
+                SELECT
+                cu.nick_name as salesName,
+                COUNT(DISTINCT u.user_id) AS userCount,
+                COUNT(DISTINCT CASE WHEN u.`status` = '1' THEN u.user_id END) AS onlineUserCount,
+                cd.dept_name AS salesDept,
+                c.company_name AS salesCompany,
+                camp.training_camp_name trainingCampName,
+                cp.period_name periodName,
+                cv.title videoTitle,
+                COUNT(DISTINCT CASE WHEN watch_log.log_type = '2' THEN watch_log.log_id END) AS finishedCount,
+                COUNT(DISTINCT CASE WHEN watch_log.log_type IN ('1', '3', '4') THEN watch_log.log_id END) AS unfinishedCount,
+                CASE
+                WHEN COUNT(DISTINCT watch_log.log_id) = 0 THEN 0
+                ELSE ROUND(COUNT(DISTINCT CASE WHEN watch_log.log_type = '2' THEN watch_log.log_id END) * 100.0 / COUNT(DISTINCT watch_log.log_id), 2)
+                END AS completionRate,
+                watch_log.create_time AS courseTime,
+                COUNT(DISTINCT u.user_id) - COUNT(DISTINCT watch_log.user_id) AS notWatchedCount,
+                COUNT(DISTINCT watch_log.user_id) - COUNT(DISTINCT answer.user_id) AS notAnsweredCount,
+                COALESCE(SUM(red_packet.amount), 0) AS redPacketAmount,
+                COUNT(DISTINCT CASE WHEN po.`status` = 3 THEN po.order_id END) AS historyOrderCount
+                FROM company_user cu
+                LEFT JOIN company c ON cu.company_id = c.company_id
+                LEFT JOIN company_dept cd ON cu.dept_id = cd.dept_id
+                LEFT JOIN fs_user_company_user cuu ON cu.user_id = cuu.company_user_id
+                LEFT JOIN fs_user u ON cuu.user_id = u.user_id
+                LEFT JOIN fs_course_watch_log watch_log ON u.user_id = watch_log.user_id AND watch_log.send_type = 1
+                LEFT JOIN fs_user_course_video cv ON cv.video_id = watch_log.video_id
+                LEFT JOIN fs_user_course_period cp ON watch_log.period_id = cp.period_id AND cp.del_flag = 0
+                LEFT JOIN fs_user_course_training_camp camp ON cp.training_camp_id = camp.training_camp_id
+                LEFT JOIN fs_course_red_packet_log red_packet ON watch_log.log_id = red_packet.watch_log_id
+                LEFT JOIN fs_course_answer_logs answer ON watch_log.user_id = answer.user_id
+                LEFT JOIN fs_package_order po ON u.user_id = po.user_id
+                WHERE cu.user_id IS NOT NULL
+                <include refid="commonConditions"/>
+                GROUP BY cu.user_id, cu.nick_name, cd.dept_name, c.company_name
+                ORDER BY userCount DESC, completionRate DESC
+            </when>
+            <!-- 公司维度 -->
+            <when test="dimension == 'company'">
+                SELECT
+                cd.dept_name AS salesDept,
+                COUNT(DISTINCT cu.user_id) AS salesCount,
+                COUNT(DISTINCT u.user_id) AS userCount,
+                COUNT(DISTINCT CASE WHEN u.`status` = '1' THEN u.user_id END) AS onlineUserCount,
+                c.company_name AS salesCompany,
+                camp.training_camp_name trainingCampName,
+                cp.period_name periodName,
+                cv.title videoTitle,
+                COUNT(DISTINCT CASE WHEN watch_log.log_type = '2' THEN watch_log.log_id END) AS finishedCount,
+                COUNT(DISTINCT CASE WHEN watch_log.log_type IN ('1', '3', '4') THEN watch_log.log_id END) AS unfinishedCount,
+                CASE
+                WHEN COUNT(DISTINCT watch_log.log_id) = 0 THEN 0
+                ELSE ROUND(COUNT(DISTINCT CASE WHEN watch_log.log_type = '2' THEN watch_log.log_id END) * 100.0 / COUNT(DISTINCT watch_log.log_id), 2)
+                END AS completionRate,
+                watch_log.create_time AS courseTime,
+                COUNT(DISTINCT u.user_id) - COUNT(DISTINCT watch_log.user_id) AS notWatchedCount,
+                COUNT(DISTINCT watch_log.user_id) - COUNT(DISTINCT answer.user_id) AS notAnsweredCount,
+                COALESCE(SUM(red_packet.amount), 0) AS redPacketAmount,
+                COUNT(DISTINCT CASE WHEN po.`status` = 3 THEN po.order_id END) AS historyOrderCount
+                FROM company c
+                LEFT JOIN company_dept cd ON c.company_id = cd.company_id
+                LEFT JOIN company_user cu ON cd.dept_id = cu.dept_id
+                LEFT JOIN fs_user_company_user cuu ON cu.user_id = cuu.company_user_id
+                LEFT JOIN fs_user u ON cuu.user_id = u.user_id
+                LEFT JOIN fs_course_watch_log watch_log ON u.user_id = watch_log.user_id AND watch_log.send_type = 1
+                LEFT JOIN fs_user_course_video cv ON cv.video_id = watch_log.video_id
+                LEFT JOIN fs_user_course_period cp ON watch_log.period_id = cp.period_id AND cp.del_flag = 0
+                LEFT JOIN fs_user_course_training_camp camp ON cp.training_camp_id = camp.training_camp_id
+                LEFT JOIN fs_course_red_packet_log red_packet ON watch_log.log_id = red_packet.watch_log_id
+                LEFT JOIN fs_course_answer_logs answer ON watch_log.user_id = answer.user_id
+                LEFT JOIN fs_package_order po ON u.user_id = po.user_id
+                WHERE c.company_id IS NOT NULL
+                <include refid="commonConditions"/>
+                GROUP BY cd.dept_id, cd.dept_name, c.company_id, c.company_name
+                ORDER BY salesCount DESC, userCount DESC, completionRate DESC
+            </when>
+
+        </choose>
 
+
+    </select>
+    <sql id="commonConditions">
+        <!-- 销售公司 -->
+        <if test="companyId != null and companyId != ''">
+            AND c.company_id = #{companyId}
+        </if>
+
+        <!-- 销售部门 -->
+        <if test="deptId != null and deptId != ''">
+            AND cd.dept_id = #{deptId}
+        </if>
+
+        <!-- 所属销售 -->
+        <if test="salesId != null and salesId != ''">
+            AND cu.user_id = #{salesId}
+        </if>
+
+        <!-- 项目 -->
+        <if test="project != null and project != ''">
+            AND cuu.project_id = #{projectId}
+        </if>
+
+        <!-- 训练营 -->
+        <if test="trainingCampId != null and trainingCampId != ''">
+            AND camp.training_camp_id = #{trainingCampId}
+        </if>
+
+        <!-- 营期 -->
+        <if test="periodId != null and periodId != ''">
+            AND cp.period_id = #{periodId}
+        </if>
+
+        <!-- 时间范围 -->
+        <if test="sTime != null and eTime != null">
+            AND watch_log.create_time BETWEEN #{startTime} AND #{endTime}
+        </if>
+
+        <!-- 会员ID -->
+        <if test="userId != null and userId != ''">
+            AND u.user_id = #{userId}
+        </if>
+
+        <!-- 会员手机号 -->
+        <if test="userPhone != null and userPhone != ''">
+            AND u.phone LIKE CONCAT('%', #{userPhone}, '%')
+        </if>
+
+        <!-- 会员昵称 -->
+        <if test="nickName != null and nickName != ''">
+            AND u.nick_name LIKE CONCAT('%', #{nickName}, '%')
+        </if>
+    </sql>
 </mapper>