Browse Source

Merge branch 'refs/heads/master' into ScrmStore

# Conflicts:
#	fs-service/src/main/java/com/fs/his/service/impl/FsUserServiceImpl.java
chenguo 6 days ago
parent
commit
8f338bbf0f
72 changed files with 1709 additions and 143 deletions
  1. 1 1
      fs-admin/src/main/java/com/fs/company/controller/CompanyController.java
  2. 148 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyDeductController.java
  3. 143 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyRechargeController.java
  4. 16 1
      fs-admin/src/main/java/com/fs/course/controller/FsCourseProductOrderController.java
  5. 8 1
      fs-admin/src/main/java/com/fs/course/controller/FsCourseQuestionBankController.java
  6. 1 1
      fs-admin/src/main/java/com/fs/course/controller/FsCourseRedPacketLogController.java
  7. 30 2
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseController.java
  8. 14 1
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseTrainingCampController.java
  9. 15 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseVideoController.java
  10. 18 1
      fs-admin/src/main/java/com/fs/course/controller/FsVideoResourceController.java
  11. 64 0
      fs-admin/src/main/java/com/fs/his/controller/FsPackageSolarTermController.java
  12. 1 1
      fs-admin/src/main/java/com/fs/qw/controller/QwSopController.java
  13. 130 0
      fs-company/src/main/java/com/fs/company/controller/course/FsCourseTrafficLogController.java
  14. 1 1
      fs-company/src/main/java/com/fs/company/controller/course/FsUserCourseController.java
  15. 153 0
      fs-company/src/main/java/com/fs/company/controller/course/FsUserWatchCourseStatisticsController.java
  16. 106 0
      fs-company/src/main/java/com/fs/company/controller/course/FsUserWatchStatisticsController.java
  17. 16 0
      fs-company/src/main/java/com/fs/company/controller/qw/QwSopLogsController.java
  18. 1 0
      fs-company/src/main/java/com/fs/user/FsUserAdminController.java
  19. 2 0
      fs-service/src/main/java/com/fs/course/domain/FsCourseQuestionBank.java
  20. 2 0
      fs-service/src/main/java/com/fs/course/domain/FsUserCourse.java
  21. 2 0
      fs-service/src/main/java/com/fs/course/domain/FsUserCourseTrainingCamp.java
  22. 2 0
      fs-service/src/main/java/com/fs/course/domain/FsVideoResource.java
  23. 2 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseTrafficLogMapper.java
  24. 7 3
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseMapper.java
  25. 6 0
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseVideoMapper.java
  26. 2 0
      fs-service/src/main/java/com/fs/course/param/FsCourseAnswerLogsParam.java
  27. 24 2
      fs-service/src/main/java/com/fs/course/param/FsCourseTrafficLogParam.java
  28. 17 0
      fs-service/src/main/java/com/fs/course/param/InternetTrafficParam.java
  29. 1 1
      fs-service/src/main/java/com/fs/course/service/IFsCourseQuestionBankService.java
  30. 2 0
      fs-service/src/main/java/com/fs/course/service/IFsCourseTrafficLogService.java
  31. 2 2
      fs-service/src/main/java/com/fs/course/service/IFsUserCourseService.java
  32. 1 2
      fs-service/src/main/java/com/fs/course/service/IFsUserCourseTrainingCampService.java
  33. 3 1
      fs-service/src/main/java/com/fs/course/service/IFsUserCourseVideoService.java
  34. 7 0
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseProductOrderServiceImpl.java
  35. 36 28
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseQuestionBankServiceImpl.java
  36. 44 0
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseTrafficLogServiceImpl.java
  37. 5 3
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseServiceImpl.java
  38. 2 1
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseTrainingCampServiceImpl.java
  39. 137 77
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  40. 5 0
      fs-service/src/main/java/com/fs/course/vo/FsCourseTrafficLogListVO.java
  41. 4 0
      fs-service/src/main/java/com/fs/course/vo/FsUserCoursePeriodVO.java
  42. 2 0
      fs-service/src/main/java/com/fs/his/domain/FsPackage.java
  43. 58 0
      fs-service/src/main/java/com/fs/his/domain/FsPackageSolarTerm.java
  44. 4 0
      fs-service/src/main/java/com/fs/his/mapper/FsPackageMapper.java
  45. 24 0
      fs-service/src/main/java/com/fs/his/mapper/FsPackageSolarTermMapper.java
  46. 1 0
      fs-service/src/main/java/com/fs/his/param/FsPackageParam.java
  47. 15 0
      fs-service/src/main/java/com/fs/his/param/FsPackageSolarTermParam.java
  48. 52 0
      fs-service/src/main/java/com/fs/his/service/IFsPackageSolarTermService.java
  49. 8 0
      fs-service/src/main/java/com/fs/his/service/impl/FsPackageServiceImpl.java
  50. 98 0
      fs-service/src/main/java/com/fs/his/service/impl/FsPackageSolarTermServiceImpl.java
  51. 1 1
      fs-service/src/main/java/com/fs/his/service/impl/FsUserIntegralLogsServiceImpl.java
  52. 43 5
      fs-service/src/main/java/com/fs/his/service/impl/FsUserServiceImpl.java
  53. 2 0
      fs-service/src/main/java/com/fs/his/vo/FsPackageListVO.java
  54. 42 0
      fs-service/src/main/java/com/fs/his/vo/FsPackageSolarTermVO.java
  55. 2 0
      fs-service/src/main/java/com/fs/his/vo/FsPackageVO.java
  56. 4 0
      fs-service/src/main/java/com/fs/his/vo/FsUserVO.java
  57. 9 0
      fs-service/src/main/java/com/fs/qw/param/GenerateShortLinkParam.java
  58. 2 2
      fs-service/src/main/resources/application-config-druid-jnmy.yml
  59. 1 0
      fs-service/src/main/resources/application-config-druid-sft.yml
  60. 3 0
      fs-service/src/main/resources/application-druid-fby.yml
  61. 3 0
      fs-service/src/main/resources/application-druid-sft.yml
  62. 46 0
      fs-service/src/main/resources/db/20250801-节气限定.sql
  63. 7 2
      fs-service/src/main/resources/mapper/course/FsCourseQuestionBankMapper.xml
  64. 34 0
      fs-service/src/main/resources/mapper/course/FsCourseTrafficLogMapper.xml
  65. 11 0
      fs-service/src/main/resources/mapper/course/FsUserCourseMapper.xml
  66. 10 1
      fs-service/src/main/resources/mapper/course/FsUserCoursePeriodMapper.xml
  67. 3 0
      fs-service/src/main/resources/mapper/course/FsUserCourseTrainingCampMapper.xml
  68. 9 0
      fs-service/src/main/resources/mapper/course/FsUserCourseVideoMapper.xml
  69. 3 0
      fs-service/src/main/resources/mapper/course/FsVideoResourceMapper.xml
  70. 5 1
      fs-service/src/main/resources/mapper/his/FsPackageMapper.xml
  71. 24 0
      fs-service/src/main/resources/mapper/his/FsPackageSolarTermMapper.xml
  72. 2 1
      fs-user-app/src/main/java/com/fs/app/controller/course/CourseQwController.java

+ 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("操作成功");
+
+    }
+}

+ 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("操作成功");
+
+    }
+}

+ 16 - 1
fs-admin/src/main/java/com/fs/course/controller/FsCourseProductOrderController.java

@@ -7,7 +7,6 @@ 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 com.fs.his.param.FsInquiryOrderRefundParam;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -30,6 +29,8 @@ 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
  * 
@@ -121,4 +122,18 @@ public class FsCourseProductOrderController extends BaseController
         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);
+    }
 }

+ 8 - 1
fs-admin/src/main/java/com/fs/course/controller/FsCourseQuestionBankController.java

@@ -43,6 +43,9 @@ public class FsCourseQuestionBankController extends BaseController
     public TableDataInfo list(FsCourseQuestionBank fsCourseQuestionBank)
     {
         startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long userId = loginUser.getUser().getUserId();
+        fsCourseQuestionBank.setUserId(userId);
         List<FsCourseQuestionBank> list = fsCourseQuestionBankService.selectFsCourseQuestionBankList(fsCourseQuestionBank);
         return getDataTable(list);
     }
@@ -55,6 +58,9 @@ public class FsCourseQuestionBankController extends BaseController
     @GetMapping("/export")
     public AjaxResult export(FsCourseQuestionBank fsCourseQuestionBank)
     {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long userId = loginUser.getUser().getUserId();
+        fsCourseQuestionBank.setUserId(userId);
         List<FsCourseQuestionBankImportDTO> list = fsCourseQuestionBankService.exportData(fsCourseQuestionBank);
         ExcelUtil<FsCourseQuestionBankImportDTO> util = new ExcelUtil<>(FsCourseQuestionBankImportDTO.class);
         return util.exportExcel(list, "题库数据");
@@ -81,6 +87,7 @@ public class FsCourseQuestionBankController extends BaseController
     {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         fsCourseQuestionBank.setCreateBy(loginUser.getUser().getNickName());
+        fsCourseQuestionBank.setUserId(loginUser.getUser().getUserId());
         return toAjax(fsCourseQuestionBankService.insertFsCourseQuestionBank(fsCourseQuestionBank));
     }
 
@@ -121,7 +128,7 @@ public class FsCourseQuestionBankController extends BaseController
         List<FsCourseQuestionBankImportDTO> list = util.importExcel(file.getInputStream());
 
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-        String message = fsCourseQuestionBankService.importData(list, loginUser.getUser().getNickName());
+        String message = fsCourseQuestionBankService.importData(list, loginUser.getUser().getNickName(), loginUser.getUser().getUserId());
         return AjaxResult.success(message);
     }
 

+ 1 - 1
fs-admin/src/main/java/com/fs/course/controller/FsCourseRedPacketLogController.java

@@ -135,7 +135,7 @@ public class FsCourseRedPacketLogController extends BaseController
     @GetMapping("/courseList")
     public R courseList()
     {
-        List<OptionsVO> optionsVOS = fsUserCourseMapper.selectFsUserCourseAllList();
+        List<OptionsVO> optionsVOS = fsUserCourseMapper.selectFsUserCourseAllList(null);
         return R.ok().put("list", optionsVOS);
     }
 

+ 30 - 2
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,10 @@ public class FsUserCourseController extends BaseController
 
     @Autowired
     private RedisCacheUtil redisCacheUtil;
+
+    @Autowired
+    private TokenService tokenService;
+
     /**
      * 查询课程列表
      */
@@ -48,6 +55,9 @@ public class FsUserCourseController extends BaseController
     public TableDataInfo list(FsUserCourse fsUserCourse)
     {
         startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long userId = loginUser.getUser().getUserId();
+        fsUserCourse.setUserId(userId);
         List<FsUserCourseListPVO> list = fsUserCourseService.selectFsUserCourseListPVO(fsUserCourse);
         return getDataTable(list);
     }
@@ -60,6 +70,9 @@ public class FsUserCourseController extends BaseController
     public TableDataInfo publicList(FsUserCourse fsUserCourse)
     {
         startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long userId = loginUser.getUser().getUserId();
+        fsUserCourse.setUserId(userId);
         List<FsUserCourseListPVO> list = fsUserCourseService.selectFsUserCourseListPVO(fsUserCourse);
         return getDataTable(list);
     }
@@ -72,6 +85,9 @@ public class FsUserCourseController extends BaseController
     @GetMapping("/export")
     public AjaxResult export(FsUserCourse fsUserCourse)
     {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long userId = loginUser.getUser().getUserId();
+        fsUserCourse.setUserId(userId);
         List<FsUserCourse> list = fsUserCourseService.selectFsUserCourseList(fsUserCourse);
         ExcelUtil<FsUserCourse> util = new ExcelUtil<FsUserCourse>(FsUserCourse.class);
         return util.exportExcel(list, "课程数据");
@@ -85,6 +101,9 @@ public class FsUserCourseController extends BaseController
     @GetMapping("/publicExport")
     public AjaxResult publicExport(FsUserCourse fsUserCourse)
     {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long userId = loginUser.getUser().getUserId();
+        fsUserCourse.setUserId(userId);
         List<FsUserCourse> list = fsUserCourseService.selectFsUserCourseList(fsUserCourse);
         ExcelUtil<FsUserCourse> util = new ExcelUtil<FsUserCourse>(FsUserCourse.class);
         return util.exportExcel(list, "课程数据");
@@ -118,6 +137,9 @@ public class FsUserCourseController extends BaseController
     @PostMapping
     public AjaxResult add(@RequestBody FsUserCourse fsUserCourse)
     {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long userId = loginUser.getUser().getUserId();
+        fsUserCourse.setUserId(userId);
         fsUserCourseService.insertFsUserCourse(fsUserCourse);
         redisCacheUtil.delRedisKey("getCourseList");
 
@@ -132,6 +154,9 @@ public class FsUserCourseController extends BaseController
     @PostMapping("/public")
     public AjaxResult publicAdd(@RequestBody FsUserCourse fsUserCourse)
     {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long userId = loginUser.getUser().getUserId();
+        fsUserCourse.setUserId(userId);
         fsUserCourseService.insertFsUserCourse(fsUserCourse);
         redisCacheUtil.delRedisKey("getCourseList");
 
@@ -172,7 +197,9 @@ public class FsUserCourseController extends BaseController
     @GetMapping("/copy/{courseId}")
     public AjaxResult copy(@PathVariable Long courseId)
     {
-        int i = fsUserCourseService.copyFsUserCourse(courseId);
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long userId = loginUser.getUser().getUserId();
+        int i = fsUserCourseService.copyFsUserCourse(courseId, userId);
         return toAjax(i);
     }
 
@@ -205,7 +232,8 @@ public class FsUserCourseController extends BaseController
     @GetMapping("/getAllList")
     public R getAllList()
     {
-        List<OptionsVO> list = fsUserCourseService.selectFsUserCourseAllList();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        List<OptionsVO> list = fsUserCourseService.selectFsUserCourseAllList(loginUser.getUser().getUserId());
         return R.ok().put("data", list);
     }
 

+ 14 - 1
fs-admin/src/main/java/com/fs/course/controller/FsUserCourseTrainingCampController.java

@@ -3,17 +3,23 @@ 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;
 import com.fs.course.dto.FsUserCourseTrainingCampUpdateDTO;
 import com.fs.course.service.IFsUserCourseTrainingCampService;
 import com.fs.course.vo.FsUserCourseTrainingCampVO;
+import com.fs.framework.web.service.TokenService;
 import com.fs.his.vo.OptionsVO;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import lombok.AllArgsConstructor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
@@ -28,8 +34,12 @@ import java.util.Objects;
 @AllArgsConstructor
 public class FsUserCourseTrainingCampController {
 
+    private static final Logger log = LoggerFactory.getLogger(FsUserCourseTrainingCampController.class);
     private final IFsUserCourseTrainingCampService fsUserCourseTrainingCampService;
 
+    @Autowired
+    private TokenService tokenService;
+
     /**
      * 查询训练营列表
      */
@@ -60,7 +70,10 @@ public class FsUserCourseTrainingCampController {
     @Log(title = "训练营", businessType = BusinessType.INSERT)
     @PostMapping
     public AjaxResult add(@Valid @RequestBody FsUserCourseTrainingCampDTO params) {
-        fsUserCourseTrainingCampService.add(params);
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long userId = loginUser.getUser().getUserId();
+
+        fsUserCourseTrainingCampService.add(params, userId);
         return AjaxResult.success();
     }
 

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

@@ -4,8 +4,10 @@ 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;
@@ -15,6 +17,7 @@ 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;
@@ -44,6 +47,9 @@ public class FsUserCourseVideoController extends BaseController
     @Autowired
     private IFsUserCourseService fsUserCourseService;
 
+    @Autowired
+    private TokenService tokenService;
+
     /**
      * 查询课堂视频列表
      */
@@ -64,6 +70,9 @@ public class FsUserCourseVideoController extends BaseController
     @GetMapping("/export")
     public AjaxResult export(FsUserCourseVideo fsUserCourseVideo)
     {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long userId = loginUser.getUser().getUserId();
+        fsUserCourseVideo.setUserId(userId);
         List<FsUserCourseVideo> list = fsUserCourseVideoService.selectFsUserCourseVideoList(fsUserCourseVideo);
         ExcelUtil<FsUserCourseVideo> util = new ExcelUtil<FsUserCourseVideo>(FsUserCourseVideo.class);
         return util.exportExcel(list, "课堂视频数据");
@@ -91,6 +100,9 @@ public class FsUserCourseVideoController extends BaseController
         if (count>0){
             return AjaxResult.error("课程排序重复");
         }
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long userId = loginUser.getUser().getUserId();
+        fsUserCourseVideo.setUserId(userId);
 
         // 设置项目ID
         FsUserCourse fsUserCourse = fsUserCourseService.selectFsUserCourseByCourseId(fsUserCourseVideo.getCourseId());
@@ -125,6 +137,9 @@ public class FsUserCourseVideoController extends BaseController
     public TableDataInfo getVideoListByCourseId(FsUserCourseVideo fsUserCourseVideo)
     {
         startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long userId = loginUser.getUser().getUserId();
+        fsUserCourseVideo.setUserId(userId);
         List<FsUserCourseVideo> list = fsUserCourseVideoService.selectFsUserCourseVideoListByCourseId(fsUserCourseVideo);
         return getDataTable(list);
     }

+ 18 - 1
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.*;
 
@@ -29,6 +33,9 @@ public class FsVideoResourceController extends BaseController {
 
     private final IFsVideoResourceService fsVideoResourceService;
 
+    @Autowired
+    private TokenService tokenService;
+
     /**
      * 查询视频素材库列表
      */
@@ -46,6 +53,8 @@ public class FsVideoResourceController extends BaseController {
         params.put("fileName", fileName);
         params.put("typeId", typeId);
         params.put("typeSubId", typeSubId);
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        params.put("userId", loginUser.getUser().getUserId());
 
         PageHelper.startPage(pageNum, pageSize);
         List<FsVideoResourceVO> list = fsVideoResourceService.selectVideoResourceListByMap(params);
@@ -71,6 +80,9 @@ public class FsVideoResourceController extends BaseController {
     @PostMapping
     public AjaxResult add(@RequestBody FsVideoResource fsVideoResource)
     {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long userId = loginUser.getUser().getUserId();
+        fsVideoResource.setUserId(userId);
         fsVideoResource.setCreateTime(LocalDateTime.now());
         fsVideoResourceService.save(fsVideoResource);
         return AjaxResult.success();
@@ -144,10 +156,15 @@ public class FsVideoResourceController extends BaseController {
     @Log(title = "视频素材库", businessType = BusinessType.INSERT)
     @PostMapping("/batchAddVideoResource")
     public AjaxResult batchAddVideoResource(@RequestBody List<FsVideoResource> list) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long userId = loginUser.getUser().getUserId();
         if (Objects.isNull(list) || list.isEmpty()) {
             return AjaxResult.error("数据不能为空");
         }
-        list.forEach(v -> v.setCreateTime(LocalDateTime.now()));
+        list.forEach(v -> {
+            v.setCreateTime(LocalDateTime.now());
+            v.setUserId(userId);
+        });
         fsVideoResourceService.saveBatch(list);
         return AjaxResult.success();
     }

+ 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());
+    }
+}

+ 1 - 1
fs-admin/src/main/java/com/fs/qw/controller/QwSopController.java

@@ -77,7 +77,7 @@ public class QwSopController extends BaseController
     @GetMapping("/courseList")
     public R courseList()
     {
-        List<OptionsVO> optionsVOS = fsUserCourseMapper.selectFsUserCourseAllList();
+        List<OptionsVO> optionsVOS = fsUserCourseMapper.selectFsUserCourseAllList(null);
         return R.ok().put("list", optionsVOS);
     }
 

+ 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(null);
+        return R.ok().put("list", optionsVOS);
+    }
+}

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

@@ -78,7 +78,7 @@ public class FsUserCourseController extends BaseController
     @GetMapping("/getAllList")
     public R getAllList()
     {
-        List<OptionsVO> list = fsUserCourseService.selectFsUserCourseAllList();
+        List<OptionsVO> list = fsUserCourseService.selectFsUserCourseAllList(null);
         return R.ok().put("data", list);
     }
 

+ 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();
+    }
+
+}

+ 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());
+    }
 }

+ 1 - 0
fs-company/src/main/java/com/fs/user/FsUserAdminController.java

@@ -74,6 +74,7 @@ public class FsUserAdminController extends BaseController {
         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("当前销售不存在!");

+ 2 - 0
fs-service/src/main/java/com/fs/course/domain/FsCourseQuestionBank.java

@@ -43,4 +43,6 @@ public class FsCourseQuestionBank extends BaseEntity
     private String answer;
     private Long questionType;
     private Long questionSubType;
+
+    private Long userId;
 }

+ 2 - 0
fs-service/src/main/java/com/fs/course/domain/FsUserCourse.java

@@ -135,6 +135,8 @@ public class FsUserCourse extends BaseEntity
     @Excel(name = "课程类型  1vip  2 积分")
     private Long courseType;
 
+    private Long userId;
+
     private Long talentId;
 
     private Integer isDel;

+ 2 - 0
fs-service/src/main/java/com/fs/course/domain/FsUserCourseTrainingCamp.java

@@ -41,4 +41,6 @@ public class FsUserCourseTrainingCamp
      * 删除状态0、正常,1、已删除
      */
     private Integer delFlag;
+
+    private Long userId;
 }

+ 2 - 0
fs-service/src/main/java/com/fs/course/domain/FsVideoResource.java

@@ -97,4 +97,6 @@ public class FsVideoResource {
     private String transcodeFileKey;//转码的文件key
 
     private Integer sort;
+
+    private Long userId;
 }

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

@@ -108,4 +108,6 @@ public interface FsCourseTrafficLogMapper
     List<FsCourseTrafficLog> selectCourseTrafficLogByTwoDaysLater(@Param("offset")Integer offset,@Param("limit")Integer limit);
     @DataSource(DataSourceType.CLICKHOUSE)
     void insertCourseTrafficLogByTwoDaysLaterBatch(@Param("list") List<FsCourseTrafficLog> redPacketLogs);
+
+    List<FsCourseTrafficLogListVO> selectTrafficNew(FsCourseTrafficLogParam param);
 }

+ 7 - 3
fs-service/src/main/java/com/fs/course/mapper/FsUserCourseMapper.java

@@ -137,6 +137,12 @@ public interface FsUserCourseMapper
             "<if test = ' maps.cateId !=null '> " +
             "and (cc.cate_id =#{maps.cateId} or cc.pid=#{maps.cateId} )" +
             "</if>" +
+            "<if test = ' maps.subCateId !=null '> " +
+            "and c.sub_cate_id =#{maps.subCateId}" +
+            "</if>" +
+            "<if test = ' maps.userId !=null '> " +
+            "and c.user_id =#{maps.userId}" +
+            "</if>" +
             "<if test = ' maps.courseName!=null and maps.courseName != \"\" '> " +
             "and c.course_name like concat('%', #{maps.courseName}, '%') " +
             "</if>" +
@@ -226,9 +232,7 @@ public interface FsUserCourseMapper
 
 
 
-    @Select("select course_id dict_value, course_name dict_label,img_url dict_imgUrl  from fs_user_course where is_del = 0 and is_private = 1 ")
-    List<OptionsVO> selectFsUserCourseAllList();
-
+    List<OptionsVO> selectFsUserCourseAllList(@Param("userId") Long userId);
 
     @Select("select course_id dict_value, course_name dict_label,img_url dict_imgUrl  from fs_user_course where is_del = 0 and is_private = 1" +
             " and find_in_set(#{companyId},company_ids) ")

+ 6 - 0
fs-service/src/main/java/com/fs/course/mapper/FsUserCourseVideoMapper.java

@@ -85,6 +85,9 @@ public interface FsUserCourseVideoMapper
             "<if test = ' maps.title!=null and maps.title != \"\" '> " +
             "and v.title = #{maps.title} " +
             "</if>" +
+            "<if test = ' maps.userId!=null and maps.userId != \"\" '> " +
+            "and v.user_id = #{maps.userId} " +
+            "</if>" +
             " order by v.course_sort  "+
             "</script>"})
     List<FsUserCourseVideo> selectFsUserCourseVideoListByCourseId(@Param("maps") FsUserCourseVideo fsUserCourseVideo);
@@ -216,4 +219,7 @@ public interface FsUserCourseVideoMapper
 
     @Select("select title from fs_user_course_video WHERE video_id=#{videoId}")
     String selectFsUserCourseVideoByVideoForTitle(@Param("videoId") Long videoId);
+
+    FsUserCourseVideo selectFsUserCourseVideoByVideoIdAndUserId(@Param("videoId") Long videoId,@Param("userId") Long userId);
+
 }

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

@@ -25,6 +25,8 @@ public class FsCourseAnswerLogsParam  extends BaseEntity  {
     private Long qwUserId;
     private Long userId;
     private String nickName;
+    private String project;
+
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date eTime;
 

+ 24 - 2
fs-service/src/main/java/com/fs/course/param/FsCourseTrafficLogParam.java

@@ -2,15 +2,37 @@ package com.fs.course.param;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
 
+import java.time.YearMonth;
 import java.util.Date;
 
 @Data
 public class FsCourseTrafficLogParam {
 
-    @JsonFormat(pattern = "yyyy-MM")
-    private Date time;
+    @DateTimeFormat(pattern = "yyyy-MM")
+    private YearMonth time;
+    /**
+     * 公司id
+     */
     private Long companyId;
     private Integer year;
     private Integer month;
+    /**
+     * 项目id
+     */
+    private Long project;
+    /**
+     * 课程id
+     */
+    private Long courseId;
+
+    private String startDate;
+    private String endDate;
+
+    /**
+     * tab类型
+     */
+    private String tabType;
+
 }

+ 17 - 0
fs-service/src/main/java/com/fs/course/param/InternetTrafficParam.java

@@ -0,0 +1,17 @@
+package com.fs.course.param;
+
+import lombok.Data;
+
+@Data
+public class InternetTrafficParam {
+
+  /**
+   * 充值金额
+   */
+  public String account;
+
+  /**
+   * 公司id
+   */
+  public Long companyId;
+}

+ 1 - 1
fs-service/src/main/java/com/fs/course/service/IFsCourseQuestionBankService.java

@@ -73,7 +73,7 @@ public interface IFsCourseQuestionBankService
      * @param nickName 昵称
      * @return String
      */
-    String importData(List<FsCourseQuestionBankImportDTO> list, @Size String nickName);
+    String importData(List<FsCourseQuestionBankImportDTO> list, String nickName, Long userId);
 
     /**
      * 根据ID查询题目

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

@@ -68,4 +68,6 @@ public interface IFsCourseTrafficLogService
      * 存储课程流量日志
      */
     void saveCourseTrafficLog();
+
+    List<FsCourseTrafficLogListVO> selectTrafficNew(FsCourseTrafficLogParam param);
 }

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

@@ -85,7 +85,7 @@ public interface IFsUserCourseService
 
     List<FsUserCourseListUVO> selectFsUserCourseListUVO(FsUserCourseListUParam param);
 
-    List<OptionsVO> selectFsUserCourseAllList();
+    List<OptionsVO> selectFsUserCourseAllList(Long userId);
 
     List<FsUserCourseListPVO> selectFsUserCourseListPVO(FsUserCourse param);
 
@@ -123,7 +123,7 @@ public interface IFsUserCourseService
 
     String createUserImageQR(@NotNull(message = "链接不能为空") String realLink, String backgroundImagePath, InputStream inputStream, String png, @NotNull(message = "销售id不能为空") Long companyUserId) throws Exception;
 
-    int copyFsUserCourse(Long courseId);
+    int copyFsUserCourse(Long courseId, Long userId);
 
     List<FsUserCourseVideoAppletVO> selectFsUserCourseVideoApplet();
 

+ 1 - 2
fs-service/src/main/java/com/fs/course/service/IFsUserCourseTrainingCampService.java

@@ -30,8 +30,7 @@ public interface IFsUserCourseTrainingCampService extends IService<FsUserCourseT
      * 新增训练营
      * @param params    参数
      */
-    void add(FsUserCourseTrainingCampDTO params);
-
+    void add(FsUserCourseTrainingCampDTO params,Long userId);
     /**
      * 删除训练营
      * @param ids   ids

+ 3 - 1
fs-service/src/main/java/com/fs/course/service/IFsUserCourseVideoService.java

@@ -36,7 +36,7 @@ public interface IFsUserCourseVideoService
      * @return 课堂视频
      */
     public FsUserCourseVideo selectFsUserCourseVideoByVideoId(Long videoId);
-    public FsUserCourseVideoQVO selectFsUserCourseVideoByVideoIdVO(Long videoId);
+    public FsUserCourseVideoQVO selectFsUserCourseVideoByVideoIdVO(Long videoId,Long userId);
 
     /**
      * 查询课堂视频列表
@@ -186,4 +186,6 @@ public interface IFsUserCourseVideoService
     R updateVideo();
 
     R checkUserInfo(Long userId);
+
+    FsUserCourseVideoQVO selectFsUserCourseVideoByVideoIdVO(Long videoId);
 }

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

@@ -153,6 +153,13 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
                     FsCourseProduct courseProduct = JSONUtil.toBean(productOrderVO.getProductJson(), FsCourseProduct.class);
                     productOrderVO.setProductName(courseProduct.getProductName());
                 }
+                if (productOrderVO.getUserPhone() != null && productOrderVO.getUserPhone().length() > 11) {
+                    productOrderVO.setUserPhone(PhoneUtil.decryptPhoneMk(productOrderVO.getUserPhone()));
+                } else {
+                    if (productOrderVO.getUserPhone()!=null) {
+                        productOrderVO.setUserPhone(productOrderVO.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                    }
+                }
             });
         }
         return productOrderVOS;

+ 36 - 28
fs-service/src/main/java/com/fs/course/service/impl/FsCourseQuestionBankServiceImpl.java

@@ -241,11 +241,7 @@ public class FsCourseQuestionBankServiceImpl implements IFsCourseQuestionBankSer
 
     @Override
     @Transactional
-    public R courseAnswer(FsCourseQuestionAnswerUParam param, Boolean isH5User) {
-        FsUser user = fsUserMapper.selectFsUserByUserId(param.getUserId());
-        if (user==null){
-            return R.error("未识别到领取信息");
-        }
+    public R courseAnswer(FsCourseQuestionAnswerUParam param,Boolean isH5User) {
         //获取配置参数
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
@@ -258,35 +254,46 @@ public class FsCourseQuestionBankServiceImpl implements IFsCourseQuestionBankSer
         //日志id
         Long logId = null;
 
-        new FsCourseAnswerLogs();
-        FsCourseAnswerLogs rightLog;
+        FsCourseAnswerLogs rightLog = new FsCourseAnswerLogs();
         //判断短链类型
+        if (param.getLinkType()!=null&&param.getLinkType()==1){
+            rightLog = courseAnswerLogsMapper.selectRightLogByCourseVideo(param.getVideoId(), param.getUserId(),null);
+            if (rightLog!=null){
+                return R.error("该课程已答题完成,不可重复答题");
+            }
+            errorCount = courseAnswerLogsMapper.selectErrorCountByCourseVideo(param.getVideoId(), param.getUserId(),null);
 
-        FsCourseWatchLog log = courseWatchLogMapper.getWatchLogByFsUser(param.getVideoId(), param.getUserId(), param.getCompanyUserId());
-        if (log==null){
-            return R.error("无记录");
-        }
-        if (log.getLogType()!=2){
-            return R.error("未完课");
-        }
-        logId = log.getLogId();
-
-        rightLog = courseAnswerLogsMapper.selectRightLogByCourseVideo(param.getVideoId(), param.getUserId(), param.getQwUserId());
-        if (rightLog != null) {
-            if (log.getRewardType() != null) {
-                // 增加判断,去查询红包记录是否已发送成功,如果成功,则返回当前提示,否则返回答题成功(让其可以继续答题,直到红包领取完成)
-                FsCourseRedPacketLog fsCourseRedPacketLog = redPacketLogMapper.selectUserFsCourseRedPacketLog(param.getVideoId(), param.getUserId(),param.getPeriodId());
-                if(fsCourseRedPacketLog != null && fsCourseRedPacketLog.getStatus() == 1) {
-                    return R.error("该课程已答题完成,不可重复答题");
+        }else {
+            FsCourseWatchLog log;
+            if(isH5User){
+                log = courseWatchLogMapper.getWatchLogByFsUser(param.getVideoId(), param.getUserId(), param.getCompanyUserId());
+            } else {
+                log = courseWatchLogMapper.getWatchCourseVideo(param.getUserId(), param.getVideoId(), param.getQwUserId(), param.getQwExternalId());
+            }
+            if (log==null){
+                return R.error("无记录");
+            }
+            if (log.getLogType()!=2){
+                return R.error("未完课");
+            }
+            logId = log.getLogId();
+
+            rightLog = courseAnswerLogsMapper.selectRightLogByCourseVideo(param.getVideoId(), param.getUserId(), param.getQwUserId());
+            if (rightLog != null) {
+                if (log.getRewardType() != null) {
+                    // 增加判断,去查询红包记录是否已发送成功,如果成功,则返回当前提示,否则返回答题成功(让其可以继续答题,直到红包领取完成)
+                    FsCourseRedPacketLog fsCourseRedPacketLog = redPacketLogMapper.selectUserFsCourseRedPacketLog(param.getVideoId(), param.getUserId(),param.getPeriodId());
+                    if(fsCourseRedPacketLog != null && fsCourseRedPacketLog.getStatus() == 1) {
+                        return R.error("该课程已答题完成,不可重复答题");
+                    } else {
+                        return R.ok("答题成功");
+                    }
                 } else {
                     return R.ok("答题成功");
                 }
-            } else {
-                return R.ok("答题成功");
             }
+            errorCount = courseAnswerLogsMapper.selectErrorCountByCourseVideo(param.getVideoId(), param.getUserId(),param.getQwUserId());
         }
-        errorCount = courseAnswerLogsMapper.selectErrorCountByCourseVideo(param.getVideoId(), param.getUserId(),param.getQwUserId());
-
 
 
         if (errorCount >= config.getAnswerErrorCount()) {
@@ -355,7 +362,7 @@ public class FsCourseQuestionBankServiceImpl implements IFsCourseQuestionBankSer
      * @return String
      */
     @Override
-    public String importData(List<FsCourseQuestionBankImportDTO> list, @Size String nickName) {
+    public String importData(List<FsCourseQuestionBankImportDTO> list, String nickName,Long userId) {
         if (Objects.isNull(list) || list.isEmpty()) {
             throw new ServiceException("导入数据不能为空");
         }
@@ -375,6 +382,7 @@ public class FsCourseQuestionBankServiceImpl implements IFsCourseQuestionBankSer
 
                 // 构建题目对象
                 FsCourseQuestionBank questionBank = buildQuestionBank(importDTO, categoryData, nickName);
+                questionBank.setUserId(userId);
                 importData.add(questionBank);
                 result.addSuccess(importDTO.getTitle());
 

+ 44 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsCourseTrafficLogServiceImpl.java

@@ -4,9 +4,16 @@ import java.text.SimpleDateFormat;
 import java.util.Collections;
 import java.util.Date;
 import java.util.List;
+
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.fs.common.exception.CustomException;
 import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.DictUtils;
+import com.fs.company.cache.ICompanyCacheService;
 import com.fs.course.param.FsCourseTrafficLogParam;
 import com.fs.course.vo.FsCourseTrafficLogListVO;
+import com.fs.store.service.cache.IFsUserCourseCacheService;
+import com.hc.openapi.tool.util.StringUtils;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -27,6 +34,12 @@ public class FsCourseTrafficLogServiceImpl implements IFsCourseTrafficLogService
     @Autowired
     private FsCourseTrafficLogMapper fsCourseTrafficLogMapper;
 
+    @Autowired
+    private ICompanyCacheService companyCacheService;
+
+    @Autowired
+    private IFsUserCourseCacheService fsUserCourseCacheService;
+
     /**
      * 查询短链课程流量记录
      *
@@ -158,6 +171,37 @@ public class FsCourseTrafficLogServiceImpl implements IFsCourseTrafficLogService
         log.info("总耗时: {}", formatDuration(endTime - startTime));
     }
 
+    @Override
+    public List<FsCourseTrafficLogListVO> selectTrafficNew(FsCourseTrafficLogParam param) {
+        if(StringUtils.isBlank(param.getStartDate()) && StringUtils.isBlank(param.getEndDate())){
+            throw new CustomException("搜索必须要一个时间范围!");
+        }
+        List<FsCourseTrafficLogListVO> fsCourseTrafficLogListVOS = fsCourseTrafficLogMapper.selectTrafficNew(param);
+        for (FsCourseTrafficLogListVO log : fsCourseTrafficLogListVOS) {
+            if (ObjectUtils.isNotNull(log.getProject())) {
+                String sysCourseProject = DictUtils.getDictLabel("sys_course_project", String.valueOf(log.getProject()));
+                if (StringUtils.isNotBlank(sysCourseProject)) {
+                    log.setProjectName(sysCourseProject);
+                }
+            }
+
+            if (ObjectUtils.isNotNull(log.getCompanyId())) {
+                String companyName = companyCacheService.selectCompanyNameById(log.getCompanyId());
+                if (StringUtils.isNotBlank(companyName)) {
+                    log.setCompanyName(companyName);
+                }
+            }
+
+            if (ObjectUtils.isNotNull(log.getCourseId())) {
+                String courseName = fsUserCourseCacheService.selectCourseNameByCourseId(log.getCourseId());
+                if (StringUtils.isNotBlank(courseName)) {
+                    log.setCourseName(courseName);
+                }
+            }
+        }
+        return fsCourseTrafficLogListVOS;
+    }
+
     private static String formatDuration(long millis) {
         long seconds = millis / 1000;
         long minutes = seconds / 60;

+ 5 - 3
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseServiceImpl.java

@@ -277,8 +277,8 @@ public class FsUserCourseServiceImpl implements IFsUserCourseService
     }
 
     @Override
-    public List<OptionsVO> selectFsUserCourseAllList() {
-        return fsUserCourseMapper.selectFsUserCourseAllList();
+    public List<OptionsVO> selectFsUserCourseAllList(Long userId) {
+        return fsUserCourseMapper.selectFsUserCourseAllList(userId);
     }
 
 
@@ -663,10 +663,11 @@ public class FsUserCourseServiceImpl implements IFsUserCourseService
 
     @Override
     @Transactional(rollbackFor = Exception.class) // 显式声明事务
-    public int copyFsUserCourse(Long courseId) {
+    public int copyFsUserCourse(Long courseId, Long userId) {
         FsUserCourse fsUserCourse = fsUserCourseService.selectFsUserCourseByCourseId(courseId);
         if(fsUserCourse != null){
             fsUserCourse.setCourseId(null);
+            fsUserCourse.setUserId(userId);
             fsUserCourseService.insertFsUserCourse(fsUserCourse);
             Long newCourseId = fsUserCourse.getCourseId();
 
@@ -676,6 +677,7 @@ public class FsUserCourseServiceImpl implements IFsUserCourseService
 
             FsUserCourseVideo fsUserCourseVideo = new FsUserCourseVideo();
             fsUserCourseVideo.setCourseId(courseId);
+            fsUserCourseVideo.setUserId(userId);
             List<FsUserCourseVideo> list = fsUserCourseVideoService.selectFsUserCourseVideoListByCourseId(fsUserCourseVideo);
             for (FsUserCourseVideo courseVideo : list) {
                 courseVideo.setVideoId(null);

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

@@ -62,11 +62,12 @@ public class FsUserCourseTrainingCampServiceImpl extends ServiceImpl<FsUserCours
      * @param params    参数
      */
     @Override
-    public void add(FsUserCourseTrainingCampDTO params) {
+    public void add(FsUserCourseTrainingCampDTO params,Long userId) {
         FsUserCourseTrainingCamp trainingCamp = new FsUserCourseTrainingCamp();
         trainingCamp.setTrainingCampName(params.getTrainingCampName());
         trainingCamp.setOrderNumber(baseMapper.getOrderNumber());
         trainingCamp.setCreateTime(LocalDateTime.now());
+        trainingCamp.setUserId(userId);
         baseMapper.insert(trainingCamp);
     }
 

+ 137 - 77
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -215,9 +215,9 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     }
 
     @Override
-    public FsUserCourseVideoQVO selectFsUserCourseVideoByVideoIdVO(Long videoId) {
+    public FsUserCourseVideoQVO selectFsUserCourseVideoByVideoIdVO(Long videoId,Long userId) {
         FsUserCourseVideoQVO fsUserCourseVideoQVO=new FsUserCourseVideoQVO();
-        FsUserCourseVideo courseVideo = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId(videoId);
+        FsUserCourseVideo courseVideo = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoIdAndUserId(videoId,userId);
 
         BeanCopyUtils.copy(courseVideo,fsUserCourseVideoQVO);
         if (courseVideo.getRedPacketMoney()!=null){
@@ -881,21 +881,28 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         FsCourseWatchLog log = new FsCourseWatchLog();
 
         // 根据链接类型判断是否已发放奖励
-        if (param.getLinkType() != null && param.getLinkType() == 1) {
+        log = courseWatchLogMapper.getWatchCourseVideo(param.getUserId(), param.getVideoId(), param.getQwUserId(), param.getQwExternalId());
+        if (log == null) {
+            return R.error("无记录");
+        }
+        if (log.getRewardType() != null) {
             FsCourseRedPacketLog packetLog = redPacketLogMapper.selectFsCourseRedPacketLogByTemporary(param.getVideoId(), param.getUserId());
-            if (packetLog != null) {
+            if(packetLog != null && packetLog.getStatus() == 1) {
                 return R.error("奖励已发放");
             }
-        } else {
-            log = courseWatchLogMapper.getWatchCourseVideo(param.getUserId(), param.getVideoId(), param.getQwUserId(), param.getQwExternalId());
-            if (log == null) {
-                return R.error("无记录");
+            if(packetLog != null && packetLog.getStatus() == 0) {
+                if(StringUtils.isNotEmpty(packetLog.getResult())){
+                    R r = JSON.parseObject(packetLog.getResult(), R.class);
+                    return r;
+                } else {
+                    return R.error("奖励已发放");
+                }
             }
-            if (log.getRewardType() != null) {
-                return R.error("奖励已发放");
+            if(packetLog != null && packetLog.getStatus() == 2) {
+                return R.error("请联系客服补发");
             }
+            return R.error("奖励已发放");
         }
-
         // 获取视频信息
         FsUserCourseVideo video = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId(param.getVideoId());
 
@@ -973,19 +980,6 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
      * @return 处理结果
      */
     private R sendRedPacketReward(FsCourseSendRewardUParam param, FsUser user, FsCourseWatchLog log, FsUserCourseVideo video, CourseConfig config) {
-        // 判断是否属于领取红包时间(会员看课发放红包)
-        FsUserCoursePeriodDays periodDays = new FsUserCoursePeriodDays();
-        periodDays.setVideoId(param.getVideoId());
-        periodDays.setPeriodId(param.getPeriodId());
-        //正常情况是只能查询到一条,之前可能存在重复的脏数据,暂使用查询list的方式
-        List<FsUserCoursePeriodDays> fsUserCoursePeriodDays = fsUserCoursePeriodDaysMapper.selectFsUserCoursePeriodDaysList(periodDays);
-        if(fsUserCoursePeriodDays != null && !fsUserCoursePeriodDays.isEmpty()){
-            periodDays = fsUserCoursePeriodDays.get(0);
-        }
-
-        if(periodDays != null && periodDays.getLastJoinTime() !=null && LocalDateTime.now().isAfter(periodDays.getLastJoinTime())) {
-            return R.error(403,"已超过领取红包时间");
-        }
 
         // 确定红包金额
         BigDecimal amount = BigDecimal.ZERO;
@@ -1001,39 +995,46 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         WxSendRedPacketParam packetParam = new WxSendRedPacketParam();
         packetParam.setOpenId(user.getMpOpenId());
         // 来源是小程序切换openId
-//        if (param.getSource() == 2) {
-//            packetParam.setOpenId(user.getMaOpenId());
-//        }
         if (param.getSource() == 2) {
+            //处理多小程序问题
             FsUserWx fsUserWx = fsUserWxService.selectByAppIdAndUserId(param.getAppId(),user.getUserId(),1);
-            if (fsUserWx ==null){
-                packetParam.setOpenId(user.getMaOpenId());
-                try {
-                    handleFsUserWx(user,param.getAppId());
-                } catch (Exception e){
-                    e.printStackTrace();
-                    logger.error(e.getMessage(),e);
-                }
-
+            if (fsUserWx ==null || fsUserWx.getOpenId()==null){
+                packetParam.setOpenId(user.getCourseMaOpenId());
             }else {
-                //查出openid并赋值
                 packetParam.setOpenId(fsUserWx.getOpenId());
             }
-
+            //查出公司绑定openid并赋值
 
         }
         packetParam.setAmount(amount);
         packetParam.setSource(param.getSource());
         packetParam.setRedPacketMode(config.getRedPacketMode());
         packetParam.setCompanyId(param.getCompanyId());
-        packetParam.setAppId(param.getAppId());
-        if (StringUtils.isNotEmpty(param.getCode())){
-            packetParam.setCode(param.getCode());
-            packetParam.setUser(user);
-        }
 
-        //2025.7.11 红包金额为0的时候
+        System.out.println("红包金额"+amount);
+        System.out.println("红包商户号"+packetParam);
+        //2025.6.19 红包金额为0的时候
         if (amount.compareTo(BigDecimal.ZERO)>0){
+
+            Company company = companyMapper.selectCompanyByIdForUpdate(param.getCompanyId());
+            BigDecimal money = company.getMoney();
+            BigDecimal subtract = money.subtract(amount);
+            if (subtract.compareTo(BigDecimal.ZERO)<0){
+                FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
+                redPacketLog.setCourseId(param.getCourseId());
+                redPacketLog.setCompanyId(param.getCompanyId());
+                redPacketLog.setUserId(param.getUserId());
+                redPacketLog.setVideoId(param.getVideoId());
+                redPacketLog.setStatus(2);
+                redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
+                redPacketLog.setCompanyUserId(param.getCompanyUserId());
+                redPacketLog.setCreateTime(new Date());
+                redPacketLog.setAmount(amount);
+                redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
+                redPacketLog.setPeriodId(param.getPeriodId());
+                redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
+                return R.error("销售公司余额不足");
+            }
             // 发送红包
             R sendRedPacket = paymentService.sendRedPacket(packetParam);
             if (sendRedPacket.get("code").equals(200)) {
@@ -1043,10 +1044,8 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
                     transferBillsResult = (TransferBillsResult)sendRedPacket.get("data");
                     redPacketLog.setResult(JSON.toJSONString(sendRedPacket));
                     redPacketLog.setOutBatchNo(transferBillsResult.getOutBillNo());
-                    redPacketLog.setBatchId(transferBillsResult.getTransferBillNo());
                 }else {
                     redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
-                    redPacketLog.setBatchId(sendRedPacket.get("batchId").toString());
                 }
                 // 添加红包记录
                 redPacketLog.setCourseId(param.getCourseId());
@@ -1061,22 +1060,28 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
                 redPacketLog.setAmount(amount);
                 redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
                 redPacketLog.setPeriodId(param.getPeriodId());
-                redPacketLog.setAppId(param.getAppId());
-
                 redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
 
                 // 更新观看记录的奖励类型
-//            if (param.getLinkType() == null || param.getLinkType() == 0) {
                 log.setRewardType(config.getRewardType());
                 courseWatchLogMapper.updateFsCourseWatchLog(log);
-//            }
+                company.setMoney(subtract);
+                companyMapper.updateCompany(company);
+
+                CompanyMoneyLogs logs=new CompanyMoneyLogs();
+                logs.setCompanyId(company.getCompanyId());
+                logs.setRemark("扣除红包金额");
+                logs.setMoney(amount.multiply(new BigDecimal(-1)));
+                logs.setLogsType(15);
+                logs.setBalance(company.getMoney());
+                logs.setCreateTime(new Date());
+                moneyLogsMapper.insertCompanyMoneyLogs(logs);
+
                 return sendRedPacket;
             } else {
                 return R.error("奖励发送失败,请联系客服");
             }
-
         } else {
-            // 发送红包
             FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
             // 添加红包记录
             redPacketLog.setCourseId(param.getCourseId());
@@ -1084,8 +1089,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             redPacketLog.setCompanyId(param.getCompanyId());
             redPacketLog.setUserId(param.getUserId());
             redPacketLog.setVideoId(param.getVideoId());
-            redPacketLog.setStatus(1);//直接设置发送成功
-            redPacketLog.setResult("{\"msg\":\"发送0红包成功\",\"code\":200,\"isNew\":1}");
+            redPacketLog.setStatus(0);
             redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
             redPacketLog.setCompanyUserId(param.getCompanyUserId());
             redPacketLog.setCreateTime(new Date());
@@ -1095,34 +1099,13 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
 
             // 更新观看记录的奖励类型
+//            if (param.getLinkType() == null || param.getLinkType() == 0) {
             log.setRewardType(config.getRewardType());
             courseWatchLogMapper.updateFsCourseWatchLog(log);
+//            }
             return R.ok("红包发送成功");
         }
-    }
 
-    private void handleFsUserWx(FsUser user, String appId) {
-        // 尝试更新
-        boolean updated = fsUserWxService.lambdaUpdate()
-                .eq(FsUserWx::getFsUserId, user.getUserId())
-                .eq(FsUserWx::getAppId,appId )
-                .eq(FsUserWx::getOpenId, user.getMaOpenId())
-//                .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.setAppId(appId);
-            fsUserWx.setOpenId(user.getMaOpenId());
-//            fsUserWx.setUnionId(session.getUnionid() == null ? "" : session.getUnionid());
-            fsUserWx.setCreateTime(new Date());
-            fsUserWx.setUpdateTime(new Date());
-            fsUserWxService.save(fsUserWx);
-        }
     }
 
     /**
@@ -1487,6 +1470,9 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             return ResponseResult.fail(504, "课程项目不匹配");
         }
 
+        if (!isUserCoursePeriodValid(param)) {
+            return ResponseResult.fail(504, "请观看最新的课程项目");
+        }
         // 项目看课数限制
         Integer logCount = fsUserCourseMapper.selectTodayCourseWatchLogCountByUserIdAndProjectId(param.getUserId(), param.getProjectId());
         if (Objects.isNull(watchCourseVideo) && logCount > 0) {
@@ -1541,7 +1527,66 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 //        }
         return ResponseResult.ok(Boolean.TRUE);
     }
+    /**
+     * 检查用户课程时间段是否有效
+     * @param param 查询参数
+     * @return 如果当前时间在有效范围内且状态为1,返回true,否则返回false
+     */
+    public boolean isUserCoursePeriodValid(FsUserCourseAddCompanyUserParam param) {
+        // 查询课程周期信息
+        FsUserCoursePeriodDays periodDays = getPeriodDaysInfo(param);
+
+        // 获取公司用户时间段信息
+        LocalDateTime[] companyUserTimeRange = getCompanyUserTimeRange(param);
+        LocalDateTime companyUserStartDateTime = companyUserTimeRange[0];
+        LocalDateTime companyUserEndDateTime = companyUserTimeRange[1];
+
+        // 确定实际使用的开始和结束时间
+        LocalDateTime effectiveStartTime = companyUserStartDateTime != null ?
+                companyUserStartDateTime : periodDays.getStartDateTime();
+        LocalDateTime effectiveEndTime = companyUserEndDateTime != null ?
+                companyUserEndDateTime : periodDays.getEndDateTime();
+        // 检查时间范围和状态
+        return DateUtil.isWithinRangeSafe(LocalDateTime.now(), effectiveStartTime, effectiveEndTime)&& periodDays.getStatus() == 1;
+    }
 
+    // 其他辅助方法保持不变
+    private FsUserCoursePeriodDays getPeriodDaysInfo(FsUserCourseAddCompanyUserParam param) {
+        FsUserCoursePeriodDays query = new FsUserCoursePeriodDays();
+        query.setVideoId(param.getVideoId());
+        query.setPeriodId(param.getPeriodId());
+
+        List<FsUserCoursePeriodDays> periodDaysList = fsUserCoursePeriodDaysMapper.selectFsUserCoursePeriodDaysList(query);
+        return CollectionUtils.isNotEmpty(periodDaysList) ? periodDaysList.get(0) : query;
+    }
+
+    private LocalDateTime[] getCompanyUserTimeRange(FsUserCourseAddCompanyUserParam param) {
+        CompanyUserTimeQueryParam query = new CompanyUserTimeQueryParam();
+        query.setPeriodId(param.getPeriodId());
+        query.setCourseId(param.getCourseId());
+        query.setVideoId(param.getVideoId());
+        query.setCompanyUserId(param.getCompanyUserId());
+
+        List<FsUserCourseCompanyUserTime> companyUserTimes =
+                companyUserTimeMapper.batchSelectByParams(Collections.singletonList(query));
+
+        if (CollectionUtils.isEmpty(companyUserTimes)) {
+            return new LocalDateTime[]{null, null};
+        }
+
+        FsUserCourseCompanyUserTime companyUserTime = companyUserTimes.get(0);
+        return new LocalDateTime[]{
+                convertDateToLocalDateTime(companyUserTime.getStartDateTime()),
+                convertDateToLocalDateTime(companyUserTime.getEndDateTime())
+        };
+    }
+
+    private LocalDateTime convertDateToLocalDateTime(Date date) {
+        if (date == null) {
+            return null;
+        }
+        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
+    }
     // 添加关系表数据
     public static FsUserCompanyUser getFsUserCompanyUser(FsUserCourseAddCompanyUserParam param, FsUser fsUser) {
         FsUserCompanyUser fsUserCompanyUser = new FsUserCompanyUser();
@@ -2278,4 +2323,19 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         }
         return R.ok().put("user",user);
     }
+
+    @Override
+    public FsUserCourseVideoQVO selectFsUserCourseVideoByVideoIdVO(Long videoId) {
+        FsUserCourseVideoQVO fsUserCourseVideoQVO = new FsUserCourseVideoQVO();
+        FsUserCourseVideo courseVideo = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId(videoId);
+
+        BeanCopyUtils.copy(courseVideo,fsUserCourseVideoQVO);
+
+        if (StringUtils.isNotEmpty(courseVideo.getQuestionBankId())){
+            List<FsCourseQuestionBank> fsCourseQuestionBanks = courseQuestionBankMapper.selectFsCourseQuestionBankByIdVO(courseVideo.getQuestionBankId().split(","));
+            fsUserCourseVideoQVO.setQuestionBankList(fsCourseQuestionBanks);
+        }
+        return fsUserCourseVideoQVO;
+    }
+
 }

+ 5 - 0
fs-service/src/main/java/com/fs/course/vo/FsCourseTrafficLogListVO.java

@@ -16,6 +16,11 @@ import java.io.Serializable;
 public class FsCourseTrafficLogListVO implements Serializable
 {
     private String companyName;
+    private Long companyId;
+    private String courseName;
+    private Long courseId;
+    private String projectName;
+    private Long project;
 
     private Long totalInternetTraffic;
 

+ 4 - 0
fs-service/src/main/java/com/fs/course/vo/FsUserCoursePeriodVO.java

@@ -85,4 +85,8 @@ public class FsUserCoursePeriodVO implements Serializable {
     @Excel(name = "营期状态")
     private Long periodStatus;
 
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "营期线", width = 31, dateFormat = "yyyy-MM-dd")
+    private Date periodLine;
+
 }

+ 2 - 0
fs-service/src/main/java/com/fs/his/domain/FsPackage.java

@@ -101,4 +101,6 @@ public class FsPackage extends BaseEntity
     private String icdCode;
     @Excel(name = "描述")
     private String description;
+    /** 节气 */
+    private Long solarTerm;
 }

+ 58 - 0
fs-service/src/main/java/com/fs/his/domain/FsPackageSolarTerm.java

@@ -0,0 +1,58 @@
+package com.fs.his.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+@TableName("fs_package_solar_term")
+public class FsPackageSolarTerm {
+    /**
+     * 主键ID
+     */
+    @TableId(type = IdType.AUTO)
+    private Long id;
+    /**
+     * 节气名称
+     */
+    private String name;
+    /**
+     * 简介
+     */
+    @TableField("`desc`")
+    private String desc;
+    /**
+     * 开始时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime startTime;
+    /**
+     * 结束时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime endTime;
+    /**
+     * 序号
+     */
+    private Integer sort;
+    /**
+     * 是否删除 0正常 1删除
+     */
+    private Integer isDel;
+    /**
+     * 状态 1启用 0停用
+     */
+    private Integer status;
+    /**
+     * 创建时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime createTime;
+    /**
+     * 修改时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime updateTime;
+}

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

@@ -82,6 +82,7 @@ public interface FsPackageMapper
             "            <if test=\"maps.privateType != null \"> and private_type = #{maps.privateType}</if>\n" +
             "            <if test=\"maps.diseaseType != null \"> and disease_type = #{maps.diseaseType}</if>\n" +
             "            <if test=\"maps.isShow != null \"> and is_show = #{maps.isShow}</if>\n" +
+            "            <if test=\"maps.solarTerm != null \"> and solar_term = #{maps.solarTerm}</if>\n" +
             "        order by sort,package_id desc"+
             "</script>"})
 
@@ -141,4 +142,7 @@ public interface FsPackageMapper
     int updatePackagesStatus(@Param("packageIds")Long[] packageIds,@Param("status")Long status);
 
     List<String> selectIcdNameByPackageId(@Param("packageId")Long packageId);
+
+    @Update("UPDATE fs_package SET solar_term = NULL WHERE package_id = #{packageId}")
+    void setSolarTermIsNullById(@Param("packageId") Long packageId);
 }

+ 24 - 0
fs-service/src/main/java/com/fs/his/mapper/FsPackageSolarTermMapper.java

@@ -0,0 +1,24 @@
+package com.fs.his.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.company.vo.OptionVO;
+import com.fs.his.domain.FsPackageSolarTerm;
+import com.fs.his.param.FsPackageSolarTermParam;
+import com.fs.his.vo.FsPackageSolarTermVO;
+
+import java.util.List;
+
+public interface FsPackageSolarTermMapper extends BaseMapper<FsPackageSolarTerm> {
+
+    /**
+     * 根据条件查询节气列表
+     * @param param 参数
+     * @return  list
+     */
+    List<FsPackageSolarTermVO> selectFsPackageSolarTermListVO(FsPackageSolarTermParam param);
+
+    /**
+     * 获取节气选项
+     */
+    List<OptionVO> getOptions();
+}

+ 1 - 0
fs-service/src/main/java/com/fs/his/param/FsPackageParam.java

@@ -24,4 +24,5 @@ public class FsPackageParam implements Serializable {
     private Integer isDel;
     private Long packageId;
     private Integer isShow;
+    private Long solarTerm;
 }

+ 15 - 0
fs-service/src/main/java/com/fs/his/param/FsPackageSolarTermParam.java

@@ -0,0 +1,15 @@
+package com.fs.his.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+public class FsPackageSolarTermParam {
+
+    @ApiModelProperty("节气名称")
+    private String name;
+
+    @ApiModelProperty("节气状态")
+    private Integer status;
+
+}

+ 52 - 0
fs-service/src/main/java/com/fs/his/service/IFsPackageSolarTermService.java

@@ -0,0 +1,52 @@
+package com.fs.his.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.company.vo.OptionVO;
+import com.fs.his.domain.FsPackageSolarTerm;
+import com.fs.his.param.FsPackageSolarTermParam;
+import com.fs.his.vo.FsPackageSolarTermVO;
+
+import java.util.List;
+
+public interface IFsPackageSolarTermService extends IService<FsPackageSolarTerm> {
+
+    /**
+     * 查询节气列表
+     * @param param 参数
+     * @return List
+     */
+    List<FsPackageSolarTermVO> selectFsPackageSolarTermListVO(FsPackageSolarTermParam param);
+
+    /**
+     * 根据ID查询节气详情
+     * @param solarTermId id
+     * @return FsPackageSolarTermVO
+     */
+    FsPackageSolarTermVO selectFsPackageSolarTermVO(Long solarTermId);
+
+    /**
+     * 添加节气
+     * @param param 参数
+     * @return  受影响行数
+     */
+    int insertFsPackageSolarTerm(FsPackageSolarTerm param);
+
+    /**
+     * 修改节气
+     * @param param 参数
+     * @return  受影响行数
+     */
+    int updateFsPackageSolarTerm(FsPackageSolarTerm param);
+
+    /**
+     * 删除节气
+     * @param solarTermIds  ids
+     * @return  受影响行数
+     */
+    int deleteFsPackageSolarTermByIds(Long[] solarTermIds);
+
+    /**
+     * 获取节气选项
+     */
+    List<OptionVO> getOptions();
+}

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

@@ -8,6 +8,7 @@ import java.net.URL;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 import cn.hutool.json.JSONArray;
 import cn.hutool.json.JSONUtil;
@@ -30,6 +31,7 @@ import org.springframework.stereotype.Service;
 import com.fs.his.mapper.FsPackageMapper;
 import com.fs.his.domain.FsPackage;
 import com.fs.his.service.IFsPackageService;
+import org.springframework.transaction.annotation.Transactional;
 
 import javax.imageio.ImageIO;
 
@@ -104,6 +106,7 @@ public class FsPackageServiceImpl implements IFsPackageService {
      * @param fsPackage 套餐包
      * @return 结果
      */
+    @Transactional(rollbackFor = Exception.class)
     @Override
     public int updateFsPackage(FsPackage fsPackage) {
         fsPackage.setUpdateTime(DateUtils.getNowDate());
@@ -126,6 +129,11 @@ public class FsPackageServiceImpl implements IFsPackageService {
         if (isShow != null && isShow == 0) {
             fsPackage.setDiseaseType(-1);
         }
+
+        if (Objects.isNull(fsPackage.getSolarTerm())) {
+            fsPackageMapper.setSolarTermIsNullById(fsPackage.getPackageId());
+        }
+
         return fsPackageMapper.updateFsPackage(fsPackage);
     }
 

+ 98 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsPackageSolarTermServiceImpl.java

@@ -0,0 +1,98 @@
+package com.fs.his.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.BeanCopyUtils;
+import com.fs.common.exception.CustomException;
+import com.fs.company.vo.OptionVO;
+import com.fs.his.domain.FsPackageSolarTerm;
+import com.fs.his.mapper.FsPackageSolarTermMapper;
+import com.fs.his.param.FsPackageSolarTermParam;
+import com.fs.his.service.IFsPackageSolarTermService;
+import com.fs.his.vo.FsPackageSolarTermVO;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+@Service
+public class FsPackageSolarTermServiceImpl extends ServiceImpl<FsPackageSolarTermMapper, FsPackageSolarTerm> implements IFsPackageSolarTermService {
+
+    /**
+     * 查询节气列表
+     * @param param 参数
+     * @return List
+     */
+    @Override
+    public List<FsPackageSolarTermVO> selectFsPackageSolarTermListVO(FsPackageSolarTermParam param) {
+        return baseMapper.selectFsPackageSolarTermListVO(param);
+    }
+
+    /**
+     * 根据ID查询节气详情
+     * @param solarTermId id
+     * @return FsPackageSolarTermVO
+     */
+    @Override
+    public FsPackageSolarTermVO selectFsPackageSolarTermVO(Long solarTermId) {
+        FsPackageSolarTerm solarTerm = baseMapper.selectById(solarTermId);
+        if (Objects.isNull(solarTerm)) {
+            throw new CustomException("节气不存在");
+        }
+
+        return BeanCopyUtils.copy(solarTerm, FsPackageSolarTermVO.class);
+    }
+
+    /**
+     * 添加节气
+     * @param param 参数
+     * @return  受影响行数
+     */
+    @Override
+    public int insertFsPackageSolarTerm(FsPackageSolarTerm param) {
+        param.setCreateTime(LocalDateTime.now());
+        return baseMapper.insert(param);
+    }
+
+    /**
+     * 修改节气
+     * @param param 参数
+     * @return  受影响行数
+     */
+    @Override
+    public int updateFsPackageSolarTerm(FsPackageSolarTerm param) {
+        if (Objects.isNull(param.getId())) {
+            throw new CustomException("节气ID不能为空");
+        }
+        param.setUpdateTime(LocalDateTime.now());
+        return baseMapper.updateById(param);
+    }
+
+    /**
+     * 删除节气
+     * @param solarTermIds  ids
+     * @return  受影响行数
+     */
+    @Override
+    public int deleteFsPackageSolarTermByIds(Long[] solarTermIds) {
+        List<FsPackageSolarTerm> fsPackageSolarTerms = baseMapper.selectBatchIds(Arrays.asList(solarTermIds));
+        if (Objects.nonNull(fsPackageSolarTerms) && !fsPackageSolarTerms.isEmpty()) {
+            fsPackageSolarTerms.forEach(fsPackageSolarTerm -> {
+                fsPackageSolarTerm.setIsDel(1);
+                baseMapper.updateById(fsPackageSolarTerm);
+            });
+            return 1;
+        }
+        return 0;
+    }
+
+    /**
+     * 获取节气选项
+     */
+    @Override
+    public List<OptionVO> getOptions() {
+        return baseMapper.getOptions();
+    }
+}

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

@@ -249,7 +249,7 @@ public class FsUserIntegralLogsServiceImpl implements IFsUserIntegralLogsService
 //                    logsType = FsUserIntegralLogTypeEnum.TYPE_1;
 //                    break;
                 case 2: //消费获得积分
-                    integralNum = param.getPoints() * config.getIntegralRatio();
+                    integralNum = param.getPoints();
                     logsType = FsUserIntegralLogTypeEnum.TYPE_2;
                     break;
                 case 3: //分享获得积分

+ 43 - 5
fs-service/src/main/java/com/fs/his/service/impl/FsUserServiceImpl.java

@@ -5,13 +5,17 @@ import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.math.MathContext;
 import java.math.RoundingMode;
+import java.time.LocalDateTime;
 import java.util.*;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
 import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fs.common.constant.HttpStatus;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.ResponseResult;
@@ -37,6 +41,7 @@ import com.fs.course.vo.newfs.FsCourseAnalysisCountVO;
 import com.fs.course.vo.newfs.FsCourseAnalysisVO;
 import com.fs.course.vo.newfs.FsUserCourseVideoPageListVO;
 import com.fs.his.config.IntegralConfig;
+import com.fs.his.domain.*;
 import com.fs.his.domain.FsUserAddress;
 import com.fs.his.domain.FsUserBill;
 import com.fs.his.domain.FsUserIntegralLogs;
@@ -80,7 +85,6 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
-import com.fs.his.domain.FsUser;
 import com.fs.his.service.IFsUserService;
 import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
@@ -125,7 +129,9 @@ public class FsUserServiceImpl implements IFsUserService
     @Autowired
     private CompanyTagUserMapper companyTagUserMapper;
     @Autowired
-    private FsUserCompanyUserMapper fsUserCompanyUserMapper;
+    private FsPackageMapper packageMapper;
+    @Autowired
+    private FsPackageSolarTermMapper packageSolarTermMapper;
 
     @Autowired
     private ICompanyUserCacheService companyUserCacheService;
@@ -305,14 +311,46 @@ public class FsUserServiceImpl implements IFsUserService
     @Override
     @Transactional
     public void addUserIntegral(BigDecimal payMoney,Long userId,Long orderId ,Integer orderType) {
+        String json =configService.selectConfigByKey("his.integral");
+        IntegralConfig config = JSONUtil.toBean(json,IntegralConfig.class);
+
+        int points = payMoney.intValue() * config.getIntegralRatio();
+
+        // 节气套餐包双倍积分
+        if (isSolarTerm(orderId, orderType)) {
+            points *= 2;
+        }
+
         FsUserAddIntegralTemplateParam integralTemplateParam = new FsUserAddIntegralTemplateParam();
         integralTemplateParam.setUserId(userId);
         integralTemplateParam.setLogType(FsUserIntegralLogTypeEnum.TYPE_2.getValue());
         integralTemplateParam.setBusinessId(orderId.toString());
-        integralTemplateParam.setPoints(payMoney.intValue());
+        integralTemplateParam.setPoints(points);
         userIntegralLogsService.addIntegralTemplate(integralTemplateParam);
     }
 
+    /**
+     * 判断是否节气套餐包
+     */
+    private boolean isSolarTerm(Long orderId ,Integer orderType) {
+        if (orderType == 2) {
+            FsStoreOrder fsStoreOrder = fsStoreOrderMapper.selectFsStoreOrderByOrderId(orderId);
+            if (Objects.nonNull(fsStoreOrder.getPackageId())) {
+                FsPackage fsPackage = packageMapper.selectFsPackageByPackageId(fsStoreOrder.getPackageId());
+                if (Objects.nonNull(fsPackage) && Objects.nonNull(fsPackage.getSolarTerm())) {
+                    Wrapper<FsPackageSolarTerm> queryWrapper = Wrappers.<FsPackageSolarTerm>lambdaQuery()
+                            .eq(FsPackageSolarTerm::getId, fsPackage.getSolarTerm())
+                            .eq(FsPackageSolarTerm::getIsDel, 0);
+                    FsPackageSolarTerm fsPackageSolarTerm = packageSolarTermMapper.selectOne(queryWrapper);
+                    return Objects.nonNull(fsPackageSolarTerm)
+                            && LocalDateTime.now().isAfter(fsPackageSolarTerm.getStartTime())
+                            && LocalDateTime.now().isBefore(fsPackageSolarTerm.getEndTime());
+                }
+            }
+        }
+        return false;
+    }
+
     @Override
     @Transactional
     public void followAddIntegral(Long userId,Long orderId) {
@@ -588,11 +626,11 @@ public class FsUserServiceImpl implements IFsUserService
     public TableDataInfo selectFsUserPageListNew(FsUserPageListParam param) {
         // 找出下级销售
         String companyUserId = param.getCompanyUserId();
-        if(companyUserId != null) {
+        if(StringUtils.isNotBlank(companyUserId)) {
             Long companyUser = Long.parseLong(companyUserId);
             Set<Long> userIds = companyUserCacheService.selectUserAllCompanyUserId(companyUser);
             if (userIds != null || userIds.size() <= 1) {
-                if (param.getIsAdmin()) {
+                if (param.getIsAdmin() != null && param.getIsAdmin()) {
                     List<CompanyUser> companyUsers = companyUserMapper.selectCompanyUserByCompanyId(param.getCompanyId());
                     userIds = companyUsers.stream().map(CompanyUser::getUserId).collect(Collectors.toSet());
                 }

+ 2 - 0
fs-service/src/main/java/com/fs/his/vo/FsPackageListVO.java

@@ -65,4 +65,6 @@ public class FsPackageListVO extends BaseEntity {
     private String secondName;
 
     private BigDecimal totalPrice;
+
+    private Long solarTerm;
 }

+ 42 - 0
fs-service/src/main/java/com/fs/his/vo/FsPackageSolarTermVO.java

@@ -0,0 +1,42 @@
+package com.fs.his.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+public class FsPackageSolarTermVO {
+
+    @ApiModelProperty("主键ID")
+    private Long id;
+
+    @ApiModelProperty("节气名称")
+    private String name;
+
+    @ApiModelProperty("简介")
+    private String desc;
+
+    @ApiModelProperty("开始时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime startTime;
+
+    @ApiModelProperty("结束时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime endTime;
+
+    @ApiModelProperty("序号")
+    private Integer sort;
+
+    @ApiModelProperty("状态 1启用 0停用")
+    private Integer status;
+
+    @ApiModelProperty("创建时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime createTime;
+
+    @ApiModelProperty("修改时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime updateTime;
+}

+ 2 - 0
fs-service/src/main/java/com/fs/his/vo/FsPackageVO.java

@@ -121,4 +121,6 @@ public class FsPackageVO {
     private String doctorRemark;
     @Excel(name = "描述")
     private String description;
+
+    private Long solarTerm;
 }

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

@@ -18,6 +18,10 @@ public class FsUserVO extends FsUser implements Serializable
     @Excel(name = "所属销售", sort = 10)
     private String companyUserNickName;
 
+    @ApiModelProperty(value = "所属公司")
+    @Excel(name = "所属公司", sort = 9)
+    private String companyName;
+
     /** 创建时间 */
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     @Excel(name = "会员注册时间", dateFormat = "yyyy-MM-dd HH:mm:ss" , sort = 6)

+ 9 - 0
fs-service/src/main/java/com/fs/qw/param/GenerateShortLinkParam.java

@@ -0,0 +1,9 @@
+package com.fs.qw.param;
+
+import lombok.Data;
+
+@Data
+public class GenerateShortLinkParam {
+    private String linkStr;
+    private String appId;
+}

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

@@ -55,8 +55,8 @@ watch:
   password3: v9xsKuqn_$d2y
 
 fs :
-  commonApi: http://127.0.0.1:7771
-  h5CommonApi: http://127.0.0.1:7771
+  commonApi: http://192.168.0.18:7771
+  h5CommonApi: http://192.168.0.18:7771
 nuonuo:
   key: 10924508
   secret: A2EB20764D304D16

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

@@ -80,6 +80,7 @@ headerImg:
   imgUrl: https://sft-1361917636.cos.ap-chongqing.myqcloud.com/sft/20250606/b08b1a6212f44f2998423c8c5d7712ee.png
 ipad:
   ipadUrl: http://ipad.cdwjyyh.com
+  aiApi:
 wx_miniapp_temp:
   pay_order_temp_id: V
   inquiry_temp_id: 9

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

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

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

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

+ 46 - 0
fs-service/src/main/resources/db/20250801-节气限定.sql

@@ -0,0 +1,46 @@
+-- 节气表
+drop table if exists `fs_package_solar_term`;
+create table `fs_package_solar_term` (
+    `id`            bigint not null auto_increment       comment '主键ID',
+    `name`          varchar(255) not null                comment '节气名称',
+    `desc`          varchar(1000)                        comment '简介',
+    `start_time`    datetime not null                    comment '开始时间',
+    `end_time`      datetime not null                    comment '结束时间',
+    `sort`          tinyint default null                 comment '排序号',
+    `is_del`        tinyint(1) default 0                 comment '是否删除 0正常 1删除',
+    `status`        tinyint(1) default 1                 comment '状态 1启用 0停用',
+    `create_time`   datetime                             comment '创建时间',
+    `update_time`   datetime                             comment '修改时间',
+    primary key (`id`) using btree
+) engine = Innodb comment '节气表';
+
+alter table fs_package
+    add column solar_term bigint comment '节气';
+
+-- 字典
+INSERT INTO `sys_dict_type`
+    (`dict_name`, `dict_type`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
+VALUES
+    ('节气状态', 'solar_Term_status', '0', 'admin', '2025-08-01 17:34:31', '', NULL, NULL);
+
+INSERT INTO `sys_dict_data`
+    (`dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
+VALUES
+    (1, '启用', '1', 'solar_Term_status', NULL, 'default', 'N', '0', 'admin', '2025-08-01 17:35:19', '', NULL, NULL),
+    (2, '停用', '0', 'solar_Term_status', NULL, 'default', 'N', '0', 'admin', '2025-08-01 17:35:33', '', NULL, NULL);
+
+-- 菜单
+INSERT INTO `sys_menu`
+    (`menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
+VALUES
+    ('节气管理', 1285, 5, 'solarTerm', 'his/packageSolarTerm/index', NULL, 1, 0, 'C', '0', '0', 'his:packageSolarTerm:list', 'theme', 'admin', '2025-08-01 17:04:29', 'admin', '2025-08-01 17:04:55', '');
+
+SET @parent_id = LAST_INSERT_ID();
+
+INSERT INTO `sys_menu`
+    (`menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
+VALUES
+    ('节气修改', @parent_id, 3, '', NULL, NULL, 1, 0, 'F', '0', '0', 'his:packageSolarTerm:edit', '#', 'admin', '2025-08-04 10:03:27', '', NULL, ''),
+    ('节气添加', @parent_id, 2, '', NULL, NULL, 1, 0, 'F', '0', '0', 'his:packageSolarTerm:add', '#', 'admin', '2025-08-04 10:03:10', '', NULL, ''),
+    ('节气查询', @parent_id, 1, '', NULL, NULL, 1, 0, 'F', '0', '0', 'his:packageSolarTerm:query', '#', 'admin', '2025-08-04 10:02:51', '', NULL, ''),
+    ('节气删除', @parent_id, 4, '', NULL, NULL, 1, 0, 'F', '0', '0', 'his:packageSolarTerm:remove', '#', 'admin', '2025-08-04 10:03:46', '', NULL, '');

+ 7 - 2
fs-service/src/main/resources/mapper/course/FsCourseQuestionBankMapper.xml

@@ -26,6 +26,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <where>
             <if test="title != null  and title != ''"> and title like concat('%', #{title}, '%') </if>
             <if test="sort != null "> and sort = #{sort}</if>
+            <if test="userId != null "> and user_id = #{userId}</if>
             <if test="type != null "> and type = #{type}</if>
             <if test="questionType != null "> and question_type = #{questionType}</if>
             <if test="questionSubType != null "> and question_sub_type = #{questionSubType}</if>
@@ -54,6 +55,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="createBy != null">create_by,</if>
             <if test="questionType != null">question_type,</if>
             <if test="questionSubType != null">question_sub_type,</if>
+            <if test="userId != null">user_id,</if>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="title != null">#{title},</if>
@@ -66,6 +68,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="createBy != null">#{createBy},</if>
             <if test="questionType != null">#{questionType},</if>
             <if test="questionSubType != null">#{questionSubType},</if>
+            <if test="userId != null">#{userId},</if>
          </trim>
     </insert>
 
@@ -80,7 +83,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         answer,
         create_by,
         question_type,
-        question_sub_type
+        question_sub_type,
+        user_id
         )
         VALUES
         <foreach collection="list" item="item" separator=",">
@@ -94,7 +98,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{item.answer, jdbcType=CLOB},
             #{item.createBy, jdbcType=VARCHAR},
             #{item.questionType, jdbcType=VARCHAR},
-            #{item.questionSubType, jdbcType=VARCHAR}
+            #{item.questionSubType, jdbcType=VARCHAR},
+            #{item.userId, jdbcType=BIGINT}
             )
         </foreach>
     </insert>

+ 34 - 0
fs-service/src/main/resources/mapper/course/FsCourseTrafficLogMapper.xml

@@ -238,4 +238,38 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             ,#{item.companyUserId},#{item.companyId},#{item.courseId},#{item.uuId},#{item.project},#{item.periodId})
         </foreach>
     </insert>
+
+    <select id="selectTrafficNew" resultType="com.fs.course.vo.FsCourseTrafficLogListVO">
+        select company_id,project,course_id,SUM(internet_traffic) AS total_internet_traffic
+        ,DATE_FORMAT(create_time, '%Y-%m-%d') AS `month`  from fs_course_traffic_log
+        <where>
+            <if test="startDate != null and endDate != null">
+                and DATE_FORMAT(create_time, '%Y-%m-%d') between #{startDate} AND #{endDate}
+            </if>
+            <if test='companyId !=null'>
+                and company_id = #{companyId}
+            </if>
+            <if test="courseId != null">
+                and course_id = ${courseId}
+            </if>
+            <if test="project != null">
+                and project = ${project}
+            </if>
+        </where>
+
+        <if test="tabType==null or tabType==''">
+            group by company_id,`month`,course_id,project
+        </if>
+        <if test="tabType!=null and tabType=='project'">
+            group by project,`month`
+        </if>
+        <if test="tabType!=null and tabType=='course'">
+            group by course_id,`month`
+        </if>
+        <if test="tabType!=null and tabType=='company'">
+            group by company_id,`month`
+        </if>
+
+    </select>
+
 </mapper>

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

@@ -85,6 +85,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="talentId != null "> and talent_id = #{talentId}</if>
             <if test="isNext != null "> and is_next = #{isNext}</if>
             <if test="isPrivate != null "> and is_private = #{isPrivate}</if>
+            <if test="userId != null "> and user_id = #{userId}</if>
         </where>
     </select>
 
@@ -193,6 +194,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="isPrivate != null">is_private,</if>
             <if test="secondImg != null">second_img,</if>
             <if test="companyIds != null">company_ids,</if>
+            <if test="userId != null">user_id,</if>
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="cateId != null">#{cateId},</if>
@@ -232,6 +234,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="isPrivate != null">#{isPrivate},</if>
             <if test="secondImg != null">#{secondImg},</if>
             <if test="companyIds != null">#{companyIds},</if>
+            <if test="userId != null">#{userId},</if>
          </trim>
     </insert>
 
@@ -309,4 +312,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 <!--        ORDER BY-->
 <!--        c.course_id-->
 <!--    </select>-->
+
+    <select id="selectFsUserCourseAllList" resultType="com.fs.his.vo.OptionsVO">
+        select course_id dict_value, course_name dict_label,img_url dict_imgUrl  from fs_user_course
+        where is_del = 0 and is_private = 1
+        <if test="userId != null">
+            and user_id = #{userId}
+        </if>
+    </select>
 </mapper>

+ 10 - 1
fs-service/src/main/resources/mapper/course/FsUserCoursePeriodMapper.xml

@@ -20,6 +20,7 @@
         <result property="maxViewNum"    column="max_view_num"    />
         <result property="courseLogo"    column="course_logo"    />
         <result property="openCommentStatus"    column="open_comment_status"    />
+        <result property="periodLine"    column="period_line"    />
     </resultMap>
 
     <sql id="selectFsUserCoursePeriodVo">
@@ -39,6 +40,7 @@
             <if test="periodType != null "> and period_type = #{periodType}</if>
             <if test="periodStartingTime != null "> and period_starting_time = #{periodStartingTime}</if>
             <if test="periodEndTime != null "> and period_end_time = #{periodEndTime}</if>
+            <if test="periodLine != null "> and period_line = #{periodLine}</if>
         </where>
     </select>
 
@@ -58,6 +60,7 @@
         period_type,
         period_end_time,
         period_starting_time,
+        period_line,
         fctc.training_camp_name AS trainingCampName,
         GROUP_CONCAT( company.company_name ) AS companyName
         FROM
@@ -77,6 +80,7 @@
             </if>
             <if test="periodStartingTime != null "> and period_starting_time &gt;= #{periodStartingTime}</if>
             <if test="periodEndTime != null "> and period_end_time &lt;= #{periodEndTime}</if>
+            <if test="periodLine != null "> and period_line = #{periodLine}</if>
         </where>
         group by fs_user_course_period.period_id
         order by create_time desc
@@ -109,6 +113,7 @@
             <if test="maxViewNum != null">max_view_num,</if>
             <if test="courseLogo != null">course_logo,</if>
             <if test="openCommentStatus != null">open_comment_status,</if>
+            <if test="periodLine != null">period_line,</if>
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="periodId != null">#{periodId},</if>
@@ -130,6 +135,7 @@
             <if test="maxViewNum != null">#{maxViewNum},</if>
             <if test="courseLogo != null">#{courseLogo},</if>
             <if test="openCommentStatus != null">#{openCommentStatus},</if>
+            <if test="periodLine != null">#{periodLine},</if>
         </trim>
     </insert>
 
@@ -154,6 +160,7 @@
             <if test="maxViewNum != null">max_view_num = #{maxViewNum},</if>
             <if test="courseLogo != null and courseLogo !=''">course_logo = #{courseLogo},</if>
             <if test="openCommentStatus != null">open_comment_status = #{openCommentStatus},</if>
+            <if test="periodLine != null">period_line = #{periodLine},</if>
         </trim>
         where period_id = #{periodId}
     </update>
@@ -218,6 +225,7 @@
                 AND fvrp.period_id = #{periodId}
                 AND fvrp.company_id = #{companyId}
                 AND fvrp.data_type = 2
+                and fvrp.del_flag = 0
         WHERE
             a.video_id IN (
                 SELECT
@@ -230,6 +238,7 @@
                     a.period_id = #{periodId}
             )
           and a.period_id = #{periodId}
+          and a.del_flag = 0
     </select>
 
     <select id="selectFsUserCoursePeriodsByIds" resultType="FsUserCoursePeriod">
@@ -249,7 +258,7 @@
             #{id}
         </foreach>
         <![CDATA[
-       and (ucp.period_starting_time <= #{params.date}
+        and (ucp.period_starting_time <= #{params.date}
         and ucp.period_end_time > #{params.date})
         ]]>
     </select>

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

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

+ 9 - 0
fs-service/src/main/resources/mapper/course/FsUserCourseVideoMapper.xml

@@ -59,6 +59,7 @@
             <if test="questionBankId != null "> and question_bank_id = #{questionBankId}</if>
             <if test="userId != null "> and user_id = #{userId}</if>
             <if test="projectId != null "> and project_id = #{projectId}</if>
+            <if test="userId != null "> and user_id = #{userId}</if>
         </where>
     </select>
 
@@ -362,6 +363,14 @@
         and fcpd.del_flag = 0 and video.is_del = 0 and fcp.del_flag = '0' and c.del_flag = '0'
     </select>
 
+    <select id="selectFsUserCourseVideoByVideoIdAndUserId" resultType="com.fs.course.domain.FsUserCourseVideo">
+        select *  from fs_user_course_video
+        where video_id=#{videoId} and is_del = 0
+        <if test="userId != null">
+            user_id = #{userId}
+        </if>
+    </select>
+
     <update id="updateRedPacketMoney">
         update fs_user_course_video set red_packet_money = #{redPacketMoney} where video_id = #{videoId}
     </update>

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

@@ -18,6 +18,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <if test="params.typeId != null">
             and rr.type_id = #{params.typeId}
         </if>
+        <if test="params.userId != null">
+            and rr.user_id = #{params.userId}
+        </if>
         <if test="params.typeSubId != null">
             and rr.type_sub_id = #{params.typeSubId}
         </if>

+ 5 - 1
fs-service/src/main/resources/mapper/his/FsPackageMapper.xml

@@ -47,10 +47,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="usagePerUseCount"    column="usage_per_use_count"    />
         <result property="icdCode"    column="icd_code"    />
         <result property="description"    column="description"    />
+        <result property="solarTerm"    column="solar_term"    />
     </resultMap>
 
     <sql id="selectFsPackageVo">
-        select package_id,description,usage_per_use_count,icd_code,images,doctor_remark,second_name,follow_temp_id,product_cost_price,inquiry_cost_price,total_cost_price,follow_num,`explain`,indication,store_id,private_type,recipe_type,counts,usage_frequency_unit, package_name,img_url,is_show,total_price,cycle,duration,`desc`,product_type,price,tags,sales,disease_type,num,package_sub_type,describe_json,pay_type,package_type, sort, product_json, status, create_time, update_time, is_del from fs_package
+        select package_id,description,usage_per_use_count,icd_code,images,doctor_remark,second_name,follow_temp_id,product_cost_price,inquiry_cost_price,total_cost_price,follow_num,`explain`,indication,store_id,private_type,recipe_type,counts,usage_frequency_unit, package_name,img_url,is_show,total_price,cycle,duration,`desc`,product_type,price,tags,sales,disease_type,num,package_sub_type,describe_json,pay_type,package_type, sort, product_json, status, create_time, update_time, is_del,solar_term from fs_package
     </sql>
 
     <select id="selectFsPackageList" parameterType="FsPackage" resultMap="FsPackageResult">
@@ -120,6 +121,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="usagePerUseCount != null">usage_per_use_count,</if>
             <if test="icdCode != null">icd_code,</if>
             <if test="description != null">description,</if>
+            <if test="solarTerm != null">solar_term,</if>
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="packageName != null">#{packageName},</if>
@@ -163,6 +165,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="usagePerUseCount != null">#{usagePerUseCount},</if>
             <if test="icdCode != null">#{icdCode},</if>
             <if test="description != null">#{description},</if>
+            <if test="solarTerm != null">#{solarTerm},</if>
         </trim>
     </insert>
 
@@ -210,6 +213,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="usagePerUseCount != null">usage_per_use_count = #{usagePerUseCount},</if>
             <if test="icdCode != null">icd_code = #{icdCode},</if>
             <if test="description != null">description = #{description},</if>
+            <if test="solarTerm != null">solar_term = #{solarTerm},</if>
         </trim>
         where package_id = #{packageId}
     </update>

+ 24 - 0
fs-service/src/main/resources/mapper/his/FsPackageSolarTermMapper.xml

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.his.mapper.FsPackageSolarTermMapper">
+
+    <select id="selectFsPackageSolarTermListVO" resultType="com.fs.his.vo.FsPackageSolarTermVO">
+        select pst.*
+        from fs_package_solar_term pst
+        where pst.is_del = 0
+        <if test="name != null and name != ''">
+            and pst.name like concat('%', #{name}, '%')
+        </if>
+        order by pst.sort,pst.id
+    </select>
+
+    <select id="getOptions" resultType="com.fs.company.vo.OptionVO">
+        select
+            pst.name label,
+            pst.id   value
+        from fs_package_solar_term pst
+        where pst.is_del = 0 and pst.status = 1
+    </select>
+</mapper>

+ 2 - 1
fs-user-app/src/main/java/com/fs/app/controller/course/CourseQwController.java

@@ -22,6 +22,7 @@ import com.fs.sop.service.IQwSopService;
 import com.fs.system.service.ISysConfigService;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
+import com.hc.openapi.tool.fastjson.JSON;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
@@ -173,7 +174,7 @@ public class CourseQwController extends AppBaseController {
     @Login
     public R courseAnswer(@RequestBody FsCourseQuestionAnswerUParam param)
     {
-        logger.info("zyp \n【答题】:{}",param.getQuestions());
+        logger.info("zyp \n【答题】:{}", JSON.toJSONString(param));
         if (param.getDuration()==null){
             logger.info("zyp \n【未识别到时长】:{}",param.getUserId());
         }