浏览代码

Merge branch 'refs/heads/master' into openIm

# Conflicts:
#	fs-service/src/main/java/com/fs/company/mapper/CompanyUserMapper.java
#	fs-service/src/main/java/com/fs/his/dto/PayloadDTO.java
#	fs-service/src/main/java/com/fs/his/mapper/FsDoctorMapper.java
#	fs-service/src/main/java/com/fs/im/config/IMConfig.java
#	fs-service/src/main/java/com/fs/im/dto/OpenImMsgDTO.java
#	fs-service/src/main/java/com/fs/im/service/OpenIMService.java
#	fs-service/src/main/java/com/fs/im/service/impl/OpenIMServiceImpl.java
#	fs-service/src/main/java/com/fs/qw/mapper/QwExternalContactMapper.java
#	fs-service/src/main/resources/mapper/company/CompanyUserMapper.xml
xdd 2 月之前
父节点
当前提交
3215c71c8e
共有 100 个文件被更改,包括 4147 次插入270 次删除
  1. 0 1
      .gitignore
  2. 1 1
      fs-admin/src/main/java/com/fs/company/controller/CompanyController.java
  3. 148 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyDeductController.java
  4. 3 3
      fs-admin/src/main/java/com/fs/company/controller/CompanyDomainBindController.java
  5. 7 7
      fs-admin/src/main/java/com/fs/company/controller/CompanyDomainController.java
  6. 143 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyRechargeController.java
  7. 63 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyRedPackageController.java
  8. 3 2
      fs-admin/src/main/java/com/fs/company/controller/CompanyUserController.java
  9. 103 0
      fs-admin/src/main/java/com/fs/course/controller/FsCourseProductController.java
  10. 139 0
      fs-admin/src/main/java/com/fs/course/controller/FsCourseProductOrderController.java
  11. 10 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseComplaintRecordController.java
  12. 4 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseController.java
  13. 2 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseTrainingCampController.java
  14. 15 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseVideoController.java
  15. 6 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserTalentController.java
  16. 145 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserWatchCourseStatisticsController.java
  17. 118 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserWatchStatisticsController.java
  18. 4 0
      fs-admin/src/main/java/com/fs/course/controller/FsVideoResourceController.java
  19. 64 0
      fs-admin/src/main/java/com/fs/his/controller/FsPackageSolarTermController.java
  20. 2 2
      fs-admin/src/main/java/com/fs/his/controller/FsPhysicalReportTemplateFieldController.java
  21. 118 5
      fs-admin/src/main/java/com/fs/his/controller/FsUserController.java
  22. 121 0
      fs-admin/src/main/java/com/fs/his/controller/FsUserOnlineStateController.java
  23. 20 0
      fs-admin/src/main/java/com/fs/his/task/SendRedPacketTask.java
  24. 56 0
      fs-admin/src/main/java/com/fs/his/task/WatchCourseTask.java
  25. 19 0
      fs-admin/src/main/java/com/fs/qw/OrderTask.java
  26. 2 2
      fs-admin/src/main/java/com/fs/qw/controller/QwUserController.java
  27. 11 0
      fs-admin/src/main/java/com/fs/qw/qwTask/qwTask.java
  28. 2 1
      fs-admin/src/main/resources/application.yml
  29. 1 0
      fs-common/src/main/java/com/fs/common/constant/FsConstants.java
  30. 6 0
      fs-company-app/src/main/java/com/fs/app/controller/AppBaseController.java
  31. 29 12
      fs-company-app/src/main/java/com/fs/app/controller/CompanyTagController.java
  32. 100 17
      fs-company-app/src/main/java/com/fs/app/controller/CompanyUserController.java
  33. 50 14
      fs-company-app/src/main/java/com/fs/app/controller/FsUserController.java
  34. 9 0
      fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java
  35. 1 1
      fs-company-app/src/main/java/com/fs/app/controller/UserController.java
  36. 153 124
      fs-company-app/src/main/java/com/fs/app/controller/WxCompanyUserController.java
  37. 14 1
      fs-company-app/src/main/java/com/fs/app/param/CompanyUserChangeApplyParam.java
  38. 5 3
      fs-company-app/src/main/java/com/fs/app/param/CompanyUserParam.java
  39. 17 0
      fs-company-app/src/main/java/com/fs/app/param/FsUserProjectUpdateParam.java
  40. 3 3
      fs-company-app/src/main/java/com/fs/app/param/FsUserTagUpdateParam.java
  41. 22 0
      fs-company-app/src/main/java/com/fs/app/param/LoginMaWxParam.java
  42. 5 1
      fs-company-app/src/main/java/com/fs/app/param/LoginParam.java
  43. 23 0
      fs-company-app/src/main/java/com/fs/app/param/TagProjectParam.java
  44. 5 1
      fs-company/pom.xml
  45. 3 3
      fs-company/src/main/java/com/fs/company/controller/company/CompanyDomainBindController.java
  46. 34 0
      fs-company/src/main/java/com/fs/company/controller/company/CompanyRechargeController.java
  47. 76 0
      fs-company/src/main/java/com/fs/company/controller/company/CompanyUserChangeApplyController.java
  48. 12 0
      fs-company/src/main/java/com/fs/company/controller/company/CompanyUserController.java
  49. 35 21
      fs-company/src/main/java/com/fs/company/controller/course/FsCourseAnswerLogsController.java
  50. 130 0
      fs-company/src/main/java/com/fs/company/controller/course/FsCourseTrafficLogController.java
  51. 1 2
      fs-company/src/main/java/com/fs/company/controller/course/FsCourseWatchLogController.java
  52. 153 0
      fs-company/src/main/java/com/fs/company/controller/course/FsUserWatchCourseStatisticsController.java
  53. 106 0
      fs-company/src/main/java/com/fs/company/controller/course/FsUserWatchStatisticsController.java
  54. 1 1
      fs-company/src/main/java/com/fs/company/controller/fastGpt/FastGptChatSessionController.java
  55. 23 0
      fs-company/src/main/java/com/fs/company/controller/param/CompanyUserChangeApplyAuditParam.java
  56. 8 0
      fs-company/src/main/java/com/fs/company/controller/pay/WxPayApiController.java
  57. 189 0
      fs-company/src/main/java/com/fs/company/controller/pay/WxPayController.java
  58. 98 0
      fs-company/src/main/java/com/fs/company/controller/pay/bean/AliPayBean.java
  59. 71 0
      fs-company/src/main/java/com/fs/company/controller/pay/bean/WxPayBean.java
  60. 106 0
      fs-company/src/main/java/com/fs/company/controller/pay/bean/WxPayV3Bean.java
  61. 2 0
      fs-company/src/main/java/com/fs/company/controller/qw/QwMaterialController.java
  62. 16 0
      fs-company/src/main/java/com/fs/company/controller/qw/QwSopLogsController.java
  63. 5 0
      fs-company/src/main/java/com/fs/company/controller/qw/QwUserController.java
  64. 33 4
      fs-company/src/main/java/com/fs/company/controller/store/FsUserController.java
  65. 136 0
      fs-company/src/main/java/com/fs/company/controller/store/FsUserOnlineStateController.java
  66. 1 0
      fs-company/src/main/java/com/fs/framework/config/SecurityConfig.java
  67. 25 2
      fs-company/src/main/java/com/fs/user/FsUserAdminController.java
  68. 3 2
      fs-company/src/main/resources/application.yml
  69. 8 5
      fs-doctor-app/src/main/java/com/fs/app/controller/InquiryOrderController.java
  70. 1 1
      fs-ipad-task/src/main/java/com/fs/app/task/SendMsg.java
  71. 49 0
      fs-qw-api-msg/src/main/java/com/fs/app/config/QWConfigProperties.java
  72. 182 13
      fs-qw-api-msg/src/main/java/com/fs/app/controller/QwMsgController.java
  73. 1 1
      fs-qw-api-msg/src/main/java/com/fs/app/controller/imgTest.java
  74. 55 0
      fs-qw-api-msg/src/main/java/com/fs/app/controller/test.java
  75. 20 3
      fs-qw-api-msg/src/main/java/com/fs/framework/config/DataSourceConfig.java
  76. 1 1
      fs-qw-api-msg/src/main/java/com/fs/framework/config/MyBatisConfig.java
  77. 2 0
      fs-qw-api-msg/src/main/java/com/fs/framework/config/SecurityConfig.java
  78. 3 2
      fs-qw-api-msg/src/main/resources/application.yml
  79. 4 2
      fs-qw-api/src/main/resources/application.yml
  80. 16 3
      fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java
  81. 1 1
      fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java
  82. 73 0
      fs-qwhook-sop/src/main/java/com/fs/app/controller/ApisQwMaterialBySidebar.java
  83. 72 0
      fs-qwhook-sop/src/main/java/com/fs/app/controller/QwMaterialBySidebar.java
  84. 81 0
      fs-qwhook/src/main/java/com/fs/app/controller/ApisQwMaterialBySidebar.java
  85. 73 0
      fs-qwhook/src/main/java/com/fs/app/controller/QwMaterialBySidebar.java
  86. 18 0
      fs-redis/src/main/java/com/fs/app/redis/RedisKeyExpirationListener.java
  87. 12 0
      fs-redis/src/main/resources/application.yml
  88. 1 1
      fs-service/src/main/java/com/fs/common/param/LoginMaWxParam.java
  89. 83 0
      fs-service/src/main/java/com/fs/company/constant/PaymentStatus.java
  90. 45 0
      fs-service/src/main/java/com/fs/company/domain/CompanyCompanyFsuser.java
  91. 75 0
      fs-service/src/main/java/com/fs/company/domain/CompanyRechargeOrder.java
  92. 64 0
      fs-service/src/main/java/com/fs/company/domain/CompanyRedPackage.java
  93. 41 0
      fs-service/src/main/java/com/fs/company/domain/CompanyUser.java
  94. 4 0
      fs-service/src/main/java/com/fs/company/domain/CompanyUserChangeApplyUser.java
  95. 18 0
      fs-service/src/main/java/com/fs/company/dto/CompBuySmsDTO.java
  96. 13 0
      fs-service/src/main/java/com/fs/company/dto/CompanyIdAndUserDTO.java
  97. 15 0
      fs-service/src/main/java/com/fs/company/dto/RechargeDTO.java
  98. 68 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyCompanyFsuserMapper.java
  99. 6 1
      fs-service/src/main/java/com/fs/company/mapper/CompanyMapper.java
  100. 3 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyMoneyLogsMapper.java

+ 0 - 1
.gitignore

@@ -8,7 +8,6 @@ target/
 #logback.xml
 application.yml
 
-
 ### STS ###
 .apt_generated
 .classpath

+ 1 - 1
fs-admin/src/main/java/com/fs/company/controller/CompanyController.java

@@ -174,7 +174,7 @@ public class CompanyController extends BaseController
     public AjaxResult resetPwd(@PathVariable Long companyId)
     {
         Company company=companyService.selectCompanyById(companyId);
-        return toAjax(userService.resetUserPwdByUserId(company.getUserId(),SecurityUtils.encryptPassword("123456")));
+        return toAjax(userService.resetUserPwdByUserId(company.getUserId(),SecurityUtils.encryptPassword("cq654321!!")));
     }
 
 //    @PreAuthorize("@ss.hasPermi('company:company:resetMoney')")

+ 148 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyDeductController.java

@@ -0,0 +1,148 @@
+package com.fs.company.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyDeduct;
+import com.fs.company.domain.CompanyMoneyLogs;
+import com.fs.company.service.ICompanyDeductService;
+import com.fs.company.service.ICompanyMoneyLogsService;
+import com.fs.company.service.ICompanyService;
+import com.fs.company.vo.CompanyDeductExportVO;
+import com.fs.company.vo.CompanyDeductVO;
+import com.fs.framework.web.service.TokenService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 扣款Controller
+ *
+ * @author fs
+ * @date 2023-02-27
+ */
+@RestController
+@RequestMapping("/company/companyDeduct")
+public class CompanyDeductController extends BaseController
+{
+    @Autowired
+    private ICompanyDeductService companyDeductService;
+    @Autowired
+    private TokenService tokenService;
+    @Autowired
+    private ICompanyService companyService;
+    @Autowired
+    private ICompanyMoneyLogsService moneyLogsService;
+    /**
+     * 查询扣款列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDeduct:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyDeduct companyDeduct)
+    {
+        startPage();
+        List<CompanyDeductVO> list = companyDeductService.selectCompanyDeductVOList(companyDeduct);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出扣款列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDeduct:export')")
+    @Log(title = "扣款", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyDeduct companyDeduct)
+    {
+        List<CompanyDeductExportVO> list = companyDeductService.selectCompanyExportDeductList(companyDeduct);
+        ExcelUtil<CompanyDeductExportVO> util = new ExcelUtil<CompanyDeductExportVO>(CompanyDeductExportVO.class);
+        return util.exportExcel(list, "companyDeduct");
+    }
+
+    /**
+     * 获取扣款详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDeduct:query')")
+    @GetMapping(value = "/{deductId}")
+    public AjaxResult getInfo(@PathVariable("deductId") Long deductId)
+    {
+        return AjaxResult.success(companyDeductService.selectCompanyDeductById(deductId));
+    }
+
+    /**
+     * 新增扣款
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDeduct:add')")
+    @Log(title = "扣款", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanyDeduct companyDeduct)
+    {
+        return toAjax(companyDeductService.insertCompanyDeduct(companyDeduct));
+    }
+
+    /**
+     * 修改扣款
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDeduct:edit')")
+    @Log(title = "扣款", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanyDeduct companyDeduct)
+    {
+        return toAjax(companyDeductService.updateCompanyDeduct(companyDeduct));
+    }
+
+    /**
+     * 删除扣款
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDeduct:remove')")
+    @Log(title = "扣款", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{deductIds}")
+    public AjaxResult remove(@PathVariable Long[] deductIds)
+    {
+        return toAjax(companyDeductService.deleteCompanyDeductByIds(deductIds));
+    }
+
+
+    @PreAuthorize("@ss.hasPermi('company:companyDeduct:audit')")
+    @PostMapping("/audit")
+    @Transactional
+    public R audit(@RequestBody CompanyDeduct param)
+    {
+        CompanyDeduct deduct=companyDeductService.selectCompanyDeductById(param.getDeductId());
+        if(deduct.getIsAudit()!=0){
+            return R.error("非法操作");
+        }
+        deduct.setIsAudit(param.getIsAudit());
+        deduct.setRemark(param.getRemark());
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        if(deduct.getIsAudit()==1){
+            Company company=companyService.selectCompanyByIdForUpdate(deduct.getCompanyId());
+            company.setMoney(company.getMoney().subtract(deduct.getMoney()));
+            companyService.updateCompany(company);
+            CompanyMoneyLogs log=new CompanyMoneyLogs();
+            log.setCompanyId(deduct.getCompanyId());
+            log.setMoney(deduct.getMoney().multiply(new BigDecimal(-1)));
+            log.setRemark(deduct.getRemark());
+            log.setLogsType(2);
+            log.setBalance(company.getMoney());
+            log.setCreateTime(new Date());
+            moneyLogsService.insertCompanyMoneyLogs(log);
+        }
+        deduct.setAuditTime(new Date());
+        deduct.setAuditUserId(loginUser.getUser().getUserId());
+        companyDeductService.updateCompanyDeduct(deduct);
+        return R.ok("操作成功");
+
+    }
+}

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

@@ -3,7 +3,7 @@ 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.R;
 import com.fs.common.core.domain.model.LoginUser;
 import com.fs.common.utils.ServletUtils;
 import com.fs.company.param.CompanyDomainBindParam;
@@ -118,10 +118,10 @@ public class CompanyDomainBindController extends BaseController
     @PostMapping("/domainBatchBinding")
     public R domainBatchBinding(@RequestBody CompanyDomainBindParam param) {
         if (ObjectUtil.isEmpty(param.getCompanyIds()) || param.getCompanyIds().isEmpty()) {
-            return R.failed("绑定失败,至少有一条域名分配信息!");
+            return R.error("绑定失败,至少有一条域名分配信息!");
         }
         if (ObjectUtil.isEmpty(param.getCompanyUserIds()) || param.getCompanyUserIds().isEmpty()) {
-            return R.failed("绑定失败,至少有一条分配人员信息!");
+            return R.error("绑定失败,至少有一条分配人员信息!");
         }
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         param.setUserId(loginUser.getUser().getUserId().toString());

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

@@ -3,7 +3,7 @@ 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.R;
 import com.fs.common.core.domain.model.LoginUser;
 import com.fs.common.exception.ServiceException;
 import com.fs.common.utils.ServletUtils;
@@ -127,10 +127,10 @@ public class CompanyDomainController extends BaseController {
     @PostMapping("/domainBatchBinding")
     public R domainBatchBinding(@RequestBody CompanyDomainParam param) {
         if (ObjectUtil.isEmpty(param.getDomainIds()) || param.getDomainIds().isEmpty()) {
-            return R.failed("绑定失败,至少有一条绑定域名信息!");
+            return R.error("绑定失败,至少有一条绑定域名信息!");
         }
         if (ObjectUtil.isEmpty(param.getCompanyIds()) || param.getCompanyIds().isEmpty()) {
-            return R.failed("绑定失败,至少有一条绑定公司信息!");
+            return R.error("绑定失败,至少有一条绑定公司信息!");
         }
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         param.setUserId(loginUser.getUser().getUserId().toString());
@@ -151,18 +151,18 @@ public class CompanyDomainController extends BaseController {
     public R importDomainData(MultipartFile file) {
         // 1. 检查文件是否为空
         if (file.isEmpty()) {
-            return R.failed("上传的文件不能为空");
+            return R.error("上传的文件不能为空");
         }
 
         // 2. 检查文件大小
         if (file.getSize() > MAX_FILE_SIZE) {
-            return R.failed("文件大小不能超过5MB");
+            return R.error("文件大小不能超过5MB");
         }
 
         // 3. 检查文件扩展名
         String fileName = file.getOriginalFilename();
         if (fileName == null || !isValidExcelFile(fileName)) {
-            return R.failed("请上传Excel文件(.xlsx或.xls格式)");
+            return R.error("请上传Excel文件(.xlsx或.xls格式)");
         }
         CompanyDomainParam param = new CompanyDomainParam();
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
@@ -173,7 +173,7 @@ public class CompanyDomainController extends BaseController {
             return companyDomainService.importDomainData(param, companyDomainList);
         } catch (Exception e) {
             e.getStackTrace();
-            return R.failed("导入失败!");
+            return R.error("导入失败!");
         }
     }
 

+ 143 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyRechargeController.java

@@ -0,0 +1,143 @@
+package com.fs.company.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyMoneyLogs;
+import com.fs.company.domain.CompanyRecharge;
+import com.fs.company.service.ICompanyMoneyLogsService;
+import com.fs.company.service.ICompanyRechargeService;
+import com.fs.company.service.ICompanyService;
+import com.fs.company.vo.CompanyRechargeExportVO;
+import com.fs.company.vo.CompanyRechargeVO;
+import com.fs.framework.web.service.TokenService;
+import lombok.Synchronized;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 充值Controller
+ *
+ * @author fs
+ * @date 2021-10-04
+ */
+@RestController
+@RequestMapping("/company/companyRecharge")
+public class CompanyRechargeController extends BaseController
+{
+    @Autowired
+    private TokenService tokenService;
+    @Autowired
+    private ICompanyRechargeService companyRechargeService;
+    @Autowired
+    private ICompanyService companyService;
+    @Autowired
+    private ICompanyMoneyLogsService moneyLogsService;
+    /**
+     * 查询充值列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRecharge:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyRecharge companyRecharge)
+    {
+        startPage();
+        List<CompanyRechargeVO> list = companyRechargeService.selectCompanyRechargeVOList(companyRecharge);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出充值列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRecharge:export')")
+    @Log(title = "充值", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyRecharge companyRecharge)
+    {
+        List<CompanyRechargeExportVO> list = companyRechargeService.selectCompanyRechargeExportList(companyRecharge);
+        ExcelUtil<CompanyRechargeExportVO> util = new ExcelUtil<CompanyRechargeExportVO>(CompanyRechargeExportVO.class);
+        return util.exportExcel(list, "公司充值明细");
+    }
+
+    /**
+     * 获取充值详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRecharge:query')")
+    @GetMapping(value = "/{rechargeId}")
+    public AjaxResult getInfo(@PathVariable("rechargeId") Long rechargeId)
+    {
+        return AjaxResult.success(companyRechargeService.selectCompanyRechargeById(rechargeId));
+    }
+
+    /**
+     * 新增充值
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRecharge:add')")
+    @Log(title = "充值", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanyRecharge companyRecharge)
+    {
+        return toAjax(companyRechargeService.insertCompanyRecharge(companyRecharge));
+    }
+
+
+
+    /**
+     * 删除充值
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRecharge:remove')")
+    @Log(title = "充值", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{rechargeIds}")
+    public AjaxResult remove(@PathVariable Long[] rechargeIds)
+    {
+        return toAjax(companyRechargeService.deleteCompanyRechargeByIds(rechargeIds));
+    }
+
+
+
+    @PreAuthorize("@ss.hasPermi('company:companyRecharge:audit')")
+    @PostMapping("/audit")
+    @Transactional
+    @Synchronized
+    public R audit(@RequestBody CompanyRecharge param)
+    {
+        CompanyRecharge companyRecharge=companyRechargeService.selectCompanyRechargeById(param.getRechargeId());
+        if(companyRecharge.getIsAudit()!=0){
+            return R.error("非法操作");
+        }
+        companyRecharge.setIsAudit(param.getIsAudit());
+        companyRecharge.setRemark(param.getRemark());
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        if(companyRecharge.getIsAudit()==1){
+            Company company=companyService.selectCompanyById(companyRecharge.getCompanyId());
+            company.setMoney(company.getMoney().add(companyRecharge.getMoney()));
+            companyService.updateCompany(company);
+            CompanyMoneyLogs log=new CompanyMoneyLogs();
+            log.setCompanyId(companyRecharge.getCompanyId());
+            log.setMoney(companyRecharge.getMoney());
+            log.setRemark(companyRecharge.getRemark());
+            log.setLogsType(1);
+            log.setBalance(company.getMoney());
+            log.setCreateTime(new Date());
+            moneyLogsService.insertCompanyMoneyLogs(log);
+            companyRecharge.setPayTime(new Date());
+            companyRecharge.setStatus(1);
+        }
+        companyRecharge.setAuditTime(new Date());
+        companyRecharge.setAuditUserId(loginUser.getUser().getUserId());
+        companyRechargeService.updateCompanyRecharge(companyRecharge);
+        return R.ok("操作成功");
+
+    }
+}

+ 63 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyRedPackageController.java

@@ -0,0 +1,63 @@
+package com.fs.company.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.*;
+import com.fs.company.service.ICompanyMoneyLogsService;
+import com.fs.company.service.ICompanyProfitLogsService;
+import com.fs.company.service.ICompanyProfitService;
+import com.fs.company.service.ICompanyService;
+import com.fs.framework.web.service.TokenService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 提现Controller
+ *
+ * @author fs
+ * @date 2022-07-04
+ */
+@RestController
+@RequestMapping("/company/redPackage")
+public class CompanyRedPackageController extends BaseController
+{
+    @Autowired
+    private ICompanyMoneyLogsService moneyLogsService;
+    /**
+     * 查询提现列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:redPackage:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyRedPackage companyRedPackage)
+    {
+        startPage();
+        List<CompanyRedPackage> list = moneyLogsService.selectCompanyRedPackageListVO(companyRedPackage);
+        String dateTime = companyRedPackage.getDateTime();
+        list.forEach(m -> m.setDateTime(dateTime));
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出提现列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:redPackage:export')")
+    @Log(title = "提现", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyRedPackage companyRedPackage)
+    {
+        List<CompanyRedPackage> list = moneyLogsService.selectCompanyRedPackageListVO(companyRedPackage);
+        String dateTime = companyRedPackage.getDateTime();
+        list.forEach(m -> m.setDateTime(dateTime));
+        ExcelUtil<CompanyRedPackage> util = new ExcelUtil<CompanyRedPackage>(CompanyRedPackage.class);
+        return util.exportExcel(list, "红包金额记录");
+    }
+
+
+}

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

@@ -11,6 +11,7 @@ import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.service.ICompanyUserService;
+import com.fs.qw.dto.UserProjectDTO;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
@@ -145,9 +146,9 @@ public class CompanyUserController extends BaseController
     @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)
+    public AjaxResult changeCompanyUser(@RequestBody List<UserProjectDTO> users, @RequestParam Long companyUserId, @RequestParam Long companyId)
     {
-        return toAjax(companyUserService.changeCompanyUser(userIds, companyUserId, companyId));
+        return toAjax(companyUserService.changeCompanyUser(users, companyUserId, companyId));
     }
     /**
      * 根据登录的用户公司获取所有的销售

+ 103 - 0
fs-admin/src/main/java/com/fs/course/controller/FsCourseProductController.java

@@ -0,0 +1,103 @@
+package com.fs.course.controller;
+
+import java.util.List;
+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.course.domain.FsCourseProduct;
+import com.fs.course.service.IFsCourseProductService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 拍单商品Controller
+ * 
+ * @author fs
+ * @date 2025-07-28
+ */
+@RestController
+@RequestMapping("/course/fsCourseProduct")
+public class FsCourseProductController extends BaseController
+{
+    @Autowired
+    private IFsCourseProductService fsCourseProductService;
+
+    /**
+     * 查询拍单商品列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProduct:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsCourseProduct fsCourseProduct)
+    {
+        startPage();
+        List<FsCourseProduct> list = fsCourseProductService.selectFsCourseProductList(fsCourseProduct);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出拍单商品列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProduct:export')")
+    @Log(title = "拍单商品", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsCourseProduct fsCourseProduct)
+    {
+        List<FsCourseProduct> list = fsCourseProductService.selectFsCourseProductList(fsCourseProduct);
+        ExcelUtil<FsCourseProduct> util = new ExcelUtil<FsCourseProduct>(FsCourseProduct.class);
+        return util.exportExcel(list, "拍单商品数据");
+    }
+
+    /**
+     * 获取拍单商品详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProduct:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsCourseProductService.selectFsCourseProductById(id));
+    }
+
+    /**
+     * 新增拍单商品
+     */
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProduct:add')")
+    @Log(title = "拍单商品", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsCourseProduct fsCourseProduct)
+    {
+        return toAjax(fsCourseProductService.insertFsCourseProduct(fsCourseProduct));
+    }
+
+    /**
+     * 修改拍单商品
+     */
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProduct:edit')")
+    @Log(title = "拍单商品", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsCourseProduct fsCourseProduct)
+    {
+        return toAjax(fsCourseProductService.updateFsCourseProduct(fsCourseProduct));
+    }
+
+    /**
+     * 删除拍单商品
+     */
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProduct:remove')")
+    @Log(title = "拍单商品", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsCourseProductService.deleteFsCourseProductByIds(ids));
+    }
+}

+ 139 - 0
fs-admin/src/main/java/com/fs/course/controller/FsCourseProductOrderController.java

@@ -0,0 +1,139 @@
+package com.fs.course.controller;
+
+import java.util.List;
+
+import com.fs.common.annotation.RepeatSubmit;
+import com.fs.common.core.domain.R;
+import com.fs.course.param.FsCourseProductOrderListParam;
+import com.fs.course.vo.FsCourseProductOrderVO;
+import com.fs.his.param.FsCourseProductOrderRefundParam;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+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.course.domain.FsCourseProductOrder;
+import com.fs.course.service.IFsCourseProductOrderService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+import static com.fs.his.utils.PhoneUtil.decryptPhone;
+
+/**
+ * 拍单商品订单Controller
+ * 
+ * @author fs
+ * @date 2025-07-28
+ */
+@RestController
+@RequestMapping("/course/fsCourseProductOrder")
+public class FsCourseProductOrderController extends BaseController
+{
+    @Autowired
+    private IFsCourseProductOrderService fsCourseProductOrderService;
+
+    /**
+     * 查询拍单商品订单列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProductOrder:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsCourseProductOrderListParam param)
+    {
+        startPage();
+        List<FsCourseProductOrderVO> list = fsCourseProductOrderService.selectFsCourseProductOrderList(param);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出拍单商品订单列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProductOrder:export')")
+    @Log(title = "拍单商品订单", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsCourseProductOrderListParam param)
+    {
+        List<FsCourseProductOrderVO> list = fsCourseProductOrderService.selectFsCourseProductOrderList(param);
+        ExcelUtil<FsCourseProductOrderVO> util = new ExcelUtil<FsCourseProductOrderVO>(FsCourseProductOrderVO.class);
+        return util.exportExcel(list, "拍单商品订单数据");
+    }
+
+    /**
+     * 获取拍单商品订单详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProductOrder:query')")
+    @GetMapping(value = "/{courseOrderId}")
+    public AjaxResult getInfo(@PathVariable("courseOrderId") Long courseOrderId)
+    {
+        return AjaxResult.success(fsCourseProductOrderService.selectFsCourseProductOrderByCourseOrderId(courseOrderId));
+    }
+
+    /**
+     * 新增拍单商品订单
+     */
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProductOrder:add')")
+    @Log(title = "拍单商品订单", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsCourseProductOrder fsCourseProductOrder)
+    {
+        return toAjax(fsCourseProductOrderService.insertFsCourseProductOrder(fsCourseProductOrder));
+    }
+
+    /**
+     * 修改拍单商品订单
+     */
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProductOrder:edit')")
+    @Log(title = "拍单商品订单", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsCourseProductOrder fsCourseProductOrder)
+    {
+        return toAjax(fsCourseProductOrderService.updateFsCourseProductOrder(fsCourseProductOrder));
+    }
+
+    /**
+     * 删除拍单商品订单
+     */
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProductOrder:remove')")
+    @Log(title = "拍单商品订单", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{courseOrderIds}")
+    public AjaxResult remove(@PathVariable Long[] courseOrderIds)
+    {
+        return toAjax(fsCourseProductOrderService.deleteFsCourseProductOrderByCourseOrderIds(courseOrderIds));
+    }
+
+    @Transactional
+    @RepeatSubmit
+    @ApiOperation("退款拍商品订单")
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProductOrder:refund')")
+    @PostMapping("/refund")
+    public R refundOrder(@Validated @RequestBody FsCourseProductOrderRefundParam param){
+        param.setSysUserName(getLoginUser().getUsername());
+        logger.info("退款拍商品订单:"+param.getCourseOrderId()+":操作人:总后台:"+ getLoginUser().getUsername());
+        return fsCourseProductOrderService.refund(param);
+    }
+
+    @GetMapping(value = "/queryPhone/{courseOrderId}")
+    @Log(title = "查看电话", businessType = BusinessType.GRANT)
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProductOrder:queryPhone')")
+    public R getPhone(@PathVariable("courseOrderId") Long courseOrderId)
+    {
+        FsCourseProductOrder courseProductOrder = fsCourseProductOrderService.selectFsCourseProductOrderByCourseOrderId(courseOrderId);
+        String userPhone = courseProductOrder.getUserPhone();
+
+        if (userPhone!=null&&userPhone.length()>11){
+            userPhone=decryptPhone(userPhone);
+        }
+        return R.ok().put("userPhone",userPhone);
+    }
+}

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

@@ -75,6 +75,16 @@ public class FsUserCourseComplaintRecordController extends BaseController
         return AjaxResult.success(fsUserCourseComplaintRecordService.selectFsUserCourseComplaintRecordByRecordId(recordId));
     }
 
+    /**
+    * 获取 看课投诉记录详细信息-客户所属关系
+    */
+    @PreAuthorize("@ss.hasPermi('course:userCourseComplaintRecord:queryQw')")
+    @GetMapping(value = "/getInfoByUserId/{userId}")
+    public AjaxResult getInfoByUserId(@PathVariable("userId") Long userId)
+    {
+        return AjaxResult.success(fsUserCourseComplaintRecordService.selectFsUserCourseComplaintRecordByUserId(userId));
+    }
+
     /**
      * 新增看课投诉记录
      */

+ 4 - 0
fs-admin/src/main/java/com/fs/course/controller/FsUserCourseController.java

@@ -3,7 +3,10 @@ package com.fs.course.controller;
 import java.util.List;
 
 import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.utils.ServletUtils;
 import com.fs.course.vo.FsUserCourseListPVO;
+import com.fs.framework.web.service.TokenService;
 import com.fs.his.utils.RedisCacheUtil;
 import com.fs.his.vo.OptionsVO;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -40,6 +43,7 @@ public class FsUserCourseController extends BaseController
 
     @Autowired
     private RedisCacheUtil redisCacheUtil;
+
     /**
      * 查询课程列表
      */

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

@@ -3,7 +3,9 @@ package com.fs.course.controller;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.model.LoginUser;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.SortUtils;
 import com.fs.course.domain.FsUserCourseTrainingCamp;
 import com.fs.course.dto.FsUserCourseTrainingCampDTO;

+ 15 - 0
fs-admin/src/main/java/com/fs/course/controller/FsUserCourseVideoController.java

@@ -4,15 +4,20 @@ import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.model.LoginUser;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.course.domain.FsUserCourse;
 import com.fs.course.domain.FsUserCourseVideo;
 import com.fs.course.mapper.FsUserCourseVideoMapper;
 import com.fs.course.param.BatchRedUpdate;
 import com.fs.course.param.BatchVideoSvae;
 import com.fs.course.param.CourseVideoUpdates;
+import com.fs.course.service.IFsUserCourseService;
 import com.fs.course.service.IFsUserCourseVideoService;
+import com.fs.framework.web.service.TokenService;
 import com.fs.his.vo.OptionsVO;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
@@ -39,6 +44,8 @@ public class FsUserCourseVideoController extends BaseController
 
     @Autowired
     private FsUserCourseVideoMapper fsUserCourseVideoMapper;
+    @Autowired
+    private IFsUserCourseService fsUserCourseService;
 
     /**
      * 查询课堂视频列表
@@ -87,6 +94,10 @@ public class FsUserCourseVideoController extends BaseController
         if (count>0){
             return AjaxResult.error("课程排序重复");
         }
+
+        // 设置项目ID
+        FsUserCourse fsUserCourse = fsUserCourseService.selectFsUserCourseByCourseId(fsUserCourseVideo.getCourseId());
+        fsUserCourseVideo.setProjectId(fsUserCourse.getProject());
         return toAjax(fsUserCourseVideoService.insertFsUserCourseVideo(fsUserCourseVideo));
     }
 
@@ -134,6 +145,10 @@ public class FsUserCourseVideoController extends BaseController
     }
     @PostMapping("/batchSaveVideo")
     public R batchSaveVideo(@RequestBody BatchVideoSvae vo){
+        // 设置项目ID
+        FsUserCourse fsUserCourse = fsUserCourseService.selectFsUserCourseByCourseId(vo.getCourseId());
+        vo.setProjectId(fsUserCourse.getProject());
+
         fsUserCourseVideoService.batchSaveVideo(vo);
         return R.ok();
     }

+ 6 - 0
fs-admin/src/main/java/com/fs/course/controller/FsUserTalentController.java

@@ -2,9 +2,12 @@ package com.fs.course.controller;
 
 import java.math.BigDecimal;
 import java.util.List;
+import java.util.Objects;
 
 import com.fs.common.core.domain.R;
 import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.his.utils.PhoneUtil;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -121,6 +124,9 @@ public class FsUserTalentController extends BaseController
     @GetMapping("/listBySearch")
     public R listBySearCh(FsUserTalent fsUserTalent)
     {
+        if (Objects.nonNull(fsUserTalent) && StringUtils.isNotBlank(fsUserTalent.getPhone())){
+            fsUserTalent.setPhone(PhoneUtil.encryptPhone(fsUserTalent.getPhone()));
+        }
         List<FsUserTalent> list = fsUserTalentService.selectFsUserTalentList(fsUserTalent);
         return R.ok().put("data",list);
     }

+ 145 - 0
fs-admin/src/main/java/com/fs/course/controller/FsUserWatchCourseStatisticsController.java

@@ -0,0 +1,145 @@
+package com.fs.course.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.course.domain.FsUserWatchCourseStatistics;
+import com.fs.course.service.IFsUserWatchCourseStatisticsService;
+import com.fs.course.vo.FsUserWatchCourseStatisticsExportVO;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 会员看课统计-按课程统计Controller
+ *
+ * @author fs
+ * @date 2025-06-16
+ */
+@RestController
+@RequestMapping("/course/userWatchCourseStatistics")
+public class FsUserWatchCourseStatisticsController extends BaseController
+{
+    @Autowired
+    private IFsUserWatchCourseStatisticsService fsUserWatchCourseStatisticsService;
+
+    /**
+     * 查询会员看课统计-按课程统计列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchCourseStatistics:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsUserWatchCourseStatistics fsUserWatchCourseStatistics)
+    {
+        startPage();
+        List<FsUserWatchCourseStatistics> list = fsUserWatchCourseStatisticsService.selectFsUserWatchCourseStatisticsList(fsUserWatchCourseStatistics);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出会员看课统计-按课程统计列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchCourseStatistics:export')")
+    @Log(title = "会员看课统计-按课程统计", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsUserWatchCourseStatistics fsUserWatchCourseStatistics)
+    {
+        List<FsUserWatchCourseStatistics> list = fsUserWatchCourseStatisticsService.selectFsUserWatchCourseStatisticsList(fsUserWatchCourseStatistics);
+        ExcelUtil<FsUserWatchCourseStatistics> util = new ExcelUtil<FsUserWatchCourseStatistics>(FsUserWatchCourseStatistics.class);
+        return util.exportExcel(list, "会员观看数据明细");
+    }
+
+    /**
+     * 获取会员看课统计-按课程统计详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchCourseStatistics:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsUserWatchCourseStatisticsService.selectFsUserWatchCourseStatisticsById(id));
+    }
+
+    /**
+     * 新增会员看课统计-按课程统计
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchCourseStatistics:add')")
+    @Log(title = "会员看课统计-按课程统计", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsUserWatchCourseStatistics fsUserWatchCourseStatistics)
+    {
+        return toAjax(fsUserWatchCourseStatisticsService.insertFsUserWatchCourseStatistics(fsUserWatchCourseStatistics));
+    }
+
+    /**
+     * 修改会员看课统计-按课程统计
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchCourseStatistics:edit')")
+    @Log(title = "会员看课统计-按课程统计", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsUserWatchCourseStatistics fsUserWatchCourseStatistics)
+    {
+        return toAjax(fsUserWatchCourseStatisticsService.updateFsUserWatchCourseStatistics(fsUserWatchCourseStatistics));
+    }
+
+    /**
+     * 删除会员看课统计-按课程统计
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchCourseStatistics:remove')")
+    @Log(title = "会员看课统计-按课程统计", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsUserWatchCourseStatisticsService.deleteFsUserWatchCourseStatisticsByIds(ids));
+    }
+
+    /**
+     * 查询会员观看数据明细汇总
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchCourseStatistics:listTotal')")
+    @GetMapping("/listTotal")
+    public TableDataInfo listTotal(FsUserWatchCourseStatistics fsUserWatchCourseStatistics)
+    {
+        startPage();
+        List<FsUserWatchCourseStatistics> list = fsUserWatchCourseStatisticsService.selectFsUserWatchCourseStatisticsListTotal(fsUserWatchCourseStatistics);
+        if(!list.isEmpty()){
+            for (FsUserWatchCourseStatistics userWatchCourseStatistics : list) {
+                userWatchCourseStatistics.setCompleteWatchRatePercent(userWatchCourseStatistics.getCompleteWatchRate() + "%");
+                userWatchCourseStatistics.setOnlineRatePercent(userWatchCourseStatistics.getOnlineRate() + "%");
+            }
+        }
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出会员看课统计-按课程汇总统计列表
+     */
+    @Log(title = "会员看课统计-按课程汇总统计", businessType = BusinessType.EXPORT)
+    @GetMapping("/exportTotal")
+    public AjaxResult exportTotal(FsUserWatchCourseStatistics fsUserWatchCourseStatistics)
+    {
+        List<FsUserWatchCourseStatistics> list = fsUserWatchCourseStatisticsService.selectFsUserWatchCourseStatisticsListTotal(fsUserWatchCourseStatistics);
+        List<FsUserWatchCourseStatisticsExportVO> listVO = list.stream().map(v -> {
+            FsUserWatchCourseStatisticsExportVO vo = new FsUserWatchCourseStatisticsExportVO();
+            BeanUtils.copyProperties(v, vo);
+            vo.setCompleteWatchRatePercent(v.getCompleteWatchRate() + "%");
+            vo.setOnlineRatePercent(v.getOnlineRate() + "%");
+            return vo;
+        }).collect(Collectors.toList());
+        ExcelUtil<FsUserWatchCourseStatisticsExportVO> util = new ExcelUtil<FsUserWatchCourseStatisticsExportVO>(FsUserWatchCourseStatisticsExportVO.class);
+        return util.exportExcel(listVO, "会员观看数据明细汇总");
+    }
+
+
+    @PostMapping("/test")
+    @ApiOperation("测试看课统计明细定时任务")
+    public void userCourseCountTask() {
+        fsUserWatchCourseStatisticsService.insertWatchCourseStatistics();
+    }
+}

+ 118 - 0
fs-admin/src/main/java/com/fs/course/controller/FsUserWatchStatisticsController.java

@@ -0,0 +1,118 @@
+package com.fs.course.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.course.domain.FsUserWatchStatistics;
+import com.fs.course.service.IFsUserWatchStatisticsService;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 会员看课统计-按营期统计Controller
+ *
+ * @author fs
+ * @date 2025-06-16
+ */
+@RestController
+@RequestMapping("/course/userWatchStatistics")
+public class FsUserWatchStatisticsController extends BaseController
+{
+    @Autowired
+    private IFsUserWatchStatisticsService fsUserWatchStatisticsService;
+
+    /**
+     * 查询会员看课统计-按营期统计列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchStatistics:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsUserWatchStatistics fsUserWatchStatistics)
+    {
+        startPage();
+        List<FsUserWatchStatistics> list = fsUserWatchStatisticsService.selectFsUserWatchStatisticsList(fsUserWatchStatistics);
+        if(!list.isEmpty()){
+            for (FsUserWatchStatistics userWatchStatistics : list) {
+                userWatchStatistics.setCompleteWatchRatePercent(userWatchStatistics.getCompleteWatchRate() + "%");
+                userWatchStatistics.setOnlineRatePercent(userWatchStatistics.getOnlineRate() + "%");
+            }
+        }
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出会员看课统计-按营期统计列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchStatistics:export')")
+    @Log(title = "会员看课统计-按营期统计", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsUserWatchStatistics fsUserWatchStatistics)
+    {
+        List<FsUserWatchStatistics> list = fsUserWatchStatisticsService.selectFsUserWatchStatisticsList(fsUserWatchStatistics);
+        if(!list.isEmpty()){
+            for (FsUserWatchStatistics userWatchStatistics : list) {
+                userWatchStatistics.setCompleteWatchRatePercent(userWatchStatistics.getCompleteWatchRate() + "%");
+                userWatchStatistics.setOnlineRatePercent(userWatchStatistics.getOnlineRate() + "%");
+            }
+        }
+        ExcelUtil<FsUserWatchStatistics> util = new ExcelUtil<FsUserWatchStatistics>(FsUserWatchStatistics.class);
+        return util.exportExcel(list, "会员看课统计-按营期统计数据");
+    }
+
+    /**
+     * 获取会员看课统计-按营期统计详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchStatistics:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsUserWatchStatisticsService.selectFsUserWatchStatisticsById(id));
+    }
+
+    /**
+     * 新增会员看课统计-按营期统计
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchStatistics:add')")
+    @Log(title = "会员看课统计-按营期统计", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsUserWatchStatistics fsUserWatchStatistics)
+    {
+        return toAjax(fsUserWatchStatisticsService.insertFsUserWatchStatistics(fsUserWatchStatistics));
+    }
+
+    /**
+     * 修改会员看课统计-按营期统计
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchStatistics:edit')")
+    @Log(title = "会员看课统计-按营期统计", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsUserWatchStatistics fsUserWatchStatistics)
+    {
+        return toAjax(fsUserWatchStatisticsService.updateFsUserWatchStatistics(fsUserWatchStatistics));
+    }
+
+    /**
+     * 删除会员看课统计-按营期统计
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchStatistics:remove')")
+    @Log(title = "会员看课统计-按营期统计", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsUserWatchStatisticsService.deleteFsUserWatchStatisticsByIds(ids));
+    }
+
+
+    @PostMapping("/test")
+    @ApiOperation("测试营期看课统计定时任务")
+    public void userCourseCountTask() {
+        fsUserWatchStatisticsService.insertStatistics();
+    }
+
+}

+ 4 - 0
fs-admin/src/main/java/com/fs/course/controller/FsVideoResourceController.java

@@ -5,13 +5,17 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.model.LoginUser;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
 import com.fs.course.domain.FsVideoResource;
 import com.fs.course.service.IFsVideoResourceService;
 import com.fs.course.vo.FsVideoResourceVO;
+import com.fs.framework.web.service.TokenService;
 import com.github.pagehelper.PageHelper;
 import lombok.AllArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 

+ 64 - 0
fs-admin/src/main/java/com/fs/his/controller/FsPackageSolarTermController.java

@@ -0,0 +1,64 @@
+package com.fs.his.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.his.domain.FsPackageSolarTerm;
+import com.fs.his.param.FsPackageSolarTermParam;
+import com.fs.his.service.IFsPackageSolarTermService;
+import com.fs.his.vo.FsPackageSolarTermVO;
+import lombok.AllArgsConstructor;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/his/packageSolarTerm")
+@AllArgsConstructor
+public class FsPackageSolarTermController extends BaseController {
+
+    private final IFsPackageSolarTermService solarTermService;
+
+    @PreAuthorize("@ss.hasPermi('his:packageSolarTerm:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsPackageSolarTermParam param) {
+        startPage();
+        List<FsPackageSolarTermVO> list = solarTermService.selectFsPackageSolarTermListVO(param);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('his:packageSolarTerm:query')")
+    @GetMapping(value = "/{solarTermId}")
+    public AjaxResult getInfo(@PathVariable Long solarTermId) {
+        return AjaxResult.success(solarTermService.selectFsPackageSolarTermVO(solarTermId));
+    }
+
+    @PreAuthorize("@ss.hasPermi('his:packageSolarTerm:add')")
+    @Log(title = "套餐包节气", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsPackageSolarTerm param) {
+        return toAjax(solarTermService.insertFsPackageSolarTerm(param));
+    }
+
+    @PreAuthorize("@ss.hasPermi('his:packageSolarTerm:edit')")
+    @Log(title = "套餐包节气", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsPackageSolarTerm param) {
+        return toAjax(solarTermService.updateFsPackageSolarTerm(param));
+    }
+
+    @PreAuthorize("@ss.hasPermi('his:packageSolarTerm:remove')")
+    @Log(title = "套餐包", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{solarTermIds}")
+    public AjaxResult remove(@PathVariable Long[] solarTermIds) {
+        return toAjax(solarTermService.deleteFsPackageSolarTermByIds(solarTermIds));
+    }
+
+    @GetMapping("/getOptions")
+    public AjaxResult getOptions() {
+        return AjaxResult.success(solarTermService.getOptions());
+    }
+}

+ 2 - 2
fs-admin/src/main/java/com/fs/his/controller/FsPhysicalReportTemplateFieldController.java

@@ -2,7 +2,7 @@ package com.fs.his.controller;
 
 import java.util.List;
 
-import com.baomidou.mybatisplus.extension.api.R;
+import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.model.LoginUser;
 import com.fs.common.exception.ServiceException;
 import com.fs.common.utils.ServletUtils;
@@ -114,7 +114,7 @@ public class FsPhysicalReportTemplateFieldController extends BaseController {
     @PostMapping("/getTemplateField/{templateId}")
     public R getTemplateField(@PathVariable String templateId) {
         if (StringUtils.isNull(templateId)) {
-            return R.failed("操作失败,模板ID不能为空!");
+            return R.error("操作失败,模板ID不能为空!");
         }
         return fsPhysicalReportTemplateFieldService.getTemplateField(templateId);
     }

+ 118 - 5
fs-admin/src/main/java/com/fs/his/controller/FsUserController.java

@@ -1,27 +1,44 @@
 package com.fs.his.controller;
 
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
+import java.util.stream.Collectors;
 
+import com.alibaba.fastjson.JSON;
 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.exception.CustomException;
 import com.fs.common.utils.ParseUtils;
 import com.fs.common.utils.SecurityUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.course.domain.FsUserWatchStatistics;
+import com.fs.course.mapper.FsUserWatchStatisticsMapper;
+import com.fs.course.service.IFsUserCompanyUserService;
 import com.fs.his.domain.FsUserAddress;
+import com.fs.his.enums.FsUserIntegralLogTypeEnum;
+import com.fs.his.mapper.FsUserMapper;
+import com.fs.his.param.FsUserAddIntegralTemplateParam;
+import com.fs.his.param.FsUserAddPointsParam;
 import com.fs.his.param.FsUserParam;
+import com.fs.his.service.IFsUserIntegralLogsService;
 import com.fs.his.utils.PhoneUtil;
 import com.fs.his.vo.FsUserExportListVO;
 import com.fs.his.vo.FsUserVO;
 import com.fs.his.vo.UserVo;
+import com.fs.qw.dto.UserProjectDTO;
 import com.fs.store.param.h5.FsUserPageListParam;
 import com.fs.store.vo.h5.FsUserPageListVO;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
+import com.google.common.collect.Lists;
 import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.session.ExecutorType;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PutMapping;
@@ -47,12 +64,20 @@ import static com.fs.his.utils.PhoneUtil.*;
  * @author fs
  * @date 2023-06-07
  */
+@Slf4j
 @RestController
 @RequestMapping("/his/user")
 public class FsUserController extends BaseController
 {
     @Autowired
     private IFsUserService fsUserService;
+    @Autowired
+    private IFsUserIntegralLogsService userIntegralLogsService;
+    @Autowired
+    private IFsUserCompanyUserService userCompanyUserService;
+
+    @Autowired
+    private SqlSessionFactory sqlSessionFactory;
 
     /**
      * 查询用户列表
@@ -65,6 +90,9 @@ public class FsUserController extends BaseController
         if (fsUser.getPhoneMk()!=null&&fsUser.getPhoneMk()!=""){
             fsUser.setPhone(encryptPhone(fsUser.getPhoneMk()));
         }
+        if(StringUtils.isNotEmpty(fsUser.getPhone())){
+            fsUser.setPhone(encryptPhone(fsUser.getPhone()));
+        }
         List<FsUserVO> list = fsUserService.selectFsUserListVO(fsUser);
         for (FsUserVO fsUserVO : list) {
             if(fsUserVO.getPhone() != null&&fsUserVO.getPhone()!=""){
@@ -80,6 +108,18 @@ public class FsUserController extends BaseController
         return getDataTable(list);
     }
 
+    @PreAuthorize("@ss.hasPermi('his:user:list')")
+    @GetMapping("/listProject")
+    public TableDataInfo listProject(FsUser fsUser)
+    {
+        startPage();
+        List<FsUserVO> list = fsUserService.selectFsUserVOListByProject(fsUser);
+        for (FsUserVO vo : list){
+            vo.setPhone(ParseUtils.parsePhone(vo.getPhone()));
+        }
+        return getDataTable(list);
+    }
+
     /**
      * 导出用户列表
      */
@@ -171,6 +211,17 @@ public class FsUserController extends BaseController
         return toAjax(fsUserService.deleteFsUserByUserIds(userIds));
     }
 
+    /**
+     * 删除微信用户和销售关系信息
+     */
+    @PreAuthorize("@ss.hasPermi('his:userCompanyUser:remove')")
+    @Log(title = "微信用户和销售关系", businessType = BusinessType.DELETE)
+    @DeleteMapping("/delete/{id}")
+    public AjaxResult delete(@PathVariable Long id)
+    {
+        return toAjax(userCompanyUserService.deleteFsUserCompanyUserById(id));
+    }
+
     /**
      * 查询用户
      */
@@ -188,6 +239,9 @@ public class FsUserController extends BaseController
     @GetMapping("/listBySearch")
     public R listBySearch(FsUser user)
     {
+        if (Objects.nonNull(user) && StringUtils.isNotBlank(user.getPhone())){
+            user.setPhone(PhoneUtil.encryptPhone(user.getPhone()));
+        }
         List<FsUser> list = fsUserService.selectFsUserList(user);
         return R.ok().put("data",list);
     }
@@ -211,9 +265,68 @@ public class FsUserController extends BaseController
     @PreAuthorize("@ss.hasPermi('his:user:enabledUsers')")
     @PostMapping("/enabledUsers")
     @ApiOperation("批量启用会员")
-    public ResponseResult<Boolean> enabledUsers(@RequestBody String[] ids) {
-        Boolean r = fsUserService.disabledUser(ids, true);
+    public ResponseResult<Boolean> enabledUsers(@RequestBody List<UserProjectDTO> ids) {
+        log.debug("批量启用会员 ids: {}", JSON.toJSONString(ids));
+        Boolean r = userCompanyUserService.batchUpdateUserProjectStatus(ids, 1);
         return ResponseResult.ok(r);
     }
 
+    @PreAuthorize("@ss.hasPermi('his:user:blacklist')")
+    @GetMapping("/blacklist")
+    @ApiOperation("黑名单")
+    public R blacklist(FsUserPageListParam param) {
+        PageInfo<FsUserPageListVO> fsUserPageListVOPageInfo = fsUserService.selectFsUserPageList(param);
+        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.getTotal());
+        return R.ok(map);
+    }
+
+    @PreAuthorize("@ss.hasPermi('his:user:enabledBlackUsers')")
+    @PostMapping("/enabledBlackUsers")
+    @ApiOperation("批量启用会员")
+    public ResponseResult<Boolean> enabledBlackUsers(@RequestBody List<UserProjectDTO> ids) {
+        log.debug("批量启用会员 ids: {}", JSON.toJSONString(ids));
+        Boolean r = userCompanyUserService.batchUpdateUserProjectStatus(ids, 1);
+        return ResponseResult.ok(r);
+    }
+
+    @PreAuthorize("@ss.hasPermi('his:user:addPoints')")
+    @PostMapping("/addPoints")
+    @ApiOperation("添加积分")
+    public R addPoints(@RequestBody @Validated FsUserAddPointsParam param) {
+        FsUserAddIntegralTemplateParam integralTemplateParam = new FsUserAddIntegralTemplateParam();
+        integralTemplateParam.setUserId(param.getUserId());
+        integralTemplateParam.setLogType(FsUserIntegralLogTypeEnum.TYPE_23.getValue());
+        integralTemplateParam.setBusinessId(SecurityUtils.getUserId().toString());
+        integralTemplateParam.setPoints(param.getPoint());
+        integralTemplateParam.setRemark(param.getRemark());
+        return userIntegralLogsService.addIntegralTemplate(integralTemplateParam);
+    }
+
+//    @PutMapping("/encryptPhoneTemp")
+//    @ApiOperation("临时接口")
+//    public void encryptPhoneTemp(){
+//        FsUser fsUser = new FsUser();
+//        List<FsUser> list = fsUserService.selectFsUserList(fsUser);
+//        List<FsUser> fsUserList = list.stream().peek(v -> v.setPhone(encryptPhone(v.getPhone()))).collect(Collectors.toList());
+//
+//        // 分批次处理,一次提交500条
+//        List<List<FsUser>> batches = Lists.partition(fsUserList, 500);
+//        batches.forEach(batch -> {
+//            SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
+//            try {
+//                FsUserMapper mapper = sqlSession.getMapper(FsUserMapper.class);
+//                batch.forEach(mapper::updateFsUser);
+//                sqlSession.commit();
+//            } finally {
+//                sqlSession.close();
+//            }
+//        });
+//
+//    }
+
 }

+ 121 - 0
fs-admin/src/main/java/com/fs/his/controller/FsUserOnlineStateController.java

@@ -0,0 +1,121 @@
+package com.fs.his.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.his.domain.FsUserOnlineState;
+import com.fs.his.service.IFsUserOnlineStateService;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+import java.util.List;
+
+import static com.fs.his.utils.PhoneUtil.decryptPhoneMk;
+import static com.fs.his.utils.PhoneUtil.encryptPhone;
+
+/**
+ * 用户上线情况Controller
+ *
+ * @author fs
+ * @date 2025-06-30
+ */
+@RestController
+@RequestMapping("/store/userOnlineState")
+public class FsUserOnlineStateController extends BaseController
+{
+    @Autowired
+    private IFsUserOnlineStateService fsUserOnlineStateService;
+
+    /**
+     * 查询用户上线情况列表
+     */
+    @PreAuthorize("@ss.hasPermi('store:userOnlineState:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsUserOnlineState fsUserOnlineState)
+    {
+        startPage();
+        if(StringUtils.isNotEmpty(fsUserOnlineState.getPhone())){
+            fsUserOnlineState.setPhone(encryptPhone(fsUserOnlineState.getPhone()));
+        }
+        List<FsUserOnlineState> list = fsUserOnlineStateService.selectFsUserOnlineStateList(fsUserOnlineState);
+        if(!list.isEmpty()){
+            for (FsUserOnlineState userOnlineState : list) {
+                if(userOnlineState.getPhone() != null && userOnlineState.getPhone() != ""){
+                    if (userOnlineState.getPhone().length()>11){
+                        userOnlineState.setPhone(decryptPhoneMk(userOnlineState.getPhone()));
+                    }else {
+                        userOnlineState.setPhone(userOnlineState.getPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                    }
+                }
+            }
+        }
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出用户上线情况列表
+     */
+    @PreAuthorize("@ss.hasPermi('store:userOnlineState:export')")
+    @Log(title = "用户上线情况", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsUserOnlineState fsUserOnlineState)
+    {
+        List<FsUserOnlineState> list = fsUserOnlineStateService.selectFsUserOnlineStateList(fsUserOnlineState);
+        ExcelUtil<FsUserOnlineState> util = new ExcelUtil<FsUserOnlineState>(FsUserOnlineState.class);
+        return util.exportExcel(list, "未上线会员");
+    }
+
+    /**
+     * 获取用户上线情况详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('store:userOnlineState:query')")
+    @GetMapping(value = "/{userId}")
+    public AjaxResult getInfo(@PathVariable("userId") Long userId)
+    {
+        return AjaxResult.success(fsUserOnlineStateService.selectFsUserOnlineStateById(userId));
+    }
+
+    /**
+     * 新增用户上线情况
+     */
+    @PreAuthorize("@ss.hasPermi('store:userOnlineState:add')")
+    @Log(title = "用户上线情况", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsUserOnlineState fsUserOnlineState)
+    {
+        return toAjax(fsUserOnlineStateService.insertFsUserOnlineState(fsUserOnlineState));
+    }
+
+    /**
+     * 修改用户上线情况
+     */
+    @PreAuthorize("@ss.hasPermi('store:userOnlineState:edit')")
+    @Log(title = "用户上线情况", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsUserOnlineState fsUserOnlineState)
+    {
+        return toAjax(fsUserOnlineStateService.updateFsUserOnlineState(fsUserOnlineState));
+    }
+
+    /**
+     * 删除用户上线情况
+     */
+    @PreAuthorize("@ss.hasPermi('store:userOnlineState:remove')")
+    @Log(title = "用户上线情况", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{userIds}")
+    public AjaxResult remove(@PathVariable Long[] userIds)
+    {
+        return toAjax(fsUserOnlineStateService.deleteFsUserOnlineStateByIds(userIds));
+    }
+
+    @ApiOperation("新增/更新未上线人员-定时任务")
+    @PostMapping("/testTask")
+    public void test(){
+        fsUserOnlineStateService.insertUserNotOnline();
+    }
+}

+ 20 - 0
fs-admin/src/main/java/com/fs/his/task/SendRedPacketTask.java

@@ -0,0 +1,20 @@
+package com.fs.his.task;
+
+import com.fs.course.service.IFsCourseRedPacketLogService;
+import com.fs.course.service.IFsUserCourseVideoRedPackageService;
+import com.fs.course.service.IFsUserCourseVideoService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service("sendRedPacketTask")
+public class SendRedPacketTask {
+    @Autowired
+    private IFsCourseRedPacketLogService redPacketLogService;
+
+    public void sendRedPacket(){
+        redPacketLogService.sendRedPacketBf();
+    }
+
+}

+ 56 - 0
fs-admin/src/main/java/com/fs/his/task/WatchCourseTask.java

@@ -0,0 +1,56 @@
+package com.fs.his.task;
+
+import com.fs.course.service.IFsUserWatchCourseStatisticsService;
+import com.fs.course.service.IFsUserWatchStatisticsService;
+import com.fs.erp.service.IErpOrderService;
+import com.fs.his.service.IFsUserOnlineStateService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * 定时任务调度测试
+ *
+ * @author fs
+ */
+@Component("storeTask")
+public class WatchCourseTask
+{
+    @Autowired
+    IErpOrderService erpOrderService;
+
+    @Autowired
+    private IFsUserWatchCourseStatisticsService fsUserWatchCourseStatisticsService;
+
+    @Autowired
+    private IFsUserWatchStatisticsService fsUserWatchStatisticsService;
+
+    @Autowired
+    private IFsUserOnlineStateService fsUserOnlineStateService;
+
+
+    /**
+     * 添加看课汇总统计
+     */
+    public void insertWatchStatistics(){
+        /***************************************进入营期会员看课汇总统计定时任务****************************************/
+        fsUserWatchStatisticsService.insertStatistics();
+        /***************************************营期会员看课汇总统计定时任务结束***************************************/
+    }
+
+    /**
+     * 添加看课明细统计
+     */
+    public void insertWatchCourseStatistics(){
+        /***************************************进入营期会员看课明细统计定时任务*******************************/
+        fsUserWatchCourseStatisticsService.insertWatchCourseStatistics();
+        /***************************************进入营期会员看课明细统计定时任务结束**********************************************/
+    }
+
+    /**
+     * 定时查询未上线的用户
+     */
+    public void insertUserNotOnline(){
+        fsUserOnlineStateService.insertUserNotOnline();
+    }
+
+}

+ 19 - 0
fs-admin/src/main/java/com/fs/qw/OrderTask.java

@@ -0,0 +1,19 @@
+package com.fs.qw;
+
+import com.fs.company.service.CompanyRechargeOrderService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component("orderTask")
+public class OrderTask {
+    @Autowired
+    private CompanyRechargeOrderService companyRechargeOrderService;
+
+
+    /**
+     * 自动关闭超时订单
+     */
+    public void autoCloseTimeOutOrder(){
+        companyRechargeOrderService.autoClosedOrder();
+    }
+}

+ 2 - 2
fs-admin/src/main/java/com/fs/qw/controller/QwUserController.java

@@ -1,6 +1,6 @@
 package com.fs.qw.controller;
 
-import com.baomidou.mybatisplus.extension.api.R;
+import com.fs.common.core.domain.R;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.qw.param.QwFsUserParam;
@@ -32,6 +32,6 @@ public class QwUserController extends BaseController {
      * **/
     @GetMapping("/getQwUserInfo")
     public R getQwUserInfo(QwFsUserParam param){
-        return R.ok(qwUserService.getQwUserInfo(param));
+        return R.ok().put("data",qwUserService.getQwUserInfo(param));
     }
 }

+ 11 - 0
fs-admin/src/main/java/com/fs/qw/qwTask/qwTask.java

@@ -3,6 +3,7 @@ package com.fs.qw.qwTask;
 import com.fs.course.service.IFsUserCourseService;
 import com.fs.qw.service.IQwExternalContactService;
 import com.fs.qw.service.IQwGroupMsgService;
+import com.fs.qw.service.IQwMaterialService;
 import com.fs.qw.service.IQwUserService;
 import com.fs.sop.service.impl.QwSopLogsServiceImpl;
 import com.fs.sop.service.impl.QwSopServiceImpl;
@@ -46,6 +47,10 @@ public class qwTask {
     @Autowired
     private IFsStatisQwWatchService fsStatisQwWatchService;
 
+    @Autowired
+    private IQwMaterialService iQwMaterialService;
+
+
     //正在使用
     public void qwExternalContact()
     {
@@ -188,4 +193,10 @@ public class qwTask {
         fsStatisQwWatchService.writeData(today.toString());
     }
 
+    /**
+    * 每俩天 更新一次 素材库
+    */
+    public void updateMaterialByTwoDays(){
+        iQwMaterialService.updateQwMaterialByQw();
+    }
 }

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

@@ -4,9 +4,10 @@ server:
 # Spring配置
 spring:
   profiles:
-    active: druid-myhk-test
+#    active: druid-myhk-test
 #    active: druid-hdt
 #    active: druid-yzt
 #    active: druid-sxjz
 #    active: druid-sft
+    active: druid-fby
 

+ 1 - 0
fs-common/src/main/java/com/fs/common/constant/FsConstants.java

@@ -10,4 +10,5 @@ public interface FsConstants {
     String REDIS_QW_appKey_Active = "qwActive:";
 
     String FRIEND_WELCOME_VIDEO_KEY = "friend:welcome:";
+    String REDIS_INTEGRAL_ORDER_UNPAY = "integral:order:unpay:";
 }

+ 6 - 0
fs-company-app/src/main/java/com/fs/app/controller/AppBaseController.java

@@ -37,6 +37,12 @@ public class AppBaseController {
 		String userId = claims.getSubject().toString();
 		return userId;
 	}
+	public Long getCompanyUserId() {
+		String headValue =  ServletUtils.getRequest().getHeader("APPToken");
+		Claims claims=jwtUtils.getClaimByToken(headValue);
+		String userId = claims.getSubject();
+		return Long.parseLong(userId);
+	}
 	//获取商城手机号
 	public Long getUserId(Long companyUserId)
 	{

+ 29 - 12
fs-company-app/src/main/java/com/fs/app/controller/CompanyTagController.java

@@ -1,7 +1,9 @@
 package com.fs.app.controller;
 
+import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSON;
 import com.fs.app.annotation.Login;
+import com.fs.app.param.TagProjectParam;
 import com.fs.common.core.domain.R;
 import com.fs.common.exception.CustomException;
 import com.fs.common.utils.StringUtils;
@@ -17,6 +19,7 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.HashMap;
@@ -41,8 +44,9 @@ public class CompanyTagController extends AppBaseController {
     @ApiOperation("查询公司标签列表")
     public R list(@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);
+                  @RequestParam(required = false, defaultValue = "10") Integer pageSize,
+                  @RequestParam(required = false) Long companyUserId) {
+        log.debug("查询公司标签列表 keyword: {}, pageNum: {}, pageSize: {}", keyword, pageNum, pageSize, companyUserId);
 
         Map<String, Object> params = new HashMap<>();
         params.put("companyId", getCompanyId());
@@ -51,13 +55,19 @@ public class CompanyTagController extends AppBaseController {
         }
 
         PageHelper.startPage(pageNum, pageSize);
-        List<CompanyTag> list = companyTagService.selectCompanyTagListByMap(params);
-        return R.ok().put("data", new PageInfo<>(list));
+        if (ObjectUtil.isNotEmpty(companyUserId)) {
+            params.put("companyUserId", companyUserId);
+            List<CompanyTag> list = companyTagService.selectCompanyTagByList(params);
+            return R.ok().put("data", new PageInfo<>(list));
+        } else {
+            List<CompanyTag> list = companyTagService.selectCompanyTagListByMap(params);
+            return R.ok().put("data", new PageInfo<>(list));
+        }
     }
 
-    /**
-     * 新增公司标签
-     */
+        /**
+         * 新增公司标签
+         */
     @Login
     @PostMapping("/add")
     @ApiOperation("新增公司标签")
@@ -81,13 +91,20 @@ public class CompanyTagController extends AppBaseController {
     }
 
     @Login
-    @GetMapping("/tagSubUsers")
+    @PostMapping("/tagSubUsers")
     @ApiOperation("标签下会员列表")
-    public R tagSubUsers(@RequestParam List<Long> tagId) {
+    public R tagSubUsers(@RequestBody TagProjectParam tagProjectParam) {
         Map<String, Object> params = new HashMap<>();
-        params.put("tagIds", tagId);
-        params.put("companyId", getCompanyId());
-        return R.ok().put("data", companyTagUserService.selectUserListByMap(params));
+        params.put("tagIds", tagProjectParam.getTagIds());
+        if (CollectionUtils.isNotEmpty(tagProjectParam.getProjectIds())){
+            params.put("projectIds", tagProjectParam.getProjectIds());
+        }
+        if (ObjectUtil.isEmpty(tagProjectParam.getCompanyUserId())){
+            params.put("companyUserId", getCompanyUserId());
+        }else {
+            params.put("companyUserId", tagProjectParam.getCompanyUserId());
+        }
+        return R.ok().put("data", companyTagUserService.selectUserByMap(params));
     }
 
     @Login

+ 100 - 17
fs-company-app/src/main/java/com/fs/app/controller/CompanyUserController.java

@@ -1,13 +1,11 @@
 package com.fs.app.controller;
 
+import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fs.app.annotation.Login;
-import com.fs.app.param.ChangeUserDeptAndPostParam;
-import com.fs.app.param.CompanyUserChangeApplyParam;
-import com.fs.app.param.CompanyUserParam;
-import com.fs.app.param.CompanyUserUpdateParam;
+import com.fs.app.param.*;
 import com.fs.app.service.IAppService;
 import com.fs.app.vo.CompanySubUserVO;
 import com.fs.common.annotation.RepeatSubmit;
@@ -18,14 +16,16 @@ import com.fs.common.utils.PatternUtils;
 import com.fs.common.utils.bean.BeanUtils;
 import com.fs.company.domain.*;
 import com.fs.company.mapper.CompanyRoleMapper;
-import com.fs.company.service.ICompanyDeptService;
-import com.fs.company.service.ICompanyService;
-import com.fs.company.service.ICompanyUserChangeApplyService;
-import com.fs.company.service.ICompanyUserService;
+import com.fs.company.service.*;
+import com.fs.company.vo.CompanyTagUserVO;
 import com.fs.company.vo.CompanyUserChangeApplyVO;
 import com.fs.core.security.SecurityUtils;
 import com.fs.course.service.IFsCourseRedPacketLogService;
 import com.fs.course.service.IFsCourseWatchLogService;
+import com.fs.course.service.IFsUserCompanyUserService;
+import com.fs.qw.dto.UserProjectDTO;
+import com.fs.system.service.ISysDictDataService;
+import com.fs.system.vo.DictVO;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.Api;
@@ -33,6 +33,8 @@ import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
 import javax.validation.Valid;
@@ -57,6 +59,12 @@ public class CompanyUserController extends AppBaseController {
     private final ICompanyUserChangeApplyService companyUserChangeApplyService;
     private final CompanyRoleMapper companyRoleMapper;
     private final IAppService appService;
+    @Autowired
+    private ISysDictDataService dictDataService;
+    @Autowired
+    private IFsUserCompanyUserService fsUserCompanyUserService;
+    @Autowired
+    private ICompanyTagUserService companyTagUserService;
 
     @Login
     @ApiOperation("查询用户列表")
@@ -165,13 +173,18 @@ public class CompanyUserController extends AppBaseController {
     @ApiOperation("注册")
     @PostMapping("/resisterCompanyUser")
     public R resisterCompanyUser(@Valid @RequestBody CompanyUserParam param) {
-        Company company = companyService.selectCompanyById(param.getCompanyId());
+        CompanyUser upCompanyUser = companyUserService.selectCompanyUserById(param.getCompanyUserId());
+        if (Objects.isNull(upCompanyUser)) {
+            return R.error("邀请销售不存在");
+        }
+
+        Company company = companyService.selectCompanyById(upCompanyUser.getCompanyId());
         if (Objects.isNull(company)) {
             return R.error("公司不存在");
         }
 
         // 判断用户数量是否已达到上线
-        Integer count = companyUserService.selectCompanyUserCountByCompanyId(param.getCompanyId());
+        Integer count = companyUserService.selectCompanyUserCountByCompanyId(upCompanyUser.getCompanyId());
         if(count > company.getLimitUserCount()) {
             return R.error("用户数量已达到上限");
         }
@@ -195,9 +208,10 @@ public class CompanyUserController extends AppBaseController {
         companyUser.setPassword(SecurityUtils.encryptPassword(companyUser.getPassword()));
         companyUser.setCreateTime(new Date());
         companyUser.setIsAudit(0);
+        companyUser.setParentId(upCompanyUser.getUserId());
 
         // 部门
-        CompanyDept dept = companyDeptService.getDefaultCompanyDeptByCompanyId(param.getCompanyId());
+        CompanyDept dept = companyDeptService.getDefaultCompanyDeptByCompanyId(upCompanyUser.getCompanyId());
         if (Objects.nonNull(dept)) {
             companyUser.setDeptId(dept.getDeptId());
         }
@@ -221,7 +235,7 @@ public class CompanyUserController extends AppBaseController {
     @RepeatSubmit
     @ApiOperation("更换会员归属申请")
     @PostMapping("/changeUserParentApply")
-    public R changeVipUser(@Valid @RequestBody CompanyUserChangeApplyParam param) {
+    public R changeVipUser(@RequestBody CompanyUserChangeApplyParam param) {
         // 参数校验
         CompanyUser fromUser = companyUserService.selectCompanyUserById(param.getFrom());
         if (Objects.isNull(fromUser)) {
@@ -233,12 +247,18 @@ public class CompanyUserController extends AppBaseController {
             throw new ServiceException("申请更换归属销售不存在");
         }
 
+        if (Objects.equals(fromUser.getUserId(), toUser.getUserId())) {
+            throw new ServiceException("申请更换归属销售不能与原归属销售相同");
+        }
+
         if (param.getType() != 0 && param.getType() != 1) {
             throw new ServiceException("类型不正确");
         }
 
-        if (param.getType() == 1 && (Objects.isNull(param.getIds()) || param.getIds().isEmpty())) {
-            throw new ServiceException("请先选择会员");
+        if (param.getType() == 1 && (CollectionUtils.isEmpty(param.getIds()))
+                &&(CollectionUtils.isEmpty(param.getProject()))
+                &&(CollectionUtils.isEmpty(param.getTagList()))) {
+            throw new ServiceException("请先选择会员!");
         }
 
         // 存在待审核的申请不能再次申请
@@ -248,14 +268,58 @@ public class CompanyUserController extends AppBaseController {
         if (companyUserChangeApplyService.count(applyWrapper) > 0) {
             throw new ServiceException("存在待审核申请");
         }
-
         CompanyUser companyUser = companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
-
+        List<UserProjectDTO> list = param.getIds();
+        if(CollectionUtils.isEmpty(list)){
+            List<UserProjectDTO> userProjectDTOS = addUserId(param.getProject(),param.getTagList(),param.getFrom());
+            if (CollectionUtils.isNotEmpty(userProjectDTOS)){
+                list.addAll(userProjectDTOS);
+            }
+        }
         // 添加申请
-        companyUserChangeApplyService.apply(param.getFrom(), param.getTo(), param.getType(), param.getIds(), companyUser.getCompanyId(), companyUser.getUserName());
+        companyUserChangeApplyService.apply(param.getFrom(), param.getTo(), param.getType(),list, companyUser.getCompanyId(), companyUser.getUserName());
         return R.ok();
     }
 
+    /**
+     * 查询标签和项目中的会员添加
+     * @param tagList
+     * @param companyUserId
+     * @return
+     */
+    private List<UserProjectDTO> addUserId(List<Long> projects, List<Long> tagList, Long companyUserId) {
+        // Prepare parameters map
+        Map<String, Object> params = new HashMap<>();
+
+        if (CollectionUtils.isNotEmpty(projects)) {
+            params.put("projectIds", projects);
+        } else {
+            params.put("tagIds", tagList);
+        }
+
+        // Set company user ID
+        Long effectiveCompanyUserId = ObjectUtil.isNotEmpty(companyUserId)
+                ? companyUserId
+                : getCompanyUserId();
+        params.put("companyUserId", effectiveCompanyUserId);
+
+        // Get data from service
+        List<CompanyTagUserVO> voList = companyTagUserService.selectUserByMap(params);
+        if (CollectionUtils.isEmpty(voList)) {
+            return Collections.emptyList();
+        }
+
+        // Transform data
+        return voList.stream()
+                .map(vo -> {
+                    UserProjectDTO dto = new UserProjectDTO();
+                    dto.setUserId(vo.getUserId());
+                    dto.setProjectId(vo.getProjectId());
+                    return dto;
+                })
+                .collect(Collectors.toList());
+    }
+
     @Login
     @ApiOperation("申请列表")
     @GetMapping("/applyList")
@@ -309,4 +373,23 @@ public class CompanyUserController extends AppBaseController {
         appService.changeUserDeptAndPost(param);
         return R.ok();
     }
+
+    @ApiOperation("查询指定公司中存在会员的项目")
+    @PostMapping("/getDictByKeyByProject")
+    public R getDictByKey(
+            @RequestBody TagProjectParam tagProjectParam){
+        List<DictVO> dictVOS=dictDataService.selectDictDataListByType("sys_course_project");
+        Map<String,Object> param = new HashMap<>();
+        param.put("tagIds",tagProjectParam.getTagIds());
+        param.put("companyUserId",tagProjectParam.getCompanyUserId());
+        List<Long> projectIds =fsUserCompanyUserService.selectFsUserCompanyUserList(param);
+        if (CollectionUtils.isEmpty(projectIds)){
+            return R.ok().put("data",new ArrayList<DictVO>());
+        }
+
+        List<DictVO> filteredDictVOS = dictVOS.stream()
+                .filter(dictVO -> projectIds.contains(Long.parseLong(dictVO.getDictValue())))
+                .collect(Collectors.toList());
+        return R.ok().put("data",filteredDictVOS);
+    }
 }

+ 50 - 14
fs-company-app/src/main/java/com/fs/app/controller/FsUserController.java

@@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.fs.app.annotation.Login;
 import com.fs.app.config.ImageStorageConfig;
+import com.fs.app.param.FsUserProjectUpdateParam;
 import com.fs.app.param.FsUserTagUpdateParam;
 import com.fs.app.param.FsUserUpdateParam;
 import com.fs.common.core.domain.R;
@@ -14,12 +15,15 @@ import com.fs.common.utils.StringUtils;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.service.ICompanyTagUserService;
 import com.fs.company.service.ICompanyUserService;
+import com.fs.course.domain.FsUserCompanyUser;
 import com.fs.course.param.CourseAnalysisParam;
 import com.fs.course.param.newfs.FsUserCourseBeMemberImageParam;
 import com.fs.course.param.newfs.FsUserCourseBeMemberParam;
+import com.fs.course.service.IFsUserCompanyUserService;
 import com.fs.course.service.IFsUserCourseService;
 import com.fs.course.vo.newfs.FsCourseAnalysisVO;
 import com.fs.his.domain.FsUser;
+import com.fs.his.service.IFsUserProjectTagService;
 import com.fs.his.service.IFsUserService;
 import com.fs.store.param.h5.FsUserPageListParam;
 import com.fs.store.param.h5.TagListParam;
@@ -46,6 +50,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 
+import static com.fs.his.utils.PhoneUtil.encryptPhone;
+
 @Slf4j
 @Api(tags = "用户会员相关接口")
 @RestController
@@ -72,11 +78,16 @@ public class FsUserController extends AppBaseController {
 
     @Autowired
     private ISysConfigService configService;
+    @Autowired
+    private IFsUserCompanyUserService userCompanyUserService;
+    @Autowired
+    private IFsUserProjectTagService userProjectTagService;
 
     @Login
     @PostMapping("/pageList")
     @ApiOperation("用户会员分页列表")
     public ResponseResult<PageInfo<FsUserPageListVO>> pageList(@RequestBody FsUserPageListParam param) {
+        log.debug("用户会员分页列表 param: {}", JSON.toJSONString(param));
         param.setUserId(Long.parseLong(getUserId()));
 //        PageHelper.startPage(param.getPageNum(), param.getPageSize());
         PageInfo<FsUserPageListVO> fsUserPageListVOPageInfo = fsUserService.selectFsUserPageList(param);
@@ -104,8 +115,9 @@ public class FsUserController extends AppBaseController {
     @GetMapping("/details")
     @ApiOperation("用户会员详情")
     public ResponseResult<UserDetailsVO> getUserDetails(@ApiParam(value = "用户id", required = true) @RequestParam Long userId,
+                                                        @ApiParam(value = "用户项目关联id", required = true) @RequestParam Long userCompanyId,
                                                         @ApiParam(value = "时间tab,不传表示查询全部,分别是:今天、昨天、前天、近七天", required = true) @RequestParam(required = false) String dateTag) {
-        UserDetailsVO userDetails = fsUserService.getUserDetails(Long.parseLong(getUserId()), userId, dateTag);
+        UserDetailsVO userDetails = fsUserService.getUserDetails(Long.parseLong(getUserId()), userId, dateTag,userCompanyId);
         return ResponseResult.ok(userDetails);
     }
 
@@ -113,9 +125,14 @@ public class FsUserController extends AppBaseController {
     @GetMapping("/tagList")
     @ApiOperation("用户会员标签列表")
     public ResponseResult<PageInfo<CompanyUserTagListVO>> getTagList(TagListParam param) {
+        log.debug("用户会员标签列表 param: {}", JSON.toJSONString(param));
         param.setUserId(Long.parseLong(getUserId()));
         PageHelper.startPage(param.getPageNum(), param.getPageSize());
-        List<CompanyUserTagListVO> tagList = companyTagUserService.getTagList(param);
+        List<CompanyUserTagListVO> tagList = userProjectTagService.getTagList(param);
+        CompanyUserTagListVO noTag = new CompanyUserTagListVO();
+        noTag.setTagId(0L);
+        noTag.setTagName("无标签");
+        tagList.add(0, noTag);
         PageInfo<CompanyUserTagListVO> pageInfo = new PageInfo<>(tagList);
         return ResponseResult.ok(pageInfo);
     }
@@ -123,22 +140,18 @@ public class FsUserController extends AppBaseController {
     @Login
     @PostMapping("/disabled")
     @ApiOperation("批量禁用会员")
-    public ResponseResult<Boolean> disabledUser(@ApiParam(value = "联系人id集合", required = true) @RequestBody String[] ids) {
-        Boolean r = fsUserService.disabledUser(ids, false);
+    public ResponseResult<Boolean> disabledUser(@ApiParam(value = "联系人id集合", required = true) @RequestBody List<Long> userCompanyUserIds) {
+        log.debug("批量禁用会员 ids: {}", JSON.toJSONString(userCompanyUserIds));
+        Boolean r = userCompanyUserService.batchUpdateStatus(userCompanyUserIds, 2);
         return ResponseResult.ok(r);
     }
 
     @Login
     @PostMapping("/enabled")
     @ApiOperation("批量启用会员")
-    public ResponseResult<Boolean> enabledUser(@ApiParam(value = "联系人id集合", required = true) @RequestBody String[] ids) {
-        // 如果存在重粉的数据,则禁止启用,需要提示
-        long companyUserId = Long.parseLong(getUserId());
-        Integer count = fsUserService.selectFsUserByUserIds(ids, companyUserId);
-        if(count > 0){
-            return ResponseResult.fail(400, "重粉会员不能移除小黑屋");
-        }
-        Boolean r = fsUserService.disabledUser(ids, true);
+    public ResponseResult<Boolean> enabledUser(@ApiParam(value = "联系人id集合", required = true) @RequestBody List<Long> userCompanyUserIds) {
+        log.debug("批量启用会员 ids: {}", JSON.toJSONString(userCompanyUserIds));
+        Boolean r = userCompanyUserService.batchUpdateStatus(userCompanyUserIds, 1);
         return ResponseResult.ok(r);
     }
 
@@ -260,11 +273,27 @@ public class FsUserController extends AppBaseController {
         return ResponseResult.ok();
     }
 
+    @Login
+    @ApiOperation("修改用户项目备注")
+    @PostMapping("/changeUserRemark")
+    public ResponseResult<Object> changeUserProjectRemark(@Valid @RequestBody FsUserProjectUpdateParam param) {
+        log.debug("修改用户备注 param:{}", JSON.toJSONString(param));
+        FsUserCompanyUser userCompanyUser = userCompanyUserService.selectFsUserCompanyUserById(param.getUserCompanyUserId());
+        if (Objects.isNull(userCompanyUser)) {
+            throw new ServiceException("用户不存在");
+        }
+
+        userCompanyUser.setRemark(param.getRemark());
+        userCompanyUserService.updateFsUserCompanyUser(userCompanyUser);
+        return ResponseResult.ok();
+    }
+
     @Login
     @ApiOperation("修改用户标签")
     @PostMapping("/changeUserTags")
     public ResponseResult<Object> changeUserTags(@Valid @RequestBody FsUserTagUpdateParam param) {
-        companyTagUserService.changeUserTags(param.getFsUserIds(), param.getTagIds());
+        log.debug("修改用户标签 param:{}", JSON.toJSONString(param));
+        userProjectTagService.addUserProjectTag(param.getUserCompanyUserIds(), param.getTagIds());
         return ResponseResult.ok();
     }
 
@@ -302,10 +331,10 @@ public class FsUserController extends AppBaseController {
         return ResponseResult.ok(fsUserService.companyUserSummaryCount(userId, companyUserId));
     }
 
-//    @Login
     @ApiOperation("会员关联绑定销售")
     @PostMapping("/beMember")
     public ResponseResult<Boolean> becomeMember(@Valid @RequestBody FsUserCourseBeMemberParam param) {
+        log.debug("会员关联绑定销售 param:{}", JSON.toJSONString(param));
         return fsUserService.becomeMember(param);
     }
 
@@ -350,4 +379,11 @@ public class FsUserController extends AppBaseController {
         userCourseCountService.insertFsUserCourseCountTask();
     }
 
+    @GetMapping("/test1")
+    @ApiOperation("1")
+    public void aa(String phone) {
+        String s = encryptPhone(phone);
+        System.out.println(s);
+    }
+
 }

+ 9 - 0
fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java

@@ -234,5 +234,14 @@ public class FsUserCourseVideoController extends AppBaseController {
         return fsUserCourseVideoService.setWatchCourseTime(collect);
     }
 
+    /**
+     * 获取跳转微信小程序的链接地址
+     */
+    @Login
+    @GetMapping("/getGotoWxAppLink")
+    @ApiOperation("获取跳转微信小程序的链接地址")
+    public ResponseResult<String> getGotoWxAppLink(String linkStr,String appid) {
+        return ResponseResult.ok(courseLinkService.getGotoWxAppLink(linkStr,appid));
+    }
 
 }

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

@@ -178,7 +178,7 @@ public class UserController extends AppBaseController {
                 throw new BaseException("此用户所属公司不存在或已停用");
             }
 
-            if (StringUtils.isNotEmpty(company.getCourseMiniAppId()) && !company.getCourseMiniAppId().equals(param.getAppId())){
+            if (StringUtils.isNotEmpty(company.getCourseMiniAppId()) && !company.getCourseMiniAppId().equals(param.getAppid())){
                 return R.error("登录用户不属于该小程序");
             }
 

+ 153 - 124
fs-company-app/src/main/java/com/fs/app/controller/WxCompanyUserController.java

@@ -11,14 +11,21 @@ import com.fs.app.param.LoginMaWxParam;
 import com.fs.app.utils.JwtUtils;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
+import com.fs.common.utils.IpUtil;
 import com.fs.common.utils.ServletUtils;
+import com.fs.company.domain.Company;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.service.ICompanyDeptService;
+import com.fs.company.service.ICompanyService;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.core.config.WxMaConfiguration;
 import com.fs.course.config.CourseMaConfig;
+import com.fs.course.domain.FsUserCompanyUser;
+import com.fs.course.service.IFsUserCompanyUserService;
 import com.fs.his.domain.FsUser;
+import com.fs.his.domain.FsUserWx;
 import com.fs.his.service.IFsUserService;
+import com.fs.his.service.IFsUserWxService;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.mapper.SysConfigMapper;
 import com.fs.wx.miniapp.config.WxMaProperties;
@@ -35,6 +42,9 @@ import org.springframework.web.bind.annotation.*;
 
 import java.util.Date;
 import java.util.List;
+import java.util.Objects;
+
+import static com.fs.his.utils.PhoneUtil.encryptPhone;
 
 @Api("微信小程序相关接口(暂废弃,后面再删除)")
 @RestController
@@ -43,164 +53,183 @@ import java.util.List;
 public class WxCompanyUserController extends AppBaseController {
     private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
-    @Autowired
-    private WxMaProperties maProperties;
-
     @Autowired
     JwtUtils jwtUtils;
-
-    @Autowired
-    RedisCache redisCache;
-
     @Autowired
     private ICompanyUserService companyUserService;
-
-    @Autowired
-    private ICompanyDeptService companyDeptService;
-
     @Autowired
     private IFsUserService userService;
-
     @Autowired
-    private SysConfigMapper sysConfigMapper;
+    private ICompanyService companyService;
+    @Autowired
+    private IFsUserCompanyUserService userCompanyUserService;
+    @Autowired
+    private IFsUserWxService fsUserWxService;
 
     @ApiOperation("小程序-授权登录")
     @PostMapping("/loginByMa")
     public R login(@RequestBody LoginMaWxParam param) {
+        log.info("=====================进入小程序授权登录, 入参: {}", param);
         if (StringUtils.isBlank(param.getCode())) {
             return R.error("code不存在");
         }
-        SysConfig sysConfig3 = sysConfigMapper.selectConfigByConfigKey("courseMa.config");
-        List<CourseMaConfig> courseMaConfigs = JSON.parseArray(sysConfig3.getConfigValue(), CourseMaConfig.class);
-        if (courseMaConfigs.isEmpty()){
-            return R.error("小程序配置为空");
+
+        // 特殊(需求设计:需要根据公司是否开启黑名单来设置会员初始化的状态)
+        Company company = companyService.selectCompanyById(param.getCompanyId());
+        if (company==null || company.getStatus()==0){
+            return R.error("注册失败团队已停用,或不存在!");
+        }
+
+        // 根据销售后台设置的  是否需要单独注册会员 来判断是否需要设置销售的值
+        CompanyUser companyUser = companyUserService.selectCompanyUserById(param.getCompanyUserId());;
+        if(companyUser == null || companyUser.getStatus().equals("1")){
+            return R.error("注册失败客服已停用,或不存在!");
         }
-        CourseMaConfig courseMaConfig = courseMaConfigs.get(0);
-        //获取第二个小程序配置,序号从0开始
-        final WxMaService wxService = WxMaConfiguration.getMaService(courseMaConfig.getAppid());
+//        if (company.getCourseMiniAppId() == null) {
+//            return R.error("小程序参数错误!");
+//        }
+//        if (!param.getAppId().equals(company.getCourseMiniAppId())){
+//            return R.error("无权限,");
+//        }
+
+        final WxMaService wxService = WxMaConfiguration.getMaService(param.getAppId());
         try {
             WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(param.getCode());
             this.logger.info(session.getSessionKey());
             this.logger.info(session.getOpenid());
-            // 解密
-            WxMaPhoneNumberInfo phoneNoInfo = wxService.getUserService().getPhoneNoInfo(session.getSessionKey(), param.getEncryptedData(), param.getIv());
-            WxMaUserInfo userInfo = wxService.getUserService().getUserInfo(session.getSessionKey(), param.getEncryptedData(), param.getIv());
-
-            //以下暂时注释,不需要往销售表添加数据
-//            CompanyUser companyUser = companyUserService.getCompanyUserByOpenId(session.getOpenid());
-//            String ip = IpUtil.getRequestIp();
-//
-////            // 如果公司id为空(表示可能是该公司的第一位销售管理员),则需要根据电话号码判断是否存在销售,如果不存在则提示
-////            if (param.getCompanyId() == null) {
-////                if (checkPhone == null) {
-////                    throw new CustomException("由于不是管理员,不能直接登录", 401);
-////                }
-////            }
-//            if (companyUser == null) {
-//                CompanyUser checkPhone = companyUserService.getCompanyUserByPhone(phoneNoInfo.getPhoneNumber());
-//                if (checkPhone != null) {
-//                    if (checkPhone.getMaOpenId() == null) {
-//                        companyUser = checkPhone;
-//                        companyUser.setMaOpenId(session.getOpenid());
-//                        companyUser.setUserId(companyUser.getUserId());
-//                        companyUser.setUpdateTime(new DateTime());
-//                        companyUser.setLoginIp(ip);
-//                        companyUserService.updateUserProfile(companyUser);
-//                    } else {
-//                        throw new CustomException("此手机号用户已存在");
-//                    }
-//                } else {
-//                    //新增
-//                    companyUser = new CompanyUser();
-//                    companyUser.setUserName(phoneNoInfo.getPhoneNumber());
-//                    companyUser.setNickName(userInfo.getNickName() == null ? "微信用户" : userInfo.getNickName());
-//                    companyUser.setPhonenumber(phoneNoInfo.getPhoneNumber());
-//                    companyUser.setSex(userInfo.getGender());
-//                    //密码初始化为123456
-//                    String pw = "123456";
-//                    companyUser.setPassword(SecurityUtils.encryptPassword(param.getPassword() == null ? pw : param.getPassword()));
-//                    companyUser.setCreateTime(new Date());
-//                    companyUser.setCompanyId(param.getCompanyId());
-//                    companyUser.setParentId(param.getParentCompanyUseId());
-//                    companyUser.setMaOpenId(session.getOpenid());
-//
-//                    //部门信息
-//                    CompanyDept dept = companyDeptService.getDefaultCompanyDeptByCompanyId(param.getCompanyId());
-//                    if (Objects.nonNull(dept)) {
-//                        companyUser.setDeptId(dept.getDeptId());
-//                    }
-//                    companyUserService.insertUser(companyUser);
-//                }
-//            } else {
-//                CompanyUser companyUserMp = new CompanyUser();
-//                companyUserMp.setPhonenumber(phoneNoInfo.getPhoneNumber());
-//                companyUserMp.setUserId(companyUser.getUserId());
-//                companyUserMp.setUpdateTime(new DateTime());
-//                companyUserMp.setLoginIp(ip);
-//                companyUserService.updateUserProfile(companyUser);
-//            }
-
-            // 添加会员表数据
-            FsUser user = userService.selectFsUserByMpOpenId(session.getOpenid());
-            if (user != null) {
-                //修改
-                FsUser userMap = new FsUser();
-                userMap.setUserId(user.getUserId());
-                userMap.setMpOpenId(session.getOpenid());
-                userMap.setUnionId(session.getUnionid());
-                userMap.setUpdateTime(new DateTime());
-                userMap.setNickName(userInfo.getNickName() != null ? userInfo.getNickName() : "微信用户");
-                userMap.setAvatar(userInfo.getAvatarUrl() != null ? userInfo.getAvatarUrl() : null);
-                userMap.setPhone(phoneNoInfo.getPhoneNumber());
-                userService.updateFsUser(userMap);
-            } else {
-                //新增
-                user = new FsUser();
-                user.setNickName(userInfo.getNickName() != null ? userInfo.getNickName() : "微信用户");
-                user.setAvatar(userInfo.getAvatarUrl() != null ? userInfo.getAvatarUrl() : null);
-                user.setStatus(1);
-                user.setMpOpenId(session.getOpenid());
-                user.setUnionId(session.getUnionid());
-                user.setCreateTime(new Date());
-                user.setPhone(phoneNoInfo.getPhoneNumber());
-                userService.insertFsUser(user);
+            this.logger.info(session.getUnionid());
+            if (StringUtils.isEmpty(session.getOpenid())){
+                return R.error("登陆失败,openid未授权,请稍后再试!");
+            }
+
+            if (param.getAuthType() == 2 && StringUtils.isEmpty(session.getUnionid())){
+                return R.error("未绑定开发平台,请联系管理员!");
+            }
+
+            // 手机号信息
+            WxMaPhoneNumberInfo phoneNoInfo = new WxMaPhoneNumberInfo();;
+            if (param.getAuthType()==1){
+                phoneNoInfo = wxService.getUserService().getPhoneNoInfo(session.getSessionKey(), param.getEncryptedData(), param.getIv());
+                if (StringUtils.isEmpty(phoneNoInfo.getPhoneNumber())){
+                    return R.error("授权失败,请联系客服!");
+                }
+            }
+
+            FsUser user = getUserByAuthType(param, wxService, session, phoneNoInfo);
+
+            // 3. 处理用户注册或更新
+            String ip = IpUtil.getRequestIp();
+            user = handleUserRegisterOrUpdate(user, param, session, phoneNoInfo, company, companyUser, ip);
+
+            FsUserCompanyUser userCompanyUser = userCompanyUserService.selectByUserIdAndProjectId(user.getUserId(), param.getProjectId());
+            if (Objects.nonNull(userCompanyUser) && !param.getCompanyUserId().equals(userCompanyUser.getCompanyUserId())){
+                return R.error(500, "该用户("+user.getUserId() + ")已成为其他销售会员");
             }
-            log.info("保存成功的用户信息user: {}, 用户id: {}", user, user.getUserId());
+
+            // 4. 处理用户与小程序的绑定
+            handleFsUserWx(user, param, session);
+
+            log.info("保存成功的用户信息user: {}, 用户id: {},小程序AppId:{}", user, user.getUserId(), param.getAppId());
             String token = jwtUtils.generateToken(user.getUserId());
-            // 返回一个写死的数据到前端
-            return R.ok("登录成功").put("token", token).put("phoneNumber", phoneNoInfo.getPhoneNumber()).put("nickName", "微信用户").put("user", user);
+            // 返回TOKEN和user
+            return R.ok("登录成功").put("token", token).put("user", user);
         } catch (WxErrorException e) {
             this.logger.error(e.getMessage(), e);
             return R.error("授权失败," + e.getMessage());
         }
     }
 
-    @Login(isMiniLogin = true)
-    @ApiOperation("获取销售通过小程序登录后的用户信息")
-    @GetMapping("/getMaUser")
-    public R getUserInfo() {
-        try {
-            CompanyUser companyUser = companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
-            if (companyUser == null) {
-                return R.error(401, "用户信息不存在");
+    /**
+     * 根据authType获取用户信息
+     */
+    private FsUser getUserByAuthType(LoginMaWxParam param, WxMaService wxService, WxMaJscode2SessionResult session, WxMaPhoneNumberInfo phoneNoInfo) throws WxErrorException {
+        FsUser user = null;
+        if (param.getAuthType() == 1) {
+            user = userService.selectFsUserByPhone(encryptPhone(phoneNoInfo.getPhoneNumber()));
+        } else {
+            // unionid判定唯一
+            if (StringUtils.isNotEmpty(session.getUnionid())) {
+                user = userService.selectFsUserByUnionId(session.getUnionid());
             }
-            return R.ok().put("user", companyUser);
-        } catch (Exception e) {
-            return R.error("操作异常");
         }
+        return user;
     }
 
     /**
-     * 特殊要求:销售小程序临时登录,登录后页面中还有一个之前常用的登录,所以为了区分,token名称不能跟之前的一样
-     *
-     * @return 用户id
+     * 处理用户注册或更新
      */
-    public String getUserId() {
-        String headValue = ServletUtils.getRequest().getHeader("UserToken");
-        Claims claims = jwtUtils.getClaimByToken(headValue);
-        String userId = claims.getSubject().toString();
-        return userId;
+    private FsUser handleUserRegisterOrUpdate(FsUser user, LoginMaWxParam param, WxMaJscode2SessionResult session, WxMaPhoneNumberInfo phoneNoInfo, Company company, CompanyUser companyUser, String ip) {
+        if (user == null) {
+            return createUser(param, session, phoneNoInfo, company, companyUser);
+        } else {
+            return updateUser(user, param, session, phoneNoInfo, company, companyUser);
+        }
+    }
+
+    /**
+     * 新增用户
+     */
+    private FsUser createUser(LoginMaWxParam param, WxMaJscode2SessionResult session, WxMaPhoneNumberInfo phoneNoInfo, Company company, CompanyUser companyUser) {
+        FsUser user = new FsUser();
+        user.setStatus((company != null ? company.getFsUserIsDefaultBlack() : 0) == 1 ? 0 : 1);
+        user.setUnionId(session.getUnionid() == null ? "" : session.getUnionid());
+        user.setCreateTime(new Date());
+        if (param.getAuthType() == 1 && phoneNoInfo != null) {
+            user.setPhone(phoneNoInfo.getPhoneNumber());
+        }
+        userService.insertFsUser(user);
+
+        if((companyUser.getIsAllowedAllRegister() == null || companyUser.getIsAllowedAllRegister() == 1)
+                && companyUser.getIsNeedRegisterMember() != null && companyUser.getIsNeedRegisterMember() != 1){
+            int defaultStatus = (company != null ? company.getFsUserIsDefaultBlack() : 0) == 1 ? 0 : 1;
+            userCompanyUserService.bindRelationship(user.getUserId(), param.getProjectId(), companyUser.getCompanyId(), companyUser.getUserId(), defaultStatus);
+        }
+        return user;
     }
 
+    /**
+     * 修改用户
+     */
+    private FsUser updateUser(FsUser user, LoginMaWxParam param, WxMaJscode2SessionResult session, WxMaPhoneNumberInfo phoneNoInfo, Company company, CompanyUser companyUser) {
+        FsUser userMap = new FsUser();
+        userMap.setUserId(user.getUserId());
+        userMap.setUnionId(session.getUnionid() == null ? "" : session.getUnionid());
+        userMap.setUpdateTime(new DateTime());
+        if (param.getAuthType() == 1 && phoneNoInfo != null) {
+            userMap.setPhone(phoneNoInfo.getPhoneNumber());
+        }
 
+        userService.updateFsUser(userMap);
+        return userMap;
+    }
+
+    /**
+     * 处理用户与小程序的绑定
+     */
+    private void handleFsUserWx(FsUser user, LoginMaWxParam param, WxMaJscode2SessionResult session) {
+        if (user == null) return;
+        // 尝试更新
+        boolean updated = fsUserWxService.lambdaUpdate()
+                .eq(FsUserWx::getFsUserId, user.getUserId())
+                .eq(FsUserWx::getAppId, param.getAppId())
+                .eq(FsUserWx::getOpenId, session.getOpenid())
+                .set(FsUserWx::getCompanyId, param.getCompanyId())
+                .set(FsUserWx::getUnionId, session.getUnionid() == null ? "" : session.getUnionid())
+                .set(FsUserWx::getUpdateTime, new Date())
+                .update();
+
+        // 如果更新失败(记录不存在),则插入
+        if (!updated) {
+            FsUserWx fsUserWx = new FsUserWx();
+            fsUserWx.setType(1);
+            fsUserWx.setFsUserId(user.getUserId());
+            fsUserWx.setCompanyId(param.getCompanyId());
+            fsUserWx.setAppId(param.getAppId());
+            fsUserWx.setOpenId(session.getOpenid());
+            fsUserWx.setUnionId(session.getUnionid() == null ? "" : session.getUnionid());
+            fsUserWx.setCreateTime(new Date());
+            fsUserWx.setUpdateTime(new Date());
+            fsUserWxService.save(fsUserWx);
+        }
+    }
 }

+ 14 - 1
fs-company-app/src/main/java/com/fs/app/param/CompanyUserChangeApplyParam.java

@@ -1,5 +1,6 @@
 package com.fs.app.param;
 
+import com.fs.qw.dto.UserProjectDTO;
 import lombok.Data;
 
 import javax.validation.constraints.NotNull;
@@ -22,8 +23,20 @@ public class CompanyUserChangeApplyParam {
      */
     @NotNull(message = "类型不能为空")
     private Integer type;
+
+    /**
+     * 项目id
+     */
+    private List<Long> project;
+
+
+    /**
+     * 标签id
+     */
+    private List<Long> tagList;
+
     /**
      * 需更换归属会员id集合
      */
-    private List<Long> ids;
+    private List<UserProjectDTO> ids;
 }

+ 5 - 3
fs-company-app/src/main/java/com/fs/app/param/CompanyUserParam.java

@@ -1,5 +1,6 @@
 package com.fs.app.param;
 
+import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import javax.validation.constraints.NotBlank;
@@ -9,10 +10,11 @@ import javax.validation.constraints.NotNull;
 public class CompanyUserParam {
 
     /**
-     * 公司ID
+     * 上级销售
      */
-    @NotNull(message = "公司ID不能为空")
-    private Long companyId;
+    @NotNull(message = "上级销售不能为空")
+    @ApiModelProperty("上级销售不能为空")
+    private Long companyUserId;
     /**
      * 手机号码
      */

+ 17 - 0
fs-company-app/src/main/java/com/fs/app/param/FsUserProjectUpdateParam.java

@@ -0,0 +1,17 @@
+package com.fs.app.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class FsUserProjectUpdateParam {
+
+    @ApiModelProperty("用户项目ID")
+    @NotNull(message = "用户项目ID不能为空")
+    private Long userCompanyUserId;
+
+    @ApiModelProperty("备注")
+    private String remark;
+}

+ 3 - 3
fs-company-app/src/main/java/com/fs/app/param/FsUserTagUpdateParam.java

@@ -11,9 +11,9 @@ public class FsUserTagUpdateParam {
     /**
      * 用户ID
      */
-    @ApiModelProperty("用户ID集合")
-    @NotEmpty(message = "用户ID不能为空")
-    private List<Long> fsUserIds;
+    @ApiModelProperty("用户项目ID集合")
+    @NotEmpty(message = "用户项目ID不能为空")
+    private List<Long> userCompanyUserIds;
     /**
      * 标签ID
      */

+ 22 - 0
fs-company-app/src/main/java/com/fs/app/param/LoginMaWxParam.java

@@ -4,6 +4,7 @@ import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
 import java.io.Serializable;
 
 @Data
@@ -19,6 +20,18 @@ public class LoginMaWxParam implements Serializable {
     @ApiModelProperty(value = "小程序加密算法的初始向量")
     private String iv;
 
+    @NotNull(message = "公司id不能为空")
+    @ApiModelProperty(value = "公司id")
+    private Long companyId;
+
+    @NotNull(message = "销售id不能为空")
+    @ApiModelProperty(value = "销售id")
+    private Long companyUserId;
+
+    @NotNull(message = "项目id不能为空")
+    @ApiModelProperty(value = "课程归属项目id")
+    private Long projectId;
+
 //    @ApiModelProperty(value = "公司id,如果不是第一位销售,都需要传")
 //    private Long companyId;
 
@@ -31,4 +44,13 @@ public class LoginMaWxParam implements Serializable {
 //    @ApiModelProperty(value = "用户密码")
 //    private String password;
 
+    /**
+     * 0:静默授权  1:手机号授权
+     */
+    @NotNull(message = "授权类型缺失")
+    @ApiModelProperty(value = "小程序授权类型")
+    private Integer authType;
+
+    private String appId;
+
 }

+ 5 - 1
fs-company-app/src/main/java/com/fs/app/param/LoginParam.java

@@ -1,5 +1,7 @@
 package com.fs.app.param;
 
+import com.fasterxml.jackson.annotation.JsonAlias;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
@@ -7,6 +9,7 @@ import javax.validation.constraints.NotBlank;
 
 
 @Data
+@JsonIgnoreProperties(ignoreUnknown = true)
 public class LoginParam {
     @NotBlank(message = "请填写帐号")
     private String account;
@@ -14,6 +17,7 @@ public class LoginParam {
     private String password;
 
     private String jpushId;
+    @JsonAlias({"appid", "appId"})
+    private String appid;
 
-    private String appId;
 }

+ 23 - 0
fs-company-app/src/main/java/com/fs/app/param/TagProjectParam.java

@@ -0,0 +1,23 @@
+package com.fs.app.param;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class TagProjectParam {
+    /**
+     * 销售id
+     */
+    private Long companyUserId;
+
+    /**
+     * 标签id
+     */
+    private List<Long> tagIds;
+
+    /**
+     * 项目id
+     */
+    private List<Long> projectIds;
+}

+ 5 - 1
fs-company/pom.xml

@@ -39,7 +39,11 @@
             <version>1.9.3</version>
         </dependency>
 
-
+        <dependency>
+            <groupId>com.github.javen205</groupId>
+            <artifactId>IJPay-All</artifactId>
+            <version>2.7.8</version>
+        </dependency>
         <!-- Mysql驱动包 -->
         <dependency>
             <groupId>mysql</groupId>

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

@@ -3,7 +3,7 @@ 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.core.domain.R;
 import com.fs.common.utils.ServletUtils;
 import com.fs.company.param.CompanyDomainBindParam;
 import com.fs.company.vo.CompanyDomainBindVo;
@@ -122,10 +122,10 @@ public class CompanyDomainBindController extends BaseController
     @PostMapping("/domainBatchBinding")
     public R domainBatchBinding(@RequestBody CompanyDomainBindParam param) {
         if (ObjectUtil.isEmpty(param.getCompanyIds()) || param.getCompanyIds().isEmpty()) {
-            return R.failed("绑定失败,至少有一条域名分配信息!");
+            return R.error("绑定失败,至少有一条域名分配信息!");
         }
         if (ObjectUtil.isEmpty(param.getCompanyUserIds()) || param.getCompanyUserIds().isEmpty()) {
-            return R.failed("绑定失败,至少有一条分配人员信息!");
+            return R.error("绑定失败,至少有一条分配人员信息!");
         }
 
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());

+ 34 - 0
fs-company/src/main/java/com/fs/company/controller/company/CompanyRechargeController.java

@@ -11,6 +11,8 @@ import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.company.domain.Company;
 import com.fs.company.domain.CompanyRecharge;
+import com.fs.company.domain.CompanyRechargeOrder;
+import com.fs.company.dto.RechargeDTO;
 import com.fs.company.service.ICompanyRechargeService;
 import com.fs.company.service.ICompanyService;
 import com.fs.company.util.OrderUtils;
@@ -72,6 +74,38 @@ public class CompanyRechargeController extends BaseController
     }
 
 
+    /**
+     * 充值
+     * @return AjaxResult
+     */
+    @PostMapping("/wxRecharge")
+    public AjaxResult recharge(@RequestBody RechargeDTO dto){
+        CompanyRechargeOrder companyRechargeOrder;
+        try {
+            LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+
+            dto.setCompanyId(loginUser.getCompany().getCompanyId());
+            dto.setUserId(loginUser.getUser().getUserId());
+            companyRechargeOrder = companyRechargeService.recharge(dto);
+        }catch (Exception e) {
+            logger.error("给公司充值失败",e);
+            return AjaxResult.error(e.getMessage());
+        }
+        return AjaxResult.success(companyRechargeOrder);
+    }
+
+    /**
+     * 查询订单
+     * @param orderNo 订单号
+     * @return AjaxResult
+     */
+    @GetMapping("/queryOrder")
+    public AjaxResult queryOrder(@RequestParam("orderNo") String orderNo) {
+        CompanyRechargeOrder order = companyRechargeService.queryOrder(orderNo);
+
+        return AjaxResult.success(order);
+    }
+
 
     /**
      * 新增充值

+ 76 - 0
fs-company/src/main/java/com/fs/company/controller/company/CompanyUserChangeApplyController.java

@@ -0,0 +1,76 @@
+package com.fs.company.controller.company;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.exception.ServiceException;
+import com.fs.common.utils.StringUtils;
+import com.fs.company.controller.param.CompanyUserChangeApplyAuditParam;
+import com.fs.company.service.ICompanyUserChangeApplyService;
+import com.fs.company.vo.CompanyUserChangeApplyVO;
+import com.fs.framework.security.SecurityUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 更换会员归属申请Controller
+ */
+@RestController
+@RequestMapping("/company/apply")
+public class CompanyUserChangeApplyController extends BaseController
+{
+    @Autowired
+    private ICompanyUserChangeApplyService companyUserChangeApplyService;
+
+    /**
+     * 查询更换会员归属申请列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:apply:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(@RequestParam(required = false) Integer status)
+    {
+        Map<String, Object> map = new HashMap<>();
+        map.put("status", status);
+        map.put("companyId", SecurityUtils.getLoginUser().getCompany().getCompanyId());
+
+        startPage();
+        List<CompanyUserChangeApplyVO> list = companyUserChangeApplyService.selectApplyListByMap(map);
+        return getDataTable(list);
+    }
+
+    /**
+     * 获取更换会员归属申请详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:apply:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(companyUserChangeApplyService.selectApplyDetailById(id));
+    }
+
+    /**
+     * 获取更换会员归属申请详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:apply:audit')")
+    @PostMapping(value = "/audit")
+    public AjaxResult audit(@Valid @RequestBody CompanyUserChangeApplyAuditParam param)
+    {
+        if (param.getStatus() != 1 && param.getStatus() != 2) {
+            throw new ServiceException("审核类型不正确");
+        }
+
+        if (param.getStatus() == 2 && StringUtils.isBlank(param.getReason())) {
+            throw new ServiceException("拒绝理由不能为空");
+        }
+
+        companyUserChangeApplyService.audit(param.getId(), param.getStatus(), param.getReason(), SecurityUtils.getUsername());
+        return AjaxResult.success();
+    }
+
+}

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

@@ -416,4 +416,16 @@ public class CompanyUserController extends BaseController
             return AjaxResult.error("操作失败");
         }
     }
+
+    @Log(title = "是否允许所有方式注册会员", businessType = BusinessType.UPDATE)
+    @PutMapping("/allowedAllRegister")
+    public AjaxResult isAllowedAllRegister(@RequestParam Boolean status, @RequestBody List<Long> userIds) {
+        Boolean r = companyUserService.isAllowedAllRegister(status, userIds);
+        if (r) {
+            return AjaxResult.success();
+        } else {
+            return AjaxResult.error("操作失败");
+        }
+    }
+
 }

+ 35 - 21
fs-company/src/main/java/com/fs/company/controller/course/FsCourseAnswerLogsController.java

@@ -1,6 +1,7 @@
 package com.fs.company.controller.course;
 
 import com.fs.common.annotation.Log;
+import com.fs.common.constant.HttpStatus;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.page.TableDataInfo;
@@ -44,16 +45,21 @@ public class FsCourseAnswerLogsController extends BaseController
     @GetMapping("/list")
     public TableDataInfo list(FsCourseAnswerLogsParam param)
     {
-
-        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         if (param.getPhoneMk() != null && param.getPhoneMk() != "") {
-            param.setPhone(encryptPhone(param.getPhoneMk()));
+            param.setPhone(param.getPhoneMk());
         }
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         param.setCompanyId( loginUser.getCompany().getCompanyId());
 
-        startPage();
-        List<FsCourseAnswerLogsListVO> list = fsCourseAnswerLogsService.selectFsCourseAnswerLogsListVO(param);
-        return getDataTable(list);
+        List<FsCourseAnswerLogsListVO> list = fsCourseAnswerLogsService.selectFsCourseAnswerLogsListVONew(param);
+        TableDataInfo rspData = new TableDataInfo();
+        rspData.setCode(HttpStatus.SUCCESS);
+        rspData.setMsg("查询成功");
+        rspData.setRows(list);
+        rspData.setTotal(fsCourseAnswerLogsService.selectFsCourseAnswerLogsListVONewCount(param));
+
+        return rspData;
     }
 
     /**
@@ -64,17 +70,22 @@ public class FsCourseAnswerLogsController extends BaseController
     public TableDataInfo myList(FsCourseAnswerLogsParam param)
     {
 
-
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         param.setCompanyId( loginUser.getCompany().getCompanyId());
-
+        param.setCompanyUserId(loginUser.getUser().getUserId());
         if (param.getPhoneMk() != null && param.getPhoneMk() != "") {
-            param.setPhone(encryptPhone(param.getPhoneMk()));
+            param.setPhone(param.getPhoneMk());
         }
-        startPage();
 
-        List<FsCourseAnswerLogsListVO> list = fsCourseAnswerLogsService.selectFsCourseAnswerLogsListVO(param);
-        return getDataTable(list);
+        List<FsCourseAnswerLogsListVO> list = fsCourseAnswerLogsService.selectFsCourseAnswerLogsListVONew(param);
+
+        TableDataInfo rspData = new TableDataInfo();
+        rspData.setCode(HttpStatus.SUCCESS);
+        rspData.setMsg("查询成功");
+        rspData.setRows(list);
+        rspData.setTotal(fsCourseAnswerLogsService.selectFsCourseAnswerLogsListVONewCount(param));
+
+        return rspData;
     }
     /**
      * 导出答题日志列表
@@ -85,31 +96,34 @@ public class FsCourseAnswerLogsController extends BaseController
     public AjaxResult export(FsCourseAnswerLogsParam param)
     {
 
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setCompanyId( loginUser.getCompany().getCompanyId());
+
         if (param.getPhoneMk() != null && param.getPhoneMk() != "") {
-            param.setPhone(encryptPhone(param.getPhoneMk()));
+            param.setPhone(param.getPhoneMk());
         }
-        List<FsCourseAnswerLogsListVO> list = fsCourseAnswerLogsService.selectFsCourseAnswerLogsListVO(param);
+        List<FsCourseAnswerLogsListVO> list = fsCourseAnswerLogsService.selectFsCourseAnswerLogsListVONew(param);
         ExcelUtil<FsCourseAnswerLogsListVO> util = new ExcelUtil<FsCourseAnswerLogsListVO>(FsCourseAnswerLogsListVO.class);
-        return util.exportExcel(list, "答题日志数据");
+        return util.exportExcel(list, "答题记录数据");
     }
 
     /**
-     * 导出答题日志列表
+     * 导出我的答题日志列表
      */
     @PreAuthorize("@ss.hasPermi('course:courseAnswerLog:myExport')")
-    @Log(title = "答题日志", businessType = BusinessType.EXPORT)
+    @Log(title = "我的答题日志", businessType = BusinessType.EXPORT)
     @GetMapping("/myExport")
     public AjaxResult myExport(FsCourseAnswerLogsParam param)
     {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         param.setCompanyId( loginUser.getCompany().getCompanyId());
-
+        param.setCompanyUserId(loginUser.getUser().getUserId());
         if (param.getPhoneMk() != null && param.getPhoneMk() != "") {
-            param.setPhone(encryptPhone(param.getPhoneMk()));
+            param.setPhone(param.getPhoneMk());
         }
-        List<FsCourseAnswerLogsListVO> list = fsCourseAnswerLogsService.selectFsCourseAnswerLogsListVO(param);
+        List<FsCourseAnswerLogsListVO> list = fsCourseAnswerLogsService.selectFsCourseAnswerLogsListVONew(param);
         ExcelUtil<FsCourseAnswerLogsListVO> util = new ExcelUtil<FsCourseAnswerLogsListVO>(FsCourseAnswerLogsListVO.class);
-        return util.exportExcel(list, "答题日志数据");
+        return util.exportExcel(list, "我的答题记录数据");
     }
 
 //    /**

+ 130 - 0
fs-company/src/main/java/com/fs/company/controller/course/FsCourseTrafficLogController.java

@@ -0,0 +1,130 @@
+package com.fs.company.controller.course;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.course.domain.FsCourseTrafficLog;
+import com.fs.course.param.FsCourseTrafficLogParam;
+import com.fs.course.service.IFsCourseTrafficLogService;
+import com.fs.course.service.IFsUserCourseService;
+import com.fs.course.vo.FsCourseTrafficLogListVO;
+import com.fs.framework.service.TokenService;
+import com.fs.his.vo.OptionsVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.time.LocalDateTime;
+import java.time.YearMonth;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+
+
+/**
+ * 短链课程流量记录Controller
+ *
+ * @author fs
+ * @date 2024-10-31
+ */
+@RestController
+@RequestMapping("/course/courseTrafficLog")
+public class FsCourseTrafficLogController extends BaseController
+{
+    @Autowired
+    private IFsCourseTrafficLogService fsCourseTrafficLogService;
+
+    @Autowired
+    private IFsUserCourseService fsUserCourseMapper;
+    @Autowired
+    private TokenService tokenService;
+
+    /**
+     * 查询短链课程流量记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseTrafficLog:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsCourseTrafficLogParam param)
+    {
+        startPage();
+        List<FsCourseTrafficLogListVO> list = fsCourseTrafficLogService.selectTrafficNew(param);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出短链课程流量记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseTrafficLog:export')")
+    @Log(title = "短链课程流量记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsCourseTrafficLogParam param)
+    {
+        if (param.getTime() != null) {
+            YearMonth yearMonth = param.getTime();
+            LocalDateTime startOfMonth = yearMonth.atDay(1).atStartOfDay();
+
+            LocalDateTime startOfNextMonth = yearMonth.plusMonths(1).atDay(1).atStartOfDay()
+                    .minusDays(1).withHour(23).withMinute(59).withSecond(59);
+            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+            param.setStartDate(startOfMonth.format(formatter));
+            param.setEndDate(startOfNextMonth.format(formatter));
+        }
+        List<FsCourseTrafficLogListVO> list = fsCourseTrafficLogService.selectTrafficByCompany(param);
+        ExcelUtil<FsCourseTrafficLogListVO> util = new ExcelUtil<FsCourseTrafficLogListVO>(FsCourseTrafficLogListVO.class);
+        return util.exportExcel(list, "短链课程流量记录数据");
+    }
+
+    /**
+     * 获取短链课程流量记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseTrafficLog:query')")
+    @GetMapping(value = "/{logId}")
+    public AjaxResult getInfo(@PathVariable("logId") Long logId)
+    {
+        return AjaxResult.success(fsCourseTrafficLogService.selectFsCourseTrafficLogByLogId(logId));
+    }
+
+    /**
+     * 新增短链课程流量记录
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseTrafficLog:add')")
+    @Log(title = "短链课程流量记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsCourseTrafficLog fsCourseTrafficLog)
+    {
+        return toAjax(fsCourseTrafficLogService.insertFsCourseTrafficLog(fsCourseTrafficLog));
+    }
+
+    /**
+     * 修改短链课程流量记录
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseTrafficLog:edit')")
+    @Log(title = "短链课程流量记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsCourseTrafficLog fsCourseTrafficLog)
+    {
+        return toAjax(fsCourseTrafficLogService.updateFsCourseTrafficLog(fsCourseTrafficLog));
+    }
+
+    /**
+     * 删除短链课程流量记录
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseTrafficLog:remove')")
+    @Log(title = "短链课程流量记录", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{logIds}")
+    public AjaxResult remove(@PathVariable Long[] logIds)
+    {
+        return toAjax(fsCourseTrafficLogService.deleteFsCourseTrafficLogByLogIds(logIds));
+    }
+
+    @GetMapping("/courseList")
+    public R courseList()
+    {
+        List<OptionsVO> optionsVOS = fsUserCourseMapper.selectFsUserCourseAllList();
+        return R.ok().put("list", optionsVOS);
+    }
+}

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

@@ -226,7 +226,6 @@ public class FsCourseWatchLogController extends BaseController
     {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         param.setCompanyId( loginUser.getCompany().getCompanyId());
-        param.setCompanyUserId( loginUser.getUser().getUserId());
         List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogListVO(param);
         ExcelUtil<FsCourseWatchLogListVO> util = new ExcelUtil<FsCourseWatchLogListVO>(FsCourseWatchLogListVO.class);
         return util.exportExcel(list, "短链课程看课记录数据");
@@ -241,7 +240,7 @@ public class FsCourseWatchLogController extends BaseController
     public AjaxResult myExport(FsCourseWatchLogListParam param)
     {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-//        param.setCompanyId( loginUser.getCompany().getCompanyId());
+        param.setCompanyId( loginUser.getCompany().getCompanyId());
         param.setCompanyUserId( loginUser.getUser().getUserId());
         List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogListVO(param);
         ExcelUtil<FsCourseWatchLogListVO> util = new ExcelUtil<FsCourseWatchLogListVO>(FsCourseWatchLogListVO.class);

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

@@ -0,0 +1,153 @@
+package com.fs.company.controller.course;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.course.domain.FsUserWatchCourseStatistics;
+import com.fs.course.service.IFsUserWatchCourseStatisticsService;
+import com.fs.course.vo.FsUserWatchCourseStatisticsExportVO;
+import com.fs.framework.security.LoginUser;
+import com.fs.framework.service.TokenService;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 会员看课统计-按课程统计Controller
+ *
+ * @author fs
+ * @date 2025-06-16
+ */
+@RestController
+@RequestMapping("/course/userWatchCourseStatistics")
+public class FsUserWatchCourseStatisticsController extends BaseController
+{
+    @Autowired
+    private IFsUserWatchCourseStatisticsService fsUserWatchCourseStatisticsService;
+    @Autowired
+    private TokenService tokenService;
+    /**
+     * 查询会员看课统计-按课程统计列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchCourseStatistics:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsUserWatchCourseStatistics fsUserWatchCourseStatistics)
+    {
+        startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        fsUserWatchCourseStatistics.setCompanyId( loginUser.getCompany().getCompanyId());
+        List<FsUserWatchCourseStatistics> list = fsUserWatchCourseStatisticsService.selectFsUserWatchCourseStatisticsList(fsUserWatchCourseStatistics);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('course:userWatchCourseStatistics:export')")
+    @Log(title = "会员看课统计-按课程统计", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsUserWatchCourseStatistics fsUserWatchCourseStatistics)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        fsUserWatchCourseStatistics.setCompanyId( loginUser.getCompany().getCompanyId());
+        List<FsUserWatchCourseStatistics> list = fsUserWatchCourseStatisticsService.selectFsUserWatchCourseStatisticsList(fsUserWatchCourseStatistics);
+        ExcelUtil<FsUserWatchCourseStatistics> util = new ExcelUtil<FsUserWatchCourseStatistics>(FsUserWatchCourseStatistics.class);
+        return util.exportExcel(list, "会员观看数据明细");
+    }
+
+    /**
+     * 查询会员观看数据明细汇总
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchCourseStatistics:listTotal')")
+    @GetMapping("/listTotal")
+    public TableDataInfo listTotal(FsUserWatchCourseStatistics fsUserWatchCourseStatistics)
+    {
+        startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        fsUserWatchCourseStatistics.setCompanyId( loginUser.getCompany().getCompanyId());
+        List<FsUserWatchCourseStatistics> list = fsUserWatchCourseStatisticsService.selectFsUserWatchCourseStatisticsListTotal(fsUserWatchCourseStatistics);
+        if(!list.isEmpty()){
+            for (FsUserWatchCourseStatistics userWatchCourseStatistics : list) {
+                userWatchCourseStatistics.setCompleteWatchRatePercent(userWatchCourseStatistics.getCompleteWatchRate() + "%");
+                userWatchCourseStatistics.setOnlineRatePercent(userWatchCourseStatistics.getOnlineRate() + "%");
+            }
+        }
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出会员看课统计-按课程汇总统计列表
+     */
+    @Log(title = "会员看课统计-按课程汇总统计", businessType = BusinessType.EXPORT)
+    @GetMapping("/exportTotal")
+    public AjaxResult exportTotal(FsUserWatchCourseStatistics fsUserWatchCourseStatistics)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        fsUserWatchCourseStatistics.setCompanyId( loginUser.getCompany().getCompanyId());
+        List<FsUserWatchCourseStatistics> list = fsUserWatchCourseStatisticsService.selectFsUserWatchCourseStatisticsListTotal(fsUserWatchCourseStatistics);
+        List<FsUserWatchCourseStatisticsExportVO> listVO = list.stream().map(v -> {
+            FsUserWatchCourseStatisticsExportVO vo = new FsUserWatchCourseStatisticsExportVO();
+            BeanUtils.copyProperties(v, vo);
+            vo.setCompleteWatchRatePercent(v.getCompleteWatchRate() + "%");
+            vo.setOnlineRatePercent(v.getOnlineRate() + "%");
+            return vo;
+        }).collect(Collectors.toList());
+        ExcelUtil<FsUserWatchCourseStatisticsExportVO> util = new ExcelUtil<FsUserWatchCourseStatisticsExportVO>(FsUserWatchCourseStatisticsExportVO.class);
+        return util.exportExcel(listVO, "会员观看数据明细汇总");
+    }
+    /**
+     * 获取会员看课统计-按课程统计详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchCourseStatistics:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsUserWatchCourseStatisticsService.selectFsUserWatchCourseStatisticsById(id));
+    }
+
+    /**
+     * 新增会员看课统计-按课程统计
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchCourseStatistics:add')")
+    @Log(title = "会员看课统计-按课程统计", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsUserWatchCourseStatistics fsUserWatchCourseStatistics)
+    {
+        return toAjax(fsUserWatchCourseStatisticsService.insertFsUserWatchCourseStatistics(fsUserWatchCourseStatistics));
+    }
+
+    /**
+     * 修改会员看课统计-按课程统计
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchCourseStatistics:edit')")
+    @Log(title = "会员看课统计-按课程统计", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsUserWatchCourseStatistics fsUserWatchCourseStatistics)
+    {
+        return toAjax(fsUserWatchCourseStatisticsService.updateFsUserWatchCourseStatistics(fsUserWatchCourseStatistics));
+    }
+
+    /**
+     * 删除会员看课统计-按课程统计
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchCourseStatistics:remove')")
+    @Log(title = "会员看课统计-按课程统计", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsUserWatchCourseStatisticsService.deleteFsUserWatchCourseStatisticsByIds(ids));
+    }
+
+
+    @PostMapping("/test")
+    @ApiOperation("测试看课统计明细定时任务")
+    public void userCourseCountTask() {
+        fsUserWatchCourseStatisticsService.insertWatchCourseStatistics();
+    }
+}

+ 106 - 0
fs-company/src/main/java/com/fs/company/controller/course/FsUserWatchStatisticsController.java

@@ -0,0 +1,106 @@
+package com.fs.company.controller.course;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.course.domain.FsUserWatchStatistics;
+import com.fs.course.service.IFsUserWatchStatisticsService;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 会员看课统计-按营期统计Controller
+ *
+ * @author fs
+ * @date 2025-06-16
+ */
+@RestController
+@RequestMapping("/course/userWatchStatistics")
+public class FsUserWatchStatisticsController extends BaseController
+{
+    @Autowired
+    private IFsUserWatchStatisticsService fsUserWatchStatisticsService;
+
+    /**
+     * 查询会员看课统计-按营期统计列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchStatistics:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsUserWatchStatistics fsUserWatchStatistics)
+    {
+        startPage();
+        List<FsUserWatchStatistics> list = fsUserWatchStatisticsService.selectFsUserWatchStatisticsList(fsUserWatchStatistics);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出会员看课统计-按营期统计列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchStatistics:export')")
+    @Log(title = "会员看课统计-按营期统计", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsUserWatchStatistics fsUserWatchStatistics)
+    {
+        List<FsUserWatchStatistics> list = fsUserWatchStatisticsService.selectFsUserWatchStatisticsList(fsUserWatchStatistics);
+        ExcelUtil<FsUserWatchStatistics> util = new ExcelUtil<FsUserWatchStatistics>(FsUserWatchStatistics.class);
+        return util.exportExcel(list, "会员看课统计-按营期统计数据");
+    }
+
+    /**
+     * 获取会员看课统计-按营期统计详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchStatistics:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsUserWatchStatisticsService.selectFsUserWatchStatisticsById(id));
+    }
+
+    /**
+     * 新增会员看课统计-按营期统计
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchStatistics:add')")
+    @Log(title = "会员看课统计-按营期统计", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsUserWatchStatistics fsUserWatchStatistics)
+    {
+        return toAjax(fsUserWatchStatisticsService.insertFsUserWatchStatistics(fsUserWatchStatistics));
+    }
+
+    /**
+     * 修改会员看课统计-按营期统计
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchStatistics:edit')")
+    @Log(title = "会员看课统计-按营期统计", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsUserWatchStatistics fsUserWatchStatistics)
+    {
+        return toAjax(fsUserWatchStatisticsService.updateFsUserWatchStatistics(fsUserWatchStatistics));
+    }
+
+    /**
+     * 删除会员看课统计-按营期统计
+     */
+    @PreAuthorize("@ss.hasPermi('course:userWatchStatistics:remove')")
+    @Log(title = "会员看课统计-按营期统计", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsUserWatchStatisticsService.deleteFsUserWatchStatisticsByIds(ids));
+    }
+
+
+    @PostMapping("/test")
+    @ApiOperation("测试营期看课统计定时任务")
+    public void userCourseCountTask() {
+        fsUserWatchStatisticsService.insertStatistics();
+    }
+
+}

+ 1 - 1
fs-company/src/main/java/com/fs/company/controller/fastGpt/FastGptChatSessionController.java

@@ -79,7 +79,7 @@ public class FastGptChatSessionController extends BaseController
     {
         FastGptChatSessionCVO sessionCVO = fastGptChatSessionService.selectFastGptChatSessionCVOBySessionId(sessionId);
 
-        List<FastGptChatMsgCVO> list = fastGptChatMsgService.selectFastGptChatMsgCVOBySessionId(sessionId);
+        List<FastGptChatMsgCVO> list = fastGptChatMsgService.selectFastGptChatMsgCVOBySessionId(sessionId,sessionCVO.getUserId());
 
         return R.ok().put("data",sessionCVO).put("list",list);
     }

+ 23 - 0
fs-company/src/main/java/com/fs/company/controller/param/CompanyUserChangeApplyAuditParam.java

@@ -0,0 +1,23 @@
+package com.fs.company.controller.param;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class CompanyUserChangeApplyAuditParam {
+    /**
+     * 申请记录ID
+     */
+    @NotNull(message = "申请记录ID不能为空")
+    private Long id;
+    /**
+     * 状态 0通过 1拒绝
+     */
+    @NotNull(message = "审核状态不能为空")
+    private Integer status;
+    /**
+     * 原因
+     */
+    private String reason;
+}

+ 8 - 0
fs-company/src/main/java/com/fs/company/controller/pay/WxPayApiController.java

@@ -0,0 +1,8 @@
+package com.fs.company.controller.pay;
+
+
+import com.ijpay.wxpay.WxPayApiConfig;
+
+public abstract class WxPayApiController {
+	public abstract WxPayApiConfig getApiConfig();
+}

+ 189 - 0
fs-company/src/main/java/com/fs/company/controller/pay/WxPayController.java

@@ -0,0 +1,189 @@
+package com.fs.company.controller.pay;
+
+
+import com.fs.common.core.domain.R;
+import com.fs.common.utils.StringUtils;
+import com.fs.company.controller.pay.bean.WxPayBean;
+import com.fs.company.domain.CompanyRecharge;
+import com.fs.company.service.ICompanyRechargeService;
+import com.fs.core.config.WxPayProperties;
+import com.github.binarywang.wxpay.util.SignUtils;
+import com.ijpay.core.enums.SignType;
+import com.ijpay.core.enums.TradeType;
+import com.ijpay.core.kit.HttpKit;
+import com.ijpay.core.kit.IpKit;
+import com.ijpay.core.kit.WxPayKit;
+import com.ijpay.wxpay.WxPayApi;
+import com.ijpay.wxpay.WxPayApiConfig;
+import com.ijpay.wxpay.WxPayApiConfigKit;
+import com.ijpay.wxpay.model.UnifiedOrderModel;
+import io.swagger.annotations.ApiParam;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.Map;
+
+@Controller
+@RequestMapping(value="/pay/wxPay")
+public class WxPayController extends WxPayApiController {
+
+    private final Logger log = LoggerFactory.getLogger(this.getClass());
+
+    @Autowired
+    WxPayBean wxPayBean;
+
+    private String notifyUrl;
+    private String refundNotifyUrl;
+
+    @Autowired
+    ICompanyRechargeService rechargeService;
+
+    @Autowired
+    private WxPayProperties wxPayProperties;
+
+
+    @Override
+    public WxPayApiConfig getApiConfig() {
+        WxPayApiConfig apiConfig;
+
+        try {
+            apiConfig = WxPayApiConfigKit.getApiConfig(wxPayBean.getAppId());
+        } catch (Exception e) {
+            apiConfig = WxPayApiConfig.builder()
+                    .appId(wxPayBean.getAppId())
+                    .mchId(wxPayBean.getMchId())
+                    .partnerKey(wxPayBean.getPartnerKey())
+                    .certPath(wxPayBean.getCertPath())
+                    .domain(wxPayBean.getDomain())
+                    .build();
+        }
+        notifyUrl = apiConfig.getDomain().concat("/pay/wxPay/payNotify");
+        refundNotifyUrl = apiConfig.getDomain().concat("/pay/wxPay/refundNotify");
+        return apiConfig;
+    }
+    @GetMapping("/test")
+    @ResponseBody
+    public WxPayBean test() {
+        return wxPayBean;
+    }
+
+    @GetMapping(value="/qrPay")
+    @ResponseBody
+    public R qrPay(
+            @ApiParam(required = true, name = "orderNo", value = "订单ID") @RequestParam(value = "orderNo", required = false) String orderNo,
+            @ApiParam(required = true, name = "orderType", value = "订单类型 1 充值") @RequestParam(value = "orderType", required = false) Integer orderType,
+            HttpServletRequest request){
+        if(orderType.equals(1)){
+            CompanyRecharge recharge=rechargeService.selectCompanyRechargeByNo(orderNo);
+            if(recharge==null){
+                return R.error("充值订单不存在");
+            }
+            if(recharge.getStatus()!=0){
+                return R.error("此订单已支付");
+            }
+            Integer money= recharge.getMoney().multiply(new BigDecimal(100)).intValue();
+            String ip = IpKit.getRealIp(request);
+            if (StringUtils.isEmpty(ip)) {
+                ip = "127.0.0.1";
+            }
+            WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();
+            Map<String, String> params = UnifiedOrderModel
+                    .builder()
+                    .appid(wxPayApiConfig.getAppId())
+                    .mch_id(wxPayApiConfig.getMchId())
+                    .nonce_str(WxPayKit.generateStr())
+                    .body("充值订单")
+                    .out_trade_no("recharge-"+recharge.getRechargeNo())
+                    .total_fee(money.toString())
+                    .spbill_create_ip(ip)
+                    .notify_url(notifyUrl)
+                    .trade_type(TradeType.NATIVE.getTradeType())
+                    .build()
+                    .createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
+
+            String xmlResult = WxPayApi.pushOrder(false, params);
+            log.info("统一下单:" + xmlResult);
+
+            Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
+
+            String returnCode = result.get("return_code");
+            String returnMsg = result.get("return_msg");
+            System.out.println(returnMsg);
+            if (!WxPayKit.codeIsOk(returnCode)) {
+                return R.error("error:" + returnMsg);
+            }
+            String resultCode = result.get("result_code");
+            if (!WxPayKit.codeIsOk(resultCode)) {
+                return R.error("error:" + returnMsg);
+            }
+            //生成预付订单success
+            //生成预付订单success
+            String qrCodeUrl = result.get("code_url");
+//            String name = order.getOrderNo()+".png";
+//            String filePath = FSConfig.getUploadPath();
+//            boolean encode = QrCodeKit.encode(qrCodeUrl, BarcodeFormat.QR_CODE, 3, ErrorCorrectionLevel.H, "png", 200, 200,
+//                    filePath +"/"+ File.separator + name);
+//            if (encode) {
+//                //在页面上显示
+//                order.setPayType(1);
+//                goodsOrderService.updateFsGoodsOrder(order);
+//                return R.ok().put("name",name);
+//            }
+            recharge.setPayType(1);
+            rechargeService.updateCompanyRecharge(recharge);
+            return R.ok().put("qr",qrCodeUrl);
+
+        }
+        return R.error("订单类型不正确");
+    }
+
+    @RequestMapping(value = "/payNotify",method={RequestMethod.POST, RequestMethod.GET})
+    @ResponseBody
+    public String payNotify(HttpServletRequest request) {
+        // 支付结果通用通知文档: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7
+        String xmlMsg = HttpKit.readData(request);
+        log.info("支付通知 {}", xmlMsg);
+        Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);
+        String returnCode = params.get("return_code");
+        // 微信支付订单号
+        String transaction_id = params.get("transaction_id");
+        // 商户订单号
+        String out_trade_no = params.get("out_trade_no");
+        // 注意重复通知的情况,同一订单号可能收到多次通知,请注意一定先判断订单状态
+        // 注意此处签名方式需与统一下单的签名类型一致1
+        if (SignUtils.checkSign(params, String.valueOf(SignType.HMACSHA256), wxPayProperties.getMchKey())) {
+            if (WxPayKit.codeIsOk(returnCode)) {
+                // 更新订单信息
+                // 发送通知等
+                String[] order=out_trade_no.split("-");
+                R r;
+                if (order[0].equals("recharge")) {
+                    r = rechargeService.payNotify(order[1],transaction_id);
+                    if (r.get("code").equals(200)) {
+                        Map<String, String> xml = new HashMap<String, String>(2);
+                        xml.put("return_code", "SUCCESS");
+                        xml.put("return_msg", "OK");
+                        return WxPayKit.toXml(xml);
+
+                    } else {
+                        return null;
+                    }
+                }
+            }
+        }
+        return null;
+
+    }
+
+
+
+
+
+
+}

+ 98 - 0
fs-company/src/main/java/com/fs/company/controller/pay/bean/AliPayBean.java

@@ -0,0 +1,98 @@
+package com.fs.company.controller.pay.bean;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.stereotype.Component;
+
+@Component
+@PropertySource("classpath:/pay/alipay.properties")
+@ConfigurationProperties(prefix = "alipay")
+public class AliPayBean {
+    private String appId;
+    private String privateKey;
+    private String publicKey;
+    private String appCertPath;
+    private String aliPayCertPath;
+    private String aliPayRootCertPath;
+    private String serverUrl;
+    private String domain;
+
+    public String getAppId() {
+        return appId;
+    }
+
+    public void setAppId(String appId) {
+        this.appId = appId;
+    }
+
+    public String getPrivateKey() {
+        return privateKey;
+    }
+
+    public void setPrivateKey(String privateKey) {
+        this.privateKey = privateKey;
+    }
+
+    public String getPublicKey() {
+        return publicKey;
+    }
+
+    public void setPublicKey(String publicKey) {
+        this.publicKey = publicKey;
+    }
+
+    public String getAppCertPath() {
+        return appCertPath;
+    }
+
+    public void setAppCertPath(String appCertPath) {
+        this.appCertPath = appCertPath;
+    }
+
+    public String getAliPayCertPath() {
+        return aliPayCertPath;
+    }
+
+    public void setAliPayCertPath(String aliPayCertPath) {
+        this.aliPayCertPath = aliPayCertPath;
+    }
+
+    public String getAliPayRootCertPath() {
+        return aliPayRootCertPath;
+    }
+
+    public void setAliPayRootCertPath(String aliPayRootCertPath) {
+        this.aliPayRootCertPath = aliPayRootCertPath;
+    }
+
+    public String getServerUrl() {
+        return serverUrl;
+    }
+
+    public void setServerUrl(String serverUrl) {
+        this.serverUrl = serverUrl;
+    }
+
+
+    public String getDomain() {
+        return domain;
+    }
+
+    public void setDomain(String domain) {
+        this.domain = domain;
+    }
+
+    @Override
+    public String toString() {
+        return "AliPayBean{" +
+                "appId='" + appId + '\'' +
+                ", privateKey='" + privateKey + '\'' +
+                ", publicKey='" + publicKey + '\'' +
+                ", appCertPath='" + appCertPath + '\'' +
+                ", aliPayCertPath='" + aliPayCertPath + '\'' +
+                ", aliPayRootCertPath='" + aliPayRootCertPath + '\'' +
+                ", serverUrl='" + serverUrl + '\'' +
+                ", domain='" + domain + '\'' +
+                '}';
+    }
+}

+ 71 - 0
fs-company/src/main/java/com/fs/company/controller/pay/bean/WxPayBean.java

@@ -0,0 +1,71 @@
+package com.fs.company.controller.pay.bean;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.stereotype.Component;
+
+@Component
+@PropertySource("classpath:/pay/wxpay.properties")
+@ConfigurationProperties(prefix = "wxpay")
+public class WxPayBean {
+    private String appId;
+    private String appSecret;
+    private String mchId;
+    private String partnerKey;
+    private String certPath;
+    private String domain;
+
+    public String getAppId() {
+        return appId;
+    }
+
+    public void setAppId(String appId) {
+        this.appId = appId;
+    }
+
+    public String getAppSecret() {
+        return appSecret;
+    }
+
+    public void setAppSecret(String appSecret) {
+        this.appSecret = appSecret;
+    }
+
+    public String getMchId() {
+        return mchId;
+    }
+
+    public void setMchId(String mchId) {
+        this.mchId = mchId;
+    }
+
+    public String getPartnerKey() {
+        return partnerKey;
+    }
+
+    public void setPartnerKey(String partnerKey) {
+        this.partnerKey = partnerKey;
+    }
+
+    public String getCertPath() {
+        return certPath;
+    }
+
+    public void setCertPath(String certPath) {
+        this.certPath = certPath;
+    }
+
+    public String getDomain() {
+        return domain;
+    }
+
+    public void setDomain(String domain) {
+        this.domain = domain;
+    }
+
+    @Override
+    public String toString() {
+        return "WxPayBean [appId=" + appId + ", appSecret=" + appSecret + ", mchId=" + mchId + ", partnerKey="
+                + partnerKey + ", certPath=" + certPath + ", domain=" + domain + "]";
+    }
+}

+ 106 - 0
fs-company/src/main/java/com/fs/company/controller/pay/bean/WxPayV3Bean.java

@@ -0,0 +1,106 @@
+package com.fs.company.controller.pay.bean;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.stereotype.Component;
+
+@Component
+@PropertySource("classpath:/pay/wxpay_v3.properties")
+@ConfigurationProperties(prefix = "v3")
+public class WxPayV3Bean {
+    private String appId;
+    private String keyPath;
+    private String certPath;
+    private String certP12Path;
+    private String platformCertPath;
+    private String mchId;
+    private String apiKey;
+    private String apiKey3;
+    private String domain;
+
+    public String getAppId() {
+        return appId;
+    }
+
+    public void setAppId(String appId) {
+        this.appId = appId;
+    }
+
+    public String getKeyPath() {
+        return keyPath;
+    }
+
+    public void setKeyPath(String keyPath) {
+        this.keyPath = keyPath;
+    }
+
+    public String getCertPath() {
+        return certPath;
+    }
+
+    public void setCertPath(String certPath) {
+        this.certPath = certPath;
+    }
+
+    public String getCertP12Path() {
+        return certP12Path;
+    }
+
+    public void setCertP12Path(String certP12Path) {
+        this.certP12Path = certP12Path;
+    }
+
+    public String getPlatformCertPath() {
+        return platformCertPath;
+    }
+
+    public void setPlatformCertPath(String platformCertPath) {
+        this.platformCertPath = platformCertPath;
+    }
+
+    public String getMchId() {
+        return mchId;
+    }
+
+    public void setMchId(String mchId) {
+        this.mchId = mchId;
+    }
+
+    public String getApiKey() {
+        return apiKey;
+    }
+
+    public void setApiKey(String apiKey) {
+        this.apiKey = apiKey;
+    }
+
+    public String getApiKey3() {
+        return apiKey3;
+    }
+
+    public void setApiKey3(String apiKey3) {
+        this.apiKey3 = apiKey3;
+    }
+
+    public String getDomain() {
+        return domain;
+    }
+
+    public void setDomain(String domain) {
+        this.domain = domain;
+    }
+
+    @Override
+    public String toString() {
+        return "WxPayV3Bean{" +
+                "keyPath='" + keyPath + '\'' +
+                ", certPath='" + certPath + '\'' +
+                ", certP12Path='" + certP12Path + '\'' +
+                ", platformCertPath='" + platformCertPath + '\'' +
+                ", mchId='" + mchId + '\'' +
+                ", apiKey='" + apiKey + '\'' +
+                ", apiKey3='" + apiKey3 + '\'' +
+                ", domain='" + domain + '\'' +
+                '}';
+    }
+}

+ 2 - 0
fs-company/src/main/java/com/fs/company/controller/qw/QwMaterialController.java

@@ -1,6 +1,7 @@
 package com.fs.company.controller.qw;
 
 import com.fs.common.annotation.Log;
+import com.fs.common.annotation.RepeatSubmit;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
@@ -101,6 +102,7 @@ public class QwMaterialController extends BaseController
     @PreAuthorize("@ss.hasPermi('qw:material:add')")
     @Log(title = "素材库", businessType = BusinessType.INSERT)
     @PostMapping
+    @RepeatSubmit
     public R add(@RequestBody QwMaterial qwMaterial) throws Exception {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         qwMaterial.setCreateUserId(loginUser.getUser().getUserId());

+ 16 - 0
fs-company/src/main/java/com/fs/company/controller/qw/QwSopLogsController.java

@@ -3,12 +3,15 @@ package com.fs.company.controller.qw;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.course.service.IFsCourseLinkService;
 import com.fs.framework.service.TokenService;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.dto.QwUserKeyDTO;
+import com.fs.qw.param.GenerateShortLinkParam;
 import com.fs.qw.service.IQwUserService;
 import com.fs.sop.domain.QwSopLogs;
 import com.fs.sop.params.QwSopLogsParam;
@@ -44,6 +47,9 @@ public class QwSopLogsController extends BaseController
     @Autowired
     private IQwUserService iQwUserService;
 
+    @Autowired
+    private IFsCourseLinkService linkService;
+
     /**
      * 查询企业微信SOP  定时任务列表
      */
@@ -180,4 +186,14 @@ public class QwSopLogsController extends BaseController
     {
         return toAjax(iQwSopLogsService.deleteQwSopLogsByIds(ids));
     }
+
+    /**
+     * 获取企业微信SOP  定时任务详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('qw:sopLogs:generate')")
+    @PostMapping("/generateShortLink")
+    public R generateShortLink(@RequestBody GenerateShortLinkParam param)
+    {
+        return linkService.getWxaCodeGenerateScheme(param.getLinkStr(), param.getAppId());
+    }
 }

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

@@ -191,6 +191,11 @@ public class QwUserController extends BaseController
     public R TwoCodeStatus(@RequestBody QwLoginHookParam loginParam){
         return qwUserService.getTwoCodeStatus(loginParam);
     }
+
+    @PostMapping("/getQwIpadStatus")
+    public R getQwIpadStatus(@RequestBody QwLoginHookParam loginParam){
+        return qwUserService.getLoginQwIpadStatus(loginParam);
+    }
     /**
     * 直接授权key
     */

+ 33 - 4
fs-company/src/main/java/com/fs/company/controller/store/FsUserController.java

@@ -1,5 +1,6 @@
 package com.fs.company.controller.store;
 
+import com.alibaba.fastjson.JSON;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
@@ -9,6 +10,7 @@ import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.course.service.IFsUserCompanyUserService;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.security.SecurityUtils;
 import com.fs.framework.service.TokenService;
@@ -19,11 +21,12 @@ import com.fs.his.service.IFsUserService;
 import com.fs.his.vo.FsUserExportListVO;
 import com.fs.his.vo.FsUserVO;
 import com.fs.his.vo.UserVo;
+import com.fs.qw.dto.UserProjectDTO;
 import com.fs.store.param.h5.FsUserPageListParam;
 import com.fs.store.vo.h5.FsUserPageListVO;
-import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.ApiOperation;
+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.*;
@@ -41,6 +44,7 @@ import static com.fs.his.utils.PhoneUtil.encryptPhone;
  * @author fs
  * @date 2023-06-07
  */
+@Slf4j
 @RestController
 @RequestMapping("/store/user")
 public class FsUserController extends BaseController
@@ -49,6 +53,8 @@ public class FsUserController extends BaseController
     private IFsUserService fsUserService;
     @Autowired
     private TokenService tokenService;
+    @Autowired
+    private IFsUserCompanyUserService userCompanyUserService;
 
     /**
      * 查询用户列表
@@ -240,15 +246,38 @@ public class FsUserController extends BaseController
         PageInfo<FsUserPageListVO> fsUserPageListVOPageInfo = fsUserService.selectFsUserPageList(param);
         Map<String, Object> map = new HashMap<String, Object>();
         map.put("rows", fsUserPageListVOPageInfo.getList());
-        map.put("total", fsUserPageListVOPageInfo.getList().size());
+        map.put("total", fsUserPageListVOPageInfo.getTotal());
         return R.ok(map);
     }
 
     @PreAuthorize("@ss.hasPermi('users:user:enabledUsers')")
     @PostMapping("/enabledUsers")
     @ApiOperation("批量启用会员")
-    public ResponseResult<Boolean> enabledUsers(@RequestBody String[] ids) {
-        Boolean r = fsUserService.disabledUser(ids, true);
+    public ResponseResult<Boolean> enabledUsers(@RequestBody List<UserProjectDTO> ids) {
+        log.debug("批量启用会员 ids: {}", JSON.toJSONString(ids));
+        Boolean r = userCompanyUserService.batchUpdateUserProjectStatus(ids, 1);
+        return ResponseResult.ok(r);
+    }
+
+    @PreAuthorize("@ss.hasPermi('users:user:blacklist')")
+    @GetMapping("/blacklist")
+    @ApiOperation("黑名单")
+    public R blacklist(FsUserPageListParam param) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setUserId(loginUser.getUser().getUserId());
+        PageInfo<FsUserPageListVO> fsUserPageListVOPageInfo = fsUserService.selectFsUserPageList(param);
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("rows", fsUserPageListVOPageInfo.getList());
+        map.put("total", fsUserPageListVOPageInfo.getTotal());
+        return R.ok(map);
+    }
+
+    @PreAuthorize("@ss.hasPermi('users:user:enabledBlackUsers')")
+    @PostMapping("/enabledBlackUsers")
+    @ApiOperation("批量启用会员")
+    public ResponseResult<Boolean> enabledBlackUsers(@RequestBody List<UserProjectDTO> ids) {
+        log.debug("批量启用会员 ids: {}", JSON.toJSONString(ids));
+        Boolean r = userCompanyUserService.batchUpdateUserProjectStatus(ids, 1);
         return ResponseResult.ok(r);
     }
 

+ 136 - 0
fs-company/src/main/java/com/fs/company/controller/store/FsUserOnlineStateController.java

@@ -0,0 +1,136 @@
+package com.fs.company.controller.store;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.framework.security.LoginUser;
+import com.fs.framework.service.TokenService;
+import com.fs.his.domain.FsUserOnlineState;
+import com.fs.his.service.IFsUserOnlineStateService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+import static com.fs.his.utils.PhoneUtil.decryptPhoneMk;
+import static com.fs.his.utils.PhoneUtil.encryptPhone;
+
+/**
+ * 用户上线情况Controller
+ *
+ * @author fs
+ * @date 2025-06-30
+ */
+@RestController
+@RequestMapping("/store/userOnlineState")
+public class FsUserOnlineStateController extends BaseController
+{
+    @Autowired
+    private IFsUserOnlineStateService fsUserOnlineStateService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    /**
+     * 查询用户上线情况列表
+     */
+    @PreAuthorize("@ss.hasPermi('store:userOnlineState:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsUserOnlineState fsUserOnlineState)
+    {
+        startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        // 如果是管理员,可以查询当前公司所有数据
+        if(loginUser.getUser().isAdmin()){
+            fsUserOnlineState.setCompanyId( loginUser.getCompany().getCompanyId());
+        } else{
+            fsUserOnlineState.setCompanyUserId( loginUser.getUser().getUserId());
+        }
+        if(StringUtils.isNotEmpty(fsUserOnlineState.getPhone())){
+            fsUserOnlineState.setPhone(encryptPhone(fsUserOnlineState.getPhone()));
+        }
+        List<FsUserOnlineState> list = fsUserOnlineStateService.selectFsUserOnlineStateList(fsUserOnlineState);
+        if(!list.isEmpty()){
+            for (FsUserOnlineState userOnlineState : list) {
+                if(userOnlineState.getPhone() != null && userOnlineState.getPhone() != ""){
+                    if (userOnlineState.getPhone().length()>11){
+                        userOnlineState.setPhone(decryptPhoneMk(userOnlineState.getPhone()));
+                    }else {
+                        userOnlineState.setPhone(userOnlineState.getPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                    }
+                }
+            }
+        }
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出用户上线情况列表
+     */
+    @PreAuthorize("@ss.hasPermi('store:userOnlineState:export')")
+    @Log(title = "用户上线情况", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsUserOnlineState fsUserOnlineState)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        // 如果是管理员,可以查询当前公司所有数据
+        if(loginUser.getUser().isAdmin()){
+            fsUserOnlineState.setCompanyId( loginUser.getCompany().getCompanyId());
+        } else{
+            fsUserOnlineState.setCompanyUserId( loginUser.getUser().getUserId());
+        }
+        List<FsUserOnlineState> list = fsUserOnlineStateService.selectFsUserOnlineStateList(fsUserOnlineState);
+        ExcelUtil<FsUserOnlineState> util = new ExcelUtil<FsUserOnlineState>(FsUserOnlineState.class);
+        return util.exportExcel(list, "未上线会员");
+    }
+
+    /**
+     * 获取用户上线情况详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('store:userOnlineState:query')")
+    @GetMapping(value = "/{userId}")
+    public AjaxResult getInfo(@PathVariable("userId") Long userId)
+    {
+        return AjaxResult.success(fsUserOnlineStateService.selectFsUserOnlineStateById(userId));
+    }
+
+    /**
+     * 新增用户上线情况
+     */
+    @PreAuthorize("@ss.hasPermi('store:userOnlineState:add')")
+    @Log(title = "用户上线情况", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsUserOnlineState fsUserOnlineState)
+    {
+        return toAjax(fsUserOnlineStateService.insertFsUserOnlineState(fsUserOnlineState));
+    }
+
+    /**
+     * 修改用户上线情况
+     */
+    @PreAuthorize("@ss.hasPermi('store:userOnlineState:edit')")
+    @Log(title = "用户上线情况", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsUserOnlineState fsUserOnlineState)
+    {
+        return toAjax(fsUserOnlineStateService.updateFsUserOnlineState(fsUserOnlineState));
+    }
+
+    /**
+     * 删除用户上线情况
+     */
+    @PreAuthorize("@ss.hasPermi('store:userOnlineState:remove')")
+    @Log(title = "用户上线情况", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{userIds}")
+    public AjaxResult remove(@PathVariable Long[] userIds)
+    {
+        return toAjax(fsUserOnlineStateService.deleteFsUserOnlineStateByIds(userIds));
+    }
+
+}

+ 1 - 0
fs-company/src/main/java/com/fs/framework/config/SecurityConfig.java

@@ -119,6 +119,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
                 .antMatchers("/msg").anonymous()
                 .antMatchers("/common/getId**").anonymous()
                 .antMatchers("/common/uploadOSS**").anonymous()
+                .antMatchers("/pay/wxPay/payNotify**").anonymous()
                 .antMatchers("/common/uploadWang**").anonymous()
                 .antMatchers("/common/download**").anonymous()
                 .antMatchers("/common/download/resource**").anonymous()

+ 25 - 2
fs-company/src/main/java/com/fs/user/FsUserAdminController.java

@@ -8,17 +8,18 @@ import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.StringUtils;
 import com.fs.company.cache.ICompanyUserCacheService;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
 
 import com.fs.his.domain.FsUser;
 import com.fs.his.service.IFsUserService;
+import com.fs.his.utils.PhoneUtil;
 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 com.fs.store.vo.h5.FsUserPageListVO;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.AllArgsConstructor;
@@ -29,7 +30,7 @@ import org.springframework.web.bind.annotation.*;
 
 import java.util.Date;
 
-import static com.fs.his.utils.PhoneUtil.decryptAutoPhoneMk;
+import static com.fs.his.utils.PhoneUtil.encryptPhone;
 
 @Api(tags = "会员管理接口")
 @RestController
@@ -63,9 +64,31 @@ public class FsUserAdminController extends BaseController {
         }else {
             param.setCompanyId(loginUser.getCompany().getCompanyId());
         }
+        if(param.getPhone()!=null && !"".equals(param.getPhone())){
+            param.setPhone(PhoneUtil.encryptPhone(param.getPhone()));
+        }
 //        if(param.getCompanyUserId() == null) {
 //            throw new IllegalArgumentException("当前销售不存在!");
 //        }
+        if(StringUtils.isNotEmpty(param.getPhone())){
+            param.setPhone(encryptPhone(param.getPhone()));
+        }
+        return fsUserService.selectFsUserPageListNew(param);
+    }
+
+    @PreAuthorize("@ss.hasPermi('user:fsUser:myList')")
+    @PostMapping("/myList")
+    @ApiOperation("我的会员列表(与移动端使用的相同查询)")
+    public TableDataInfo pageMyList(@RequestBody FsUserPageListParam param) {
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setCompanyId(loginUser.getCompany().getCompanyId());
+        param.setCompanyUserId(String.valueOf(loginUser.getUser().getUserId()));
+        param.setIsAdmin(loginUser.getUser().isAdmin());
+
+        if(param.getCompanyUserId() == null) {
+            throw new IllegalArgumentException("当前销售不存在!");
+        }
         return fsUserService.selectFsUserPageListNew(param);
     }
 

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

@@ -4,10 +4,11 @@ server:
 spring:
   profiles:
 #    active: druid-fcky-test
-    active: dev
-#    active: druid-jzzx
+#    active: dev
+#    active: druid-jzzx-test
 #    active: druid-hdt
 #    active: druid-sxjz
 #    active: druid-yzt
 #    active: druid-myhk
 #    active: druid-sft
+    active: druid-hzyy

+ 8 - 5
fs-doctor-app/src/main/java/com/fs/app/controller/InquiryOrderController.java

@@ -51,10 +51,7 @@ import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 import static com.fs.his.utils.PhoneUtil.decryptPhone;
 
@@ -98,7 +95,13 @@ public class InquiryOrderController extends  AppBaseController {
     {
         FsDoctor doctor=doctorService.selectFsDoctorByDoctorId(Long.parseLong(getDoctorId()));
         PageHelper.startPage(param.getPageNum(), param.getPageSize());
-        param.setDoctorId(Long.parseLong(getDoctorId()));
+
+        if (Objects.nonNull(param.getUserId())) {
+            param.setDoctorId(null);
+        } else if (Objects.nonNull(param.getDoctorId())) {
+            param.setDoctorId(Long.parseLong(getDoctorId()));
+        }
+
         param.setIsAccept(doctor.getIsAccept());
         param.setIsSelf(doctor.getIsSelf());
         List<FsInquiryOrderListPDVO> list = inquiryOrderService.selectFsInquiryOrderListPDVO(param);

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

@@ -163,7 +163,7 @@ public class SendMsg {
             Long time = redisCache.getCacheObject(key);
             if (redisCache.getCacheObject(key) != null) {
                 log.error("{}已有发送:{}, :{}", qwUser.getQwUserName(), qwSopLogs.getId(), time);
-                return;
+                continue;
             }
             redisCache.setCacheObject(key, System.currentTimeMillis(), 10, TimeUnit.MINUTES);
             for (QwSopCourseFinishTempSetting.Setting content : setting.getSetting()) {

+ 49 - 0
fs-qw-api-msg/src/main/java/com/fs/app/config/QWConfigProperties.java

@@ -0,0 +1,49 @@
+package com.fs.app.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+@Component
+public class QWConfigProperties {
+
+    @Value("${custom.token}")
+    private String token;
+
+    @Value("${custom.encoding-aes-key}")
+    private String encodingAesKey;
+
+    @Value("${custom.corp-id}")
+    private String corpId;
+    @Value("${custom.secret}")
+    private String secret;
+
+    @Value("${custom.private-key-path}")
+    private String privateKeyPath;
+
+    @Value("${custom.webhook-url}")
+    private String webhookUrl;
+
+    public String getToken() {
+        return token;
+    }
+
+    public String getEncodingAesKey() {
+        return encodingAesKey;
+    }
+
+    public String getCorpId() {
+        return corpId;
+    }
+
+    public String getSecret() {
+        return secret;
+    }
+
+    public String getPrivateKeyPath() {
+        return privateKeyPath;
+    }
+
+    public String getWebhookUrl() {
+        return webhookUrl;
+    }
+}

+ 182 - 13
fs-qw-api-msg/src/main/java/com/fs/app/controller/QwMsgController.java

@@ -1,12 +1,22 @@
 package com.fs.app.controller;
 
 import com.alibaba.fastjson.JSON;
+import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.uuid.IdUtils;
 import com.fs.fastGpt.service.AiHookService;
+import com.fs.his.domain.FsStoreOrder;
+import com.fs.his.service.IFsStoreOrderService;
+import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.domain.QwUser;
+import com.fs.qw.mapper.QwExternalContactMapper;
 import com.fs.qw.mapper.QwUserMapper;
+import com.fs.qw.service.IQwExternalContactService;
 import com.fs.qw.service.IQwUserVoiceLogService;
+import com.fs.sop.mapper.QwSopLogsMapper;
+import com.fs.sop.mapper.SopUserLogsInfoMapper;
+import com.fs.sop.params.GetQwSopLogsByJsApiParam;
+import com.fs.voice.utils.StringUtil;
 import com.fs.wxwork.dto.*;
 import com.fs.wxwork.service.WxWorkService;
 import io.swagger.annotations.Api;
@@ -15,8 +25,7 @@ import org.json.JSONObject;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
-import java.util.HashMap;
-import java.util.Map;
+import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -37,6 +46,70 @@ public class QwMsgController {
     WxWorkService wxWorkService;
     @Autowired
     IQwUserVoiceLogService qwUserVoiceLogService;
+    @Autowired
+    IFsStoreOrderService fsStoreOrderService;
+    @Autowired
+    IQwExternalContactService externalContactService;
+    @Autowired
+    QwExternalContactMapper qwExternalContactMapper;
+    @Autowired
+    SopUserLogsInfoMapper sopUserLogsInfoMapper;
+    @Autowired
+    QwSopLogsMapper qwSopLogsMapper;
+
+    @GetMapping("/sendExpressInfo/{orderId}")
+    public R sendExpressInfo(@PathVariable Long orderId){
+        FsStoreOrder order = fsStoreOrderService.selectFsStoreOrderByOrderId(orderId);
+        if(order != null && order.getUserId() != null){
+            List<QwExternalContact> qwExternalContact = externalContactService.selectQwExternalContactByFsUserId(order.getUserId());
+            if(qwExternalContact != null && !qwExternalContact.isEmpty()){
+                for (QwExternalContact externalContact : qwExternalContact) {
+                    Long qwUserId = externalContact.getQwUserId();
+                    if(qwUserId != null ){
+                        QwUser qwUser = qwUserMapper.selectQwUserById(qwUserId);
+                        if(qwUser != null && qwUser.getUid() != null && qwUser.getServerId() != null && qwUser.getServerStatus() == 1 && qwUser.getIpadStatus() == 1){
+                            WxWorkUserId2VidDTO wxWorkUserId2VidDTO = new WxWorkUserId2VidDTO();
+                            wxWorkUserId2VidDTO.setOpenid(Collections.singletonList(externalContact.getExternalUserId()));
+                            wxWorkUserId2VidDTO.setUuid(qwUser.getUid());
+                            WxWorkResponseDTO<List<WxWorkVid2UserIdRespDTO>> WxWorkVid2UserIdRespDTO = wxWorkService.UserId2Vid(wxWorkUserId2VidDTO,qwUser.getServerId());
+                            List<WxWorkVid2UserIdRespDTO> data = WxWorkVid2UserIdRespDTO.getData();
+                            StringBuilder sBuilder = new StringBuilder();
+                            if(data != null && !data.isEmpty()){
+                                Long sendId = data.get(0).getUser_id();
+                                switch (order.getStatus())
+                                {
+                                    case -1:
+                                    case -2:
+                                    case 1:
+                                        break;
+                                    case 2:
+                                        sBuilder.append("您好,您购买的").append(order.getPackageName()).append("正在准备发货,请耐心等待;\n").append("\uD83C\uDF39\uD83C\uDF39\uD83C\uDF39");
+                                        break;
+                                    case 3:
+                                    case 4:
+                                    case 5:
+                                        break;
+                                }
+                                if(!"".contentEquals(sBuilder)){
+                                    //2.发送模板中的文字内容
+                                    String content = sBuilder.toString();
+                                    WxWorkSendTextMsgDTO wxWorkSendTextMsgDTO = new WxWorkSendTextMsgDTO();
+                                    wxWorkSendTextMsgDTO.setSend_userid(sendId);
+                                    wxWorkSendTextMsgDTO.setUuid(qwUser.getUid());
+                                    wxWorkSendTextMsgDTO.setContent(content);
+                                    wxWorkSendTextMsgDTO.setIsRoom(false);
+                                    wxWorkService.SendTextMsg(wxWorkSendTextMsgDTO,qwUser.getServerId());
+                                }
+                                return R.ok();
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
 
     @PostMapping("/callback/{serverId}")
     @ResponseBody
@@ -80,7 +153,7 @@ public class QwMsgController {
                     WxWorkGetQrCodeDTO wxWorkGetQrCodeDTO = new WxWorkGetQrCodeDTO();
                     wxWorkGetQrCodeDTO.setUuid(wxWorkMsgResp.getUuid());
                     wxWorkService.LoginOut(wxWorkGetQrCodeDTO,serverId);
-                    System.out.println("调用退出登录");
+                    log.info("调用退出登录");
                     break;
                 }
                 if (!qu.getQwUserId().equals(jsonObject.get("acctid"))){
@@ -89,7 +162,7 @@ public class QwMsgController {
                     WxWorkGetQrCodeDTO wxWorkGetQrCodeDTO = new WxWorkGetQrCodeDTO();
                     wxWorkGetQrCodeDTO.setUuid(wxWorkMsgResp.getUuid());
                     wxWorkService.LoginOut(wxWorkGetQrCodeDTO,serverId);
-                    System.out.println("调用退出登录");
+                    log.info("调用退出登录");
                     break;
                 }
                 QwUser qwUser = new QwUser();
@@ -101,39 +174,45 @@ public class QwMsgController {
                 redisCache.setCacheObject("qrCodeUid:"+wxWorkMsgResp.getUuid(),104001,10, TimeUnit.MINUTES);
                 break;
             case 100006:
-                System.out.println("企业切换");
+
                 break;
             case 100004:
                 System.out.println("需要验证二维码消息");
                 redisCache.setCacheObject("qrCodeUid:"+wxWorkMsgResp.getUuid(),100004,10, TimeUnit.MINUTES);
                 break;
             case 100012:
-                System.out.println("需要二次验证");
+                log.info("需要二次验证:"+wxWorkMsgResp.getJson());
+
                 redisCache.setCacheObject("qrCodeUid:"+wxWorkMsgResp.getUuid(),100012,10, TimeUnit.MINUTES);
 
                 break;
             case 100005:
-                System.out.println("手机端结束登录");
+
                 log.info("手机端结束登录:"+wxWorkMsgResp.getJson());
                 qwUserStatus(wxWorkMsgResp.getUuid(),0);
                 break;
             case 100008:
-                System.out.println("当前账号在其他设备登录");
-                log.info("当前账号在其他设备登录:"+wxWorkMsgResp.getJson());
-                qwUserStatus(wxWorkMsgResp.getUuid(),0);
+                QwUser vidUser = qwUserMapper.selectQwUserById(id);
+                if (vidUser.getUid().equals(wxWorkMsgResp.getUuid())){
+                    log.info("当前账号在其他设备登录:"+wxWorkMsgResp.getJson());
+                    qwUserStatus(wxWorkMsgResp.getUuid(),0);
+                }
+                log.info("当前账号重新登录:"+wxWorkMsgResp.getJson());
                 break;
             case 100007:
-                System.out.println("异常断开");
                 log.info("异常断开:"+wxWorkMsgResp.getJson());
                 qwUserStatus(wxWorkMsgResp.getUuid(),0);
                 break;
             case 100009:
-                System.out.println("二次验证");
                 log.info("二次验证:"+wxWorkMsgResp.getJson());
                 qwUserStatus(wxWorkMsgResp.getUuid(),0);
                 break;
+            case 102001:
+            case 102002:
+                WxWorkMessageDTO wxWorkMessageDTO1 = JSON.parseObject(wxWorkMsgResp.getJson(), WxWorkMessageDTO.class);
+                handleSopBlockOrDel(id,wxWorkMessageDTO1,wxWorkMsgResp.getUuid(),5);
+                break;
             case 102000:
-
                 WxWorkMessageDTO wxWorkMessageDTO = JSON.parseObject(wxWorkMsgResp.getJson(), WxWorkMessageDTO.class);
                 if (wxWorkMessageDTO.getIs_room()!=0){
                     break;
@@ -155,6 +234,15 @@ public class QwMsgController {
                         ste.setUuid(wxWorkMsgResp.getUuid());
                         WxWorkResponseDTO<WxwSpeechToTextEntityRespDTO> dto = wxWorkService.SpeechToTextEntity(ste, serverId);
                         System.out.println(dto);
+                        if(dto.getErrcode() != 0){
+                            try {
+                                TimeUnit.SECONDS.sleep(1); // 阻塞1秒
+                            } catch (InterruptedException e) {
+                                Thread.currentThread().interrupt(); // 处理中断异常
+                                System.out.println("第一次语音转换失败");
+                            }
+                            dto = wxWorkService.SpeechToTextEntity(ste, serverId);
+                        }
                         WxwSpeechToTextEntityRespDTO data = dto.getData();
                         content = data.getText();
                         System.out.println("语音消息"+content);
@@ -239,6 +327,87 @@ public class QwMsgController {
         return map;
     }
 
+    /**
+     * 处理被拉黑的用户
+     * @param qwUserId
+     * @param wxWorkMessageDTO
+     * @param uuid
+     * @param status
+     */
+    private void handleSopBlockOrDel(Long qwUserId,WxWorkMessageDTO wxWorkMessageDTO,String uuid, Integer status){
+        QwUser user = qwUserMapper.selectQwUserById(qwUserId);
+        //查询接收人
+        if(user==null){
+            System.out.println("查询接收人为空");
+        }
+        if(user.getFastGptRoleId()==null){
+            System.out.println("未绑定角色");
+        }
+        Long serverId = user.getServerId();
+        System.out.println("服务器id"+serverId);
+        if (serverId == null) {
+            System.out.println("服务id为空");
+        }
+
+        WxWorkVid2UserIdDTO wxWorkVid2UserIdDTO = new WxWorkVid2UserIdDTO();
+        wxWorkVid2UserIdDTO.setUser_id(Arrays.asList(wxWorkMessageDTO.getReceiver()));
+        wxWorkVid2UserIdDTO.setUuid(uuid);
+        //下面的方法是返回当前对象
+        WxWorkResponseDTO<List<WxWorkVid2UserIdRespDTO>> WxWorkVid2UserIdRespDTO = wxWorkService.Vid2UserId(wxWorkVid2UserIdDTO,serverId);
+        List<WxWorkVid2UserIdRespDTO> data = WxWorkVid2UserIdRespDTO.getData();
+        if (data==null|| data.isEmpty()){
+
+            System.out.println("未获取到extId"+wxWorkVid2UserIdDTO);
+        }
+        com.fs.wxwork.dto.WxWorkVid2UserIdRespDTO dto = data.get(0);
+
+        QwExternalContact qwExternalContacts = qwExternalContactMapper.selectQwExternalContactByExternalUserIdAndQwUserId(dto.getOpenid(), user.getCorpId(),user.getQwUserId());
+        if (qwExternalContacts==null){
+            System.out.println("没有外部联系人");
+        }
+
+        //处理拉黑的
+        String appKey = user.getAppKey();
+        //客户编号
+        String receiverOpenid = qwExternalContacts.getExternalUserId();
+
+        if (StringUtil.strIsNullOrEmpty(appKey) || StringUtil.strIsNullOrEmpty(receiverOpenid)){
+            log.error("删除或拉黑-处理营期失败数据不对:"+appKey+"|"+receiverOpenid);
+            return;
+        }
+
+        try {
+            QwUser qwUser = qwUserMapper.selectQwUserByAppKey(appKey);
+            if (qwUser!=null){
+
+                //修改客户状态
+                QwExternalContact contact=new QwExternalContact();
+                contact.setStatus(status);
+                contact.setUserId(qwUser.getQwUserId());
+                contact.setCorpId(qwUser.getCorpId());
+                contact.setExternalUserId(receiverOpenid);
+                qwExternalContactMapper.updateQwExternalContactByUseridBlock(contact);
+
+
+                log.info("删除或拉黑-处理营期-"+qwUser.getQwUserId()+"|"+qwUser.getCorpId()+"|"+receiverOpenid);
+
+                //删除营期
+                sopUserLogsInfoMapper.deleteByQwUserIdAndCorpIdToContactId(qwUser.getQwUserId(),qwUser.getCorpId(),receiverOpenid);
+
+                //删除待发送记录
+                GetQwSopLogsByJsApiParam apiParam=new GetQwSopLogsByJsApiParam();
+                apiParam.setQwUserId(qwUser.getQwUserId());
+                apiParam.setCorpId(qwUser.getCorpId());
+                apiParam.setExternalUserId(receiverOpenid);
+                qwSopLogsMapper.deleteQwSopLogsByJsApi(apiParam);
+            }
+
+        }catch (Exception e){
+            log.error("删除或拉黑-处理营期失败:"+appKey+"|"+receiverOpenid+"|"+e.getMessage());
+        }
+
+    }
+
     /**
      * 处理图片消息
      * @param serverId          服务器ID

+ 1 - 1
fs-qw-api-msg/src/main/java/com/fs/app/controller/imgTest.java

@@ -18,7 +18,7 @@ public class imgTest {
             String apiKey = "208d3549-8dc9-4ef6-b3fa-5aa358f1ab20";
             String requestBody = String.format(
                     "{" +
-                            "\"model\": \"doubao-vision-lite-32k-241015\"," +
+                            "\"model\": \"doubao-1-5-thinking-vision-pro-250428\"," +
                             "\"messages\": [{" +
                             "\"role\": \"user\"," +
                             "\"content\": [" +

+ 55 - 0
fs-qw-api-msg/src/main/java/com/fs/app/controller/test.java

@@ -0,0 +1,55 @@
+package com.fs.app.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.fs.common.annotation.Excel;
+import com.fs.fastGpt.domain.FastGptChatSession;
+import com.fs.fastgptApi.util.AiImgUtil;
+import com.fs.qw.domain.QwExternalContact;
+import com.fs.qw.domain.QwExternalContactInfo;
+import com.fs.wxwork.dto.WxwSilkVoceDTO;
+import com.fs.wxwork.utils.WxWorkHttpUtil;
+
+import javax.validation.constraints.Null;
+import java.lang.reflect.Field;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class test {
+    public static void main(String[] args) {
+
+        AiImgUtil aiImgUtil = new AiImgUtil();
+        String imageParse = aiImgUtil.getImageParse("https://cos.his.cdwjyyh.com/fs/20250606/098d6e12acf747548372ad61bdade4e3.jpg");
+        System.out.println(imageParse);
+    }
+
+    private static String imgEmoticon(String imageParse) {
+        Pattern img = Pattern.compile("【表情包:(.*?)】", Pattern.DOTALL);
+        Matcher imgMatcher = img.matcher(imageParse);
+        while  (imgMatcher.find()) {
+            String imgTag = imgMatcher.group(1).trim();
+            if(imgTag!=null&&!imgTag.equals("")){
+                return imgTag;
+            }
+
+        }
+        return null;
+    }
+
+
+    void voice(){
+        String  url="http://162.14.193.126:8009/app/common/voice?voice="+"你好"+"&id="+2020;
+        String json = WxWorkHttpUtil.get(url);
+        System.out.println(json);
+        WxwSilkVoceDTO wxwSilkVoceDTO = JSON.parseObject(json, WxwSilkVoceDTO.class);
+    }
+
+
+    void img(){
+        AiImgUtil aiImgUtil = new AiImgUtil();
+        String imageParse = aiImgUtil.getImageParse("https://cos.his.cdwjyyh.com/fs/20250604/e8458ed36e534135b50e7459e67b19af.jpg");
+        System.out.println(imageParse);
+    }
+
+}

+ 20 - 3
fs-qw-api-msg/src/main/java/com/fs/framework/config/DataSourceConfig.java

@@ -21,12 +21,16 @@ import java.util.Map;
 
 @Configuration
 public class DataSourceConfig {
-
     @Bean
     @ConfigurationProperties(prefix = "spring.datasource.sop.druid.master")
     public DataSource sopDataSource() {
         return new DruidDataSource();
     }
+    @Bean
+    @ConfigurationProperties(prefix = "spring.datasource.clickhouse")
+    public DataSource clickhouseDataSource() {
+        return new DruidDataSource();
+    }
 
     @Bean
     @ConfigurationProperties(prefix = "spring.datasource.mysql.druid.master")
@@ -34,13 +38,26 @@ public class DataSourceConfig {
         return new DruidDataSource();
     }
 
+    @Bean
+    @ConfigurationProperties(prefix = "spring.datasource.mysql.druid.slave")
+    public DataSource slaveDataSource() {
+        return new DruidDataSource();
+    }
+
 
 
     @Bean
     @Primary
-    public DynamicDataSource dataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("sopDataSource") DataSource sopDataSource) {
+    public DynamicDataSource dataSource(@Qualifier("clickhouseDataSource") DataSource clickhouseDataSource,
+                                        @Qualifier("masterDataSource") DataSource masterDataSource,
+                                        @Qualifier("sopDataSource") DataSource sopDataSource,
+                                        @Qualifier("slaveDataSource") DataSource slaveDataSource) {
         Map<Object, Object> targetDataSources = new HashMap<>();
+        targetDataSources.put(DataSourceType.MASTER, masterDataSource);
+
+        targetDataSources.put(DataSourceType.SLAVE, slaveDataSource);
         targetDataSources.put(DataSourceType.SOP.name(), sopDataSource);
+        targetDataSources.put(DataSourceType.CLICKHOUSE.name(), clickhouseDataSource); // Ensure matching key
         return new DynamicDataSource(masterDataSource, targetDataSources);
     }
 
@@ -49,7 +66,7 @@ public class DataSourceConfig {
      */
     @SuppressWarnings({ "rawtypes", "unchecked" })
     @Bean
-    @ConditionalOnProperty(name = "spring.datasource.mysql.druid.statViewServlet.enabled", havingValue = "true")
+    @ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true")
     public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties)
     {
         // 获取web监控页面的参数

+ 1 - 1
fs-qw-api-msg/src/main/java/com/fs/framework/config/MyBatisConfig.java

@@ -26,7 +26,7 @@ import java.util.List;
 
 /**
  * Mybatis支持*匹配扫描包
- *
+ * 
 
  */
 @Configuration

+ 2 - 0
fs-qw-api-msg/src/main/java/com/fs/framework/config/SecurityConfig.java

@@ -110,6 +110,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
                 ).permitAll()
 
                 .antMatchers("/**").anonymous()
+                .antMatchers("**/errorLogUpload").anonymous()
                 .antMatchers("/msg/**").anonymous()
                 .antMatchers("/msg/**/**").anonymous()
                 .antMatchers("/msg").anonymous()
@@ -125,6 +126,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
                 .antMatchers("/*/api-docs").anonymous()
                 .antMatchers("/druid/**").anonymous()
                 .antMatchers("/qw/data/**").anonymous()
+                .antMatchers("/qw/test/**").anonymous()
                 // 除上面外的所有请求全部需要鉴权认证
                 .anyRequest().authenticated()
                 .and()

+ 3 - 2
fs-qw-api-msg/src/main/resources/application.yml

@@ -1,9 +1,10 @@
 server:
-  port: 8006
+  port: 8667
 # Spring配置
 spring:
   profiles:
-    active: dev
+#    active: dev
 #    active: druid-jzzx
 #    active: druid-hdt
 #    active: druid-sxjz
+    active: druid-hzyy-test

+ 4 - 2
fs-qw-api/src/main/resources/application.yml

@@ -1,11 +1,13 @@
 server:
   # 服务器的HTTP端口,默认为8080
-  port: 8006
+  port: 8007
 
 # Spring配置
 spring:
   profiles:
-    active: dev
+#    active: dev
 #    active: druid-hdt
 #    active: druid-sft
 #    active: druid-myhk
+    active: config-druid-hzyy
+

+ 16 - 3
fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java

@@ -16,6 +16,7 @@ import com.fs.his.service.IFsInquiryOrderService;
 import com.fs.his.service.IFsPackageOrderService;
 import com.fs.qw.mapper.QwExternalContactMapper;
 import com.fs.qw.service.IQwExternalContactService;
+import com.fs.qw.service.IQwMaterialService;
 import com.fs.qwApi.service.QwApiService;
 import com.fs.sop.mapper.QwSopLogsMapper;
 import com.fs.sop.mapper.QwSopMapper;
@@ -99,6 +100,12 @@ public class CommonController {
     @Autowired
     private IFsInquiryOrderService inquiryOrderService;
 
+    @Autowired
+    private IQwMaterialService iQwMaterialService;
+
+
+    @Autowired
+    private IFsCourseLinkService iFsCourseLinkService;
 
     /**
     * 发官方通连
@@ -136,12 +143,18 @@ public class CommonController {
         return R.ok();
     }
 
+
+    @GetMapping("/testMaterial")
+    public void testMaterial() throws Exception {
+
+        iQwMaterialService.updateQwMaterialByQw();
+
+    }
+
     @GetMapping("/testSop")
     public R testSop() throws Exception {
 
-        byte[] bytes = inquiryOrderService.getWxaCodeInquiryOrderUnLimit(2582616L);
-        String base64 = Base64.getEncoder().encodeToString(bytes);
-        return R.ok().put("data",base64);
+        return iFsCourseLinkService.getWxaCodeGenerateScheme("/pages_course/video.html?course={\"companyId\":100,\"companyUserId\":2020,\"corpId\":\"wweb0666cc79d79da5\",\"courseId\":61,\"link\":\"1950497651577323520\",\"linkType\":3,\"qwExternalId\":2356946,\"qwUserId\":\"1682\",\"uNo\":\"b8b010e1-ee0f-42ec-8ad8-06681d1b449a\",\"videoId\":366}","wx34bba1ae94d34986");
     }
 
     @GetMapping("/testRatingSop")

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

@@ -911,7 +911,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                             createParam.setCompanyUserId(Long.parseLong(companyUserId));
                             createParam.setCompanyId(Long.parseLong(companyId));
                             createParam.setChatId(logVo.getChatId());
-                            createParam.setQwUserId(Long.parseLong(qwUserId));
+                            createParam.setQwUserId(Long.valueOf(qwUserId));
                             createParam.setDays(setting.getExpiresDays());
                             R createLink = courseLinkService.createRoomLinkUrl(createParam);
                             if (createLink.get("code").equals(500)) {

+ 73 - 0
fs-qwhook-sop/src/main/java/com/fs/app/controller/ApisQwMaterialBySidebar.java

@@ -0,0 +1,73 @@
+package com.fs.app.controller;
+
+import com.fs.common.core.domain.R;
+import com.fs.qw.domain.QwUser;
+import com.fs.qw.param.QwMaterialParam;
+import com.fs.qw.param.QwMaterialParamBySidebar;
+import com.fs.qw.service.IQwExternalContactService;
+import com.fs.qw.service.IQwMaterialService;
+import com.fs.qw.vo.QwMaterialVO;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@Api("素材库库相关接口")
+@RestController
+@RequestMapping("/apis/app/qw/material")
+@Slf4j
+public class ApisQwMaterialBySidebar {
+
+
+
+    @Autowired
+    private IQwExternalContactService qwExternalContactService;
+
+    @Autowired
+    private IQwMaterialService qwMaterialService;
+
+    /**
+     * 查询素材库列表
+     */
+    @PostMapping("/MaterialList")
+    public R list(@RequestBody QwMaterialParamBySidebar param)
+    {
+
+        QwUser qwUser = qwExternalContactService.getQwUserByRedis(param.getCorpId().trim(),param.getQwUserId().trim());
+
+        if (qwUser == null || qwUser.getCompanyId() == null) {
+            return R.error("员工未绑定 销售公司 或 未获取到员工信息,请重试!");
+        }
+
+
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+
+        QwMaterialParam materialParam=new QwMaterialParam();
+        materialParam.setCompanyId(qwUser.getCompanyId());
+        materialParam.setTitle(param.getKeyword());
+        List<QwMaterialVO> list = qwMaterialService.selectQwMaterialList(materialParam);
+
+
+        PageInfo<QwMaterialVO> result = new PageInfo<>(list);
+        return R.ok().put("data", result);
+
+
+    }
+
+    @GetMapping("/updateMaterialTime/{materialId}")
+    public R updateMaterialTime(@PathVariable Long materialId) throws Exception {
+
+        return R.ok().put("data",qwMaterialService.selectQwMaterialByMaterialIdByTime(materialId));
+    }
+
+    @GetMapping("/getMaterialByTime/{materialId}")
+    public R getMaterialByTime(@PathVariable Long materialId) throws Exception {
+
+        return R.ok().put("data",qwMaterialService.selectQwMaterialByMaterialIdByTimeTwo(materialId));
+    }
+
+}

+ 72 - 0
fs-qwhook-sop/src/main/java/com/fs/app/controller/QwMaterialBySidebar.java

@@ -0,0 +1,72 @@
+package com.fs.app.controller;
+
+import com.fs.common.core.domain.R;
+import com.fs.qw.domain.QwUser;
+import com.fs.qw.param.QwMaterialParam;
+import com.fs.qw.param.QwMaterialParamBySidebar;
+import com.fs.qw.service.IQwExternalContactService;
+import com.fs.qw.service.IQwMaterialService;
+import com.fs.qw.vo.QwMaterialVO;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@Api("素材库库相关接口")
+@RestController
+@RequestMapping("/app/qw/material")
+@Slf4j
+public class QwMaterialBySidebar {
+
+
+
+    @Autowired
+    private IQwExternalContactService qwExternalContactService;
+
+    @Autowired
+    private IQwMaterialService qwMaterialService;
+
+    /**
+     * 查询素材库列表
+     */
+    @PostMapping("/MaterialList")
+    public R list(@RequestBody QwMaterialParamBySidebar param)
+    {
+
+        QwUser qwUser = qwExternalContactService.getQwUserByRedis(param.getCorpId().trim(),param.getQwUserId().trim());
+
+        if (qwUser == null || qwUser.getCompanyId() == null) {
+            return R.error("员工未绑定 销售公司 或 未获取到员工信息,请重试!");
+        }
+
+
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+
+        QwMaterialParam materialParam=new QwMaterialParam();
+        materialParam.setCompanyId(qwUser.getCompanyId());
+        materialParam.setTitle(param.getKeyword());
+        List<QwMaterialVO> list = qwMaterialService.selectQwMaterialList(materialParam);
+
+
+        PageInfo<QwMaterialVO> result = new PageInfo<>(list);
+        return R.ok().put("data", result);
+
+    }
+
+    @GetMapping("/updateMaterialTime/{materialId}")
+    public R updateMaterialTime(@PathVariable Long materialId) throws Exception {
+
+        return R.ok().put("data",qwMaterialService.selectQwMaterialByMaterialIdByTime(materialId));
+    }
+
+    @GetMapping("/getMaterialByTime/{materialId}")
+    public R getMaterialByTime(@PathVariable Long materialId) throws Exception {
+
+        return R.ok().put("data",qwMaterialService.selectQwMaterialByMaterialIdByTimeTwo(materialId));
+    }
+
+}

+ 81 - 0
fs-qwhook/src/main/java/com/fs/app/controller/ApisQwMaterialBySidebar.java

@@ -0,0 +1,81 @@
+package com.fs.app.controller;
+
+import com.fs.common.core.domain.R;
+import com.fs.qw.domain.QwMaterial;
+import com.fs.qw.domain.QwUser;
+import com.fs.qw.param.QwMaterialParam;
+import com.fs.qw.param.QwMaterialParamBySidebar;
+import com.fs.qw.service.IQwExternalContactService;
+import com.fs.qw.service.IQwMaterialService;
+import com.fs.qw.vo.QwMaterialVO;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@Api("素材库库相关接口")
+@RestController
+@RequestMapping("/apis/app/qw/material")
+@Slf4j
+public class ApisQwMaterialBySidebar {
+
+
+
+    @Autowired
+    private IQwExternalContactService qwExternalContactService;
+
+    @Autowired
+    private IQwMaterialService qwMaterialService;
+
+    /**
+     * 查询素材库列表
+     */
+    @PostMapping("/MaterialList")
+    public R list(@RequestBody QwMaterialParamBySidebar param)
+    {
+
+        QwUser qwUser = qwExternalContactService.getQwUserByRedis(param.getCorpId().trim(),param.getQwUserId().trim());
+
+        if (qwUser == null || qwUser.getCompanyId() == null) {
+            return R.error("员工未绑定 销售公司 或 未获取到员工信息,请重试!");
+        }
+
+
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+
+        QwMaterialParam materialParam=new QwMaterialParam();
+        materialParam.setCompanyId(qwUser.getCompanyId());
+        materialParam.setTitle(param.getKeyword());
+        List<QwMaterialVO> list = qwMaterialService.selectQwMaterialList(materialParam);
+
+
+        PageInfo<QwMaterialVO> result = new PageInfo<>(list);
+        return R.ok().put("data", result);
+
+
+    }
+
+    /**
+    * 更新 素材库的某个素材的 media_id
+    */
+    @GetMapping("/updateMaterialTime/{materialId}")
+    public R updateMaterialTime(@PathVariable Long materialId) throws Exception {
+
+        return R.ok().put("data",qwMaterialService.selectQwMaterialByMaterialIdByTime(materialId));
+    }
+
+    /**
+    * 获取某个素材id
+    */
+    @GetMapping("/getMaterialByTime/{materialId}")
+    public R getMaterialByTime(@PathVariable Long materialId) throws Exception {
+
+        return R.ok().put("data",qwMaterialService.selectQwMaterialByMaterialIdByTimeTwo(materialId));
+    }
+
+
+}

+ 73 - 0
fs-qwhook/src/main/java/com/fs/app/controller/QwMaterialBySidebar.java

@@ -0,0 +1,73 @@
+package com.fs.app.controller;
+
+import com.fs.common.core.domain.R;
+import com.fs.qw.domain.QwUser;
+import com.fs.qw.param.QwMaterialParam;
+import com.fs.qw.param.QwMaterialParamBySidebar;
+import com.fs.qw.service.IQwExternalContactService;
+import com.fs.qw.service.IQwMaterialService;
+import com.fs.qw.vo.QwMaterialVO;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@Api("素材库库相关接口")
+@RestController
+@RequestMapping("/app/qw/material")
+@Slf4j
+public class QwMaterialBySidebar {
+
+
+
+    @Autowired
+    private IQwExternalContactService qwExternalContactService;
+
+    @Autowired
+    private IQwMaterialService qwMaterialService;
+
+    /**
+     * 查询素材库列表
+     */
+    @PostMapping("/MaterialList")
+    public R list(@RequestBody QwMaterialParamBySidebar param)
+    {
+
+        QwUser qwUser = qwExternalContactService.getQwUserByRedis(param.getCorpId().trim(),param.getQwUserId().trim());
+
+        if (qwUser == null || qwUser.getCompanyId() == null) {
+            return R.error("员工未绑定 销售公司 或 未获取到员工信息,请重试!");
+        }
+
+
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+
+        QwMaterialParam materialParam=new QwMaterialParam();
+        materialParam.setCompanyId(qwUser.getCompanyId());
+        materialParam.setTitle(param.getKeyword());
+        List<QwMaterialVO> list = qwMaterialService.selectQwMaterialList(materialParam);
+
+
+        PageInfo<QwMaterialVO> result = new PageInfo<>(list);
+        return R.ok().put("data", result);
+
+
+    }
+
+    @GetMapping("/updateMaterialTime/{materialId}")
+    public R updateMaterialTime(@PathVariable Long materialId) throws Exception {
+
+        return R.ok().put("data",qwMaterialService.selectQwMaterialByMaterialIdByTime(materialId));
+    }
+
+    @GetMapping("/getMaterialByTime/{materialId}")
+    public R getMaterialByTime(@PathVariable Long materialId) throws Exception {
+
+        return R.ok().put("data",qwMaterialService.selectQwMaterialByMaterialIdByTimeTwo(materialId));
+    }
+
+}

+ 18 - 0
fs-redis/src/main/java/com/fs/app/redis/RedisKeyExpirationListener.java

@@ -6,10 +6,12 @@ import com.fs.event.TemplateBean;
 import com.fs.event.TemplateEvent;
 import com.fs.event.TemplateListenEnum;
 import com.fs.his.domain.FsInquiryOrder;
+import com.fs.his.domain.FsIntegralOrder;
 import com.fs.his.domain.FsPackageOrder;
 import com.fs.his.param.FsInquiryOrderCancelParam;
 import com.fs.his.service.IFsInquiryOrderLogsService;
 import com.fs.his.service.IFsInquiryOrderService;
+import com.fs.his.service.IFsIntegralOrderService;
 import com.fs.his.service.IFsPackageOrderService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -97,5 +99,21 @@ public class RedisKeyExpirationListener extends KeyExpirationEventMessageListene
             }
 
         }
+        // 积分订单
+        else if (key.contains(FsConstants.REDIS_INTEGRAL_ORDER_UNPAY)) {
+            key = key.replace(FsConstants.REDIS_INTEGRAL_ORDER_UNPAY, "");
+            log.info("body:{}",key);
+
+            Long orderId = Long.parseLong(key);
+            IFsIntegralOrderService orderService = SpringUtils.getBean(IFsIntegralOrderService.class);
+            FsIntegralOrder order = orderService.selectFsIntegralOrderByOrderId(orderId);
+            if (!order.getStatus().equals(4)){
+                return;
+            }
+
+            // 取消订单
+            orderService.cannelOrder(orderId);
+            log.info("积分订单id:{},超时未支付取消成功",orderId);
+        }
     }
 }

+ 12 - 0
fs-redis/src/main/resources/application.yml

@@ -0,0 +1,12 @@
+server:
+  # 服务器的HTTP端口,默认为8080
+  port: 18004
+# Spring配置
+spring:
+  profiles:
+    active: dev
+#    active: druid-hdt
+#    active: druid-yzt
+#    active: druid-sxjz
+#    active: druid-sft
+

+ 1 - 1
fs-service/src/main/java/com/fs/common/param/LoginMaWxParam.java

@@ -34,7 +34,7 @@ public class LoginMaWxParam implements Serializable {
     @ApiModelProperty(value = "用户头像")
     private String avatar;
 
-//    @NotNull(message = "项目id不能为空")
+    @NotNull(message = "项目id不能为空")
     @ApiModelProperty(value = "课程归属项目id")
     private Long projectId;
 

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

@@ -0,0 +1,83 @@
+package com.fs.company.constant;
+
+import lombok.Getter;
+
+/**
+ * 支付状态枚举类
+ *
+ * 描述支付过程中可能的状态
+ */
+@Getter
+public enum PaymentStatus {
+
+    /**
+     * 支付创建,初始状态
+     */
+    CREATED(0, "创建"),
+
+    /**
+     * 支付处理中
+     */
+    PROCESSING(1, "处理中"),
+
+    /**
+     * 支付成功
+     */
+    SUCCESS(2, "支付成功"),
+
+    /**
+     * 支付失败
+     */
+    FAILED(3, "支付失败");
+
+    /**
+     * 状态码
+     * -- GETTER --
+     *  获取状态码
+     *
+     * @return 状态码
+
+     */
+    private final int code;
+
+    /**
+     * 状态描述
+     * -- GETTER --
+     *  获取状态描述
+     *
+     * @return 状态描述
+
+     */
+    private final String description;
+
+    /**
+     * 构造函数
+     *
+     * @param code 状态码
+     * @param description 状态描述
+     */
+    PaymentStatus(int code, String description) {
+        this.code = code;
+        this.description = description;
+    }
+
+    /**
+     * 根据状态码获取对应的枚举值
+     *
+     * @param code 状态码
+     * @return 对应的支付状态枚举,如果没找到则返回null
+     */
+    public static PaymentStatus getByCode(int code) {
+        for (PaymentStatus status : PaymentStatus.values()) {
+            if (status.getCode() == code) {
+                return status;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        return code + ":" + description;
+    }
+}

+ 45 - 0
fs-service/src/main/java/com/fs/company/domain/CompanyCompanyFsuser.java

@@ -0,0 +1,45 @@
+package com.fs.company.domain;
+
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 销售绑定用户(一个用户绑定唯一一个销售)对象 company_company_fsuser
+ *
+ * @author fs
+ * @date 2025-04-09
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class CompanyCompanyFsuser extends BaseEntity{
+
+    /** $column.columnComment */
+    private Long id;
+
+    /** 公司id */
+    @Excel(name = "公司id")
+    private Long companyId;
+
+    /** 销售id */
+    @Excel(name = "销售id")
+    private Long companyUserId;
+
+    /** 会员id */
+    @Excel(name = "会员id")
+    private Long userId;
+
+    @Excel(name = "企微外部联系人id")
+    private Long qwContactId;
+
+
+    /** 状态 0:禁用 1:正常 */
+    @Excel(name = "状态 0:禁用 1:正常")
+    private Integer status;
+
+    /** 绑定类型 0:链接二维码 1:看课 */
+    private Integer bindType;
+
+
+}

+ 75 - 0
fs-service/src/main/java/com/fs/company/domain/CompanyRechargeOrder.java

@@ -0,0 +1,75 @@
+package com.fs.company.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * 公司充值订单表
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class CompanyRechargeOrder {
+
+    /**
+     * 主键ID
+     */
+    private Long id;
+
+    /**
+     * 订单号
+     */
+    private String orderNo;
+
+    /**
+     * 支付平台交易号
+     */
+    private String transactionId;
+
+    /**
+     * 支付方式:1-微信 2-支付宝 3-银行卡 4-其他
+     */
+    private Integer payType;
+
+    /**
+     * 支付金额
+     */
+    private BigDecimal payAmount;
+
+    private Long companyId;
+
+    private Long userId;
+
+    /**
+     * 支付状态:0-创建 1-处理中 2-支付成功 3-支付失败
+     */
+    private Integer payStatus;
+
+    /**
+     * 支付时间
+     */
+    private LocalDateTime paymentTime;
+
+    /**
+     * 回调内容
+     */
+    private String callbackContent;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+
+    private String qrLink;
+}

+ 64 - 0
fs-service/src/main/java/com/fs/company/domain/CompanyRedPackage.java

@@ -0,0 +1,64 @@
+package com.fs.company.domain;
+
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+
+import java.util.Date;
+
+public class CompanyRedPackage extends BaseEntity {
+
+    private Long companyId;
+
+    @Excel(name = "公司名称")
+    private String companyName;
+
+    @Excel(name = "销售名称")
+    private String nickName;
+
+    @Excel(name = "红包金额")
+    private Double totalAmount;
+
+    @Excel(name = "统计时间")
+    private String dateTime;
+
+
+    public Long getCompanyId() {
+        return companyId;
+    }
+
+    public void setCompanyId(Long companyId) {
+        this.companyId = companyId;
+    }
+
+    public String getCompanyName() {
+        return companyName;
+    }
+
+    public void setCompanyName(String companyName) {
+        this.companyName = companyName;
+    }
+
+    public String getNickName() {
+        return nickName;
+    }
+
+    public void setNickName(String nickName) {
+        this.nickName = nickName;
+    }
+
+    public Double getTotalAmount() {
+        return totalAmount;
+    }
+
+    public void setTotalAmount(Double totalAmount) {
+        this.totalAmount = totalAmount;
+    }
+
+    public String getDateTime() {
+        return dateTime;
+    }
+
+    public void setDateTime(String dateTime) {
+        this.dateTime = dateTime;
+    }
+}

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

@@ -142,6 +142,19 @@ public class CompanyUser extends BaseEntity
 
     private String addressId;
 
+    //绑定二维码
+    private String bindCode;
+
+    private String imNickName;
+
+    public String getImNickName() {
+        return imNickName;
+    }
+
+    public void setImNickName(String imNickName) {
+        this.imNickName = imNickName;
+    }
+
     /** 看课域名 */
     private String domain;
 
@@ -151,9 +164,30 @@ public class CompanyUser extends BaseEntity
     /** 用户上级id */
     private Long parentId;
 
+    /** 微信小程序OPENID(如果有小程序授权) */
+    private String  maOpenId;
+
     /** 是否需要单独注册会员,1-是,0-否(用于个微销售分享看课) */
     private Integer isNeedRegisterMember;
 
+    /** 是否允许所有方式注册会员,1-是,0-否,默认1(用于个微注册会员) */
+    private Integer isAllowedAllRegister;
+
+    public String getMaOpenId() {
+        return maOpenId;
+    }
+
+    public void setMaOpenId(String maOpenId) {
+        this.maOpenId = maOpenId;
+    }
+
+    public Integer getIsAllowedAllRegister() {
+        return isAllowedAllRegister;
+    }
+
+    public void setIsAllowedAllRegister(Integer isAllowedAllRegister) {
+        this.isAllowedAllRegister = isAllowedAllRegister;
+    }
 
     public Long getParentId() {
         return parentId;
@@ -505,4 +539,11 @@ public class CompanyUser extends BaseEntity
     public void setPosts(List<CompanyPost> posts) {
         this.posts = posts;
     }
+    public String getBindCode() {
+        return bindCode;
+    }
+
+    public void setBindCode(String bindCode) {
+        this.bindCode = bindCode;
+    }
 }

+ 4 - 0
fs-service/src/main/java/com/fs/company/domain/CompanyUserChangeApplyUser.java

@@ -21,4 +21,8 @@ public class CompanyUserChangeApplyUser {
      * 用户ID
      */
     private Long userId;
+    /**
+     * 项目ID
+     */
+    private Long projectId;
 }

+ 18 - 0
fs-service/src/main/java/com/fs/company/dto/CompBuySmsDTO.java

@@ -0,0 +1,18 @@
+package com.fs.company.dto;
+
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class CompBuySmsDTO implements Serializable {
+    /**
+     * 公司id
+     */
+    private String companyId;
+    /**
+     * 套餐id
+     */
+    private String packageId;
+}

+ 13 - 0
fs-service/src/main/java/com/fs/company/dto/CompanyIdAndUserDTO.java

@@ -0,0 +1,13 @@
+package com.fs.company.dto;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+
+@EqualsAndHashCode
+@Data
+public class CompanyIdAndUserDTO implements Serializable {
+    private Long companyId;
+    private Long companyUserId;
+}

+ 15 - 0
fs-service/src/main/java/com/fs/company/dto/RechargeDTO.java

@@ -0,0 +1,15 @@
+package com.fs.company.dto;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+public class RechargeDTO {
+    /**
+     * 充值金额
+     */
+    private BigDecimal amount;
+    private Long companyId;
+    private Long userId;
+}

+ 68 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyCompanyFsuserMapper.java

@@ -0,0 +1,68 @@
+package com.fs.company.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.company.domain.CompanyCompanyFsuser;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 销售绑定用户Mapper接口
+ *
+ * @author fs
+ * @date 2025-04-09
+ */
+public interface CompanyCompanyFsuserMapper extends BaseMapper<CompanyCompanyFsuser>{
+    /**
+     * 查询销售绑定用户
+     *
+     * @param id 销售绑定用户主键
+     * @return 销售绑定用户
+     */
+    CompanyCompanyFsuser selectCompanyCompanyUserById(Long id);
+
+    /**
+     * 查询销售绑定用户列表
+     *
+     * @param companyCompanyUser 销售绑定用户
+     * @return 销售绑定用户集合
+     */
+    List<CompanyCompanyFsuser> selectCompanyCompanyUserList(CompanyCompanyFsuser companyCompanyUser);
+
+    /**
+     * 新增销售绑定用户
+     *
+     * @param companyCompanyUser 销售绑定用户
+     * @return 结果
+     */
+    int insertCompanyCompanyUser(CompanyCompanyFsuser companyCompanyUser);
+
+    /**
+     * 修改销售绑定用户
+     *
+     * @param companyCompanyUser 销售绑定用户
+     * @return 结果
+     */
+    int updateCompanyCompanyUser(CompanyCompanyFsuser companyCompanyUser);
+
+    /**
+     * 删除销售绑定用户
+     *
+     * @param id 销售绑定用户主键
+     * @return 结果
+     */
+    int deleteCompanyCompanyUserById(Long id);
+
+    /**
+     * 批量删除销售绑定用户
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteCompanyCompanyUserByIds(Long[] ids);
+
+    CompanyCompanyFsuser getInfoByUserId(@Param("userId") String userId);
+
+    List<CompanyCompanyFsuser> selectNoHistoryApp(@Param("limit") Integer limit);
+
+}

+ 6 - 1
fs-service/src/main/java/com/fs/company/mapper/CompanyMapper.java

@@ -2,6 +2,8 @@ package com.fs.company.mapper;
 
 import java.math.BigDecimal;
 import java.util.List;
+import java.util.Set;
+
 import com.fs.company.domain.Company;
 import com.fs.company.param.CompanyParam;
 import com.fs.company.vo.CompanyCrmVO;
@@ -165,7 +167,7 @@ public interface CompanyMapper
             "</script>"})
     List<CompanyVO> selectCompanyListVO(Company param);
 
-    @Select("select company_id dictValue,company_name dictLabel from company")
+    @Select("select company_id dictValue,company_name dictLabel from company where is_del= 0")
     List<OptionsVO> selectAllCompanyList();
 
     @Select("select company_id from company")
@@ -184,4 +186,7 @@ public interface CompanyMapper
      * 通过企业id批量查询
      * **/
     List<Company> selectCompanyByIds(@Param("ids") List<Long> ids);
+
+    List<Company> selectCompanyByIds2(@Param("companyIds") Set<Long> companyIds);
+
 }

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

@@ -3,6 +3,7 @@ package com.fs.company.mapper;
 import java.math.BigDecimal;
 import java.util.List;
 import com.fs.company.domain.CompanyMoneyLogs;
+import com.fs.company.domain.CompanyRedPackage;
 import com.fs.company.param.CompanyMoneyLogsParam;
 import com.fs.company.param.CompanyStoreOrderMoneyLogsListParam;
 import com.fs.company.vo.*;
@@ -320,4 +321,6 @@ public interface CompanyMoneyLogsMapper
             "</if>" +
             "</script>"})
     Integer selectCompanyMoneyLogsExport1Counts(@Param("maps")FsCompanyMoneyLogsExportParam param);
+
+    List<CompanyRedPackage> selectCompanyRedPackageListVO(CompanyRedPackage companyRedPackage);
 }

部分文件因为文件数量过多而无法显示