Browse Source

Merge remote-tracking branch 'origin/master'

jzp 3 days ago
parent
commit
9942d536cb
41 changed files with 1825 additions and 308 deletions
  1. 2 1
      fs-admin/src/main/resources/application.yml
  2. 1 0
      fs-company-app/src/main/java/com/fs/app/controller/CompanyUserController.java
  3. 64 0
      fs-company/src/main/java/com/fs/company/controller/store/FsFollowTempController.java
  4. 60 0
      fs-company/src/main/java/com/fs/company/controller/store/FsIcdController.java
  5. 93 0
      fs-company/src/main/java/com/fs/company/controller/store/FsMaterialController.java
  6. 91 0
      fs-company/src/main/java/com/fs/company/controller/store/FsMaterialGroupController.java
  7. 71 0
      fs-company/src/main/java/com/fs/company/controller/store/FsPackageCateController.java
  8. 10 0
      fs-company/src/main/java/com/fs/company/controller/store/FsStoreProductController.java
  9. 39 4
      fs-qw-task/src/main/java/com/fs/app/task/qwTask.java
  10. 10 0
      fs-qw-task/src/main/java/com/fs/app/taskService/QwExternalContactRatingMoreSevenDaysService.java
  11. 9 0
      fs-qw-task/src/main/java/com/fs/app/taskService/SopUserLogsInfoByIsDaysNotStudy.java
  12. 333 0
      fs-qw-task/src/main/java/com/fs/app/taskService/impl/QwExternalContactRatingMoreSevenDaysServiceImpl.java
  13. 50 60
      fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java
  14. 262 0
      fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopUserLogsInfoByIsDaysNotStudyImpl.java
  15. 7 226
      fs-service/src/main/java/com/fs/company/domain/Company.java
  16. 41 0
      fs-service/src/main/java/com/fs/company/domain/CompanyMiniapp.java
  17. 62 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyMiniappMapper.java
  18. 70 0
      fs-service/src/main/java/com/fs/company/service/ICompanyMiniappService.java
  19. 141 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyMiniappServiceImpl.java
  20. 18 1
      fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java
  21. 3 0
      fs-service/src/main/java/com/fs/company/vo/CompanyVO.java
  22. 28 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java
  23. 4 0
      fs-service/src/main/java/com/fs/his/vo/FsStoreOrderExportVO.java
  24. 4 0
      fs-service/src/main/java/com/fs/qw/mapper/QwExternalContactMapper.java
  25. 6 0
      fs-service/src/main/java/com/fs/sop/domain/SopUserLogsInfo.java
  26. 52 0
      fs-service/src/main/java/com/fs/sop/mapper/SopUserLogsInfoMapper.java
  27. 7 0
      fs-service/src/main/java/com/fs/sop/mapper/SopUserLogsMapper.java
  28. 1 0
      fs-service/src/main/java/com/fs/sop/params/QwRatingConfig.java
  29. 8 0
      fs-service/src/main/java/com/fs/sop/service/ISopUserLogsInfoService.java
  30. 3 0
      fs-service/src/main/java/com/fs/sop/service/ISopUserLogsService.java
  31. 84 13
      fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsInfoServiceImpl.java
  32. 5 0
      fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsServiceImpl.java
  33. 1 1
      fs-service/src/main/java/com/fs/sop/vo/QwRatingVO.java
  34. 1 1
      fs-service/src/main/resources/application-config-druid-hcl.yml
  35. 1 0
      fs-service/src/main/resources/application-config-druid-xzt.yml
  36. 3 0
      fs-service/src/main/resources/application-druid-xzt.yml
  37. 91 0
      fs-service/src/main/resources/mapper/CompanyMiniappMapper.xml
  38. 12 0
      fs-service/src/main/resources/mapper/company/CompanyMapper.xml
  39. 24 0
      fs-service/src/main/resources/mapper/qw/QwExternalContactMapper.xml
  40. 12 1
      fs-service/src/main/resources/mapper/sop/SopUserLogsInfoMapper.xml
  41. 41 0
      fs-service/src/main/resources/mapper/sop/SopUserLogsMapper.xml

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

@@ -9,5 +9,6 @@ spring:
 #    active: druid-yzt
 #    active: druid-yzt
 #    active: druid-sxjz
 #    active: druid-sxjz
 #    active: druid-sft
 #    active: druid-sft
-    active: druid-fby
+#    active: druid-fby
+    active: dev
 
 

+ 1 - 0
fs-company-app/src/main/java/com/fs/app/controller/CompanyUserController.java

@@ -209,6 +209,7 @@ public class CompanyUserController extends AppBaseController {
         companyUser.setCreateTime(new Date());
         companyUser.setCreateTime(new Date());
         companyUser.setIsAudit(0);
         companyUser.setIsAudit(0);
         companyUser.setParentId(upCompanyUser.getUserId());
         companyUser.setParentId(upCompanyUser.getUserId());
+        companyUser.setCompanyId(upCompanyUser.getCompanyId());
 
 
         // 部门
         // 部门
         CompanyDept dept = companyDeptService.getDefaultCompanyDeptByCompanyId(upCompanyUser.getCompanyId());
         CompanyDept dept = companyDeptService.getDefaultCompanyDeptByCompanyId(upCompanyUser.getCompanyId());

+ 64 - 0
fs-company/src/main/java/com/fs/company/controller/store/FsFollowTempController.java

@@ -0,0 +1,64 @@
+package com.fs.company.controller.store;
+
+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.poi.ExcelUtil;
+import com.fs.his.domain.FsFollowTemp;
+import com.fs.his.service.IFsFollowTempService;
+import com.fs.his.vo.OptionsVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 随访模板Controller
+ *
+ * @author fs
+ * @date 2023-07-14
+ */
+@RestController
+@RequestMapping("/store/followTemp")
+public class FsFollowTempController extends BaseController
+{
+    @Autowired
+    private IFsFollowTempService fsFollowTempService;
+
+    /**
+     * 查询随访模板列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(FsFollowTemp fsFollowTemp)
+    {
+        startPage();
+        List<FsFollowTemp> list = fsFollowTempService.selectFsFollowTempList(fsFollowTemp);
+        return getDataTable(list);
+    }
+
+
+
+    /**
+     * 获取随访模板详细信息
+     */
+    @GetMapping(value = "/{tempId}")
+    public AjaxResult getInfo(@PathVariable("tempId") Long tempId)
+    {
+        return AjaxResult.success(fsFollowTempService.selectFsFollowTempByTempId(tempId));
+    }
+
+
+
+    /**
+     * 查询模板名称列表
+     */
+    @GetMapping("/allList")
+    public TableDataInfo getAllList()
+    {
+        List<OptionsVO> list = fsFollowTempService.selectAllFsFollowTempList();
+        return getDataTable(list);
+    }
+}

+ 60 - 0
fs-company/src/main/java/com/fs/company/controller/store/FsIcdController.java

@@ -0,0 +1,60 @@
+package com.fs.company.controller.store;
+
+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.poi.ExcelUtil;
+import com.fs.his.domain.FsIcd;
+import com.fs.his.service.IFsIcdService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+/**
+ * icd编码库Controller
+ *
+ * @author fs
+ * @date 2024-04-22
+ */
+@RestController
+@RequestMapping("/store/icd")
+public class FsIcdController extends BaseController
+{
+    @Autowired
+    private IFsIcdService fsIcdService;
+
+    /**
+     * 查询icd编码库列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(FsIcd fsIcd)
+    {
+        startPage();
+        List<FsIcd> list = fsIcdService.selectFsIcdList(fsIcd);
+        return getDataTable(list);
+    }
+
+
+
+    /**
+     * 获取icd编码库详细信息
+     */
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsIcdService.selectFsIcdById(id));
+    }
+
+
+    @GetMapping(value = "/allIcd/{name}")
+    public AjaxResult allIcd(@PathVariable("name") String name)
+    {
+        return AjaxResult.success(fsIcdService.selectFsIcdByName(name));
+    }
+
+}

+ 93 - 0
fs-company/src/main/java/com/fs/company/controller/store/FsMaterialController.java

@@ -0,0 +1,93 @@
+package com.fs.company.controller.store;
+
+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.poi.ExcelUtil;
+import com.fs.his.domain.FsMaterial;
+import com.fs.his.service.IFsMaterialService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 素材库Controller
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/material")
+public class FsMaterialController extends BaseController
+{
+    @Autowired
+    private IFsMaterialService fsMaterialService;
+
+    /**
+     * 查询素材库列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(FsMaterial fsMaterial)
+    {
+        startPage();
+        fsMaterial.setStoreId(0L);
+        List<FsMaterial> list = fsMaterialService.selectFsMaterialList(fsMaterial);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出素材库列表
+     */
+    @Log(title = "素材库", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsMaterial fsMaterial)
+    {
+        fsMaterial.setStoreId(0L);
+        List<FsMaterial> list = fsMaterialService.selectFsMaterialList(fsMaterial);
+        ExcelUtil<FsMaterial> util = new ExcelUtil<FsMaterial>(FsMaterial.class);
+        return util.exportExcel(list, "material");
+    }
+
+    /**
+     * 获取素材库详细信息
+     */
+    @GetMapping(value = "/{materialId}")
+    public AjaxResult getInfo(@PathVariable("materialId") Long materialId)
+    {
+        return AjaxResult.success(fsMaterialService.selectFsMaterialByMaterialId(materialId));
+    }
+
+    /**
+     * 新增素材库
+     */
+    @Log(title = "素材库", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsMaterial fsMaterial)
+    {
+        fsMaterial.setStoreId(0L);
+        return toAjax(fsMaterialService.insertFsMaterial(fsMaterial));
+    }
+
+    /**
+     * 修改素材库
+     */
+    @Log(title = "素材库", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsMaterial fsMaterial)
+    {
+        return toAjax(fsMaterialService.updateFsMaterial(fsMaterial));
+    }
+
+    /**
+     * 删除素材库
+     */
+    @Log(title = "素材库", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{materialIds}")
+    public AjaxResult remove(@PathVariable Long[] materialIds)
+    {
+        return toAjax(fsMaterialService.deleteFsMaterialByMaterialIds(materialIds));
+    }
+}

+ 91 - 0
fs-company/src/main/java/com/fs/company/controller/store/FsMaterialGroupController.java

@@ -0,0 +1,91 @@
+package com.fs.company.controller.store;
+
+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.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.his.domain.FsMaterialGroup;
+import com.fs.his.service.IFsMaterialGroupService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 素材分组Controller
+ *
+ * @author fs
+ * @date 2022-03-15
+ */
+@RestController
+@RequestMapping("/store/materialGroup")
+public class FsMaterialGroupController extends BaseController
+{
+    @Autowired
+    private IFsMaterialGroupService fsMaterialGroupService;
+
+    /**
+     * 查询素材分组列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(FsMaterialGroup fsMaterialGroup)
+    {
+        startPage();
+        fsMaterialGroup.setStoreId(0L);
+        List<FsMaterialGroup> list = fsMaterialGroupService.selectFsMaterialGroupList(fsMaterialGroup);
+        return getDataTable(list);
+    }
+
+
+
+    /**
+     * 获取素材分组详细信息
+     */
+    @GetMapping(value = "/{groupId}")
+    public AjaxResult getInfo(@PathVariable("groupId") Long groupId)
+    {
+        return AjaxResult.success(fsMaterialGroupService.selectFsMaterialGroupByGroupId(groupId));
+    }
+
+    /**
+     * 新增素材分组
+     */
+    @Log(title = "素材分组", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsMaterialGroup fsMaterialGroup)
+    {
+        fsMaterialGroup.setStoreId(0L);
+        return toAjax(fsMaterialGroupService.insertFsMaterialGroup(fsMaterialGroup));
+    }
+
+    /**
+     * 修改素材分组
+     */
+    @Log(title = "素材分组", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsMaterialGroup fsMaterialGroup)
+    {
+        return toAjax(fsMaterialGroupService.updateFsMaterialGroup(fsMaterialGroup));
+    }
+
+    /**
+     * 删除素材分组
+     */
+    @Log(title = "素材分组", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{groupIds}")
+    public AjaxResult remove(@PathVariable Long[] groupIds)
+    {
+        return toAjax(fsMaterialGroupService.deleteFsMaterialGroupByGroupIds(groupIds));
+    }
+
+    @GetMapping("/getAllList")
+    public R getAllList(FsMaterialGroup fsMaterialGroup)
+    {
+        fsMaterialGroup.setStoreId(0L);
+        List<FsMaterialGroup> list = fsMaterialGroupService.selectFsMaterialGroupList(fsMaterialGroup);
+        return R.ok().put("data",list);
+    }
+}

+ 71 - 0
fs-company/src/main/java/com/fs/company/controller/store/FsPackageCateController.java

@@ -0,0 +1,71 @@
+package com.fs.company.controller.store;
+
+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.core.redis.RedisCache;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.his.domain.FsPackageCate;
+import com.fs.his.param.FsPackageCateUParam;
+import com.fs.his.service.IFsPackageCateService;
+import com.fs.his.vo.OptionsVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 套餐包分类Controller
+ *
+ * @author fs
+ * @date 2024-05-08
+ */
+@RestController
+@RequestMapping("/store/packageCate")
+public class FsPackageCateController extends BaseController
+{
+    @Autowired
+    private IFsPackageCateService fsPackageCateService;
+    @Autowired
+    RedisCache redisCache;
+    /**
+     * 查询套餐包分类列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(FsPackageCateUParam fsPackageCate)
+    {
+        startPage();
+        List<FsPackageCate> list = fsPackageCateService.selectFsPackageCateList(fsPackageCate);
+        return getDataTable(list);
+    }
+
+
+    /**
+     * 获取套餐包分类详细信息
+     */
+    @GetMapping(value = "/{cateId}")
+    public AjaxResult getInfo(@PathVariable("cateId") Long cateId)
+    {
+        return AjaxResult.success(fsPackageCateService.selectFsPackageCateByCateId(cateId));
+    }
+
+
+
+    @GetMapping("/allList")
+    public AjaxResult allList()
+    {
+        Map map = fsPackageCateService.selectFsArticleCateAllList();
+        return AjaxResult.success(map);
+    }
+    @GetMapping("/cateList")
+    public TableDataInfo cateList()
+    {
+        List<OptionsVO> list = fsPackageCateService.selectCateList();
+        return getDataTable(list);
+    }
+}

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

@@ -10,9 +10,11 @@ import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.his.domain.FsStoreProduct;
 import com.fs.his.domain.FsStoreProduct;
 import com.fs.his.domain.FsStoreProductAttr;
 import com.fs.his.domain.FsStoreProductAttr;
 import com.fs.his.domain.FsStoreProductRule;
 import com.fs.his.domain.FsStoreProductRule;
+import com.fs.his.param.FsProductAttrValueParam;
 import com.fs.his.param.FsStoreProductAddEditParam;
 import com.fs.his.param.FsStoreProductAddEditParam;
 import com.fs.his.service.IFsStoreProductAttrService;
 import com.fs.his.service.IFsStoreProductAttrService;
 import com.fs.his.service.IFsStoreProductService;
 import com.fs.his.service.IFsStoreProductService;
+import com.fs.his.vo.FsStoreProductAttrValueVO;
 import com.fs.his.vo.FsStoreProductExcelVO;
 import com.fs.his.vo.FsStoreProductExcelVO;
 import com.fs.his.vo.FsStoreProductVO;
 import com.fs.his.vo.FsStoreProductVO;
 import com.fs.his.vo.OptionsVO;
 import com.fs.his.vo.OptionsVO;
@@ -182,5 +184,13 @@ public class FsStoreProductController extends BaseController
         return fsStoreProductService.addOrEdit(fsStoreProduct);
         return fsStoreProductService.addOrEdit(fsStoreProduct);
     }
     }
 
 
+    @GetMapping("/getStoreProductAttrValueList")
+    public TableDataInfo getStoreProductAttrValueList(FsProductAttrValueParam param)
+    {
+        startPage();
+        List<FsStoreProductAttrValueVO> list=fsStoreProductService.selectFsStoreProductAttrValueListVO(param);
+        return getDataTable(list);
+    }
+
 
 
 }
 }

+ 39 - 4
fs-qw-task/src/main/java/com/fs/app/task/qwTask.java

@@ -1,9 +1,6 @@
 package com.fs.app.task;
 package com.fs.app.task;
 
 
-import com.fs.app.taskService.QwExternalContactRatingService;
-import com.fs.app.taskService.SopLogsChatTaskService;
-import com.fs.app.taskService.SopLogsTaskService;
-import com.fs.app.taskService.SopWxLogsService;
+import com.fs.app.taskService.*;
 import com.fs.qw.service.IQwExternalErrRetryService;
 import com.fs.qw.service.IQwExternalErrRetryService;
 import com.fs.qw.service.IQwGroupMsgService;
 import com.fs.qw.service.IQwGroupMsgService;
 import com.fs.qw.service.IQwWorkUserService;
 import com.fs.qw.service.IQwWorkUserService;
@@ -75,6 +72,12 @@ public class qwTask {
     @Autowired
     @Autowired
     private IQwSopTagService qwSopTagService;
     private IQwSopTagService qwSopTagService;
 
 
+    @Autowired
+    private SopUserLogsInfoByIsDaysNotStudy logsInfoByIsDaysNotStudy;
+
+    @Autowired
+    private QwExternalContactRatingMoreSevenDaysService qwExternalContactRatingMoreSevenDaysService;
+
     /**
     /**
      * 定时任务:检查SOP规则时间
      * 定时任务:检查SOP规则时间
      * 执行时间:每天凌晨 1:10:00
      * 执行时间:每天凌晨 1:10:00
@@ -306,6 +309,22 @@ public class qwTask {
         sopUserLogsService.repairSopUserLogsTimer();
         sopUserLogsService.repairSopUserLogsTimer();
     }
     }
 
 
+
+    /**
+     * 凌晨 2点35开始,将营期小于7天中标记为 是否7天未看课的(E级) 客户的 但是看课了的恢复一下
+     */
+    @Scheduled(cron = "0 35 2 * * ?")
+    @Async
+    public void processSopUserLogsInfoByIsDaysNotStudy() {
+        long startTimeMillis = System.currentTimeMillis();
+        log.info("====== 开始选择和处理 是否7天未看课的(E级) 客户的 恢复一下 ======");
+
+        logsInfoByIsDaysNotStudy.restoreByIsDaysNotStudy();
+
+        long endTimeMillis = System.currentTimeMillis();
+        log.info("====== 用户E级恢复处理完成,耗时 {} 毫秒 ======", (endTimeMillis - startTimeMillis));
+    }
+
     /**
     /**
      * 定时任务:客户评级处理
      * 定时任务:客户评级处理
      * 执行时间:每天凌晨 3:45:00
      * 执行时间:每天凌晨 3:45:00
@@ -327,6 +346,22 @@ public class qwTask {
         log.info("====== sop营期-用户分级处理完成,耗时 {} 毫秒 ======", (endTimeMillis - startTimeMillis));
         log.info("====== sop营期-用户分级处理完成,耗时 {} 毫秒 ======", (endTimeMillis - startTimeMillis));
     }
     }
 
 
+    /**
+     * 凌晨4点35开始 客户超过7天没有看课的 标记E级
+     */
+    @Scheduled(cron = "0 30 3 * * ?")
+    @Async
+    public void processQwSopExternalContactRatingMoreSevenDaysTimer() {
+        long startTimeMillis = System.currentTimeMillis();
+        log.info("====== 开始选择和处理 sop营期-用户超7天的看课情况 ======");
+
+        qwExternalContactRatingMoreSevenDaysService.ratingMoreSevenDaysUserLogs();
+
+        long endTimeMillis = System.currentTimeMillis();
+        log.info("====== sop营期-用户超7天处理完成,耗时 {} 毫秒 ======", (endTimeMillis - startTimeMillis));
+    }
+
+
     /**
     /**
      * 更新掉所有前一天的所有待发送
      * 更新掉所有前一天的所有待发送
      */
      */

+ 10 - 0
fs-qw-task/src/main/java/com/fs/app/taskService/QwExternalContactRatingMoreSevenDaysService.java

@@ -0,0 +1,10 @@
+package com.fs.app.taskService;
+
+import com.fs.common.core.domain.R;
+
+public interface QwExternalContactRatingMoreSevenDaysService {
+    /**
+     * Sop客户超7天评次
+     */
+    public R ratingMoreSevenDaysUserLogs();
+}

+ 9 - 0
fs-qw-task/src/main/java/com/fs/app/taskService/SopUserLogsInfoByIsDaysNotStudy.java

@@ -0,0 +1,9 @@
+package com.fs.app.taskService;
+
+public interface SopUserLogsInfoByIsDaysNotStudy {
+
+    /**
+     * 将前7天营期中标记为 是否7天未看课的(E级) 客户的 恢复一下,突然有的恢复一下 (复刻版)
+     */
+    public void restoreByIsDaysNotStudy();
+}

+ 333 - 0
fs-qw-task/src/main/java/com/fs/app/taskService/impl/QwExternalContactRatingMoreSevenDaysServiceImpl.java

@@ -0,0 +1,333 @@
+package com.fs.app.taskService.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.fs.app.taskService.QwExternalContactRatingMoreSevenDaysService;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.redis.RedisCache;
+import com.fs.course.mapper.FsCourseWatchLogMapper;
+import com.fs.qw.domain.QwExternalContact;
+import com.fs.qw.mapper.QwExternalContactMapper;
+import com.fs.sop.domain.SopUserLogs;
+import com.fs.sop.domain.SopUserLogsInfo;
+import com.fs.sop.mapper.SopUserLogsInfoMapper;
+import com.fs.sop.mapper.SopUserLogsMapper;
+import com.fs.sop.params.QwRatingConfig;
+import com.fs.sop.service.IQwSopTempDayService;
+import com.fs.sop.service.ISopUserLogsInfoService;
+import com.fs.sop.vo.QwRatingVO;
+import com.fs.system.service.ISysConfigService;
+import com.fs.voice.utils.StringUtil;
+import com.google.common.util.concurrent.AtomicDouble;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.*;
+import java.util.stream.Collectors;
+
+@Service
+@Slf4j
+public class QwExternalContactRatingMoreSevenDaysServiceImpl implements QwExternalContactRatingMoreSevenDaysService {
+
+
+
+    @Autowired
+    private ISysConfigService configService;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    @Autowired
+    private SopUserLogsMapper sopUserLogsMapper;
+
+    @Autowired
+    private IQwSopTempDayService qwSopTempDayService;
+
+    @Autowired
+    private SopUserLogsInfoMapper sopUserLogsInfoMapper;
+
+    @Autowired
+    private FsCourseWatchLogMapper fsCourseWatchLogMapper;
+
+    @Autowired
+    private QwExternalContactMapper qwExternalContactMapper;
+
+    @Autowired
+    private ISopUserLogsInfoService iSopUserLogsInfoService;
+
+    @Autowired
+    private ExecutorService sopRatingExecutor;  // 自定义线程池
+
+    // 任务队列
+    private final BlockingQueue<SopUserLogs> taskQueue = new LinkedBlockingQueue<>(10000);
+
+    private volatile boolean running = true;
+    //批量更新队列
+    private final List<CompletableFuture<Void>> updateFutures = Collections.synchronizedList(new ArrayList<>());
+
+    private final Object configLock = new Object();
+
+    // 启动时初始化消费者线程
+    @PostConstruct
+    public void init() {
+
+        loadCourseConfig();
+
+        int consumerCount = Runtime.getRuntime().availableProcessors(); // 消费者线程数,默认 CPU 核心数
+        for (int i = 0; i < consumerCount; i++) {
+            sopRatingExecutor.submit(this::consumeTasks); // 提交消费者任务
+        }
+
+        log.info("初始化 {} 个消费者线程", consumerCount);
+    }
+
+    private  volatile QwRatingConfig qwRatingConfig;
+
+    private void loadCourseConfig() {
+        try {
+            String json = configService.selectConfigByKey("qwRating:config");
+            QwRatingConfig config = JSON.parseObject(json, QwRatingConfig.class);
+            if (!StringUtil.strIsNullOrEmpty(json) && config != null) {
+                qwRatingConfig = config;
+                log.info("Loaded qwRating.config successfully.");
+            } else {
+                log.error("Failed to load course.config from configService.");
+            }
+        } catch (Exception e) {
+            log.error("Exception while loading qwRating.config: {}", e.getMessage(), e);
+        }
+    }
+
+
+    @Override
+    public R ratingMoreSevenDaysUserLogs() {
+        // 分页加载并放入队列
+        int pageSize = 1000;
+        int offset = 0;
+        List<SopUserLogs> sopUserLogs;
+
+        // 获取缓存的配置
+        QwRatingConfig config;
+        synchronized(configLock) {
+            config = qwRatingConfig;
+        }
+
+        do {
+            sopUserLogs = sopUserLogsMapper.meetsTheRatingByUserInfoWithPaginationStudyDays(offset, pageSize,config.getNotStudyDays());
+            if (!sopUserLogs.isEmpty()) {
+                sopUserLogs.forEach(item -> {
+                    try {
+                        taskQueue.put(item); // 将任务放入队列
+                    } catch (InterruptedException e) {
+                        log.error("任务放入队列失败,sopId: {}", item.getSopId(), e);
+                        Thread.currentThread().interrupt();
+                    }
+                });
+                offset += pageSize;
+            }
+        } while (!sopUserLogs.isEmpty());
+
+
+        // 等待队列处理完成
+        CompletableFuture.runAsync(() -> {
+            while (!taskQueue.isEmpty()) {
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    log.error("等待队列处理时中断", e);
+                    Thread.currentThread().interrupt();
+                }
+            }
+        }).join(); // 等待任务完成
+
+        return R.ok();
+    }
+
+
+    private void consumeTasks() {
+
+        if (!running && taskQueue.isEmpty()) {
+            log.info("没有评级任务需要处理");
+            return; // 如果队列为空且没有正在运行的线程,则直接返回
+        }
+
+        while (running) {
+            try {
+                SopUserLogs item = taskQueue.poll(1, TimeUnit.SECONDS); // 等待 1 秒
+                if (item != null) {
+                    processSingleTask(item);
+                }
+            } catch (Exception e) {
+                log.error("消费者线程异常", e);
+            }
+        }
+    }
+
+    private void processSingleTask(SopUserLogs item) {
+
+        // 获取缓存的配置
+        QwRatingConfig config;
+        synchronized(configLock) {
+            config = qwRatingConfig;
+        }
+
+        List<SopUserLogsInfo> sopUserLogsInfosList = sopUserLogsInfoMapper
+                .selectSopUserLogsInfoListBySopId(item.getSopId(), item.getId());
+
+        if (sopUserLogsInfosList == null || sopUserLogsInfosList.isEmpty()) {
+            log.error("当前营期没有客户-sopId:{},营期id:{}", item.getSopId(), item.getId());
+            return;
+        }
+
+        List<QwExternalContact> batchQwExternalContact = sopUserLogsInfosList.stream()
+                .map(logsInfo -> processUserLog(logsInfo, config))
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+
+        if (!batchQwExternalContact.isEmpty()) {
+            batchUpdateQwExternalContact(batchQwExternalContact);
+        }
+    }
+
+    private QwExternalContact processUserLog(SopUserLogsInfo logsInfo, QwRatingConfig config) {
+        try {
+            Long externalId = logsInfo.getExternalId();
+            if (externalId == null) {
+                return null;
+            }
+
+            List<QwRatingVO> ratingVOS = fsCourseWatchLogMapper
+                    .selectFsCourseWatchLogByExtIdRatingMoreStudyDays(externalId, config.getNotStudyDays());
+
+            if (ratingVOS == null || ratingVOS.isEmpty() || ratingVOS.size() < 6) {
+                log.info("没有记录或不满足条件不评级或看课记录小于6 不评级,externalId: {}", externalId);
+                return null;
+            }
+
+
+            //判断 7天的时长是否大于0
+            boolean scoreMoreStudyLevel = getScoreMoreStudyLevel(ratingVOS);
+
+            if (!scoreMoreStudyLevel) {
+                QwExternalContact externalContact = new QwExternalContact();
+                externalContact.setId(externalId);
+                externalContact.setLevel(5);
+                externalContact.setIsDaysNotStudy(1);
+                return externalContact;
+            }else {
+                QwExternalContact externalContact = new QwExternalContact();
+                externalContact.setId(externalId);
+                externalContact.setLevel(ratingVOS.get(0).getLevel());
+                externalContact.setIsDaysNotStudy(0);
+                return externalContact;
+            }
+
+
+        } catch (Exception e) {
+            log.error("计算用户积分异常,用户:{}", logsInfo, e);
+            return null;
+        }
+    }
+
+    private void batchUpdateQwExternalContact(List<QwExternalContact> notInExternalUseridList) {
+        int batchSize = 300;
+
+        for (int i = 0; i < notInExternalUseridList.size(); i += batchSize) {
+            int endIndex = Math.min(i + batchSize, notInExternalUseridList.size());
+            List<QwExternalContact> batchList = notInExternalUseridList.subList(i, endIndex);
+
+            int finalI = i;
+            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
+                try {
+                    qwExternalContactMapper.batchUpdateQwExternalContactByMoreStudy(batchList);
+                    iSopUserLogsInfoService.batchUpdateSopUserLogsInfoByMoreStudy(batchList);
+                    log.info("成功更新看课7天数据,起始索引: {}, 数量: {}", finalI, batchList.size());
+                } catch (Exception e) {
+                    log.error("批量更新异常,批次起始索引: {}", finalI, e);
+                }
+
+            }, sopRatingExecutor);
+
+            updateFutures.add(future);
+        }
+    }
+
+    @PreDestroy
+    public void shutdown() {
+        running = false;  // 标记消费者停止
+        log.info("正在关闭线程池...");
+
+        // **等待任务队列处理完毕**
+        while (!taskQueue.isEmpty()) {
+            try {
+                Thread.sleep(500);
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                log.warn("等待任务队列处理完成时被中断", e);
+            }
+        }
+
+        // **确保所有 `batchUpdateQwExternalContact` 的任务完成**
+        log.info("等待所有批量更新任务完成...");
+        CompletableFuture.allOf(updateFutures.toArray(new CompletableFuture[0])).join();
+
+        // 关闭线程池
+        sopRatingExecutor.shutdown();
+        try {
+            if (!sopRatingExecutor.awaitTermination(60, TimeUnit.SECONDS)) {
+                List<Runnable> pendingTasks = sopRatingExecutor.shutdownNow();
+                log.warn("强制关闭线程池,未完成任务数: {}", pendingTasks.size());
+            }
+        } catch (InterruptedException e) {
+            sopRatingExecutor.shutdownNow();
+            Thread.currentThread().interrupt();
+        }
+        log.info("线程池和消费者已完全关闭");
+    }
+
+
+    /**
+     * 每6小时更新一次
+     */
+    @Scheduled(cron = "0 50 0/6 * * ?")
+    public void refreshRatingConfig() {
+
+        synchronized(configLock) {
+            try {
+                String json = configService.selectConfigByKey("qwRating:config");
+                QwRatingConfig config = JSON.parseObject(json, QwRatingConfig.class);
+                if (!StringUtil.strIsNullOrEmpty(json) && config != null) {
+                    qwRatingConfig = config;
+                    log.info("LoadedTime qwRating.config successfully.");
+                } else {
+                    log.error("Failed to load course.config from configService.");
+                }
+            } catch (Exception e) {
+                log.error("Exception while refreshing course.config: {}", e.getMessage(), e);
+            }
+        }
+
+    }
+
+
+    //查 E级
+    public boolean getScoreMoreStudyLevel(List<QwRatingVO> qwRatingVOS) {
+
+        AtomicDouble watchCount= new AtomicDouble();
+
+        qwRatingVOS.forEach(vo -> {
+            watchCount.addAndGet(vo.getWatchDuration());
+        });
+
+        // 判断总 watchDuration 是否 > 0
+        return watchCount.get() > 0;
+    }
+
+}

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

@@ -8,7 +8,9 @@ import com.fs.common.core.domain.R;
 import com.fs.common.exception.base.BaseException;
 import com.fs.common.exception.base.BaseException;
 import com.fs.common.utils.PubFun;
 import com.fs.common.utils.PubFun;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.StringUtils;
+import com.fs.company.domain.CompanyMiniapp;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.domain.CompanyUser;
+import com.fs.company.service.ICompanyMiniappService;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.*;
 import com.fs.course.domain.*;
@@ -150,7 +152,8 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
     private IQwGroupChatService qwGroupChatService;
     private IQwGroupChatService qwGroupChatService;
     @Autowired
     @Autowired
     private IQwGroupChatUserService qwGroupChatUserService;
     private IQwGroupChatUserService qwGroupChatUserService;
-
+    @Autowired
+    private ICompanyMiniappService companyMiniappService;
     // Shutdown flags
     // Shutdown flags
     private volatile boolean running = true;
     private volatile boolean running = true;
     @Autowired
     @Autowired
@@ -304,44 +307,10 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
         Map<String, List<SopUserLogsVo>> sopLogsGroupedById = sopUserLogsVos.stream()
         Map<String, List<SopUserLogsVo>> sopLogsGroupedById = sopUserLogsVos.stream()
                 .collect(Collectors.groupingBy(SopUserLogsVo::getSopId));
                 .collect(Collectors.groupingBy(SopUserLogsVo::getSopId));
 
 
+        // 查询公司关联小程序数据
+        List<CompanyMiniapp> miniList = companyMiniappService.list(new QueryWrapper<CompanyMiniapp>().orderByAsc("sort_num"));
 
 
-        // 查询销售二级域名
-//        Set<Long> ids = sopUserLogsVos.stream().map(s -> {
-//            String[] userKey = s.getUserId().split("\\|");
-//            if (userKey.length < 3) {
-//                return null;
-//            }
-//            return Long.parseLong(userKey[1]);
-//        }).filter(Objects::nonNull).collect(Collectors.toSet());
-//
-//        List<CompanyUser> companyUserList;
-//        if (ids.isEmpty()) {
-//            companyUserList = new ArrayList<>();
-//        } else {
-//            companyUserList = companyUserService.selectCompanyUserByIds(ids);
-//        }
-//
-//        Map<String, List<SopUserLogsVo>> sopLogsGroupedById = sopUserLogsVos.stream()
-//                .peek(s -> {
-//                    String[] userKey = s.getUserId().split("\\|");
-//                    if (userKey.length < 3) {
-//                        return;
-//                    }
-//
-//                    // 销售ID
-//                    Long companyUserId = Long.parseLong(userKey[1]);
-//                    CompanyUser companyUser = companyUserList.stream().filter(cu -> Objects.equals(cu.getUserId(), companyUserId)).findFirst().orElse(null);
-//                    if (Objects.nonNull(companyUser)) {
-//                        if (!StringUtil.strIsNullOrEmpty(companyUser.getDomain())) {
-//                            s.setDomain(companyUser.getDomain().trim());
-//                        } else {
-//                            s.setDomain(config.getRealLinkDomainName().trim());
-//                        }
-//                    } else {
-//                        s.setDomain(config.getRealLinkDomainName().trim());
-//                    }
-//                })
-//                .collect(Collectors.groupingBy(SopUserLogsVo::getSopId));
+        Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap = miniList.stream().collect(Collectors.groupingBy(CompanyMiniapp::getCompanyId, Collectors.groupingBy(CompanyMiniapp::getType)));
 
 
         log.info("共分组 {} 个 SOP ID 进行处理。", sopLogsGroupedById.size());
         log.info("共分组 {} 个 SOP ID 进行处理。", sopLogsGroupedById.size());
 
 
@@ -350,7 +319,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
         for (Map.Entry<String, List<SopUserLogsVo>> entry : sopLogsGroupedById.entrySet()) {
         for (Map.Entry<String, List<SopUserLogsVo>> entry : sopLogsGroupedById.entrySet()) {
             String sopId = entry.getKey();
             String sopId = entry.getKey();
             List<SopUserLogsVo> userLogsVos = entry.getValue();
             List<SopUserLogsVo> userLogsVos = entry.getValue();
-            processSopGroupAsync(sopId, userLogsVos, sopGroupLatch,currentTime, groupChatMap,config);
+            processSopGroupAsync(sopId, userLogsVos, sopGroupLatch,currentTime, groupChatMap,config,miniMap);
         }
         }
 
 
         // 等待所有 SOP 分组处理完成
         // 等待所有 SOP 分组处理完成
@@ -371,9 +340,9 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
             backoff = @Backoff(delay = 2000)
             backoff = @Backoff(delay = 2000)
     )
     )
     public void processSopGroupAsync(String sopId, List<SopUserLogsVo> userLogsVos, CountDownLatch latch ,LocalDateTime currentTime,
     public void processSopGroupAsync(String sopId, List<SopUserLogsVo> userLogsVos, CountDownLatch latch ,LocalDateTime currentTime,
-                                     Map<String, QwGroupChat> groupChatMap,CourseConfig config) {
+                                     Map<String, QwGroupChat> groupChatMap,CourseConfig config,Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap) {
         try {
         try {
-            processSopGroup(sopId, userLogsVos,currentTime, groupChatMap, config);
+            processSopGroup(sopId, userLogsVos,currentTime, groupChatMap, config,miniMap);
         } catch (Exception e) {
         } catch (Exception e) {
             log.error("处理 SOP ID {} 时发生异常: {}", sopId, e.getMessage(), e);
             log.error("处理 SOP ID {} 时发生异常: {}", sopId, e.getMessage(), e);
         } finally {
         } finally {
@@ -383,7 +352,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
 
 
 
 
     private void processSopGroup(String sopId, List<SopUserLogsVo> userLogsVos,LocalDateTime currentTime, Map<String,
     private void processSopGroup(String sopId, List<SopUserLogsVo> userLogsVos,LocalDateTime currentTime, Map<String,
-            QwGroupChat> groupChatMap,CourseConfig config) throws Exception {
+            QwGroupChat> groupChatMap,CourseConfig config,Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap) throws Exception {
         QwSopRuleTimeVO ruleTimeVO = sopMapper.selectQwSopByClickHouseId(sopId);
         QwSopRuleTimeVO ruleTimeVO = sopMapper.selectQwSopByClickHouseId(sopId);
 
 
         if (ruleTimeVO == null) {
         if (ruleTimeVO == null) {
@@ -425,7 +394,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
 
 
         CountDownLatch userLogsLatch = new CountDownLatch(userLogsVos.size());
         CountDownLatch userLogsLatch = new CountDownLatch(userLogsVos.size());
         for (SopUserLogsVo logVo : userLogsVos) {
         for (SopUserLogsVo logVo : userLogsVos) {
-            processUserLogAsync(logVo, ruleTimeVO, rulesList, userLogsLatch, currentTime, groupChatMap,qwCompany.getMiniAppId(), config);
+            processUserLogAsync(logVo, ruleTimeVO, rulesList, userLogsLatch, currentTime, groupChatMap,qwCompany.getMiniAppId(), config,miniMap);
         }
         }
 
 
         // 等待所有用户日志处理完成
         // 等待所有用户日志处理完成
@@ -446,9 +415,9 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
     )
     )
     public void processUserLogAsync(SopUserLogsVo logVo, QwSopRuleTimeVO ruleTimeVO, List<QwSopTempRules> tempSettings,
     public void processUserLogAsync(SopUserLogsVo logVo, QwSopRuleTimeVO ruleTimeVO, List<QwSopTempRules> tempSettings,
                                     CountDownLatch latch, LocalDateTime currentTime, Map<String, QwGroupChat> groupChatMap,
                                     CountDownLatch latch, LocalDateTime currentTime, Map<String, QwGroupChat> groupChatMap,
-                                    String miniAppId,CourseConfig config) {
+                                    String miniAppId,CourseConfig config,Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap) {
         try {
         try {
-            processUserLog(logVo, ruleTimeVO, tempSettings,currentTime, groupChatMap, miniAppId, config);
+            processUserLog(logVo, ruleTimeVO, tempSettings,currentTime, groupChatMap, miniAppId, config,miniMap);
         } catch (Exception e) {
         } catch (Exception e) {
             log.error("处理用户日志 {} 时发生异常: {}", logVo.getId(), e.getMessage(), e);
             log.error("处理用户日志 {} 时发生异常: {}", logVo.getId(), e.getMessage(), e);
         } finally {
         } finally {
@@ -458,7 +427,8 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
 
 
 
 
     private void processUserLog(SopUserLogsVo logVo, QwSopRuleTimeVO ruleTimeVO, List<QwSopTempRules> tempSettings,
     private void processUserLog(SopUserLogsVo logVo, QwSopRuleTimeVO ruleTimeVO, List<QwSopTempRules> tempSettings,
-                                LocalDateTime currentTime, Map<String, QwGroupChat> groupChatMap,String miniAppId,CourseConfig config) {
+                                LocalDateTime currentTime, Map<String, QwGroupChat> groupChatMap,String miniAppId,
+                                CourseConfig config,Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap) {
         try {
         try {
 
 
             LocalDate startDate = LocalDate.parse(logVo.getStartTime(), DATE_FORMATTER);
             LocalDate startDate = LocalDate.parse(logVo.getStartTime(), DATE_FORMATTER);
@@ -510,6 +480,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
             String qwUserId = String.valueOf(qwUserByRedis.getId()).trim();
             String qwUserId = String.valueOf(qwUserByRedis.getId()).trim();
             String companyUserId = String.valueOf(qwUserByRedis.getCompanyUserId()).trim();
             String companyUserId = String.valueOf(qwUserByRedis.getCompanyUserId()).trim();
             String companyId = String.valueOf(qwUserByRedis.getCompanyId()).trim();
             String companyId = String.valueOf(qwUserByRedis.getCompanyId()).trim();
+            Integer sendMsgType = qwUserByRedis.getSendMsgType();
 
 
             if (StringUtil.strIsNullOrEmpty(companyUserId) || StringUtil.strIsNullOrEmpty(companyId) || "null".equals(companyUserId)) {
             if (StringUtil.strIsNullOrEmpty(companyUserId) || StringUtil.strIsNullOrEmpty(companyId) || "null".equals(companyUserId)) {
                 log.error("员工未绑定销售账号或公司,跳过处理:"+qwUserId);
                 log.error("员工未绑定销售账号或公司,跳过处理:"+qwUserId);
@@ -635,7 +606,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
 
 
                         insertSopUserLogs(sopUserLogsInfos, logVo, sendTime, ruleTimeVO, content, qwUserId,
                         insertSopUserLogs(sopUserLogsInfos, logVo, sendTime, ruleTimeVO, content, qwUserId,
                                 companyUserId, companyId, qwUserByRedis.getWelcomeText(),qwUserByRedis.getQwUserName(),
                                 companyUserId, companyId, qwUserByRedis.getWelcomeText(),qwUserByRedis.getQwUserName(),
-                                groupChatMap, miniAppId,config);
+                                groupChatMap, miniAppId,config,miniMap, sendMsgType);
 
 
                     }
                     }
                 } catch (Exception e) {
                 } catch (Exception e) {
@@ -678,7 +649,8 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
     private void insertSopUserLogs(List<SopUserLogsInfo> sopUserLogsInfos, SopUserLogsVo logVo, Date sendTime,
     private void insertSopUserLogs(List<SopUserLogsInfo> sopUserLogsInfos, SopUserLogsVo logVo, Date sendTime,
                                    QwSopRuleTimeVO ruleTimeVO, QwSopTempSetting.Content content,
                                    QwSopRuleTimeVO ruleTimeVO, QwSopTempSetting.Content content,
                                    String qwUserId,String companyUserId,String companyId,String welcomeText,String qwUserName,
                                    String qwUserId,String companyUserId,String companyId,String welcomeText,String qwUserName,
-                                   Map<String, QwGroupChat> groupChatMap,String miniAppId,CourseConfig config) {
+                                   Map<String, QwGroupChat> groupChatMap,String miniAppId,CourseConfig config,
+                                   Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap, Integer sendMsgType) {
         String formattedSendTime = sendTime.toInstant()
         String formattedSendTime = sendTime.toInstant()
                 .atZone(ZoneId.systemDefault())
                 .atZone(ZoneId.systemDefault())
                 .format(DATE_TIME_FORMATTER);
                 .format(DATE_TIME_FORMATTER);
@@ -705,7 +677,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                 QwSopLogs sopLogs = createBaseLog(formattedSendTime, logVo, ruleTimeVO, groupChat.getChatId(), groupChat.getName(), null, isOfficial, null);
                 QwSopLogs sopLogs = createBaseLog(formattedSendTime, logVo, ruleTimeVO, groupChat.getChatId(), groupChat.getName(), null, isOfficial, null);
                 handleLogBasedOnType(sopLogs, content, logVo, sendTime, courseId, videoId,
                 handleLogBasedOnType(sopLogs, content, logVo, sendTime, courseId, videoId,
                         type, qwUserId, companyUserId, companyId, groupChat.getChatId(), welcomeText, qwUserName,
                         type, qwUserId, companyUserId, companyId, groupChat.getChatId(), welcomeText, qwUserName,
-                        null, true, miniAppId, groupChat,config);
+                        null, true, miniAppId, groupChat,config, miniMap, null, sendMsgType);
             } else {
             } else {
                 if(groupChat.getChatUserList() != null && !groupChat.getChatUserList().isEmpty()){
                 if(groupChat.getChatUserList() != null && !groupChat.getChatUserList().isEmpty()){
                     groupChat.getChatUserList().forEach(user -> {
                     groupChat.getChatUserList().forEach(user -> {
@@ -714,7 +686,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                         QwSopLogs sopLogs = createBaseLog(formattedSendTime, logVo, ruleTimeVO, user.getUserId(), user.getName(), null, isOfficial, null);
                         QwSopLogs sopLogs = createBaseLog(formattedSendTime, logVo, ruleTimeVO, user.getUserId(), user.getName(), null, isOfficial, null);
                         handleLogBasedOnType(sopLogs, content, logVo, sendTime, courseId, videoId,
                         handleLogBasedOnType(sopLogs, content, logVo, sendTime, courseId, videoId,
                                 type, qwUserId, companyUserId, companyId, user.getId().toString(), welcomeText, qwUserName,
                                 type, qwUserId, companyUserId, companyId, user.getId().toString(), welcomeText, qwUserName,
-                                null, false, miniAppId, groupChat,config);
+                                null, false, miniAppId, groupChat,config, miniMap, null, sendMsgType);
                     });
                     });
                 }
                 }
             }
             }
@@ -725,9 +697,11 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                     String externalId = contactId.getExternalId().toString();
                     String externalId = contactId.getExternalId().toString();
                     String externalUserName = contactId.getExternalUserName();
                     String externalUserName = contactId.getExternalUserName();
                     Long fsUserId = contactId.getFsUserId();
                     Long fsUserId = contactId.getFsUserId();
+                    Integer grade = contactId.getGrade();
                     QwSopLogs sopLogs = createBaseLog(formattedSendTime, logVo, ruleTimeVO, contactId.getExternalContactId(), externalUserName, fsUserId, isOfficial, contactId.getExternalId());
                     QwSopLogs sopLogs = createBaseLog(formattedSendTime, logVo, ruleTimeVO, contactId.getExternalContactId(), externalUserName, fsUserId, isOfficial, contactId.getExternalId());
                     handleLogBasedOnType(sopLogs, content, logVo, sendTime, courseId, videoId,
                     handleLogBasedOnType(sopLogs, content, logVo, sendTime, courseId, videoId,
-                            type, qwUserId, companyUserId, companyId, externalId, welcomeText, qwUserName, fsUserId, false, miniAppId, null,config);
+                            type, qwUserId, companyUserId, companyId, externalId, welcomeText, qwUserName, fsUserId, false, miniAppId,
+                            null,config, miniMap, grade, sendMsgType);
                 } catch (Exception e) {
                 } catch (Exception e) {
                     log.error("处理 externalContactId {} 时发生异常: {}", contactId, e.getMessage(), e);
                     log.error("处理 externalContactId {} 时发生异常: {}", contactId, e.getMessage(), e);
                 }
                 }
@@ -831,11 +805,12 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
     }
     }
 
 
     private void handleLogBasedOnType(QwSopLogs sopLogs, QwSopTempSetting.Content content,
     private void handleLogBasedOnType(QwSopLogs sopLogs, QwSopTempSetting.Content content,
-                                      SopUserLogsVo logVo, Date sendTime, Long courseId,
-                                      Long videoId, int type, String qwUserId,
+                                      SopUserLogsVo logVo, Date sendTime, Long courseId, Long videoId, int type, String qwUserId,
                                       String companyUserId, String companyId, String externalId, String welcomeText,
                                       String companyUserId, String companyId, String externalId, String welcomeText,
                                       String qwUserName, Long fsUserId, boolean isGroupChat, String miniAppId,
                                       String qwUserName, Long fsUserId, boolean isGroupChat, String miniAppId,
-                                      QwGroupChat groupChat,CourseConfig config) {
+                                      QwGroupChat groupChat,CourseConfig config,
+                                      Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap,
+                                      Integer grade, Integer sendMsgType  ) {
         switch (type) {
         switch (type) {
             case 1:
             case 1:
                 handleNormalMessage(sopLogs, content,companyUserId);
                 handleNormalMessage(sopLogs, content,companyUserId);
@@ -843,7 +818,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
             case 2:
             case 2:
                 handleCourseMessage(sopLogs, content, logVo, sendTime, courseId, videoId,
                 handleCourseMessage(sopLogs, content, logVo, sendTime, courseId, videoId,
                         qwUserId, companyUserId, companyId, externalId, welcomeText,qwUserName, fsUserId,
                         qwUserId, companyUserId, companyId, externalId, welcomeText,qwUserName, fsUserId,
-                        isGroupChat, miniAppId, groupChat,config);
+                        isGroupChat, miniAppId, groupChat,config,miniMap, grade, sendMsgType);
                 break;
                 break;
             case 3:
             case 3:
                 handleOrderMessage(sopLogs, content);
                 handleOrderMessage(sopLogs, content);
@@ -873,10 +848,10 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
     }
     }
 
 
     private void handleCourseMessage(QwSopLogs sopLogs, QwSopTempSetting.Content content,
     private void handleCourseMessage(QwSopLogs sopLogs, QwSopTempSetting.Content content,
-                                     SopUserLogsVo logVo, Date sendTime, Long courseId,
-                                     Long videoId, String qwUserId, String companyUserId,
+                                     SopUserLogsVo logVo, Date sendTime, Long courseId, Long videoId, String qwUserId, String companyUserId,
                                      String companyId, String externalId, String welcomeText, String qwUserName,
                                      String companyId, String externalId, String welcomeText, String qwUserName,
-                                     Long fsUserId, boolean isGroupChat, String miniAppId, QwGroupChat groupChat,CourseConfig config) {
+                                     Long fsUserId, boolean isGroupChat, String miniAppId, QwGroupChat groupChat,CourseConfig config,Map<Long,
+                                     Map<Integer, List<CompanyMiniapp>>> miniMap,Integer grade, Integer sendMsgType) {
         // 深拷贝 Content 对象,避免使用 JSON
         // 深拷贝 Content 对象,避免使用 JSON
         QwSopTempSetting.Content clonedContent = deepCopyContent(content);
         QwSopTempSetting.Content clonedContent = deepCopyContent(content);
         if (clonedContent == null) {
         if (clonedContent == null) {
@@ -968,10 +943,25 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                     String sortLink = createLinkByMiniApp(setting, logVo, sendTime, courseId, videoId,
                     String sortLink = createLinkByMiniApp(setting, logVo, sendTime, courseId, videoId,
                             qwUserId, companyUserId, companyId, externalId,isOfficial,sopLogs.getFsUserId());
                             qwUserId, companyUserId, companyId, externalId,isOfficial,sopLogs.getFsUserId());
 
 
-                    if (!StringUtil.strIsNullOrEmpty(miniAppId)) {
+                    if (!miniMap.isEmpty() && sendMsgType==1) {
+                        Map<Integer, List<CompanyMiniapp>> integerListMap = miniMap.get(Long.valueOf(companyId));
+                        if (integerListMap != null) {
+
+                            int effectiveGrade = (grade == null) ? 5 : grade;
+                            int listIndex = (effectiveGrade == 1 || effectiveGrade == 2) ? 0 : 1;
+                            List<CompanyMiniapp> miniapps = integerListMap.get(listIndex);
+
+                            if (miniapps != null && !miniapps.isEmpty()) {
+                                CompanyMiniapp companyMiniapp = miniapps.get(0);
+                                if (companyMiniapp != null && !StringUtil.strIsNullOrEmpty(companyMiniapp.getAppId())) {
+                                    setting.setMiniprogramAppid(companyMiniapp.getAppId());
+                                }
+                            }
+                        }
+                    }else if (!StringUtil.strIsNullOrEmpty(miniAppId)){
                         setting.setMiniprogramAppid(miniAppId);
                         setting.setMiniprogramAppid(miniAppId);
                     }else {
                     }else {
-                        log.error("公司的小程序id为空:采用了前端传的固定值"+sopLogs.getSopId());
+                        log.error("公司的小程序id为空:采用了前端传的固定值" + sopLogs.getSopId());
                     }
                     }
 
 
                     setting.setMiniprogramPage(sortLink.replaceAll("^[\\s\\u2005]+", ""));
                     setting.setMiniprogramPage(sortLink.replaceAll("^[\\s\\u2005]+", ""));

+ 262 - 0
fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopUserLogsInfoByIsDaysNotStudyImpl.java

@@ -0,0 +1,262 @@
+package com.fs.app.taskService.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.fs.app.taskService.SopUserLogsInfoByIsDaysNotStudy;
+import com.fs.course.mapper.FsCourseWatchLogMapper;
+import com.fs.qw.domain.QwExternalContact;
+import com.fs.qw.mapper.QwExternalContactMapper;
+import com.fs.sop.domain.SopUserLogs;
+import com.fs.sop.domain.SopUserLogsInfo;
+import com.fs.sop.params.QwRatingConfig;
+import com.fs.sop.service.ISopUserLogsInfoService;
+import com.fs.sop.service.ISopUserLogsService;
+import com.fs.system.service.ISysConfigService;
+import com.fs.voice.utils.StringUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.*;
+import java.util.stream.Collectors;
+
+@Service
+@Slf4j
+public class SopUserLogsInfoByIsDaysNotStudyImpl implements SopUserLogsInfoByIsDaysNotStudy {
+
+
+    @Autowired
+    private FsCourseWatchLogMapper fsCourseWatchLogMapper;
+
+    @Autowired
+    private ISysConfigService configService;
+
+    @Autowired
+    private QwExternalContactMapper qwExternalContactMapper;
+
+    @Autowired
+    private ISopUserLogsInfoService iSopUserLogsInfoService;
+
+    @Autowired
+    private ISopUserLogsService iSopUserLogsService;
+
+    @Autowired
+    private ExecutorService sopRatingExecutor;  // 自定义线程池
+
+    // 任务队列
+    private final BlockingQueue<SopUserLogs> taskQueue = new LinkedBlockingQueue<>(10000);
+
+    private volatile boolean running = true;
+    //批量更新队列
+    private final List<CompletableFuture<Void>> updateFutures = Collections.synchronizedList(new ArrayList<>());
+
+    private final Object configLock = new Object();
+
+
+    private  volatile QwRatingConfig qwRatingConfig;
+
+    // 启动时初始化消费者线程
+    @PostConstruct
+    public void init() {
+
+        loadCourseConfig();
+
+        int consumerCount = Runtime.getRuntime().availableProcessors(); // 消费者线程数,默认 CPU 核心数
+        for (int i = 0; i < consumerCount; i++) {
+            sopRatingExecutor.submit(this::consumeTasks); // 提交消费者任务
+        }
+
+    }
+
+    private void loadCourseConfig() {
+        try {
+            String json = configService.selectConfigByKey("qwRating:config");
+            QwRatingConfig config = JSON.parseObject(json, QwRatingConfig.class);
+            if (!StringUtil.strIsNullOrEmpty(json) && config != null) {
+                qwRatingConfig = config;
+                log.info("Loaded qwRating.config successfully.");
+            } else {
+                log.error("Failed to load course.config from configService.");
+            }
+        } catch (Exception e) {
+            log.error("Exception while loading qwRating.config: {}", e.getMessage(), e);
+        }
+    }
+
+
+
+    @Override
+    public void restoreByIsDaysNotStudy() {
+
+        // 分页加载并放入队列
+        int pageSize = 1000;
+        int offset = 0;
+        List<SopUserLogs> sopUserLogs;
+
+        // 获取缓存的配置
+        QwRatingConfig config;
+        synchronized(configLock) {
+            config = qwRatingConfig;
+        }
+
+        do {
+            sopUserLogs = iSopUserLogsService.meetsTherestoreByIsDaysNotStudy(offset, pageSize,config.getNotStudyDays());
+            if (!sopUserLogs.isEmpty()) {
+                sopUserLogs.forEach(item -> {
+                    try {
+                        taskQueue.put(item); // 将任务放入队列
+                    } catch (InterruptedException e) {
+                        log.error("任务放入队列失败,sopId: {}", item.getSopId(), e);
+                        Thread.currentThread().interrupt();
+                    }
+                });
+                offset += pageSize;
+            }
+        } while (!sopUserLogs.isEmpty());
+
+
+        // 等待队列处理完成
+        CompletableFuture.runAsync(() -> {
+            while (!taskQueue.isEmpty()) {
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    log.error("等待队列处理时中断", e);
+                    Thread.currentThread().interrupt();
+                }
+            }
+        }).join(); // 等待任务完成
+
+    }
+
+    private void consumeTasks() {
+        if (!running && taskQueue.isEmpty()) {
+            log.info("没有评级任务需要处理");
+            return; // 如果队列为空且没有正在运行的线程,则直接返回
+        }
+
+        while (running) {
+            try {
+                SopUserLogs item = taskQueue.poll(1, TimeUnit.SECONDS); // 等待 1 秒
+                if (item != null) {
+                    processRestoreByIsDaysNotStudy(item);
+                }
+            } catch (Exception e) {
+                log.error("消费者线程异常", e);
+            }
+        }
+    }
+
+    private void processRestoreByIsDaysNotStudy(SopUserLogs item) {
+
+        // 获取缓存的配置
+        QwRatingConfig config;
+        synchronized(configLock) {
+            config = qwRatingConfig;
+        }
+
+        List<SopUserLogsInfo> infos = iSopUserLogsInfoService.selectRestoreByIsDaysNotStudy(
+                item.getSopId(), item.getId());
+
+        if (infos == null || infos.isEmpty()) {
+            log.error("当前营期没有E级客户-sopId:{},营期id:{}", item.getSopId(), item.getId());
+            return;
+        }
+
+        List<QwExternalContact> contacts = infos.stream()
+                .map(info -> processUserLog(info, config))
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+
+        if (!contacts.isEmpty()) {
+            batchUpdateQwExternalContact(contacts);
+        }
+    }
+
+    private void batchUpdateQwExternalContact(List<QwExternalContact> contacts) {
+        // 9. 优化分批逻辑
+        int total = contacts.size();
+        for (int i = 0; i < total; i += 300) {
+            List<QwExternalContact> batch = contacts.subList(i, Math.min(i + 300, total));
+
+            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
+                try {
+                    qwExternalContactMapper.batchUpdateQwExternalByIsDaysNotStudy(batch);
+                    iSopUserLogsInfoService.batchUpdateSopUserLogsInfoByIsDaysNotStudy(batch);
+                } catch (Exception e) {
+                    log.error("批量更新异常, 批次大小: {}", batch.size(), e);
+                }
+            }, sopRatingExecutor);
+
+            updateFutures.add(future);
+        }
+    }
+
+    @PreDestroy
+    public void shutdown() {
+        running = false;  // 标记消费者停止
+        log.info("正在关闭线程池...");
+
+        // **等待任务队列处理完毕**
+        while (!taskQueue.isEmpty()) {
+            try {
+                Thread.sleep(500);
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                log.warn("等待任务队列处理完成时被中断", e);
+            }
+        }
+
+        // **确保所有  的任务完成**
+        log.info("等待所有批量更新任务完成...");
+        CompletableFuture.allOf(updateFutures.toArray(new CompletableFuture[0])).join();
+
+        // 关闭线程池
+        sopRatingExecutor.shutdown();
+        try {
+            if (!sopRatingExecutor.awaitTermination(60, TimeUnit.SECONDS)) {
+                List<Runnable> pendingTasks = sopRatingExecutor.shutdownNow();
+                log.warn("强制关闭线程池,未完成任务数: {}", pendingTasks.size());
+            }
+        } catch (InterruptedException e) {
+            sopRatingExecutor.shutdownNow();
+            Thread.currentThread().interrupt();
+        }
+        log.info("线程池和消费者已完全关闭");
+    }
+
+    /**
+    * 只计算时长
+    */
+    private QwExternalContact processUserLog(SopUserLogsInfo logsInfo, QwRatingConfig config) {
+        try {
+
+            Long externalId = logsInfo.getExternalId();
+            if (externalId == null) {
+                return null;
+            }
+
+            Integer sumDuration = fsCourseWatchLogMapper.selectFsCourseWatchLogByByIsDaysNotStudy(externalId, config.getNotStudyDays());
+
+            if (sumDuration!=null && sumDuration>0) {
+                QwExternalContact externalContact = new QwExternalContact();
+                externalContact.setId(externalId);
+                externalContact.setIsDaysNotStudy(0);
+                return externalContact;
+            }
+
+            return null;
+
+        } catch (Exception e) {
+            log.error("计算用户积分异常,用户:{}", logsInfo, e);
+            return null;
+        }
+    }
+
+
+}

+ 7 - 226
fs-service/src/main/java/com/fs/company/domain/Company.java

@@ -112,233 +112,14 @@ public class Company extends BaseEntity
     private String courseMiniAppId;
     private String courseMiniAppId;
     /** 会员是否默认黑名单,1-是;0-否(用于销售分享成为会员的操作) */
     /** 会员是否默认黑名单,1-是;0-否(用于销售分享成为会员的操作) */
     private Integer fsUserIsDefaultBlack;
     private Integer fsUserIsDefaultBlack;
+    private Integer repeat;
+    private Integer sendIfType;
+    private Integer ifNum;
+    @TableField(exist = false)
+    private List<String> miniAppMaster;
+    @TableField(exist = false)
+    private List<String> miniAppServer;
 
 
-//    public String getDoctorIds() {
-//        return doctorIds;
-//    }
-//
-//    public void setDoctorIds(String doctorIds) {
-//        this.doctorIds = doctorIds;
-//    }
-//
-//    public String getFollowDoctorIds() {
-//        return followDoctorIds;
-//    }
-//
-//    public void setFollowDoctorIds(String followDoctorIds) {
-//        this.followDoctorIds = followDoctorIds;
-//    }
-//
-//    public String getManager() {
-//        return manager;
-//    }
-//
-//    public void setManager(String manager) {
-//        this.manager = manager;
-//    }
-//
-//    public String getOmsCode() {
-//        return omsCode;
-//    }
-//
-//    public void setOmsCode(String omsCode) {
-//        this.omsCode = omsCode;
-//    }
-//
-//    public Integer getVoiceCallerNumber() {
-//        return voiceCallerNumber;
-//    }
-//
-//    public void setVoiceCallerNumber(Integer voiceCallerNumber) {
-//        this.voiceCallerNumber = voiceCallerNumber;
-//    }
-//
-//    public Integer getIsDel() {
-//        return isDel;
-//    }
-//
-//    public void setIsDel(Integer isDel) {
-//        this.isDel = isDel;
-//    }
-//
-//    public BigDecimal getTuiMoney() {
-//        return tuiMoney;
-//    }
-//
-//    public void setTuiMoney(BigDecimal tuiMoney) {
-//        this.tuiMoney = tuiMoney;
-//    }
-//
-//    @Override
-//    public String getRemark() {
-//        return remark;
-//    }
-//
-//    @Override
-//    public void setRemark(String remark) {
-//        this.remark = remark;
-//    }
-//
-//    public String getLinkName() {
-//        return linkName;
-//    }
-//
-//    public void setLinkName(String linkName) {
-//        this.linkName = linkName;
-//    }
-//
-//    public Integer getLimitUserCount() {
-//        return limitUserCount;
-//    }
-//
-//    public void setLimitUserCount(Integer limitUserCount) {
-//        this.limitUserCount = limitUserCount;
-//    }
-//
-//    public Date getLimitTime() {
-//        return limitTime;
-//    }
-//
-//    public void setLimitTime(Date limitTime) {
-//        this.limitTime = limitTime;
-//    }
-//
-//    public String getAppId() {
-//        return appId;
-//    }
-//
-//    public void setAppId(String appId) {
-//        this.appId = appId;
-//    }
-//
-//    public String getAppKey() {
-//        return appKey;
-//    }
-//
-//    public void setAppKey(String appKey) {
-//        this.appKey = appKey;
-//    }
-//
-//    public Long getUserId() {
-//        return userId;
-//    }
-//
-//    public void setUserId(Long userId) {
-//        this.userId = userId;
-//    }
-//
-//    public String getAddressId() {
-//        return addressId;
-//    }
-//
-//    public void setAddressId(String addressId) {
-//        this.addressId = addressId;
-//    }
-//
-//    public Integer getCompanyType() {
-//        return companyType;
-//    }
-//
-//    public void setCompanyType(Integer companyType) {
-//        this.companyType = companyType;
-//    }
-//
-//    public static long getSerialVersionUID() {
-//        return serialVersionUID;
-//    }
-//
-//
-//
-//    public String getUserName() {
-//        return userName;
-//    }
-//
-//    public void setUserName(String userName) {
-//        this.userName = userName;
-//    }
-//
-//    public String getPassword() {
-//        return password;
-//    }
-//
-//    public void setPassword(String password) {
-//        this.password = password;
-//    }
-//
-//    public void setCompanyId(Long companyId)
-//    {
-//        this.companyId = companyId;
-//    }
-//
-//    public Long getCompanyId()
-//    {
-//        return companyId;
-//    }
-//    public void setCompanyName(String companyName)
-//    {
-//        this.companyName = companyName;
-//    }
-//
-//    public String getCompanyName()
-//    {
-//        return companyName;
-//    }
-//    public void setCompanyMobile(String companyMobile)
-//    {
-//        this.companyMobile = companyMobile;
-//    }
-//
-//    public String getCompanyMobile()
-//    {
-//        return companyMobile;
-//    }
-//    public void setCompanyAddress(String companyAddress)
-//    {
-//        this.companyAddress = companyAddress;
-//    }
-//
-//    public String getCompanyAddress()
-//    {
-//        return companyAddress;
-//    }
-//    public void setStatus(Integer status)
-//    {
-//        this.status = status;
-//    }
-//
-//    public Integer getStatus()
-//    {
-//        return status;
-//    }
-//    public void setStartTime(Date startTime)
-//    {
-//        this.startTime = startTime;
-//    }
-//
-//    public Date getStartTime()
-//    {
-//        return startTime;
-//    }
-//
-//    public void setMoney(BigDecimal money)
-//    {
-//        this.money = money;
-//    }
-//
-//    public BigDecimal getMoney()
-//    {
-//        return money;
-//    }
-//
-//    public void setVoiceApiId(Long voiceApiId)
-//    {
-//        this.voiceApiId = voiceApiId;
-//    }
-//
-//    public Long getVoiceApiId()
-//    {
-//        return voiceApiId;
-//    }
 
 
 
 
 }
 }

+ 41 - 0
fs-service/src/main/java/com/fs/company/domain/CompanyMiniapp.java

@@ -0,0 +1,41 @@
+package com.fs.company.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 客服公司小程序对象 company_miniapp
+ *
+ * @author fs
+ * @date 2025-07-24
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class CompanyMiniapp extends BaseEntity{
+
+    /** id */
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /** 客服公司ID */
+    @Excel(name = "客服公司ID")
+    private Long companyId;
+
+    /** 小程序appid */
+    @Excel(name = "小程序appid")
+    private String appId;
+
+    /** 主从 0主小程序1备用小程序 */
+    @Excel(name = "主从 0主小程序1备用小程序")
+    private Integer type;
+
+    /** 排序 */
+    @Excel(name = "排序")
+    private Integer sortNum;
+
+
+}

+ 62 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyMiniappMapper.java

@@ -0,0 +1,62 @@
+package com.fs.company.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.company.domain.CompanyMiniapp;
+
+import java.util.List;
+
+/**
+ * 客服公司小程序Mapper接口
+ * 
+ * @author fs
+ * @date 2025-07-24
+ */
+public interface CompanyMiniappMapper extends BaseMapper<CompanyMiniapp>{
+    /**
+     * 查询客服公司小程序
+     * 
+     * @param id 客服公司小程序主键
+     * @return 客服公司小程序
+     */
+    CompanyMiniapp selectCompanyMiniappById(Long id);
+
+    /**
+     * 查询客服公司小程序列表
+     * 
+     * @param companyMiniapp 客服公司小程序
+     * @return 客服公司小程序集合
+     */
+    List<CompanyMiniapp> selectCompanyMiniappList(CompanyMiniapp companyMiniapp);
+
+    /**
+     * 新增客服公司小程序
+     * 
+     * @param companyMiniapp 客服公司小程序
+     * @return 结果
+     */
+    int insertCompanyMiniapp(CompanyMiniapp companyMiniapp);
+
+    /**
+     * 修改客服公司小程序
+     * 
+     * @param companyMiniapp 客服公司小程序
+     * @return 结果
+     */
+    int updateCompanyMiniapp(CompanyMiniapp companyMiniapp);
+
+    /**
+     * 删除客服公司小程序
+     * 
+     * @param id 客服公司小程序主键
+     * @return 结果
+     */
+    int deleteCompanyMiniappById(Long id);
+
+    /**
+     * 批量删除客服公司小程序
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteCompanyMiniappByIds(Long[] ids);
+}

+ 70 - 0
fs-service/src/main/java/com/fs/company/service/ICompanyMiniappService.java

@@ -0,0 +1,70 @@
+package com.fs.company.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.company.domain.CompanyMiniapp;
+import com.fs.company.vo.CompanyVO;
+
+import java.util.List;
+
+/**
+ * 客服公司小程序Service接口
+ * 
+ * @author fs
+ * @date 2025-07-24
+ */
+public interface ICompanyMiniappService extends IService<CompanyMiniapp>{
+    /**
+     * 查询客服公司小程序
+     * 
+     * @param id 客服公司小程序主键
+     * @return 客服公司小程序
+     */
+    CompanyMiniapp selectCompanyMiniappById(Long id);
+
+    /**
+     * 查询客服公司小程序列表
+     * 
+     * @param companyMiniapp 客服公司小程序
+     * @return 客服公司小程序集合
+     */
+    List<CompanyMiniapp> selectCompanyMiniappList(CompanyMiniapp companyMiniapp);
+
+    /**
+     * 新增客服公司小程序
+     * 
+     * @param companyMiniapp 客服公司小程序
+     * @return 结果
+     */
+    int insertCompanyMiniapp(CompanyMiniapp companyMiniapp);
+
+    /**
+     * 修改客服公司小程序
+     * 
+     * @param companyMiniapp 客服公司小程序
+     * @return 结果
+     */
+    int updateCompanyMiniapp(CompanyMiniapp companyMiniapp);
+
+    /**
+     * 批量删除客服公司小程序
+     * 
+     * @param ids 需要删除的客服公司小程序主键集合
+     * @return 结果
+     */
+    int deleteCompanyMiniappByIds(Long[] ids);
+
+    /**
+     * 删除客服公司小程序信息
+     * 
+     * @param id 客服公司小程序主键
+     * @return 结果
+     */
+    int deleteCompanyMiniappById(Long id);
+
+    void insertBatch(List<String> appIds, Long companyId, Integer type);
+
+    void removeByCompanyId(Long companyId);
+
+    void setMiniAppList(List<CompanyVO> companyVOS);
+    List<CompanyMiniapp> getMiniAppListByCompanyList(List<Long> companyIds);
+}

+ 141 - 0
fs-service/src/main/java/com/fs/company/service/impl/CompanyMiniappServiceImpl.java

@@ -0,0 +1,141 @@
+package com.fs.company.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.PubFun;
+import com.fs.company.domain.CompanyMiniapp;
+import com.fs.company.mapper.CompanyMiniappMapper;
+import com.fs.company.service.ICompanyMiniappService;
+import com.fs.company.vo.CompanyVO;
+import org.springframework.stereotype.Service;
+
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.BiFunction;
+import java.util.stream.Collectors;
+
+/**
+ * 客服公司小程序Service业务层处理
+ * 
+ * @author fs
+ * @date 2025-07-24
+ */
+@Service
+public class CompanyMiniappServiceImpl extends ServiceImpl<CompanyMiniappMapper, CompanyMiniapp> implements ICompanyMiniappService {
+
+    public static BiFunction<Integer, List<CompanyMiniapp>, List<String>> GET_MINI_APP_STR = (type, list) -> list.stream().filter(m -> Objects.equals(m.getType(), type)).sorted(Comparator.comparing(CompanyMiniapp::getSortNum)).map(CompanyMiniapp::getAppId).collect(Collectors.toList());
+
+
+    /**
+     * 查询客服公司小程序
+     * 
+     * @param id 客服公司小程序主键
+     * @return 客服公司小程序
+     */
+    @Override
+    public CompanyMiniapp selectCompanyMiniappById(Long id)
+    {
+        return baseMapper.selectCompanyMiniappById(id);
+    }
+
+    /**
+     * 查询客服公司小程序列表
+     * 
+     * @param companyMiniapp 客服公司小程序
+     * @return 客服公司小程序
+     */
+    @Override
+    public List<CompanyMiniapp> selectCompanyMiniappList(CompanyMiniapp companyMiniapp)
+    {
+        return baseMapper.selectCompanyMiniappList(companyMiniapp);
+    }
+
+    /**
+     * 新增客服公司小程序
+     * 
+     * @param companyMiniapp 客服公司小程序
+     * @return 结果
+     */
+    @Override
+    public int insertCompanyMiniapp(CompanyMiniapp companyMiniapp)
+    {
+        companyMiniapp.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertCompanyMiniapp(companyMiniapp);
+    }
+
+    /**
+     * 修改客服公司小程序
+     * 
+     * @param companyMiniapp 客服公司小程序
+     * @return 结果
+     */
+    @Override
+    public int updateCompanyMiniapp(CompanyMiniapp companyMiniapp)
+    {
+        companyMiniapp.setUpdateTime(DateUtils.getNowDate());
+        return baseMapper.updateCompanyMiniapp(companyMiniapp);
+    }
+
+    /**
+     * 批量删除客服公司小程序
+     * 
+     * @param ids 需要删除的客服公司小程序主键
+     * @return 结果
+     */
+    @Override
+    public int deleteCompanyMiniappByIds(Long[] ids)
+    {
+        return baseMapper.deleteCompanyMiniappByIds(ids);
+    }
+
+    /**
+     * 删除客服公司小程序信息
+     * 
+     * @param id 客服公司小程序主键
+     * @return 结果
+     */
+    @Override
+    public int deleteCompanyMiniappById(Long id)
+    {
+        return baseMapper.deleteCompanyMiniappById(id);
+    }
+
+    @Override
+    public void insertBatch(List<String> appIds, Long companyId, Integer type) {
+        AtomicInteger i = new AtomicInteger();
+        List<CompanyMiniapp> list = appIds.stream().map(e -> {
+            CompanyMiniapp miniapp = new CompanyMiniapp();
+            miniapp.setCompanyId(companyId);
+            miniapp.setAppId(e);
+            miniapp.setType(type);
+            miniapp.setSortNum(i.getAndIncrement());
+            return miniapp;
+        }).collect(Collectors.toList());
+        super.saveBatch(list);
+    }
+
+    @Override
+    public void removeByCompanyId(Long companyId) {
+        remove(new QueryWrapper<CompanyMiniapp>().eq("company_id",companyId));
+    }
+
+    @Override
+    public void setMiniAppList(List<CompanyVO> companyVOS) {
+        List<CompanyMiniapp> miniAppList = getMiniAppListByCompanyList(PubFun.listToNewList(companyVOS, CompanyVO::getCompanyId));
+        Map<Long, List<CompanyMiniapp>> miniAppMap = PubFun.listToMapByGroupList(miniAppList, CompanyMiniapp::getCompanyId);
+        companyVOS.stream().filter(e -> miniAppMap.containsKey(e.getCompanyId())).forEach(e -> {
+            List<CompanyMiniapp> list = miniAppMap.get(e.getCompanyId());
+            e.setMiniAppMaster(GET_MINI_APP_STR.apply(0, list));
+            e.setMiniAppServer(GET_MINI_APP_STR.apply(1, list));
+        });
+    }
+
+    @Override
+    public List<CompanyMiniapp> getMiniAppListByCompanyList(List<Long> companyIds) {
+        return list(new QueryWrapper<CompanyMiniapp>().in("company_id", companyIds));
+    }
+}

+ 18 - 1
fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java

@@ -13,6 +13,7 @@ import com.fs.common.utils.StringUtils;
 import com.fs.company.domain.*;
 import com.fs.company.domain.*;
 import com.fs.company.mapper.*;
 import com.fs.company.mapper.*;
 import com.fs.company.param.CompanyParam;
 import com.fs.company.param.CompanyParam;
+import com.fs.company.service.ICompanyMiniappService;
 import com.fs.company.service.ICompanyProfitService;
 import com.fs.company.service.ICompanyProfitService;
 import com.fs.company.service.ICompanyRoleService;
 import com.fs.company.service.ICompanyRoleService;
 import com.fs.company.vo.CompanyCrmVO;
 import com.fs.company.vo.CompanyCrmVO;
@@ -54,6 +55,8 @@ public class CompanyServiceImpl implements ICompanyService
     @Autowired
     @Autowired
     private CompanyMapper companyMapper;
     private CompanyMapper companyMapper;
     @Autowired
     @Autowired
+    private ICompanyMiniappService companyMiniappService;
+    @Autowired
     private CompanyDeptMapper deptMapper;
     private CompanyDeptMapper deptMapper;
     @Autowired
     @Autowired
     private ICompanyRoleService roleService;
     private ICompanyRoleService roleService;
@@ -232,7 +235,7 @@ public class CompanyServiceImpl implements ICompanyService
             userPostMapper.insertCompanyUserPost(userPost);
             userPostMapper.insertCompanyUserPost(userPost);
             company.setUserId(user.getUserId());
             company.setUserId(user.getUserId());
             companyMapper.updateCompany(company);
             companyMapper.updateCompany(company);
-
+            bindMiniApp(company);
             return R.ok();
             return R.ok();
         }
         }
         else
         else
@@ -251,8 +254,22 @@ public class CompanyServiceImpl implements ICompanyService
     public int updateCompany(Company company)
     public int updateCompany(Company company)
     {
     {
         company.setUpdateTime(DateUtils.getNowDate());
         company.setUpdateTime(DateUtils.getNowDate());
+        bindMiniApp(company);
         return companyMapper.updateCompany(company);
         return companyMapper.updateCompany(company);
     }
     }
+    // 绑定小程序
+    public void bindMiniApp(Company company){
+        companyMiniappService.removeByCompanyId(company.getCompanyId());
+        List<String> miniAppMaster = company.getMiniAppMaster();
+        if(miniAppMaster != null && !miniAppMaster.isEmpty()){
+            companyMiniappService.insertBatch(miniAppMaster, company.getCompanyId(), 0);
+        }
+        List<String> miniAppServer = company.getMiniAppServer();
+        if(miniAppServer != null && !miniAppServer.isEmpty()){
+            companyMiniappService.insertBatch(miniAppServer, company.getCompanyId(), 1);
+        }
+
+    }
 
 
     /**
     /**
      * 批量删除企业
      * 批量删除企业

+ 3 - 0
fs-service/src/main/java/com/fs/company/vo/CompanyVO.java

@@ -7,6 +7,7 @@ import lombok.Data;
 import java.io.Serializable;
 import java.io.Serializable;
 import java.math.BigDecimal;
 import java.math.BigDecimal;
 import java.util.Date;
 import java.util.Date;
+import java.util.List;
 
 
 /**
 /**
  * 企业账户记录对象 company_money_logs
  * 企业账户记录对象 company_money_logs
@@ -86,4 +87,6 @@ public class CompanyVO implements Serializable
     private String followDoctorName;
     private String followDoctorName;
 
 
     private String restartTime;
     private String restartTime;
+    private List<String> miniAppMaster;
+    private List<String> miniAppServer;
 }
 }

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

@@ -165,6 +165,34 @@ public interface FsCourseWatchLogMapper extends BaseMapper<FsCourseWatchLog> {
             "\tAND wl.create_time < CURDATE() ")
             "\tAND wl.create_time < CURDATE() ")
     List<QwRatingVO> selectFsCourseWatchLogByExtIdRating(@Param("externalId") Long externalId, @Param("dayNum") Integer dayNum);
     List<QwRatingVO> selectFsCourseWatchLogByExtIdRating(@Param("externalId") Long externalId, @Param("dayNum") Integer dayNum);
 
 
+    @Select("SELECT\n" +
+            "\twl.duration AS watchDuration,\n" +
+            "\tcv.duration AS allDuration,\n" +
+            "\twl.finish_time,\n" +
+            "\twl.create_time," +
+            "\tec.`level` \n" +
+            "FROM\n" +
+            "\tfs_course_watch_log wl\n" +
+            "\tLEFT JOIN qw_external_contact ec ON wl.qw_external_contact_id = ec.id\n" +
+            "\tLEFT JOIN fs_user_course_video cv ON wl.video_id = cv.video_id \n" +
+            "WHERE\n" +
+            "\twl.send_type = 2 \n" +
+            "\tAND wl.qw_external_contact_id = #{externalId} \n" +
+            "\tAND wl.create_time >= DATE_SUB(CURDATE(), INTERVAL #{dayNum} DAY ) \n" +
+            "\tAND wl.create_time < CURDATE()")
+    List<QwRatingVO> selectFsCourseWatchLogByExtIdRatingMoreStudyDays(@Param("externalId") Long externalId, @Param("dayNum") Integer dayNum);
+
+    @Select("SELECT\n" +
+            "\tCOALESCE(SUM(wl.duration), 0) AS watchDuration\n" +
+            "FROM\n" +
+            "\tfs_course_watch_log wl\n" +
+            "WHERE\n" +
+            "\twl.send_type = 2 \n" +
+            "\tAND wl.qw_external_contact_id = #{externalId} \n" +
+            "\tAND wl.create_time >= DATE_SUB( CURDATE(), INTERVAL #{dayNum} DAY ) \n" +
+            "\tAND wl.create_time < CURDATE()")
+    Integer selectFsCourseWatchLogByByIsDaysNotStudy(@Param("externalId") Long externalId,@Param("dayNum") Integer dayNum);
+
     @Select("select l.*,v.title,c.course_name from fs_course_watch_log l LEFT JOIN fs_user_course_video v ON v.video_id = l.video_id LEFT JOIN fs_user_course c ON c.course_id = l.course_id WHERE l.qw_external_contact_id =#{ExtId} and l.qw_user_id=#{QwUserId} and DATE(l.create_time) =CURDATE() ORDER BY l.create_time  desc LIMIT 1  ")
     @Select("select l.*,v.title,c.course_name from fs_course_watch_log l LEFT JOIN fs_user_course_video v ON v.video_id = l.video_id LEFT JOIN fs_user_course c ON c.course_id = l.course_id WHERE l.qw_external_contact_id =#{ExtId} and l.qw_user_id=#{QwUserId} and DATE(l.create_time) =CURDATE() ORDER BY l.create_time  desc LIMIT 1  ")
     FsCourseWatchLogVO selectFsCourseWatchLogByExtIdAndQwUserId(@Param("ExtId")String ExtId,@Param("QwUserId")Long QwUserId);
     FsCourseWatchLogVO selectFsCourseWatchLogByExtIdAndQwUserId(@Param("ExtId")String ExtId,@Param("QwUserId")Long QwUserId);
 
 

+ 4 - 0
fs-service/src/main/java/com/fs/his/vo/FsStoreOrderExportVO.java

@@ -64,6 +64,10 @@ public class FsStoreOrderExportVO implements Serializable
     @Excel(name = "商品金额",cellType= Excel.ColumnType.NUMERIC)
     @Excel(name = "商品金额",cellType= Excel.ColumnType.NUMERIC)
     private BigDecimal totalPrice;
     private BigDecimal totalPrice;
 
 
+    /** 商品数量 */
+    @Excel(name = "商品数量")
+    private Integer totalNum;
+
 
 
     /** 实际支付金额 */
     /** 实际支付金额 */
     @Excel(name = "应付金额",cellType= Excel.ColumnType.NUMERIC)
     @Excel(name = "应付金额",cellType= Excel.ColumnType.NUMERIC)

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

@@ -78,6 +78,10 @@ public interface QwExternalContactMapper extends BaseMapper<QwExternalContact> {
                                                   @Param("corpId") String corpId);
                                                   @Param("corpId") String corpId);
 
 
 
 
+    public int batchUpdateQwExternalContactByMoreStudy(List<QwExternalContact> qwExternalContact);
+    public int batchUpdateQwExternalByIsDaysNotStudy(List<QwExternalContact> qwExternalContact);
+
+
     @Select("SELECT * FROM qw_external_contact WHERE external_user_id = #{externalUserId}  AND corp_id=#{corpId} and user_id=#{qwUserId} limit 1")
     @Select("SELECT * FROM qw_external_contact WHERE external_user_id = #{externalUserId}  AND corp_id=#{corpId} and user_id=#{qwUserId} limit 1")
     public QwExternalContact selectQwExternalContactByExternalUserIdAndQwUserId(@Param("externalUserId") String externalUserId,@Param("corpId") String corpId,@Param("qwUserId") String qwUserId);
     public QwExternalContact selectQwExternalContactByExternalUserIdAndQwUserId(@Param("externalUserId") String externalUserId,@Param("corpId") String corpId,@Param("qwUserId") String qwUserId);
 
 

+ 6 - 0
fs-service/src/main/java/com/fs/sop/domain/SopUserLogsInfo.java

@@ -73,6 +73,12 @@ public class SopUserLogsInfo implements Serializable {
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private String inComingETime;
     private String inComingETime;
 
 
+
+    /**
+     * 评级
+     */
+    private Integer grade;
+
     /**
     /**
      * 营期时间
      * 营期时间
      */
      */

+ 52 - 0
fs-service/src/main/java/com/fs/sop/mapper/SopUserLogsInfoMapper.java

@@ -2,6 +2,7 @@ package com.fs.sop.mapper;
 
 
 import com.fs.common.annotation.DataSource;
 import com.fs.common.annotation.DataSource;
 import com.fs.common.enums.DataSourceType;
 import com.fs.common.enums.DataSourceType;
+import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.param.QwExtCourseSopWatchLog;
 import com.fs.qw.param.QwExtCourseSopWatchLog;
 import com.fs.sop.domain.SopUserLogsInfo;
 import com.fs.sop.domain.SopUserLogsInfo;
 import com.fs.sop.params.BatchSopUserLogsInfoParamU;
 import com.fs.sop.params.BatchSopUserLogsInfoParamU;
@@ -148,11 +149,62 @@ public interface SopUserLogsInfoMapper {
     @DataSource(DataSourceType.SOP)
     @DataSource(DataSourceType.SOP)
     List<SopUserLogsInfo> selectSopUserLogsInfoListBySopId(@Param("sopId") String sopId, @Param("userLogsId") String userLogsId);
     List<SopUserLogsInfo> selectSopUserLogsInfoListBySopId(@Param("sopId") String sopId, @Param("userLogsId") String userLogsId);
 
 
+    @DataSource(DataSourceType.SOP)
+    List<SopUserLogsInfo> selectRestoreByIsDaysNotStudy(@Param("sopId") String sopId, @Param("userLogsId") String userLogsId);
+
 
 
 
 
     @DataSource(DataSourceType.SOP)
     @DataSource(DataSourceType.SOP)
     void batchInsertSopUserLogsInfo(@Param("SopUserLogsInfo") List<SopUserLogsInfo> logsToInsert);
     void batchInsertSopUserLogsInfo(@Param("SopUserLogsInfo") List<SopUserLogsInfo> logsToInsert);
 
 
+
+    @DataSource(DataSourceType.SOP)
+    @Update("<script>" +
+            "UPDATE sop_user_logs_info " +
+            "SET is_days_not_study = CASE " +
+            "<foreach collection='contactList' item='item'> " +
+            "    WHEN external_id = #{item.id} THEN " +
+            "    CASE WHEN #{item.level} = 5 AND #{item.isDaysNotStudy}=1 THEN 1 ELSE 0 END " +
+            "</foreach> " +
+            "ELSE is_days_not_study " +
+            "END " +
+            "WHERE external_id IN " +
+            "<foreach collection='contactList' item='item' open='(' separator=',' close=')'> " +
+            "    #{item.id} " +
+            "</foreach>" +
+            "</script>")
+    void batchUpdateSopUserLogsInfoByMoreStudy(@Param("contactList") List<QwExternalContact> contactList);
+
+    @DataSource(DataSourceType.SOP)
+    @Update("<script>" +
+            "UPDATE sop_user_logs_info " +
+            "SET is_days_not_study = 0 " +
+            "WHERE external_id IN " +
+            "<foreach collection='contactList' item='item' open='(' separator=',' close=')'>" +
+            "    #{item.id} " +
+            "</foreach>" +
+            "</script>")
+    void batchUpdateSopUserLogsInfoByIsDaysNotStudy(@Param("contactList") List<QwExternalContact> contactList);
+
+    @DataSource(DataSourceType.SOP)
+    @Update("<script>" +
+            "UPDATE sop_user_logs_info " +
+            "SET grade = CASE external_id " +
+            "<foreach collection=\"contactList\" item=\"item\">" +
+            "    WHEN #{item.id} THEN #{item.level} " +
+            "</foreach>" +
+            "    ELSE grade " +
+            "END " +
+            "WHERE external_id IN " +
+            "<foreach collection='contactList' item='item' open='(' separator=',' close=')'>" +
+            "    #{item.id} " +
+            "</foreach>" +
+            "</script>")
+    void batchUpdateSopUserLogsInfoByLevel(@Param("contactList") List<QwExternalContact> contactList);
+
+
+
+
     @DataSource(DataSourceType.SOP)
     @DataSource(DataSourceType.SOP)
     void batchUpdateSopUserLogsInfoToTime(BatchSopUserLogsInfoParamU paramU);
     void batchUpdateSopUserLogsInfoToTime(BatchSopUserLogsInfoParamU paramU);
 
 

+ 7 - 0
fs-service/src/main/java/com/fs/sop/mapper/SopUserLogsMapper.java

@@ -64,6 +64,13 @@ public interface SopUserLogsMapper {
     @DataSource(DataSourceType.SOP)
     @DataSource(DataSourceType.SOP)
     public List<SopUserLogs> meetsTheRatingByUserInfoWithPagination(@Param("offset") int offset,@Param("pageSize") int pageSize);
     public List<SopUserLogs> meetsTheRatingByUserInfoWithPagination(@Param("offset") int offset,@Param("pageSize") int pageSize);
 
 
+    @DataSource(DataSourceType.SOP)
+    public List<SopUserLogs> meetsTheRatingByUserInfoWithPaginationStudyDays(@Param("offset") int offset,@Param("pageSize") int pageSize,@Param("notStudyDays") Integer notStudyDays);
+
+    @DataSource(DataSourceType.SOP)
+    public List<SopUserLogs> meetsTherestoreByIsDaysNotStudy(@Param("offset") int offset,@Param("pageSize") int pageSize,@Param("notStudyDays") Integer notStudyDays);
+
+
     @DataSource(DataSourceType.SOP)
     @DataSource(DataSourceType.SOP)
     public List<SopUserLogs> meetsTheRatingByUserInfoBySopId(@Param("sopId") String sopId);
     public List<SopUserLogs> meetsTheRatingByUserInfoBySopId(@Param("sopId") String sopId);
 
 

+ 1 - 0
fs-service/src/main/java/com/fs/sop/params/QwRatingConfig.java

@@ -5,6 +5,7 @@ import lombok.Data;
 @Data
 @Data
 public class QwRatingConfig {
 public class QwRatingConfig {
     private Integer levelDay;
     private Integer levelDay;
+    private Integer notStudyDays;
     private Integer aLevelMin;
     private Integer aLevelMin;
     private Integer aLevelMax;
     private Integer aLevelMax;
     private Integer bLevelMin;
     private Integer bLevelMin;

+ 8 - 0
fs-service/src/main/java/com/fs/sop/service/ISopUserLogsInfoService.java

@@ -1,6 +1,7 @@
 package com.fs.sop.service;
 package com.fs.sop.service;
 
 
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
+import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.param.QwExtCourseSopWatchLog;
 import com.fs.qw.param.QwExtCourseSopWatchLog;
 import com.fs.sop.domain.SopUserLogsInfo;
 import com.fs.sop.domain.SopUserLogsInfo;
 import com.fs.sop.params.BatchSopUserLogsInfoParam;
 import com.fs.sop.params.BatchSopUserLogsInfoParam;
@@ -54,6 +55,11 @@ public interface ISopUserLogsInfoService {
     List<SopUserLogsInfoVOE> selectSopUserLogsInfoListVO(SopUserLogsInfo info);
     List<SopUserLogsInfoVOE> selectSopUserLogsInfoListVO(SopUserLogsInfo info);
 
 
     void batchInsertSopUserLogsInfo(List<SopUserLogsInfo> logsToInsert);
     void batchInsertSopUserLogsInfo(List<SopUserLogsInfo> logsToInsert);
+
+    void batchUpdateSopUserLogsInfoByMoreStudy(List<QwExternalContact> contactList);
+    void batchUpdateSopUserLogsInfoByIsDaysNotStudy(List<QwExternalContact> contactList);
+    void batchUpdateSopUserLogsInfoByLevel(List<QwExternalContact> contactList);
+
     void insertSopUserLogsInfo(SopUserLogsInfo logsToInsert);
     void insertSopUserLogsInfo(SopUserLogsInfo logsToInsert);
     /**
     /**
      * 查询sopUserLogsInfo
      * 查询sopUserLogsInfo
@@ -74,5 +80,7 @@ public interface ISopUserLogsInfoService {
     public R sendUserLogsInfoMsg(SendUserLogsInfoMsgParam param);
     public R sendUserLogsInfoMsg(SendUserLogsInfoMsgParam param);
     public R sendUserLogsInfoMsgType(SendUserLogsInfoMsgParam param);
     public R sendUserLogsInfoMsgType(SendUserLogsInfoMsgParam param);
 
 
+    List<SopUserLogsInfo> selectRestoreByIsDaysNotStudy(String sopId, String userLogsId);
+
     public List<ExtCourseSopWatchLogVO> getExtCourseSopWatchLog(QwExtCourseSopWatchLog qwExternalContactId);
     public List<ExtCourseSopWatchLogVO> getExtCourseSopWatchLog(QwExtCourseSopWatchLog qwExternalContactId);
 }
 }

+ 3 - 0
fs-service/src/main/java/com/fs/sop/service/ISopUserLogsService.java

@@ -61,4 +61,7 @@ public interface ISopUserLogsService {
     void updateLogDate(UpdateSopUserLogDateVo vo);
     void updateLogDate(UpdateSopUserLogDateVo vo);
 
 
     void addGroupChat(AddSopUserGroupChat vo);
     void addGroupChat(AddSopUserGroupChat vo);
+
+    public List<SopUserLogs> meetsTherestoreByIsDaysNotStudy(int offset,int pageSize,Integer notStudyDays);
+
 }
 }

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

@@ -3,12 +3,15 @@ package com.fs.sop.service.impl;
 import cn.hutool.json.JSONUtil;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONArray;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
 import com.fs.common.exception.base.BaseException;
 import com.fs.common.exception.base.BaseException;
 import com.fs.common.utils.PubFun;
 import com.fs.common.utils.PubFun;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.date.DateUtil;
 import com.fs.common.utils.date.DateUtil;
+import com.fs.company.domain.CompanyMiniapp;
 import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.company.mapper.CompanyUserMapper;
+import com.fs.company.service.ICompanyMiniappService;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.FsCourseDomainName;
 import com.fs.course.domain.FsCourseDomainName;
 import com.fs.course.domain.FsCourseLink;
 import com.fs.course.domain.FsCourseLink;
@@ -153,6 +156,9 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
     @Autowired
     @Autowired
     private QwGroupChatUserMapper qwGroupChatUserMapper;
     private QwGroupChatUserMapper qwGroupChatUserMapper;
 
 
+    @Autowired
+    private ICompanyMiniappService companyMiniappService;
+
     @Override
     @Override
     public void save(SopUserLogsInfo sopUserLogsInfo) {
     public void save(SopUserLogsInfo sopUserLogsInfo) {
         sopUserLogsInfoMapper.insertSopUserLogsInfo(sopUserLogsInfo);
         sopUserLogsInfoMapper.insertSopUserLogsInfo(sopUserLogsInfo);
@@ -218,6 +224,21 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
         sopUserLogsInfoMapper.batchInsertSopUserLogsInfo(logsToInsert);
         sopUserLogsInfoMapper.batchInsertSopUserLogsInfo(logsToInsert);
     }
     }
 
 
+    @Override
+    public void batchUpdateSopUserLogsInfoByMoreStudy(List<QwExternalContact> contactList) {
+        sopUserLogsInfoMapper.batchUpdateSopUserLogsInfoByMoreStudy(contactList);
+    }
+
+    @Override
+    public void batchUpdateSopUserLogsInfoByIsDaysNotStudy(List<QwExternalContact> contactList) {
+        sopUserLogsInfoMapper.batchUpdateSopUserLogsInfoByIsDaysNotStudy(contactList);
+    }
+
+    @Override
+    public void batchUpdateSopUserLogsInfoByLevel(List<QwExternalContact> contactList) {
+        sopUserLogsInfoMapper.batchUpdateSopUserLogsInfoByLevel(contactList);
+    }
+
     @Override
     @Override
     public void insertSopUserLogsInfo(SopUserLogsInfo logsToInsert) {
     public void insertSopUserLogsInfo(SopUserLogsInfo logsToInsert) {
         sopUserLogsInfoMapper.insertSopUserLogsInfo(logsToInsert);
         sopUserLogsInfoMapper.insertSopUserLogsInfo(logsToInsert);
@@ -698,6 +719,14 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                 }).collect(Collectors.toList());
                 }).collect(Collectors.toList());
             }
             }
         }else{
         }else{
+
+
+            // 查询公司关联小程序数据
+            List<CompanyMiniapp> miniList = companyMiniappService.list(new QueryWrapper<CompanyMiniapp>().orderByAsc("sort_num"));
+
+            Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap = miniList.stream().collect(Collectors.groupingBy(CompanyMiniapp::getCompanyId, Collectors.groupingBy(CompanyMiniapp::getType)));
+
+
             sopLogsList = new ArrayList<>();
             sopLogsList = new ArrayList<>();
             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
             List<SopUserLogsInfo> sopUserLogsInfos = sopUserLogsInfoMapper.selectSopUserLogsInfoByIds(param.getIds());
             List<SopUserLogsInfo> sopUserLogsInfos = sopUserLogsInfoMapper.selectSopUserLogsInfoByIds(param.getIds());
@@ -810,12 +839,28 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                             String linkByMiniApp = createLinkByMiniApp(st, param.getCorpId(), createTime, param.getCourseId(), param.getVideoId(),
                             String linkByMiniApp = createLinkByMiniApp(st, param.getCorpId(), createTime, param.getCourseId(), param.getVideoId(),
                                     qwUserId, companyUserId, companyId, item.getExternalId(), config);
                                     qwUserId, companyUserId, companyId, item.getExternalId(), config);
 
 
-                            if (StringUtil.strIsNullOrEmpty(qwCompany.getMiniAppId())){
-                                log.error("企业未配置小程序-"+param.getCorpId());
-                            }else {
-                                //置换各自的小程序
+                            if (!miniMap.isEmpty() && qwUser.getSendMsgType() == 1) {
+                                Map<Integer, List<CompanyMiniapp>> integerListMap = miniMap.get(Long.valueOf(companyId));
+                                if (integerListMap != null) {
+
+                                    int effectiveGrade = (item.getGrade() == null) ? 5 : item.getGrade();
+                                    int listIndex = (effectiveGrade == 1 || effectiveGrade == 2) ? 0 : 1;
+                                    List<CompanyMiniapp> miniapps = integerListMap.get(listIndex);
+
+                                    if (miniapps != null && !miniapps.isEmpty()) {
+                                        CompanyMiniapp companyMiniapp = miniapps.get(0);
+                                        if (companyMiniapp != null && !StringUtil.strIsNullOrEmpty(companyMiniapp.getAppId())) {
+                                            st.setMiniprogramAppid(companyMiniapp.getAppId());
+                                        }
+                                    }
+                                }
+                            } else if (!StringUtil.strIsNullOrEmpty(qwCompany.getMiniAppId())) {
                                 st.setMiniprogramAppid(qwCompany.getMiniAppId());
                                 st.setMiniprogramAppid(qwCompany.getMiniAppId());
+                            } else {
+                                log.error("公司的小程序id为空:采用了前端传的固定值" + sopLogs.getSopId());
                             }
                             }
+
+
                             st.setMiniprogramPage(linkByMiniApp);
                             st.setMiniprogramPage(linkByMiniApp);
 
 
                             break;
                             break;
@@ -874,6 +919,11 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
         return null;
         return null;
     }
     }
 
 
+    @Override
+    public List<SopUserLogsInfo> selectRestoreByIsDaysNotStudy(String sopId, String userLogsId) {
+        return sopUserLogsInfoMapper.selectRestoreByIsDaysNotStudy(sopId, userLogsId);
+    }
+
     @Override
     @Override
     public List<ExtCourseSopWatchLogVO> getExtCourseSopWatchLog(QwExtCourseSopWatchLog qwExternalContactId) {
     public List<ExtCourseSopWatchLogVO> getExtCourseSopWatchLog(QwExtCourseSopWatchLog qwExternalContactId) {
 
 
@@ -915,6 +965,9 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
 
 
         List<SopUserLogsInfo> sopUserLogs = sopUserLogsMapper.selectSopUserLogsByIds(param.getIds());
         List<SopUserLogsInfo> sopUserLogs = sopUserLogsMapper.selectSopUserLogsByIds(param.getIds());
 
 
+        // 查询公司关联小程序数据
+        List<CompanyMiniapp> miniList = companyMiniappService.list(new QueryWrapper<CompanyMiniapp>().orderByAsc("sort_num"));
+        Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap = miniList.stream().collect(Collectors.groupingBy(CompanyMiniapp::getCompanyId, Collectors.groupingBy(CompanyMiniapp::getType)));
 
 
         //排序
         //排序
         int sort = 0;
         int sort = 0;
@@ -955,7 +1008,8 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                 log.error("员工信息用户不存在:" + key.getKey()+",企业id:"+key.getValue());
                 log.error("员工信息用户不存在:" + key.getKey()+",企业id:"+key.getValue());
             }else {
             }else {
 
 
-                List<QwSopLogs> sopLogsList = processInsertSopUserLogsInfo(logs, qwUser, param, words, config, qwCompany, finalSort, finalSendType);
+                List<QwSopLogs> sopLogsList = processInsertSopUserLogsInfo(logs, qwUser, param, words, config, qwCompany, finalSort,
+                        finalSendType,miniMap );
 
 
                 //批量插入 发送记录
                 //批量插入 发送记录
                 if (!sopLogsList.isEmpty()) {
                 if (!sopLogsList.isEmpty()) {
@@ -972,7 +1026,8 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
 
 
     private List<QwSopLogs> processInsertSopUserLogsInfo(List<SopUserLogsInfo> sopUserLogsInfos,QwUser qwUser,
     private List<QwSopLogs> processInsertSopUserLogsInfo(List<SopUserLogsInfo> sopUserLogsInfos,QwUser qwUser,
                                                          SendUserLogsInfoMsgParam param,List<FastGptChatReplaceWords> words,
                                                          SendUserLogsInfoMsgParam param,List<FastGptChatReplaceWords> words,
-                                                         CourseConfig config,QwCompany qwCompany,int finalSort,int finalSendType){
+                                                         CourseConfig config,QwCompany qwCompany,int finalSort,int finalSendType,
+                                                         Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap){
 
 
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 
 
@@ -1026,7 +1081,8 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
 
 
             switch (finalSendType){
             switch (finalSendType){
                 case 5:
                 case 5:
-                    List<QwSopCourseFinishTempSetting.Setting> list = processSetting(item,qwUser, param, words, config, qwCompany,companyUserId,companyId,contact,dataTime, finalDomainName);
+                    List<QwSopCourseFinishTempSetting.Setting> list = processSetting(item,qwUser, param, words, config, qwCompany,companyUserId,companyId,
+                            contact,dataTime, finalDomainName,miniMap);
                     setting.setSetting(list);
                     setting.setSetting(list);
                     break;
                     break;
                 case 9:
                 case 9:
@@ -1088,7 +1144,8 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
     private List<QwSopCourseFinishTempSetting.Setting> processSetting(SopUserLogsInfo item, QwUser qwUser,
     private List<QwSopCourseFinishTempSetting.Setting> processSetting(SopUserLogsInfo item, QwUser qwUser,
                                                                       SendUserLogsInfoMsgParam param,List<FastGptChatReplaceWords> words,
                                                                       SendUserLogsInfoMsgParam param,List<FastGptChatReplaceWords> words,
                                                                       CourseConfig config,QwCompany qwCompany,String companyUserId, String companyId,
                                                                       CourseConfig config,QwCompany qwCompany,String companyUserId, String companyId,
-                                                                      QwExternalContact contact,Date dataTime,String domainName){
+                                                                      QwExternalContact contact,Date dataTime,String domainName,
+                                                                      Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap){
         List<QwSopCourseFinishTempSetting.Setting> list = JSONArray.parseArray(param.getSetting(),QwSopCourseFinishTempSetting.Setting.class);
         List<QwSopCourseFinishTempSetting.Setting> list = JSONArray.parseArray(param.getSetting(),QwSopCourseFinishTempSetting.Setting.class);
 
 
         for (QwSopCourseFinishTempSetting.Setting st : list) {
         for (QwSopCourseFinishTempSetting.Setting st : list) {
@@ -1158,13 +1215,27 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
 //                    }else {
 //                    }else {
 //                        st.setMiniprogramAppid(config.getMiniprogramAppid());
 //                        st.setMiniprogramAppid(config.getMiniprogramAppid());
 //                    }
 //                    }
-                    if (StringUtil.strIsNullOrEmpty(qwCompany.getMiniAppId())){
-                        log.error("企业未配置小程序-"+param.getCorpId());
-
-                    }else {
-                        //置换各自的小程序
+                    if (!miniMap.isEmpty() && qwUser.getSendMsgType() == 1) {
+                        Map<Integer, List<CompanyMiniapp>> integerListMap = miniMap.get(Long.valueOf(companyId));
+                        if (integerListMap != null) {
+
+                            int effectiveGrade = (item.getGrade() == null) ? 5 : item.getGrade();
+                            int listIndex = (effectiveGrade == 1 || effectiveGrade == 2) ? 0 : 1;
+                            List<CompanyMiniapp> miniapps = integerListMap.get(listIndex);
+
+                            if (miniapps != null && !miniapps.isEmpty()) {
+                                CompanyMiniapp companyMiniapp = miniapps.get(0);
+                                if (companyMiniapp != null && !StringUtil.strIsNullOrEmpty(companyMiniapp.getAppId())) {
+                                    st.setMiniprogramAppid(companyMiniapp.getAppId());
+                                }
+                            }
+                        }
+                    } else if (!StringUtil.strIsNullOrEmpty(qwCompany.getMiniAppId())) {
                         st.setMiniprogramAppid(qwCompany.getMiniAppId());
                         st.setMiniprogramAppid(qwCompany.getMiniAppId());
+                    } else {
+                        log.error("企业未配置小程序-" + param.getCorpId());
                     }
                     }
+
                     st.setMiniprogramPage(linkByMiniApp);
                     st.setMiniprogramPage(linkByMiniApp);
                     break;
                     break;
                 default:
                 default:

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

@@ -955,6 +955,11 @@ public class SopUserLogsServiceImpl  implements ISopUserLogsService {
         sopUserLogsMapper.batchInsertSopUserLogs(list);
         sopUserLogsMapper.batchInsertSopUserLogs(list);
     }
     }
 
 
+    @Override
+    public List<SopUserLogs> meetsTherestoreByIsDaysNotStudy(int offset, int pageSize, Integer notStudyDays) {
+        return sopUserLogsMapper.meetsTherestoreByIsDaysNotStudy(offset,pageSize,notStudyDays);
+    }
+
     //批量更新
     //批量更新
     private void batchUpdateQwExternalContact(List<QwExternalContact> notInExternalUseridList) {
     private void batchUpdateQwExternalContact(List<QwExternalContact> notInExternalUseridList) {
         // 定义批量插入的大小
         // 定义批量插入的大小

+ 1 - 1
fs-service/src/main/java/com/fs/sop/vo/QwRatingVO.java

@@ -16,7 +16,7 @@ public class QwRatingVO {
     */
     */
     private Integer allDuration;
     private Integer allDuration;
 
 
-
+    private Integer level;
 
 
     /**
     /**
      * 1升 2降 3未变动
      * 1升 2降 3未变动

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

@@ -85,7 +85,7 @@ cloud_host:
   company_name: 恒春来
   company_name: 恒春来
 #看课授权时显示的头像
 #看课授权时显示的头像
 headerImg:
 headerImg:
-  imgUrl: https://hcl-1b2b.obs.cn-south-1.myhuaweicloud.com/fs/20250803/1754213762409.png
+  imgUrl: http://hcl-1b2b.obs.cn-south-1.myhuaweicloud.com/fs/20250808/1754640068227.png
 ipad:
 ipad:
   ipadUrl: http://ipad.cdwjyyh.com
   ipadUrl: http://ipad.cdwjyyh.com
   aiApi:
   aiApi:

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

@@ -82,6 +82,7 @@ headerImg:
   imgUrl: https://drk-1363981074.cos.ap-chongqing.myqcloud.com/fs/logo/30d7a0d1ec31e5ac16c6e96d5ca76ad.png
   imgUrl: https://drk-1363981074.cos.ap-chongqing.myqcloud.com/fs/logo/30d7a0d1ec31e5ac16c6e96d5ca76ad.png
 ipad:
 ipad:
   ipadUrl: http://ipad.cdwjyyh.com
   ipadUrl: http://ipad.cdwjyyh.com
+  aiApi: 1212121212
 wx_miniapp_temp:
 wx_miniapp_temp:
   pay_order_temp_id:
   pay_order_temp_id:
   inquiry_temp_id:
   inquiry_temp_id:

+ 3 - 0
fs-service/src/main/resources/application-druid-xzt.yml

@@ -139,3 +139,6 @@ rocketmq:
         group: test-group
         group: test-group
         access-key: ak1243b25nj17d4b2dc1a03 # 替换为实际的 accessKey
         access-key: ak1243b25nj17d4b2dc1a03 # 替换为实际的 accessKey
         secret-key: sk08a7ea1f9f4b0237 # 替换为实际的 secretKey
         secret-key: sk08a7ea1f9f4b0237 # 替换为实际的 secretKey
+openIM:
+    secret: openIM123
+    userID: imAdmin

+ 91 - 0
fs-service/src/main/resources/mapper/CompanyMiniappMapper.xml

@@ -0,0 +1,91 @@
+<?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.company.mapper.CompanyMiniappMapper">
+    
+    <resultMap type="CompanyMiniapp" id="CompanyMiniappResult">
+        <result property="id"    column="id"    />
+        <result property="companyId"    column="company_id"    />
+        <result property="appId"    column="app_id"    />
+        <result property="type"    column="type"    />
+        <result property="sortNum"    column="sort_num"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="createBy"    column="create_by"    />
+        <result property="updateBy"    column="update_by"    />
+        <result property="updateTime"    column="update_time"    />
+        <result property="remark"    column="remark"    />
+    </resultMap>
+
+    <sql id="selectCompanyMiniappVo">
+        select id, company_id, app_id, type, sort_num, create_time, create_by, update_by, update_time, remark from company_miniapp
+    </sql>
+
+    <select id="selectCompanyMiniappList" parameterType="CompanyMiniapp" resultMap="CompanyMiniappResult">
+        <include refid="selectCompanyMiniappVo"/>
+        <where>  
+            <if test="companyId != null "> and company_id = #{companyId}</if>
+            <if test="appId != null  and appId != ''"> and app_id = #{appId}</if>
+            <if test="type != null "> and type = #{type}</if>
+            <if test="sortNum != null "> and sort_num = #{sortNum}</if>
+        </where>
+    </select>
+    
+    <select id="selectCompanyMiniappById" parameterType="Long" resultMap="CompanyMiniappResult">
+        <include refid="selectCompanyMiniappVo"/>
+        where id = #{id}
+    </select>
+        
+    <insert id="insertCompanyMiniapp" parameterType="CompanyMiniapp" useGeneratedKeys="true" keyProperty="id">
+        insert into company_miniapp
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="companyId != null">company_id,</if>
+            <if test="appId != null">app_id,</if>
+            <if test="type != null">type,</if>
+            <if test="sortNum != null">sort_num,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="createBy != null">create_by,</if>
+            <if test="updateBy != null">update_by,</if>
+            <if test="updateTime != null">update_time,</if>
+            <if test="remark != null">remark,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="companyId != null">#{companyId},</if>
+            <if test="appId != null">#{appId},</if>
+            <if test="type != null">#{type},</if>
+            <if test="sortNum != null">#{sortNum},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="remark != null">#{remark},</if>
+         </trim>
+    </insert>
+
+    <update id="updateCompanyMiniapp" parameterType="CompanyMiniapp">
+        update company_miniapp
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="companyId != null">company_id = #{companyId},</if>
+            <if test="appId != null">app_id = #{appId},</if>
+            <if test="type != null">type = #{type},</if>
+            <if test="sortNum != null">sort_num = #{sortNum},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="createBy != null">create_by = #{createBy},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="remark != null">remark = #{remark},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteCompanyMiniappById" parameterType="Long">
+        delete from company_miniapp where id = #{id}
+    </delete>
+
+    <delete id="deleteCompanyMiniappByIds" parameterType="String">
+        delete from company_miniapp where id in 
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 12 - 0
fs-service/src/main/resources/mapper/company/CompanyMapper.xml

@@ -35,6 +35,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="packageCateIds"    column="package_cate_ids"    />
         <result property="packageCateIds"    column="package_cate_ids"    />
         <result property="courseMaAppId"    column="course_ma_app_id"    />
         <result property="courseMaAppId"    column="course_ma_app_id"    />
         <result property="courseMiniAppId"    column="course_mini_app_id"    />
         <result property="courseMiniAppId"    column="course_mini_app_id"    />
+        <result property="repeat"    column="repeat"    />
+        <result property="sendIfType"    column="send_if_type"    />
+        <result property="ifNum"    column="if_num"    />
     </resultMap>
     </resultMap>
 
 
     <sql id="selectCompanyVo">
     <sql id="selectCompanyVo">
@@ -105,6 +108,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="packageCateIds != null">package_cate_ids,</if>
             <if test="packageCateIds != null">package_cate_ids,</if>
             <if test="courseMaAppId != null">course_ma_app_id,</if>
             <if test="courseMaAppId != null">course_ma_app_id,</if>
             <if test="courseMiniAppId != null">course_mini_app_id,</if>
             <if test="courseMiniAppId != null">course_mini_app_id,</if>
+            <if test="repeat != null">`repeat`,</if>
+            <if test="sendIfType != null">send_if_type,</if>
+            <if test="ifNum != null">if_num,</if>
         </trim>
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="companyName != null">#{companyName},</if>
             <if test="companyName != null">#{companyName},</if>
@@ -134,6 +140,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="packageCateIds != null">#{packageCateIds},</if>
             <if test="packageCateIds != null">#{packageCateIds},</if>
             <if test="courseMaAppId != null">#{courseMaAppId},</if>
             <if test="courseMaAppId != null">#{courseMaAppId},</if>
             <if test="courseMiniAppId != null">#{courseMiniAppId},</if>
             <if test="courseMiniAppId != null">#{courseMiniAppId},</if>
+            <if test="repeat != null">#{repeat},</if>
+            <if test="sendIfType != null">#{sendIfType},</if>
+            <if test="ifNum != null">#{ifNum},</if>
          </trim>
          </trim>
     </insert>
     </insert>
 
 
@@ -169,6 +178,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="courseMaAppId != null">course_ma_app_id = #{courseMaAppId},</if>
             <if test="courseMaAppId != null">course_ma_app_id = #{courseMaAppId},</if>
             <if test="courseMiniAppId != null">course_mini_app_id = #{courseMiniAppId},</if>
             <if test="courseMiniAppId != null">course_mini_app_id = #{courseMiniAppId},</if>
             <if test="fsUserIsDefaultBlack != null ">fs_user_is_default_black = #{fsUserIsDefaultBlack},</if>
             <if test="fsUserIsDefaultBlack != null ">fs_user_is_default_black = #{fsUserIsDefaultBlack},</if>
+            <if test="repeat != null">`repeat` = #{repeat},</if>
+            <if test="sendIfType != null">send_if_type = #{sendIfType},</if>
+            <if test="ifNum != null">if_num = #{ifNum},</if>
         </trim>
         </trim>
         where company_id = #{companyId}
         where company_id = #{companyId}
     </update>
     </update>

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

@@ -201,6 +201,30 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         </foreach>
         </foreach>
     </update>
     </update>
 
 
+    <update id="batchUpdateQwExternalContactByMoreStudy" parameterType="map">
+        UPDATE qw_external_contact
+        SET
+        level = CASE id
+        <foreach collection="list" item="item">
+            WHEN #{item.id} THEN #{item.level}
+        </foreach>
+        ELSE level
+        END
+        WHERE id IN
+        <foreach collection="list" item="item" open="(" separator="," close=")">
+            #{item.id}
+        </foreach>
+    </update>
+
+    <update id="batchUpdateQwExternalByIsDaysNotStudy" parameterType="map">
+        UPDATE qw_external_contact
+        SET level =  NULL
+        WHERE id IN
+        <foreach collection="list" item="item" open="(" separator="," close=")">
+            #{item.id}
+        </foreach>
+    </update>
+
 
 
     <insert id="insertQwExternalContact" parameterType="QwExternalContact" useGeneratedKeys="true" keyProperty="id" >
     <insert id="insertQwExternalContact" parameterType="QwExternalContact" useGeneratedKeys="true" keyProperty="id" >
         insert into qw_external_contact
         insert into qw_external_contact

+ 12 - 1
fs-service/src/main/resources/mapper/sop/SopUserLogsInfoMapper.xml

@@ -20,6 +20,7 @@
         <result property="updateTime" column="update_time" jdbcType="VARCHAR" />
         <result property="updateTime" column="update_time" jdbcType="VARCHAR" />
         <result property="tagIds" column="tag_ids" jdbcType="VARCHAR" />
         <result property="tagIds" column="tag_ids" jdbcType="VARCHAR" />
         <result property="isDaysNotStudy" column="is_days_not_study"/>
         <result property="isDaysNotStudy" column="is_days_not_study"/>
+        <result property="grade" column="grade"/>
     </resultMap>
     </resultMap>
 
 
     <sql id="selectSopUserLogsInfoVo">
     <sql id="selectSopUserLogsInfoVo">
@@ -185,7 +186,7 @@
 
 
     <!-- 根据ID查询单条记录 -->
     <!-- 根据ID查询单条记录 -->
     <select id="selectById" parameterType="String" resultMap="SopUserLogsInfoResult">
     <select id="selectById" parameterType="String" resultMap="SopUserLogsInfoResult">
-        SELECT id, sop_id, user_logs_id, external_contact_id,qw_user_id,corp_id,external_id, fs_user_id, external_user_name,create_time,crt_Time,update_time
+        SELECT id, sop_id, user_logs_id, external_contact_id,qw_user_id,corp_id,external_id, fs_user_id, external_user_name,create_time,crt_Time,update_time,grade
         FROM sop_user_logs_info
         FROM sop_user_logs_info
         WHERE id = #{id}
         WHERE id = #{id}
     </select>
     </select>
@@ -235,6 +236,16 @@
         from sop_user_logs_info where sop_id = #{sopId} and user_logs_id=#{userLogsId}
         from sop_user_logs_info where sop_id = #{sopId} and user_logs_id=#{userLogsId}
     </select>
     </select>
 
 
+    <select id="selectRestoreByIsDaysNotStudy" parameterType="String" resultMap="SopUserLogsInfoResult">
+        select
+            id,external_id
+        from sop_user_logs_info
+        where sop_id = #{sopId}
+          and user_logs_id=#{userLogsId}
+          and is_days_not_study=1
+    </select>
+
+
     <!-- 查询所有记录 -->
     <!-- 查询所有记录 -->
     <select id="selectAll" resultMap="SopUserLogsInfoResult">
     <select id="selectAll" resultMap="SopUserLogsInfoResult">
         SELECT id, sop_id, user_logs_id, external_contact_id,qw_user_id,corp_id,external_id,
         SELECT id, sop_id, user_logs_id, external_contact_id,qw_user_id,corp_id,external_id,

+ 41 - 0
fs-service/src/main/resources/mapper/sop/SopUserLogsMapper.xml

@@ -253,6 +253,47 @@
             LIMIT #{offset}, #{pageSize}
             LIMIT #{offset}, #{pageSize}
     </select>
     </select>
 
 
+
+    <select id="meetsTheRatingByUserInfoWithPaginationStudyDays" resultType="Integer"  resultMap="SopUserLogsResult">
+        SELECT
+            ul.id,
+            ul.sop_id,
+            ul.sop_temp_id,
+            ul.qw_user_id,
+            ul.corp_id,
+            ul.start_time,
+            ul.`status`,
+            ul.user_id,
+            DATEDIFF( CURRENT_DATE, ul.start_time ) AS count_days
+        FROM
+            sop_user_logs ul  LEFT JOIN qw_sop qs on ul.sop_id=qs.id
+        WHERE
+            ul.`status` = '1'
+          and qs.type=2
+          and qs.send_type=2
+          and qs.`status` in (2,3)
+          AND ( DATEDIFF( CURRENT_DATE, ul.start_time ) ) >= #{notStudyDays}
+        ORDER BY id ASC
+            LIMIT #{offset}, #{pageSize}
+    </select>
+
+    <select id="meetsTherestoreByIsDaysNotStudy" resultType="Integer"  resultMap="SopUserLogsResult">
+        SELECT
+            ul.id,
+            ul.sop_id
+        FROM
+            sop_user_logs ul  LEFT JOIN qw_sop qs on ul.sop_id=qs.id
+        WHERE
+            ul.`status` = '1'
+          and qs.type=2
+          and qs.send_type=2
+          and qs.`status` in (2,3)
+          AND ( DATEDIFF( CURRENT_DATE, ul.start_time ) ) &lt; #{notStudyDays}
+        ORDER BY id ASC
+            LIMIT #{offset}, #{pageSize}
+    </select>
+
+
     <select id="meetsTheRatingByUserInfoBySopId" resultType="String"  resultMap="SopUserLogsResult">
     <select id="meetsTheRatingByUserInfoBySopId" resultType="String"  resultMap="SopUserLogsResult">
         SELECT
         SELECT
             ul.id,
             ul.id,