xdd преди 1 месец
родител
ревизия
293481bda4
променени са 25 файла, в които са добавени 1184 реда и са изтрити 54 реда
  1. 0 1
      fs-admin/src/main/java/com/fs/task/FsCourseTask.java
  2. 64 0
      fs-admin/src/main/java/com/fs/task/qw/FsCourseTask.java
  3. 1 1
      fs-admin/src/main/resources/application.yml
  4. 80 0
      fs-common/src/main/java/com/fs/common/utils/PhoneUtil.java
  5. 10 2
      fs-company/src/main/java/com/fs/course/controller/FsCourseAnswerLogsController.java
  6. 3 3
      fs-company/src/main/java/com/fs/course/controller/FsCourseWatchLogController.java
  7. 153 0
      fs-company/src/main/java/com/fs/course/controller/qw/QwFsCourseAnswerLogsController.java
  8. 267 0
      fs-company/src/main/java/com/fs/course/controller/qw/QwFsCourseWatchLogController.java
  9. 3 3
      fs-company/src/main/java/com/fs/qw/qw/QwWorkTaskController.java
  10. 1 1
      fs-company/src/main/resources/application.yml
  11. 1 0
      fs-service-system/src/main/java/com/fs/course/mapper/FsCourseAnswerLogsMapper.java
  12. 1 13
      fs-service-system/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java
  13. 1 20
      fs-service-system/src/main/java/com/fs/course/mapper/FsUserCourseMapper.java
  14. 2 0
      fs-service-system/src/main/java/com/fs/course/param/FsCourseAnswerLogsParam.java
  15. 1 0
      fs-service-system/src/main/java/com/fs/course/service/IFsCourseAnswerLogsService.java
  16. 2 0
      fs-service-system/src/main/java/com/fs/course/service/IFsCourseWatchLogService.java
  17. 5 0
      fs-service-system/src/main/java/com/fs/course/service/impl/FsCourseAnswerLogsServiceImpl.java
  18. 66 4
      fs-service-system/src/main/java/com/fs/course/service/impl/FsCourseWatchLogServiceImpl.java
  19. 4 4
      fs-service-system/src/main/java/com/fs/course/vo/FsCourseOverVO.java
  20. 2 2
      fs-service-system/src/main/java/com/fs/course/vo/FsCourseWatchLogStatisticsListVO.java
  21. 222 0
      fs-service-system/src/main/java/com/fs/qw/mapper/QwWatchLogExMapper.java
  22. 27 0
      fs-service-system/src/main/resources/mapper/course/FsCourseAnswerLogsMapper.xml
  23. 13 0
      fs-service-system/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml
  24. 23 0
      fs-service-system/src/main/resources/mapper/course/FsUserCourseMapper.xml
  25. 232 0
      fs-service-system/src/main/resources/mapper/qw/QwWatchLogExMapper.xml

+ 0 - 1
fs-admin/src/main/java/com/fs/task/FsCourseTask.java

@@ -26,7 +26,6 @@ public class FsCourseTask {
         fsCourseWatchLogService.addCourseWatchLogDayNew();
     }
 
-
     /**
      * 企微任务定时更新
      * @throws Exception

+ 64 - 0
fs-admin/src/main/java/com/fs/task/qw/FsCourseTask.java

@@ -0,0 +1,64 @@
+package com.fs.task.qw;
+
+import com.fs.course.service.IFsCourseWatchLogService;
+import com.fs.qw.service.IQwWorkTaskService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 后台统计相关 定时任务
+ */
+@Slf4j
+@Service("qwFsCourseTask")
+public class FsCourseTask {
+    @Autowired
+    private IFsCourseWatchLogService fsCourseWatchLogService;
+    @Autowired
+    private IQwWorkTaskService qwWorkTaskService;
+
+    /**
+     * 添加企微观看日志
+     * @throws Exception
+     */
+    public void addQwWatchLog() throws Exception
+    {
+        fsCourseWatchLogService.addCourseWatchLogDay();
+    }
+
+    /**
+     * 企微任务定时更新
+     * @throws Exception
+     */
+    public void qwWorkTask1() throws Exception
+    {
+        qwWorkTaskService.addQwWorkByCourse4();
+        qwWorkTaskService.addQwWorkByCourseLastTime();
+    }
+    /**
+     * 企微待看课和先导课
+     * @throws Exception
+     */
+    public void qwWorkTask2() throws Exception
+    {
+        qwWorkTaskService.addQwWorkByCourse();
+        qwWorkTaskService.addQwWorkByFirstCourse();
+    }
+    /**
+     * 用户大小转
+     * @throws Exception
+     */
+    public void qwWorkTask3() throws Exception
+    {
+        qwWorkTaskService.addQwWorkByConversionDay();
+    }
+    /**
+     * 删除过期数据
+     * @throws Exception
+     */
+    public void qwWorkTask4() throws Exception
+    {
+        qwWorkTaskService.delQwWorkTaskByOver();
+    }
+
+}

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

@@ -34,7 +34,7 @@ server:
 # 日志配置
 logging:
   level:
-    com.fs: info
+    com.fs: debug
     org.springframework: warn
 # Spring配置
 spring:

+ 80 - 0
fs-common/src/main/java/com/fs/common/utils/PhoneUtil.java

@@ -0,0 +1,80 @@
+package com.fs.common.utils;
+
+import com.fs.common.utils.ParseUtils;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.SecretKeySpec;
+import java.util.Base64;
+
+public class PhoneUtil {
+
+    public static String encryptPhone(String text) {
+        String encryptedText=null;
+        try {
+            SecretKeySpec secretKey = new SecretKeySpec("AESAabCdeREssREA".getBytes(), "AES");
+            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
+            // Encryption
+            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
+            byte[] encryptedBytes = cipher.doFinal(text.getBytes());
+            encryptedText = Base64.getEncoder().encodeToString(encryptedBytes);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return encryptedText;
+    }
+    /**
+    * 解密
+    */
+    public static String decryptPhone(String encryptedText) {
+        String text=null;
+        try {
+            SecretKeySpec secretKey = new SecretKeySpec("AESAabCdeREssREA".getBytes(), "AES");
+            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
+            cipher.init(Cipher.DECRYPT_MODE, secretKey);
+            byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
+            text = new String(decryptedBytes);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return text;
+    }
+    /**
+    * 解密加*
+    */
+    public static String decryptPhoneMk(String encryptedText) {
+        String text=null;
+        try {
+            SecretKeySpec secretKey = new SecretKeySpec("AESAabCdeREssREA".getBytes(), "AES");
+            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
+            cipher.init(Cipher.DECRYPT_MODE, secretKey);
+            byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
+            text = new String(decryptedBytes);
+            text =text.replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2");
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return text;
+    }
+
+    public static String decryptAutoPhoneMk(String encryptedText) {
+        String text=null;
+        if (encryptedText!=null&&encryptedText!="") {
+            if (encryptedText.length()>11){
+                try {
+                    SecretKeySpec secretKey = new SecretKeySpec("AESAabCdeREssREA".getBytes(), "AES");
+                    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
+                    cipher.init(Cipher.DECRYPT_MODE, secretKey);
+                    byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
+                    text = new String(decryptedBytes);
+                    text =text.replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2");
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }else {
+                text =  ParseUtils.parsePhone(encryptedText);
+            }
+        }
+
+        return text;
+    }
+}

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

@@ -1,6 +1,7 @@
 package com.fs.course.controller;
 
 import com.fs.common.annotation.Log;
+import com.fs.common.constant.HttpStatus;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.page.TableDataInfo;
@@ -13,6 +14,7 @@ import com.fs.course.service.IFsCourseAnswerLogsService;
 import com.fs.course.vo.FsCourseAnswerLogsListVO;
 import com.fs.common.annotation.Log;
 import com.fs.core.web.service.TokenService;
+import com.github.pagehelper.PageInfo;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -59,7 +61,6 @@ public class FsCourseAnswerLogsController extends BaseController
     @GetMapping("/myList")
     public TableDataInfo myList(FsCourseAnswerLogsParam param)
     {
-        startPage();
 
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         param.setCompanyId( loginUser.getCompany().getCompanyId());
@@ -69,7 +70,14 @@ public class FsCourseAnswerLogsController extends BaseController
         }
 
         List<FsCourseAnswerLogsListVO> list = fsCourseAnswerLogsService.selectFsCourseAnswerLogsListVONew(param);
-        return getDataTable(list);
+
+        TableDataInfo rspData = new TableDataInfo();
+        rspData.setCode(HttpStatus.SUCCESS);
+        rspData.setMsg("查询成功");
+        rspData.setRows(list);
+        rspData.setTotal(fsCourseAnswerLogsService.selectFsCourseAnswerLogsListVONewCount(param));
+
+        return rspData;
     }
     /**
      * 导出答题日志列表

+ 3 - 3
fs-company/src/main/java/com/fs/course/controller/FsCourseWatchLogController.java

@@ -62,7 +62,7 @@ public class FsCourseWatchLogController extends BaseController
     {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         param.setCompanyId( loginUser.getCompany().getCompanyId());
-        List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogListVO(param);
+        List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogListVONew(param);
         TableDataInfo rspData = new TableDataInfo();
         rspData.setCode(HttpStatus.SUCCESS);
         rspData.setMsg("查询成功");
@@ -145,7 +145,7 @@ public class FsCourseWatchLogController extends BaseController
         if (param.getSTime()==null||param.getETime()==null){
             return getDataTable(new ArrayList<>());
         }
-        List<FsCourseOverVO> list = fsCourseWatchLogService.selectFsCourseWatchLogOverStatisticsListVO(param);
+        List<FsCourseOverVO> list = fsCourseWatchLogService.selectFsCourseWatchLogOverStatisticsListVONew(param);
         return getDataTable(list);
     }
     @GetMapping("/watchLogStatisticsExport")
@@ -187,7 +187,7 @@ public class FsCourseWatchLogController extends BaseController
     {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         param.setCompanyId( loginUser.getCompany().getCompanyId());
-        List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogListVO(param);
+        List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogListVONew(param);
         TableDataInfo rspData = new TableDataInfo();
         rspData.setCode(HttpStatus.SUCCESS);
         rspData.setMsg("查询成功");

+ 153 - 0
fs-company/src/main/java/com/fs/course/controller/qw/QwFsCourseAnswerLogsController.java

@@ -0,0 +1,153 @@
+package com.fs.course.controller.qw;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.core.security.LoginUser;
+import com.fs.core.web.service.TokenService;
+import com.fs.course.param.FsCourseAnswerLogsParam;
+import com.fs.course.service.IFsCourseAnswerLogsService;
+import com.fs.course.vo.FsCourseAnswerLogsListVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+import static com.fs.common.utils.PhoneUtil.encryptPhone;
+
+/**
+ * 答题日志Controller
+ *
+ * @author fs
+ * @date 2024-10-26
+ */
+@RestController
+@RequestMapping("/qw/course/courseAnswerLog")
+public class QwFsCourseAnswerLogsController extends BaseController
+{
+    @Autowired
+    private IFsCourseAnswerLogsService fsCourseAnswerLogsService;
+
+    @Autowired
+    private TokenService tokenService;
+    /**
+     * 查询答题日志列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseAnswerLog:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsCourseAnswerLogsParam param)
+    {
+        startPage();
+        if (param.getPhoneMk() != null && param.getPhoneMk() != "") {
+            param.setPhone(encryptPhone(param.getPhoneMk()));
+        }
+
+        List<FsCourseAnswerLogsListVO> list = fsCourseAnswerLogsService.selectFsCourseAnswerLogsListVO(param);
+        return getDataTable(list);
+    }
+
+    /**
+     * 查询答题日志列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseAnswerLog:myList')")
+    @GetMapping("/myList")
+    public TableDataInfo myList(FsCourseAnswerLogsParam param)
+    {
+        startPage();
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setCompanyId( loginUser.getCompany().getCompanyId());
+
+        if (param.getPhoneMk() != null && param.getPhoneMk() != "") {
+            param.setPhone(encryptPhone(param.getPhoneMk()));
+        }
+
+        List<FsCourseAnswerLogsListVO> list = fsCourseAnswerLogsService.selectFsCourseAnswerLogsListVO(param);
+        return getDataTable(list);
+    }
+    /**
+     * 导出答题日志列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseAnswerLog:export')")
+    @Log(title = "答题日志", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsCourseAnswerLogsParam param)
+    {
+
+        if (param.getPhoneMk() != null && param.getPhoneMk() != "") {
+            param.setPhone(encryptPhone(param.getPhoneMk()));
+        }
+        List<FsCourseAnswerLogsListVO> list = fsCourseAnswerLogsService.selectFsCourseAnswerLogsListVO(param);
+        ExcelUtil<FsCourseAnswerLogsListVO> util = new ExcelUtil<FsCourseAnswerLogsListVO>(FsCourseAnswerLogsListVO.class);
+        return util.exportExcel(list, "答题日志数据");
+    }
+
+    /**
+     * 导出答题日志列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseAnswerLog:myExport')")
+    @Log(title = "答题日志", businessType = BusinessType.EXPORT)
+    @GetMapping("/myExport")
+    public AjaxResult myExport(FsCourseAnswerLogsParam param)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setCompanyId( loginUser.getCompany().getCompanyId());
+
+        if (param.getPhoneMk() != null && param.getPhoneMk() != "") {
+            param.setPhone(encryptPhone(param.getPhoneMk()));
+        }
+        List<FsCourseAnswerLogsListVO> list = fsCourseAnswerLogsService.selectFsCourseAnswerLogsListVO(param);
+        ExcelUtil<FsCourseAnswerLogsListVO> util = new ExcelUtil<FsCourseAnswerLogsListVO>(FsCourseAnswerLogsListVO.class);
+        return util.exportExcel(list, "答题日志数据");
+    }
+
+//    /**
+//     * 获取答题日志详细信息
+//     */
+//    @PreAuthorize("@ss.hasPermi('course:courseAnswerLog:query')")
+//    @GetMapping(value = "/{logId}")
+//    public AjaxResult getInfo(@PathVariable("logId") Long logId)
+//    {
+//        return AjaxResult.success(fsCourseAnswerLogsService.selectFsCourseAnswerLogsByLogId(logId));
+//    }
+
+//    /**
+//     * 新增答题日志
+//     */
+//    @PreAuthorize("@ss.hasPermi('course:courseAnswerLog:add')")
+//    @Log(title = "答题日志", businessType = BusinessType.INSERT)
+//    @PostMapping
+//    public AjaxResult add(@RequestBody FsCourseAnswerLogs fsCourseAnswerLogs)
+//    {
+//        return toAjax(fsCourseAnswerLogsService.insertFsCourseAnswerLogs(fsCourseAnswerLogs));
+//    }
+//
+//    /**
+//     * 修改答题日志
+//     */
+//    @PreAuthorize("@ss.hasPermi('course:courseAnswerLog:edit')")
+//    @Log(title = "答题日志", businessType = BusinessType.UPDATE)
+//    @PutMapping
+//    public AjaxResult edit(@RequestBody FsCourseAnswerLogs fsCourseAnswerLogs)
+//    {
+//        return toAjax(fsCourseAnswerLogsService.updateFsCourseAnswerLogs(fsCourseAnswerLogs));
+//    }
+//
+//    /**
+//     * 删除答题日志
+//     */
+//    @PreAuthorize("@ss.hasPermi('course:courseAnswerLog:remove')")
+//    @Log(title = "答题日志", businessType = BusinessType.DELETE)
+//	@DeleteMapping("/{logIds}")
+//    public AjaxResult remove(@PathVariable Long[] logIds)
+//    {
+//        return toAjax(fsCourseAnswerLogsService.deleteFsCourseAnswerLogsByLogIds(logIds));
+//    }
+}

+ 267 - 0
fs-company/src/main/java/com/fs/course/controller/qw/QwFsCourseWatchLogController.java

@@ -0,0 +1,267 @@
+package com.fs.course.controller.qw;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.core.security.LoginUser;
+import com.fs.core.web.service.TokenService;
+import com.fs.course.domain.FsCourseWatchLog;
+import com.fs.course.param.FsCourseOverParam;
+import com.fs.course.param.FsCourseUserStatisticsListParam;
+import com.fs.course.param.FsCourseWatchLogListParam;
+import com.fs.course.param.FsCourseWatchLogStatisticsListParam;
+import com.fs.course.service.IFsCourseWatchLogService;
+import com.fs.course.vo.FsCourseOverVO;
+import com.fs.course.vo.FsCourseUserStatisticsListVO;
+import com.fs.course.vo.FsCourseWatchLogListVO;
+import com.fs.course.vo.FsCourseWatchLogStatisticsListVO;
+import com.fs.qw.param.QwWatchLogStatisticsListParam;
+import com.fs.qw.service.IQwWatchLogService;
+import com.fs.qw.vo.QwWatchLogAllStatisticsListVO;
+import com.fs.qw.vo.QwWatchLogStatisticsListVO;
+import com.fs.sop.mapper.SopUserLogsMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 短链课程看课记录Controller
+ *
+ * @author fs
+ * @date 2024-10-24
+ */
+@RestController
+@RequestMapping("/qw/course/courseWatchLog")
+public class QwFsCourseWatchLogController extends BaseController
+{
+    @Autowired
+    private IFsCourseWatchLogService fsCourseWatchLogService;
+    @Autowired
+    private TokenService tokenService;
+    @Autowired
+    private SopUserLogsMapper sopUserLogsMapper;
+    @Autowired
+    private IQwWatchLogService qwWatchLogService;
+    /**
+     * 查询短链课程看课记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsCourseWatchLogListParam param)
+    {
+
+//        if (param.getScheduleStartTime() != null && param.getScheduleEndTime() != null){
+//            List<String> sopUserLogsVOS = sopUserLogsMapper.selectSopUserLogsByDate(param.getScheduleStartTime(), param.getScheduleEndTime());
+//            param.setSopIds(sopUserLogsVOS);
+//            if (sopUserLogsVOS==null||sopUserLogsVOS.size()==0){
+//                return getDataTable(new ArrayList<>());
+//            }
+//        }
+        startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setCompanyId( loginUser.getCompany().getCompanyId());
+        List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogListVO(param);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:statisticsList')")
+    @GetMapping("/statisticsList")
+    public TableDataInfo statisticsList(FsCourseWatchLogStatisticsListParam param)
+    {
+        startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setCompanyId( loginUser.getCompany().getCompanyId());
+        if (param.getSTime()==null||param.getETime()==null){
+            return getDataTable(new ArrayList<>());
+        }
+        List<FsCourseWatchLogStatisticsListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogStatisticsListVO(param);
+        return getDataTable(list);
+    }
+
+    @GetMapping("/qwWatchLogStatisticsList")
+    public TableDataInfo qwWatchLogStatisticsList(QwWatchLogStatisticsListParam param)
+    {
+        startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setCompanyId( loginUser.getCompany().getCompanyId());
+        if (param.getSTime()==null||param.getETime()==null){
+            return getDataTable(new ArrayList<>());
+        }
+        List<QwWatchLogStatisticsListVO> list = qwWatchLogService.selectQwWatchLogStatisticsListVO(param);
+        return getDataTable(list);
+    }
+    @GetMapping("/myQwWatchLogStatisticsList")
+    public TableDataInfo myQwWatchLogStatisticsList(QwWatchLogStatisticsListParam param)
+    {
+        startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setCompanyId( loginUser.getCompany().getCompanyId());
+        param.setCompanyUserId(loginUser.getUser().getUserId());
+        if (param.getSTime()==null||param.getETime()==null){
+            return getDataTable(new ArrayList<>());
+        }
+        List<QwWatchLogStatisticsListVO> list = qwWatchLogService.selectQwWatchLogStatisticsListVO(param);
+        return getDataTable(list);
+    }
+
+
+    @GetMapping("/qwWatchLogAllStatisticsList")
+    public TableDataInfo qwWatchLogAllStatisticsList(QwWatchLogStatisticsListParam param)
+    {
+        startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setCompanyId( loginUser.getCompany().getCompanyId());
+        if (param.getSTime()==null||param.getETime()==null){
+            return getDataTable(new ArrayList<>());
+        }
+        List<QwWatchLogAllStatisticsListVO> list = qwWatchLogService.selectQwWatchLogAllStatisticsListVO(param);
+        return getDataTable(list);
+    }
+    @GetMapping("/myQwWatchLogAllStatisticsList")
+    public TableDataInfo myQwWatchLogAllStatisticsList(QwWatchLogStatisticsListParam param)
+    {
+        startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setCompanyId( loginUser.getCompany().getCompanyId());
+        param.setCompanyUserId(loginUser.getUser().getUserId());
+        if (param.getSTime()==null||param.getETime()==null){
+            return getDataTable(new ArrayList<>());
+        }
+        List<QwWatchLogAllStatisticsListVO> list = qwWatchLogService.selectQwWatchLogAllStatisticsListVO(param);
+        return getDataTable(list);
+    }
+    @GetMapping("/watchLogStatistics")
+    public TableDataInfo watchLogStatistics(FsCourseOverParam param)
+    {
+        startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setCompanyId( loginUser.getCompany().getCompanyId());
+        if (param.getSTime()==null||param.getETime()==null){
+            return getDataTable(new ArrayList<>());
+        }
+        List<FsCourseOverVO> list = fsCourseWatchLogService.selectFsCourseWatchLogOverStatisticsListVO(param);
+        return getDataTable(list);
+    }
+    @GetMapping("/watchLogStatisticsExport")
+    public AjaxResult watchLogStatisticsExport(FsCourseOverParam param)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setCompanyId( loginUser.getCompany().getCompanyId());
+        if (param.getSTime()==null||param.getETime()==null){
+            return AjaxResult.error("请选择时间");
+        }
+        List<FsCourseOverVO> list = fsCourseWatchLogService.selectFsCourseWatchLogOverStatisticsListVO(param);
+        ExcelUtil<FsCourseOverVO> util = new ExcelUtil<FsCourseOverVO>(FsCourseOverVO.class);
+        return util.exportExcel(list, "完课数据");
+    }
+
+
+    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:userStatisticsList')")
+    @GetMapping("/userStatisticsList")
+    public TableDataInfo userStatisticsList(FsCourseUserStatisticsListParam param)
+    {
+        startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setCompanyId( loginUser.getCompany().getCompanyId());
+        if (param.getSTime()==null||param.getETime()==null){
+            return getDataTable(new ArrayList<>());
+        }
+        List<FsCourseUserStatisticsListVO> list = fsCourseWatchLogService.selectFsCourseUserStatisticsListVO(param);
+        return getDataTable(list);
+    }
+
+
+
+    /**
+     * 查询短链课程看课记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:myList')")
+    @GetMapping("/myList")
+    public TableDataInfo myList(FsCourseWatchLogListParam param)
+    {
+        startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setCompanyUserId( loginUser.getUser().getUserId());
+        List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogListVO(param);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出短链课程看课记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:export')")
+    @Log(title = "短链课程看课记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsCourseWatchLogListParam param)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setCompanyId( loginUser.getCompany().getCompanyId());
+        List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogListVO(param);
+        ExcelUtil<FsCourseWatchLogListVO> util = new ExcelUtil<FsCourseWatchLogListVO>(FsCourseWatchLogListVO.class);
+        return util.exportExcel(list, "短链课程看课记录数据");
+    }
+
+    /**
+     * 导出短链课程看课记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:myExport')")
+    @Log(title = "短链课程看课记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/myExport")
+    public AjaxResult myExport(FsCourseWatchLogListParam param)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setCompanyId( loginUser.getCompany().getCompanyId());
+        List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogListVO(param);
+        ExcelUtil<FsCourseWatchLogListVO> util = new ExcelUtil<FsCourseWatchLogListVO>(FsCourseWatchLogListVO.class);
+        return util.exportExcel(list, "短链课程看课记录数据");
+    }
+    /**
+     * 获取短链课程看课记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:query')")
+    @GetMapping(value = "/{logId}")
+    public AjaxResult getInfo(@PathVariable("logId") Long logId)
+    {
+        return AjaxResult.success(fsCourseWatchLogService.selectFsCourseWatchLogByLogId(logId));
+    }
+
+    /**
+     * 新增短链课程看课记录
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:add')")
+    @Log(title = "短链课程看课记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsCourseWatchLog fsCourseWatchLog)
+    {
+        return toAjax(fsCourseWatchLogService.insertFsCourseWatchLog(fsCourseWatchLog));
+    }
+
+    /**
+     * 修改短链课程看课记录
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:edit')")
+    @Log(title = "短链课程看课记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsCourseWatchLog fsCourseWatchLog)
+    {
+        return toAjax(fsCourseWatchLogService.updateFsCourseWatchLog(fsCourseWatchLog));
+    }
+
+    /**
+     * 删除短链课程看课记录
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:remove')")
+    @Log(title = "短链课程看课记录", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{logIds}")
+    public AjaxResult remove(@PathVariable Long[] logIds)
+    {
+        return toAjax(fsCourseWatchLogService.deleteFsCourseWatchLogByLogIds(logIds));
+    }
+}

+ 3 - 3
fs-company/src/main/java/com/fs/qw/QwWorkTaskController.java → fs-company/src/main/java/com/fs/qw/qw/QwWorkTaskController.java

@@ -1,4 +1,4 @@
-package com.fs.qw;
+package com.fs.qw.qw;
 
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.fs.common.annotation.Log;
@@ -29,7 +29,7 @@ import java.util.List;
  * @date 2025-03-25
  */
 @RestController
-@RequestMapping("/qw/QwWorkTask")
+@RequestMapping("/qw/qw/QwWorkTask")
 public class QwWorkTaskController extends BaseController
 {
     @Autowired
@@ -51,7 +51,7 @@ public class QwWorkTaskController extends BaseController
         if(ObjectUtils.isNull(qwWorkTask.getCompanyUserId())) {
             qwWorkTask.setCompanyUserId(loginUser.getUser().getUserId());
         }
-        List<QwWorkTaskListVO> list = qwWorkTaskService.selectQwWorkTaskListVONew(qwWorkTask);
+        List<QwWorkTaskListVO> list = qwWorkTaskService.selectQwWorkTaskListVO(qwWorkTask);
         for (QwWorkTaskListVO qwWorkTaskListVO : list) {
             qwWorkTaskListVO.setLogs(fsCourseWatchLogMapper.selectFsCourseWatchLog7DayByExtId(qwWorkTaskListVO.getExtId()));
         }

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

@@ -34,7 +34,7 @@ server:
 # 日志配置
 logging:
   level:
-    com.fs: info
+    com.fs: debug
     org.springframework: warn
 # Spring配置
 spring:

+ 1 - 0
fs-service-system/src/main/java/com/fs/course/mapper/FsCourseAnswerLogsMapper.java

@@ -121,4 +121,5 @@ public interface FsCourseAnswerLogsMapper
     int selectErrorCountByCourseVideo(@Param("videoId") Long videoId,@Param("userId") Long userId,@Param("qwUserId") String qwUserId);
 
     List<FsCourseAnswerLogsListVO> selectFsCourseAnswerLogsListVONew(FsCourseAnswerLogsParam param);
+    Long selectFsCourseAnswerLogsListVONewCount(FsCourseAnswerLogsParam param);
 }

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

@@ -231,19 +231,7 @@ public interface FsCourseWatchLogMapper extends BaseMapper<FsCourseWatchLog> {
 
     List<FsCourseUserStatisticsListVO> selectFsCourseUserStatisticsListVO(FsCourseUserStatisticsListParam param);
 
-    @Select({"<script> " +
-            "select MIN(o.create_time) createTime,ANY_VALUE(qu.qw_user_name) qwUserName ,ext.name externalUserName,ext.create_time userCreateTime from fs_course_watch_log o LEFT JOIN qw_user qu on qu.id=o.qw_user_id LEFT JOIN qw_external_contact ext ON ext.id =  o.qw_external_contact_id where log_type=2 and o.company_id=#{companyId} " +
-            "<if test= 'sTime != null '> " +
-            "       and DATE(o.create_time) &gt;= DATE(#{sTime})\n" +
-            "</if>\n" +
-            "<if test='eTime != null '> " +
-            "      and DATE(o.create_time) &lt;= DATE(#{eTime})\n" +
-            "</if>" +
-            "<if test ='nickName !=null and nickName!=\"\"'>\n" +
-            "   and qu.qw_user_name like concat( #{nickName}, '%')\n" +
-            "</if>"+
-            " GROUP BY o.qw_external_contact_id"+
-            "</script>"})
+
     List<FsCourseOverVO> selectFsCourseWatchLogOverStatisticsListVO(FsCourseOverParam param);
 
 

+ 1 - 20
fs-service-system/src/main/java/com/fs/course/mapper/FsUserCourseMapper.java

@@ -198,26 +198,7 @@ public interface FsUserCourseMapper
             "where v.video_id = #{videoId}")
     FsUserCourseVideoH5DVO selectFsUserCourseVideoH5DVOByVideoId(@Param("videoId") Long videoId);
 
-    @Select({"<script> " +
-            "select c.*,cc.cate_name,ucc.cate_name as sub_cate_name from fs_user_course  c " +
-            " left join fs_user_course_category cc on c.cate_id=cc.cate_id" +
-            " left join fs_user_course_category ucc on  ucc.cate_id = c.sub_cate_id " +
-            "where c.is_del = 0 and " +
-            " FIND_IN_SET(#{maps.companyId}, company_ids) " +
-            "<if test = ' maps.cateId !=null '> " +
-            "and (cc.cate_id =#{maps.cateId} or cc.pid=#{maps.cateId} )" +
-            "</if>" +
-            "<if test = ' maps.courseName!=null and maps.courseName != \"\" '> " +
-            "and c.course_name like concat('%', #{maps.courseName}, '%') " +
-            "</if>" +
-            "<if test = ' maps.isPrivate !=null '> " +
-            "and c.is_private = #{maps.isPrivate} " +
-            "</if>" +
-            "<if test = ' maps.isShow !=null '> " +
-            "and c.is_show = #{maps.isShow} " +
-            "</if>" +
-            " order by c.course_id  "+
-            "</script>"})
+
     List<FsUserCourseListPVO> selectFsUserCourseListCompanyPVO(@Param("maps")FsUserCourseParam fsUserCourse);
 
     @Select("select course_id dict_value, course_name dict_label,img_url dict_imgUrl  from fs_user_course where is_del = 0 and is_private = 1" +

+ 2 - 0
fs-service-system/src/main/java/com/fs/course/param/FsCourseAnswerLogsParam.java

@@ -58,4 +58,6 @@ public class FsCourseAnswerLogsParam  extends BaseEntity  {
 
     private String sTime;
 
+    private Long pageNum;
+    private Long pageSize;
 }

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

@@ -31,6 +31,7 @@ public interface IFsCourseAnswerLogsService
     public List<FsCourseAnswerLogs> selectFsCourseAnswerLogsList(FsCourseAnswerLogs fsCourseAnswerLogs);
     public List<FsCourseAnswerLogsListVO> selectFsCourseAnswerLogsListVO(FsCourseAnswerLogsParam param);
     public List<FsCourseAnswerLogsListVO> selectFsCourseAnswerLogsListVONew(FsCourseAnswerLogsParam param);
+    public Long selectFsCourseAnswerLogsListVONewCount(FsCourseAnswerLogsParam param);
 
     /**
      * 新增答题日志

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

@@ -82,6 +82,7 @@ public interface IFsCourseWatchLogService extends IService<FsCourseWatchLog> {
 
 
     List<FsCourseWatchLogListVO> selectFsCourseWatchLogListVO(FsCourseWatchLogListParam param);
+    List<FsCourseWatchLogListVO> selectFsCourseWatchLogListVONew(FsCourseWatchLogListParam param);
     Long selectFsCourseWatchLogListVOCount(FsCourseWatchLogListParam param);
     List<FsCourseWatchLogListVO> selectFsCourseWatchLogListVOExport(FsCourseWatchLogListParam param);
 
@@ -99,6 +100,7 @@ public interface IFsCourseWatchLogService extends IService<FsCourseWatchLog> {
     List<FsCourseUserStatisticsListVO> selectFsCourseUserStatisticsListVO(FsCourseUserStatisticsListParam param);
 
     List<FsCourseOverVO> selectFsCourseWatchLogOverStatisticsListVO(FsCourseOverParam param);
+    List<FsCourseOverVO> selectFsCourseWatchLogOverStatisticsListVONew(FsCourseOverParam param);
 
     void addCourseWatchLogDayNew();
 

+ 5 - 0
fs-service-system/src/main/java/com/fs/course/service/impl/FsCourseAnswerLogsServiceImpl.java

@@ -129,6 +129,11 @@ public class FsCourseAnswerLogsServiceImpl implements IFsCourseAnswerLogsService
         return data;
     }
 
+    @Override
+    public Long selectFsCourseAnswerLogsListVONewCount(FsCourseAnswerLogsParam param) {
+        return fsCourseAnswerLogsMapper.selectFsCourseAnswerLogsListVONewCount(param);
+    }
+
     /**
      * 新增答题日志
      *

+ 66 - 4
fs-service-system/src/main/java/com/fs/course/service/impl/FsCourseWatchLogServiceImpl.java

@@ -230,6 +230,67 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
 
     @Override
     public List<FsCourseWatchLogListVO> selectFsCourseWatchLogListVO(FsCourseWatchLogListParam param) {
+        if(ObjectUtils.isNull(param.getPageNum())){
+            param.setPageNum(1L);
+        }
+        if(ObjectUtils.isNull(param.getPageSize())){
+            param.setPageSize(10L);
+        }
+        List<FsCourseWatchLogListVO> list = fsCourseWatchLogMapper.selectFsCourseWatchLogListVO(param);
+        for (FsCourseWatchLogListVO item : list) {
+            // 项目
+            if(ObjectUtils.isNotNull(item.getProject())) {
+                String sysCourseProject = DictUtils.getDictLabel("sys_course_project", String.valueOf(item.getProject()));
+                if(StringUtils.isNotBlank(sysCourseProject)){
+                    item.setProjectName(sysCourseProject);
+                }
+            }
+            // 用户名
+            if(ObjectUtils.isNotNull(item.getUserId())) {
+                FsUser fsUser = fsUserCacheService.selectFsUserById(item.getUserId());
+                if(ObjectUtils.isNotNull(fsUser)){
+                    item.setUserName(String.format("%s_%d",fsUser.getNickname(),fsUser.getUserId()));
+                    item.setFsNickName(fsUser.getNickname());
+                    item.setFsAvatar(fsUser.getAvatar());
+                }
+            }
+            // 公司名
+            if(ObjectUtils.isNotNull(item.getCompanyId())){
+                Company company = companyCacheService.selectCompanyById(Long.valueOf(item.getCompanyId()));
+                if(ObjectUtils.isNotNull(company)){
+                    item.setCompanyName(String.format("%s_%d", company.getCompanyName(), company.getCompanyId()));
+                }
+            }
+
+            // 销售名
+            if(ObjectUtils.isNotNull(item.getCompanyUserId())){
+                CompanyUser companyUser = companyUserCacheService.selectCompanyUserById(item.getCompanyUserId());
+                if(ObjectUtils.isNotNull(companyUser)){
+                    item.setCompanyUserName(String.format("%s_%d", companyUser.getNickName(), companyUser.getUserId()));
+                }
+            }
+
+            // 课程
+            if(ObjectUtils.isNotNull(item.getCourseId())){
+                FsUserCourse course = fsUserCourseCacheService.selectFsUserCourseByCourseId(item.getCourseId());
+                if(ObjectUtils.isNotNull(course)){
+                    item.setCourseName(course.getCourseName());
+                }
+            }
+            // 小节
+            if(ObjectUtils.isNotNull(item.getVideoId())){
+                FsUserCourseVideo fsUserCourseVideo = fsUserCourseVideoCacheService.selectFsUserCourseVideoByVideoId(item.getVideoId());
+                if(ObjectUtils.isNotNull(fsUserCourseVideo)){
+                    item.setVideoName(fsUserCourseVideo.getTitle());
+                }
+            }
+
+        }
+        return list;
+    }
+
+    @Override
+    public List<FsCourseWatchLogListVO> selectFsCourseWatchLogListVONew(FsCourseWatchLogListParam param) {
         if(ObjectUtils.isNull(param.getPageNum())){
             param.setPageNum(1L);
         }
@@ -535,6 +596,11 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
 
     @Override
     public List<FsCourseOverVO> selectFsCourseWatchLogOverStatisticsListVO(FsCourseOverParam param) {
+        return fsCourseWatchLogMapper.selectFsCourseWatchLogOverStatisticsListVO(param);
+    }
+
+    @Override
+    public List<FsCourseOverVO> selectFsCourseWatchLogOverStatisticsListVONew(FsCourseOverParam param) {
         QueryWrapper<FsCourseWatchLog> queryWrapper = new QueryWrapper<>();
         queryWrapper.select("MIN(create_time) as createTime","company_user_id as companyUserId");
         if(param.getCompanyId() != null) {
@@ -690,9 +756,6 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
                         qwWatchLog.setStatus(fsCourseWatchLog.getLogType()==3?0:fsCourseWatchLog.getLogType()==2?2:1);
                         qwWatchLog.setProject(project);
                         qwWatchLog.setCreateTime(fsCourseWatchLog.getCreateTime());
-                        qwWatchLog.setCompanyId(fsCourseWatchLog.getCompanyId());
-                        qwWatchLog.setCompanyUserId(fsCourseWatchLog.getCompanyUserId());
-                        qwWatchLog.setFsUserId(fsCourseWatchLog.getUserId());
                         QwWatchLogs.add(qwWatchLog);
                     }
                     if (!QwWatchLogs.isEmpty()){
@@ -706,7 +769,6 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
             }
         }
 
-
     }
 
 

+ 4 - 4
fs-service-system/src/main/java/com/fs/course/vo/FsCourseOverVO.java

@@ -10,10 +10,10 @@ import java.util.Date;
 public class FsCourseOverVO {
 
 
-//    @Excel(name = "企微客户")
-//    private String qwUserName;
-//    @Excel(name = "企业微信员工名称")
-//    private String externalUserName;
+    @Excel(name = "企微客户")
+    private String qwUserName;
+    @Excel(name = "企业微信员工名称")
+    private String externalUserName;
     @Excel(name = "用户名")
     private String userName;
 

+ 2 - 2
fs-service-system/src/main/java/com/fs/course/vo/FsCourseWatchLogStatisticsListVO.java

@@ -30,8 +30,8 @@ public class FsCourseWatchLogStatisticsListVO {
     private String type3;
     @Excel(name = "看课中断")
     private String type4;
-//    @Excel(name = "企业微信员工名称")
-//    private String qwUserName;
+    @Excel(name = "企业微信员工名称")
+    private String qwUserName;
 
     private Long userId;
     @Excel(name = "员工名称")

+ 222 - 0
fs-service-system/src/main/java/com/fs/qw/mapper/QwWatchLogExMapper.java

@@ -0,0 +1,222 @@
+package com.fs.qw.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.qw.domain.QwWatchLog;
+import com.fs.qw.param.QwWatchLogStatisticsListParam;
+import com.fs.qw.vo.QwWatchLogAllStatisticsListVO;
+import com.fs.qw.vo.QwWatchLogStatisticsListVO;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 企微看课Mapper接口
+ *
+ * @author fs
+ * @date 2025-03-08
+ */
+public interface QwWatchLogExMapper extends BaseMapper<QwWatchLog>{
+    /**
+     * 查询企微看课
+     *
+     * @param id 企微看课主键
+     * @return 企微看课
+     */
+    QwWatchLog selectQwWatchLogById(Long id);
+
+    /**
+     * 查询企微看课列表
+     *
+     * @param qwWatchLog 企微看课
+     * @return 企微看课集合
+     */
+    List<QwWatchLog> selectQwWatchLogList(QwWatchLog qwWatchLog);
+
+    /**
+     * 新增企微看课
+     *
+     * @param qwWatchLog 企微看课
+     * @return 结果
+     */
+    int insertQwWatchLog(QwWatchLog qwWatchLog);
+    void insertQwWatchLogBatch(@Param("watchLogs")List<QwWatchLog> qwWatchLog);
+    /**
+     * 修改企微看课
+     *
+     * @param qwWatchLog 企微看课
+     * @return 结果
+     */
+    int updateQwWatchLog(QwWatchLog qwWatchLog);
+
+    /**
+     * 删除企微看课
+     *
+     * @param id 企微看课主键
+     * @return 结果
+     */
+    int deleteQwWatchLogById(Long id);
+
+    /**
+     * 批量删除企微看课
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteQwWatchLogByIds(Long[] ids);
+    @Select({"<script> " +
+            "SELECT\n" +
+            "    qec.qw_user_id id,\n" +
+            "    qu.qw_user_name AS qw_user_name, \n" +
+            "    DATE(qec.create_time) AS create_time, \n" +
+            "    COUNT(1) AS line,\n" +
+            "    COUNT(CASE WHEN qec.is_interact = 1 THEN 1 END) AS interact,\n" +
+            "    COUNT(CASE WHEN qec.`level` = 1 THEN 1 END) AS A,\n" +
+            "    COUNT(CASE WHEN qec.`level` = 2 THEN 1 END) AS B,\n" +
+            "    COUNT(CASE WHEN qec.`level` = 3 THEN 1 END) AS C,\n" +
+            "    COUNT(CASE WHEN qec.`level` = 4 THEN 1 END) AS D,\n" +
+            "    COUNT(CASE WHEN qec.fs_user_id IS NOT NULL THEN 1 END) AS sign,\n" +
+            "    COUNT(CASE WHEN qec.`status` =3 THEN 1 END) AS los,\n" +
+            "    COUNT(CASE WHEN qec.`status` IN (4, 5,6) THEN 1 END) AS del\n" +
+            "FROM\n" +
+            "    qw_external_contact qec\n" +
+            "JOIN\n" +
+            "    qw_user qu ON qec.qw_user_id = qu.id \n" +
+            "WHERE\n" +
+            "    DATE(qec.create_time) &gt;= DATE(#{sTime}) and  DATE(qec.create_time) &lt;= DATE(#{eTime}) and qec.company_id =#{companyId} " +
+            "<if test ='nickName !=null and nickName!=\"\"'>\n" +
+            "   and qu.qw_user_name like concat( #{nickName}, '%')\n" +
+            "</if>" +
+            "<if test ='ids !=null and ids!=\"\"'>\n" +
+            "   and qec.qw_user_id in (${ids})\n" +
+            "</if>" +
+            "GROUP BY\n" +
+            "    qec.qw_user_id, DATE(qec.create_time) \n" +
+            "ORDER BY\n" +
+            "    DATE(qec.create_time) "+
+            "</script>"})
+    List<QwWatchLogStatisticsListVO> selectQwExtCountByDayAnd(QwWatchLogStatisticsListParam param);
+    @Select("select \n" +
+            "COUNT(CASE WHEN day = 0 and status in (1,2) THEN 1 END) AS firstOnline,\n" +
+            "COUNT(CASE WHEN day = 0 and status=2 THEN 1 END) AS firstOver,\n" +
+            "COUNT(CASE WHEN day = 1 and status in (1,2) THEN 1 END) AS d1Online,\n" +
+            "COUNT(CASE WHEN day = 1 and status=2 THEN 1 END) AS d1Over\n" +
+            " from qw_watch_log where qw_user_id=#{id} and DATE(line_time) = DATE(#{createTime})")
+    QwWatchLogStatisticsListVO selectQwWatchLogByQwUserId(@Param("id")Long id,@Param("createTime") Date createTime);
+
+    List<QwWatchLogStatisticsListVO> selectQwWatchLogByCompanyUserId(
+            @Param("companyId") Long companyId,
+            @Param("companyUserId") Long companyUserId,
+                                                                     @Param("sTime") Date sTime,
+                                                                     @Param("dTime") Date dTime,
+                                                                     @Param("project") Long project,
+                                                                     @Param("courseId") Long courseId,
+                                                                     @Param("videoId") Long videoId
+    );
+
+
+    @Select("SELECT count(1) from qw_watch_log where ext_id=#{id} and `day`=0 ")
+    int selectQwWatchLogIsFirst(Long id);
+
+    @Select("SELECT count(1) from qw_watch_log where fs_user_id=#{userId} and `day`=0")
+    int selectQwWatchLogIsFirstByUserId(Long userId);
+
+    @Select("select \n" +
+            "COUNT(CASE WHEN day = 0 and status in (1,2) THEN 1 END) AS firstOnline,\n" +
+            "COUNT(CASE WHEN day = 0 and status=2 THEN 1 END) AS firstOver,\n" +
+            "COUNT(CASE WHEN day = 1 and status in (1,2) THEN 1 END) AS d1Online,\n" +
+            "COUNT(CASE WHEN day = 1 and status=2 THEN 1 END) AS d1Over,\n" +
+            "COUNT(CASE WHEN day = 2 and status in (1,2) THEN 1 END) AS d2Online,\n" +
+            "COUNT(CASE WHEN day = 2 and status=2 THEN 1 END) AS d2Over,\n" +
+            "COUNT(CASE WHEN day = 3 and status in (1,2) THEN 1 END) AS d3Online,\n" +
+            "COUNT(CASE WHEN day = 3 and status=2 THEN 1 END) AS d3Over,\n" +
+            "COUNT(CASE WHEN day = 4 and status in (1,2) THEN 1 END) AS d4Online,\n" +
+            "COUNT(CASE WHEN day = 4 and status=2 THEN 1 END) AS d4Over,\n" +
+            "COUNT(CASE WHEN day = 5 and status in (1,2) THEN 1 END) AS d5Online,\n" +
+            "COUNT(CASE WHEN day = 5 and status=2 THEN 1 END) AS d5Over,\n" +
+            "COUNT(CASE WHEN day = 6 and status in (1,2) THEN 1 END) AS d6Online,\n" +
+            "COUNT(CASE WHEN day = 6 and status=2 THEN 1 END) AS d6Over,\n" +
+            "COUNT(CASE WHEN day = 7 and status in (1,2) THEN 1 END) AS d7Online,\n" +
+            "COUNT(CASE WHEN day = 7 and status=2 THEN 1 END) AS d7Over,\n" +
+            "COUNT(CASE WHEN day = 8 and status in (1,2) THEN 1 END) AS d8Online,\n" +
+            "COUNT(CASE WHEN day = 8 and status=2 THEN 1 END) AS d8Over,\n" +
+            "COUNT(CASE WHEN day = 9 and status in (1,2) THEN 1 END) AS d9Online,\n" +
+            "COUNT(CASE WHEN day = 9 and status=2 THEN 1 END) AS d9Over,\n" +
+            "COUNT(CASE WHEN day = 10 and status in (1,2) THEN 1 END) AS d10Online,\n" +
+            "COUNT(CASE WHEN day = 10 and status=2 THEN 1 END) AS d10Over,\n" +
+            "COUNT(CASE WHEN day = 11 and status in (1,2) THEN 1 END) AS d11Online,\n" +
+            "COUNT(CASE WHEN day = 11 and status=2 THEN 1 END) AS d11Over,\n" +
+            "COUNT(CASE WHEN day = 12 and status in (1,2) THEN 1 END) AS d12Online,\n" +
+            "COUNT(CASE WHEN day = 12 and status=2 THEN 1 END) AS d12Over,\n" +
+            "COUNT(CASE WHEN day = 13 and status in (1,2) THEN 1 END) AS d13Online,\n" +
+            "COUNT(CASE WHEN day = 13 and status=2 THEN 1 END) AS d13Over,\n" +
+            "COUNT(CASE WHEN day = 14 and status in (1,2) THEN 1 END) AS d14Online,\n" +
+            "COUNT(CASE WHEN day = 14 and status=2 THEN 1 END) AS d14Over,\n" +
+            "COUNT(CASE WHEN day = 15 and status in (1,2) THEN 1 END) AS d15Online,\n" +
+            "COUNT(CASE WHEN day = 15 and status=2 THEN 1 END) AS d15Over,\n" +
+            "COUNT(CASE WHEN day = 16 and status in (1,2) THEN 1 END) AS d16Online,\n" +
+            "COUNT(CASE WHEN day = 16 and status=2 THEN 1 END) AS d16Over,\n" +
+            "COUNT(CASE WHEN day = 17 and status in (1,2) THEN 1 END) AS d17Online,\n" +
+            "COUNT(CASE WHEN day = 17 and status=2 THEN 1 END) AS d17Over,\n" +
+            "COUNT(CASE WHEN day = 18 and status in (1,2) THEN 1 END) AS d18Online,\n" +
+            "COUNT(CASE WHEN day = 18 and status=2 THEN 1 END) AS d18Over,\n" +
+            "COUNT(CASE WHEN day = 19 and status in (1,2) THEN 1 END) AS d19Online,\n" +
+            "COUNT(CASE WHEN day = 19 and status=2 THEN 1 END) AS d19Over,\n" +
+            "COUNT(CASE WHEN day = 20 and status in (1,2) THEN 1 END) AS d20Online,\n" +
+            "COUNT(CASE WHEN day = 20 and status=2 THEN 1 END) AS d20Over,\n" +
+            "COUNT(CASE WHEN day = 21 and status in (1,2) THEN 1 END) AS d21Online,\n" +
+            "COUNT(CASE WHEN day = 21 and status=2 THEN 1 END) AS d21Over,\n" +
+            "COUNT(CASE WHEN day = 22 and status in (1,2) THEN 1 END) AS d22Online,\n" +
+            "COUNT(CASE WHEN day = 22 and status=2 THEN 1 END) AS d22Over,\n" +
+            "COUNT(CASE WHEN day = 23 and status in (1,2) THEN 1 END) AS d23Online,\n" +
+            "COUNT(CASE WHEN day = 23 and status=2 THEN 1 END) AS d23Over,\n" +
+            "COUNT(CASE WHEN day = 24 and status in (1,2) THEN 1 END) AS d24Online,\n" +
+            "COUNT(CASE WHEN day = 24 and status=2 THEN 1 END) AS d24Over,\n" +
+            "COUNT(CASE WHEN day = 25 and status in (1,2) THEN 1 END) AS d25Online,\n" +
+            "COUNT(CASE WHEN day = 25 and status=2 THEN 1 END) AS d25Over,\n" +
+            "COUNT(CASE WHEN day = 26 and status in (1,2) THEN 1 END) AS d26Online,\n" +
+            "COUNT(CASE WHEN day = 26 and status=2 THEN 1 END) AS d26Over,\n" +
+            "COUNT(CASE WHEN day = 27 and status in (1,2) THEN 1 END) AS d27Online,\n" +
+            "COUNT(CASE WHEN day = 27 and status=2 THEN 1 END) AS d27Over,\n" +
+            "COUNT(CASE WHEN day = 28 and status in (1,2) THEN 1 END) AS d28Online,\n" +
+            "COUNT(CASE WHEN day = 28 and status=2 THEN 1 END) AS d28Over,\n" +
+            "COUNT(CASE WHEN day = 29 and status in (1,2) THEN 1 END) AS d29Online,\n" +
+            "COUNT(CASE WHEN day = 29 and status=2 THEN 1 END) AS d29Over,\n" +
+            "COUNT(CASE WHEN day = 30 and status in (1,2) THEN 1 END) AS d30Online,\n" +
+            "COUNT(CASE WHEN day = 30 and status=2 THEN 1 END) AS d30Over" +
+            " from qw_watch_log where qw_user_id=#{id} and DATE(line_time) = DATE(#{createTime})")
+    QwWatchLogAllStatisticsListVO selectQwWatchLogAllStatisticsListVO(@Param("id")Long id,@Param("createTime") Date createTime);
+
+
+    List<QwWatchLogAllStatisticsListVO> selectQwWatchLogAllStatisticsListVONew(@Param("companyUserId")Long companyUserId,
+                                                                               @Param("companyId")Long companyId,
+                                                                               @Param("sDate") Date sDate, @Param("eDate") Date eDate,
+                                                                               @Param("project") Long project,
+                                                                               @Param("courseId") Long courseId,
+                                                                               @Param("videoId") Long videoId);
+    @Select({"<script> " +
+            "SELECT\n" +
+            "    qec.qw_user_id id,\n" +
+            "    qu.qw_user_name AS qw_user_name, \n" +
+            "    DATE(qec.create_time) AS create_time, \n" +
+            "    COUNT(1) AS line\n" +
+            "FROM\n" +
+            "    qw_external_contact qec\n" +
+            "JOIN\n" +
+            "    qw_user qu ON qec.qw_user_id = qu.id \n" +
+            "WHERE\n" +
+            "    DATE(qec.create_time) &gt;= DATE(#{sTime}) and  DATE(qec.create_time) &lt;= DATE(#{eTime}) and qec.company_id =#{companyId} " +
+            "<if test ='ids !=null and ids!=\"\"'>\n" +
+            "   and qec.qw_user_id in (${ids})\n" +
+            "</if>" +
+            "<if test ='nickName !=null and nickName!=\"\"'>\n" +
+            "   and qu.qw_user_name like concat( #{nickName}, '%')\n" +
+            "</if>" +
+            "GROUP BY\n" +
+            "    qec.qw_user_id, DATE(qec.create_time) \n" +
+            "ORDER BY\n" +
+            "    DATE(qec.create_time) "+
+            "</script>"})
+    List<QwWatchLogAllStatisticsListVO> selectQwExtCountByDayAndLine(QwWatchLogStatisticsListParam param);
+}

+ 27 - 0
fs-service-system/src/main/resources/mapper/course/FsCourseAnswerLogsMapper.xml

@@ -62,6 +62,33 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="sTime != null and eTime != null">
                 AND cal.create_time BETWEEN #{sTime} AND #{eTime}
             </if>
+
+        </where>
+
+    </select>
+    <select id="selectFsCourseAnswerLogsListVONewCount" resultType="java.lang.Long">
+        select count(1) from fs_course_answer_logs cal
+        left join fs_user_course uc on cal.course_id=uc.course_id
+        <where>
+            <if test="courseId != null">
+                cal.course_id = #{courseId}
+            </if>
+            <if test="companyUserId != null">
+                AND cal.company_user_id = #{companyUserId}
+            </if>
+            <if test="companyId != null">
+                AND cal.company_id = #{companyId}
+            </if>
+            <if test="isRight != null">
+                AND is_right = #{isRight}
+            </if>
+            <if test="project != null">
+                AND uc.project = #{project}
+            </if>
+            <if test="sTime != null and eTime != null">
+                AND cal.create_time BETWEEN #{sTime} AND #{eTime}
+            </if>
+
         </where>
     </select>
 

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

@@ -627,4 +627,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             </if>
         </where>
     </select>
+    <select id="selectFsCourseWatchLogOverStatisticsListVO" resultType="com.fs.course.vo.FsCourseOverVO">
+        select MIN(o.create_time) createTime,ANY_VALUE(qu.qw_user_name) qwUserName ,ext.name externalUserName,ext.create_time userCreateTime from fs_course_watch_log o LEFT JOIN qw_user qu on qu.id=o.qw_user_id LEFT JOIN qw_external_contact ext ON ext.id =  o.qw_external_contact_id where log_type=2 and o.company_id=#{companyId}
+        <if test= 'sTime != null '>
+            and DATE(o.create_time) &gt;= DATE(#{sTime})
+        </if>
+        <if test='eTime != null '>
+            and DATE(o.create_time) &lt;= DATE(#{eTime})
+        </if>
+        <if test ='nickName !=null and nickName!=""'>
+            and qu.qw_user_name like concat( #{nickName}, '%')
+        </if>
+        GROUP BY o.qw_external_contact_id
+    </select>
 </mapper>

+ 23 - 0
fs-service-system/src/main/resources/mapper/course/FsUserCourseMapper.xml

@@ -313,4 +313,27 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             </otherwise>
         </choose>
     </select>
+    <select id="selectFsUserCourseListCompanyPVO" resultType="com.fs.course.vo.FsUserCourseListPVO">
+        select c.*,cc.cate_name,ucc.cate_name as sub_cate_name from fs_user_course  c
+        left join fs_user_course_category cc on c.cate_id=cc.cate_id
+        left join fs_user_course_category ucc on  ucc.cate_id = c.sub_cate_id
+        where c.is_del = 0 and
+        FIND_IN_SET(#{maps.companyId}, company_ids)
+        <if test = ' maps.cateId !=null '>
+            and (cc.cate_id =#{maps.cateId} or cc.pid=#{maps.cateId} )
+        </if>
+        <if test = ' maps.courseName!=null and maps.courseName != "" '>
+            and c.course_name like concat('%', #{maps.courseName}, '%')
+        </if>
+        <if test = ' maps.isPrivate !=null '>
+            and c.is_private = #{maps.isPrivate}
+        </if>
+        <if test = ' maps.isShow !=null '>
+            and c.is_show = #{maps.isShow}
+        </if>
+        <if test="maps.project != null">
+            and c.project = #{maps.project}
+        </if>
+        order by c.course_id
+    </select>
 </mapper>

+ 232 - 0
fs-service-system/src/main/resources/mapper/qw/QwWatchLogExMapper.xml

@@ -0,0 +1,232 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.qw.mapper.QwWatchLogExMapper">
+
+    <resultMap type="QwWatchLog" id="QwWatchLogResult">
+        <result property="id"    column="id"    />
+        <result property="extId"    column="ext_id"    />
+        <result property="qwUserId"    column="qw_user_id"    />
+        <result property="status"    column="status"    />
+        <result property="day"    column="day"    />
+        <result property="project"    column="project"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="lineTime"    column="line_time"    />
+    </resultMap>
+
+    <sql id="selectQwWatchLogVo">
+        select id, ext_id, qw_user_id,line_time, status, day, project, create_time from qw_watch_log_ex
+    </sql>
+
+    <select id="selectQwWatchLogList" parameterType="QwWatchLog" resultMap="QwWatchLogResult">
+        <include refid="selectQwWatchLogVo"/>
+        <where>
+            <if test="extId != null "> and ext_id = #{extId}</if>
+            <if test="qwUserId != null "> and qw_user_id = #{qwUserId}</if>
+            <if test="status != null "> and status = #{status}</if>
+            <if test="day != null "> and day = #{day}</if>
+            <if test="project != null "> and project = #{project}</if>
+        </where>
+    </select>
+
+    <select id="selectQwWatchLogById" parameterType="Long" resultMap="QwWatchLogResult">
+        <include refid="selectQwWatchLogVo"/>
+        where id = #{id}
+    </select>
+    <select id="selectQwWatchLogByCompanyUserId" resultType="com.fs.qw.vo.QwWatchLogStatisticsListVO">
+            select
+            COUNT(CASE WHEN day = 0 and status in (1,2) THEN 1 END) AS firstOnline,
+            COUNT(CASE WHEN day = 0 and status=2 THEN 1 END) AS firstOver,
+            COUNT(CASE WHEN day = 1 and status in (1,2) THEN 1 END) AS d1Online,
+            COUNT(CASE WHEN day = 1 and status=2 THEN 1 END) AS d1Over,
+            COUNT(1) AS line,project,course_id,video_id
+             from qw_watch_log_ex
+             <where>
+                 <if test="companyUserId">
+                     and company_user_id = #{companyUserId}
+                 </if>
+                 <if test="companyId">
+                     and company_id = #{companyId}
+                 </if>
+                 <if test="project != null">
+                     and project=#{project}
+                 </if>
+                 <if test="courseId != null">
+                     and course_id=#{courseId}
+                 </if>
+                 <if test="videoId != null">
+                     and video_id=#{videoId}
+                 </if>
+                 and DATE(line_time) between #{sTime} and #{dTime}
+             </where>
+            group by project,course_id,video_id
+    </select>
+    <select id="selectQwWatchLogAllStatisticsListVONew"
+            resultType="com.fs.qw.vo.QwWatchLogAllStatisticsListVO">
+            select
+            COUNT(CASE WHEN day = 0 and status in (1,2) THEN 1 END) AS firstOnline,
+            COUNT(CASE WHEN day = 0 and status=2 THEN 1 END) AS firstOver,
+            COUNT(CASE WHEN day = 1 and status in (1,2) THEN 1 END) AS d1Online,
+            COUNT(CASE WHEN day = 1 and status=2 THEN 1 END) AS d1Over,
+            COUNT(CASE WHEN day = 2 and status in (1,2) THEN 1 END) AS d2Online,
+            COUNT(CASE WHEN day = 2 and status=2 THEN 1 END) AS d2Over,
+            COUNT(CASE WHEN day = 3 and status in (1,2) THEN 1 END) AS d3Online,
+            COUNT(CASE WHEN day = 3 and status=2 THEN 1 END) AS d3Over,
+            COUNT(CASE WHEN day = 4 and status in (1,2) THEN 1 END) AS d4Online,
+            COUNT(CASE WHEN day = 4 and status=2 THEN 1 END) AS d4Over,
+            COUNT(CASE WHEN day = 5 and status in (1,2) THEN 1 END) AS d5Online,
+            COUNT(CASE WHEN day = 5 and status=2 THEN 1 END) AS d5Over,
+            COUNT(CASE WHEN day = 6 and status in (1,2) THEN 1 END) AS d6Online,
+            COUNT(CASE WHEN day = 6 and status=2 THEN 1 END) AS d6Over,
+            COUNT(CASE WHEN day = 7 and status in (1,2) THEN 1 END) AS d7Online,
+            COUNT(CASE WHEN day = 7 and status=2 THEN 1 END) AS d7Over,
+            COUNT(CASE WHEN day = 8 and status in (1,2) THEN 1 END) AS d8Online,
+            COUNT(CASE WHEN day = 8 and status=2 THEN 1 END) AS d8Over,
+            COUNT(CASE WHEN day = 9 and status in (1,2) THEN 1 END) AS d9Online,
+            COUNT(CASE WHEN day = 9 and status=2 THEN 1 END) AS d9Over,
+            COUNT(CASE WHEN day = 10 and status in (1,2) THEN 1 END) AS d10Online,
+            COUNT(CASE WHEN day = 10 and status=2 THEN 1 END) AS d10Over,
+            COUNT(CASE WHEN day = 11 and status in (1,2) THEN 1 END) AS d11Online,
+            COUNT(CASE WHEN day = 11 and status=2 THEN 1 END) AS d11Over,
+            COUNT(CASE WHEN day = 12 and status in (1,2) THEN 1 END) AS d12Online,
+            COUNT(CASE WHEN day = 12 and status=2 THEN 1 END) AS d12Over,
+            COUNT(CASE WHEN day = 13 and status in (1,2) THEN 1 END) AS d13Online,
+            COUNT(CASE WHEN day = 13 and status=2 THEN 1 END) AS d13Over,
+            COUNT(CASE WHEN day = 14 and status in (1,2) THEN 1 END) AS d14Online,
+            COUNT(CASE WHEN day = 14 and status=2 THEN 1 END) AS d14Over,
+            COUNT(CASE WHEN day = 15 and status in (1,2) THEN 1 END) AS d15Online,
+            COUNT(CASE WHEN day = 15 and status=2 THEN 1 END) AS d15Over,
+            COUNT(CASE WHEN day = 16 and status in (1,2) THEN 1 END) AS d16Online,
+            COUNT(CASE WHEN day = 16 and status=2 THEN 1 END) AS d16Over,
+            COUNT(CASE WHEN day = 17 and status in (1,2) THEN 1 END) AS d17Online,
+            COUNT(CASE WHEN day = 17 and status=2 THEN 1 END) AS d17Over,
+            COUNT(CASE WHEN day = 18 and status in (1,2) THEN 1 END) AS d18Online,
+            COUNT(CASE WHEN day = 18 and status=2 THEN 1 END) AS d18Over,
+            COUNT(CASE WHEN day = 19 and status in (1,2) THEN 1 END) AS d19Online,
+            COUNT(CASE WHEN day = 19 and status=2 THEN 1 END) AS d19Over,
+            COUNT(CASE WHEN day = 20 and status in (1,2) THEN 1 END) AS d20Online,
+            COUNT(CASE WHEN day = 20 and status=2 THEN 1 END) AS d20Over,
+            COUNT(CASE WHEN day = 21 and status in (1,2) THEN 1 END) AS d21Online,
+            COUNT(CASE WHEN day = 21 and status=2 THEN 1 END) AS d21Over,
+            COUNT(CASE WHEN day = 22 and status in (1,2) THEN 1 END) AS d22Online,
+            COUNT(CASE WHEN day = 22 and status=2 THEN 1 END) AS d22Over,
+            COUNT(CASE WHEN day = 23 and status in (1,2) THEN 1 END) AS d23Online,
+            COUNT(CASE WHEN day = 23 and status=2 THEN 1 END) AS d23Over,
+            COUNT(CASE WHEN day = 24 and status in (1,2) THEN 1 END) AS d24Online,
+            COUNT(CASE WHEN day = 24 and status=2 THEN 1 END) AS d24Over,
+            COUNT(CASE WHEN day = 25 and status in (1,2) THEN 1 END) AS d25Online,
+            COUNT(CASE WHEN day = 25 and status=2 THEN 1 END) AS d25Over,
+            COUNT(CASE WHEN day = 26 and status in (1,2) THEN 1 END) AS d26Online,
+            COUNT(CASE WHEN day = 26 and status=2 THEN 1 END) AS d26Over,
+            COUNT(CASE WHEN day = 27 and status in (1,2) THEN 1 END) AS d27Online,
+            COUNT(CASE WHEN day = 27 and status=2 THEN 1 END) AS d27Over,
+            COUNT(CASE WHEN day = 28 and status in (1,2) THEN 1 END) AS d28Online,
+            COUNT(CASE WHEN day = 28 and status=2 THEN 1 END) AS d28Over,
+            COUNT(CASE WHEN day = 29 and status in (1,2) THEN 1 END) AS d29Online,
+            COUNT(CASE WHEN day = 29 and status=2 THEN 1 END) AS d29Over,
+            COUNT(CASE WHEN day = 30 and status in (1,2) THEN 1 END) AS d30Online,
+            COUNT(CASE WHEN day = 30 and status=2 THEN 1 END) AS d30Over,
+            COUNT(1) AS line,project,course_id,video_id
+             from qw_watch_log_ex
+            <where>
+                 <if test="companyUserId">
+                     and company_user_id=#{companyUserId}
+                 </if>
+                <if test="companyId">
+                    and company_id = #{companyId}
+                </if>
+                <if test="project != null">
+                    and project = #{project}
+                </if>
+                <if test="courseId != null">
+                    and course_id = #{courseId}
+                </if>
+                <if test="videoId != null">
+                    and video_id =#{videoId}
+                </if>
+                and DATE(line_time) between #{sDate} AND #{eDate} group by project,course_id,video_id
+            </where>
+    </select>
+
+    <insert id="insertQwWatchLog" parameterType="QwWatchLog" useGeneratedKeys="true" keyProperty="id">
+        insert into qw_watch_log_ex
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="extId != null">ext_id,</if>
+            <if test="qwUserId != null">qw_user_id,</if>
+            <if test="status != null">status,</if>
+            <if test="day != null">day,</if>
+            <if test="project != null">project,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="lineTime != null">line_time,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="extId != null">#{extId},</if>
+            <if test="qwUserId != null">#{qwUserId},</if>
+            <if test="status != null">#{status},</if>
+            <if test="day != null">#{day},</if>
+            <if test="project != null">#{project},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="lineTime != null">#{lineTime},</if>
+         </trim>
+    </insert>
+
+    <insert id="insertQwWatchLogBatch" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="id">
+        INSERT INTO qw_watch_log_ex (
+        ext_id,
+        qw_user_id,
+        status,
+        day,
+        project,
+        create_time,
+        line_time,
+        fs_user_id,
+        company_id,
+        company_user_id,
+        course_id,
+        video_id
+        )
+        VALUES
+    <foreach collection="watchLogs" item="log" separator=",">
+            (
+            #{log.extId},
+            #{log.qwUserId},
+            #{log.status},
+            #{log.day},
+            #{log.project},
+            #{log.createTime},
+            #{log.lineTime},
+             #{log.fsUserId},
+             #{log.companyId},
+             #{log.companyUserId},
+             #{log.courseId},
+             #{log.videoId}
+            )
+    </foreach>
+    </insert>
+
+    <update id="updateQwWatchLog" parameterType="QwWatchLog">
+        update qw_watch_log_ex
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="extId != null">ext_id = #{extId},</if>
+            <if test="qwUserId != null">qw_user_id = #{qwUserId},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="day != null">day = #{day},</if>
+            <if test="project != null">project = #{project},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="lineTime != null">line_time = #{lineTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteQwWatchLogById" parameterType="Long">
+        delete from qw_watch_log_ex where id = #{id}
+    </delete>
+
+    <delete id="deleteQwWatchLogByIds" parameterType="String">
+        delete from qw_watch_log_ex where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>