Explorar o código

Merge remote-tracking branch 'origin/master'

吴树波 hai 1 día
pai
achega
1d5a49c56d
Modificáronse 100 ficheiros con 3677 adicións e 472 borrados
  1. 130 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyDomainBindController.java
  2. 99 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyDomainBindUserController.java
  3. 189 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyDomainController.java
  4. 25 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyUserController.java
  5. 10 6
      fs-admin/src/main/java/com/fs/his/controller/FsUserController.java
  6. 14 0
      fs-admin/src/main/java/com/fs/his/task/FsCourseTask.java
  7. 29 0
      fs-admin/src/main/java/com/fs/his/task/PeriodTask.java
  8. 93 0
      fs-common-api/src/main/resources/logback.xml
  9. 3 2
      fs-company-app/src/main/java/com/fs/app/controller/CompanyUserController.java
  10. 0 1
      fs-company-app/src/main/java/com/fs/app/controller/FsUserController.java
  11. 16 1
      fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java
  12. 1 1
      fs-company-app/src/main/java/com/fs/app/controller/UserController.java
  13. 135 0
      fs-company/src/main/java/com/fs/company/controller/company/CompanyDomainBindController.java
  14. 108 0
      fs-company/src/main/java/com/fs/company/controller/company/CompanyDomainBindUserController.java
  15. 1 0
      fs-company/src/main/java/com/fs/company/controller/company/CompanyUserController.java
  16. 6 2
      fs-company/src/main/java/com/fs/company/controller/course/FsCourseAnswerLogsController.java
  17. 43 4
      fs-company/src/main/java/com/fs/user/FsUserAdminController.java
  18. 1 1
      fs-company/src/main/resources/application.yml
  19. 5 2
      fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java
  20. 2 2
      fs-qw-task/src/main/java/com/fs/app/task/UserCourseWatchCountTask.java
  21. 34 18
      fs-qw-task/src/main/java/com/fs/app/task/qwTask.java
  22. 1 1
      fs-qw-task/src/main/resources/application.yml
  23. 5 20
      fs-qwhook-sop/src/main/java/com/fs/app/controller/ApisFsUserCourseVideoController.java
  24. 5 45
      fs-qwhook-sop/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java
  25. 5 21
      fs-qwhook/src/main/java/com/fs/app/controller/ApisFsUserCourseVideoController.java
  26. 66 41
      fs-qwhook/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java
  27. 4 2
      fs-service/src/main/java/com/fs/company/cache/ICompanyTagCacheService.java
  28. 33 5
      fs-service/src/main/java/com/fs/company/cache/impl/CompanyTagCacheServiceImpl.java
  29. 27 0
      fs-service/src/main/java/com/fs/company/domain/CompanyDomain.java
  30. 35 0
      fs-service/src/main/java/com/fs/company/domain/CompanyDomainBind.java
  31. 31 0
      fs-service/src/main/java/com/fs/company/domain/CompanyDomainBindUser.java
  32. 83 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyDomainBindMapper.java
  33. 75 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyDomainBindUserMapper.java
  34. 79 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyDomainMapper.java
  35. 5 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyMapper.java
  36. 3 3
      fs-service/src/main/java/com/fs/company/mapper/CompanyTagMapper.java
  37. 14 2
      fs-service/src/main/java/com/fs/company/mapper/CompanyUserMapper.java
  38. 47 0
      fs-service/src/main/java/com/fs/company/param/CompanyDomainBindParam.java
  39. 36 0
      fs-service/src/main/java/com/fs/company/param/CompanyDomainBindUserParam.java
  40. 47 0
      fs-service/src/main/java/com/fs/company/param/CompanyDomainParam.java
  41. 74 0
      fs-service/src/main/java/com/fs/company/service/ICompanyDomainBindService.java
  42. 63 0
      fs-service/src/main/java/com/fs/company/service/ICompanyDomainBindUserService.java
  43. 83 0
      fs-service/src/main/java/com/fs/company/service/ICompanyDomainService.java
  44. 2 2
      fs-service/src/main/java/com/fs/company/service/ICompanyTagService.java
  45. 4 1
      fs-service/src/main/java/com/fs/company/service/ICompanyUserService.java
  46. 166 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyDomainBindServiceImpl.java
  47. 95 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyDomainBindUserServiceImpl.java
  48. 274 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyDomainServiceImpl.java
  49. 1 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java
  50. 3 3
      fs-service/src/main/java/com/fs/company/service/impl/CompanyTagServiceImpl.java
  51. 1 1
      fs-service/src/main/java/com/fs/company/service/impl/CompanyTagUserServiceImpl.java
  52. 16 3
      fs-service/src/main/java/com/fs/company/service/impl/CompanyUserServiceImpl.java
  53. 58 0
      fs-service/src/main/java/com/fs/company/vo/CompanyDomainBindUserVo.java
  54. 59 0
      fs-service/src/main/java/com/fs/company/vo/CompanyDomainBindVo.java
  55. 26 0
      fs-service/src/main/java/com/fs/company/vo/CompanyDomainExportTemplateVo.java
  56. 52 0
      fs-service/src/main/java/com/fs/company/vo/CompanyDomainVo.java
  57. 8 9
      fs-service/src/main/java/com/fs/core/config/WxMaConfiguration.java
  58. 6 0
      fs-service/src/main/java/com/fs/course/domain/FsCourseLink.java
  59. 7 0
      fs-service/src/main/java/com/fs/course/domain/FsCourseRealLink.java
  60. 3 2
      fs-service/src/main/java/com/fs/course/mapper/FsCourseRedPacketLogMapper.java
  61. 1 0
      fs-service/src/main/java/com/fs/course/param/FsCourseLinkMiniParam.java
  62. 2 0
      fs-service/src/main/java/com/fs/course/param/FsCourseWatchLogListParam.java
  63. 2 2
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseLinkServiceImpl.java
  64. 25 8
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseServiceImpl.java
  65. 49 16
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  66. 1 0
      fs-service/src/main/java/com/fs/his/mapper/FsDoctorMapper.java
  67. 2 0
      fs-service/src/main/java/com/fs/his/mapper/FsPackageMapper.java
  68. 4 0
      fs-service/src/main/java/com/fs/his/mapper/FsUserDoctorMapper.java
  69. 3 1
      fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java
  70. 7 0
      fs-service/src/main/java/com/fs/his/service/IFsPackageService.java
  71. 3 0
      fs-service/src/main/java/com/fs/his/service/IFsUserDoctorService.java
  72. 6 0
      fs-service/src/main/java/com/fs/his/service/impl/FsPackageServiceImpl.java
  73. 6 1
      fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java
  74. 6 0
      fs-service/src/main/java/com/fs/his/service/impl/FsUserDoctorServiceImpl.java
  75. 69 24
      fs-service/src/main/java/com/fs/his/service/impl/FsUserServiceImpl.java
  76. 10 0
      fs-service/src/main/java/com/fs/his/vo/FsUserVO.java
  77. 3 0
      fs-service/src/main/java/com/fs/qw/mapper/CustomerTransferApprovalMapper.java
  78. 5 0
      fs-service/src/main/java/com/fs/qw/service/ICustomerTransferApprovalService.java
  79. 13 0
      fs-service/src/main/java/com/fs/qw/service/impl/CustomerTransferApprovalServiceImpl.java
  80. 43 39
      fs-service/src/main/java/com/fs/qw/service/impl/QwExternalContactServiceImpl.java
  81. 4 1
      fs-service/src/main/java/com/fs/sop/mapper/QwSopLogsMapper.java
  82. 8 0
      fs-service/src/main/java/com/fs/sop/params/QwSopLogsParam.java
  83. 1 1
      fs-service/src/main/java/com/fs/sop/service/IQwSopLogsService.java
  84. 172 133
      fs-service/src/main/java/com/fs/sop/service/impl/QwSopLogsServiceImpl.java
  85. 12 0
      fs-service/src/main/java/com/fs/store/domain/FsUserCourseCount.java
  86. 6 0
      fs-service/src/main/java/com/fs/store/mapper/FsUserCourseCountMapper.java
  87. 4 0
      fs-service/src/main/java/com/fs/store/param/h5/FsUserPageListParam.java
  88. 17 0
      fs-service/src/main/java/com/fs/store/service/impl/FsUserCourseCountServiceImpl.java
  89. 2 0
      fs-service/src/main/java/com/fs/store/vo/h5/FsUserPageListVO.java
  90. 3 1
      fs-service/src/main/java/com/fs/store/vo/h5/UserDetailsVO.java
  91. 3 2
      fs-service/src/main/resources/application-common.yml
  92. 94 0
      fs-service/src/main/resources/application-config-druid-bnkc.yml
  93. 2 9
      fs-service/src/main/resources/application-config-druid-fcky.yml
  94. 3 3
      fs-service/src/main/resources/application-config-druid-jzzx.yml
  95. 79 0
      fs-service/src/main/resources/application-config-druid-lmjy.yml
  96. 10 28
      fs-service/src/main/resources/application-config-druid-zsjk.yml
  97. 149 0
      fs-service/src/main/resources/application-druid-bnkc.yml
  98. 150 0
      fs-service/src/main/resources/application-druid-fcky-test.yml
  99. 2 2
      fs-service/src/main/resources/application-druid-jzzx.yml
  100. 150 0
      fs-service/src/main/resources/application-druid-lmjy.yml

+ 130 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyDomainBindController.java

@@ -0,0 +1,130 @@
+package com.fs.company.controller;
+
+import java.util.List;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.extension.api.R;
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.utils.ServletUtils;
+import com.fs.company.param.CompanyDomainBindParam;
+import com.fs.company.vo.CompanyDomainBindVo;
+import com.fs.framework.web.service.TokenService;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.company.domain.CompanyDomainBind;
+import com.fs.company.service.ICompanyDomainBindService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 域名绑定销售公司Controller
+ * 
+ * @author fs
+ * @date 2025-06-17
+ */
+@RestController
+@RequestMapping("/company/companyDomainBind")
+public class CompanyDomainBindController extends BaseController
+{
+    @Autowired
+    private TokenService tokenService;
+    @Autowired
+    private ICompanyDomainBindService companyDomainBindService;
+
+    /**
+     * 查询域名绑定销售公司列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDomainBind:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyDomainBindParam companyDomainBind)
+    {
+        startPage();
+        List<CompanyDomainBindVo> list = companyDomainBindService.selectCompanyDomainBindList(companyDomainBind);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出域名绑定销售公司列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDomainBind:export')")
+    @Log(title = "域名绑定销售公司", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyDomainBindParam companyDomainBind)
+    {
+        List<CompanyDomainBindVo> list = companyDomainBindService.selectCompanyDomainBindList(companyDomainBind);
+        ExcelUtil<CompanyDomainBindVo> util = new ExcelUtil<CompanyDomainBindVo>(CompanyDomainBindVo.class);
+        return util.exportExcel(list, "域名绑定销售公司数据");
+    }
+
+    /**
+     * 获取域名绑定销售公司详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDomainBind:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(companyDomainBindService.selectCompanyDomainBindById(id));
+    }
+
+    /**
+     * 新增域名绑定销售公司
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDomainBind:add')")
+    @Log(title = "域名绑定销售公司", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanyDomainBind companyDomainBind)
+    {
+        return toAjax(companyDomainBindService.insertCompanyDomainBind(companyDomainBind));
+    }
+
+    /**
+     * 修改域名绑定销售公司
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDomainBind:edit')")
+    @Log(title = "域名绑定销售公司", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanyDomainBind companyDomainBind)
+    {
+        return toAjax(companyDomainBindService.updateCompanyDomainBind(companyDomainBind));
+    }
+
+    /**
+     * 删除域名绑定销售公司
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDomainBind:remove')")
+    @Log(title = "域名绑定销售公司", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(companyDomainBindService.deleteCompanyDomainBindByIds(ids));
+    }
+
+    /**
+     * 域名批量绑定
+     **/
+    @PreAuthorize("@ss.hasPermi('company:companyDomain:domainBatchBinding')")
+    @PostMapping("/domainBatchBinding")
+    public R domainBatchBinding(@RequestBody CompanyDomainBindParam param) {
+        if (ObjectUtil.isEmpty(param.getCompanyIds()) || param.getCompanyIds().isEmpty()) {
+            return R.failed("绑定失败,至少有一条域名分配信息!");
+        }
+        if (ObjectUtil.isEmpty(param.getCompanyUserIds()) || param.getCompanyUserIds().isEmpty()) {
+            return R.failed("绑定失败,至少有一条分配人员信息!");
+        }
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setUserId(loginUser.getUser().getUserId().toString());
+        return companyDomainBindService.domainBatchBinding(param);
+    }
+}

+ 99 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyDomainBindUserController.java

@@ -0,0 +1,99 @@
+package com.fs.company.controller;
+
+import java.util.List;
+
+import com.fs.company.param.CompanyDomainBindUserParam;
+import com.fs.company.vo.CompanyDomainBindUserVo;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.company.domain.CompanyDomainBindUser;
+import com.fs.company.service.ICompanyDomainBindUserService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 企业域名分配中间表Controller
+ *
+ * @author fs
+ * @date 2025-06-19
+ */
+@RestController
+@RequestMapping("/company/companyBindUser")
+public class CompanyDomainBindUserController extends BaseController {
+    @Autowired
+    private ICompanyDomainBindUserService companyDomainBindUserService;
+
+    /**
+     * 查询企业域名分配中间表列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyBindUser:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyDomainBindUserParam companyDomainBindUser) {
+        startPage();
+        List<CompanyDomainBindUserVo> list = companyDomainBindUserService.selectCompanyDomainBindUserList(companyDomainBindUser);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出企业域名分配中间表列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyBindUser:export')")
+    @Log(title = "企业域名分配中间表", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyDomainBindUserParam companyDomainBindUser) {
+        List<CompanyDomainBindUserVo> list = companyDomainBindUserService.selectCompanyDomainBindUserList(companyDomainBindUser);
+        ExcelUtil<CompanyDomainBindUserVo> util = new ExcelUtil<CompanyDomainBindUserVo>(CompanyDomainBindUserVo.class);
+        return util.exportExcel(list, "企业域名分配中间表数据");
+    }
+
+    /**
+     * 获取企业域名分配中间表详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyBindUser:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id) {
+        return AjaxResult.success(companyDomainBindUserService.selectCompanyDomainBindUserById(id));
+    }
+
+    /**
+     * 新增企业域名分配中间表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyBindUser:add')")
+    @Log(title = "企业域名分配中间表", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanyDomainBindUser companyDomainBindUser) {
+        return toAjax(companyDomainBindUserService.insertCompanyDomainBindUser(companyDomainBindUser));
+    }
+
+    /**
+     * 修改企业域名分配中间表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyBindUser:edit')")
+    @Log(title = "企业域名分配中间表", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanyDomainBindUser companyDomainBindUser) {
+        return toAjax(companyDomainBindUserService.updateCompanyDomainBindUser(companyDomainBindUser));
+    }
+
+    /**
+     * 删除企业域名分配中间表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyBindUser:remove')")
+    @Log(title = "企业域名分配中间表", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids) {
+        return toAjax(companyDomainBindUserService.deleteCompanyDomainBindUserByIds(ids));
+    }
+}

+ 189 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyDomainController.java

@@ -0,0 +1,189 @@
+package com.fs.company.controller;
+
+import java.util.List;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.extension.api.R;
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.exception.ServiceException;
+import com.fs.common.utils.ServletUtils;
+import com.fs.company.param.CompanyDomainParam;
+import com.fs.company.vo.CompanyDomainExportTemplateVo;
+import com.fs.company.vo.CompanyDomainVo;
+import com.fs.framework.web.service.TokenService;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.company.domain.CompanyDomain;
+import com.fs.company.service.ICompanyDomainService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * 域名管路Controller
+ *
+ * @author fs
+ * @date 2025-06-16
+ */
+@RestController
+@RequestMapping("/company/companyDomain")
+public class CompanyDomainController extends BaseController {
+    @Autowired
+    private TokenService tokenService;
+    @Autowired
+    private ICompanyDomainService companyDomainService;
+
+    // 允许的文件扩展名
+    private static final String[] ALLOWED_EXCEL_EXTENSIONS = {".xlsx", ".xls"};
+    // 最大文件大小(5MB)
+    private static final long MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
+
+    /**
+     * 查询域名管路列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDomain:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyDomainParam companyDomain) {
+        startPage();
+        List<CompanyDomainVo> list = companyDomainService.selectCompanyDomainList(companyDomain);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出域名管路列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDomain:export')")
+    @Log(title = "域名管理", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyDomainParam companyDomain) {
+        List<CompanyDomainVo> list = companyDomainService.selectCompanyDomainList(companyDomain);
+        ExcelUtil<CompanyDomainVo> util = new ExcelUtil<CompanyDomainVo>(CompanyDomainVo.class);
+        return util.exportExcel(list, "域名管路数据");
+    }
+
+    /**
+     * 获取域名管路详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDomain:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id) {
+        return AjaxResult.success(companyDomainService.selectCompanyDomainById(id));
+    }
+
+    /**
+     * 新增域名管路
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDomain:add')")
+    @Log(title = "域名管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanyDomain companyDomain) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        companyDomain.setCreateBy(loginUser.getUser().getUserId().toString());
+        return toAjax(companyDomainService.insertCompanyDomain(companyDomain));
+    }
+
+    /**
+     * 修改域名管路
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDomain:edit')")
+    @Log(title = "域名管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanyDomain companyDomain) {
+        if (ObjectUtil.isEmpty(companyDomain.getId())) {
+            throw new ServiceException("修改关键信息不能为空!");
+        }
+        return toAjax(companyDomainService.updateCompanyDomain(companyDomain));
+    }
+
+    /**
+     * 删除域名管路
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDomain:remove')")
+    @Log(title = "域名管理", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids) {
+        if (ObjectUtil.isEmpty(ids)) {
+            throw new ServiceException("删除关键信息不能为空!");
+        }
+        return toAjax(companyDomainService.deleteCompanyDomainByIds(ids));
+    }
+
+    /**
+     * 域名批量绑定
+     **/
+    @PreAuthorize("@ss.hasPermi('company:companyDomain:domainBatchBinding')")
+    @PostMapping("/domainBatchBinding")
+    public R domainBatchBinding(@RequestBody CompanyDomainParam param) {
+        if (ObjectUtil.isEmpty(param.getDomainIds()) || param.getDomainIds().isEmpty()) {
+            return R.failed("绑定失败,至少有一条绑定域名信息!");
+        }
+        if (ObjectUtil.isEmpty(param.getCompanyIds()) || param.getCompanyIds().isEmpty()) {
+            return R.failed("绑定失败,至少有一条绑定公司信息!");
+        }
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setUserId(loginUser.getUser().getUserId().toString());
+        return companyDomainService.domainBatchBinding(param);
+    }
+
+    /**
+     * 导出模板
+     **/
+    @GetMapping("/exportTemplate")
+    public AjaxResult exportTemplate() {
+        ExcelUtil<CompanyDomainExportTemplateVo> util = new ExcelUtil<>(CompanyDomainExportTemplateVo.class);
+        return util.importTemplateExcel("域名导入模板");
+    }
+
+    @Log(title = "域名导入", businessType = BusinessType.IMPORT)
+    @PostMapping("/importDomainData")
+    public R importDomainData(MultipartFile file) {
+        // 1. 检查文件是否为空
+        if (file.isEmpty()) {
+            return R.failed("上传的文件不能为空");
+        }
+
+        // 2. 检查文件大小
+        if (file.getSize() > MAX_FILE_SIZE) {
+            return R.failed("文件大小不能超过5MB");
+        }
+
+        // 3. 检查文件扩展名
+        String fileName = file.getOriginalFilename();
+        if (fileName == null || !isValidExcelFile(fileName)) {
+            return R.failed("请上传Excel文件(.xlsx或.xls格式)");
+        }
+        CompanyDomainParam param = new CompanyDomainParam();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setUserId(loginUser.getUser().getUserId().toString());
+        ExcelUtil<CompanyDomainExportTemplateVo> util = new ExcelUtil<>(CompanyDomainExportTemplateVo.class);
+        try {
+            List<CompanyDomainExportTemplateVo> companyDomainList = util.importExcel(file.getInputStream());
+            return companyDomainService.importDomainData(param, companyDomainList);
+        } catch (Exception e) {
+            e.getStackTrace();
+            return R.failed("导入失败!");
+        }
+    }
+
+    // 检查文件是否为有效的Excel文件
+    private boolean isValidExcelFile(String fileName) {
+        for (String ext : ALLOWED_EXCEL_EXTENSIONS) {
+            if (fileName.toLowerCase().endsWith(ext)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}

+ 25 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyUserController.java

@@ -136,4 +136,29 @@ public class CompanyUserController extends BaseController
         List<CompanyUser> list = companyUserService.selectCompanyUserList(map);
         return  R.ok().put("data",list);
     }
+
+    /**
+     * 更换会员归属销售
+     * @return
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyUser:change')")
+    @Log(title = "更换会员归属", businessType = BusinessType.OTHER)
+    @PostMapping("/changeCompanyUser")
+    public AjaxResult changeCompanyUser(@RequestBody List<Long> userIds, @RequestParam Long companyUserId, @RequestParam Long companyId)
+    {
+        return toAjax(companyUserService.changeCompanyUser(userIds, companyUserId, companyId));
+    }
+    /**
+     * 根据登录的用户公司获取所有的销售
+     * @return
+     */
+    @GetMapping("/getCompanyUserList")
+    public R getCompanyUserList(@RequestParam Long companyId)
+    {
+        CompanyUser cu = new CompanyUser();
+        cu.setCompanyId(companyId);
+        List<CompanyUser> list = companyUserService.selectCompanyUserList(cu);
+        return  R.ok().put("data",list);
+    }
+
 }

+ 10 - 6
fs-admin/src/main/java/com/fs/his/controller/FsUserController.java

@@ -4,6 +4,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.ResponseResult;
 import com.fs.common.utils.ParseUtils;
@@ -198,13 +199,16 @@ public class FsUserController extends BaseController
 //        startPage();
         PageHelper.startPage(param.getPageNum(), param.getPageSize());
         PageInfo<FsUserPageListVO> fsUserPageListVOPageInfo = fsUserService.selectFsUserPageList(param);
-        for (FsUserPageListVO fsUserPageListVO : fsUserPageListVOPageInfo.getList()) {
-            fsUserPageListVO.setPhone(ParseUtils.parsePhone(fsUserPageListVO.getPhone()));
+        if(ObjectUtils.isNotNull(fsUserPageListVOPageInfo)){
+            for (FsUserPageListVO fsUserPageListVO : fsUserPageListVOPageInfo.getList()) {
+                fsUserPageListVO.setPhone(ParseUtils.parsePhone(fsUserPageListVO.getPhone()));
+            }
+            Map<String, Object> map = new HashMap<String, Object>();
+            map.put("rows", fsUserPageListVOPageInfo.getList());
+            map.put("total", fsUserPageListVOPageInfo.getList().size());
+            return R.ok(map);
         }
-        Map<String, Object> map = new HashMap<String, Object>();
-        map.put("rows", fsUserPageListVOPageInfo.getList());
-        map.put("total", fsUserPageListVOPageInfo.getList().size());
-        return R.ok(map);
+        return R.ok();
     }
 
     @PreAuthorize("@ss.hasPermi('his:user:enabledUsers')")

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

@@ -1,7 +1,9 @@
 package com.fs.his.task;
 
 import com.fs.course.service.IFsCourseWatchLogService;
+import com.fs.qw.service.ICustomerTransferApprovalService;
 import com.fs.qw.service.IHyWorkTaskService;
+import com.fs.statis.service.FsStatisSalerWatchService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -16,6 +18,11 @@ public class FsCourseTask {
     private IFsCourseWatchLogService fsCourseWatchLogService;
     @Autowired
     private IHyWorkTaskService hyWorkTaskService;
+
+    @Autowired
+    private FsStatisSalerWatchService fsStatisSalerWatchService;
+    @Autowired
+    private ICustomerTransferApprovalService customerTransferApprovalService;
     /**
      * 添加会员观看日志
      * @throws Exception
@@ -44,4 +51,11 @@ public class FsCourseTask {
         hyWorkTaskService.hyWorkTask();
     }
 
+    /**
+     * 客户转移审批自动通过
+     */
+    public void fsUserTransferAutoPass(){
+        customerTransferApprovalService.autoApprovePass();
+    }
+
 }

+ 29 - 0
fs-admin/src/main/java/com/fs/his/task/PeriodTask.java

@@ -0,0 +1,29 @@
+package com.fs.his.task;
+
+import com.fs.course.service.IFsUserCoursePeriodDaysService;
+import com.fs.course.service.IFsUserCoursePeriodService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component("periodTask")
+public class PeriodTask {
+
+    @Autowired
+    private IFsUserCoursePeriodService userCoursePeriodService;
+    @Autowired
+    private IFsUserCoursePeriodDaysService userCoursePeriodDaysService;
+
+    /**
+     * 更新营期状态
+     */
+    public void refreshPeriod() {
+        userCoursePeriodService.changePeriodStatus();
+    }
+
+    /**
+     * 更新营期课程状态
+     */
+    public void refreshPeriodDays() {
+        userCoursePeriodDaysService.changePeriodCourseStatus();
+    }
+}

+ 93 - 0
fs-common-api/src/main/resources/logback.xml

@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <!-- 日志存放路径 -->
+	<property name="log.path" value="/home/fs-common-api/logs" />
+    <!-- 日志输出格式 -->
+	<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
+
+	<!-- 控制台输出 -->
+	<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+		<encoder>
+			<pattern>${log.pattern}</pattern>
+		</encoder>
+	</appender>
+
+	<!-- 系统日志输出 -->
+	<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
+	    <file>${log.path}/sys-info.log</file>
+        <!-- 循环政策:基于时间创建日志文件 -->
+		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志文件名格式 -->
+			<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
+			<!-- 日志最大的历史 30 -->
+			<maxHistory>30</maxHistory>
+		</rollingPolicy>
+		<encoder>
+			<pattern>${log.pattern}</pattern>
+		</encoder>
+		<filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <!-- 过滤的级别 -->
+            <level>INFO</level>
+            <!-- 匹配时的操作:接收(记录) -->
+            <onMatch>ACCEPT</onMatch>
+            <!-- 不匹配时的操作:拒绝(不记录) -->
+            <onMismatch>DENY</onMismatch>
+        </filter>
+	</appender>
+
+	<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
+	    <file>${log.path}/sys-error.log</file>
+        <!-- 循环政策:基于时间创建日志文件 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志文件名格式 -->
+            <fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
+			<!-- 日志最大的历史 30 -->
+			<maxHistory>30</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <!-- 过滤的级别 -->
+            <level>ERROR</level>
+			<!-- 匹配时的操作:接收(记录) -->
+            <onMatch>ACCEPT</onMatch>
+			<!-- 不匹配时的操作:拒绝(不记录) -->
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+	<!-- 用户访问日志输出  -->
+    <appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
+		<file>${log.path}/sys-user.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 按天回滚 daily -->
+            <fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
+            <!-- 日志最大的历史 30 -->
+            <maxHistory>30</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+    </appender>
+
+	<!-- 系统模块日志级别控制  -->
+	<logger name="com.fs" level="info" />
+	<!-- Spring日志级别控制  -->
+	<logger name="org.springframework" level="warn" />
+
+	<root level="info">
+		<appender-ref ref="console" />
+	</root>
+
+	<!--系统操作日志-->
+    <root level="info">
+        <appender-ref ref="file_info" />
+        <appender-ref ref="file_error" />
+    </root>
+
+	<!--系统用户操作日志-->
+    <logger name="sys-user" level="info">
+        <appender-ref ref="sys-user"/>
+    </logger>
+</configuration>

+ 3 - 2
fs-company-app/src/main/java/com/fs/app/controller/CompanyUserController.java

@@ -73,12 +73,12 @@ public class CompanyUserController extends AppBaseController {
         // 判断是否管理员 或者包含 1:全部数据权限
         if (companyUser.isAdmin() || companyRoles.stream().anyMatch(r -> "1".equals(r.getDataScope()))) {
             PageHelper.startPage(pageNum, pageSize);
-            companyUsers = companyUserService.getCompanyUserListByDeptId(null);
+            companyUsers = companyUserService.getCompanyUserListByCompanyIdAndDeptId(companyUser.getCompanyId(), null);
         }
         // 判断是否包含 3:本部门数据权限 4:本部门及以下数据权限
         else if (companyRoles.stream().anyMatch(r -> "3".equals(r.getDataScope()) || "4".equals(r.getDataScope()))) {
             PageHelper.startPage(pageNum, pageSize);
-            companyUsers = companyUserService.getCompanyUserListByDeptId(companyUser.getDeptId());
+            companyUsers = companyUserService.getCompanyUserListByCompanyIdAndDeptId(companyUser.getCompanyId(), companyUser.getDeptId());
         }
         // 默认空 -- 判断是否包含 5:仅可查看本人
         else {
@@ -190,6 +190,7 @@ public class CompanyUserController extends AppBaseController {
         BeanUtils.copyProperties(param, companyUser);
 
         companyUser.setUserName(param.getPhoneNumber());
+        companyUser.setUserType("01");
         companyUser.setPhonenumber(param.getPhoneNumber());
         companyUser.setPassword(SecurityUtils.encryptPassword(companyUser.getPassword()));
         companyUser.setCreateTime(new Date());

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

@@ -77,7 +77,6 @@ public class FsUserController extends AppBaseController {
         param.setUserId(Long.parseLong(getUserId()));
         PageHelper.startPage(param.getPageNum(), param.getPageSize());
         PageInfo<FsUserPageListVO> fsUserPageListVOPageInfo = fsUserService.selectFsUserPageList(param);
-//        PageInfo<FsUserPageListVO> pageInfo = new PageInfo<>(list);
         return ResponseResult.ok(fsUserPageListVOPageInfo);
     }
 

+ 16 - 1
fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java

@@ -5,6 +5,8 @@ import com.fs.app.config.ImageStorageConfig;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.ResponseResult;
 import com.fs.common.utils.StringUtils;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.service.ICompanyUserService;
 import com.fs.course.domain.FsUserCoursePeriod;
 import com.fs.course.param.FsCourseLinkCreateParam;
 import com.fs.course.param.FsWatchCourseTimeParam;
@@ -58,6 +60,8 @@ public class FsUserCourseVideoController extends AppBaseController {
 
     @Autowired
     private IFsUserCoursePeriodService fsUserCoursePeriodService;
+    @Autowired
+    private ICompanyUserService companyUserService;
 
     @Login
     @GetMapping("/pageList")
@@ -108,12 +112,23 @@ public class FsUserCourseVideoController extends AppBaseController {
                                                       @RequestParam(required = false) String keyword,
                                                       @RequestParam(required = false, defaultValue = "1") Integer pageNum,
                                                       @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
-        log.debug("参与记录 keyword: {}, pageNum: {}, pageSize: {}", keyword, pageNum, pageSize);
+        log.debug("参与记录 videoId:{}, type:{}, keyword: {}, pageNum: {}, pageSize: {}", videoId, type, keyword, pageNum, pageSize);
         Map<String, Object> params = new HashMap<>();
         params.put("videoId", videoId);
         params.put("type", type);
         params.put("keyword", keyword);
 
+        // type 0 答题领奖记录----答题正确并且领取红包的
+        // type 1 完播----这堂课看完的人
+        // type 2 未完播---看课中断
+        // 管理员看整个公司 否则看自己的
+        CompanyUser companyUser = companyUserService.selectCompanyUserByUserId(Long.parseLong(getUserId()));
+        if (companyUser.isAdmin()) {
+            params.put("companyId", companyUser.getCompanyId());
+        } else {
+            params.put("companyUserId", companyUser.getUserId());
+        }
+
         PageHelper.startPage(pageNum, pageSize);
         List<FsUserCourseParticipationRecordVO> record = fsUserCourseService.getParticipationRecordByMap(params);
         return ResponseResult.ok(new PageInfo<>(record));

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

@@ -257,7 +257,7 @@ public class UserController extends AppBaseController {
             companyUser.setCompanyName(company.getCompanyName());
             // 岗位
             companyUser.setPosts(postService.selectCompanyPostListByUserId(companyUser.getUserId()));
-            return R.ok().put("user", companyUser);
+            return R.ok().put("user", companyUser).put("balance", company.getMoney());
         } catch (Exception e) {
 
             return R.error("操作异常");

+ 135 - 0
fs-company/src/main/java/com/fs/company/controller/company/CompanyDomainBindController.java

@@ -0,0 +1,135 @@
+package com.fs.company.controller.company;
+
+import java.util.List;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.extension.api.R;
+import com.fs.common.utils.ServletUtils;
+import com.fs.company.param.CompanyDomainBindParam;
+import com.fs.company.vo.CompanyDomainBindVo;
+import com.fs.framework.security.LoginUser;
+import com.fs.framework.service.TokenService;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.company.domain.CompanyDomainBind;
+import com.fs.company.service.ICompanyDomainBindService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 域名绑定销售公司Controller
+ * 
+ * @author fs
+ * @date 2025-06-17
+ */
+@RestController
+@RequestMapping("/company/companyDomainBind")
+public class CompanyDomainBindController extends BaseController
+{
+    @Autowired
+    private TokenService tokenService;
+    @Autowired
+    private ICompanyDomainBindService companyDomainBindService;
+
+    /**
+     * 查询域名绑定销售公司列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDomainBind:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyDomainBindParam companyDomainBind)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        companyDomainBind.setCompanyId(loginUser.getUser().getCompanyId());
+        startPage();
+        List<CompanyDomainBindVo> list = companyDomainBindService.selectCompanyDomainBindList(companyDomainBind);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出域名绑定销售公司列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDomainBind:export')")
+    @Log(title = "域名绑定销售公司", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyDomainBindParam companyDomainBind)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        companyDomainBind.setCompanyId(loginUser.getUser().getCompanyId());
+        List<CompanyDomainBindVo> list = companyDomainBindService.selectCompanyDomainBindList(companyDomainBind);
+        ExcelUtil<CompanyDomainBindVo> util = new ExcelUtil<CompanyDomainBindVo>(CompanyDomainBindVo.class);
+        return util.exportExcel(list, "域名绑定销售公司数据");
+    }
+
+    /**
+     * 获取域名绑定销售公司详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDomainBind:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(companyDomainBindService.selectCompanyDomainBindById(id));
+    }
+
+    /**
+     * 新增域名绑定销售公司
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDomainBind:add')")
+    @Log(title = "域名绑定销售公司", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanyDomainBind companyDomainBind)
+    {
+        return toAjax(companyDomainBindService.insertCompanyDomainBind(companyDomainBind));
+    }
+
+    /**
+     * 修改域名绑定销售公司
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDomainBind:edit')")
+    @Log(title = "域名绑定销售公司", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanyDomainBind companyDomainBind)
+    {
+        return toAjax(companyDomainBindService.updateCompanyDomainBind(companyDomainBind));
+    }
+
+    /**
+     * 删除域名绑定销售公司
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDomainBind:remove')")
+    @Log(title = "域名绑定销售公司", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(companyDomainBindService.deleteCompanyDomainBindByIds(ids));
+    }
+
+    /**
+     * 域名批量绑定
+     **/
+    @PreAuthorize("@ss.hasPermi('company:companyDomain:domainBatchBinding')")
+    @PostMapping("/domainBatchBinding")
+    public R domainBatchBinding(@RequestBody CompanyDomainBindParam param) {
+        if (ObjectUtil.isEmpty(param.getCompanyIds()) || param.getCompanyIds().isEmpty()) {
+            return R.failed("绑定失败,至少有一条域名分配信息!");
+        }
+        if (ObjectUtil.isEmpty(param.getCompanyUserIds()) || param.getCompanyUserIds().isEmpty()) {
+            return R.failed("绑定失败,至少有一条分配人员信息!");
+        }
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setUserId(loginUser.getUser().getUserId().toString());
+        return companyDomainBindService.domainBatchBinding(param);
+    }
+}

+ 108 - 0
fs-company/src/main/java/com/fs/company/controller/company/CompanyDomainBindUserController.java

@@ -0,0 +1,108 @@
+package com.fs.company.controller.company;
+
+import java.util.List;
+
+import com.fs.common.utils.ServletUtils;
+import com.fs.company.param.CompanyDomainBindUserParam;
+import com.fs.company.vo.CompanyDomainBindUserVo;
+import com.fs.framework.security.LoginUser;
+import com.fs.framework.service.TokenService;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.company.domain.CompanyDomainBindUser;
+import com.fs.company.service.ICompanyDomainBindUserService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 企业域名分配中间表Controller
+ *
+ * @author fs
+ * @date 2025-06-19
+ */
+@RestController
+@RequestMapping("/company/companyBindUser")
+public class CompanyDomainBindUserController extends BaseController {
+    @Autowired
+    private TokenService tokenService;
+    @Autowired
+    private ICompanyDomainBindUserService companyDomainBindUserService;
+
+    /**
+     * 查询企业域名分配中间表列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyBindUser:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyDomainBindUserParam companyDomainBindUser) {
+        startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        companyDomainBindUser.setCompanyId(loginUser.getUser().getCompanyId());
+        List<CompanyDomainBindUserVo> list = companyDomainBindUserService.selectCompanyDomainBindUserList(companyDomainBindUser);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出企业域名分配中间表列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyBindUser:export')")
+    @Log(title = "企业域名分配中间表", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyDomainBindUserParam companyDomainBindUser) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        companyDomainBindUser.setCompanyId(loginUser.getUser().getCompanyId());
+        List<CompanyDomainBindUserVo> list = companyDomainBindUserService.selectCompanyDomainBindUserList(companyDomainBindUser);
+        ExcelUtil<CompanyDomainBindUserVo> util = new ExcelUtil<CompanyDomainBindUserVo>(CompanyDomainBindUserVo.class);
+        return util.exportExcel(list, "企业域名分配中间表数据");
+    }
+
+    /**
+     * 获取企业域名分配中间表详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyBindUser:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id) {
+        return AjaxResult.success(companyDomainBindUserService.selectCompanyDomainBindUserById(id));
+    }
+
+    /**
+     * 新增企业域名分配中间表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyBindUser:add')")
+    @Log(title = "企业域名分配中间表", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanyDomainBindUser companyDomainBindUser) {
+        return toAjax(companyDomainBindUserService.insertCompanyDomainBindUser(companyDomainBindUser));
+    }
+
+    /**
+     * 修改企业域名分配中间表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyBindUser:edit')")
+    @Log(title = "企业域名分配中间表", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanyDomainBindUser companyDomainBindUser) {
+        return toAjax(companyDomainBindUserService.updateCompanyDomainBindUser(companyDomainBindUser));
+    }
+
+    /**
+     * 删除企业域名分配中间表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyBindUser:remove')")
+    @Log(title = "企业域名分配中间表", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids) {
+        return toAjax(companyDomainBindUserService.deleteCompanyDomainBindUserByIds(ids));
+    }
+}

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

@@ -180,6 +180,7 @@ public class CompanyUserController extends BaseController
         user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
         user.setCreateTime(new Date());
         user.setUserType("01");//一般用户
+        user.setIsAudit(1);
         return toAjax(companyUserService.insertUser(user));
     }
 

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

@@ -44,11 +44,14 @@ public class FsCourseAnswerLogsController extends BaseController
     @GetMapping("/list")
     public TableDataInfo list(FsCourseAnswerLogsParam param)
     {
-        startPage();
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         if (param.getPhoneMk() != null && param.getPhoneMk() != "") {
             param.setPhone(encryptPhone(param.getPhoneMk()));
         }
+        param.setCompanyId( loginUser.getCompany().getCompanyId());
 
+        startPage();
         List<FsCourseAnswerLogsListVO> list = fsCourseAnswerLogsService.selectFsCourseAnswerLogsListVO(param);
         return getDataTable(list);
     }
@@ -60,7 +63,7 @@ public class FsCourseAnswerLogsController extends BaseController
     @GetMapping("/myList")
     public TableDataInfo myList(FsCourseAnswerLogsParam param)
     {
-        startPage();
+
 
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         param.setCompanyId( loginUser.getCompany().getCompanyId());
@@ -68,6 +71,7 @@ public class FsCourseAnswerLogsController extends BaseController
         if (param.getPhoneMk() != null && param.getPhoneMk() != "") {
             param.setPhone(encryptPhone(param.getPhoneMk()));
         }
+        startPage();
 
         List<FsCourseAnswerLogsListVO> list = fsCourseAnswerLogsService.selectFsCourseAnswerLogsListVO(param);
         return getDataTable(list);

+ 43 - 4
fs-company/src/main/java/com/fs/user/FsUserAdminController.java

@@ -1,5 +1,6 @@
 package com.fs.user;
 
+import com.alibaba.fastjson.JSON;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
@@ -7,11 +8,16 @@ import com.fs.common.utils.ServletUtils;
 import com.fs.company.cache.ICompanyUserCacheService;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
+
 import com.fs.his.service.IFsUserService;
+import com.fs.qw.domain.CustomerTransferApproval;
+import com.fs.qw.dto.FsUserTransferParamDTO;
+import com.fs.qw.service.ICustomerTransferApprovalService;
 import com.fs.store.param.h5.FsUserPageListParam;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -19,8 +25,11 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.Date;
+
 @Api(tags = "会员管理接口")
 @RestController
+@Slf4j
 @RequestMapping("/user/fsUser")
 @AllArgsConstructor
 public class FsUserAdminController extends BaseController {
@@ -34,16 +43,22 @@ public class FsUserAdminController extends BaseController {
     @Autowired
     private TokenService tokenService;
 
+    @Autowired
+    private ICustomerTransferApprovalService transferApprovalService;
+
     @PreAuthorize("@ss.hasPermi('user:fsUser:list')")
     @PostMapping("/list")
     @ApiOperation("会员列表(与移动端使用的相同查询)")
     public TableDataInfo pageList(@RequestBody FsUserPageListParam param) {
-//        startPage();
+        //startPage();
 
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-        param.setCompanyId(loginUser.getCompany().getCompanyId());
-        param.setCompanyUserId(String.valueOf(loginUser.getUser().getUserId()));
-
+        if (param.isMyFsUser()){
+            param.setCompanyId(loginUser.getCompany().getCompanyId());
+            param.setCompanyUserId(String.valueOf(loginUser.getUser().getUserId()));
+        }else {
+            param.setCompanyId(loginUser.getCompany().getCompanyId());
+        }
         if(param.getCompanyUserId() == null) {
             throw new IllegalArgumentException("当前销售不存在!");
         }
@@ -60,5 +75,29 @@ public class FsUserAdminController extends BaseController {
         return R.error();
     }
 
+    /**
+     * 转移
+     * @param param
+     */
+    @PostMapping("/transfer")
+    public R transfer(@RequestBody FsUserTransferParamDTO param){
+        log.info("客户转移: {}",param);
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setSourceCompanyUserId(loginUser.getUser().getUserId());
+        CustomerTransferApproval customerTransferApproval = new CustomerTransferApproval();
+        customerTransferApproval.setCorpId(String.valueOf(loginUser.getCompany().getCompanyId()));
+        customerTransferApproval.setCustomerIds(JSON.toJSONString(param.getUserIds()));
+        customerTransferApproval.setOriginalUserId(param.getSourceCompanyUserId());
+        customerTransferApproval.setTargetUserId(param.getTargetCompanyUserId());
+        customerTransferApproval.setInitiatorUserId(param.getSourceCompanyUserId());
+        customerTransferApproval.setContent(param.getContent());
+        customerTransferApproval.setCreatedAt(new Date());
+        customerTransferApproval.setUpdatedAt(new Date());
+        customerTransferApproval.setApprovalStatus(0);
+        customerTransferApproval.setTransferType(2);
+        transferApprovalService.insertCustomerTransferApproval(customerTransferApproval);
+        return R.ok("转移申请已经提交,等待转移成功!");
+    }
+
 
 }

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

@@ -3,7 +3,7 @@ server:
 # Spring配置
 spring:
   profiles:
-    active: dev
+    active: druid-fcky-test
 #    active: druid-jzzx
 #    active: druid-hdt
 #    active: druid-sxjz

+ 5 - 2
fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java

@@ -20,6 +20,7 @@ import com.fs.sop.mapper.QwSopMapper;
 import com.fs.sop.mapper.SopUserLogsMapper;
 import com.fs.sop.service.*;
 import com.fs.sop.vo.QwSopLogsDoSendListTVO;
+import com.fs.store.service.IFsUserCourseCountService;
 import io.swagger.annotations.Api;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -82,6 +83,9 @@ public class CommonController {
     @Autowired
     private ISopUserLogsService iSopUserLogsService;
 
+    @Autowired
+    private IFsUserCourseCountService userCourseCountService;
+
 
     @GetMapping("/testSop")
     public R testSop() throws Exception {
@@ -194,8 +198,7 @@ public class CommonController {
     private SopLogsChatTaskService sopLogsChatTaskService;
     @GetMapping("/test2")
     public String selectChatSopUserLogsListByTime() throws Exception {
-        System.out.println("test2");
-       // sopLogsChatTaskService.createAiChatSopLogs();
+        userCourseCountService.insertFsUserCourseCountTask();
         return "s";
     }
 

+ 2 - 2
fs-qw-task/src/main/java/com/fs/app/task/UserCourseWatchCountTask.java

@@ -14,9 +14,9 @@ public class UserCourseWatchCountTask {
 
 
     /**
-     * 每天两点进行会员看课统计
+     * 每15分钟执行一次
      */
-    @Scheduled(cron = "0 0 2 * * ?")  // 2点0分0秒执行
+    @Scheduled(cron = "0 */15 * * * ?")  // 每15分钟执行一次
     public void userCourseCountTask() {
         try {
             log.info("==============会员看课统计任务执行===============开始");

+ 34 - 18
fs-qw-task/src/main/java/com/fs/app/task/qwTask.java

@@ -28,7 +28,7 @@ import java.util.List;
 /**
  * 企业微信SOP定时任务管理类
  * 负责处理各种定时任务,包括SOP规则检查、消息发送、数据清理等
- * 
+ *
  * @author 系统
  * @version 1.0
  */
@@ -50,10 +50,10 @@ public class qwTask {
 
     @Autowired
     private ISopUserLogsService sopUserLogsService;
-    
+
     @Autowired
     private SopLogsTaskService sopLogsTaskService;
-    
+
     @Autowired
     private SopWxLogsService sopWxLogsService;
 
@@ -71,7 +71,7 @@ public class qwTask {
 
     @Autowired
     private QwSopLogsMapper qwSopLogsMapper;
-    
+
     @Autowired
     private IQwSopTagService qwSopTagService;
 
@@ -99,7 +99,7 @@ public class qwTask {
      * 定时任务:根据营期生成sopLogs待发记录
      * 执行时间:每小时的第5分钟执行
      * 功能:根据营期时间生成需要发送的SOP日志记录
-     * 
+     *
      * @throws Exception 执行异常
      */
     @Scheduled(cron = "0 5 * * * ?") // 每小时的第5分钟触发
@@ -118,7 +118,7 @@ public class qwTask {
      * 定时任务:微信SOP处理
      * 执行时间:每小时的第5分钟执行
      * 功能:处理微信相关的SOP日志
-     * 
+     *
      * @throws Exception 执行异常
      */
     @Scheduled(cron = "0 5 * * * ?") // 每小时的第5分钟触发
@@ -136,7 +136,7 @@ public class qwTask {
      * 定时任务:处理聊天SOP用户日志
      * 执行时间:已注释,原为每分钟的第5秒执行
      * 功能:将clickHouse的sopUserLogsChat(营期表)按每分钟巡回处理
-     * 
+     *
      * @throws Exception 执行异常
      */
 //    @Scheduled(cron = "5 0/1 * * * ?")
@@ -149,20 +149,36 @@ public class qwTask {
     }
 
     /**
-     * 定时任务:发送企业微信SOP群发消息(新版-按营期发送)
-     * 执行时间:每天凌晨 0:20:00
-     * 功能:通过调用企业微信接口发送SOP群发消息
+     * 定时 发送 通过调用 企业微信接口 发送的 SOP 群发消息(按单链发)
      */
-    @Scheduled(cron = "0 20 0 * * ?")
-    public void SendQwApiSopLogTimerNew() {
-        log.info("zyp \n【企微官方接口群发开始】");
-        
-        // 获取当前日期
+    @Scheduled(cron = "0 20 1 * * ?")
+    public void SendQwApiSopLogTimer(){
+        log.info("zyp \n【企微官方接口群发开始-单链】");
+//        qwSopLogsService.checkQwSopLogs();
         LocalDate localDate = LocalDateTime.now().withMinute(0).withSecond(0).withNano(0).toLocalDate();
         String date = localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
 
-        // 根据用户日志创建企业群发
-        qwSopLogsService.createCorpMassSendingByUserLogs(date);
+        qwSopLogsService.createCorpMassSending(date);
+    }
+
+    /**
+     * 定时 发送 通过调用 企业微信接口 发送的 SOP 群发消息(新版-安装营期发)
+     */
+    @Scheduled(cron = "0 10 0,1 * * ?")
+    public void SendQwApiSopLogTimerNew(){
+
+        log.info("zyp \n【企微官方接口群发开始】");
+//        qwSopLogsService.checkQwSopLogs();
+//        LocalDate localDate = LocalDateTime.now().withMinute(0).withSecond(0).withNano(0).toLocalDate();
+//        String date = localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+
+        int currentHour = LocalDateTime.now().getHour();
+        String taskStartTime = LocalDate.now().atTime(currentHour, 0, 0)
+                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+        String taskEndTime = LocalDate.now().atTime(currentHour, 59, 59)
+                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+
+        qwSopLogsService.createCorpMassSendingByUserLogs(taskStartTime,taskEndTime);
     }
 
     /**
@@ -246,7 +262,7 @@ public class qwTask {
 
     /**
      * 批量处理插入逻辑,支持每500条数据一次的批量插入
-     * 
+     *
      * @param logsByJsApiNotExtId 需要处理的日志列表
      */
     private void processAndInsertQwSopLogs(List<QwSopLogsDoSendListTVO> logsByJsApiNotExtId) {

+ 1 - 1
fs-qw-task/src/main/resources/application.yml

@@ -10,4 +10,4 @@ spring:
 #    active: druid-hcl
 #    active: druid-sxjz
 #    active: druid-hdt
-    active: druid-myhk
+    active: druid-fcky-test

+ 5 - 20
fs-qwhook-sop/src/main/java/com/fs/app/controller/ApisFsUserCourseVideoController.java

@@ -54,25 +54,6 @@ public class ApisFsUserCourseVideoController extends BaseController {
 
 
 
-    @PostMapping("/pageList")
-    @ApiOperation("课程分页列表")
-    public R list(@RequestBody UserCourseVideoPageParam param) {
-
-        QwUser qwUser = qwExternalContactService.getQwUserByRedis(param.getCorpId().trim(), param.getQwUserId().trim());
-
-        if (qwUser == null || qwUser.getCompanyId() == null) {
-            return R.error("员工未绑定 销售公司 或 未获取到员工信息,请重试!");
-        }
-        param.setCompanyId(qwUser.getCompanyId());
-
-
-        PageHelper.startPage(param.getPageNum(), param.getPageSize());
-        List<FsUserCourseVideoPageListVO> list = fsUserCourseVideoService.pageListCourseVideo(param);
-        PageInfo<FsUserCourseVideoPageListVO> pageInfo = new PageInfo<>(list);
-        return R.ok().put("data",pageInfo);
-    }
-
-
     @ApiOperation("课程视频详情")
     @GetMapping(value = "/videoDetails")
     public R getVideoDetails(Long videoId) {
@@ -163,7 +144,11 @@ public class ApisFsUserCourseVideoController extends BaseController {
             return R.error("客户id不能为空");
         }
 
-        return fsUserCourseVideoService.createCartLink(param);
+        if (param.getType()==null || param.getType()==1){
+            return fsUserCourseVideoService.createCartLink(param);
+        }else {
+            return fsUserCourseVideoService.createMiniLink(param);
+        }
     }
 
     @GetMapping("/createRoomLink")

+ 5 - 45
fs-qwhook-sop/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java

@@ -53,21 +53,6 @@ public class FsUserCourseVideoController {
     @Autowired
     private IQwExternalContactService qwExternalContactService;
 
-    @GetMapping("/pageList")
-    @ApiOperation("课程分页列表")
-    public ResponseResult<PageInfo<FsUserCourseVideoPageListVO>> list(UserCourseVideoPageParam param) {
-
-        QwUser qwUser = qwExternalContactService.getQwUserByRedis(param.getCorpId().trim(), param.getQwUserId().trim());
-
-        if (qwUser==null||qwUser.getCompanyId()==null){
-            return ResponseResult.fail(500,"无权限");
-        }
-        PageHelper.startPage(param.getPageNum(), param.getPageSize());
-        param.setCompanyId(qwUser.getCompanyId());
-        List<FsUserCourseVideoPageListVO> list = fsUserCourseVideoService.pageListCourseVideo(param);
-        PageInfo<FsUserCourseVideoPageListVO> pageInfo = new PageInfo<>(list);
-        return ResponseResult.ok(pageInfo);
-    }
 
     @ApiOperation("课程视频详情")
     @GetMapping(value = "/videoDetails")
@@ -75,35 +60,6 @@ public class FsUserCourseVideoController {
         return fsUserCourseVideoService.getVideoDetails(videoId);
     }
 
-    @GetMapping("/courseList")
-    @ApiOperation("获取课程下拉列表")
-    public ResponseResult<PageInfo<FsUserCourseListVO>> getAllCourseList(FsUserCourseListParam param) {
-        QwUser qwUser = qwUserService.getByQwUserIdAndCorId(param.getQwUserId(), param.getCorpId());
-        if (qwUser==null||qwUser.getCompanyId()==null){
-            return ResponseResult.fail(500,"无权限");
-        }
-        PageHelper.startPage(param.getPageNum(), param.getPageSize());
-        param.setCompanyId(qwUser.getCompanyId());
-        List<FsUserCourseListVO> fsUserCourseList = fsUserCourseService.getFsUserCourseList(param);
-        PageInfo<FsUserCourseListVO> pageInfo = new PageInfo<>(fsUserCourseList);
-        return ResponseResult.ok(pageInfo);
-    }
-
-    @GetMapping("/videoList")
-    @ApiOperation("获取视频下拉列表")
-    public ResponseResult<PageInfo<FsUserVideoListVO>> getAllVideoList(UserCourseVideoPageParam param) {
-        QwUser qwUser = qwUserService.getByQwUserIdAndCorId(param.getQwUserId(), param.getCorpId());
-        if (qwUser==null||qwUser.getCompanyId()==null){
-            return ResponseResult.fail(500,"无权限");
-        }
-        PageHelper.startPage(param.getPageNum(), param.getPageSize());
-        param.setCompanyId(qwUser.getCompanyId());
-        List<FsUserVideoListVO> listCourseVideo = fsUserCourseVideoService.getListCourseVideo(param);
-        PageInfo<FsUserVideoListVO> result = new PageInfo<>(listCourseVideo);
-        return ResponseResult.ok(result);
-    }
-
-
     @PostMapping("/getFsCourseListBySidebar")
     @ApiOperation("获取视频课程下拉列表 侧边栏")
     public R getFsCourseListBySidebar(@RequestBody FsCourseListBySidebarParam param) {
@@ -221,6 +177,10 @@ public class FsUserCourseVideoController {
             return R.error("客户id不能为空");
         }
 
-        return fsUserCourseVideoService.createCartLink(param);
+        if (param.getType()==null || param.getType()==1){
+            return fsUserCourseVideoService.createCartLink(param);
+        }else {
+            return fsUserCourseVideoService.createMiniLink(param);
+        }
     }
 }

+ 5 - 21
fs-qwhook/src/main/java/com/fs/app/controller/ApisFsUserCourseVideoController.java

@@ -53,26 +53,6 @@ public class ApisFsUserCourseVideoController extends BaseController {
     private IFsCourseLinkService courseLinkService;
 
 
-
-    @PostMapping("/pageList")
-    @ApiOperation("课程分页列表")
-    public R list(@RequestBody UserCourseVideoPageParam param) {
-
-        QwUser qwUser = qwExternalContactService.getQwUserByRedis(param.getCorpId().trim(), param.getQwUserId().trim());
-
-        if (qwUser == null || qwUser.getCompanyId() == null) {
-            return R.error("员工未绑定 销售公司 或 未获取到员工信息,请重试!");
-        }
-        param.setCompanyId(qwUser.getCompanyId());
-
-
-        PageHelper.startPage(param.getPageNum(), param.getPageSize());
-        List<FsUserCourseVideoPageListVO> list = fsUserCourseVideoService.pageListCourseVideo(param);
-        PageInfo<FsUserCourseVideoPageListVO> pageInfo = new PageInfo<>(list);
-        return R.ok().put("data",pageInfo);
-    }
-
-
     @ApiOperation("课程视频详情")
     @GetMapping(value = "/videoDetails")
     public R getVideoDetails(Long videoId) {
@@ -163,7 +143,11 @@ public class ApisFsUserCourseVideoController extends BaseController {
             return R.error("客户id不能为空");
         }
 
-        return fsUserCourseVideoService.createCartLink(param);
+        if (param.getType()==null || param.getType()==1){
+            return fsUserCourseVideoService.createCartLink(param);
+        }else {
+            return fsUserCourseVideoService.createMiniLink(param);
+        }
 
     }
 

+ 66 - 41
fs-qwhook/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java

@@ -1,10 +1,12 @@
 package com.fs.app.controller;
 
 import com.alibaba.fastjson.JSONObject;
+import com.fs.common.annotation.RepeatSubmit;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.ResponseResult;
 import com.fs.course.domain.FsUserCourse;
 import com.fs.course.param.FsCourseLinkCreateParam;
+import com.fs.course.param.FsCourseLinkMiniParam;
 import com.fs.course.param.FsCourseLinkRoomParam;
 import com.fs.course.param.FsCourseListBySidebarParam;
 import com.fs.course.param.newfs.FsUserCourseListParam;
@@ -21,6 +23,7 @@ import com.fs.course.vo.newfs.FsUserVideoListVO;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.service.IQwExternalContactService;
 import com.fs.qw.service.IQwUserService;
+import com.fs.voice.utils.StringUtil;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.Api;
@@ -50,19 +53,6 @@ public class FsUserCourseVideoController {
     @Autowired
     private IQwExternalContactService qwExternalContactService;
 
-    @GetMapping("/pageList")
-    @ApiOperation("课程分页列表")
-    public ResponseResult<PageInfo<FsUserCourseVideoPageListVO>> list(UserCourseVideoPageParam param) {
-        QwUser qwUser = qwUserService.getByQwUserIdAndCorId(param.getQwUserId(), param.getCorpId());
-        if (qwUser==null||qwUser.getCompanyId()==null){
-            return ResponseResult.fail(500,"无权限");
-        }
-        PageHelper.startPage(param.getPageNum(), param.getPageSize());
-        param.setCompanyId(qwUser.getCompanyId());
-        List<FsUserCourseVideoPageListVO> list = fsUserCourseVideoService.pageListCourseVideo(param);
-        PageInfo<FsUserCourseVideoPageListVO> pageInfo = new PageInfo<>(list);
-        return ResponseResult.ok(pageInfo);
-    }
 
     @ApiOperation("课程视频详情")
     @GetMapping(value = "/videoDetails")
@@ -70,34 +60,6 @@ public class FsUserCourseVideoController {
         return fsUserCourseVideoService.getVideoDetails(videoId);
     }
 
-    @GetMapping("/courseList")
-    @ApiOperation("获取课程下拉列表")
-    public ResponseResult<PageInfo<FsUserCourseListVO>> getAllCourseList(FsUserCourseListParam param) {
-        QwUser qwUser = qwUserService.getByQwUserIdAndCorId(param.getQwUserId(), param.getCorpId());
-        if (qwUser==null||qwUser.getCompanyId()==null){
-            return ResponseResult.fail(500,"无权限");
-        }
-        PageHelper.startPage(param.getPageNum(), param.getPageSize());
-        param.setCompanyId(qwUser.getCompanyId());
-        List<FsUserCourseListVO> fsUserCourseList = fsUserCourseService.getFsUserCourseList(param);
-        PageInfo<FsUserCourseListVO> pageInfo = new PageInfo<>(fsUserCourseList);
-        return ResponseResult.ok(pageInfo);
-    }
-
-    @GetMapping("/videoList")
-    @ApiOperation("获取视频下拉列表")
-    public ResponseResult<PageInfo<FsUserVideoListVO>> getAllVideoList(UserCourseVideoPageParam param) {
-        QwUser qwUser = qwUserService.getByQwUserIdAndCorId(param.getQwUserId(), param.getCorpId());
-        if (qwUser==null||qwUser.getCompanyId()==null){
-            return ResponseResult.fail(500,"无权限");
-        }
-        PageHelper.startPage(param.getPageNum(), param.getPageSize());
-        param.setCompanyId(qwUser.getCompanyId());
-        List<FsUserVideoListVO> listCourseVideo = fsUserCourseVideoService.getListCourseVideo(param);
-        PageInfo<FsUserVideoListVO> result = new PageInfo<>(listCourseVideo);
-        return ResponseResult.ok(result);
-    }
-
 
     @PostMapping("/getFsCourseListBySidebar")
     @ApiOperation("获取视频课程下拉列表 侧边栏")
@@ -130,9 +92,72 @@ public class FsUserCourseVideoController {
         return R.ok().put("data", result);
     }
 
+
+
     @Autowired
     private IFsCourseLinkService courseLinkService;
 
+
+    /**
+     * 创建 发客户小程序
+     */
+
+    @RepeatSubmit
+    @PostMapping("/createMiniLink")
+    public R createMiniLink(@RequestBody FsCourseLinkMiniParam param) {
+
+        if (param.getCourseId()==null){
+            return R.error("课程id不能为空");
+        }
+        if (param.getVideoId()==null){
+            return R.error("视频id不能为空");
+        }
+        if (StringUtil.strIsNullOrEmpty(param.getQwUserId())){
+            return R.error("用户id不能为空");
+        }
+        if (StringUtil.strIsNullOrEmpty(param.getCorpId())){
+            return R.error("企业id不能为空");
+        }
+
+        if (param.getExternalUserId()==null){
+            return R.error("客户id不能为空");
+        }
+
+        return fsUserCourseVideoService.createMiniLink(param);
+    }
+
+    /**
+     * 创建发卡片
+     */
+    @RepeatSubmit
+    @PostMapping("/createCartLink")
+    public R createCartLink(@RequestBody  FsCourseLinkMiniParam param) {
+
+        if (param.getCourseId()==null){
+            return R.error("课程id不能为空");
+        }
+        if (param.getVideoId()==null){
+            return R.error("视频id不能为空");
+        }
+        if (StringUtil.strIsNullOrEmpty(param.getQwUserId())){
+            return R.error("用户id不能为空");
+        }
+        if (StringUtil.strIsNullOrEmpty(param.getCorpId())){
+            return R.error("企业id不能为空");
+        }
+
+        if (param.getExternalUserId()==null){
+            return R.error("客户id不能为空");
+        }
+
+        if (param.getType()==null || param.getType()==1){
+            return fsUserCourseVideoService.createCartLink(param);
+        }else {
+            return fsUserCourseVideoService.createMiniLink(param);
+        }
+
+    }
+
     @GetMapping("/createRoomLink")
     @ApiOperation("创建发群链接")
     public R createRoomLink(FsCourseLinkRoomParam param) {

+ 4 - 2
fs-service/src/main/java/com/fs/company/cache/ICompanyTagCacheService.java

@@ -1,9 +1,11 @@
 package com.fs.company.cache;
 
+import com.fs.company.domain.CompanyTag;
+
 import java.util.Map;
 
 public interface ICompanyTagCacheService {
-    String findUserTagByUserId(Long userId);
+    String findUserTagByUserId(Long userId,Long companyUserId);
 
-    Map<Long, String> queryAllTagMap();
+    Map<Long, CompanyTag> queryAllTagMap();
 }

+ 33 - 5
fs-service/src/main/java/com/fs/company/cache/impl/CompanyTagCacheServiceImpl.java

@@ -1,13 +1,17 @@
 package com.fs.company.cache.impl;
 
 import com.fs.company.cache.ICompanyTagCacheService;
+import com.fs.company.domain.CompanyTag;
 import com.fs.company.service.ICompanyTagService;
 import com.github.benmanes.caffeine.cache.Cache;
 import com.github.benmanes.caffeine.cache.Caffeine;
+import lombok.Data;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.io.Serializable;
 import java.util.Map;
+import java.util.Objects;
 import java.util.concurrent.TimeUnit;
 
 @Service
@@ -15,22 +19,46 @@ public class CompanyTagCacheServiceImpl implements ICompanyTagCacheService {
 
     @Autowired
     private ICompanyTagService companyTagService;
-    private static final Cache<Long,String> COMPANY_TAG_CACHE = Caffeine.newBuilder()
+    private static final Cache<TagConbKey,String> COMPANY_TAG_CACHE = Caffeine.newBuilder()
             .maximumSize(1000)
             .expireAfterWrite(5, TimeUnit.MINUTES)
             .build();
 
-    private static final Cache<Long,Map<Long, String>> COMPANY_USER_TAG_CACHE = Caffeine.newBuilder()
+    private static final Cache<Long,Map<Long, CompanyTag>> COMPANY_USER_TAG_CACHE = Caffeine.newBuilder()
             .maximumSize(1000)
             .expireAfterWrite(5, TimeUnit.MINUTES)
             .build();
+
+
+    @Data
+    static class TagConbKey implements Serializable {
+        private Long userId;
+        private Long companyUserId;
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            TagConbKey that = (TagConbKey) o;
+            return Objects.equals(userId, that.userId) && Objects.equals(companyUserId, that.companyUserId);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(userId, companyUserId);
+        }
+    }
     @Override
-    public String findUserTagByUserId(Long key) {
-        return COMPANY_TAG_CACHE.get(key,e-> companyTagService.findUserTagByUserId(key));
+    public String findUserTagByUserId(Long userId,Long companyUserId) {
+        TagConbKey tagConbKey = new TagConbKey();
+        tagConbKey.setUserId(userId);
+        tagConbKey.setCompanyUserId(companyUserId);
+        return COMPANY_TAG_CACHE.get(tagConbKey,e->
+                companyTagService.findUserTagByUserId(tagConbKey.getUserId(),tagConbKey.getCompanyUserId()));
     }
 
     @Override
-    public Map<Long, String> queryAllTagMap() {
+    public Map<Long, CompanyTag> queryAllTagMap() {
         return COMPANY_USER_TAG_CACHE.get(0L, e-> companyTagService.queryAllTagMap());
     }
 }

+ 27 - 0
fs-service/src/main/java/com/fs/company/domain/CompanyDomain.java

@@ -0,0 +1,27 @@
+package com.fs.company.domain;
+
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 域名管路对象 company_domain
+ *
+ * @author fs
+ * @date 2025-06-16
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class CompanyDomain extends BaseEntity{
+
+    /** 域名id */
+    private Long id;
+
+    /** 域名 */
+    private String domain;
+
+    /** 状态(1未启用、2启用) */
+    private Long status;
+
+
+}

+ 35 - 0
fs-service/src/main/java/com/fs/company/domain/CompanyDomainBind.java

@@ -0,0 +1,35 @@
+package com.fs.company.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 域名绑定销售公司对象 company_domain_bind
+ *
+ * @author fs
+ * @date 2025-06-17
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class CompanyDomainBind extends BaseEntity{
+
+    /** 域名绑定中间表 */
+    private Long id;
+
+    /** 销售公司ID */
+    @Excel(name = "销售公司ID")
+    private Long companyId;
+
+    /** 绑定域名ID */
+    @Excel(name = "绑定域名ID")
+    private Long domainId;
+
+    /** 状态 */
+    @Excel(name = "状态")
+    private Long status;
+
+
+}

+ 31 - 0
fs-service/src/main/java/com/fs/company/domain/CompanyDomainBindUser.java

@@ -0,0 +1,31 @@
+package com.fs.company.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 企业域名分配中间表对象 company_domain_bind_user
+ *
+ * @author fs
+ * @date 2025-06-19
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class CompanyDomainBindUser extends BaseEntity{
+
+    /** 中间表id */
+    private Long id;
+
+    /** 企业销售id */
+    @Excel(name = "企业销售id")
+    private Long companyUserId;
+
+    /** 中间表id */
+    @Excel(name = "中间表id")
+    private Long bindId;
+
+
+}

+ 83 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyDomainBindMapper.java

@@ -0,0 +1,83 @@
+package com.fs.company.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.company.domain.CompanyDomainBind;
+import com.fs.company.param.CompanyDomainBindParam;
+import com.fs.company.vo.CompanyDomainBindVo;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 域名绑定销售公司Mapper接口
+ * 
+ * @author fs
+ * @date 2025-06-17
+ */
+public interface CompanyDomainBindMapper extends BaseMapper<CompanyDomainBind>{
+    /**
+     * 查询域名绑定销售公司
+     * 
+     * @param id 域名绑定销售公司主键
+     * @return 域名绑定销售公司
+     */
+    CompanyDomainBind selectCompanyDomainBindById(Long id);
+
+    /**
+     * 查询域名绑定销售公司列表
+     * 
+     * @param companyDomainBind 域名绑定销售公司
+     * @return 域名绑定销售公司集合
+     */
+    List<CompanyDomainBind> selectCompanyDomainBindList(CompanyDomainBindParam companyDomainBind);
+
+    /**
+     * 新增域名绑定销售公司
+     * 
+     * @param companyDomainBind 域名绑定销售公司
+     * @return 结果
+     */
+    int insertCompanyDomainBind(CompanyDomainBind companyDomainBind);
+
+    /**
+     * 修改域名绑定销售公司
+     * 
+     * @param companyDomainBind 域名绑定销售公司
+     * @return 结果
+     */
+    int updateCompanyDomainBind(CompanyDomainBind companyDomainBind);
+
+    /**
+     * 删除域名绑定销售公司
+     * 
+     * @param id 域名绑定销售公司主键
+     * @return 结果
+     */
+    int deleteCompanyDomainBindById(Long id);
+
+    /**
+     * 批量删除域名绑定销售公司
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteCompanyDomainBindByIds(Long[] ids);
+
+    /**
+     * 批量插入绑定数据
+     * @param bindList 数据集合
+     * **/
+    void batchInsertBindInfo(@Param("bindList") List<CompanyDomainBind> bindList);
+
+    /**
+     * 批量删除域名绑定销售公司
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteCompanyDomainBindBydomainIds(Long[] ids);
+
+    /**
+     * 查询中间表链接信息
+     * **/
+    List<CompanyDomainBindVo> selectJoinBindInfo(CompanyDomainBindParam companyDomainBind);
+}

+ 75 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyDomainBindUserMapper.java

@@ -0,0 +1,75 @@
+package com.fs.company.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.company.domain.CompanyDomainBindUser;
+import com.fs.company.param.CompanyDomainBindUserParam;
+import com.fs.company.vo.CompanyDomainBindUserVo;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 企业域名分配中间表Mapper接口
+ * 
+ * @author fs
+ * @date 2025-06-19
+ */
+public interface CompanyDomainBindUserMapper extends BaseMapper<CompanyDomainBindUser>{
+    /**
+     * 查询企业域名分配中间表
+     * 
+     * @param id 企业域名分配中间表主键
+     * @return 企业域名分配中间表
+     */
+    CompanyDomainBindUser selectCompanyDomainBindUserById(Long id);
+
+    /**
+     * 查询企业域名分配中间表列表
+     * 
+     * @param companyDomainBindUser 企业域名分配中间表
+     * @return 企业域名分配中间表集合
+     */
+    List<CompanyDomainBindUserVo> selectCompanyDomainBindUserList(CompanyDomainBindUserParam companyDomainBindUser);
+
+    /**
+     * 新增企业域名分配中间表
+     * 
+     * @param companyDomainBindUser 企业域名分配中间表
+     * @return 结果
+     */
+    int insertCompanyDomainBindUser(CompanyDomainBindUser companyDomainBindUser);
+
+    /**
+     * 修改企业域名分配中间表
+     * 
+     * @param companyDomainBindUser 企业域名分配中间表
+     * @return 结果
+     */
+    int updateCompanyDomainBindUser(CompanyDomainBindUser companyDomainBindUser);
+
+    /**
+     * 删除企业域名分配中间表
+     * 
+     * @param id 企业域名分配中间表主键
+     * @return 结果
+     */
+    int deleteCompanyDomainBindUserById(Long id);
+
+    /**
+     * 批量删除企业域名分配中间表
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteCompanyDomainBindUserByIds(Long[] ids);
+
+    /**
+     * 批量插入
+     * @param bindUserList 插入对象
+     * **/
+    void batchInsertBindUserInfo(@Param("bindUserList") List<CompanyDomainBindUser> bindUserList);
+
+    /**
+     * 批量查询用户分配域名中间表接口
+     * **/
+    List<CompanyDomainBindUserVo> selectDoaminBindUserJoinInfo(CompanyDomainBindUserParam companyDomainBindUser);
+}

+ 79 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyDomainMapper.java

@@ -0,0 +1,79 @@
+package com.fs.company.mapper;
+
+import java.util.List;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.company.domain.CompanyDomain;
+import com.fs.company.param.CompanyDomainParam;
+import com.fs.company.vo.CompanyDomainVo;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 域名管路Mapper接口
+ *
+ * @author fs
+ * @date 2025-06-16
+ */
+public interface CompanyDomainMapper extends BaseMapper<CompanyDomain> {
+    /**
+     * 查询域名管路
+     *
+     * @param id 域名管路主键
+     * @return 域名管路
+     */
+    CompanyDomain selectCompanyDomainById(Long id);
+
+    /**
+     * 查询域名管路列表
+     *
+     * @param companyDomain 域名管路
+     * @return 域名管路集合
+     */
+    List<CompanyDomainVo> selectCompanyDomainList(CompanyDomainParam companyDomain);
+
+    /**
+     * 新增域名管路
+     *
+     * @param companyDomain 域名管路
+     * @return 结果
+     */
+    int insertCompanyDomain(CompanyDomain companyDomain);
+
+    /**
+     * 修改域名管路
+     *
+     * @param companyDomain 域名管路
+     * @return 结果
+     */
+    int updateCompanyDomain(CompanyDomain companyDomain);
+
+    /**
+     * 删除域名管路
+     *
+     * @param id 域名管路主键
+     * @return 结果
+     */
+    int deleteCompanyDomainById(Long id);
+
+    /**
+     * 批量删除域名管路
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteCompanyDomainByIds(Long[] ids);
+
+    /**
+     * 获取路由链接列表数量查询接口
+     *
+     * @param companyDomain 参数
+     * @return 结果
+     **/
+    List<CompanyDomainVo> selectCompanyDomainJoinInfo(CompanyDomainParam companyDomain);
+
+    /**
+     * 批量插入
+     * @param list 插入数据
+     * **/
+    void batchDomainInfo(@Param("list") List<CompanyDomain> list);
+}

+ 5 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyMapper.java

@@ -169,4 +169,9 @@ public interface CompanyMapper
 
     @Select("select company_id from company")
     List<Long> selectCompanyIds();
+
+    /**
+     * 通过企业id批量查询
+     * **/
+    List<Company> selectCompanyByIds(@Param("ids") List<Long> ids);
 }

+ 3 - 3
fs-service/src/main/java/com/fs/company/mapper/CompanyTagMapper.java

@@ -77,7 +77,7 @@ public interface CompanyTagMapper
      */
     List<CompanyTag> selectCompanyTagListByUserId(@Param("userId") Long userId);
 
-    String findUserTagByUserId(@Param("userId") Long userId);
-    @MapKey("tag_id")
-    Map<Long,String> queryAllTagMap();
+    String findUserTagByUserId(@Param("userId") Long userId,@Param("companyUserId") Long companyUserId);
+    @MapKey("tagId")
+    Map<Long,CompanyTag> queryAllTagMap();
 }

+ 14 - 2
fs-service/src/main/java/com/fs/company/mapper/CompanyUserMapper.java

@@ -1,5 +1,7 @@
 package com.fs.company.mapper;
 
+import com.fs.common.annotation.DataSource;
+import com.fs.common.enums.DataSourceType;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.param.CompanyUserAreaParam;
 import com.fs.company.param.CompanyUserQwParam;
@@ -212,7 +214,7 @@ public interface CompanyUserMapper
     @Select("select domain from company_user where user_id = #{userId}")
     String selectDomainByUserId(Long userId);
 
-    List<CompanyUser> selectAllCompanyUserAndSelf(@Param("userId") Long userId);
+    List<CompanyUser> selectAllCompanyUserAndSelf(@Param("userId") Long userId,@Param("companyId") Long companyId);
 
     @Select("select * from company_user where company_id=#{companyId} and del_flag=0")
     List<CompanyUser> selectCompanyUserByCompanyId(Long companyId);
@@ -231,10 +233,11 @@ public interface CompanyUserMapper
 
     /**
      * 根据部门ID查询销售列表
+     * @param companyId 公司ID
      * @param deptId    部门ID
      * @return  list
      */
-    List<CompanyUser> selectAllCompanyUserByDeptId(@Param("deptId") Long deptId);
+    List<CompanyUser> selectAllCompanyUserByCompanyIdAndDeptId(@Param("companyId") Long companyId, @Param("deptId") Long deptId);
 
     @Select("select * from company_user where ma_open_id = #{maOpenId}")
     CompanyUser getCompanyUserByOpenId(String openId);
@@ -252,4 +255,13 @@ public interface CompanyUserMapper
     int setIsRegisterMember(@Param("status") boolean status, @Param("userIds")List<Long> userIds);
 
     void auditUsers(@Param("userIds") List<Long> userIds);
+
+    /**
+     * 获取企业用户信息
+     * @param ids 数组
+     * @return 结果
+     * **/
+    List<CompanyUser> getUserInfoByUserIds(@Param("ids") List<Long> ids);
+    @DataSource(DataSourceType.MASTER)
+    CompanyUser selectCompanyUserByPhone(String phone);
 }

+ 47 - 0
fs-service/src/main/java/com/fs/company/param/CompanyDomainBindParam.java

@@ -0,0 +1,47 @@
+package com.fs.company.param;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 绑定域名管理中间表接收
+ **/
+@Data
+public class CompanyDomainBindParam implements Serializable {
+    /**
+     * 企业名称
+     * **/
+    private String companyName;
+
+    /**
+     * 域名
+     * **/
+    private String domain;
+
+    /**
+     * 绑定域名ID
+     * **/
+    private Long domainId;
+
+    /**
+     * 公司ID
+     * **/
+    private Long companyId;
+
+    /**
+     * 企业Id数组
+     **/
+    private List<Long> companyIds;
+
+    /**
+     * 企业用户ids
+     * **/
+    private List<Long> companyUserIds;
+
+    /**
+     * 用户id
+     * **/
+    private String userId;
+}

+ 36 - 0
fs-service/src/main/java/com/fs/company/param/CompanyDomainBindUserParam.java

@@ -0,0 +1,36 @@
+package com.fs.company.param;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class CompanyDomainBindUserParam implements Serializable {
+    /** 中间表id */
+    private Long id;
+
+    /** 企业销售id */
+    private Long companyUserId;
+
+    /** 中间表id */
+    private Long bindId;
+
+    /**
+     * 分配域名
+     **/
+    private String domain;
+
+    /**
+     * 分配人员
+     **/
+    private String userName;
+
+    /**
+     * 分配人员手机号
+     **/
+    private String phonenumber;
+
+    /**
+     * 企业ID
+     * **/
+    private Long companyId;
+}

+ 47 - 0
fs-service/src/main/java/com/fs/company/param/CompanyDomainParam.java

@@ -0,0 +1,47 @@
+package com.fs.company.param;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 域名管理接收
+ **/
+@Data
+public class CompanyDomainParam implements Serializable {
+    /**
+     * 域名id
+     */
+    private Long id;
+
+    /**
+     * 域名
+     */
+    private String domain;
+
+    /**
+     * 状态(1未启用、2启用)
+     */
+    private Long status;
+
+    /**
+     * 域名ID数组
+     **/
+    private List<Long> domainIds;
+
+    /**
+     * 企业Id数组
+     **/
+    private List<Long> companyIds;
+
+    /**
+     * 用户ID
+     * **/
+    private String userId;
+
+    /**
+     * 参数ids
+     * **/
+    private Long[] ids;
+}

+ 74 - 0
fs-service/src/main/java/com/fs/company/service/ICompanyDomainBindService.java

@@ -0,0 +1,74 @@
+package com.fs.company.service;
+
+import java.util.List;
+
+import com.baomidou.mybatisplus.extension.api.R;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.company.domain.CompanyDomainBind;
+import com.fs.company.param.CompanyDomainBindParam;
+import com.fs.company.vo.CompanyDomainBindVo;
+
+/**
+ * 域名绑定销售公司Service接口
+ * 
+ * @author fs
+ * @date 2025-06-17
+ */
+public interface ICompanyDomainBindService extends IService<CompanyDomainBind>{
+    /**
+     * 查询域名绑定销售公司
+     * 
+     * @param id 域名绑定销售公司主键
+     * @return 域名绑定销售公司
+     */
+    CompanyDomainBind selectCompanyDomainBindById(Long id);
+
+    /**
+     * 查询域名绑定销售公司列表
+     * 
+     * @param companyDomainBind 域名绑定销售公司
+     * @return 域名绑定销售公司集合
+     */
+    List<CompanyDomainBindVo> selectCompanyDomainBindList(CompanyDomainBindParam companyDomainBind);
+
+    /**
+     * 新增域名绑定销售公司
+     * 
+     * @param companyDomainBind 域名绑定销售公司
+     * @return 结果
+     */
+    int insertCompanyDomainBind(CompanyDomainBind companyDomainBind);
+
+    /**
+     * 修改域名绑定销售公司
+     * 
+     * @param companyDomainBind 域名绑定销售公司
+     * @return 结果
+     */
+    int updateCompanyDomainBind(CompanyDomainBind companyDomainBind);
+
+    /**
+     * 批量删除域名绑定销售公司
+     * 
+     * @param ids 需要删除的域名绑定销售公司主键集合
+     * @return 结果
+     */
+    int deleteCompanyDomainBindByIds(Long[] ids);
+
+    /**
+     * 删除域名绑定销售公司信息
+     * 
+     * @param id 域名绑定销售公司主键
+     * @return 结果
+     */
+    int deleteCompanyDomainBindById(Long id);
+
+
+    /**
+     * 域名批量绑定接口
+     *
+     * @param param 接收参数
+     * @return R
+     **/
+    R domainBatchBinding(CompanyDomainBindParam param);
+}

+ 63 - 0
fs-service/src/main/java/com/fs/company/service/ICompanyDomainBindUserService.java

@@ -0,0 +1,63 @@
+package com.fs.company.service;
+
+import java.util.List;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.company.domain.CompanyDomainBindUser;
+import com.fs.company.param.CompanyDomainBindUserParam;
+import com.fs.company.vo.CompanyDomainBindUserVo;
+
+/**
+ * 企业域名分配中间表Service接口
+ * 
+ * @author fs
+ * @date 2025-06-19
+ */
+public interface ICompanyDomainBindUserService extends IService<CompanyDomainBindUser>{
+    /**
+     * 查询企业域名分配中间表
+     * 
+     * @param id 企业域名分配中间表主键
+     * @return 企业域名分配中间表
+     */
+    CompanyDomainBindUser selectCompanyDomainBindUserById(Long id);
+
+    /**
+     * 查询企业域名分配中间表列表
+     * 
+     * @param companyDomainBindUser 企业域名分配中间表
+     * @return 企业域名分配中间表集合
+     */
+    List<CompanyDomainBindUserVo> selectCompanyDomainBindUserList(CompanyDomainBindUserParam companyDomainBindUser);
+
+    /**
+     * 新增企业域名分配中间表
+     * 
+     * @param companyDomainBindUser 企业域名分配中间表
+     * @return 结果
+     */
+    int insertCompanyDomainBindUser(CompanyDomainBindUser companyDomainBindUser);
+
+    /**
+     * 修改企业域名分配中间表
+     * 
+     * @param companyDomainBindUser 企业域名分配中间表
+     * @return 结果
+     */
+    int updateCompanyDomainBindUser(CompanyDomainBindUser companyDomainBindUser);
+
+    /**
+     * 批量删除企业域名分配中间表
+     * 
+     * @param ids 需要删除的企业域名分配中间表主键集合
+     * @return 结果
+     */
+    int deleteCompanyDomainBindUserByIds(Long[] ids);
+
+    /**
+     * 删除企业域名分配中间表信息
+     * 
+     * @param id 企业域名分配中间表主键
+     * @return 结果
+     */
+    int deleteCompanyDomainBindUserById(Long id);
+}

+ 83 - 0
fs-service/src/main/java/com/fs/company/service/ICompanyDomainService.java

@@ -0,0 +1,83 @@
+package com.fs.company.service;
+
+import java.util.List;
+
+import com.baomidou.mybatisplus.extension.api.R;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.company.domain.CompanyDomain;
+import com.fs.company.param.CompanyDomainParam;
+import com.fs.company.vo.CompanyDomainExportTemplateVo;
+import com.fs.company.vo.CompanyDomainVo;
+
+/**
+ * 域名管路Service接口
+ *
+ * @author fs
+ * @date 2025-06-16
+ */
+public interface ICompanyDomainService extends IService<CompanyDomain> {
+    /**
+     * 查询域名管路
+     *
+     * @param id 域名管路主键
+     * @return 域名管路
+     */
+    CompanyDomain selectCompanyDomainById(Long id);
+
+    /**
+     * 查询域名管路列表
+     *
+     * @param companyDomain 域名管路
+     * @return 域名管路集合
+     */
+    List<CompanyDomainVo> selectCompanyDomainList(CompanyDomainParam companyDomain);
+
+    /**
+     * 新增域名管路
+     *
+     * @param companyDomain 域名管路
+     * @return 结果
+     */
+    int insertCompanyDomain(CompanyDomain companyDomain);
+
+    /**
+     * 修改域名管路
+     *
+     * @param companyDomain 域名管路
+     * @return 结果
+     */
+    int updateCompanyDomain(CompanyDomain companyDomain);
+
+    /**
+     * 批量删除域名管路
+     *
+     * @param ids 需要删除的域名管路主键集合
+     * @return 结果
+     */
+    int deleteCompanyDomainByIds(Long[] ids);
+
+    /**
+     * 删除域名管路信息
+     *
+     * @param id 域名管路主键
+     * @return 结果
+     */
+    int deleteCompanyDomainById(Long id);
+
+    /**
+     * 域名批量绑定接口
+     *
+     * @param param 接收参数
+     * @return R
+     **/
+    R domainBatchBinding(CompanyDomainParam param);
+
+    /**
+     * 域名批量导入
+     *
+     * @param param      参数
+     * @param domainList 解析数组
+     * @return R
+     **/
+    R importDomainData(CompanyDomainParam param, List<CompanyDomainExportTemplateVo> domainList);
+}

+ 2 - 2
fs-service/src/main/java/com/fs/company/service/ICompanyTagService.java

@@ -74,7 +74,7 @@ public interface ICompanyTagService
      */
     List<CompanyTag> selectCompanyTagListByMap(Map<String, Object> params);
 
-    Map<Long,String> queryAllTagMap();
+    Map<Long,CompanyTag> queryAllTagMap();
 
-    String findUserTagByUserId(Long key);
+    String findUserTagByUserId(Long userId,Long companyUserId);
 }

+ 4 - 1
fs-service/src/main/java/com/fs/company/service/ICompanyUserService.java

@@ -151,10 +151,11 @@ public interface ICompanyUserService {
 
     /**
      * 查询销售列表
+     * @param companyId 公司ID
      * @param deptId 部门ID
      * @return list
      */
-    List<CompanyUser> getCompanyUserListByDeptId(Long deptId);
+    List<CompanyUser> getCompanyUserListByCompanyIdAndDeptId(Long companyId, Long deptId);
 
     /**
      * 根据openid获取销售
@@ -193,4 +194,6 @@ public interface ICompanyUserService {
     Boolean setIsRegisterMember(boolean status,  List<Long> userIds);
 
     void auditUsers(List<Long> userIds);
+
+    CompanyUser selectCompanyUserByPhone(String phone);
 }

+ 166 - 0
fs-service/src/main/java/com/fs/company/service/impl/CompanyDomainBindServiceImpl.java

@@ -0,0 +1,166 @@
+package com.fs.company.service.impl;
+
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.api.R;
+import com.fs.common.utils.DateUtils;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.company.domain.CompanyDomainBindUser;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.mapper.CompanyDomainBindUserMapper;
+import com.fs.company.mapper.CompanyUserMapper;
+import com.fs.company.param.CompanyDomainBindParam;
+import com.fs.company.vo.CompanyDomainBindVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.fs.company.mapper.CompanyDomainBindMapper;
+import com.fs.company.domain.CompanyDomainBind;
+import com.fs.company.service.ICompanyDomainBindService;
+
+/**
+ * 域名绑定销售公司Service业务层处理
+ *
+ * @author fs
+ * @date 2025-06-17
+ */
+@Service
+public class CompanyDomainBindServiceImpl extends ServiceImpl<CompanyDomainBindMapper, CompanyDomainBind> implements ICompanyDomainBindService {
+    @Autowired
+    private CompanyDomainBindMapper baseMapper;
+    @Autowired
+    private CompanyUserMapper companyUserMapper;
+
+    @Autowired
+    private CompanyDomainBindUserMapper companyDomainBindUserMapper;
+
+    /**
+     * 查询域名绑定销售公司
+     *
+     * @param id 域名绑定销售公司主键
+     * @return 域名绑定销售公司
+     */
+    @Override
+    public CompanyDomainBind selectCompanyDomainBindById(Long id) {
+        return baseMapper.selectCompanyDomainBindById(id);
+    }
+
+    /**
+     * 查询域名绑定销售公司列表
+     *
+     * @param companyDomainBind 域名绑定销售公司
+     * @return 域名绑定销售公司
+     */
+    @Override
+    public List<CompanyDomainBindVo> selectCompanyDomainBindList(CompanyDomainBindParam companyDomainBind) {
+        return baseMapper.selectJoinBindInfo(companyDomainBind);
+    }
+
+    /**
+     * 新增域名绑定销售公司
+     *
+     * @param companyDomainBind 域名绑定销售公司
+     * @return 结果
+     */
+    @Override
+    public int insertCompanyDomainBind(CompanyDomainBind companyDomainBind) {
+        companyDomainBind.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertCompanyDomainBind(companyDomainBind);
+    }
+
+    /**
+     * 修改域名绑定销售公司
+     *
+     * @param companyDomainBind 域名绑定销售公司
+     * @return 结果
+     */
+    @Override
+    public int updateCompanyDomainBind(CompanyDomainBind companyDomainBind) {
+        companyDomainBind.setUpdateTime(DateUtils.getNowDate());
+        return baseMapper.updateCompanyDomainBind(companyDomainBind);
+    }
+
+    /**
+     * 批量删除域名绑定销售公司
+     *
+     * @param ids 需要删除的域名绑定销售公司主键
+     * @return 结果
+     */
+    @Override
+    public int deleteCompanyDomainBindByIds(Long[] ids) {
+        return baseMapper.deleteCompanyDomainBindByIds(ids);
+    }
+
+    /**
+     * 删除域名绑定销售公司信息
+     *
+     * @param id 域名绑定销售公司主键
+     * @return 结果
+     */
+    @Override
+    public int deleteCompanyDomainBindById(Long id) {
+        return baseMapper.deleteCompanyDomainBindById(id);
+    }
+
+    @Override
+    public R domainBatchBinding(CompanyDomainBindParam param) {
+        //验证分配企业信息是否存在
+        List<CompanyDomainBind> companyDomainBindList = baseMapper.selectList(new LambdaQueryWrapper<CompanyDomainBind>().in(CompanyDomainBind::getId, param.getCompanyIds()));
+
+        if (companyDomainBindList.isEmpty()) {
+            return R.failed("分配域名企业数据不存在!");
+        }
+        if (companyDomainBindList.size() != param.getCompanyIds().size()) {
+            return R.failed("分配域名中存在不存在的记录!");
+        }
+
+        //验证分配人员是否存在
+        List<CompanyUser> companyUserList = companyUserMapper.getUserInfoByUserIds(param.getCompanyUserIds());
+        if (companyUserList.isEmpty()) {
+            return R.failed("分配人员数据不存在!");
+        }
+
+        if (companyUserList.size() != param.getCompanyUserIds().size()) {
+            return R.failed("分配人员中存在不存在的记录!");
+        }
+
+        //获取分配关系
+        Set<String> existingBinds = companyDomainBindUserMapper.selectList(new LambdaQueryWrapper<CompanyDomainBindUser>().in(CompanyDomainBindUser::getBindId, param.getCompanyIds()).in(CompanyDomainBindUser::getCompanyUserId, param.getCompanyUserIds())).stream()
+                .map(bind -> bind.getBindId() + "key" + bind.getCompanyUserId())
+                .collect(Collectors.toSet());
+
+        List<CompanyDomainBindUser> insertUserList = new LinkedList<>();
+        String userId = param.getUserId();
+        for (Long bind : param.getCompanyIds()) {
+            for (Long bindUser : param.getCompanyUserIds()) {
+                String key = bind + "key" + bindUser;
+                if (!existingBinds.contains(key)) {
+                    CompanyDomainBindUser user = new CompanyDomainBindUser();
+                    user.setBindId(bind);
+                    user.setCompanyUserId(bindUser);
+                    user.setCreateTime(new Date());
+                    user.setCreateBy(userId);
+                    insertUserList.add(user);
+                }
+            }
+        }
+
+        //批量插入数据
+        if (!insertUserList.isEmpty()) {
+            batchBindInsert(insertUserList, 1000);
+        }
+        return R.ok("操作成功!");
+    }
+
+    // 分批插入方法
+    private void batchBindInsert(List<CompanyDomainBindUser> list, int batchSize) {
+        for (int i = 0; i < list.size(); i += batchSize) {
+            int end = Math.min(i + batchSize, list.size());
+            companyDomainBindUserMapper.batchInsertBindUserInfo(list.subList(i, end));
+        }
+    }
+}

+ 95 - 0
fs-service/src/main/java/com/fs/company/service/impl/CompanyDomainBindUserServiceImpl.java

@@ -0,0 +1,95 @@
+package com.fs.company.service.impl;
+
+import java.util.List;
+import com.fs.common.utils.DateUtils;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.company.param.CompanyDomainBindUserParam;
+import com.fs.company.vo.CompanyDomainBindUserVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.fs.company.mapper.CompanyDomainBindUserMapper;
+import com.fs.company.domain.CompanyDomainBindUser;
+import com.fs.company.service.ICompanyDomainBindUserService;
+
+/**
+ * 企业域名分配中间表Service业务层处理
+ * 
+ * @author fs
+ * @date 2025-06-19
+ */
+@Service
+public class CompanyDomainBindUserServiceImpl extends ServiceImpl<CompanyDomainBindUserMapper, CompanyDomainBindUser> implements ICompanyDomainBindUserService {
+
+    /**
+     * 查询企业域名分配中间表
+     * 
+     * @param id 企业域名分配中间表主键
+     * @return 企业域名分配中间表
+     */
+    @Override
+    public CompanyDomainBindUser selectCompanyDomainBindUserById(Long id)
+    {
+        return baseMapper.selectCompanyDomainBindUserById(id);
+    }
+
+    /**
+     * 查询企业域名分配中间表列表
+     * 
+     * @param companyDomainBindUser 企业域名分配中间表
+     * @return 企业域名分配中间表
+     */
+    @Override
+    public List<CompanyDomainBindUserVo> selectCompanyDomainBindUserList(CompanyDomainBindUserParam companyDomainBindUser)
+    {
+        return baseMapper.selectDoaminBindUserJoinInfo(companyDomainBindUser);
+    }
+
+    /**
+     * 新增企业域名分配中间表
+     * 
+     * @param companyDomainBindUser 企业域名分配中间表
+     * @return 结果
+     */
+    @Override
+    public int insertCompanyDomainBindUser(CompanyDomainBindUser companyDomainBindUser)
+    {
+        companyDomainBindUser.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertCompanyDomainBindUser(companyDomainBindUser);
+    }
+
+    /**
+     * 修改企业域名分配中间表
+     * 
+     * @param companyDomainBindUser 企业域名分配中间表
+     * @return 结果
+     */
+    @Override
+    public int updateCompanyDomainBindUser(CompanyDomainBindUser companyDomainBindUser)
+    {
+        return baseMapper.updateCompanyDomainBindUser(companyDomainBindUser);
+    }
+
+    /**
+     * 批量删除企业域名分配中间表
+     * 
+     * @param ids 需要删除的企业域名分配中间表主键
+     * @return 结果
+     */
+    @Override
+    public int deleteCompanyDomainBindUserByIds(Long[] ids)
+    {
+        return baseMapper.deleteCompanyDomainBindUserByIds(ids);
+    }
+
+    /**
+     * 删除企业域名分配中间表信息
+     * 
+     * @param id 企业域名分配中间表主键
+     * @return 结果
+     */
+    @Override
+    public int deleteCompanyDomainBindUserById(Long id)
+    {
+        return baseMapper.deleteCompanyDomainBindUserById(id);
+    }
+}

+ 274 - 0
fs-service/src/main/java/com/fs/company/service/impl/CompanyDomainServiceImpl.java

@@ -0,0 +1,274 @@
+package com.fs.company.service.impl;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.api.R;
+import com.fs.common.exception.ServiceException;
+import com.fs.common.utils.DateUtils;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyDomainBind;
+import com.fs.company.mapper.CompanyDomainBindMapper;
+import com.fs.company.mapper.CompanyMapper;
+import com.fs.company.param.CompanyDomainParam;
+import com.fs.company.vo.CompanyDomainExportTemplateVo;
+import com.fs.company.vo.CompanyDomainVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.fs.company.mapper.CompanyDomainMapper;
+import com.fs.company.domain.CompanyDomain;
+import com.fs.company.service.ICompanyDomainService;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * 域名管路Service业务层处理
+ *
+ * @author fs
+ * @date 2025-06-16
+ */
+@Service
+public class CompanyDomainServiceImpl extends ServiceImpl<CompanyDomainMapper, CompanyDomain> implements ICompanyDomainService {
+    @Autowired
+    private CompanyMapper companyMapper;
+
+    @Autowired
+    private CompanyDomainMapper baseMapper;
+
+    @Autowired
+    private CompanyDomainBindMapper companyDomainBindMapper;
+
+    /**
+     * 查询域名管路
+     *
+     * @param id 域名管路主键
+     * @return 域名管路
+     */
+    @Override
+    public CompanyDomain selectCompanyDomainById(Long id) {
+        return baseMapper.selectCompanyDomainById(id);
+    }
+
+    /**
+     * 查询域名管路列表
+     *
+     * @param companyDomain 域名管路
+     * @return 域名管路
+     */
+    @Override
+    public List<CompanyDomainVo> selectCompanyDomainList(CompanyDomainParam companyDomain) {
+        return baseMapper.selectCompanyDomainJoinInfo(companyDomain);
+    }
+
+    /**
+     * 新增域名管路
+     *
+     * @param companyDomain 域名管路
+     * @return 结果
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int insertCompanyDomain(CompanyDomain companyDomain) {
+        //验证是否域名重复
+        if (baseMapper.selectCount(new LambdaQueryWrapper<CompanyDomain>().eq(CompanyDomain::getDomain, companyDomain.getDomain()).eq(CompanyDomain::getStatus, 1)) > 0) {
+            throw new ServiceException("更新失败,当前域名" + companyDomain.getDomain() + "已存在!");
+        }
+
+        companyDomain.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertCompanyDomain(companyDomain);
+    }
+
+    /**
+     * 修改域名管路
+     *
+     * @param companyDomain 域名管路
+     * @return 结果
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int updateCompanyDomain(CompanyDomain companyDomain) {
+        //验证数据是否存在
+        CompanyDomain domain = baseMapper.selectById(companyDomain.getId());
+        if (ObjectUtil.isEmpty(domain)) {
+            throw new ServiceException("操作失败,更新数据不存在!");
+        }
+
+        //验证是否域名重复
+        if (baseMapper.selectCount(new LambdaQueryWrapper<CompanyDomain>().eq(CompanyDomain::getDomain, companyDomain.getDomain()).eq(CompanyDomain::getStatus, 1).ne(CompanyDomain::getId, companyDomain.getId())) > 0) {
+            throw new ServiceException("更新失败,当前域名" + companyDomain.getDomain() + "已存在!");
+        }
+
+        companyDomain.setUpdateTime(DateUtils.getNowDate());
+        return baseMapper.updateCompanyDomain(companyDomain);
+    }
+
+    /**
+     * 批量删除域名管路
+     *
+     * @param ids 需要删除的域名管路主键
+     * @return 结果
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int deleteCompanyDomainByIds(Long[] ids) {
+        //查询域名
+        CompanyDomainParam companyDomain = new CompanyDomainParam();
+        companyDomain.setIds(ids);
+        List<CompanyDomainVo> domainList = baseMapper.selectCompanyDomainJoinInfo(companyDomain);
+        if (domainList.isEmpty() || domainList.size() != ids.length) {
+            throw new ServiceException("域名数量不一致,请核对后再试!");
+        }
+
+//        Map<Long, CompanyDomainVo> checkMap = domainList.stream().collect(Collectors.toMap(CompanyDomainVo::getId, d -> d));
+//        //查询是否有分配
+//        CompanyDomainVo checkVo;
+//        for (Long id : ids) {
+//            checkVo = checkMap.get(id);
+//            if (ObjectUtil.isNotNull(checkVo)) {
+//                if (ObjectUtil.isNotNull(checkVo.getBindNum()) && checkVo.getBindNum() > 0) {
+//                    throw new ServiceException("删除失败,当前域名" + checkVo.getDomain() + "已绑定" + checkVo.getBindNum() + "家销售公司,请解绑后操作!");
+//                } else if (checkVo.getStatus() == 1) {
+//                    throw new ServiceException("删除失败,当前域名" + checkVo.getDomain() + "状态正常启用中,请关闭后操作!");
+//                }
+//            }
+//        }
+        //删除域名企业中间表数据
+        companyDomainBindMapper.deleteCompanyDomainBindBydomainIds(ids);
+        //删除企业销售中间表数据
+
+        return baseMapper.deleteCompanyDomainByIds(ids);
+    }
+
+    /**
+     * 删除域名管路信息
+     *
+     * @param id 域名管路主键
+     * @return 结果
+     */
+    @Override
+    public int deleteCompanyDomainById(Long id) {
+        return baseMapper.deleteCompanyDomainById(id);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public R domainBatchBinding(CompanyDomainParam param) {
+        // 验证绑定域名是否存在(批量查询)
+        List<CompanyDomain> domainList = baseMapper.selectList(
+                new LambdaQueryWrapper<CompanyDomain>()
+                        .select(CompanyDomain::getId)
+                        .in(CompanyDomain::getId, param.getDomainIds())
+                        .eq(CompanyDomain::getStatus, 1)
+        );
+
+        if (domainList.isEmpty()) {
+            return R.failed("绑定域名数据不存在!");
+        }
+
+        if (domainList.size() != param.getDomainIds().size()) {
+            return R.failed("绑定域名中存在状态非激活或不存在的记录!");
+        }
+
+        // 验证绑定企业是否存在
+        List<Company> companyList = companyMapper.selectCompanyByIds(param.getCompanyIds());
+        if (companyList.isEmpty()) {
+            return R.failed("绑定企业数据不存在!");
+        }
+
+        if (companyList.size() != param.getCompanyIds().size()) {
+            return R.failed("绑定企业中存在不存在的记录!");
+        }
+
+        // 获取已存在的绑定关系
+        Set<String> existingBinds = companyDomainBindMapper.selectList(
+                        new LambdaQueryWrapper<CompanyDomainBind>()
+                                .select(CompanyDomainBind::getDomainId, CompanyDomainBind::getCompanyId)
+                                .in(CompanyDomainBind::getDomainId, param.getDomainIds())
+                                .in(CompanyDomainBind::getCompanyId, param.getCompanyIds())
+                )
+                .stream()
+                .map(bind -> bind.getDomainId() + "key" + bind.getCompanyId())
+                .collect(Collectors.toSet());
+
+        // 生成待插入的绑定关系(优化集合操作)
+        List<CompanyDomainBind> insertList = new ArrayList<>();
+        String userId = param.getUserId();  // 假设此处为userId
+
+        for (Long domainId : param.getDomainIds()) {
+            for (Company company : companyList) {
+                String key = domainId + "key" + company.getCompanyId();
+                if (!existingBinds.contains(key)) {
+                    insertList.add(createBind(domainId, company, userId));
+                }
+            }
+        }
+
+        // 批量插入数据(修正条件判断)
+        if (!insertList.isEmpty()) {
+            // 分批处理,每批1000条
+            batchBindInsert(insertList, 1000);
+        }
+
+        return R.ok("操作成功!");
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public R importDomainData(CompanyDomainParam param, List<CompanyDomainExportTemplateVo> domainList) {
+        if (!domainList.isEmpty()) {
+            //查询域名列表数据
+            List<String> domains = domainList.stream().map(CompanyDomainExportTemplateVo::getDomain).collect(Collectors.toList());
+            List<CompanyDomain> companyDomainList = baseMapper.selectList(new LambdaQueryWrapper<CompanyDomain>().select(CompanyDomain::getDomain).eq(CompanyDomain::getStatus, 1).in(CompanyDomain::getDomain, domains));
+            Map<String, Long> checkMap = companyDomainList.stream().collect(Collectors.toMap(CompanyDomain::getDomain, s -> 0L));
+            //便利数据
+            List<CompanyDomain> insertList = new LinkedList<>();
+            String userId = param.getUserId();
+            domainList.stream().filter(d -> ObjectUtil.isNotNull(d.getDomain())).forEach(f -> {
+                if (!checkMap.containsKey(f.getDomain())) {
+                    CompanyDomain domain = new CompanyDomain();
+                    domain.setStatus(1L);//默认启用
+                    domain.setCreateBy(userId);
+                    domain.setDomain(f.getDomain());
+                    domain.setRemark(f.getRemark());
+                    domain.setCreateTime(new Date());
+                    insertList.add(domain);
+                    checkMap.put(f.getDomain(), 0L);
+                }
+            });
+
+            //批量插入
+            if (!insertList.isEmpty()) {
+                batchDomainInsert(insertList, 1000);
+            }
+        }
+        return R.ok(null);
+    }
+
+    // 辅助方法:创建绑定对象
+    private CompanyDomainBind createBind(Long domainId, Company company, String userId) {
+        CompanyDomainBind bind = new CompanyDomainBind();
+        bind.setDomainId(domainId);
+        bind.setCompanyId(company.getCompanyId());
+        bind.setCreateBy(userId);
+        bind.setCreateTime(new Date());  // 补充创建时间
+        return bind;
+    }
+
+    // 分批插入方法
+    private void batchBindInsert(List<CompanyDomainBind> list, int batchSize) {
+        for (int i = 0; i < list.size(); i += batchSize) {
+            int end = Math.min(i + batchSize, list.size());
+            companyDomainBindMapper.batchInsertBindInfo(list.subList(i, end));
+        }
+    }
+
+    // 分批插入方法
+    private void batchDomainInsert(List<CompanyDomain> list, int batchSize) {
+        for (int i = 0; i < list.size(); i += batchSize) {
+            int end = Math.min(i + batchSize, list.size());
+            baseMapper.batchDomainInfo(list.subList(i, end));
+        }
+    }
+}

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

@@ -160,6 +160,7 @@ public class CompanyServiceImpl implements ICompanyService
             user.setSex("0");
             user.setStatus("0");
             user.setIsDel(0);
+            user.setIsAudit(1);
             userMapper.insertCompanyUser(user);
             //添加用户角色表
             CompanyUserRole userRole=new CompanyUserRole();

+ 3 - 3
fs-service/src/main/java/com/fs/company/service/impl/CompanyTagServiceImpl.java

@@ -118,12 +118,12 @@ public class CompanyTagServiceImpl implements ICompanyTagService
     }
 
     @Override
-    public Map<Long, String> queryAllTagMap() {
+    public Map<Long, CompanyTag> queryAllTagMap() {
         return companyTagMapper.queryAllTagMap();
     }
 
     @Override
-    public String findUserTagByUserId(Long key) {
-        return companyTagMapper.findUserTagByUserId(key);
+    public String findUserTagByUserId(Long key,Long companyUserId) {
+        return companyTagMapper.findUserTagByUserId(key,companyUserId);
     }
 }

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

@@ -118,7 +118,7 @@ public class CompanyTagUserServiceImpl implements ICompanyTagUserService
             }
         }
         //获取所有销售
-        List<CompanyUser> companyUsers = companyUserMapper.selectAllCompanyUserAndSelf(param != null ? param.getUserId() : null);
+        List<CompanyUser> companyUsers = companyUserMapper.selectAllCompanyUserAndSelf(param != null ? param.getUserId() : null,null);
         List<Long> userIds = Collections.emptyList();
         if(companyUsers != null && !companyUsers.isEmpty()){
             userIds = companyUsers.stream().map(CompanyUser::getUserId).collect(Collectors.toList());

+ 16 - 3
fs-service/src/main/java/com/fs/company/service/impl/CompanyUserServiceImpl.java

@@ -452,17 +452,25 @@ public class CompanyUserServiceImpl implements ICompanyUserService
 
     @Override
     public List<CompanyUser> selectAllCompanyUserAndSelf(Long userId) {
-        return companyUserMapper.selectAllCompanyUserAndSelf(userId);
+        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(userId);
+        List<CompanyUser> list = new ArrayList<>();
+        if (companyUser.isAdmin()){
+            list = companyUserMapper.selectAllCompanyUserAndSelf(userId,companyUser.getCompanyId());
+        }else {
+            list =   companyUserMapper.selectAllCompanyUserAndSelf(userId,null);
+        }
+        return list;
     }
 
     /**
      * 查询销售列表
+     * @param companyId 公司ID
      * @param deptId 部门ID
      * @return list
      */
     @Override
-    public List<CompanyUser> getCompanyUserListByDeptId(Long deptId) {
-        return companyUserMapper.selectAllCompanyUserByDeptId(deptId);
+    public List<CompanyUser> getCompanyUserListByCompanyIdAndDeptId(Long companyId, Long deptId) {
+        return companyUserMapper.selectAllCompanyUserByCompanyIdAndDeptId(companyId, deptId);
     }
 
     @Override
@@ -512,4 +520,9 @@ public class CompanyUserServiceImpl implements ICompanyUserService
         }
         companyUserMapper.auditUsers(userIds);
     }
+
+    @Override
+    public CompanyUser selectCompanyUserByPhone(String phone) {
+        return companyUserMapper.selectCompanyUserByPhone(phone);
+    }
 }

+ 58 - 0
fs-service/src/main/java/com/fs/company/vo/CompanyDomainBindUserVo.java

@@ -0,0 +1,58 @@
+package com.fs.company.vo;
+
+import com.baidu.dev2.thirdparty.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 企业域名分配中间表对象 company_domain_bind_user
+ *
+ * @author fs
+ * @date 2025-06-19
+ */
+@Data
+public class CompanyDomainBindUserVo implements Serializable {
+
+    /**
+     * 中间表id
+     */
+    @Excel(name = "编号", sort = 0)
+    private Long id;
+
+    /**
+     * 企业销售id
+     */
+    private Long companyUserId;
+
+    /**
+     * 中间表id
+     */
+    private Long bindId;
+
+    /**
+     * 分配域名
+     **/
+    @Excel(name = "分配域名", sort = 1)
+    private String domain;
+
+    /**
+     * 分配人员
+     **/
+    @Excel(name = "分配人员", sort = 2)
+    private String userName;
+
+    /**
+     * 分配人员手机号
+     **/
+    @Excel(name = "分配人员手机号", sort = 3)
+    private String phonenumber;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @Excel(name = "绑定时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", sort = 4)
+    private Date createTime;
+}

+ 59 - 0
fs-service/src/main/java/com/fs/company/vo/CompanyDomainBindVo.java

@@ -0,0 +1,59 @@
+package com.fs.company.vo;
+
+import com.baidu.dev2.thirdparty.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 域名绑定销售公司对象 company_domain_bind
+ *
+ * @author fs
+ * @date 2025-06-17
+ */
+@Data
+public class CompanyDomainBindVo implements Serializable {
+
+    /**
+     * 域名绑定中间表
+     */
+    @Excel(name = "编码", sort = 0)
+    private Long id;
+
+    /**
+     * 销售公司ID
+     */
+    @Excel(name = "销售公司编码", sort = 1)
+    private Long companyId;
+
+    /**
+     * 绑定域名ID
+     */
+    @Excel(name = "绑定域名编码", sort = 3)
+    private Long domainId;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @Excel(name = "绑定时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", sort = 5)
+    private Date createTime;
+
+    /**
+     * 域名名称
+     **/
+    @Excel(name = "域名", sort = 4)
+    private String domain;
+
+    /**
+     * 公司
+     **/
+    @Excel(name = "公司", sort = 2)
+    private String companyName;
+
+    /**
+     * 分配数量
+     * **/
+    @Excel(name = "分配数量", sort = 4)
+    private int allocationNum;
+
+}

+ 26 - 0
fs-service/src/main/java/com/fs/company/vo/CompanyDomainExportTemplateVo.java

@@ -0,0 +1,26 @@
+package com.fs.company.vo;
+
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+import java.io.Serializable;
+
+/**
+ * 域名管路导入模板对象 CompanyDomainExportTemplateVo
+ *
+ * @author fs
+ * @date 2025-06-16
+ */
+@Data
+public class CompanyDomainExportTemplateVo implements Serializable {
+
+    /**
+     * 域名
+     */
+    @Excel(name = "域名", sort = 1,width = 30)
+    private String domain;
+    /**
+     * 备注
+     **/
+    @Excel(name = "备注", sort = 2,width = 50)
+    private String remark;
+}

+ 52 - 0
fs-service/src/main/java/com/fs/company/vo/CompanyDomainVo.java

@@ -0,0 +1,52 @@
+package com.fs.company.vo;
+
+import com.baidu.dev2.thirdparty.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 域名管路对象 company_domain
+ *
+ * @author fs
+ * @date 2025-06-16
+ */
+@Data
+public class CompanyDomainVo implements Serializable {
+
+    /**
+     * 域名id
+     */
+    @Excel(name = "编号", sort = 0)
+    private Long id;
+
+    /**
+     * 域名
+     */
+    @Excel(name = "域名", sort = 1)
+    private String domain;
+
+    /**
+     * 状态(0=停用、1正常)
+     */
+    @Excel(name = "状态", dictType = "sys_company_status", sort = 3)
+    private Long status;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", sort = 4)
+    private Date createTime;
+
+    /**
+     * 备注
+     **/
+    @Excel(name = "备注", sort = 5)
+    private String remark;
+
+    /**
+     * 绑定数量
+     **/
+    @Excel(name = "域名绑定企业数量", sort = 2)
+    private int bindNum;
+}

+ 8 - 9
fs-service/src/main/java/com/fs/core/config/WxMaConfiguration.java

@@ -47,10 +47,9 @@ public class WxMaConfiguration {
         WxMaConfig.Config config = JSON.parseObject(configValue, WxMaConfig.Config.class);
         WxMaConfig wx = new WxMaConfig();
         List<WxMaConfig.Config> c = new ArrayList<>();
-//        if (StringUtil.isNotEmpty(config.getAppid())){
-//            c.add(config);
-//        }
-        c.add(config);
+        if (StringUtil.isNotEmpty(config.getAppid())){
+            c.add(config);
+        }
         String appid = config.getAppid();
 //        SysConfig sysConfig2 = sysConfigMapper.selectConfigByConfigKey("store.config");
 //        if (sysConfig2!=null&&sysConfig2.getConfigValue()!=null&&sysConfig2.getConfigValue()!="") {
@@ -63,12 +62,12 @@ public class WxMaConfiguration {
         List<CourseMaConfig> courseMaConfigs = JSON.parseArray(sysConfig3.getConfigValue(), CourseMaConfig.class);
         if (courseMaConfigs!=null&& !courseMaConfigs.isEmpty()){
             for (CourseMaConfig courseMaConfig : courseMaConfigs) {
-                if (!appid.equals(courseMaConfig.getAppid())) {
-                    WxMaConfig.Config wxMaConfig = new WxMaConfig.Config();
-                    BeanUtils.copyProperties(courseMaConfig, wxMaConfig);
-                    c.add(wxMaConfig);
+                if (appid.equals(courseMaConfig.getAppid())) {
+                    continue;
                 }
-
+                WxMaConfig.Config wxMaConfig = new WxMaConfig.Config();
+                BeanUtils.copyProperties(courseMaConfig, wxMaConfig);
+                c.add(wxMaConfig);
             }
         }
         wx.setConfigs(c);

+ 6 - 0
fs-service/src/main/java/com/fs/course/domain/FsCourseLink.java

@@ -2,6 +2,7 @@ package com.fs.course.domain;
 
 import com.fs.common.annotation.Excel;
 import com.fs.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 /**
@@ -57,6 +58,11 @@ public class FsCourseLink extends BaseEntity
     private Integer isRoom;//是否发群
     private String chatId;//是否发群
 
+    private Long periodId;
+
+    @ApiModelProperty(value = "营期课程id")
+    private Long id;
+
 //    private String link_uuid;
 
 }

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

@@ -2,6 +2,7 @@ package com.fs.course.domain;
 
 import com.fs.common.annotation.Excel;
 import com.fs.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import java.io.Serializable;
@@ -36,4 +37,10 @@ public class FsCourseRealLink implements Serializable
     private Integer isRoom;
     private Long fsUserId;
 
+    private Long periodId;
+
+    @ApiModelProperty(value = "营期课程id")
+    private Long id;
+
+
 }

+ 3 - 2
fs-service/src/main/java/com/fs/course/mapper/FsCourseRedPacketLogMapper.java

@@ -103,9 +103,10 @@ public interface FsCourseRedPacketLogMapper
     List<FsCourseRedPacketLogListPVO> selectRedPacketLogListVO(@Param("maps") FsCourseRedPacketLogParam param);
 
     @Select({"<script> " +
-            "select l.*,v.title,u.nick_name as fsNickName,u.avatar as fsAvatar,u.phone,cu.nick_name company_user_name,c.company_name,qu.qw_user_name  from fs_course_red_packet_log l  \n" +
+            "select l.*,v.title,u.nick_name as fsNickName,u.avatar as fsAvatar,u.phone,cu.nick_name company_user_name,c.company_name,qu.qw_user_name,fuc.course_name,u.phone as phoneNumber   from fs_course_red_packet_log l  \n" +
             "left join fs_user_course_video v on v.video_id = l.video_id \n" +
             "left join fs_user u on u.user_id = l.user_id \n" +
+            "left join fs_user_course fuc on fuc.course_id = l.course_id \n" +
             "left join company_user cu on cu.user_id=l.company_user_id \n" +
             "left join company c on c.company_id=l.company_id \n" +
             "LEFT JOIN qw_user qu on qu.id= l.qw_user_id  " +
@@ -118,7 +119,7 @@ public interface FsCourseRedPacketLogMapper
             "<if test = ' maps.courseId !=null '> and l.course_id = #{maps.courseId} </if>" +
             "<if test = ' maps.videoId !=null '> and l.video_id = #{maps.videoId} </if>" +
             "<if test = ' maps.status !=null '> and l.status = #{maps.status} </if>" +
-            "<if test = ' maps.phone !=null '> and u.phone = #{maps.phone} </if>" +
+            "<if test = \"maps.phone !=null and maps.phone != '' \"> and u.phone = #{maps.phone} </if>" +
             "<if test = ' maps.qwUserId !=null '> and l.qw_user_id = #{maps.qwUserId} </if>" +
             "<if test=\"maps.sTime != null \">  and DATE(l.create_time) &gt;= DATE(#{maps.sTime})</if>\n" +
             "<if test=\"maps.eTime != null \">  and DATE(l.create_time) &lt;= DATE(#{maps.eTime})</if>\n" +

+ 1 - 0
fs-service/src/main/java/com/fs/course/param/FsCourseLinkMiniParam.java

@@ -15,6 +15,7 @@ public class FsCourseLinkMiniParam {
 
     private String title;//视频标题
 
+    private Integer type;
     /**
     * 客户表的主键
     */

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

@@ -35,6 +35,8 @@ public class FsCourseWatchLogListParam implements Serializable {
 
     private String sopDate;
 
+    private Integer sendType;
+
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date eTime;
 

+ 2 - 2
fs-service/src/main/java/com/fs/course/service/impl/FsCourseLinkServiceImpl.java

@@ -533,14 +533,14 @@ public class FsCourseLinkServiceImpl implements IFsCourseLinkService
                         return R.error("真实链接不存在").put("realLink", sLink);
                     }
                     log.info("链接仍然有效: {}", sLink);
-                    String json = configService.selectConfigByKey("h5.course.config");
+                    String json = configService.selectConfigByKey("course.config");
                     CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
                     String domainName = companyUserMapper.selectDomainByUserId(courseLink.getCompanyUserId());
                     if (StringUtils.isEmpty(domainName)){
                         domainName = config.getRealLinkDomainName();
                     }
                     String realLink = domainName+courseLink.getRealLink();
-                    String imgUrl = "";
+                    String imgUrl = cloudHostProper.getHeaderImg();
                     return R.ok().put("realLink",realLink ).put("config",config).put("headerImg",imgUrl);
                 }
             } else {

+ 25 - 8
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseServiceImpl.java

@@ -650,20 +650,37 @@ public class FsUserCourseServiceImpl implements IFsUserCourseService
         }
         return domainName;
     }
+
     public static String generateRandomString() {
         return FsCourseLinkServiceImpl.generateRandomString();
     }
+
     private static Calendar getExpireDay(FsCourseLinkCreateParam param, CourseConfig config, Date createTime) {
-        Integer expireDuration;
-        if (param.getEffectiveDuration() == null || param.getEffectiveDuration() == 0){
-            expireDuration = config.getVideoLinkExpireDate();
-        }else {
-            expireDuration = param.getEffectiveDuration();
+        if (param == null || config == null || createTime == null) {
+            throw new IllegalArgumentException("Parameters cannot be null");
         }
-        // 设置过期时间
+
         Calendar calendar = Calendar.getInstance();
-        calendar.setTime(createTime);
-        calendar.add(Calendar.MINUTE, expireDuration);
+
+        if (param.getEffectiveDuration() == null || param.getEffectiveDuration() == 0) {
+            // 未传时间分钟的走配置,当天24:00(次日0:00)过期
+            Integer expireDays = config.getVideoLinkExpireDate() != null ? config.getVideoLinkExpireDate() : 1; // 默认1天
+
+            Date baseDate = param.getSendTime() != null ? param.getSendTime() : createTime;
+            calendar.setTime(baseDate);
+            calendar.add(Calendar.DAY_OF_MONTH, expireDays);
+
+            // 设置为次日0:00(即当天的24:00)
+            calendar.set(Calendar.HOUR_OF_DAY, 0);
+            calendar.set(Calendar.MINUTE, 0);
+            calendar.set(Calendar.SECOND, 0);
+            calendar.set(Calendar.MILLISECOND, 0);
+        } else {
+            // 传入时间分钟的
+            calendar.setTime(createTime);
+            calendar.add(Calendar.MINUTE, param.getEffectiveDuration());
+        }
+
         return calendar;
     }
     /**

+ 49 - 16
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -935,6 +935,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         packetParam.setOpenId(user.getMpOpenId());
         // 来源是小程序切换openId
         if (param.getSource() == 2) {
+            System.out.println("小程序id"+user.getCourseMaOpenId());
             packetParam.setOpenId(user.getCourseMaOpenId());
         }
         packetParam.setAmount(amount);
@@ -944,17 +945,45 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
         System.out.println("红包商户号"+amount);
         System.out.println("红包商户号"+packetParam);
-        // 发送红包
-        R sendRedPacket = paymentService.sendRedPacket(packetParam);
-        if (sendRedPacket.get("code").equals(200)) {
-            FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
-            TransferBillsResult transferBillsResult;
-            if (sendRedPacket.get("isNew").equals(1)){
-                transferBillsResult = (TransferBillsResult)sendRedPacket.get("data");
-                redPacketLog.setOutBatchNo(transferBillsResult.getOutBillNo());
-            }else {
-                redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
+        //2025.6.19 红包金额为0的时候
+        if (amount.compareTo(BigDecimal.ZERO)>0){
+            // 发送红包
+            R sendRedPacket = paymentService.sendRedPacket(packetParam);
+            if (sendRedPacket.get("code").equals(200)) {
+                FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
+                TransferBillsResult transferBillsResult;
+                if (sendRedPacket.get("isNew").equals(1)){
+                    transferBillsResult = (TransferBillsResult)sendRedPacket.get("data");
+                    redPacketLog.setOutBatchNo(transferBillsResult.getOutBillNo());
+                }else {
+                    redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
+                }
+                // 添加红包记录
+                redPacketLog.setCourseId(param.getCourseId());
+//            redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
+                redPacketLog.setCompanyId(param.getCompanyId());
+                redPacketLog.setUserId(param.getUserId());
+                redPacketLog.setVideoId(param.getVideoId());
+                redPacketLog.setStatus(0);
+                redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
+                redPacketLog.setCompanyUserId(param.getCompanyUserId());
+                redPacketLog.setCreateTime(new Date());
+                redPacketLog.setAmount(amount);
+                redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
+                redPacketLog.setPeriodId(param.getPeriodId());
+                redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
+
+                // 更新观看记录的奖励类型
+//            if (param.getLinkType() == null || param.getLinkType() == 0) {
+                log.setRewardType(config.getRewardType());
+                courseWatchLogMapper.updateFsCourseWatchLog(log);
+//            }
+                return sendRedPacket;
+            } else {
+                return R.error("奖励发送失败,请联系客服");
             }
+        } else {
+            FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
             // 添加红包记录
             redPacketLog.setCourseId(param.getCourseId());
 //            redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
@@ -965,7 +994,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
             redPacketLog.setCompanyUserId(param.getCompanyUserId());
             redPacketLog.setCreateTime(new Date());
-            redPacketLog.setAmount(amount);
+            redPacketLog.setAmount(BigDecimal.ZERO);
             redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
             redPacketLog.setPeriodId(param.getPeriodId());
             redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
@@ -975,10 +1004,9 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             log.setRewardType(config.getRewardType());
             courseWatchLogMapper.updateFsCourseWatchLog(log);
 //            }
-            return sendRedPacket;
-        } else {
-            return R.error("奖励发送失败,请联系客服");
+            return R.ok("红包发送成功");
         }
+
     }
 
     /**
@@ -1161,8 +1189,8 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
         // 如果开启了黑名单审核,需要提示
         if(fsUser.getStatus() == 0) {
-//            return ResponseResult.fail(505, "管理开启了会员审核,请等待审核");
-            return ResponseResult.fail(BizResponseEnum.WAIT_APPROVAL,getCompanyUserQRCode(companyUser));
+            return ResponseResult.fail(505, "请微信联系您的群主~");
+//            return ResponseResult.fail(BizResponseEnum.WAIT_APPROVAL,getCompanyUserQRCode(companyUser));
         }
 
         //查询看课记录
@@ -1196,6 +1224,11 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             fsCourseWatchLog.setLogType(1);
             fsCourseWatchLog.setProject(courseProject);
             courseWatchLogMapper.insertFsCourseWatchLog(fsCourseWatchLog);
+
+            String redisKey = "h5wxuser:watch:heartbeat:" + param.getUserId() + ":" + param.getVideoId() + ":" + param.getCompanyUserId();
+            redisCache.setCacheObject(redisKey, LocalDateTime.now().toString());
+            // 设置 Redis 记录的过期时间(例如 5 分钟)
+            redisCache.expire(redisKey, 300, TimeUnit.SECONDS);
         }
 
         // 添加会员销售关系表数据

+ 1 - 0
fs-service/src/main/java/com/fs/his/mapper/FsDoctorMapper.java

@@ -166,6 +166,7 @@ public interface FsDoctorMapper
             " order by d.sort desc "+
             "</script>"})
     List<FsDoctorListUVO> selectFsDoctorListUVO(@Param("maps") FsDoctorListUParam param);
+
     @Select("select * from fs_doctor where account=#{account}")
     FsDoctor selectFsDoctorByAccount(String account);
     @Select("select * from fs_doctor where user_id=#{userId}")

+ 2 - 0
fs-service/src/main/java/com/fs/his/mapper/FsPackageMapper.java

@@ -139,4 +139,6 @@ public interface FsPackageMapper
             "</foreach>"+
             "</script>"})
     int updatePackagesStatus(@Param("packageIds")Long[] packageIds,@Param("status")Long status);
+
+    List<String> selectIcdNameByPackageId(@Param("packageId")Long packageId);
 }

+ 4 - 0
fs-service/src/main/java/com/fs/his/mapper/FsUserDoctorMapper.java

@@ -3,6 +3,7 @@ package com.fs.his.mapper;
 import java.util.List;
 
 import com.fs.common.core.domain.R;
+import com.fs.his.domain.FsDoctor;
 import com.fs.his.domain.FsUserDoctor;
 import com.fs.his.param.FsUserDoctorListUParam;
 import com.fs.his.vo.FsUserDoctorListUVO;
@@ -85,4 +86,7 @@ public interface FsUserDoctorMapper
     int checkFollow(@Param("doctorId") Long doctorId,@Param("userId")long userId);
     @Delete("delete from fs_user_doctor  where type=1 and doctor_id=#{doctorId} and user_id=#{userId} ")
     int deleteFollow(@Param("doctorId") Long doctorId,@Param("userId")long userId);
+
+    @Select("select doctor_name as doctorName,avatar as avatar from fs_doctor where is_agreement_prescribe_doctor = 1 ORDER BY RAND() LIMIT 1")
+    FsDoctor getAgreement();
 }

+ 3 - 1
fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java

@@ -76,7 +76,9 @@ public interface FsUserMapper
      */
     public int deleteFsUserByUserIds(Long[] userIds);
     @Select({"<script> " +
-                "select f1.*,f2.nick_name tui_name,f2.phone tui_phone FROM fs_user f1 LEFT JOIN fs_user f2 ON f1.tui_user_id =f2.user_id "+
+                "select f1.*,f2.nick_name tui_name,f2.phone tui_phone,cu.nick_name AS companyUserNickName,co.company_name FROM fs_user f1 LEFT JOIN fs_user f2 ON f1.tui_user_id =f2.user_id "+
+            " LEFT JOIN company_user cu ON cu.user_id = f1.company_user_id"+
+            " LEFT JOIN company co on co.company_id = f1.company_id"+
             " where f1.is_del=0 "+
             "  <if test=\"nickName != null  and nickName != ''\"> and f1.nick_name like concat( #{nickName}, '%')</if>\n" +
             "            <if test=\"avatar != null  and avatar != ''\"> and f1.avatar = #{avatar}</if>\n" +

+ 7 - 0
fs-service/src/main/java/com/fs/his/service/IFsPackageService.java

@@ -79,4 +79,11 @@ public interface IFsPackageService
     int updatePackagesStatus(Long[] packageIds, Long status);
 
     String convertImageToJpg(String imgUrl, Long packageId);
+
+    /**
+     * 根据套餐id查询icd名字
+     * @param packageId
+     * @return icdName
+     */
+    List<String> selectIcdNameByPackageId(Long packageId);
 }

+ 3 - 0
fs-service/src/main/java/com/fs/his/service/IFsUserDoctorService.java

@@ -3,6 +3,7 @@ package com.fs.his.service;
 import java.util.List;
 
 import com.fs.common.core.domain.R;
+import com.fs.his.domain.FsDoctor;
 import com.fs.his.domain.FsUserDoctor;
 import com.fs.his.param.FsUserDoctorListUParam;
 import com.fs.his.vo.FsUserDoctorListUVO;
@@ -69,4 +70,6 @@ public interface IFsUserDoctorService
     R checkFollow(Long doctorId, long userId);
 
     int deleteFollow(Long doctorId, long userId);
+
+    FsDoctor getAgreement();
 }

+ 6 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsPackageServiceImpl.java

@@ -5,6 +5,7 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.math.BigDecimal;
 import java.net.URL;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
@@ -293,5 +294,10 @@ public class FsPackageServiceImpl implements IFsPackageService {
         }
         return null;
     }
+
+    @Override
+    public List<String> selectIcdNameByPackageId(Long packageId) {
+        return fsPackageMapper.selectIcdNameByPackageId(packageId);
+    }
 }
 

+ 6 - 1
fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java

@@ -533,7 +533,12 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
         TransferService transferService = wxPayService.getTransferService();
 
         TransferBatchesRequest request = new TransferBatchesRequest();
-        request.setAppid(config.getAppId());
+        if (param.getSource() == 2){
+            request.setAppid(config.getMiniappId());
+        }else {
+            request.setAppid(config.getAppId());
+        }
+
         String code = IdUtil.getSnowflake(0, 0).nextIdStr();
         request.setOutBatchNo("fsCourse" + code);
         request.setBatchRemark("课堂答题奖励");

+ 6 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsUserDoctorServiceImpl.java

@@ -3,6 +3,7 @@ package com.fs.his.service.impl;
 import java.util.List;
 
 import com.fs.common.core.domain.R;
+import com.fs.his.domain.FsDoctor;
 import com.fs.his.param.FsUserDoctorListUParam;
 import com.fs.his.vo.FsUserDoctorListUVO;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -109,4 +110,9 @@ public class FsUserDoctorServiceImpl implements IFsUserDoctorService
     public int deleteFollow(Long doctorId, long userId) {
         return fsUserDoctorMapper.deleteFollow(doctorId,userId);
     }
+
+    @Override
+    public FsDoctor getAgreement() {
+        return fsUserDoctorMapper.getAgreement();
+    }
 }

+ 69 - 24
fs-service/src/main/java/com/fs/his/service/impl/FsUserServiceImpl.java

@@ -17,17 +17,13 @@ import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.ResponseResult;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.DictUtils;
+import com.fs.common.utils.ParseUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.company.cache.ICompanyTagCacheService;
 import com.fs.company.cache.ICompanyUserCacheService;
-import com.fs.company.domain.Company;
-import com.fs.company.domain.CompanyTag;
-import com.fs.company.domain.CompanyTagUser;
-import com.fs.company.domain.CompanyUser;
-import com.fs.company.mapper.CompanyMapper;
-import com.fs.company.mapper.CompanyTagMapper;
-import com.fs.company.mapper.CompanyTagUserMapper;
-import com.fs.company.mapper.CompanyUserMapper;
+import com.fs.company.domain.*;
+import com.fs.company.mapper.*;
 import com.fs.company.service.ICompanyTagService;
 import com.fs.course.domain.FsUserCompanyUser;
 import com.fs.course.mapper.FsUserCompanyUserMapper;
@@ -59,6 +55,7 @@ import com.fs.store.vo.h5.*;
 import com.fs.system.service.ISysConfigService;
 import com.fs.watch.domain.WatchUser;
 import com.fs.watch.service.WatchUserService;
+import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.http.util.Asserts;
@@ -124,6 +121,9 @@ public class FsUserServiceImpl implements IFsUserService
     @Autowired
     private IQwExternalContactCacheService qwExternalContactCacheService;
 
+    @Autowired
+    private CompanyRoleMapper companyRoleMapper;
+
 
     /**
      * 查询用户
@@ -509,8 +509,33 @@ public class FsUserServiceImpl implements IFsUserService
 
     @Override
     public PageInfo<FsUserPageListVO> selectFsUserPageList(FsUserPageListParam param) {
-        List<FsUserPageListVO> fsUserPageListVOS = fsUserMapper.selectFsUserPageList(param);
 
+
+//        List<CompanyRole> companyRoles = companyRoleMapper.selectRolePermissionByUserId(param.getUserId());
+//        List<CompanyUser> companyUsers;
+//        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(param.getUserId());
+//        // 判断是否管理员 或者包含 1:全部数据权限
+//        if (companyUser.isAdmin() || companyRoles.stream().anyMatch(r -> "1".equals(r.getDataScope()))) {
+//            companyUsers = companyUserService.getCompanyUserListByCompanyIdAndDeptId(companyUser.getCompanyId(), null);
+//        }
+//        // 判断是否包含 3:本部门数据权限 4:本部门及以下数据权限
+//        else if (companyRoles.stream().anyMatch(r -> "3".equals(r.getDataScope()) || "4".equals(r.getDataScope()))) {
+//            companyUsers = companyUserService.getCompanyUserListByCompanyIdAndDeptId(companyUser.getCompanyId(), companyUser.getDeptId());
+//        }
+//        // 默认空 -- 判断是否包含 5:仅可查看本人
+//        else {
+//            companyUsers = new ArrayList<>();
+//        }
+
+        if (param.getUserId() != null) {
+            CompanyUser companyUser = companyUserMapper.selectCompanyUserById(param.getUserId());
+                if (companyUser.isAdmin()){
+                    param.setUserId(0L);
+                    param.setCompanyId(companyUser.getCompanyId());
+                }
+        }
+
+        List<FsUserPageListVO> fsUserPageListVOS = fsUserMapper.selectFsUserPageList(param);
         // 获取当前销售所有重粉会员
         List<FsUserCompanyUser> fsUserCompanyUsers = fsUserCompanyUserMapper.selectRepeatUser(param.getUserId());
 
@@ -534,6 +559,8 @@ public class FsUserServiceImpl implements IFsUserService
         } else {
             return new PageInfo<>(fsUserPageListVOS);
         }
+
+
     }
 
     private static StringBuilder removeRepeatFansTag(FsUserPageListVO fsUserPageListVO) {
@@ -587,6 +614,7 @@ public class FsUserServiceImpl implements IFsUserService
         }
 
         List<FsUserPageListVO> fsUserPageListVOS = fsUserMapper.selectFsUserPageListNew(param);
+        Map<Long, CompanyTag> tagMap = companyTagCacheService.queryAllTagMap();
         for (FsUserPageListVO item : fsUserPageListVOS) {
             if(item.getCompanyUserId() != null) {
                 String companyUserName = companyUserCacheService.selectCompanyUserNameUserById(item.getCompanyUserId());
@@ -594,6 +622,15 @@ public class FsUserServiceImpl implements IFsUserService
                     item.setCompanyUserNickName(companyUserName);
                 }
             }
+            if(item.getPhone() != null) {
+                item.setPhone(ParseUtils.parsePhone(item.getPhone()));
+            }
+            if(item.getStatus() != null) {
+                String userStatus = DictUtils.getDictLabel("user_status", String.valueOf(item.getStatus()));
+                if(StringUtils.isNotBlank(userStatus)){
+                    item.setStatusText(userStatus);
+                }
+            }
             if(item.getUserId() != null) {
                 FsUserCourseCount byUserId = fsUserCourseCountCacheService.findByUserId(item.getUserId());
                 if(byUserId != null) {
@@ -607,17 +644,18 @@ public class FsUserServiceImpl implements IFsUserService
                     item.setStopWatchDays(byUserId.getStopWatchDays());
                     item.setCompleteWatchDate(byUserId.getCompleteWatchDate());
                 }
-
-                String userTagByUserId = companyTagCacheService.findUserTagByUserId(item.getUserId());
+                String userTagByUserId = companyTagCacheService
+                        .findUserTagByUserId(item.getUserId(),item.getCompanyUserId());
                 if(StringUtils.isNotEmpty(userTagByUserId)) {
                     String[] split = userTagByUserId.split(",");
-                    Map<Long, String> tagMap = companyTagCacheService.queryAllTagMap();
                     Set<String> tagNames = new HashSet<>();
                     for (String tag : split) {
-                        if(tag != null) {
+                        if(StringUtils.isNotBlank(tag)) {
                             Long tagL = Long.parseLong(tag);
-                            String tagName = tagMap.get(tagL);
-                            tagNames.add(tagName);
+                            CompanyTag companyTag = tagMap.get(tagL);
+                            if(companyTag != null) {
+                                tagNames.add(companyTag.getTag());
+                            }
                         }
                     }
                     item.setTagIds(userTagByUserId);
@@ -625,10 +663,10 @@ public class FsUserServiceImpl implements IFsUserService
                 }
 
                 // 是否宠粉
-                Integer isRepeat = qwExternalContactCacheService.selectQwIsRepeat(item.getUserId());
-                if(isRepeat != null) {
-                    item.setIsRepeat(isRepeat);
-                }
+//                Integer isRepeat = qwExternalContactCacheService.selectQwIsRepeat(item.getUserId());
+//                if(isRepeat != null) {
+//                    item.setIsRepeat(isRepeat);
+//                }
             }
         }
 
@@ -689,6 +727,8 @@ public class FsUserServiceImpl implements IFsUserService
         if (countRedPacket != null) {
             vo.setAnswerRedPacketTime(countRedPacket.getAnswerRedPacketTime());
             vo.setAnswerRedPacketAmount(countRedPacket.getAnswerRedPacketAmount());
+        } else {
+            vo.setAnswerRedPacketAmount(BigDecimal.ZERO);
         }
         if (countAnswer != null) {
             vo.setAnswerTime(countAnswer.getAnswerTime());
@@ -840,13 +880,18 @@ public class FsUserServiceImpl implements IFsUserService
             return ResponseResult.fail(404,"当前用户信息不存在");
         }
 
+        // 逻辑调整:如果会员已经绑定了销售,直接提示,不添加重粉数据了-2025年6月16日14点53分
+        if (fsUser.getCompanyUserId() != null && !param.getCompanyUserId().equals(fsUser.getCompanyUserId())){
+            return ResponseResult.fail(406,"该用户已成为其他销售会员");
+        }
+
         //判断该销售是否存在
         CompanyUser companyUser = companyUserMapper.selectCompanyUserById(param.getCompanyUserId());
         if (Objects.isNull(companyUser)){
             return ResponseResult.fail(405,"销售不存在");
         }
 
-        // 判断是否绑定了销售
+        // 添加关系表数据
         FsUserCompanyUser fsUserCompanyUser = getFsUserCompanyUser(param, fsUser);
         QueryWrapper<FsUserCompanyUser> queryWrapper = new QueryWrapper<FsUserCompanyUser>().eq("user_id", param.getUserId()).eq("company_user_id", param.getCompanyUserId());
         Integer i = fsUserCompanyUserMapper.selectCount(queryWrapper);
@@ -887,10 +932,10 @@ public class FsUserServiceImpl implements IFsUserService
             companyTagUserMapper.insertCompanyTagUser(companyTagUser);
         }
 
-        // 如果是重粉,直接打上重粉的标签
-        if(1 == fsUserCompanyUser.getIsRepeatFans()){
-            this.setRepeatFansTag(param);
-        }
+//        // 如果是重粉,直接打上重粉的标签
+//        if(1 == fsUserCompanyUser.getIsRepeatFans()){
+//            this.setRepeatFansTag(param);
+//        }
 
         //如果是设置了需要进入小黑屋,则需要返回提示,否则正常返回
         if(isDefaultBlack == 1){

+ 10 - 0
fs-service/src/main/java/com/fs/his/vo/FsUserVO.java

@@ -2,6 +2,7 @@ package com.fs.his.vo;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fs.common.annotation.Excel;
+import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import javax.crypto.Cipher;
@@ -99,6 +100,15 @@ public class FsUserVO implements Serializable {
 
     private String source;//app来源
 
+
+    @ApiModelProperty(value = "销售名称")
+    @Excel(name = "所属销售", sort = 10)
+    private String companyUserNickName;
+
+    @ApiModelProperty(value = "所属公司")
+    @Excel(name = "所属公司", sort = 9)
+    private String companyName;
+
     public void setPhone(String phone)
     {
        this.phone = phone;

+ 3 - 0
fs-service/src/main/java/com/fs/qw/mapper/CustomerTransferApprovalMapper.java

@@ -59,4 +59,7 @@ public interface CustomerTransferApprovalMapper
      * @return 结果
      */
     public int deleteCustomerTransferApprovalByIds(Long[] ids);
+
+
+    List<CustomerTransferApproval> queryPendingData();
 }

+ 5 - 0
fs-service/src/main/java/com/fs/qw/service/ICustomerTransferApprovalService.java

@@ -59,4 +59,9 @@ public interface ICustomerTransferApprovalService
      * @return 结果
      */
     public int deleteCustomerTransferApprovalById(Long id);
+
+    /**
+     * 自动审批通过
+     */
+    public void autoApprovePass();
 }

+ 13 - 0
fs-service/src/main/java/com/fs/qw/service/impl/CustomerTransferApprovalServiceImpl.java

@@ -18,6 +18,7 @@ import com.fs.qw.vo.TransferCustomDTO;
 import com.fs.store.service.cache.IFsUserCacheService;
 import com.hc.openapi.tool.util.StringUtils;
 import org.apache.http.util.Asserts;
+import org.springframework.aop.framework.AopContext;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.EnableAspectJAutoProxy;
 import org.springframework.stereotype.Service;
@@ -263,4 +264,16 @@ public class CustomerTransferApprovalServiceImpl implements ICustomerTransferApp
     {
         return customerTransferApprovalMapper.deleteCustomerTransferApprovalById(id);
     }
+
+    @Override
+    public void autoApprovePass() {
+        List<CustomerTransferApproval> customerTransferApprovals = customerTransferApprovalMapper.queryPendingData();
+        for (CustomerTransferApproval approval : customerTransferApprovals) {
+            approval.setApprovalStatus(1);
+            approval.setApprovalRemark("自动审批");
+            approval.setApproverUserId(1L);
+            ICustomerTransferApprovalService service = (ICustomerTransferApprovalService) AopContext.currentProxy();
+            service.updateCustomerTransferApproval(approval);
+        }
+    }
 }

+ 43 - 39
fs-service/src/main/java/com/fs/qw/service/impl/QwExternalContactServiceImpl.java

@@ -169,6 +169,9 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
     @Autowired
     private SopUserLogsInfoMapper sopUserLogsInfoMapper;
 
+    @Autowired
+    private IQwCompanyService iQwCompanyService;
+
     @Autowired
     private ISopUserLogsService sopUserLogsService;
 
@@ -3114,9 +3117,7 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
             return attachments;
         }
 
-        String json = configService.selectConfigByKey("course.config");
-        CourseConfig config = JSON.parseObject(json, CourseConfig.class);
-
+        QwCompany qwCompany = iQwCompanyService.getQwCompanyByRedis(corpId);
 
         attachments.forEach(att -> {
             // 生成短链的条件判断
@@ -3161,51 +3162,54 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
 
                 try {
 
-                    String mediaId = (String) redisCache.getCacheObject("miniprogram:" + corpId + ":" + att.getMiniprogram().getCourseId());
-                    if (!StringUtil.strIsNullOrEmpty(mediaId)) {
-
-                        FsCourseLinkCreateParam param = new FsCourseLinkCreateParam();
-                        param.setVideoId(Long.valueOf(att.getMiniprogram().getVideoId()));
-                        param.setQwUserId(qwUser.getId());
-                        param.setDays(att.getMiniprogram().getExpiresDays());
-                        param.setCorpId(corpId);
-                        param.setCourseId(Long.valueOf(att.getMiniprogram().getCourseId()));
-                        param.setCompanyUserId(qwUser.getCompanyUserId());
-                        param.setCompanyId(qwUser.getCompanyId());
-                        param.setQwExternalId(qwExternalId);
-                        param.setSendTime(new Date());
+                    //小程序
+                    if("miniprogram".equals(att.getMsgtype())
+                            && !StringUtil.strIsNullOrEmpty(att.getMiniprogram().getCourseId())
+                            && !StringUtil.strIsNullOrEmpty(att.getMiniprogram().getVideoId())){
 
-                        String linkUrl = iFsCourseLinkService.createLinkUrlWcmini(param);
+                        try {
 
-                        if (!StringUtil.strIsNullOrEmpty(linkUrl)) {
-                            att.getMiniprogram().setPage(linkUrl);
-                        }
+                            String mediaId =(String)redisCache.getCacheObject("miniprogram:"+corpId+":"+att.getMiniprogram().getCourseId());
+                            if (!StringUtil.strIsNullOrEmpty(mediaId)){
 
-                        if (config!=null){
+                                FsCourseLinkCreateParam param = new FsCourseLinkCreateParam();
+                                param.setVideoId(Long.valueOf(att.getMiniprogram().getVideoId()));
+                                param.setQwUserId(qwUser.getId());
+                                param.setDays(att.getMiniprogram().getExpiresDays());
+                                param.setCorpId(corpId);
+                                param.setCourseId(Long.valueOf(att.getMiniprogram().getCourseId()));
+                                param.setCompanyUserId(qwUser.getCompanyUserId());
+                                param.setCompanyId(qwUser.getCompanyId());
+                                param.setQwExternalId(qwExternalId);
+                                param.setSendTime(new Date());
 
-                            if (StringUtil.strIsNullOrEmpty(config.getMiniprogramAppid())) {
-                                logger.error("配置中无小程序id,采用默认的");
-                                att.getMiniprogram().setAppid("wxc84c6f789ba7f176");
-                            } else {
+                                String linkUrl = iFsCourseLinkService.createLinkUrlWcmini(param);
 
-                                att.getMiniprogram().setAppid(config.getMiniprogramAppid());
+                                if (!StringUtil.strIsNullOrEmpty(linkUrl)) {
+                                    att.getMiniprogram().setPage(linkUrl);
+                                }
+                                if (!StringUtil.strIsNullOrEmpty(qwCompany.getMiniAppId())){
+                                    att.getMiniprogram().setAppid(qwCompany.getMiniAppId());
+                                }else {
+                                    logger.error("欢迎语:企业未配置小程序id:采用默认appid"+corpId);
+                                }
+                                att.getMiniprogram().setPic_media_id(mediaId);
+
+                                //生成观看记录
+                                addWatchLogIfNeeded(Integer.valueOf(att.getMiniprogram().getVideoId()),
+                                        Integer.valueOf(att.getMiniprogram().getCourseId()),
+                                        String.valueOf(qwUser.getId()),
+                                        String.valueOf(qwUser.getCompanyUserId()),
+                                        String.valueOf(qwUser.getCompanyId()),
+                                        String.valueOf(qwExternalId));
+                            }else {
+                                logger.error("查到课程相关信息:"+corpId+":"+att.getMiniprogram().getCourseId());
                             }
 
+                        }  catch (Exception e) {
+                            logger.error("欢迎语生成小程序消息失败:"+e.getMessage()+"|"+corpId+"|"+att.getMiniprogram().getCourseId());
                         }
-
-                        att.getMiniprogram().setPic_media_id(mediaId);
-
-                        //生成观看记录
-                        addWatchLogIfNeeded(Integer.valueOf(att.getMiniprogram().getVideoId()),
-                                Integer.valueOf(att.getMiniprogram().getCourseId()),
-                                String.valueOf(qwUser.getId()),
-                                String.valueOf(qwUser.getCompanyUserId()),
-                                String.valueOf(qwUser.getCompanyId()),
-                                String.valueOf(qwExternalId));
-                    }else {
-                        logger.error("查到课程相关信息:"+corpId+":"+att.getMiniprogram().getCourseId());
                     }
-
                 }  catch (Exception e) {
                     logger.error("欢迎语生成小程序消息失败:"+e.getMessage()+"|"+corpId+"|"+att.getMiniprogram().getCourseId());
                 }

+ 4 - 1
fs-service/src/main/java/com/fs/sop/mapper/QwSopLogsMapper.java

@@ -197,7 +197,10 @@ public interface QwSopLogsMapper extends BaseMapper<QwSopLogs> {
 
 
     @DataSource(DataSourceType.SOP)
-    public List<QwSopLogs> selectSopLogsByCreateCorpMassSending(@Param("date") String date);
+    public List<QwSopLogs> createCorpMassSending(@Param("date") String date);
+
+    @DataSource(DataSourceType.SOP)
+    public List<QwSopLogs> selectSopLogsByCreateCorpMassSending(@Param("taskStartTime") String taskStartTime,@Param("taskEndTime") String taskEndTime);
 
     /**
     * 为了避免一直轮询无效(发送不了,给不了反馈的)数据,只查与定时的时间过后,之前3天内的的数据反馈

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

@@ -3,6 +3,8 @@ package com.fs.sop.params;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.Data;
 
+import java.util.List;
+
 @Data
 public class QwSopLogsParam {
     /**
@@ -16,6 +18,7 @@ public class QwSopLogsParam {
     private String qwUserName;
 
     private String qwUserid;
+    private List<String> qwUseridByList;
 
     /**
      * 客户昵称
@@ -51,4 +54,9 @@ public class QwSopLogsParam {
 
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private String sendTime;
+
+    /**
+     * 手机号
+     */
+    private String phone;
 }

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

@@ -95,7 +95,7 @@ public interface IQwSopLogsService
     /**
      *  创建企业群发(按照营期发)
      */
-    public void createCorpMassSendingByUserLogs(String date);
+    public void createCorpMassSendingByUserLogs(String taskStartTime,String taskEndTime);
 
     /**
      *  检索执行符合条件的定时任务的结果回调(企业微信)

+ 172 - 133
fs-service/src/main/java/com/fs/sop/service/impl/QwSopLogsServiceImpl.java

@@ -1,13 +1,17 @@
 package com.fs.sop.service.impl;
 
 
+import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSON;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.StringUtils;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.service.ICompanyUserService;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.FsCourseWatchLog;
 import com.fs.course.service.IFsCourseWatchLogService;
+import com.fs.course.service.IFsUserCompanyUserService;
 import com.fs.fastGpt.service.IFastGptChatSessionService;
 import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.domain.QwUser;
@@ -37,6 +41,7 @@ import com.fs.sop.vo.QwSopLogsDoSendListTVO;
 import com.fs.sop.vo.QwSopLogsListCVO;
 import com.fs.system.service.ISysConfigService;
 import com.fs.voice.utils.StringUtil;
+import org.apache.commons.collections.CollectionUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -99,6 +104,9 @@ public class QwSopLogsServiceImpl implements IQwSopLogsService
     @Autowired
     private IFastGptChatSessionService fastGptChatSessionService;
 
+    @Autowired
+    private ICompanyUserService companyUserService;
+
 
     /**
      * 查询企业微信SOP  定时任务
@@ -129,16 +137,42 @@ public class QwSopLogsServiceImpl implements IQwSopLogsService
      */
     @Override
     public List<QwSopLogsListCVO> selectQwSopLogsListBySopId(QwSopLogsParam param) {
+        if (param == null || param.getType() == null) {
+            return Collections.emptyList();
+        }
 
-        switch (param.getType()){
-            //个微
+        switch (param.getType()) {
+            // 个微
             case 1:
                 return qwSopLogsMapper.selectQwSopLogsListByGwSopId(param);
-            //企微
+            // 企微
             case 2:
-                return qwSopLogsMapper.selectQwSopLogsListByQwSopId(param);
+                return handleQwSopLogs(param);
+            default:
+                return Collections.emptyList();
+        }
+    }
+
+    private List<QwSopLogsListCVO> handleQwSopLogs(QwSopLogsParam param) {
+        if (StringUtils.isNotEmpty(param.getPhone())) {
+            try {
+                CompanyUser companyUser = companyUserService.selectCompanyUserByPhone(param.getPhone());
+                if (companyUser == null) {
+                    return Collections.emptyList();
+                }
+                QwUser qwUser = new QwUser();
+                qwUser.setCompanyUserId(companyUser.getUserId());
+                List<QwUser> qwUsers = qwUserMapper.selectQwUserList(qwUser);
+                if (CollectionUtils.isNotEmpty(qwUsers)){
+                    List<String> qwUserIds = qwUsers.stream().map(QwUser::getQwUserId).collect(Collectors.toList());
+                    param.setQwUseridByList(qwUserIds);
+                }
+            } catch (Exception e) {
+                logger.error("根据手机号查询企业用户出现异常,手机号: {}, 异常信息: {}", param.getPhone(), e.getMessage(), e);
+                return Collections.emptyList();
+            }
         }
-       return null;
+        return qwSopLogsMapper.selectQwSopLogsListByQwSopId(param);
     }
 
 
@@ -1292,173 +1326,178 @@ public class QwSopLogsServiceImpl implements IQwSopLogsService
      * 该方法负责处理企业微信的群发消息创建和发送
      */
     @Override
-    public void createCorpMassSending(String date) {
+    public void createCorpMassSending(String date)  {
+
         long startTime = System.currentTimeMillis();
         logger.info("开始执行企业微信群发消息创建任务");
 
-        String json = configService.selectConfigByKey("course.config");
-        CourseConfig config = JSON.parseObject(json, CourseConfig.class);
-
-        if (config == null) {
-            logger.error("课程默认配置为空,不执行");
-            return;
-        }
-        // 获取需要发送的SOP日志记录
-        List<QwSopLogs> qwSopLogs = qwSopLogsMapper.selectSopLogsByCreateCorpMassSending(date);
-//        List<QwSopLogs> qwSopLogs = qwSopLogsMapper.checkQwSopLogs();
+        List<QwSopLogs> qwSopLogs = qwSopLogsMapper.createCorpMassSending(date);
         if (qwSopLogs.isEmpty()) {
             logger.error("zyp \n【企微官方群发记录为空】");
             return;
         }
 
-        // 按照企业员工ID、发送时间、SOP ID和企业ID进行分组
         Map<String, List<QwSopLogs>> groupedLogs = new HashMap<>();
         for (QwSopLogs log : qwSopLogs) {
             String key = log.getQwUserid() + "|" + log.getSendTime() + "|" + log.getSopId() + "|" + log.getCorpId();
             groupedLogs.computeIfAbsent(key, k -> new ArrayList<>()).add(log);
         }
 
-        // 创建线程池,使用固定大小的线程池以避免过多线程导致的资源竞争
         int threadCount = Math.min(10, Runtime.getRuntime().availableProcessors() + 1);
         ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
-
-        // 创建用于发送消息的嵌套线程池
         ExecutorService messageExecutorService = Executors.newFixedThreadPool(20);
-
-        // 用于存储需要批量更新的日志记录,使用线程安全的集合
         List<QwSopLogs> updateList = Collections.synchronizedList(new ArrayList<>());
 
-        // 使用CountDownLatch等待所有任务完成
         CountDownLatch latch = new CountDownLatch(groupedLogs.size());
 
-        // 处理每个分组
-        for (Map.Entry<String, List<QwSopLogs>> entry : groupedLogs.entrySet()) {
-            String key = entry.getKey();
-            List<QwSopLogs> logs = entry.getValue();
-            String[] keys = key.split("\\|");
-            String qwUserid = keys[0];
-            String corpId = keys[3];
-
-//            QwUser qwUser = qwUserMapper.selectQwUserByCorpIdAndUserId(corpId, qwUserid);
-            // 查询员工信息的id
-            QwUser qwUser = qwExternalContactService.getQwUserByRedis(corpId.trim(),qwUserid.trim());
-            if (qwUser != null && qwUser.getIsDel() == 0) {
-                // 提交到线程池处理每个分组
-                executorService.submit(() -> {
-                    try {
-                        // 按外部用户ID分组
-                        Map<String, List<QwSopLogs>> userLogsMap = new HashMap<>();
-                        for (QwSopLogs log : logs) {
-                            String externalUserId = log.getExternalUserId();
-                            userLogsMap.computeIfAbsent(externalUserId, k -> new ArrayList<>()).add(log);
-                        }
-
-                        // 使用嵌套的CountDownLatch等待所有消息发送完成
-                        CountDownLatch messageLatch = new CountDownLatch(userLogsMap.size());
-
-                        // 处理每个外部用户
-                        for (Map.Entry<String, List<QwSopLogs>> userEntry : userLogsMap.entrySet()) {
-                            String externalUserId = userEntry.getKey();
-                            List<QwSopLogs> userLogs = userEntry.getValue();
+        try {
+            for (Map.Entry<String, List<QwSopLogs>> entry : groupedLogs.entrySet()) {
+                String key = entry.getKey();
+                List<QwSopLogs> logs = entry.getValue();
+                String[] keys = key.split("\\|");
+                String qwUserid = keys[0];
+                String corpId = keys[3];
+
+                QwUser qwUser = qwExternalContactService.getQwUserByRedis(corpId.trim(), qwUserid.trim());
+                if (qwUser != null && qwUser.getIsDel() == 0) {
+                    executorService.submit(() -> {
+                        try {
+                            Map<String, List<QwSopLogs>> userLogsMap = new HashMap<>();
+                            for (QwSopLogs log : logs) {
+                                userLogsMap.computeIfAbsent(log.getExternalUserId(), k -> new ArrayList<>()).add(log);
+                            }
 
-                            // 提交到消息发送线程池
-                            messageExecutorService.submit(() -> {
-                                try {
-                                    QwMsgTemplateSop templateSop = new QwMsgTemplateSop();
-                                    templateSop.setChatType("single");
-                                    templateSop.setAllowSelect(false);
-                                    templateSop.setSender(qwUserid);
-                                    templateSop.setExternalUseridList(Collections.singletonList(externalUserId));
-
-                                    List<QwMsgTemplateSop.Attachment> attachments = new ArrayList<>();
-                                    boolean hasError = false;
-
-                                    for (QwSopLogs log : userLogs) {
-                                        try {
-                                            QwSopTempSetting.Content content = JSON.parseObject(log.getContentJson(), QwSopTempSetting.Content.class);
-                                            if (content == null || content.getSetting() == null) continue;
-                                            Long courseId = content.getCourseId();
-                                            for (QwSopTempSetting.Content.Setting set : content.getSetting()) {
-                                                processContent(set, corpId, templateSop, attachments, courseId);
+                            CountDownLatch messageLatch = new CountDownLatch(userLogsMap.size());
+                            for (Map.Entry<String, List<QwSopLogs>> userEntry : userLogsMap.entrySet()) {
+                                String externalUserId = userEntry.getKey();
+                                List<QwSopLogs> userLogs = userEntry.getValue();
+
+                                messageExecutorService.submit(() -> {
+                                    try {
+                                        QwMsgTemplateSop templateSop = new QwMsgTemplateSop();
+                                        templateSop.setChatType("single");
+                                        templateSop.setAllowSelect(false);
+                                        templateSop.setSender(qwUserid);
+                                        templateSop.setExternalUseridList(Collections.singletonList(externalUserId));
+
+                                        List<QwMsgTemplateSop.Attachment> attachments = new ArrayList<>();
+                                        boolean hasError = false;
+                                        for (QwSopLogs log : userLogs) {
+                                            try {
+                                                QwSopTempSetting.Content content = JSON.parseObject(log.getContentJson(), QwSopTempSetting.Content.class);
+                                                if (content == null || content.getSetting() == null) continue;
+                                                Long courseId = content.getCourseId();
+                                                for (QwSopTempSetting.Content.Setting set : content.getSetting()) {
+                                                    processContent(set, corpId, templateSop, attachments, courseId);
+                                                }
+                                            } catch (Exception e) {
+                                                logger.error("消息内容解析失败,logId:{},{},{}", log.getId(), e,key);
+                                                hasError = true;
                                             }
-                                        } catch (Exception e) {
-                                            logger.error("消息内容解析失败,logId:{}", log.getId(), e);
-                                            hasError = true;
                                         }
-                                    }
+                                        if (!hasError && (!attachments.isEmpty() || templateSop.getTextContent() != null)) {
+                                            templateSop.setAttachments(attachments);
+                                            try {
+                                                QwAddMsgTemplateResult result = qwApiService.addMsgTemplateBySop(templateSop, corpId);
+                                                if (result.getErrCode() == 0 || result.getErrCode() == 41063){
+                                                    for (QwSopLogs log : userLogs) {
+                                                        log.setSendStatus(1L);
+                                                        log.setMsgId(result.getMsgId());
+                                                        updateList.add(log);
+                                                    }
+                                                }else {
+
+                                                    for (QwSopLogs log : userLogs) {
+                                                        log.setSendType(2);
+                                                        log.setSendStatus(3L);
+                                                        log.setRemark("官方有误,sop补发");
+                                                        log.setReceivingStatus(0L);
+                                                        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+                                                        LocalDateTime currentTime = LocalDateTime.now();
+                                                        String newTimeString = currentTime.format(formatter);
+                                                        log.setSendTime(newTimeString);
+                                                        log.setSort(30000001);
+                                                        updateList.add(log);
+                                                    }
 
-                                    if (!hasError && (!attachments.isEmpty() || templateSop.getTextContent() != null)) {
-                                        templateSop.setAttachments(attachments);
-                                        try {
-                                            QwAddMsgTemplateResult result = qwApiService.addMsgTemplateBySop(templateSop, corpId);
-                                            for (QwSopLogs log : userLogs) {
-                                                log.setSendStatus(result.getErrCode() == 0 || result.getErrCode() == 41063 ? 1L : 0L);
-                                                log.setMsgId(result.getMsgId());
-                                                updateList.add(log);
-                                            }
-                                            if (result.getErrCode() != 0 && result.getErrCode() != 41063){
-                                                logger.error("企业微信接口-消息发送失败,corpId:{},errCode:{},errMsg:{}", corpId, result.getErrCode(), result.getErrMsg());
-                                            }
-                                        } catch (Exception e) {
-                                            logger.error("消息发送失败,user:{}", externalUserId, e);
-                                            for (QwSopLogs log : userLogs) {
-                                                log.setSendStatus(0L);
-                                                updateList.add(log);
+                                                    logger.error("企业微信接口-消息发送失败-进入sop补偿,corpId:{},errCode:{},errMsg:{},key:{}", corpId, result.getErrCode(), result.getErrMsg(),key);
+                                                }
+                                            } catch (Exception e) {
+                                                logger.error("消息发送失败,user:{},{},{}", externalUserId, e,key);
+                                                for (QwSopLogs log : userLogs) {
+                                                    log.setSendStatus(0L);
+                                                    log.setRemark("信息异常");
+                                                    updateList.add(log);
+                                                }
                                             }
                                         }
+
+                                    } finally {
+                                        logger.info("执行结束-messageLatch-countDown:"+updateList.size());
+                                        messageLatch.countDown();
                                     }
-                                } finally {
-                                    messageLatch.countDown();
-                                }
-                            });
-                        }
+                                });
 
-                        // 等待所有消息发送完成
-                        try {
+                            }
+
+                            logger.info("messageExecutorService-updateList总量:"+updateList.size());
+
+                            // 等待所有消息发送完成
                             messageLatch.await();
+
                         } catch (InterruptedException e) {
-                            logger.error("等待消息发送完成时被中断", e);
+                            logger.info("messageExecutorService-Thread.currentThread().interrupt():"+updateList.size());
                             Thread.currentThread().interrupt();
+                        } finally {
+                            logger.info("finally-latch.countDown:"+updateList.size());
+                            latch.countDown();
                         }
-                    } finally {
-                        latch.countDown();
-                    }
-                });
-            }else {
-                logger.error("官方群发 员工信息有误:"+corpId+":"+qwUserid);
+                    });
+                } else {
+                    logger.error("员工信息无效-不存在或被删除,corpId:{}, userId:{}", corpId, qwUserid);
+
+                    latch.countDown(); // 确保每个分组都减少计数
+                }
             }
 
-        }
+            latch.await(); // 等待所有分组提交的任务完成
+            logger.info("关闭线程池并等待任务完成:"+updateList.size());
+            // 关闭线程池并等待任务完成
+            executorService.shutdown();
+            messageExecutorService.shutdown();
+            if (!executorService.awaitTermination(300, TimeUnit.SECONDS)) {
+                logger.error("ExecutorService未完全关闭");
+            }
+            if (!messageExecutorService.awaitTermination(300, TimeUnit.SECONDS)) {
+                logger.error("MessageExecutorService未完全关闭");
+            }
 
-        // 等待所有分组处理完成
-        try {
-            latch.await();
-        } catch (InterruptedException e) {
-            logger.error("等待分组处理完成时被中断", e);
-            Thread.currentThread().interrupt();
-        }
+            // 5. 同步块生成快照(终极防护),创建快照避免并发修改
+            List<QwSopLogs> batchList;
+            synchronized (updateList) { // 加锁确保无并发修改
+                batchList = new ArrayList<>(updateList);
+            }
 
-        // 批量更新发送状态,每500条一批
-        if (!updateList.isEmpty()) {
-            int batchSize = 500;
-            for (int i = 0; i < updateList.size(); i += batchSize) {
-                int endIndex = Math.min(i + batchSize, updateList.size());
-                List<QwSopLogs> batch = updateList.subList(i, endIndex);
-                try {
-                    qwSopLogsMapper.batchUpdateStatus(batch);
-                    logger.info("批量修改 sopLogs 成功,修改数量: " + batch.size());
-                } catch (Exception e) {
-                    logger.error("批量修改 sopLogs 失败", e);
+
+            logger.info("批量修改总数: {}", batchList.size());
+
+            if (!batchList.isEmpty()){
+                int batchSize = 1000;
+                for (int i = 0; i < batchList.size(); i += batchSize) {
+                    int end = Math.min(i + batchSize, batchList.size());
+                    List<QwSopLogs> subList = batchList.subList(i, end);
+                    qwSopLogsMapper.batchUpdateStatus(subList);
                 }
             }
-        }
 
-        // 关闭线程池
-        executorService.shutdown();
-        messageExecutorService.shutdown();
 
-        long endTime = System.currentTimeMillis();
-        logger.info("企业微信群发消息创建任务执行完成,总耗时: {} 毫秒", (endTime - startTime));
+        } catch (InterruptedException e) {
+            logger.error("线程中断异常", e);
+            Thread.currentThread().interrupt();
+        } finally {
+            long endTime = System.currentTimeMillis();
+            logger.info("任务完成,耗时: {} 毫秒", endTime - startTime);
+        }
     }
 
     // 处理不同类型的内容
@@ -1559,12 +1598,12 @@ public class QwSopLogsServiceImpl implements IQwSopLogsService
 //    }
 
     @Override
-    public void createCorpMassSendingByUserLogs(String date) {
+    public void createCorpMassSendingByUserLogs(String taskStartTime,String taskEndTime) {
 
         long startTime = System.currentTimeMillis();
         logger.info("开始执行企业微信群发消息创建任务");
 
-        List<QwSopLogs> qwSopLogsList = qwSopLogsMapper.selectSopLogsByCreateCorpMassSending(date);
+        List<QwSopLogs> qwSopLogsList = qwSopLogsMapper.selectSopLogsByCreateCorpMassSending(taskStartTime,taskEndTime);
         if (qwSopLogsList.isEmpty()) {
             logger.error("zyp \n【企微官方群发记录为空】");
             return;

+ 12 - 0
fs-service/src/main/java/com/fs/store/domain/FsUserCourseCount.java

@@ -80,6 +80,10 @@ public class FsUserCourseCount extends BaseEntity
     @Excel(name = "创建日期,为了创建唯一索引", width = 30, dateFormat = "yyyy-MM-dd")
     private Date createDate;
 
+    //最大的看课日期,用于查询唯一数据
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date lastDate;
+
     public void setId(Long id)
     {
         this.id = id;
@@ -215,6 +219,14 @@ public class FsUserCourseCount extends BaseEntity
         this.createDate = createDate;
     }
 
+    public Date getLastDate() {
+        return lastDate;
+    }
+
+    public void setLastDate(Date lastDate) {
+        this.lastDate = lastDate;
+    }
+
     @Override
     public String toString() {
         return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)

+ 6 - 0
fs-service/src/main/java/com/fs/store/mapper/FsUserCourseCountMapper.java

@@ -69,6 +69,12 @@ public interface FsUserCourseCountMapper
      */
     List<FsUserCourseCount> getCountResult();
 
+    /**
+     * 获取最近七天每天最大心跳时间的看课记录数据
+     * @return
+     */
+    List<FsUserCourseCount> getUserStatusAndLastWatchDate();
+
     /**
      * 往看课统计表中插入数据
      */

+ 4 - 0
fs-service/src/main/java/com/fs/store/param/h5/FsUserPageListParam.java

@@ -70,6 +70,10 @@ public class FsUserPageListParam implements Serializable {
      * 销售端登录用户id(该字段用于区分之前的登录用户)
      */
     private Long pcLoginUserId;
+    /**
+     * 是否为我的
+     */
+    private boolean isMyFsUser = true;
 
 
 

+ 17 - 0
fs-service/src/main/java/com/fs/store/service/impl/FsUserCourseCountServiceImpl.java

@@ -13,6 +13,8 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * 用户看课统计Service业务层处理
@@ -116,6 +118,21 @@ public class FsUserCourseCountServiceImpl implements IFsUserCourseCountService
         // 1、获取统计结果
         List<FsUserCourseCount> countResult = fsUserCourseCountMapper.getCountResult();
 
+        // 查询用户-每天的最新的看课状态,和最后的心跳时间
+        List<FsUserCourseCount> userStatusAndLastWatchDate = fsUserCourseCountMapper.getUserStatusAndLastWatchDate();
+        Map<String, FsUserCourseCount> map = userStatusAndLastWatchDate.stream()
+                .collect(Collectors.toMap(k -> String.format("%s-%s", k.getUserId(), k.getLastDate()), v -> v));
+
+        for (FsUserCourseCount data : countResult) {
+            String key = String.format("%s-%s",data.getUserId(), data.getLastDate());
+            FsUserCourseCount fsUserCourseCount = map.get(key);
+            if(fsUserCourseCount != null){
+                data.setLastWatchDate(fsUserCourseCount.getLastWatchDate());
+                data.setStatus(fsUserCourseCount.getStatus());
+                data.setStopWatchDays(fsUserCourseCount.getStopWatchDays());
+            }
+        }
+
         // 2、分批插入数据
         this.batchInsert(countResult);
 

+ 2 - 0
fs-service/src/main/java/com/fs/store/vo/h5/FsUserPageListVO.java

@@ -29,6 +29,8 @@ public class FsUserPageListVO {
     @ApiModelProperty(value = "状态:1为正常,0为禁止")
     private Integer status;
 
+    private String statusText;
+
     @ApiModelProperty(value = "公司id")
     private Long companyId;
 

+ 3 - 1
fs-service/src/main/java/com/fs/store/vo/h5/UserDetailsVO.java

@@ -4,6 +4,8 @@ import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
+import java.math.BigDecimal;
+
 /**
  * 用户会员详情 输出参数
  */
@@ -21,7 +23,7 @@ public class UserDetailsVO {
     private int answerRedPacketTime;
 
     @ApiModelProperty(value = "答题红包金额")
-    private int answerRedPacketAmount;
+    private BigDecimal answerRedPacketAmount;
 
     @ApiModelProperty(value = "完播次数")
     private int completeWatchCount;

+ 3 - 2
fs-service/src/main/resources/application-common.yml

@@ -110,7 +110,8 @@ mybatis:
 # PageHelper分页插件
 pagehelper:
   helperDialect: mysql
-  supportMethodsArguments: true
+  reasonable: false #超出后不显示
+  supportMethodsArguments: false
   params: count=countSql
 
 # Swagger配置
@@ -134,4 +135,4 @@ zhyf:
 image:
   storage:
     local-path: C:\logoFile\logo.jpg
-    server-path: C:\logoFile\logo.jpg
+    server-path: C:\logoFile\logo.jpg

+ 94 - 0
fs-service/src/main/resources/application-config-druid-bnkc.yml

@@ -0,0 +1,94 @@
+baidu:
+  token: 12313231232
+  back-domain: https://www.xxxx.com
+#配置
+logging:
+  level:
+    org.springframework.web: INFO
+    com.github.binarywang.demo.wx.cp: DEBUG
+    me.chanjar.weixin: DEBUG
+wx:
+  miniapp:
+    configs:
+      - appid: wx4115995705bb0ea0   #中康智慧
+        secret: 58910ae743005c396012b029c7def579
+        token: Ncbnd7lJvkripVOpyTFAna6NAWCxCrvC
+        aesKey: HlEiBB55eaWUaeBVAQO3cWKWPYv1vOVQSq7nFNICw4E
+        msgDataFormat: JSON
+      - appid: wxedde588767b358b1   #中康未来智慧药房
+        secret: 928d2961c81610d8f64b019597212fcd
+        token: Ncbnd7lJvkripVOpyTFAna6NAWCxCrvC
+        aesKey: HlEiBB55eaWUaeBVAQO3cWKWPYv1vOVQSq7nFNICw4E
+        msgDataFormat: JSON
+  cp:
+    corpId: wwb2a1055fb6c9a7c2
+    appConfigs:
+      - agentId: 1000005
+        secret: ec7okROXJqkNafq66-L6aKNv0asTzQIG0CYrj3vyBbo
+        token: PPKOdAlCoMO
+        aesKey: PKvaxtpSv8NGpfTDm7VUHIK8Wok2ESyYX24qpXJAdMP
+#  pay:
+#    appId:  #微信公众号或者小程序等的appid
+#    mchId:  #微信支付商户号
+#    mchKey:  #微信支付商户密钥
+#    subAppId:  #服务商模式下的子商户公众账号ID
+#    subMchId:  #服务商模式下的子商户号
+#    keyPath: c:\\cert\\apiclient_cert.p12 # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)
+#    notifyUrl: https://userapp.his.runtzh.com/app/wxpay/wxPayNotify
+  mp:
+    useRedis: false
+    redisConfig:
+      host: 127.0.0.1
+      port: 6379
+      timeout: 2000
+    configs:
+      - appId: wx5d3096e20e4bd8ba # 第一个公众号的appid  //公众号名称:成都九州在线互联网医院
+        secret: 1afa05f0c71beff0d52fb849c62e479a # 公众号的appsecret
+        token: PPKOdAlCoMO # 接口配置里的Token值
+        aesKey: Eswa6VjwtVMCcw03qZy6fWllgrv5aytIA1SZPEU0kU2 # 接口配置里的EncodingAESKey值
+aifabu:  #爱链接
+  appKey: 7b471be905ab17e00f3b858c6710dd117601d008
+watch:
+  watchUrl: watch.ylrzcloud.com/prod-api
+  #  account: tcloud
+  #  password: mdf-m2h_6yw2$hq
+  account1: ccif #866655060138751
+  password1: cp-t5or_6xw7$mt
+  account2: tcloud #rt500台
+  password2: mdf-m2h_6yw2$hq
+  account3: whr
+  password3: v9xsKuqn_$d2y
+
+fs :
+  commonApi: http://127.0.0.1:7771
+  h5CommonApi: http://127.0.0.1:7771
+nuonuo:
+  key: 10924508
+  secret: A2EB20764D304D16
+
+# 存储捅配置
+tencent_cloud_config:
+  secret_id: AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT
+  secret_key: u5SuS80342xzx8FRBukza9lVNHKNMSaB
+  bucket: bnkc-1323137866
+  app_id: 1323137866
+  region: ap-chongqing
+  proxy: bnkc
+tmp_secret_config:
+  secret_id: AKIDCj7NSNAovtqeJpBau8GZ4CGB71thXIxX
+  secret_key: lTB5zwqqz7CNhzDOWivFWedgfTBgxgBT
+  bucket: fs-1319721001
+  app_id: 1319721001
+  region: ap-chongqing
+  proxy: fs
+cloud_host:
+  company_name: 百年康成
+headerImg:
+  imgUrl: https
+ipad:
+  ipadUrl: http://ipad.cdwjyyh.com
+wx_miniapp_temp:
+  pay_order_temp_id:
+  inquiry_temp_id:
+
+

+ 2 - 9
fs-service/src/main/resources/application-config-druid-fcky.yml

@@ -46,7 +46,7 @@ watch:
   password3: v9xsKuqn_$d2y
 
 fs :
-  commonApi: http://127.0.0.1:7771
+  commonApi: http://10.206.0.16:8010
   h5CommonApi: http://127.0.0.1:7771
 nuonuo:
   key: 10924508
@@ -60,17 +60,10 @@ tencent_cloud_config:
   app_id: 1323137866
   region: ap-chongqing
   proxy: fcky
-tmp_secret_config:
-  secret_id: AKIDCj7NSNAovtqeJpBau8GZ4CGB71thXIxX
-  secret_key: lTB5zwqqz7CNhzDOWivFWedgfTBgxgBT
-  bucket: fs-1319721001
-  app_id: 1319721001
-  region: ap-chongqing
-  proxy: fs
 cloud_host:
   company_name: 蜂巢快药
 headerImg:
-  imgUrl: https
+  imgUrl: https://fc-1361520560.cos.ap-beijing.myqcloud.com/fs/20250619/ca569852d1da47f3bac8b209347c8011.png
 ipad:
   ipadUrl: http://ipad.cdwjyyh.com
 wx_miniapp_temp:

+ 3 - 3
fs-service/src/main/resources/application-config-druid-jzzx.yml

@@ -60,8 +60,8 @@ watch:
   password3: v9xsKuqn_$d2y
 
 fs :
-  commonApi: http://172.16.0.16:8010
-  h5CommonApi: http://119.29.195.254:8010
+  commonApi: http://127.0.0.1:8010
+  h5CommonApi: http://127.0.0.1:8010
 nuonuo:
   key: 10924508
   secret: A2EB20764D304D16
@@ -84,7 +84,7 @@ tmp_secret_config:
 cloud_host:
   company_name: 九州在线
 headerImg:
-  imgUrl: https://jz-cos-1356808054.cos.ap-chengdu.myqcloud.com/fs/20250515/0877754b59814ea8a428fa3697b20e68.png
+  imgUrl: https://jiuzhouzaixian.obs.cn-southwest-2.myhuaweicloud.com/fs/20250623/1750665141214.png
 ipad:
   ipadUrl: http://ipad.cdwjyyh.com
 wx_miniapp_temp:

+ 79 - 0
fs-service/src/main/resources/application-config-druid-lmjy.yml

@@ -0,0 +1,79 @@
+baidu:
+  token:
+  back-domain:
+#配置
+logging:
+  level:
+    org.springframework.web: INFO
+    com.github.binarywang.demo.wx.cp: DEBUG
+    me.chanjar.weixin: DEBUG
+wx:
+  cp:
+    corpId: wwb2a1055fb6c9a7c2
+    appConfigs:
+      - agentId: 1000008
+        secret: ec7okROXJqkNafq66-L6aKNv0asTzQIG0CYrj3vyBbo
+        token: PPKOdAlCoMO
+        aesKey: PKvaxtpSv8NGpfTDm7VUHIK8Wok2ESyYX24qpXJAdMP
+  pay:
+    appId:  #微信公众号或者小程序等的appid
+    mchId:  #微信支付商户号
+    mchKey:  #微信支付商户密钥
+    subAppId:  #服务商模式下的子商户公众账号ID
+    subMchId:  #服务商模式下的子商户号
+    keyPath: c:\\cert\\apiclient_cert.p12 # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)
+    notifyUrl: https://userapp.his.runtzh.com/app/wxpay/wxPayNotify
+  mp:
+    useRedis: false
+    redisConfig:
+      host: 127.0.0.1
+      port: 6379
+      timeout: 2000
+    configs:
+      - appId: wx5d3096e20e4bd8bb # 第一个公众号的appid  //公众号名称:成都九州在线互联网医院
+        secret: 1afa05f0c71beff0d52fb849c62e479a # 公众号的appsecret
+        token: PPKOdAlCoMO # 接口配置里的Token值
+        aesKey: Eswa6VjwtVMCcw03qZy6fWllgrv5aytIA1SZPEU0kU2 # 接口配置里的EncodingAESKey值
+aifabu:  #爱链接
+  appKey:
+watch:
+  watchUrl: watch.ylrzcloud.com/prod-api
+#  account: tcloud
+#  password: mdf-m2h_6yw2$hq
+  account1: ccif #866655060138751
+  password1: cp-t5or_6xw7$mt
+  account2: tcloud #rt500台
+  password2: mdf-m2h_6yw2$hq
+  account3: whr
+  password3: v9xsKuqn_$d2y
+
+fs :
+  commonApi: http://172.27.0.7:8010
+#  commonApi: http://127.0.0.1:8010
+  h5CommonApi: http://119.29.195.254:8010
+nuonuo:
+  key:
+  secret:
+
+
+  # 存储捅配置
+tencent_cloud_config:
+  secret_id: AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT
+  secret_key: u5SuS80342xzx8FRBukza9lVNHKNMSaB
+  bucket: lm-1323137866
+  app_id: 1323137866
+  region: ap-chongqing
+  proxy: lm
+cloud_host:
+  company_name: 良苗教育
+#看课授权时显示的头像
+headerImg:
+  imgUrl:
+ipad:
+  ipadUrl:
+
+wx_miniapp_temp:
+  pay_order_temp_id:
+  inquiry_temp_id:
+
+

+ 10 - 28
fs-service/src/main/resources/application-config-druid-zsjk.yml

@@ -1,5 +1,6 @@
 baidu:
   token: 12313231232
+  back-domain: https://www.xxxx.com
 #配置
 logging:
   level:
@@ -7,18 +8,6 @@ logging:
     com.github.binarywang.demo.wx.cp: DEBUG
     me.chanjar.weixin: DEBUG
 wx:
-  miniapp:
-    configs:
-      - appid: wx4115995705bb0ea0   #中康智慧
-        secret: 58910ae743005c396012b029c7def579
-        token: Ncbnd7lJvkripVOpyTFAna6NAWCxCrvC
-        aesKey: HlEiBB55eaWUaeBVAQO3cWKWPYv1vOVQSq7nFNICw4E
-        msgDataFormat: JSON
-      - appid: wxedde588767b358b1   #中康未来智慧药房
-        secret: 928d2961c81610d8f64b019597212fcd
-        token: Ncbnd7lJvkripVOpyTFAna6NAWCxCrvC
-        aesKey: HlEiBB55eaWUaeBVAQO3cWKWPYv1vOVQSq7nFNICw4E
-        msgDataFormat: JSON
   cp:
     corpId:
     appConfigs:
@@ -42,10 +31,10 @@ wx:
       timeout: 2000
       password: F&C6SI@w
     configs:
-      - appId:  # 第一个公众号的appid  //公众号名称:成都九州在线互联网医院
-        secret:  # 公众号的appsecret
-        token:  # 接口配置里的Token值
-        aesKey:  # 接口配置里的EncodingAESKey值
+      - appId: wx21eb60f1670b30fb # 第一个公众号的appid  //公众号名称:中食健康CFSH
+        secret: ce4dbc601a9c1d7944f6c75467e43aa0 # 公众号的appsecret
+        token: PPKOdAlCoMO # 接口配置里的Token值
+        aesKey: Eswa6VjwtVcw03qZy6Wllgrv5aytIA1SZPEU0kU2 # 接口配置里的EncodingAESKey值
 aifabu:  #爱链接
   appKey:
 watch:
@@ -68,23 +57,16 @@ nuonuo:
 
 # 存储捅配置
 tencent_cloud_config:
-  secret_id:
-  secret_key:
-  bucket:
-  app_id:
+  secret_id: AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT
+  secret_key: u5SuS80342xzx8FRBukza9lVNHKNMSaB
+  bucket: zsjk-1323137866
+  app_id: 1323137866
   region: ap-chongqing
   proxy: zsjk
-tmp_secret_config:
-  secret_id:
-  secret_key:
-  bucket:
-  app_id: 1319721001
-  region: ap-chongqing
-  proxy: fs
 cloud_host:
   company_name: 中食健康
 headerImg:
-  imgUrl: https
+  imgUrl: https://zs-1362480099.cos.ap-beijing.myqcloud.com/fs/20250618/4839e2ff3bdb4908b459abea45a04f4b.png
 ipad:
   ipadUrl: http://ipad.cdwjyyh.com
 wx_miniapp_temp:

+ 149 - 0
fs-service/src/main/resources/application-druid-bnkc.yml

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

+ 150 - 0
fs-service/src/main/resources/application-druid-fcky-test.yml

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

+ 2 - 2
fs-service/src/main/resources/application-druid-jzzx.yml

@@ -5,13 +5,13 @@ spring:
     # redis 配置
     redis:
         # 地址
-        host: 127.0.0.1
+        host: 192.168.0.125
         # 端口,默认为6379
         port: 6379
         # 数据库索引
         database: 0
         # 密码
-        password:
+        password: Ylrztek250218!3@.
         # 连接超时时间
         timeout: 20s
         lettuce:

+ 150 - 0
fs-service/src/main/resources/application-druid-lmjy.yml

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

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio