소스 검색

Merge remote-tracking branch 'origin/master'

Long 4 일 전
부모
커밋
6eb9037cda
46개의 변경된 파일657개의 추가작업 그리고 927개의 파일을 삭제
  1. 21 4
      fs-admin/src/main/java/com/fs/course/controller/FsUserCoursePeriodController.java
  2. 2 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseTrainingCampController.java
  3. 10 0
      fs-admin/src/main/java/com/fs/course/controller/qw/QwFsCourseWatchLogController.java
  4. 39 0
      fs-admin/src/main/java/com/fs/his/controller/FsUserOperationLogController.java
  5. 15 0
      fs-company/src/main/java/com/fs/company/controller/course/FsUserCoursePeriodController.java
  6. 2 1
      fs-company/src/main/java/com/fs/company/controller/course/FsUserCourseTrainingCampController.java
  7. 35 0
      fs-company/src/main/java/com/fs/company/controller/course/FsUserOperationLogController.java
  8. 10 4
      fs-company/src/main/java/com/fs/company/controller/course/qw/FsQwCourseWatchLogController.java
  9. 6 0
      fs-company/src/main/java/com/fs/company/controller/qw/QwUserController.java
  10. 0 38
      fs-ipad-task/src/main/java/com/fs/app/controller/CommonController.java
  11. 6 5
      fs-ipad-task/src/main/java/com/fs/app/exception/FSExceptionHandler.java
  12. 4 2
      fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java
  13. 0 140
      fs-ipad-task/src/main/java/com/fs/app/task/QwMsgTask.java
  14. 16 12
      fs-ipad-task/src/main/java/com/fs/app/task/SendMsg.java
  15. 0 93
      fs-ipad-task/src/main/java/com/fs/app/task/SendMsgTest.java
  16. 0 149
      fs-ipad-task/src/main/resources/application-dev.yml
  17. 0 149
      fs-ipad-task/src/main/resources/application-druid-ylrz.yml
  18. 0 151
      fs-ipad-task/src/main/resources/application-druid.yml
  19. 5 166
      fs-ipad-task/src/main/resources/application.yml
  20. 2 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java
  21. 12 0
      fs-service/src/main/java/com/fs/course/mapper/FsUserCoursePeriodMapper.java
  22. 32 0
      fs-service/src/main/java/com/fs/course/param/PeriodStatisticCountParam.java
  23. 7 0
      fs-service/src/main/java/com/fs/course/service/IFsCourseWatchLogService.java
  24. 19 0
      fs-service/src/main/java/com/fs/course/service/IFsUserCoursePeriodService.java
  25. 5 0
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseWatchLogServiceImpl.java
  26. 26 1
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseComplaintRecordServiceImpl.java
  27. 50 0
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCoursePeriodServiceImpl.java
  28. 28 0
      fs-service/src/main/java/com/fs/course/vo/FsCourseStaticsCountVO.java
  29. 7 0
      fs-service/src/main/java/com/fs/course/vo/FsCourseWatchLogVO.java
  30. 10 2
      fs-service/src/main/java/com/fs/his/mapper/FsUserOperationLogMapper.java
  31. 4 1
      fs-service/src/main/java/com/fs/his/service/IFsUserOperationLogService.java
  32. 23 2
      fs-service/src/main/java/com/fs/his/service/impl/FsUserOperationLogServiceImpl.java
  33. 19 0
      fs-service/src/main/java/com/fs/his/vo/FsUserOperationLogParamVo.java
  34. 19 0
      fs-service/src/main/java/com/fs/his/vo/FsUserOperationLogVo.java
  35. 2 0
      fs-service/src/main/java/com/fs/qw/mapper/QwExternalContactMapper.java
  36. 1 0
      fs-service/src/main/java/com/fs/qw/mapper/QwUserMapper.java
  37. 3 4
      fs-service/src/main/java/com/fs/qw/service/IQwUserService.java
  38. 12 0
      fs-service/src/main/java/com/fs/qw/service/impl/QwUserServiceImpl.java
  39. 13 0
      fs-service/src/main/java/com/fs/qw/vo/UpdateSendTypeVo.java
  40. 38 0
      fs-service/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml
  41. 3 3
      fs-service/src/main/resources/mapper/course/FsUserCourseComplaintRecordMapper.xml
  42. 125 0
      fs-service/src/main/resources/mapper/course/FsUserCoursePeriodMapper.xml
  43. 4 0
      fs-service/src/main/resources/mapper/course/FsUserCourseTrainingCampMapper.xml
  44. 11 0
      fs-service/src/main/resources/mapper/his/FsUserOperationLogMapper.xml
  45. 8 0
      fs-service/src/main/resources/mapper/qw/QwExternalContactMapper.xml
  46. 3 0
      fs-service/src/main/resources/mapper/qw/QwUserMapper.xml

+ 21 - 4
fs-admin/src/main/java/com/fs/course/controller/FsUserCoursePeriodController.java

@@ -13,13 +13,11 @@ import com.fs.course.domain.FsUserCourseVideoRedPackage;
 import com.fs.course.param.CompanyRedPacketParam;
 import com.fs.course.param.FsBatchPeriodRedPackageParam;
 import com.fs.course.param.PeriodCountParam;
+import com.fs.course.param.PeriodStatisticCountParam;
 import com.fs.course.service.IFsUserCoursePeriodDaysService;
 import com.fs.course.service.IFsUserCoursePeriodService;
 import com.fs.course.service.IFsUserCourseVideoRedPackageService;
-import com.fs.course.vo.FsPeriodCountVO;
-import com.fs.course.vo.FsUserCoursePeriodVO;
-import com.fs.course.vo.PeriodRedPacketVO;
-import com.fs.course.vo.UpdateCourseTimeVo;
+import com.fs.course.vo.*;
 import com.fs.his.vo.OptionsVO;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
@@ -29,9 +27,12 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 
 /**
@@ -45,6 +46,7 @@ import java.util.Map;
 @RequestMapping("/course/period")
 @Slf4j
 public class FsUserCoursePeriodController extends BaseController {
+
     private final IFsUserCoursePeriodService fsUserCoursePeriodService;
     private final IFsUserCoursePeriodDaysService fsUserCoursePeriodDaysService;
     private final IFsUserCourseVideoRedPackageService fsUserCourseVideoRedPackageService;
@@ -254,4 +256,19 @@ public class FsUserCoursePeriodController extends BaseController {
         return R.ok();
     }
 
+    @PostMapping("/periodCourseStatisticCount")
+    @ApiOperation("会员详情训练营数据总览")
+    public R periodCourseStatisticCount(@RequestBody PeriodStatisticCountParam param) {
+        if (param == null) {
+            return R.error("请求参数不能为空!");
+        }
+        return R.ok().put("data", fsUserCoursePeriodService.periodCourseStatisticCount(param));
+    }
+
+    @PostMapping("/periodlist")
+    public R periodList(@RequestBody PeriodStatisticCountParam param)
+    {
+        List<FsUserCoursePeriod> list = fsUserCoursePeriodService.selectFsPeriodlist(param);
+        return R.ok().put("data", list);
+    }
 }

+ 2 - 0
fs-admin/src/main/java/com/fs/course/controller/FsUserCourseTrainingCampController.java

@@ -36,6 +36,7 @@ public class FsUserCourseTrainingCampController {
     @PreAuthorize("@ss.hasPermi('course:trainingCamp:list')")
     @GetMapping("/list")
     public AjaxResult list(@RequestParam(required = false) String trainingCampName,
+                           @RequestParam(required = false) String userId,
                            @RequestParam String scs,
                            @RequestParam(required = false, defaultValue = "1") Integer pageNum,
                            @RequestParam(required = false, defaultValue = "10") Integer pageSize)
@@ -43,6 +44,7 @@ public class FsUserCourseTrainingCampController {
         Map<String, Object> params = new HashMap<>();
         params.put("trainingCampName", trainingCampName);
         params.put("scs", SortUtils.parseSort(scs));
+        params.put("userId", userId);
 
         PageHelper.startPage(pageNum, pageSize);
         List<FsUserCourseTrainingCampVO> list = fsUserCourseTrainingCampService.selectFsUserCourseTrainingCampVOListByMap(params);

+ 10 - 0
fs-admin/src/main/java/com/fs/course/controller/qw/QwFsCourseWatchLogController.java

@@ -10,6 +10,7 @@ import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.course.domain.FsCourseWatchLog;
 import com.fs.course.param.FsCourseWatchLogListParam;
 import com.fs.course.param.FsCourseWatchLogStatisticsListParam;
+import com.fs.course.param.PeriodStatisticCountParam;
 import com.fs.course.service.IFsCourseWatchLogService;
 import com.fs.course.vo.FsCourseWatchLogListVO;
 import com.fs.course.vo.FsCourseWatchLogStatisticsListVO;
@@ -139,4 +140,13 @@ public class QwFsCourseWatchLogController extends BaseController
     {
         return toAjax(fsCourseWatchLogService.deleteFsCourseWatchLogByLogIds(logIds));
     }
+
+//    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:list')")
+    @GetMapping("/listBytrainingCampId")
+    public TableDataInfo listBytrainingCampId(PeriodStatisticCountParam param)
+    {
+        startPage();
+        List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectListBytrainingCampId(param);
+        return getDataTable(list);
+    }
 }

+ 39 - 0
fs-admin/src/main/java/com/fs/his/controller/FsUserOperationLogController.java

@@ -0,0 +1,39 @@
+package com.fs.his.controller;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.his.domain.FsUserOperationLog;
+import com.fs.his.service.IFsUserOperationLogService;
+import com.fs.his.vo.FsUserOperationLogParamVo;
+import com.fs.his.vo.FsUserOperationLogVo;
+import com.hc.openapi.tool.fastjson.JSON;
+import org.springframework.beans.BeanUtils;
+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.ArrayList;
+import java.util.List;
+
+/**
+ * 用户操作日志对象
+ */
+@RestController
+@RequestMapping("/his/userOperationLog")
+public class FsUserOperationLogController extends BaseController {
+
+    @Autowired
+    private IFsUserOperationLogService fsUserOperationLogService;
+
+//    @PreAuthorize("@ss.hasPermi('his:userOperationLog:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsUserOperationLog fsUserOperationLog)
+    {
+        startPage();
+        List<FsUserOperationLogVo> list = fsUserOperationLogService.selectFsUserOperationLogByList(fsUserOperationLog);
+
+        return getDataTable(list);
+    }
+}

+ 15 - 0
fs-company/src/main/java/com/fs/company/controller/course/FsUserCoursePeriodController.java

@@ -14,6 +14,7 @@ import com.fs.course.domain.FsUserCourseVideoRedPackage;
 import com.fs.course.param.CompanyRedPacketParam;
 import com.fs.course.param.FsBatchPeriodRedPackageParam;
 import com.fs.course.param.PeriodCountParam;
+import com.fs.course.param.PeriodStatisticCountParam;
 import com.fs.course.service.IFsUserCoursePeriodDaysService;
 import com.fs.course.service.IFsUserCoursePeriodService;
 import com.fs.course.service.IFsUserCourseVideoRedPackageService;
@@ -252,5 +253,19 @@ public class FsUserCoursePeriodController extends BaseController {
         fsUserCoursePeriodService.closePeriod(id);
         return R.ok();
     }
+    @PostMapping("/periodCourseStatisticCount")
+    @ApiOperation("会员详情训练营数据总览")
+    public R periodCourseStatisticCount(@RequestBody PeriodStatisticCountParam param) {
+        if (param == null) {
+            return R.error("请求参数不能为空!");
+        }
+        return R.ok().put("data", fsUserCoursePeriodService.periodCourseStatisticCount(param));
+    }
 
+    @PostMapping("/periodlist")
+    public R periodList(@RequestBody PeriodStatisticCountParam param)
+    {
+        List<FsUserCoursePeriod> list = fsUserCoursePeriodService.selectFsPeriodlist(param);
+        return R.ok().put("data", list);
+    }
 }

+ 2 - 1
fs-company/src/main/java/com/fs/company/controller/course/FsUserCourseTrainingCampController.java

@@ -39,6 +39,7 @@ public class FsUserCourseTrainingCampController {
     @PreAuthorize("@ss.hasPermi('course:trainingCamp:list')")
     @GetMapping("/list")
     public AjaxResult list(@RequestParam(required = false) String trainingCampName,
+                           @RequestParam(required = false) String userId,
                            @RequestParam String scs,
                            @RequestParam(required = false, defaultValue = "1") Integer pageNum,
                            @RequestParam(required = false, defaultValue = "10") Integer pageSize)
@@ -48,7 +49,7 @@ public class FsUserCourseTrainingCampController {
         params.put("trainingCampName", trainingCampName);
         params.put("scs", SortUtils.parseSort(scs));
         params.put("companyId", loginUser.getCompany().getCompanyId());
-
+        params.put("userId", userId);
         PageHelper.startPage(pageNum, pageSize);
         List<FsUserCourseTrainingCampVO> list = fsUserCourseTrainingCampService.selectFsUserCourseTrainingCampVOListByMap(params);
         return AjaxResult.success(new PageInfo<>(list));

+ 35 - 0
fs-company/src/main/java/com/fs/company/controller/course/FsUserOperationLogController.java

@@ -0,0 +1,35 @@
+package com.fs.company.controller.course;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.his.domain.FsUserOperationLog;
+import com.fs.his.service.IFsUserOperationLogService;
+import com.fs.his.vo.FsUserOperationLogVo;
+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;
+
+/**
+ * 用户操作日志对象
+ */
+@RestController
+@RequestMapping("/his/userOperationLog")
+public class FsUserOperationLogController extends BaseController {
+
+    @Autowired
+    private IFsUserOperationLogService fsUserOperationLogService;
+
+    @PreAuthorize("@ss.hasPermi('his:userOperationLog:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsUserOperationLog fsUserOperationLog)
+    {
+        startPage();
+        List<FsUserOperationLogVo> list = fsUserOperationLogService.selectFsUserOperationLogByList(fsUserOperationLog);
+
+        return getDataTable(list);
+    }
+}

+ 10 - 4
fs-company/src/main/java/com/fs/company/controller/course/qw/FsQwCourseWatchLogController.java

@@ -8,10 +8,7 @@ import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 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.param.*;
 import com.fs.course.service.IFsCourseWatchLogService;
 import com.fs.course.vo.FsCourseOverVO;
 import com.fs.course.vo.FsCourseUserStatisticsListVO;
@@ -259,4 +256,13 @@ public class FsQwCourseWatchLogController extends BaseController
     {
         return toAjax(fsCourseWatchLogService.deleteFsCourseWatchLogByLogIds(logIds));
     }
+
+    //    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:list')")
+    @GetMapping("/listBytrainingCampId")
+    public TableDataInfo listBytrainingCampId(PeriodStatisticCountParam param)
+    {
+        startPage();
+        List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectListBytrainingCampId(param);
+        return getDataTable(list);
+    }
 }

+ 6 - 0
fs-company/src/main/java/com/fs/company/controller/qw/QwUserController.java

@@ -35,6 +35,7 @@ import com.fs.qw.service.IQwExternalContactService;
 import com.fs.qw.service.IQwUserService;
 import com.fs.qw.vo.QwOptionsVO;
 import com.fs.qw.vo.QwUserVO;
+import com.fs.qw.vo.UpdateSendTypeVo;
 import com.fs.qwApi.domain.QwExternalContactAllListResult;
 import com.fs.qwApi.domain.inner.ExternalContact;
 import com.fs.qwApi.domain.inner.ExternalContactInfo;
@@ -826,4 +827,9 @@ public class QwUserController extends BaseController
     public R restartCloudHost(@RequestParam String serverIp) {
         return qwUserService.restartCloudHost(serverIp);
     }
+    @PostMapping("/updateSendType")
+    public R updateSendType(@RequestBody UpdateSendTypeVo vo) {
+        return qwUserService.updateSendType(vo);
+    }
+
 }

+ 0 - 38
fs-ipad-task/src/main/java/com/fs/app/controller/CommonController.java

@@ -1,38 +0,0 @@
-package com.fs.app.controller;
-
-
-import com.fs.app.task.QwMsgTask;
-import com.fs.common.core.redis.RedisCache;
-import com.fs.course.mapper.FsCourseWatchLogMapper;
-import com.fs.course.service.*;
-import com.fs.qw.mapper.QwExternalContactMapper;
-import com.fs.qw.service.IQwExternalContactService;
-import com.fs.sop.mapper.QwSopLogsMapper;
-import com.fs.sop.mapper.QwSopMapper;
-import com.fs.sop.mapper.SopUserLogsMapper;
-import com.fs.sop.service.IQwSopLogsService;
-import com.fs.sop.service.IQwSopTempRulesService;
-import com.fs.sop.service.IQwSopTempVoiceService;
-import com.fs.sop.service.ISopUserLogsService;
-import com.fs.system.service.ISysConfigService;
-import io.swagger.annotations.Api;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-@Api("公共接口")
-@RestController
-@RequestMapping(value="/app/common")
-@Slf4j
-public class CommonController {
-
-    @Autowired
-    private QwMsgTask qwMsgTask;
-
-    @GetMapping("/msg")
-    public void msg() throws InterruptedException {
-        qwMsgTask.sendMsg();
-    }
-}

+ 6 - 5
fs-ipad-task/src/main/java/com/fs/app/exception/FSExceptionHandler.java

@@ -5,6 +5,7 @@ package com.fs.app.exception;
 
 import com.fs.common.core.domain.R;
 import com.fs.common.exception.CustomException;
+import lombok.extern.slf4j.Slf4j;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.dao.DuplicateKeyException;
@@ -20,9 +21,9 @@ import org.springframework.web.servlet.NoHandlerFoundException;
 /**
  * 异常处理器
  */
+@Slf4j
 @RestControllerAdvice
 public class FSExceptionHandler {
-	private Logger logger = LoggerFactory.getLogger(getClass());
 
 	/**
 	 * 处理自定义异常
@@ -38,25 +39,25 @@ public class FSExceptionHandler {
 
 	@ExceptionHandler(NoHandlerFoundException.class)
 	public R handlerNoFoundException(Exception e) {
-		logger.error(e.getMessage(), e);
+		log.error(e.getMessage(), e);
 		return R.error(404, "路径不存在,请检查路径是否正确");
 	}
 
 	@ExceptionHandler(DuplicateKeyException.class)
 	public R handleDuplicateKeyException(DuplicateKeyException e){
-		logger.error(e.getMessage(), e);
+		log.error(e.getMessage(), e);
 		return R.error("数据库中已存在该记录");
 	}
 
 
 	@ExceptionHandler(Exception.class)
 	public R handleException(Exception e){
-		logger.error(e.getMessage(), e);
+		log.error(e.getMessage(), e);
 		return R.error();
 	}
 	@ExceptionHandler(AccessDeniedException.class)
 	public R handleAccessDeniedException(AccessDeniedException e){
-		logger.error(e.getMessage(), e);
+		log.error(e.getMessage(), e);
 		return R.error("没有权限");
 	}
 

+ 4 - 2
fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java

@@ -200,7 +200,10 @@ public class IpadSendServer {
     }
 
     public boolean isSendLogs(QwSopLogs qwSopLogs, QwSopCourseFinishTempSetting setting, QwUser qwUser) {
-
+        if(qwSopLogs.getSendStatus() != 3){
+            log.info("状态异常不发送:{}, LOGID: {}", qwUser.getQwUserName(), qwSopLogs.getId());
+            return false;
+        }
         if(redisCache.getCacheObject("qw:user:id:" + qwUser.getId()) != null){
             log.info("频率异常不发送:{}", qwUser.getQwUserName());
             return false;
@@ -292,7 +295,6 @@ public class IpadSendServer {
                     // 图片
                     sendImg(vo, content);
                     break;
-                case "9":
                 case "3":
                     // 链接
                     sendLink(vo, content);

+ 0 - 140
fs-ipad-task/src/main/java/com/fs/app/task/QwMsgTask.java

@@ -1,140 +0,0 @@
-package com.fs.app.task;
-
-
-import com.alibaba.fastjson.JSON;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.fs.common.utils.PubFun;
-import com.fs.common.utils.date.DateUtil;
-import com.fs.course.config.CourseConfig;
-import com.fs.qw.domain.QwUser;
-import com.fs.qw.mapper.QwUserMapper;
-import com.fs.qw.vo.QwSopLogMqVo;
-import com.fs.sop.domain.QwSopLogs;
-import com.fs.sop.mapper.QwSopLogsMapper;
-import com.fs.sop.service.IQwSopLogsService;
-import com.fs.system.domain.SysConfig;
-import com.fs.system.mapper.SysConfigMapper;
-import lombok.AllArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.rocketmq.spring.core.RocketMQTemplate;
-import org.springframework.retry.annotation.Backoff;
-import org.springframework.retry.annotation.Retryable;
-import org.springframework.scheduling.annotation.Async;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
-
-import java.time.LocalDateTime;
-import java.time.temporal.ChronoUnit;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.stream.Collectors;
-
-@Component
-@Slf4j
-@AllArgsConstructor
-public class QwMsgTask {
-
-    private final QwUserMapper qwUserMapper;
-    private final QwSopLogsMapper qwSopLogsMapper;
-    private final IQwSopLogsService qwSopLogsService;
-    private final SysConfigMapper sysConfigMapper;
-    private final RocketMQTemplate rocketMQTemplate;
-
-
-//    @Scheduled(fixedDelay = 1000)
-    public void sendMsg() throws InterruptedException {
-        long startTimeFun = System.currentTimeMillis();
-        log.info("============= 开始处理ipad发送逻辑 =============");
-        LocalDateTime now = LocalDateTime.now();
-        LocalDateTime dateTime = LocalDateTime.now().plusMinutes(15);
-
-        SysConfig courseConfig = sysConfigMapper.selectConfigByConfigKey("course.config");
-        CourseConfig config = JSON.parseObject(courseConfig.getConfigValue(), CourseConfig.class);
-        // 消息发送延迟
-        int delay;
-        if(config.getDelayStart() == null){
-            log.info("消息发送延迟为空手动设置1000ms");
-            delay = 1000;
-        }else {
-            delay = config.getDelayStart();
-        }
-        log.info("消息发送延迟:{}ms", delay);
-        List<QwUser> qwUsers = qwUserMapper.selectList(new QueryWrapper<QwUser>().eq("send_msg_type", 1).eq("server_status", 1).eq("ipad_status", 1).isNotNull("server_id"));
-        Map<String, QwUser> qwUserMap = PubFun.listToMapByGroupObject(qwUsers, e -> e.getQwUserId() + e.getCorpId());
-        log.info("获取到需要发送ipad企微数量:{}", qwUsers.size());
-        List<List<QwUser>> groupList = new ArrayList<>();
-        PubFun.batchProcessing(10, qwUsers, groupList::add);
-
-        CountDownLatch sopGroupLatch = new CountDownLatch(groupList.size());
-        int sum = groupList.parallelStream().mapToInt(e -> processSopGroupFun(e, qwUserMap, delay, now, dateTime, sopGroupLatch)).sum();
-        // 等待所有 SOP 分组处理完成
-        sopGroupLatch.await();
-        long endTime = System.currentTimeMillis();
-        log.info("============= 处理结束ipad发送逻辑:{}ms   报错记录:{}条=============", endTime - startTimeFun, sum);
-    }
-
-
-    @Async("sopIpadTaskExecutor")
-    @Retryable(
-            value = {Exception.class},
-            maxAttempts = 3,
-            backoff = @Backoff(delay = 2000)
-    )
-    public int processSopGroupFun(List<QwUser> qwUserList, Map<String, QwUser> qwUserMap, int delay, LocalDateTime now, LocalDateTime dateTime, CountDownLatch latch) {
-        try {
-            return processSopGroupAsync(qwUserList, qwUserMap, delay, dateTime, now);
-        } catch (Exception e) {
-            log.error("处理IPAD代发送错误", e);
-        } finally {
-            latch.countDown();
-        }
-        return 0;
-    }
-    public int processSopGroupAsync(List<QwUser> qwUserList, Map<String, QwUser> qwUserMap, int delay, LocalDateTime now, LocalDateTime dateTime) {
-//        log.info("开始分批处理企微:{}", qwUserList.size());
-        List<Long> qwUserIds = PubFun.listToNewList(qwUserList, QwUser::getId);
-        List<QwSopLogs> qwSopLogs = qwSopLogsMapper.selectByQwUserIdIn(qwUserIds, DateUtil.formatLocalDateTime(dateTime));
-//        log.info("获取到企微:{}代发送记录条数:{}", PubFun.listToNewList(qwUserList, QwUser::getQwUserName), qwSopLogs.size());
-        Map<String, List<QwSopLogs>> qwSopLogMap = PubFun.listToMapByGroupList(qwSopLogs, QwSopLogs::getQwUserid);
-        int num = 0;
-        qwSopLogMap.forEach((k, v) -> {
-            AtomicLong i = new AtomicLong(1);
-            AtomicLong lastTime = new AtomicLong(0);
-            v.stream().filter(e -> qwUserMap.containsKey(e.getQwUserid() + e.getCorpId())).sorted(Comparator.comparing(e -> DateUtil.toInstant(DateUtil.stringToLocalDateTime(e.getSendTime())) + e.getSort())).forEach(e -> {
-                long darkTime = delay * i.getAndIncrement();
-                LocalDateTime startTime = DateUtil.stringToLocalDateTime(e.getSendTime());
-                long between = ChronoUnit.MILLIS.between(now, startTime);
-                if(between < 0) between = 0;
-//                if(lastTime.get() + darkTime + delay < between){
-//                    darkTime = between;
-//                }else{
-                    darkTime += between;
-//                }
-                e.setSend(true);
-
-                rocketMQTemplate.syncSendDelayTimeMills("ipad-send-new", JSON.toJSONString(QwSopLogMqVo.builder().id(e.getId()).build()), darkTime);
-                lastTime.set(darkTime);
-                e.setMs(darkTime);
-            });
-        });
-        List<String> saveBath = qwSopLogs.stream().filter(QwSopLogs::isSend).map(QwSopLogs::getId).collect(Collectors.toList());
-        if(!saveBath.isEmpty()){
-            log.info("企微:{}保存发送记录条数:{}", PubFun.listToNewList(qwUserList, QwUser::getQwUserName), saveBath.size());
-//                qwSopLogsMapper.batchUpdateQwSopLogsIpadSendStatus(saveBath);
-
-            qwSopLogsService.updateBatch(qwSopLogs.stream().map(e -> {
-                QwSopLogs l = new QwSopLogs();
-                l.setId(e.getId());
-                l.setSendStatus(6L);
-                l.setMs(e.getMs());
-                return l;
-            }).collect(Collectors.toList()));
-            return qwSopLogs.size();
-        }
-        return 0;
-    }
-}

+ 16 - 12
fs-ipad-task/src/main/java/com/fs/app/task/SendMsg.java

@@ -14,7 +14,6 @@ import com.fs.qw.mapper.QwIpadServerMapper;
 import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.service.impl.AsyncSopTestService;
 import com.fs.qw.vo.QwSopCourseFinishTempSetting;
-import com.fs.qw.vo.QwSopTempSetting;
 import com.fs.sop.domain.QwSopLogs;
 import com.fs.sop.mapper.QwSopLogsMapper;
 import com.fs.sop.service.IQwSopLogsService;
@@ -29,8 +28,9 @@ import org.springframework.util.StringUtils;
 import java.text.SimpleDateFormat;
 import java.time.LocalDateTime;
 import java.util.*;
-import java.util.concurrent.*;
-import java.util.function.Function;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 @Component
@@ -42,6 +42,7 @@ public class SendMsg {
     private final IpadSendServer sendServer;
     private final SysConfigMapper sysConfigMapper;
     private final IQwSopLogsService qwSopLogsService;
+    private final AsyncSopTestService asyncSopTestService;
     private final RedisCacheT<Long> redisCache;
     private final QwIpadServerMapper qwIpadServerMapper;
 
@@ -51,12 +52,13 @@ public class SendMsg {
     private final Map<Long, Long> qwMap = new ConcurrentHashMap<>();
 
 
-    public SendMsg(QwUserMapper qwUserMapper, QwSopLogsMapper qwSopLogsMapper, IpadSendServer sendServer, SysConfigMapper sysConfigMapper, IQwSopLogsService qwSopLogsService, RedisCacheT<Long> redisCache, QwIpadServerMapper qwIpadServerMapper) {
+    public SendMsg(QwUserMapper qwUserMapper, QwSopLogsMapper qwSopLogsMapper, IpadSendServer sendServer, SysConfigMapper sysConfigMapper, IQwSopLogsService qwSopLogsService, AsyncSopTestService asyncSopTestService, RedisCacheT<Long> redisCache, QwIpadServerMapper qwIpadServerMapper) {
         this.qwUserMapper = qwUserMapper;
         this.qwSopLogsMapper = qwSopLogsMapper;
         this.sendServer = sendServer;
         this.sysConfigMapper = sysConfigMapper;
         this.qwSopLogsService = qwSopLogsService;
+        this.asyncSopTestService = asyncSopTestService;
         this.redisCache = redisCache;
         this.qwIpadServerMapper = qwIpadServerMapper;
     }
@@ -86,7 +88,7 @@ public class SendMsg {
         qwUserList.clear();
     }
 
-    @Scheduled(fixedRate = 10000) // 每10秒执行一次
+    @Scheduled(fixedRate = 20000) // 每10秒执行一次
     public void sendMsg2() {
         log.info("执行日志:{}", LocalDateTime.now());
         if (StringUtils.isEmpty(groupNo)) {
@@ -108,10 +110,9 @@ public class SendMsg {
         }
         Map<String, CourseMaConfig> miniMap = getMiniMap();
 
-        List<QwUser> qwUsers = getQwUserList();
+        List<QwUser> qwUsers = getQwUserList().stream().parallel().filter(e -> !qwMap.containsKey(e.getId())).collect(Collectors.toList());
         qwUsers.parallelStream().forEach(e -> {
             if (qwMap.putIfAbsent(e.getId(), System.currentTimeMillis()) == null) {
-//                log.info("提交销售任务:{}", e.getQwUserName());
                 // 判断企微是否发送消息,是否为ipad发送并且判断是否真实在线
                 new Thread(() -> {
                     try {
@@ -127,6 +128,11 @@ public class SendMsg {
     }
 
     private void processUser(QwUser qwUser, int delayStart, int delayEnd, Map<String, CourseMaConfig> miniMap) {
+        if (!qwMap.containsKey(qwUser.getId())) {
+            log.warn("用户:{}已在处理中,跳过重复执行", qwUser.getQwUserName());
+            return;
+        }
+        qwMap.put(qwUser.getId(), System.currentTimeMillis());
         long start1 = System.currentTimeMillis();
         List<QwSopLogs> qwSopLogList = qwSopLogsMapper.selectByQwUserId(qwUser.getId());
         if(qwSopLogList.isEmpty()){
@@ -138,7 +144,7 @@ public class SendMsg {
             qwMap.remove(user.getId());
             return;
         }
-        log.info("销售:{}, 消息:{}, 耗时: {}", user.getQwUserName(), qwSopLogList.size(), end1 - start1);
+        log.info("销售:{}, 消息:{}, 耗时: {}, 时间:{}", user.getQwUserName(), qwSopLogList.size(), end1 - start1, qwMap.get(qwUser.getId()));
         long start3 = System.currentTimeMillis();
         for (QwSopLogs qwSopLogs : qwSopLogList) {
 
@@ -200,10 +206,8 @@ public class SendMsg {
             updateQwSop.setContentJson(JSON.toJSONString(setting));
 
             long end2 = System.currentTimeMillis();
-            new Thread(() -> {
-                int i = qwSopLogsService.updateQwSopLogsSendType(updateQwSop);
-                log.info("销售:{}, 修改条数{}, 发送方消息完成:{}, 耗时: {}", user.getQwUserName(), i, qwSopLogs.getId(),end2 - start2);
-            }).start();
+            int i = qwSopLogsService.updateQwSopLogsSendType(updateQwSop);
+            log.info("销售:{}, 修改条数{}, 发送方消息完成:{}, 耗时: {}", user.getQwUserName(), i, qwSopLogs.getId(),end2 - start2);
             try {
                 int delay = ThreadLocalRandom.current().nextInt(delayStart, delayEnd);
                 log.debug("等待:{}ms", delay);

+ 0 - 93
fs-ipad-task/src/main/java/com/fs/app/task/SendMsgTest.java

@@ -1,93 +0,0 @@
-package com.fs.app.task;
-
-
-import com.alibaba.fastjson.JSON;
-import com.fs.app.service.IpadSendServer;
-import com.fs.common.core.redis.RedisCacheT;
-import com.fs.course.config.CourseConfig;
-import com.fs.qw.mapper.QwUserMapper;
-import com.fs.qw.service.impl.AsyncSopTestService;
-import com.fs.sop.mapper.QwSopLogsMapper;
-import com.fs.sop.service.IQwSopLogsService;
-import com.fs.system.domain.SysConfig;
-import com.fs.system.mapper.SysConfigMapper;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
-import org.springframework.util.StringUtils;
-
-import java.time.LocalDateTime;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadLocalRandom;
-import java.util.function.Function;
-
-@Component
-@Slf4j
-public class SendMsgTest {
-
-    private final List<Integer> qwUserList = Collections.synchronizedList(Arrays.asList(
-            1,
-            12,
-            13,
-            14,
-            15,
-            16,
-            17,
-            18,
-            19,
-            10,
-            111,
-            112,
-            113,
-            114,
-            115,
-            116,
-            117,
-            118,
-            119,
-            121,
-            122,
-            123,
-            124,
-            125,
-            126,
-            127
-    ));
-    // 使用固定大小线程池防止资源耗尽
-    private final ExecutorService executor = Executors.newFixedThreadPool(400);
-    private final Map<Integer, Long> qwMap = new ConcurrentHashMap<>();
-
-
-//    @Scheduled(fixedRate = 10000) // 每10秒执行一次
-    public void sendMsg2() {
-        qwUserList.forEach(e -> {
-            if (qwMap.putIfAbsent(e, System.currentTimeMillis()) == null) {
-                log.info("提交销售任务:{}", e);
-                executor.submit(() -> {
-                    try {
-                        processUser();
-                    } finally {
-                        qwMap.remove(e);
-                    }
-                });
-            }
-        });
-    }
-
-    private void processUser() {
-        try {
-            int delay = ThreadLocalRandom.current().nextInt(10000, 30000);
-            Thread.sleep(delay);
-        } catch (InterruptedException e) {
-            log.error("线程等待错误!");
-        }
-    }
-
-}

+ 0 - 149
fs-ipad-task/src/main/resources/application-dev.yml

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

+ 0 - 149
fs-ipad-task/src/main/resources/application-druid-ylrz.yml

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

+ 0 - 151
fs-ipad-task/src/main/resources/application-druid.yml

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

+ 5 - 166
fs-ipad-task/src/main/resources/application.yml

@@ -1,173 +1,12 @@
-# 项目相关配置
-fs:
-  # 名称
-  name: fs
-  # 版本
-  version: 1.1.0
-  # 版权年份
-  copyrightYear: 2021
-  # 实例演示开关
-  demoEnabled: true
-  # 文件路径 示例( Windows配置D:/fs/uploadPath,Linux配置 /home/fs/uploadPath)
-  profile: c:/fs/uploadPath
-  # 获取ip地址开关
-  addressEnabled: false
-  # 验证码类型 math 数组计算 char 字符验证
-  captchaType: math
-
-# 开发环境配置
 server:
   # 服务器的HTTP端口,默认为8080
-  port: 7006
-  servlet:
-    # 应用的访问路径
-    context-path: /
-  tomcat:
-    # tomcat的URI编码
-    uri-encoding: UTF-8
-    # tomcat最大线程数,默认为200
-    max-threads: 800
-    # Tomcat启动初始化的线程数,默认值25
-    min-spare-threads: 30
-
-# 日志配置
-logging:
-  level:
-    com.fs: info
-    org.springframework: warn
-
+  port: 9000
 # Spring配置
 spring:
-  # 资源信息
-  messages:
-    # 国际化资源文件路径
-    basename: i18n/messages
   profiles:
-#    active: druid-yjf
     active: dev
-#    active: druid-ylrz
-#    active: druid
-    include: config
-  # 文件上传
-  servlet:
-    multipart:
-      # 单个文件大小
-      max-file-size:  10MB
-      # 设置总上传的文件大小
-      max-request-size:  20MB
-  # 服务模块
-  devtools:
-    restart:
-      # 热部署开关
-      enabled: true
-
-# token配置
-token:
-  # 令牌自定义标识
-  header: Authorization
-  # 令牌密钥
-  secret: abcdefghijklmnopqrstuvwxyz
-  # 令牌有效期(默认30分钟)
-  expireTime: 180
-mybatis-plus:
-  # 搜索指定包别名
-  typeAliasesPackage: com.fs.**.domain,com.fs.**.bo
-  # 配置mapper的扫描,找到所有的mapper.xml映射文件
-  mapperLocations: classpath*:/mapper/**/*.xml
-  configLocation: classpath:mybatis/mybatis-config.xml
-  # 全局配置
-  global-config:
-    db-config:
-      # 主键类型  0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
-      idType: AUTO
-      # 字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
-      fieldStrategy: NOT_EMPTY
-    banner: false
-    # 配置
-  configuration:
-    # 驼峰式命名
-    mapUnderscoreToCamelCase: true
-    # 全局映射器启用缓存
-    cacheEnabled: true
-    # 配置默认的执行器
-    defaultExecutorType: REUSE
-    # 允许 JDBC 支持自动生成主键
-    useGeneratedKeys: true
-
-# MyBatis配置
-mybatis:
-  # 搜索指定包别名
-  typeAliasesPackage: com.fs.**.domain
-  # 配置mapper的扫描,找到所有的mapper.xml映射文件
-  mapperLocations: classpath*:mapper/**/*Mapper.xml
-  # 加载全局的配置文件
-  configLocation: classpath:mybatis/mybatis-config.xml
-
-# PageHelper分页插件
-pagehelper:
-  helperDialect: mysql
-  supportMethodsArguments: true
-  params: count=countSql
-
-# Swagger配置
-swagger:
-  # 是否开启swagger
-  enabled: false
-  # 请求前缀
-  pathMapping: /dev-api
-# 防止XSS攻击
-xss:
-  # 过滤开关
-  enabled: true
-  # 排除链接(多个用逗号分隔)
-  excludes: /system/notice,/system/config/*
-  # 匹配链接
-  urlPatterns: /system/*,/monitor/*,/tool/*
-wx:
-  miniapp:
-    configs:
-      - appid: wxbe53e91d9ad11ca6
-        secret: 447135e6ca602fa4745b81216f600615
-        token: Ncbnd7lJvkripVOpyTFAna6NAWCxCrvC
-        aesKey: HlEiBB55eaWUaeBVAQO3cWKWPYv1vOVQSq7nFNICw4E
-        msgDataFormat: JSON
-  pay:
-    appId: wx782bacb12a6b5d4f #微信公众号或者小程序等的appid
-    mchId: 1518509741 #微信支付商户号
-    mchKey: Jinrichengzhang88888888888888888 #微信支付商户密钥
-    subAppId:  #服务商模式下的子商户公众账号ID
-    subMchId:  #服务商模式下的子商户号
-    keyPath: c:\tools\apiclient_cert.p12 # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)
-    notifyUrl: https://api.haitujia.com/app/wxpay/wxPayNotify
+#    active: druid-hdt
+#    active: druid-yzt
+#    active: druid-sxjz
+#    active: druid-sft
 group-no: 1
-
-  
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=ww7bdf13931a6442d6 --server.port=9001   自动发消息(布偶猫舍)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=wweb0666cc79d79da5 --server.port=9002    自动发消息(茶园新区课堂)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=ww51717e2b71d5e2d3 --server.port=9003    自动发消息(云联融智)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=ww5a88c4f879f204c5 --server.port=9004    自动发消息(芳华未来守护您的健康)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=ww8fddae4df911c6aa --server.port=9005    自动发消息(御君方管理)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=ww44239b22628b206c --server.port=9006    自动发消息(芳华未来)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=wwdbd998fbb222fd91 --server.port=9007    自动发消息(百草鉴养生)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=wwa594e16ad105f9b7 --server.port=9008    自动发消息(润心智慧云医茶园新区智慧 )
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=ww6b20c4d6ac4a7298 --server.port=9009    自动发消息(碧康达生活)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=ww6a7548362b9cad48 --server.port=9010    自动发消息(芳华未来与您健康同行)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=wwf15af5d781bee541 --server.port=9011    自动发消息(御君方好课)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=ww6b789509f8db4e2d --server.port=9012    自动发消息(康与合健康管理)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=wwe6e3a3fd25eae04e --server.port=9013    自动发消息(御君方养生)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=wwdaf789c25f04d18f --server.port=9014    自动发消息(康源泰)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=ww91088a1e17d81d6d --server.port=9015    自动发消息(御君方课堂)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=ww96c0b2ad89546e5a --server.port=9016    自动发消息(御君方生活智慧)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=ww3a7bc63475e9f3dd --server.port=9017    自动发消息(济合昌技术)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=ww0590bdbaca51d96e --server.port=9018    自动发消息(润心智慧云医青南学堂)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=wwf49d502737165389 --server.port=9019    自动发消息(润心智慧云医米兰学堂)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=wwdf650a12d59fd4d9 --server.port=9020    自动发消息(百草鉴智慧)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=ww98294fb364da9d9c --server.port=9021    自动发消息(百草鉴健康)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=ww6c34c3f89517d4c4 --server.port=9022    自动发消息(百草鉴生活)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=wwa425b9bfad14ba55 --server.port=9023    自动发消息(润心智慧云医通江大道学堂)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=ww4a42ea8c821dc033 --server.port=9024    自动发消息(百草鉴学堂)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=ww5b5506c754838051 --server.port=9025    自动发消息(百草鉴学院)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=ww12ce922187cbbd36 --server.port=9026    自动发消息(彩虹惠医重庆)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=ww23ea983d9201c7ad --server.port=9027    自动发消息(同泰大药房茶园旗舰店)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=ww70ac72e824957fc9 --server.port=9028    自动发消息(御君方互联网医院)
-#  --spring.profiles.active=druid-yjf --spring.redis.password=Yzx19860213 --corp-id=ww76ab1028d66d7432 --server.port=9029    自动发消息(蔡汉皋药房)

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

@@ -419,4 +419,6 @@ public interface FsCourseWatchLogMapper extends BaseMapper<FsCourseWatchLog> {
             "    qec.corp_id"+
             "</script>")
     List<QwExternalContact> selectQwWatchLogFomExtContact(@Param("logIds") List<Long> logIds);
+
+    List<FsCourseWatchLogListVO> selectListBytrainingCampId(PeriodStatisticCountParam param);
 }

+ 12 - 0
fs-service/src/main/java/com/fs/course/mapper/FsUserCoursePeriodMapper.java

@@ -2,6 +2,7 @@ package com.fs.course.mapper;
 
 import com.fs.course.domain.FsUserCoursePeriod;
 import com.fs.course.param.CompanyRedPacketParam;
+import com.fs.course.param.PeriodStatisticCountParam;
 import com.fs.course.vo.FsUserCoursePeriodVO;
 import com.fs.course.vo.PeriodRedPacketVO;
 import org.apache.ibatis.annotations.MapKey;
@@ -9,6 +10,7 @@ import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 import org.apache.ibatis.annotations.Update;
 
+import java.math.BigDecimal;
 import java.time.LocalDate;
 import java.util.List;
 import java.util.Map;
@@ -145,5 +147,15 @@ public interface FsUserCoursePeriodMapper
     int updateBatchDelFlag(@Param("ids") Long [] ids, @Param("delFlag") Integer delFlag);
 
 
+    Long setlectCourseCompleteNum(PeriodStatisticCountParam param);
 
+    Long setlectCourseWatchNum(PeriodStatisticCountParam param);
+
+    Long setlectRedPacketCount(PeriodStatisticCountParam param);
+
+    BigDecimal setlectRedPacketAmount(PeriodStatisticCountParam param);
+
+    Long setlectCorrectAnswerNum(PeriodStatisticCountParam param);
+
+    List<FsUserCoursePeriod> selectFsPeriodlist(PeriodStatisticCountParam param);
 }

+ 32 - 0
fs-service/src/main/java/com/fs/course/param/PeriodStatisticCountParam.java

@@ -0,0 +1,32 @@
+package com.fs.course.param;
+
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import java.io.Serializable;
+import java.time.LocalDate;
+import java.util.List;
+
+/**
+ * 营期统计入参
+ */
+@Data
+public class PeriodStatisticCountParam implements Serializable {
+
+    @ApiModelProperty(value = "营期id")
+    private Long periodId;
+
+    /**
+     * 训练营Id
+     */
+    private Long trainingCampId;
+
+    /**
+     * 用户Id
+     */
+    private Long userId;
+
+}
+

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

@@ -121,4 +121,11 @@ public interface IFsCourseWatchLogService extends IService<FsCourseWatchLog> {
     void scheduleUpdateDurationToDatabase();
 
     void checkFsUserWatchStatus();
+
+    /**
+     * 查询看课记录数据信息
+     * @param param
+     * @return
+     */
+    List<FsCourseWatchLogListVO> selectListBytrainingCampId(PeriodStatisticCountParam param);
 }

+ 19 - 0
fs-service/src/main/java/com/fs/course/service/IFsUserCoursePeriodService.java

@@ -1,8 +1,11 @@
 package com.fs.course.service;
 
 import com.fs.course.domain.FsUserCoursePeriod;
+import com.fs.course.param.PeriodStatisticCountParam;
+import com.fs.course.vo.FsCourseStaticsCountVO;
 import com.fs.course.vo.FsUserCoursePeriodVO;
 
+import java.math.BigDecimal;
 import java.util.List;
 
 /**
@@ -78,4 +81,20 @@ public interface IFsUserCoursePeriodService
      * 更新营期状态
      */
     void changePeriodStatus();
+
+
+    /**
+     * 查询数据信息(查询总学习时长、正确答题数、答题红包金额、答题红包数)
+     * @param param
+     * @return
+     */
+    FsCourseStaticsCountVO periodCourseStatisticCount(PeriodStatisticCountParam param);
+
+    /**
+     * 查询自己的所有营期
+     *
+     * @param param
+     * @return
+     */
+    List<FsUserCoursePeriod> selectFsPeriodlist(PeriodStatisticCountParam param);
 }

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

@@ -447,6 +447,11 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
 
     }
 
+    @Override
+    public List<FsCourseWatchLogListVO> selectListBytrainingCampId(PeriodStatisticCountParam param) {
+        return baseMapper.selectListBytrainingCampId(param);
+    }
+
 
     public void batchUpdateFsUserCourseWatchLog(List<FsCourseWatchLog> logs, int batchSize) {
         if (logs == null || logs.isEmpty()) {

+ 26 - 1
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseComplaintRecordServiceImpl.java

@@ -1,11 +1,18 @@
 package com.fs.course.service.impl;
 
 import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
 import com.fs.common.utils.DateUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fs.course.param.UserCourseComplaintRecordParam;
 import com.fs.course.vo.FsUserCourseComplaintRecordPageListVO;
+import com.fs.qw.domain.QwExternalContact;
+import com.fs.qw.mapper.QwExternalContactMapper;
 import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.fs.course.mapper.FsUserCourseComplaintRecordMapper;
 import com.fs.course.domain.FsUserCourseComplaintRecord;
@@ -20,6 +27,9 @@ import com.fs.course.service.IFsUserCourseComplaintRecordService;
 @Service
 public class FsUserCourseComplaintRecordServiceImpl extends ServiceImpl<FsUserCourseComplaintRecordMapper, FsUserCourseComplaintRecord> implements IFsUserCourseComplaintRecordService {
 
+    @Autowired
+    private QwExternalContactMapper qwExternalContactMapper;
+
     /**
      * 查询看课投诉记录
      *
@@ -41,7 +51,22 @@ public class FsUserCourseComplaintRecordServiceImpl extends ServiceImpl<FsUserCo
     @Override
     public List<FsUserCourseComplaintRecordPageListVO> selectFsUserCourseComplaintRecordList(FsUserCourseComplaintRecord fsUserCourseComplaintRecord)
     {
-        return baseMapper.selectFsUserCourseComplaintRecordPageList(fsUserCourseComplaintRecord);
+        List<FsUserCourseComplaintRecordPageListVO> list = baseMapper.selectFsUserCourseComplaintRecordPageList(fsUserCourseComplaintRecord);
+
+        // 获取外部联系人看课状态
+        List<Long> userIds = list.stream().map(FsUserCourseComplaintRecordPageListVO::getUserId).collect(Collectors.toList());
+        List<QwExternalContact> qwExternalContacts = qwExternalContactMapper.selectExternalByFsUserIds(userIds);
+        Map<Long, QwExternalContact> qwExternalContactMap = qwExternalContacts.stream().collect(Collectors.toMap(QwExternalContact::getFsUserId, Function.identity(), (v1, v2) -> v1));
+
+        for (FsUserCourseComplaintRecordPageListVO vo : list) {
+            QwExternalContact contact = qwExternalContactMap.get(vo.getUserId());
+            if(contact != null) {
+                vo.setStatus(contact.getCommentStatus() != null && contact.getCommentStatus() == 1 ? "已拉黑" : "正常");
+            } else {
+                vo.setStatus("正常");
+            }
+        }
+        return list;
     }
 
     /**

+ 50 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsUserCoursePeriodServiceImpl.java

@@ -1,14 +1,20 @@
 package com.fs.course.service.impl;
 
+import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.redis.RedisCache;
 import com.fs.common.exception.ServiceException;
+import com.fs.common.utils.StringUtils;
 import com.fs.course.domain.FsUserCoursePeriod;
 import com.fs.course.domain.FsUserCoursePeriodDays;
 import com.fs.course.mapper.FsUserCoursePeriodDaysMapper;
 import com.fs.course.mapper.FsUserCoursePeriodMapper;
 import com.fs.course.mapper.FsUserCourseVideoRedPackageMapper;
+import com.fs.course.param.PeriodStatisticCountParam;
 import com.fs.course.service.IFsUserCoursePeriodService;
+import com.fs.course.vo.FsCourseStaticsCountVO;
 import com.fs.course.vo.FsUserCoursePeriodVO;
 import org.apache.commons.collections.CollectionUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -16,6 +22,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
+import java.math.BigDecimal;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.temporal.ChronoUnit;
@@ -23,6 +30,7 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 /**
@@ -37,6 +45,8 @@ public class FsUserCoursePeriodServiceImpl implements IFsUserCoursePeriodService
     @Autowired
     private FsUserCoursePeriodMapper fsUserCoursePeriodMapper;
     @Resource
+    RedisCache redisCache;
+    @Resource
     private FsUserCoursePeriodDaysMapper fsUserCoursePeriodDaysMapper;
     @Resource
     private FsUserCourseVideoRedPackageMapper fsUserCourseVideoRedPackageMapper;
@@ -241,4 +251,44 @@ public class FsUserCoursePeriodServiceImpl implements IFsUserCoursePeriodService
         // 关营
         fsUserCoursePeriodMapper.endPeriod(LocalDate.now());
     }
+    @Override
+    public FsCourseStaticsCountVO periodCourseStatisticCount(PeriodStatisticCountParam param) {
+        String redisKey = "user:trainingCampId:periodId:" + param.getUserId() + ":" + param.getTrainingCampId();
+        if (ObjectUtil.isNotEmpty(param.getPeriodId())){
+            redisKey=redisKey+":"+param.getPeriodId();
+        }
+        FsCourseStaticsCountVO durationStr = redisCache.getCacheObject(redisKey);
+        if (ObjectUtil.isNotEmpty(durationStr)){
+            return durationStr;
+        }
+        FsCourseStaticsCountVO fsCourseStaticsCountVO = new FsCourseStaticsCountVO();
+        try {
+            Long courseCompleteNum = fsUserCoursePeriodMapper.setlectCourseCompleteNum(param);
+            fsCourseStaticsCountVO.setCourseCompleteNum(courseCompleteNum != null ? courseCompleteNum : 0L);
+
+            Long courseWatchNum = fsUserCoursePeriodMapper.setlectCourseWatchNum(param);
+            fsCourseStaticsCountVO.setCourseWatchNum(courseWatchNum != null ? courseWatchNum : 0L);
+
+            Long redPacketCount = fsUserCoursePeriodMapper.setlectRedPacketCount(param);
+            fsCourseStaticsCountVO.setRedPacketCount(redPacketCount != null ? redPacketCount : 0L);
+
+            BigDecimal redPacketAmount = fsUserCoursePeriodMapper.setlectRedPacketAmount(param);
+            fsCourseStaticsCountVO.setRedPacketAmount(redPacketAmount != null ? redPacketAmount : BigDecimal.ZERO);
+
+            Long correctAnswerNum = fsUserCoursePeriodMapper.setlectCorrectAnswerNum(param);
+            fsCourseStaticsCountVO.setCorrectAnswerNum(correctAnswerNum != null ? correctAnswerNum : 0L);
+            redisCache.setCacheObject(redisKey,fsCourseStaticsCountVO);
+            // 设置 Redis 记录的过期时间(例如 5 分钟)
+            redisCache.expire(redisKey, 600, TimeUnit.SECONDS);
+            return fsCourseStaticsCountVO;
+
+        } catch (Exception e) {
+            return fsCourseStaticsCountVO;
+        }
+    }
+
+    @Override
+    public List<FsUserCoursePeriod> selectFsPeriodlist(PeriodStatisticCountParam param) {
+        return fsUserCoursePeriodMapper.selectFsPeriodlist(param);
+    }
 }

+ 28 - 0
fs-service/src/main/java/com/fs/course/vo/FsCourseStaticsCountVO.java

@@ -0,0 +1,28 @@
+package com.fs.course.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.math.BigDecimal;
+
+@Data
+public class FsCourseStaticsCountVO{
+
+    @ApiModelProperty(value = "总学习时长")
+    private Long courseWatchNum;
+
+    @ApiModelProperty(value = "到课数")
+    private Long courseCompleteNum;
+
+    @ApiModelProperty(value = "答题红包数")
+    private Long redPacketCount;
+
+    @ApiModelProperty(value = "答题红包金额")
+    private BigDecimal redPacketAmount;
+
+    @ApiModelProperty(value = "正确答题数")
+    private Long correctAnswerNum;
+
+}

+ 7 - 0
fs-service/src/main/java/com/fs/course/vo/FsCourseWatchLogVO.java

@@ -4,6 +4,9 @@ import com.fs.common.annotation.Excel;
 import com.fs.common.core.domain.BaseEntity;
 import lombok.Data;
 
+import java.time.LocalDateTime;
+import java.util.Date;
+
 @Data
 public class FsCourseWatchLogVO extends BaseEntity  {
 
@@ -54,4 +57,8 @@ public class FsCourseWatchLogVO extends BaseEntity  {
     private String title;
 
     private String courseName;
+
+    private String videoName;
+    private Date finishTime;
+    private LocalDateTime lastHeartbeatTime;
 }

+ 10 - 2
fs-service/src/main/java/com/fs/his/mapper/FsUserOperationLogMapper.java

@@ -4,7 +4,7 @@ import java.util.List;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.fs.his.domain.FsUserOperationLog;
 import com.fs.his.param.FsUserOperationLogQueryParam;
-import com.fs.his.vo.FsUserOperationLogPageVo;
+import com.fs.his.vo.FsUserOperationLogVo;
 
 /**
  * 用户操作日志Mapper接口
@@ -19,7 +19,7 @@ public interface FsUserOperationLogMapper extends BaseMapper<FsUserOperationLog>
      * @param logId 用户操作日志主键
      * @return 用户操作日志
      */
-    FsUserOperationLog selectFsUserOperationLogByLogId(Long logId);
+    FsUserOperationLogVo selectFsUserOperationLogByLogId(Long logId);
 
     /**
      * 查询用户操作日志列表
@@ -29,6 +29,14 @@ public interface FsUserOperationLogMapper extends BaseMapper<FsUserOperationLog>
      */
     List<FsUserOperationLog> selectFsUserOperationLogList(FsUserOperationLogQueryParam fsUserOperationLog);
 
+    /**
+     * 查询用户操作日志列表
+     *
+     * @param fsUserOperationLog 用户操作日志
+     * @return 用户操作日志集合
+     */
+    List<FsUserOperationLogVo> selectFsUserOperationLogByList(FsUserOperationLog fsUserOperationLog);
+
     /**
      * 新增用户操作日志
      *

+ 4 - 1
fs-service/src/main/java/com/fs/his/service/IFsUserOperationLogService.java

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.fs.his.domain.FsUserOperationLog;
 import com.fs.his.param.FsUserOperationLogQueryParam;
 import com.fs.his.vo.FsUserOperationLogPageVo;
+import com.fs.his.vo.FsUserOperationLogVo;
 
 /**
  * 用户操作日志Service接口
@@ -19,7 +20,7 @@ public interface IFsUserOperationLogService extends IService<FsUserOperationLog>
      * @param logId 用户操作日志主键
      * @return 用户操作日志
      */
-    FsUserOperationLog selectFsUserOperationLogByLogId(Long logId);
+    FsUserOperationLogVo selectFsUserOperationLogByLogId(Long logId);
 
     /**
      * 查询用户操作日志列表
@@ -60,4 +61,6 @@ public interface IFsUserOperationLogService extends IService<FsUserOperationLog>
      * @return 结果
      */
     int deleteFsUserOperationLogByLogId(Long logId);
+
+    List<FsUserOperationLogVo> selectFsUserOperationLogByList(FsUserOperationLog fsUserOperationLog);
 }

+ 23 - 2
fs-service/src/main/java/com/fs/his/service/impl/FsUserOperationLogServiceImpl.java

@@ -3,13 +3,18 @@ package com.fs.his.service.impl;
 import java.util.ArrayList;
 import java.util.List;
 
+import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSON;
 import com.fs.common.utils.DateUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fs.common.utils.StringUtils;
+import com.fs.course.domain.FsCourseRedPacketLog;
+import com.fs.course.mapper.FsCourseRedPacketLogMapper;
 import com.fs.course.vo.FsUserCourseVO;
 import com.fs.his.param.FsUserOperationLogQueryParam;
 import com.fs.his.vo.FsUserOperationLogPageVo;
+import com.fs.his.vo.FsUserOperationLogParamVo;
+import com.fs.his.vo.FsUserOperationLogVo;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -25,7 +30,8 @@ import com.fs.his.service.IFsUserOperationLogService;
  */
 @Service
 public class FsUserOperationLogServiceImpl extends ServiceImpl<FsUserOperationLogMapper, FsUserOperationLog> implements IFsUserOperationLogService {
-
+    @Autowired
+    private FsCourseRedPacketLogMapper fsCourseRedPacketLogMapper;
     /**
      * 查询用户操作日志
      *
@@ -33,7 +39,7 @@ public class FsUserOperationLogServiceImpl extends ServiceImpl<FsUserOperationLo
      * @return 用户操作日志
      */
     @Override
-    public FsUserOperationLog selectFsUserOperationLogByLogId(Long logId)
+    public FsUserOperationLogVo selectFsUserOperationLogByLogId(Long logId)
     {
         return baseMapper.selectFsUserOperationLogByLogId(logId);
     }
@@ -132,4 +138,19 @@ public class FsUserOperationLogServiceImpl extends ServiceImpl<FsUserOperationLo
     {
         return baseMapper.deleteFsUserOperationLogByLogId(logId);
     }
+
+    @Override
+    public List<FsUserOperationLogVo> selectFsUserOperationLogByList(FsUserOperationLog fsUserOperationLog) {
+        List<FsUserOperationLogVo> list = baseMapper.selectFsUserOperationLogByList(fsUserOperationLog);
+        list.forEach(e->{
+            FsUserOperationLogParamVo fsUserOperationLogParamVo = JSON.parseObject(e.getParam(), FsUserOperationLogParamVo.class);
+            e.setParamVo(fsUserOperationLogParamVo);
+            if (ObjectUtil.isEmpty(fsUserOperationLogParamVo)){
+                return;
+            }
+            FsCourseRedPacketLog fsCourseRedPacketLog = fsCourseRedPacketLogMapper.selectFsCourseRedPacketLogByTemporary(fsUserOperationLogParamVo.getVideoId(),e.getUserId());
+            e.setFsCourseRedPacketLog(fsCourseRedPacketLog);
+        });
+        return list;
+    }
 }

+ 19 - 0
fs-service/src/main/java/com/fs/his/vo/FsUserOperationLogParamVo.java

@@ -0,0 +1,19 @@
+package com.fs.his.vo;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+/**
+ * 用户操作日志对象返回子参数
+ */
+@Data
+public class FsUserOperationLogParamVo {
+    private Integer courseId;
+    private String courseName;
+    private Integer periodId;
+    private String periodName;
+    private String title;
+    private Integer trainingCampId;
+    private String trainingCampName;
+    private Long videoId;
+}

+ 19 - 0
fs-service/src/main/java/com/fs/his/vo/FsUserOperationLogVo.java

@@ -0,0 +1,19 @@
+package com.fs.his.vo;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fs.common.annotation.Excel;
+import com.fs.course.domain.FsCourseRedPacketLog;
+import com.fs.course.vo.FsCourseRedPacketLogListPVO;
+import com.fs.his.domain.FsUserOperationLog;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 用户操作日志对象返回参数
+ */
+@Data
+public class FsUserOperationLogVo extends FsUserOperationLog{
+
+    public FsUserOperationLogParamVo paramVo;
+    public FsCourseRedPacketLog fsCourseRedPacketLog;
+}

+ 2 - 0
fs-service/src/main/java/com/fs/qw/mapper/QwExternalContactMapper.java

@@ -404,4 +404,6 @@ public interface QwExternalContactMapper extends BaseMapper<QwExternalContact> {
     @Select("select sum(amount) as redPacketAmount from fs_course_red_packet_log where user_id = #{userId}")
     BigDecimal getRedPacketAmount(@Param("userId") Long userId);
 
+    List<QwExternalContact> selectExternalByFsUserIds(@Param("userIds")List<Long> userIds);
+
 }

+ 1 - 0
fs-service/src/main/java/com/fs/qw/mapper/QwUserMapper.java

@@ -423,4 +423,5 @@ public interface QwUserMapper extends BaseMapper<QwUser>
      */
     List<ExternalContactQwUserVO> selectQwUserByFsUserId(@Param("fsUserId") Long fsUserId);
 
+    void updateSendType(UpdateSendTypeVo vo);
 }

+ 3 - 4
fs-service/src/main/java/com/fs/qw/service/IQwUserService.java

@@ -5,10 +5,7 @@ import com.fs.qw.domain.QwUser;
 import com.fs.qw.domain.QwWorkTask;
 import com.fs.qw.dto.QwUserKeyDTO;
 import com.fs.qw.param.*;
-import com.fs.qw.vo.QwHookAuthVO;
-import com.fs.qw.vo.QwOptionsVO;
-import com.fs.qw.vo.QwUserVO;
-import com.fs.qw.vo.UserVOs;
+import com.fs.qw.vo.*;
 import com.fs.sop.domain.QwSop;
 import org.apache.commons.lang3.tuple.Pair;
 
@@ -188,4 +185,6 @@ public interface IQwUserService
     List<UserVOs> getUserList(Long userId);
 
     List<UserVOs> getQwUserList(Long userId, String qwUserId);
+
+    R updateSendType(UpdateSendTypeVo vo);
 }

+ 12 - 0
fs-service/src/main/java/com/fs/qw/service/impl/QwUserServiceImpl.java

@@ -1387,6 +1387,18 @@ public class QwUserServiceImpl implements IQwUserService
         return qwWorkTaskMapper.getQwUserList(userId, qwUserId);
     }
 
+    @Override
+    public R updateSendType(UpdateSendTypeVo vo) {
+        if(vo.getIds() == null || vo.getIds().isEmpty()) return R.error("修改人不能为空");
+        qwUserMapper.updateSendType(vo);
+        List<QwUser> qwUsers = qwUserMapper.selectBatchIds(vo.getIds());
+        qwUsers.forEach(e -> {
+            redisCache.setCacheObject("qwUserRd:"+e.getCorpId()+":"+e.getQwUserId() ,JSON.toJSONString(e),1, TimeUnit.HOURS);
+        });
+        return R.ok();
+    }
+
+
     /**
      * 构建查询条件
      * **/

+ 13 - 0
fs-service/src/main/java/com/fs/qw/vo/UpdateSendTypeVo.java

@@ -0,0 +1,13 @@
+package com.fs.qw.vo;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class UpdateSendTypeVo {
+
+    private List<Long> ids;
+    private Integer type;
+
+}

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

@@ -625,4 +625,42 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             (#{item.videoId}, #{item.userId}, #{item.companyUserId})
         </foreach>
     </update>
+
+
+    <select id="selectListBytrainingCampId" resultType="com.fs.course.vo.FsCourseWatchLogVO">
+        select
+        uc.course_name,v.title as video_name,
+        watch.log_id,
+        watch.user_id,
+        watch.finish_time,
+        watch.send_finish_msg,
+        watch.sop_id,
+        watch.video_id,
+        watch.reward_type,
+        watch.log_type,
+        watch.create_time,
+        watch.update_time,
+        watch.qw_external_contact_id,
+        watch.duration,
+        watch.qw_user_id,
+        watch.company_user_id,
+        watch.company_id,
+        watch.course_id,
+        watch.camp_period_time
+        from
+        fs_user_course_training_camp camp
+        left join fs_user_course_period period on
+        camp.training_camp_id = period.training_camp_id
+        left join fs_course_watch_log watch on
+        period.period_id = watch.period_id
+        left join fs_user_course uc on uc.course_id = watch.course_id
+        left join fs_user_course_video v on v.video_id = watch.video_id
+        <where>
+            `period`.del_flag = '0' and watch.log_type &lt;&gt; 3
+            <if test="trainingCampId != null">and camp.training_camp_id = #{trainingCampId}</if>
+            <if test="userId != null">and watch.user_id = #{userId}</if>
+            <if test="periodId != null">and `period`.period_id = #{periodId}</if>
+        </where>
+    </select>
+
 </mapper>

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

@@ -36,15 +36,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         ct.complaint_type_name,
         uc.course_name,
         ucv.title,
-        fs_user.nick_name,
-        if(ec.comment_status = 1,'已拉黑','正常') as status
+        fs_user.nick_name
+--         if(ec.comment_status = 1,'已拉黑','正常') as status
         FROM
         fs_user_course_complaint_record cr
         LEFT JOIN fs_user_course_complaint_type ct ON ct.complaint_type_id = cr.complaint_type_id
         LEFT JOIN fs_user_course uc ON uc.course_id = cr.course_id
         LEFT JOIN fs_user_course_video ucv ON ucv.video_id = cr.video_id
         LEFT JOIN fs_user ON fs_user.user_id = cr.user_id
-        left join qw_external_contact ec on cr.user_id = ec.fs_user_id
+--         left join qw_external_contact ec on cr.user_id = ec.fs_user_id
         <where>
             <if test="nickName != null and nickName != '' ">
                 and fs_user.nick_name like concat('%', #{nickName}, '%')

+ 125 - 0
fs-service/src/main/resources/mapper/course/FsUserCoursePeriodMapper.xml

@@ -262,4 +262,129 @@
         </foreach>
     </select>
 
+
+    <select id="setlectCourseCompleteNum" resultType="java.lang.Long">
+        select
+        count(watch.log_id)
+        from
+        fs_user_course_training_camp camp
+        left join fs_user_course_period period on
+        camp.training_camp_id = period.training_camp_id
+        left join fs_course_watch_log watch on
+        period.period_id = watch.period_id
+        <where>
+            `period`.del_flag = '0' and watch.log_type &lt;&gt; 3
+            <if test="trainingCampId != null">and camp.training_camp_id = #{trainingCampId}</if>
+            <if test="userId != null">and watch.user_id = #{userId}</if>
+            <if test="periodId != null">and `period`.period_id = #{periodId}</if>
+        </where>
+    </select>
+
+
+    <select id="setlectCourseWatchNum" resultType="java.lang.Long">
+        select
+        sum(watch.duration)
+        from
+        fs_user_course_training_camp camp
+        left join fs_user_course_period period on
+        camp.training_camp_id = period.training_camp_id
+        left join fs_course_watch_log watch on
+        period.period_id = watch.period_id
+        <where>
+           `period`.del_flag = '0' and watch.log_type &lt;&gt; 3
+            <if test="trainingCampId != null">and camp.training_camp_id = #{trainingCampId}</if>
+            <if test="userId != null">and watch.user_id = #{userId}</if>
+            <if test="periodId != null">and `period`.period_id = #{periodId}</if>
+        </where>
+
+
+    </select>
+
+    <select id="setlectRedPacketCount" resultType="java.lang.Long">
+        select
+            count(packet.log_id)
+        from
+            fs_user_course_training_camp camp
+                left join fs_user_course_period period on
+                camp.training_camp_id = period.training_camp_id
+                left join fs_course_red_packet_log packet on
+                period.period_id = packet.period_id
+        <where>
+            `period`.del_flag = '0' and packet.status =1
+            <if test="trainingCampId != null">and camp.training_camp_id = #{trainingCampId}</if>
+            <if test="userId != null">and packet.user_id = #{userId}</if>
+            <if test="periodId != null">and `period`.period_id = #{periodId}</if>
+        </where>
+    </select>
+
+    <select id="setlectRedPacketAmount" resultType="java.math.BigDecimal">
+        select
+            sum(packet.amount)
+        from
+            fs_user_course_training_camp camp
+                left join fs_user_course_period period on
+                camp.training_camp_id = period.training_camp_id
+                left join fs_course_red_packet_log packet on
+                period.period_id = packet.period_id
+        <where>
+            `period`.del_flag = '0' and packet.status =1
+            <if test="trainingCampId != null">and camp.training_camp_id = #{trainingCampId}</if>
+            <if test="userId != null">and packet.user_id = #{userId}</if>
+            <if test="periodId != null">and `period`.period_id = #{periodId}</if>
+        </where>
+    </select>
+
+    <select id="setlectCorrectAnswerNum" resultType="java.lang.Long">
+        select
+            count(answer.log_id)
+        from
+            fs_user_course_training_camp camp
+                left join fs_user_course_period period on
+                camp.training_camp_id = period.training_camp_id
+                left join fs_course_answer_logs answer on
+                period.period_id = answer.period_id
+        <where>
+            `period`.del_flag = '0' and answer.is_right =1
+            <if test="trainingCampId != null">and camp.training_camp_id = #{trainingCampId}</if>
+            <if test="userId != null">and answer.user_id = #{userId}</if>
+            <if test="periodId != null">and `period`.period_id = #{periodId}</if>
+        </where>
+    </select>
+
+
+    <select id="selectFsPeriodlist" resultMap="FsUserCoursePeriodResult">
+        select
+        period.period_id,
+        period.period_name,
+        period.company_id,
+        period.training_camp_id,
+        period.create_time,
+        period.update_time,
+        period.course_style,
+        period.live_room_style,
+        period.red_packet_grant_method,
+        period.period_type,
+        period.period_starting_time,
+        period.period_end_time,
+        period.period_status,
+        period.view_start_time,
+        period.view_end_time,
+        period.last_join_time,
+        period.max_view_num,
+        period.course_logo,
+        period.open_comment_status,
+        period.del_flag
+        from
+        fs_user_course_period period
+        left join fs_course_watch_log watch on
+        period.period_id = watch.period_id
+        <where>
+            `period`.del_flag = '0' and watch.log_type &lt;&gt; 3
+            <if test="trainingCampId != null">and `period`.training_camp_id = #{trainingCampId}</if>
+            <if test="userId != null">and watch.user_id = #{userId}</if>
+            <if test="periodId != null">and `period`.period_id = #{periodId}</if>
+        </where>
+        group by
+        `period`.period_id
+    </select>
 </mapper>

+ 4 - 0
fs-service/src/main/resources/mapper/course/FsUserCourseTrainingCampMapper.xml

@@ -24,6 +24,10 @@
             <if test="params.companyId != null and params.companyId != ''">
                 and ctp.company_id like concat('%',#{params.companyId},'%')
             </if>
+
+            <if test="params.userId != null and params.userId != ''">
+                and cu.user_id = #{params.userId}
+            </if>
         </where>
         group by ctc.training_camp_id, ctc.training_camp_name, ctc.order_number
         order by

+ 11 - 0
fs-service/src/main/resources/mapper/his/FsUserOperationLogMapper.xml

@@ -27,6 +27,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         order by create_time desc
     </select>
 
+    <select id="selectFsUserOperationLogByList" parameterType="FsUserOperationLog" resultType="com.fs.his.vo.FsUserOperationLogVo">
+        <include refid="selectFsUserOperationLogVo"/>
+        <where>
+            <if test="userId != null "> and user_id = #{userId}</if>
+            <if test="operationType != null  and operationType != ''"> and operation_type = #{operationType}</if>
+            <if test="details != null  and details != ''"> and details = #{details}</if>
+        </where>
+        order by create_time desc
+    </select>
+
+
     <select id="selectFsUserOperationLogByLogId" parameterType="Long" resultMap="FsUserOperationLogResult">
         <include refid="selectFsUserOperationLogVo"/>
         where log_id = #{logId}

+ 8 - 0
fs-service/src/main/resources/mapper/qw/QwExternalContactMapper.xml

@@ -572,4 +572,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         </foreach>
     </update>
 
+    <select id="selectExternalByFsUserIds" resultType="QwExternalContact">
+        select * from qw_external_contact
+        where fs_user_id in
+        <foreach collection="userIds" item="userId" open="(" separator="," close=")">
+            #{userId}
+        </foreach>
+    </select>
+
 </mapper>

+ 3 - 0
fs-service/src/main/resources/mapper/qw/QwUserMapper.xml

@@ -248,4 +248,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             qw_user.qw_user_id IN ( SELECT user_id FROM qw_external_contact WHERE fs_user_id = #{fsUserId} )
     </select>
 
+    <update id="updateSendType">
+        update qw_user set send_msg_type = #{type} where id in <foreach collection="ids" open="(" close=")" separator="," item="item">#{item}</foreach>
+    </update>
 </mapper>