Bladeren bron

Merge branch 'master' of http://1.14.104.71:10880/root/ylrz_his_scrm_java

caoliqin 1 week geleden
bovenliggende
commit
ab1f0a217b
78 gewijzigde bestanden met toevoegingen van 3112 en 193 verwijderingen
  1. 103 0
      fs-admin/src/main/java/com/fs/course/controller/FsCourseProductController.java
  2. 139 0
      fs-admin/src/main/java/com/fs/course/controller/FsCourseProductOrderController.java
  3. 64 0
      fs-admin/src/main/java/com/fs/his/controller/FsPackageSolarTermController.java
  4. 16 0
      fs-company/src/main/java/com/fs/company/controller/qw/QwSopLogsController.java
  5. 8 0
      fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java
  6. 2 1
      fs-service/src/main/java/com/fs/core/utils/OrderCodeUtils.java
  7. 56 0
      fs-service/src/main/java/com/fs/course/domain/FsCourseProduct.java
  8. 99 0
      fs-service/src/main/java/com/fs/course/domain/FsCourseProductOrder.java
  9. 9 0
      fs-service/src/main/java/com/fs/course/domain/FsUserCourseVideo.java
  10. 61 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseProductMapper.java
  11. 81 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseProductOrderMapper.java
  12. 32 0
      fs-service/src/main/java/com/fs/course/param/FsCourseProductOrderCreateParam.java
  13. 52 0
      fs-service/src/main/java/com/fs/course/param/FsCourseProductOrderListParam.java
  14. 16 0
      fs-service/src/main/java/com/fs/course/param/FsCourseProductOrderListUParam.java
  15. 87 0
      fs-service/src/main/java/com/fs/course/service/IFsCourseProductOrderService.java
  16. 61 0
      fs-service/src/main/java/com/fs/course/service/IFsCourseProductService.java
  17. 653 0
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseProductOrderServiceImpl.java
  18. 93 0
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseProductServiceImpl.java
  19. 34 27
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseQuestionBankServiceImpl.java
  20. 139 75
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  21. 76 0
      fs-service/src/main/java/com/fs/course/vo/FsCourseProductOrderListUVO.java
  22. 100 0
      fs-service/src/main/java/com/fs/course/vo/FsCourseProductOrderVO.java
  23. 7 0
      fs-service/src/main/java/com/fs/course/vo/FsUserCourseVideoH5DVO.java
  24. 13 0
      fs-service/src/main/java/com/fs/course/vo/FsUserCourseVideoQVO.java
  25. 11 1
      fs-service/src/main/java/com/fs/erp/service/impl/DfOrderServiceImpl.java
  26. 2 1
      fs-service/src/main/java/com/fs/fastGpt/mapper/FastGptChatMsgMapper.java
  27. 2 0
      fs-service/src/main/java/com/fs/his/domain/FsPackage.java
  28. 58 0
      fs-service/src/main/java/com/fs/his/domain/FsPackageSolarTerm.java
  29. 29 0
      fs-service/src/main/java/com/fs/his/enums/FsCourseProductOrderStatusEnum.java
  30. 4 0
      fs-service/src/main/java/com/fs/his/mapper/FsPackageMapper.java
  31. 24 0
      fs-service/src/main/java/com/fs/his/mapper/FsPackageSolarTermMapper.java
  32. 1 11
      fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java
  33. 10 0
      fs-service/src/main/java/com/fs/his/param/ApplyCourseProductOrderRefundParam.java
  34. 8 0
      fs-service/src/main/java/com/fs/his/param/FsCourseProductOrderCancelParam.java
  35. 11 0
      fs-service/src/main/java/com/fs/his/param/FsCourseProductOrderComputeParam.java
  36. 14 0
      fs-service/src/main/java/com/fs/his/param/FsCourseProductOrderDoPayParam.java
  37. 11 0
      fs-service/src/main/java/com/fs/his/param/FsCourseProductOrderRefundParam.java
  38. 1 0
      fs-service/src/main/java/com/fs/his/param/FsPackageParam.java
  39. 15 0
      fs-service/src/main/java/com/fs/his/param/FsPackageSolarTermParam.java
  40. 52 0
      fs-service/src/main/java/com/fs/his/service/IFsPackageSolarTermService.java
  41. 1 1
      fs-service/src/main/java/com/fs/his/service/IFsUserService.java
  42. 8 0
      fs-service/src/main/java/com/fs/his/service/impl/FsPackageServiceImpl.java
  43. 98 0
      fs-service/src/main/java/com/fs/his/service/impl/FsPackageSolarTermServiceImpl.java
  44. 43 28
      fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java
  45. 1 1
      fs-service/src/main/java/com/fs/his/service/impl/FsUserIntegralLogsServiceImpl.java
  46. 43 7
      fs-service/src/main/java/com/fs/his/service/impl/FsUserServiceImpl.java
  47. 2 0
      fs-service/src/main/java/com/fs/his/vo/FsPackageListVO.java
  48. 42 0
      fs-service/src/main/java/com/fs/his/vo/FsPackageSolarTermVO.java
  49. 2 0
      fs-service/src/main/java/com/fs/his/vo/FsPackageVO.java
  50. 14 0
      fs-service/src/main/java/com/fs/huifuPay/service/impl/HuiFuServiceImpl.java
  51. 9 0
      fs-service/src/main/java/com/fs/qw/param/GenerateShortLinkParam.java
  52. 85 25
      fs-service/src/main/java/com/fs/qw/service/impl/QwMaterialServiceImpl.java
  53. 1 1
      fs-service/src/main/java/com/fs/statis/service/impl/StatisticsCompanyServiceImpl.java
  54. 1 1
      fs-service/src/main/java/com/fs/statis/service/impl/StatisticsServiceImpl.java
  55. 2 2
      fs-service/src/main/resources/application-config-druid-jnmy.yml
  56. 1 0
      fs-service/src/main/resources/application-config-druid-sft.yml
  57. 3 1
      fs-service/src/main/resources/application-druid-bjczwh.yml
  58. 3 1
      fs-service/src/main/resources/application-druid-bnkc.yml
  59. 3 0
      fs-service/src/main/resources/application-druid-drk.yml
  60. 3 0
      fs-service/src/main/resources/application-druid-hcl.yml
  61. 3 0
      fs-service/src/main/resources/application-druid-sft.yml
  62. 3 0
      fs-service/src/main/resources/application-druid-whhm.yml
  63. 3 0
      fs-service/src/main/resources/application-druid-xfk-test.yml
  64. 3 0
      fs-service/src/main/resources/application-druid-xfk.yml
  65. 46 0
      fs-service/src/main/resources/db/20250801-节气限定.sql
  66. 99 0
      fs-service/src/main/resources/mapper/course/FsCourseProductMapper.xml
  67. 145 0
      fs-service/src/main/resources/mapper/course/FsCourseProductOrderMapper.xml
  68. 12 3
      fs-service/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml
  69. 1 0
      fs-service/src/main/resources/mapper/course/FsUserCourseComplaintRecordMapper.xml
  70. 13 1
      fs-service/src/main/resources/mapper/course/FsUserCourseVideoMapper.xml
  71. 5 1
      fs-service/src/main/resources/mapper/his/FsPackageMapper.xml
  72. 24 0
      fs-service/src/main/resources/mapper/his/FsPackageSolarTermMapper.xml
  73. 5 3
      fs-service/src/main/resources/mapper/his/FsUserMapper.xml
  74. 30 0
      fs-user-app/src/main/java/com/fs/app/controller/CourseProductController.java
  75. 87 0
      fs-user-app/src/main/java/com/fs/app/controller/CourseProductOrderController.java
  76. 6 0
      fs-user-app/src/main/java/com/fs/app/controller/HuifuPayController.java
  77. 6 0
      fs-user-app/src/main/java/com/fs/app/controller/WxPayController.java
  78. 2 1
      fs-user-app/src/main/java/com/fs/app/controller/course/CourseQwController.java

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

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

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

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

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

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

+ 8 - 0
fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java

@@ -143,6 +143,14 @@ public class CommonController {
         return R.ok();
     }
 
+
+    @GetMapping("/testMaterial")
+    public void testMaterial() throws Exception {
+
+        iQwMaterialService.updateQwMaterialByQw();
+
+    }
+
     @GetMapping("/testSop")
     public R testSop() throws Exception {
 

+ 2 - 1
fs-service/src/main/java/com/fs/core/utils/OrderCodeUtils.java

@@ -44,7 +44,8 @@ public class OrderCodeUtils {
 
     }
     public static String getOrderSn(){
-        String url= FSConfig.getCommonApi()+ "/app/common/genOrderCode";
+        //String url= FSConfig.getCommonApi()+ "/app/common/genOrderCode";
+        String url= "42.194.245.189:8010/app/common/genOrderCode";
         String json = HttpRequest.get(url)
                 .execute().body();
         OrderCodeVO vo= JSONUtil.toBean(json, OrderCodeVO.class);

+ 56 - 0
fs-service/src/main/java/com/fs/course/domain/FsCourseProduct.java

@@ -0,0 +1,56 @@
+package com.fs.course.domain;
+
+import java.math.BigDecimal;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 拍单商品对象 fs_course_product
+ *
+ * @author fs
+ * @date 2025-07-28
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsCourseProduct extends BaseEntity{
+
+    /** 拍单商品id */
+    private Long id;
+
+    /** 商品图片 */
+    @Excel(name = "商品图片")
+    private String imgUrl;
+
+    /** 商品组图 */
+    @Excel(name = "商品组图")
+    private String images;
+
+    /** 产品条码 */
+    @Excel(name = "产品条码")
+    private String barCode;
+
+    /** 排序 */
+    @Excel(name = "排序")
+    private Long sort;
+
+    /** 库存 */
+    @Excel(name = "库存")
+    private Long stock;
+
+    /** 商品介绍 */
+    @Excel(name = "商品介绍")
+    private String productContent;
+
+    /** 商品价格 */
+    @Excel(name = "商品价格")
+    private BigDecimal productPrice;
+
+    /** 商品名称 */
+    @Excel(name = "商品名称")
+    private String productName;
+
+
+}

+ 99 - 0
fs-service/src/main/java/com/fs/course/domain/FsCourseProductOrder.java

@@ -0,0 +1,99 @@
+package com.fs.course.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 拍单商品订单对象 fs_course_product_order
+ *
+ * @author fs
+ * @date 2025-07-28
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsCourseProductOrder extends BaseEntity{
+
+    /** 拍单商品订单表id */
+    private Long courseOrderId;
+
+    /** 订单编号 */
+    @Excel(name = "订单编号")
+    private String orderCode;
+
+    /** 用户id */
+    @Excel(name = "用户id")
+    private Long userId;
+
+    /** 用户名称 */
+    @Excel(name = "用户名称")
+    private String userName;
+
+    /** 用户电话 */
+    @Excel(name = "用户电话")
+    private String userPhone;
+
+    /** 拍单商品id */
+    @Excel(name = "拍单商品id")
+    private Long courseProductId;
+
+    /** 商品json */
+    @Excel(name = "商品json")
+    private String productJson;
+
+    /** 课程id */
+    @Excel(name = "课程id")
+    private Long courseId;
+
+    /** 视频小节id */
+    @Excel(name = "视频小节id")
+    private Long videoId;
+
+    /** 支付状态 0 待支付 1已支付 */
+    @Excel(name = "支付状态 0 待支付 1已支付")
+    private Long isPay;
+
+    /** 支付时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "支付时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date payTime;
+
+    /** 支付方式 微信 */
+    @Excel(name = "支付方式 微信")
+    private Long payType;
+
+    /** 1 待支付 2已支付 3 已完成 -1 申请退款 -2 : 退款成功 */
+    @Excel(name = "1 待支付 2已支付 3 已完成 -1 申请退款 -2 : 退款成功")
+    private Long status;
+
+    /** 申请退款时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "申请退款时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date refundTime;
+
+    /** 申请退款理由 */
+    @Excel(name = "申请退款理由")
+    private String refundExplain;
+
+    /** 核销码 */
+    @Excel(name = "核销码")
+    private String verifyCode;
+
+    /** 公司id */
+    @Excel(name = "公司id")
+    private Long companyId;
+
+    /** 销售id */
+    @Excel(name = "销售id")
+    private Long companyUserId;
+
+    /** 企微外部联系人id */
+    @Excel(name = "企微外部联系人id")
+    private Long extId;
+
+
+}

+ 9 - 0
fs-service/src/main/java/com/fs/course/domain/FsUserCourseVideo.java

@@ -104,4 +104,13 @@ public class FsUserCourseVideo extends BaseEntity
      * 项目ID
      */
     private Long projectId;
+    private Integer isProduct;//是否关联拍商品 0:否 1:是
+
+    private Long productId;//拍商品id
+
+    private Long listingStartTime;//商品售卖时间
+
+    private Long listingEndTime;//商品结束售卖时间
+
+
 }

+ 61 - 0
fs-service/src/main/java/com/fs/course/mapper/FsCourseProductMapper.java

@@ -0,0 +1,61 @@
+package com.fs.course.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.course.domain.FsCourseProduct;
+
+/**
+ * 拍单商品Mapper接口
+ * 
+ * @author fs
+ * @date 2025-07-28
+ */
+public interface FsCourseProductMapper extends BaseMapper<FsCourseProduct>{
+    /**
+     * 查询拍单商品
+     * 
+     * @param id 拍单商品主键
+     * @return 拍单商品
+     */
+    FsCourseProduct selectFsCourseProductById(Long id);
+
+    /**
+     * 查询拍单商品列表
+     * 
+     * @param fsCourseProduct 拍单商品
+     * @return 拍单商品集合
+     */
+    List<FsCourseProduct> selectFsCourseProductList(FsCourseProduct fsCourseProduct);
+
+    /**
+     * 新增拍单商品
+     * 
+     * @param fsCourseProduct 拍单商品
+     * @return 结果
+     */
+    int insertFsCourseProduct(FsCourseProduct fsCourseProduct);
+
+    /**
+     * 修改拍单商品
+     * 
+     * @param fsCourseProduct 拍单商品
+     * @return 结果
+     */
+    int updateFsCourseProduct(FsCourseProduct fsCourseProduct);
+
+    /**
+     * 删除拍单商品
+     * 
+     * @param id 拍单商品主键
+     * @return 结果
+     */
+    int deleteFsCourseProductById(Long id);
+
+    /**
+     * 批量删除拍单商品
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsCourseProductByIds(Long[] ids);
+}

+ 81 - 0
fs-service/src/main/java/com/fs/course/mapper/FsCourseProductOrderMapper.java

@@ -0,0 +1,81 @@
+package com.fs.course.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.course.domain.FsCourseProductOrder;
+import com.fs.course.param.FsCourseProductOrderListParam;
+import com.fs.course.param.FsCourseProductOrderListUParam;
+import com.fs.course.vo.FsCourseProductOrderListUVO;
+import com.fs.course.vo.FsCourseProductOrderVO;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+/**
+ * 拍单商品订单Mapper接口
+ * 
+ * @author fs
+ * @date 2025-07-28
+ */
+public interface FsCourseProductOrderMapper extends BaseMapper<FsCourseProductOrder>{
+    /**
+     * 查询拍单商品订单
+     * 
+     * @param courseOrderId 拍单商品订单主键
+     * @return 拍单商品订单
+     */
+    FsCourseProductOrder selectFsCourseProductOrderByCourseOrderId(Long courseOrderId);
+
+    /**
+     * 查询拍单商品订单列表
+     * 
+     * @param param 拍单商品订单
+     * @return 拍单商品订单集合
+     */
+    List<FsCourseProductOrderVO> selectFsCourseProductOrderList(FsCourseProductOrderListParam param);
+
+    /**
+     * 新增拍单商品订单
+     * 
+     * @param fsCourseProductOrder 拍单商品订单
+     * @return 结果
+     */
+    int insertFsCourseProductOrder(FsCourseProductOrder fsCourseProductOrder);
+
+    /**
+     * 修改拍单商品订单
+     * 
+     * @param fsCourseProductOrder 拍单商品订单
+     * @return 结果
+     */
+    int updateFsCourseProductOrder(FsCourseProductOrder fsCourseProductOrder);
+
+    /**
+     * 删除拍单商品订单
+     * 
+     * @param courseOrderId 拍单商品订单主键
+     * @return 结果
+     */
+    int deleteFsCourseProductOrderByCourseOrderId(Long courseOrderId);
+
+    /**
+     * 批量删除拍单商品订单
+     * 
+     * @param courseOrderIds 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsCourseProductOrderByCourseOrderIds(Long[] courseOrderIds);
+
+    @Select({"<script>" +
+            "SELECT cpo.*,cp.product_name,cp.img_url FROM fs_course_product_order cpo" +
+            "LEFT JOIN fs_course_product cp ON cp.id =  cpo.course_product_id" +
+            "WHERE 1=1" +
+            "<if test='maps.status != null'> AND cpo.status = #{maps.status}</if>" +
+            "<if test='maps.userId != null'> AND cpo.user_id = #{maps.userId}</if>" +
+            "ORDER BY cpo.course_order_id" +
+            "</script>"})
+    List<FsCourseProductOrderListUVO> selectFsCourseProductOrderListUVO(@Param("maps") FsCourseProductOrderListUParam param);
+
+    @Select({"SELECT * FROM fs_course_product_order where order_code = #{orderCode}"})
+    FsCourseProductOrder selectFsCourseProductOrderByOrderCode(String orderCode);
+
+}

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

@@ -0,0 +1,32 @@
+package com.fs.course.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class FsCourseProductOrderCreateParam {
+
+    private Long userId;
+
+    @ApiModelProperty(value = "用户名")
+    private String userName;
+
+    private String userPhone;
+
+    private Long companyUserId;
+
+    private Long courseProductId;
+
+    private Long courseId;
+
+    private Long videoId;
+
+    @NotNull(message = "支付类型不能为空")
+    private Integer payType;
+
+    private Long companyId;
+
+    private Long extId;
+}

+ 52 - 0
fs-service/src/main/java/com/fs/course/param/FsCourseProductOrderListParam.java

@@ -0,0 +1,52 @@
+package com.fs.course.param;
+
+import lombok.Data;
+
+@Data
+public class FsCourseProductOrderListParam {
+
+    /**
+     * 订单号
+     */
+    private String orderCode;
+
+    /**
+     * 用户名称
+     */
+    private String userName;
+
+    /**
+     * 用户电话
+     */
+    private String userPhone;
+
+    /**
+     * 支付状态 0 待支付 1已支付
+     */
+    private Integer isPay;
+
+    /**
+     * 订单状态 1 待支付 2已支付 3 已完成 -1 申请退款 -2 : 退款成功
+     */
+    private Integer status;
+
+    /**
+     * 支付开始时间
+     */
+    private String payStartTime;
+
+    /**
+     * 支付结束时间
+     */
+    private String payEndTime;
+
+    /**
+     * 退款开始时间
+     */
+    private String refundStartTime;
+
+    /**
+     * 退款结束时间
+     */
+    private String refundEndTime;
+}

+ 16 - 0
fs-service/src/main/java/com/fs/course/param/FsCourseProductOrderListUParam.java

@@ -0,0 +1,16 @@
+package com.fs.course.param;
+
+import com.fs.his.param.BaseParam;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class FsCourseProductOrderListUParam extends BaseParam {
+
+    private Long userId;
+    /**
+     * 1 待支付 2已支付 3 已完成 -1 申请退款 -2 : 退款成功
+     */
+    private Integer status;
+}

+ 87 - 0
fs-service/src/main/java/com/fs/course/service/IFsCourseProductOrderService.java

@@ -0,0 +1,87 @@
+package com.fs.course.service;
+
+import java.util.List;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.common.core.domain.R;
+import com.fs.course.domain.FsCourseProductOrder;
+import com.fs.course.param.FsCourseProductOrderCreateParam;
+import com.fs.course.param.FsCourseProductOrderListParam;
+import com.fs.course.param.FsCourseProductOrderListUParam;
+import com.fs.course.vo.FsCourseProductOrderListUVO;
+import com.fs.course.vo.FsCourseProductOrderVO;
+import com.fs.his.param.ApplyCourseProductOrderRefundParam;
+import com.fs.his.param.FsCourseProductOrderComputeParam;
+import com.fs.his.param.FsCourseProductOrderDoPayParam;
+import com.fs.his.param.FsCourseProductOrderRefundParam;
+
+/**
+ * 拍单商品订单Service接口
+ * 
+ * @author fs
+ * @date 2025-07-28
+ */
+public interface IFsCourseProductOrderService extends IService<FsCourseProductOrder>{
+    /**
+     * 查询拍单商品订单
+     * 
+     * @param courseOrderId 拍单商品订单主键
+     * @return 拍单商品订单
+     */
+    FsCourseProductOrder selectFsCourseProductOrderByCourseOrderId(Long courseOrderId);
+
+    /**
+     * 查询拍单商品订单列表
+     * 
+     * @param param 拍单商品订单
+     * @return 拍单商品订单集合
+     */
+    List<FsCourseProductOrderVO> selectFsCourseProductOrderList(FsCourseProductOrderListParam param);
+
+    /**
+     * 新增拍单商品订单
+     * 
+     * @param fsCourseProductOrder 拍单商品订单
+     * @return 结果
+     */
+    int insertFsCourseProductOrder(FsCourseProductOrder fsCourseProductOrder);
+
+    /**
+     * 修改拍单商品订单
+     * 
+     * @param fsCourseProductOrder 拍单商品订单
+     * @return 结果
+     */
+    int updateFsCourseProductOrder(FsCourseProductOrder fsCourseProductOrder);
+
+    /**
+     * 批量删除拍单商品订单
+     * 
+     * @param courseOrderIds 需要删除的拍单商品订单主键集合
+     * @return 结果
+     */
+    int deleteFsCourseProductOrderByCourseOrderIds(Long[] courseOrderIds);
+
+    /**
+     * 删除拍单商品订单信息
+     * 
+     * @param courseOrderId 拍单商品订单主键
+     * @return 结果
+     */
+    int deleteFsCourseProductOrderByCourseOrderId(Long courseOrderId);
+
+    R createOrder(FsCourseProductOrderCreateParam param);
+
+    FsCourseProductOrderListUVO selectCourseProductByCourseOrderId(Long courseOrderId);
+
+    R computeOrder(FsCourseProductOrderComputeParam param);
+
+    List<FsCourseProductOrderListUVO> selectFsCourseProductOrderListUVO(FsCourseProductOrderListUParam param);
+
+    R payment(FsCourseProductOrderDoPayParam param);
+
+    R  payConfirm(String orderSn,String payCode, String tradeNo,String payType,Integer type);
+
+    R refund(FsCourseProductOrderRefundParam param);
+
+    R applyRefund(ApplyCourseProductOrderRefundParam param);
+}

+ 61 - 0
fs-service/src/main/java/com/fs/course/service/IFsCourseProductService.java

@@ -0,0 +1,61 @@
+package com.fs.course.service;
+
+import java.util.List;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.course.domain.FsCourseProduct;
+
+/**
+ * 拍单商品Service接口
+ * 
+ * @author fs
+ * @date 2025-07-28
+ */
+public interface IFsCourseProductService extends IService<FsCourseProduct>{
+    /**
+     * 查询拍单商品
+     * 
+     * @param id 拍单商品主键
+     * @return 拍单商品
+     */
+    FsCourseProduct selectFsCourseProductById(Long id);
+
+    /**
+     * 查询拍单商品列表
+     * 
+     * @param fsCourseProduct 拍单商品
+     * @return 拍单商品集合
+     */
+    List<FsCourseProduct> selectFsCourseProductList(FsCourseProduct fsCourseProduct);
+
+    /**
+     * 新增拍单商品
+     * 
+     * @param fsCourseProduct 拍单商品
+     * @return 结果
+     */
+    int insertFsCourseProduct(FsCourseProduct fsCourseProduct);
+
+    /**
+     * 修改拍单商品
+     * 
+     * @param fsCourseProduct 拍单商品
+     * @return 结果
+     */
+    int updateFsCourseProduct(FsCourseProduct fsCourseProduct);
+
+    /**
+     * 批量删除拍单商品
+     * 
+     * @param ids 需要删除的拍单商品主键集合
+     * @return 结果
+     */
+    int deleteFsCourseProductByIds(Long[] ids);
+
+    /**
+     * 删除拍单商品信息
+     * 
+     * @param id 拍单商品主键
+     * @return 结果
+     */
+    int deleteFsCourseProductById(Long id);
+}

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

@@ -0,0 +1,653 @@
+package com.fs.course.service.impl;
+
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSON;
+import com.fs.common.core.domain.R;
+import com.fs.common.exception.CustomException;
+import com.fs.common.utils.DateUtils;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.ip.IpUtils;
+import com.fs.core.config.WxPayProperties;
+import com.fs.core.utils.OrderCodeUtils;
+import com.fs.course.domain.FsCourseProduct;
+import com.fs.course.mapper.FsCourseProductMapper;
+import com.fs.course.param.FsCourseProductOrderCreateParam;
+import com.fs.course.param.FsCourseProductOrderListParam;
+import com.fs.course.param.FsCourseProductOrderListUParam;
+import com.fs.course.vo.FsCourseProductOrderListUVO;
+import com.fs.course.vo.FsCourseProductOrderVO;
+import com.fs.his.domain.*;
+import com.fs.his.dto.PayConfigDTO;
+import com.fs.his.enums.FsCourseProductOrderStatusEnum;
+import com.fs.his.mapper.FsStorePaymentMapper;
+import com.fs.his.param.ApplyCourseProductOrderRefundParam;
+import com.fs.his.param.FsCourseProductOrderComputeParam;
+import com.fs.his.param.FsCourseProductOrderDoPayParam;
+import com.fs.his.param.FsCourseProductOrderRefundParam;
+import com.fs.his.service.IFsStorePaymentService;
+import com.fs.his.service.IFsUserService;
+import com.fs.his.utils.PhoneUtil;
+import com.fs.huifuPay.domain.HuiFuCreateOrder;
+import com.fs.huifuPay.domain.HuiFuRefundResult;
+import com.fs.huifuPay.domain.HuifuCreateOrderResult;
+import com.fs.huifuPay.sdk.opps.core.request.V2TradePaymentScanpayRefundRequest;
+import com.fs.huifuPay.service.HuiFuService;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.mapper.SysConfigMapper;
+import com.fs.system.service.ISysConfigService;
+import com.fs.tzBankPay.TzBankService.TzBankService;
+import com.fs.tzBankPay.doman.*;
+import com.fs.ybPay.domain.CreateWxOrderResult;
+import com.fs.ybPay.domain.OrderResult;
+import com.fs.ybPay.domain.RefundResult;
+import com.fs.ybPay.dto.OrderQueryDTO;
+import com.fs.ybPay.dto.RefundDTO;
+import com.fs.ybPay.dto.WxJspayDTO;
+import com.fs.ybPay.service.IPayService;
+import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
+import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
+import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
+import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryResult;
+import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
+import com.github.binarywang.wxpay.config.WxPayConfig;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.WxPayService;
+import com.google.common.collect.Maps;
+import com.google.gson.Gson;
+import org.apache.commons.collections4.CollectionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.fs.course.mapper.FsCourseProductOrderMapper;
+import com.fs.course.domain.FsCourseProductOrder;
+import com.fs.course.service.IFsCourseProductOrderService;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.interceptor.TransactionAspectSupport;
+
+/**
+ * 拍单商品订单Service业务层处理
+ * 
+ * @author fs
+ * @date 2025-07-28
+ */
+@Service
+public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProductOrderMapper, FsCourseProductOrder> implements IFsCourseProductOrderService {
+    Logger logger= LoggerFactory.getLogger(getClass());
+    @Autowired
+    private WxPayProperties wxPayProperties;
+
+    @Autowired
+    private FsCourseProductMapper courseProductMapper;
+
+    @Autowired FsCourseProductOrderMapper courseProductOrderMapper;
+
+    @Autowired
+    private IFsUserService userService;
+
+    @Autowired
+    private ISysConfigService configService;
+
+    @Autowired
+    private IFsStorePaymentService storePaymentService;
+
+    @Autowired
+    SysConfigMapper sysConfigMapper;
+
+    @Autowired
+    private WxPayService wxPayService;
+
+    @Autowired
+    IPayService payService;
+
+    @Autowired
+    private FsStorePaymentMapper fsStorePaymentMapper;
+
+    @Autowired
+    private TzBankService tzBankService;
+
+    @Autowired
+    private HuiFuService huiFuService;
+
+    @Autowired
+    private IPayService ybPayService;
+
+    private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+
+    private static final int CODE_LENGTH = 12;
+
+
+    /**
+     * 查询拍单商品订单
+     * 
+     * @param courseOrderId 拍单商品订单主键
+     * @return 拍单商品订单
+     */
+    @Override
+    public FsCourseProductOrder selectFsCourseProductOrderByCourseOrderId(Long courseOrderId)
+    {
+        return baseMapper.selectFsCourseProductOrderByCourseOrderId(courseOrderId);
+    }
+
+    /**
+     * 查询拍单商品订单列表
+     * 
+     * @param param 拍单商品订单
+     * @return 拍单商品订单
+     */
+    @Override
+    public List<FsCourseProductOrderVO> selectFsCourseProductOrderList(FsCourseProductOrderListParam param)
+    {
+        List<FsCourseProductOrderVO> productOrderVOS = baseMapper.selectFsCourseProductOrderList(param);
+        if (CollectionUtils.isNotEmpty(productOrderVOS)) {
+            productOrderVOS.forEach(productOrderVO -> {
+                if (StringUtils.isNotEmpty(productOrderVO.getProductJson())) {
+                    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;
+    }
+
+    /**
+     * 新增拍单商品订单
+     * 
+     * @param fsCourseProductOrder 拍单商品订单
+     * @return 结果
+     */
+    @Override
+    public int insertFsCourseProductOrder(FsCourseProductOrder fsCourseProductOrder)
+    {
+        fsCourseProductOrder.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertFsCourseProductOrder(fsCourseProductOrder);
+    }
+
+    /**
+     * 修改拍单商品订单
+     * 
+     * @param fsCourseProductOrder 拍单商品订单
+     * @return 结果
+     */
+    @Override
+    public int updateFsCourseProductOrder(FsCourseProductOrder fsCourseProductOrder)
+    {
+        fsCourseProductOrder.setUpdateTime(DateUtils.getNowDate());
+        return baseMapper.updateFsCourseProductOrder(fsCourseProductOrder);
+    }
+
+    /**
+     * 批量删除拍单商品订单
+     * 
+     * @param courseOrderIds 需要删除的拍单商品订单主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsCourseProductOrderByCourseOrderIds(Long[] courseOrderIds)
+    {
+        return baseMapper.deleteFsCourseProductOrderByCourseOrderIds(courseOrderIds);
+    }
+
+    /**
+     * 删除拍单商品订单信息
+     * 
+     * @param courseOrderId 拍单商品订单主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsCourseProductOrderByCourseOrderId(Long courseOrderId)
+    {
+        return baseMapper.deleteFsCourseProductOrderByCourseOrderId(courseOrderId);
+    }
+
+    @Override
+    public R createOrder(FsCourseProductOrderCreateParam param) {
+        FsCourseProduct courseProduct = courseProductMapper.selectFsCourseProductById(param.getCourseProductId());
+        if (courseProduct == null) {
+            return R.error("商品不存在");
+        }
+
+        FsCourseProductOrder courseProductOrder = new FsCourseProductOrder();
+        BeanUtils.copyProperties(param, courseProductOrder);
+        String orderCode =  OrderCodeUtils.getOrderSn();
+        if(StringUtils.isEmpty(orderCode)){
+            return R.error("订单生成失败,请重试");
+        }
+        courseProductOrder.setOrderCode(orderCode);
+        courseProductOrder.setIsPay(0L);
+        courseProductOrder.setCreateTime(new Date());
+        courseProductOrder.setProductJson(JSON.toJSONString(courseProduct));
+        courseProductOrder.setStatus(1L);
+        courseProductOrder.setVerifyCode(VerificationCodeGenerator());
+        try {
+            if (baseMapper.insertFsCourseProductOrder(courseProductOrder) > 0) {
+                return R.ok("下单成功").put("order",courseProductOrder);
+            } else {
+                return R.error("订单创建失败");
+            }
+        } catch (Exception e) {
+            // 异常处理
+            return R.error("订单创建失败:" + e.getMessage());
+        }
+    }
+
+    @Override
+    public FsCourseProductOrderListUVO selectCourseProductByCourseOrderId(Long courseOrderId) {
+        FsCourseProductOrderListUVO productOrderListUVO = new FsCourseProductOrderListUVO();
+        FsCourseProductOrder courseProductOrder = courseProductOrderMapper.selectFsCourseProductOrderByCourseOrderId(courseOrderId);
+        if (ObjectUtil.isNotEmpty(courseProductOrder)) {
+            BeanUtils.copyProperties(courseProductOrder, productOrderListUVO);
+            productOrderListUVO.setProductJson(courseProductOrder.getProductJson());
+        }
+        return productOrderListUVO;
+    }
+
+    @Override
+    public R computeOrder(FsCourseProductOrderComputeParam param) {
+        FsCourseProductOrder courseProductOrder = courseProductOrderMapper.selectFsCourseProductOrderByCourseOrderId(param.getOrderId());
+        if (courseProductOrder == null) {
+            return R.error("订单不存在");
+        }
+        if (courseProductOrder.getStatus() != 1) {
+            return R.error("订单状态不正确");
+        }
+        FsUser user = userService.selectFsUserByUserId(courseProductOrder.getUserId());
+        if (user != null && StringUtils.isNotEmpty(user.getMaOpenId())) {
+            Map<String,Object> moneys= Maps.newHashMap();
+            FsCourseProduct courseProduct = JSONUtil.toBean(courseProductOrder.getProductJson(), FsCourseProduct.class);
+            moneys.put("payPrice",courseProduct.getProductPrice());
+            moneys.put("product",courseProduct);
+            return R.ok().put("moneys",moneys);
+        } else {
+            return R.error("用户不存在");
+        }
+
+    }
+
+    @Override
+    public List<FsCourseProductOrderListUVO> selectFsCourseProductOrderListUVO(FsCourseProductOrderListUParam param) {
+
+        List<FsCourseProductOrderListUVO> productOrderListUVOS = baseMapper.selectFsCourseProductOrderListUVO(param);
+        //订单商品价格
+        if (CollectionUtils.isNotEmpty(productOrderListUVOS)) {
+            productOrderListUVOS.forEach(item -> {
+                FsCourseProduct courseProduct = JSONUtil.toBean(item.getProductJson(), FsCourseProduct.class);
+                if (courseProduct != null) {
+                    item.setPrice(courseProduct.getProductPrice());
+                }
+            });
+        }
+        return productOrderListUVOS;
+    }
+
+    @Override
+    @Transactional
+    public R payment(FsCourseProductOrderDoPayParam param) {
+        logger.info("支付参数==============={}",param);
+        FsCourseProductOrder courseProductOrder = courseProductOrderMapper.selectFsCourseProductOrderByCourseOrderId(param.getOrderId());
+        logger.info("订单信息==============={}",courseProductOrder);
+        if (!FsCourseProductOrderStatusEnum.STATUS_1.getValue().equals(courseProductOrder.getStatus())) {
+            return R.error("非法操作");
+        }
+        FsCourseProduct courseProduct = JSONUtil.toBean(courseProductOrder.getProductJson(), FsCourseProduct.class);
+        if (courseProduct == null) {
+            return R.error("订单商品不存在");
+        }
+        FsUser user = userService.selectFsUserByUserId(param.getUserId());
+        logger.info("用户信息==============={}",user);
+        if (user != null && StringUtils.isNotEmpty(user.getCourseMaOpenId())) {
+            if (courseProduct.getProductPrice().compareTo(new BigDecimal(0))==1) {
+                String json = configService.selectConfigByKey("his.pay");
+                PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+                String payCode =  OrderCodeUtils.getOrderSn();
+                if(StringUtils.isEmpty(payCode)){
+                    return R.error("订单生成失败,请重试");
+                }
+                FsStorePayment storePayment=new FsStorePayment();
+                storePayment.setStatus(0);
+                storePayment.setPayMode(payConfigDTO.getType());
+                storePayment.setBusinessCode(courseProductOrder.getOrderCode());
+                storePayment.setPayCode(payCode);
+                storePayment.setPayMoney(courseProduct.getProductPrice());
+                storePayment.setCreateTime(new Date());
+                storePayment.setPayTypeCode("weixin");
+                storePayment.setBusinessType(6);
+                storePayment.setCompanyId(courseProductOrder.getCompanyId());
+                storePayment.setCompanyUserId(courseProductOrder.getCompanyUserId());
+                storePayment.setRemark("拍商品订单支付");
+                storePayment.setOpenId(user.getCourseMaOpenId());
+                storePayment.setUserId(user.getUserId());
+                storePayment.setBusinessId(courseProductOrder.getCourseOrderId().toString());
+                if (storePaymentService.insertFsStorePayment(storePayment) > 0) {
+                    if (payConfigDTO.getType().equals("wx")) {
+                        //创建微信订单
+                        WxPayConfig payConfig = new WxPayConfig();
+                        SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.pay");
+                        FsPayConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), FsPayConfig.class);
+                        payConfig.setAppId(fsPayConfig.getAppId());
+                        payConfig.setMchId(fsPayConfig.getWxMchId());
+                        payConfig.setMchKey(fsPayConfig.getWxMchKey());
+                        payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));
+                        payConfig.setSubMchId(org.apache.commons.lang3.StringUtils.trimToNull(null));
+                        payConfig.setKeyPath(null);
+                        payConfig.setNotifyUrl(wxPayProperties.getNotifyUrl());
+                        wxPayService.setConfig(payConfig);
+                        WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
+                        orderRequest.setOpenid(user.getCourseMaOpenId());//公众号支付提供用户openid
+                        orderRequest.setBody("拍商品订单支付");
+                        orderRequest.setOutTradeNo("product-" + storePayment.getPayCode());
+                        orderRequest.setTotalFee(WxPayUnifiedOrderRequest.yuanToFen(storePayment.getPayMoney().toString()));//测试
+                        //orderRequest.setTotalFee(WxPayUnifiedOrderRequest.yuanToFen(money));//测试
+                        orderRequest.setTradeType("JSAPI");
+                        orderRequest.setSpbillCreateIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
+                        //调用统一下单接口,获取"预支付交易会话标识"
+                        try {
+                            WxPayMpOrderResult orderResult = wxPayService.createOrder(orderRequest);
+                            return R.ok().put("data", orderResult).put("type", "wx").put("isPay", 0);
+                        } catch (WxPayException e) {
+                            e.printStackTrace();
+                            throw new CustomException("支付失败" + e.getMessage());
+                        }
+                    } else if (payConfigDTO.getType().equals("yb")) {
+                        WxJspayDTO p = new WxJspayDTO();
+                        // 使用setter方法为对象赋值
+                        p.setPayMoney(storePayment.getPayMoney().toString());
+                        p.setLowOrderId("product-" + storePayment.getPayCode());
+                        p.setBody("拍商品订单支付");
+                        p.setIsMinipg("1");
+                        p.setOpenId(user.getCourseMaOpenId());
+                        p.setAttach("");
+                        p.setStoreid("0");
+                        CreateWxOrderResult wxOrder = payService.createWxOrder(p);
+                        logger.info("易宝返回"+wxOrder);
+                        if (wxOrder.getStatus().equals("100")) {
+                            FsStorePayment mt=new FsStorePayment();
+                            mt.setPaymentId(storePayment.getPaymentId());
+                            mt.setTradeNo(wxOrder.getUpOrderId());
+                            fsStorePaymentMapper.updateFsStorePayment(mt);
+                            return R.ok().put("isPay", 0).put("data", wxOrder).put("type", "yb");
+                        } else {
+                            throw new CustomException("支付失败");
+                        }
+                    } else if (payConfigDTO.getType().equals("tz")) {
+                        PayCreateOrder o = new PayCreateOrder();
+                        o.setOrderNo("product" + storePayment.getPayCode()); // 业务系统订单号
+                        o.setTrxAmt(storePayment.getPayMoney().doubleValue()); // 交易金额
+                        o.setBusinessCstNo(courseProductOrder.getUserId().toString()); // 业务平台客户号
+                        String phone="";
+                        if (user.getPhone()!=null&&user.getPhone().length()>4){
+                            phone=user.getPhone().substring(user.getPhone().length()-4);
+                            if (user.getPhone().length()>11){
+                                o.setPayerMobileNo(PhoneUtil.decryptPhone(user.getPhone()));
+                            }else {
+                                o.setPayerMobileNo(user.getPhone());
+                            }
+                        }
+                        o.setPayerName("微信用户"+phone);
+                        o.setGoodsInfo("拍商品订单支付"); // 订单信息
+                        o.setOpenId(user.getCourseMaOpenId());
+                        o.setOrderType(3);
+                        o.setOrderId(courseProductOrder.getCourseOrderId().toString());
+                        TzBankResult<PayCreateOrderResult> result = tzBankService.createOrder(o);
+                        FsStorePayment mt=new FsStorePayment();
+                        mt.setPaymentId(storePayment.getPaymentId());
+                        mt.setTradeNo(result.getBody().getOrderFlowNo());
+                        fsStorePaymentMapper.updateFsStorePayment(mt);
+                        return R.ok().put("isPay", 0).put("data", result).put("type", "tz");
+                    }else if (payConfigDTO.getType().equals("hf")) {
+                        logger.info("创建汇付订单");
+                        HuiFuCreateOrder o = new HuiFuCreateOrder();
+                        o.setTradeType("T_MINIAPP");
+                        o.setOpenid(user.getCourseMaOpenId());
+                        o.setReqSeqId("product-"+storePayment.getPayCode());
+                        o.setTransAmt(storePayment.getPayMoney().toString());
+                        o.setGoodsDesc("拍商品订单支付");
+                        HuifuCreateOrderResult result = huiFuService.createOrder(o);
+                        logger.info("创建汇付支付:"+result);
+                        FsStorePayment mt=new FsStorePayment();
+                        mt.setPaymentId(storePayment.getPaymentId());
+                        mt.setTradeNo(result.getHf_seq_id());
+                        storePaymentService.updateFsStorePayment(mt);
+                        return R.ok().put("isPay", 0).put("data", result).put("type", "hf");
+                    }
+                }
+            } else {
+                //TODO 支付金额为0的业务
+            }
+
+        } else {
+           return R.error("用户OPENID不存在");
+        }
+        return R.error();
+    }
+
+    @Override
+    public R payConfirm(String orderSn, String payCode, String tradeNo, String payType, Integer type) {
+        logger.info("进入拍商品订单支付回调 orderSn: {}, payCode: {}, tradeNo: {}, payType: {}, type: {}",
+                orderSn, payCode, tradeNo, payType, type);
+        FsCourseProductOrder order = null;
+        if(type.equals(1)){
+            FsStorePayment storePayment = fsStorePaymentMapper.selectFsStorePaymentByPaymentCode(payCode);
+            if (storePayment!=null){
+                if(storePayment.getStatus().equals(0)){
+                    FsStorePayment paymentMap=new FsStorePayment();
+                    paymentMap.setPaymentId(storePayment.getPaymentId());
+                    paymentMap.setStatus(1);
+                    paymentMap.setPayTime(new Date());
+                    paymentMap.setTradeNo(tradeNo);
+                    if(payType.equals(PayType.WECHAT_MINI_PROGRAM_PAYMENT.getCode())){
+                        paymentMap.setPayTypeCode(PayType.WECHAT_MINI_PROGRAM_PAYMENT.name());
+                    }
+                    else if(payType.equals(PayType.ALIPAY_BARCODE_PAYMENT.getCode())){
+                        paymentMap.setPayTypeCode(PayType.ALIPAY_BARCODE_PAYMENT.name());
+                    }
+                    if (storePayment.getPayMode().equals("yb")){
+                        OrderQueryDTO orderQueryDTO = new OrderQueryDTO();
+                        orderQueryDTO.setUpOrderId(tradeNo);
+                        OrderResult orderResult = ybPayService.getOrder(orderQueryDTO);
+                        paymentMap.setBankSerialNo(orderResult.getBankOrderId());
+                        paymentMap.setBankTransactionId(orderResult.getBankTrxId());
+                    }
+                    logger.info("更新支付记录");
+                    fsStorePaymentMapper.updateFsStorePayment(paymentMap);
+                    order = courseProductOrderMapper.selectFsCourseProductOrderByCourseOrderId(Long.parseLong(storePayment.getBusinessId()));
+                }
+            }
+            else{
+                logger.info("支付单号不存在:"+payCode);
+                return R.error("支付单号不存在");
+            }
+        } else if(type.equals(2)){
+            order=courseProductOrderMapper.selectFsCourseProductOrderByOrderCode(orderSn);
+        }
+        FsCourseProduct courseProduct = JSONUtil.toBean(order.getProductJson(), FsCourseProduct.class);
+
+        if (!order.getStatus().equals(FsCourseProductOrderStatusEnum.STATUS_1.getValue()) && courseProduct == null){
+            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
+            return R.error("非法操作");
+        }
+
+        logger.info("更新拍商品订单支付状态");
+        FsCourseProductOrder map = new FsCourseProductOrder();
+        map.setCourseOrderId(order.getCourseOrderId());
+        map.setIsPay(1L);
+        map.setStatus(FsCourseProductOrderStatusEnum.STATUS_2.getValue());
+        map.setPayTime(new Date());
+        courseProductOrderMapper.updateFsCourseProductOrder(map);
+        return R.ok();
+    }
+
+    @Transactional
+    @Override
+    public R refund(FsCourseProductOrderRefundParam param) {
+        FsCourseProductOrder courseProductOrder = courseProductOrderMapper.selectFsCourseProductOrderByCourseOrderId(param.getCourseOrderId());
+        if (courseProductOrder == null) {
+            throw new CustomException("订单不存在");
+        }
+
+        if (courseProductOrder.getIsPay() != 1 || !Objects.equals(courseProductOrder.getStatus(), FsCourseProductOrderStatusEnum.STATUS_NE1.getValue())) {
+            throw new CustomException("此状态的订单不可退款");
+        }
+
+        FsCourseProduct courseProduct = JSONUtil.toBean(courseProductOrder.getProductJson(), FsCourseProduct.class);
+        if (courseProduct == null) {
+            throw new CustomException("订单商品不存在");
+        }
+
+        //修改拍商品订单状态
+        FsCourseProductOrder mapOrder = new FsCourseProductOrder();
+        mapOrder.setCourseOrderId(param.getCourseOrderId());
+        mapOrder.setStatus(FsCourseProductOrderStatusEnum.STATUS_NE2.getValue());
+        mapOrder.setRefundTime(new Date());
+        courseProductOrderMapper.updateFsCourseProductOrder(mapOrder);
+
+        if(courseProduct.getProductPrice().compareTo(new BigDecimal(0))==1){
+            List<FsStorePayment> fsStorePayments = fsStorePaymentMapper.selectFsStorePaymentByPay(6, param.getCourseOrderId());
+            if (fsStorePayments != null && fsStorePayments.size() == 1) {
+                FsStorePayment payment=fsStorePayments.get(0);
+                if(payment.getPayMode().equals("wx")){
+                    WxPayConfig payConfig = new WxPayConfig();
+                    SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.pay");
+                    FsPayConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), FsPayConfig.class);
+                    payConfig.setAppId(fsPayConfig.getAppId());
+                    payConfig.setMchId(fsPayConfig.getWxMchId());
+                    payConfig.setMchKey(fsPayConfig.getWxMchKey());
+
+                    payConfig.setKeyPath(wxPayProperties.getKeyPath());
+
+                    payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));
+                    payConfig.setSubMchId(org.apache.commons.lang3.StringUtils.trimToNull(null));
+                    wxPayService.setConfig(payConfig);
+                    WxPayRefundRequest refundRequest = new WxPayRefundRequest();
+                    refundRequest.setOutTradeNo("product-"+payment.getPayCode());
+                    refundRequest.setOutRefundNo("product-"+payment.getPayCode());
+                    refundRequest.setTotalFee(WxPayUnifiedOrderRequest.yuanToFen(payment.getPayMoney().toString()));
+                    refundRequest.setRefundFee(WxPayUnifiedOrderRequest.yuanToFen(payment.getPayMoney().toString()));
+                    try {
+                        WxPayRefundResult refundResult = wxPayService.refund(refundRequest);
+                        WxPayRefundQueryResult refundQueryResult = wxPayService.refundQuery("", refundResult.getOutTradeNo(), refundResult.getOutRefundNo(), refundResult.getRefundId());
+                        if(refundQueryResult!=null&&refundQueryResult.getResultCode().equals("SUCCESS")){
+                            FsStorePayment paymentMap=new FsStorePayment();
+                            paymentMap.setPaymentId(payment.getPaymentId());
+                            paymentMap.setStatus(-1);
+                            paymentMap.setRefundTime(DateUtils.getNowDate());
+                            paymentMap.setRefundMoney(payment.getPayMoney());
+                            fsStorePaymentMapper.updateFsStorePayment(paymentMap);
+                        }
+                        else {
+                            throw new CustomException("退款请求失败"+refundQueryResult.getReturnMsg());
+                        }
+                    } catch (WxPayException e) {
+                        throw new CustomException("退款请求失败"+e.getReturnMsg());
+                    }
+                } else if(payment.getPayMode().equals("yb")){
+                    //易宝
+                    RefundDTO refundDTO=new RefundDTO();
+                    refundDTO.setRefundMoney(payment.getPayMoney().toString());
+                    refundDTO.setLowRefundNo("product-"+payment.getPayCode());
+                    refundDTO.setUpOrderId(payment.getTradeNo());
+                    RefundResult result=payService.refund(refundDTO);
+                    if(result.getState().equals("5")){
+                        FsStorePayment paymentMap=new FsStorePayment();
+                        paymentMap.setPaymentId(payment.getPaymentId());
+                        paymentMap.setStatus(-1);
+                        paymentMap.setRefundTime(DateUtils.getNowDate());
+                        paymentMap.setRefundMoney(payment.getPayMoney());
+                        fsStorePaymentMapper.updateFsStorePayment(paymentMap);
+                    }
+                } else if(payment.getPayMode().equals("tz")){
+                    RefundParam tzBankResult = new RefundParam();
+                    // 使用set方法为对象的字段赋值
+                    //商户原支付订单号
+                    tzBankResult.setOldPayOutOrderNo("product"+payment.getPayCode());
+                    // 商户退款订单号 对接平台系统里自己生成的退款订单号
+                    tzBankResult.setRefundOrderNo("product"+payment.getPayCode());
+                    // 交易发送时间 yyyyMMddHHmmss
+                    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
+                    tzBankResult.setTrxSendTime(sdf.format(new Date()));
+
+                    // 退款金额
+                    tzBankResult.setRefundOrdTransAmt(payment.getPayMoney().doubleValue());
+                    TzBankResult<com.fs.tzBankPay.doman.RefundResult> result = tzBankService.refund(tzBankResult);
+                    if(result.getBody().getRefundOrdStatus().equals("90")){
+                        FsStorePayment paymentMap=new FsStorePayment();
+                        paymentMap.setPaymentId(payment.getPaymentId());
+                        paymentMap.setStatus(-1);
+                        paymentMap.setRefundTime(DateUtils.getNowDate());
+                        paymentMap.setRefundMoney(payment.getPayMoney());
+                        fsStorePaymentMapper.updateFsStorePayment(paymentMap);
+                    }
+                } else if (payment.getPayMode().equals("hf")){
+
+                    V2TradePaymentScanpayRefundRequest request = new V2TradePaymentScanpayRefundRequest();
+                    request.setOrdAmt(payment.getPayMoney().toString());
+                    request.setOrgReqDate(new SimpleDateFormat("yyyyMMdd").format(payment.getCreateTime()));
+                    request.setReqSeqId("refund-"+payment.getPayCode());
+                    Map<String, Object> extendInfoMap = new HashMap<>();
+                    extendInfoMap.put("org_req_seq_id", "product-"+payment.getPayCode());
+                    request.setExtendInfo(extendInfoMap);
+                    HuiFuRefundResult refund = huiFuService.refund(request);
+                    logger.info("拍商品订单退款返回结果:问诊订单id:"+courseProductOrder.getCourseOrderId()+refund);
+                    if(refund.getResp_code().equals("00000000")&&(refund.getTrans_stat().equals("S")||refund.getTrans_stat().equals("P"))){
+                        FsStorePayment paymentMap=new FsStorePayment();
+                        paymentMap.setPaymentId(payment.getPaymentId());
+                        paymentMap.setStatus(-1);
+                        paymentMap.setRefundTime(DateUtils.getNowDate());
+                        paymentMap.setRefundMoney(payment.getPayMoney());
+                        fsStorePaymentMapper.updateFsStorePayment(paymentMap);
+                    }
+                }
+
+            }
+        }
+
+        return R.ok();
+    }
+
+    @Override
+    public R applyRefund(ApplyCourseProductOrderRefundParam param) {
+        FsCourseProductOrder courseProductOrder = courseProductOrderMapper.selectFsCourseProductOrderByCourseOrderId(param.getCourseOderId());
+        if (courseProductOrder == null) {
+            return R.error("订单不存在");
+        }
+        if (!Objects.equals(courseProductOrder.getStatus(), FsCourseProductOrderStatusEnum.STATUS_2.getValue())) {
+            return R.error("订单状态异常,申请退款失败");
+        }
+        FsCourseProductOrder map = new FsCourseProductOrder();
+        map.setCourseOrderId(courseProductOrder.getCourseOrderId());
+        map.setRefundExplain(param.getRefundReason());
+        map.setRefundTime(new Date());
+        map.setStatus(FsCourseProductOrderStatusEnum.STATUS_NE1.getValue());
+        if (courseProductOrderMapper.updateFsCourseProductOrder(map) > 0) {
+            return R.ok();
+        }
+        return R.error();
+    }
+
+    //生成核销码
+    private String VerificationCodeGenerator(){
+        Random random = new Random();
+        StringBuilder codeBuilder = new StringBuilder(CODE_LENGTH);
+        for (int i = 0; i < CODE_LENGTH; i++) {
+            int index = random.nextInt(CHARACTERS.length());
+            codeBuilder.append(CHARACTERS.charAt(index));
+        }
+        return codeBuilder.toString();
+    }
+
+}

+ 93 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsCourseProductServiceImpl.java

@@ -0,0 +1,93 @@
+package com.fs.course.service.impl;
+
+import java.util.List;
+import com.fs.common.utils.DateUtils;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+import com.fs.course.mapper.FsCourseProductMapper;
+import com.fs.course.domain.FsCourseProduct;
+import com.fs.course.service.IFsCourseProductService;
+
+/**
+ * 拍单商品Service业务层处理
+ * 
+ * @author fs
+ * @date 2025-07-28
+ */
+@Service
+public class FsCourseProductServiceImpl extends ServiceImpl<FsCourseProductMapper, FsCourseProduct> implements IFsCourseProductService {
+
+    /**
+     * 查询拍单商品
+     * 
+     * @param id 拍单商品主键
+     * @return 拍单商品
+     */
+    @Override
+    public FsCourseProduct selectFsCourseProductById(Long id)
+    {
+        return baseMapper.selectFsCourseProductById(id);
+    }
+
+    /**
+     * 查询拍单商品列表
+     * 
+     * @param fsCourseProduct 拍单商品
+     * @return 拍单商品
+     */
+    @Override
+    public List<FsCourseProduct> selectFsCourseProductList(FsCourseProduct fsCourseProduct)
+    {
+        return baseMapper.selectFsCourseProductList(fsCourseProduct);
+    }
+
+    /**
+     * 新增拍单商品
+     * 
+     * @param fsCourseProduct 拍单商品
+     * @return 结果
+     */
+    @Override
+    public int insertFsCourseProduct(FsCourseProduct fsCourseProduct)
+    {
+        fsCourseProduct.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertFsCourseProduct(fsCourseProduct);
+    }
+
+    /**
+     * 修改拍单商品
+     * 
+     * @param fsCourseProduct 拍单商品
+     * @return 结果
+     */
+    @Override
+    public int updateFsCourseProduct(FsCourseProduct fsCourseProduct)
+    {
+        fsCourseProduct.setUpdateTime(DateUtils.getNowDate());
+        return baseMapper.updateFsCourseProduct(fsCourseProduct);
+    }
+
+    /**
+     * 批量删除拍单商品
+     * 
+     * @param ids 需要删除的拍单商品主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsCourseProductByIds(Long[] ids)
+    {
+        return baseMapper.deleteFsCourseProductByIds(ids);
+    }
+
+    /**
+     * 删除拍单商品信息
+     * 
+     * @param id 拍单商品主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsCourseProductById(Long id)
+    {
+        return baseMapper.deleteFsCourseProductById(id);
+    }
+}

+ 34 - 27
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()) {

+ 139 - 75
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -195,6 +195,8 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     @Autowired
     private IFsUserWxService fsUserWxService;
     @Autowired
+    private FsCourseProductMapper courseProductMapper;
+    @Autowired
     private IFsUserCompanyUserService userCompanyUserService;
     @Autowired
     private SysDictDataMapper dictDataMapper;
@@ -225,6 +227,12 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             List<FsCourseQuestionBank> fsCourseQuestionBanks = courseQuestionBankMapper.selectFsCourseQuestionBankByIdVO(courseVideo.getQuestionBankId().split(","));
             fsUserCourseVideoQVO.setQuestionBankList(fsCourseQuestionBanks);
         }
+        //返回课程关联的拍商品
+        if(courseVideo.getIsProduct() != null && courseVideo.getIsProduct() == 1 && courseVideo.getProductId() != null){
+            FsCourseProduct courseProduct = courseProductMapper.selectFsCourseProductById(courseVideo.getProductId());
+            List<FsCourseProduct> courseProducts = Arrays.asList(courseProduct);
+            fsUserCourseVideoQVO.setCourseProducts(courseProducts);
+        }
         return fsUserCourseVideoQVO;
     }
 
@@ -263,6 +271,12 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     public int updateFsUserCourseVideo(FsUserCourseVideo fsUserCourseVideo)
     {
         fsUserCourseVideo.setUpdateTime(DateUtils.getNowDate());
+        //无关联商品的课程 清除脏数据
+        if (fsUserCourseVideo.getIsProduct() != null && fsUserCourseVideo.getIsProduct() == 0 && fsUserCourseVideo.getProductId() != null) {
+            fsUserCourseVideo.setProductId(null);
+            fsUserCourseVideo.setListingStartTime(null);
+            fsUserCourseVideo.setListingEndTime(null);
+        }
         return fsUserCourseVideoMapper.updateFsUserCourseVideo(fsUserCourseVideo);
     }
 
@@ -411,6 +425,10 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             return R.error(504,"未授权");
         }
 
+        if (fsUser.getStatus()==0){
+            return R.error("会员被停用,无权限,请联系客服!");
+        }
+
         String msg = "<div style=\"color: red;margin-bottom: 15px;font-weight: bold;\">本课程为会员独享<br>请长按二维码</div>\n" +
                 "\t\t\t\t\t<div style=\"color: #999;font-size: 14px;font-weight: bold;\">添加伴学助手免费领取会员权限</div>";
 //        try {
@@ -863,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());
 
@@ -955,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;
@@ -983,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)) {
@@ -1025,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());
@@ -1043,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());
@@ -1066,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());
@@ -1077,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);
-        }
     }
 
     /**
@@ -1469,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) {
@@ -1483,6 +1487,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             }
 
             FsCourseWatchLog updateLog = new FsCourseWatchLog();
+            updateLog.setLogId(watchCourseVideo.getLogId());
             updateLog.setPeriodId(param.getPeriodId());
             updateLog.setProject(courseProject);
             updateLog.setUpdateTime(new Date());
@@ -1522,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();

+ 76 - 0
fs-service/src/main/java/com/fs/course/vo/FsCourseProductOrderListUVO.java

@@ -0,0 +1,76 @@
+package com.fs.course.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import com.fs.course.domain.FsCourseProduct;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+public class FsCourseProductOrderListUVO {
+
+    /** 拍单商品订单表id */
+    private Long courseOrderId;
+
+    /** 订单编号 */
+    private String orderCode;
+
+    /** 用户id */
+    private Long userId;
+
+    /** 用户名称 */
+    private String userName;
+
+    /** 用户电话 */
+    private String userPhone;
+
+    /** 拍单商品id */
+    private Long courseProductId;
+
+    /** 商品json */
+    private String productJson;
+
+    /** 课程id */
+    private Long courseId;
+
+    /** 视频小节id */
+    private Long videoId;
+
+    /** 支付状态 0 待支付 1已支付 */
+    private Long isPay;
+
+    /** 支付时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date payTime;
+
+    /** 支付方式 微信 */
+    private Long payType;
+
+    /** 1 待支付 2已支付 3 已完成 -1 申请退款 -2 : 退款成功 */
+    private Long status;
+
+    /** 申请退款时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date refundTime;
+
+    /** 申请退款理由 */
+    private String refundExplain;
+
+    /** 核销码 */
+    private String verifyCode;
+
+    /** 公司id */
+    private Long companyId;
+
+    /** 销售id */
+    private Long companyUserId;
+
+    /** 企微外部联系人id */
+    private Long extId;
+
+    private BigDecimal price;
+
+    private FsCourseProduct courseProduct;
+}

+ 100 - 0
fs-service/src/main/java/com/fs/course/vo/FsCourseProductOrderVO.java

@@ -0,0 +1,100 @@
+package com.fs.course.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class FsCourseProductOrderVO extends BaseEntity {
+    /** 拍单商品订单表id */
+    private Long courseOrderId;
+
+    /** 订单编号 */
+    @Excel(name = "订单编号")
+    private String orderCode;
+
+    /** 用户id */
+    private Long userId;
+
+    /** 用户名称 */
+    @Excel(name = "用户名称")
+    private String userName;
+
+    /** 用户电话 */
+    @Excel(name = "用户电话")
+    private String userPhone;
+
+    /** 拍单商品id */
+    private Long courseProductId;
+
+    /** 商品json */
+    private String productJson;
+
+    /** 课程id */
+    private Long courseId;
+
+    /** 视频小节id */
+    private Long videoId;
+
+    /** 支付状态 0 待支付 1已支付 */
+    @Excel(name = "支付状态",readConverterExp = "0=待支付,1=已支付")
+    private Long isPay;
+
+    /** 支付时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "支付时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date payTime;
+
+    /** 支付方式 微信 */
+    private Long payType;
+
+    /** 1 待支付 2已支付 3 已完成 -1 申请退款 -2 : 退款成功 */
+    @Excel(name = "订单状态",readConverterExp = "1=待支付,2=已支付,3=已完成,-1=申请退款,-2=退款成功")
+    private Long status;
+
+    /** 申请退款时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "申请退款时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date refundTime;
+
+    /** 申请退款理由 */
+    @Excel(name = "申请退款理由")
+    private String refundExplain;
+
+    /** 核销码 */
+    @Excel(name = "核销码")
+    private String verifyCode;
+
+    /** 公司id */
+    private Long companyId;
+
+    /** 销售id */
+
+    private Long companyUserId;
+
+    /** 企微外部联系人id */
+    private Long extId;
+
+    @Excel(name = "课程")
+    private String courseName;
+
+    @Excel(name = "视频")
+    private String title;
+
+    @Excel(name = "公司名称")
+    private String companyName;
+
+    @Excel(name = "销售")
+    private String companyUserName;
+
+    @Excel(name = "企微外部联系人")
+    private String extName;
+
+    @Excel(name = "商品名称")
+    private String productName;
+}

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

@@ -43,5 +43,12 @@ public class FsUserCourseVideoH5DVO extends BaseEntity
     private String lineThree; //线路三 华为云obs
     private Integer uploadType;
 
+    private Integer isProduct;//是否关联拍商品 0:否 1:是
+
+    private Long productId;//拍商品id
+
+    private Long listingStartTime;//商品售卖时间
+
+    private Long listingEndTime;//商品结束售卖时间
 
 }

+ 13 - 0
fs-service/src/main/java/com/fs/course/vo/FsUserCourseVideoQVO.java

@@ -2,6 +2,7 @@ package com.fs.course.vo;
 
 import com.fs.common.annotation.Excel;
 import com.fs.common.core.domain.BaseEntity;
+import com.fs.course.domain.FsCourseProduct;
 import com.fs.course.domain.FsCourseQuestionBank;
 import lombok.Data;
 
@@ -82,4 +83,16 @@ public class FsUserCourseVideoQVO extends BaseEntity {
 
     private String packageJson;
     private Integer isFirst;
+    private Integer isProduct;//是否关联拍商品 0:否 1:是
+
+    private Long productId;//拍商品id
+
+    private Long listingStartTime;//商品售卖时间
+
+    private Long listingEndTime;//商品结束售卖时间
+
+    /**
+     * 课程关联的拍商品
+     */
+    private List<FsCourseProduct>  courseProducts;
 }

+ 11 - 1
fs-service/src/main/java/com/fs/erp/service/impl/DfOrderServiceImpl.java

@@ -26,6 +26,8 @@ import com.fs.his.service.IFsExpressService;
 import com.fs.his.service.IFsStoreOrderLogsService;
 import com.fs.his.service.IFsStoreOrderService;
 import com.fs.his.utils.ConfigUtil;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.mapper.SysConfigMapper;
 import com.hc.openapi.tool.util.StringUtils;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.http.util.Asserts;
@@ -78,6 +80,9 @@ public class DfOrderServiceImpl implements IErpOrderService
     @Autowired
     private IFsStoreOrderService fsStoreOrderService;
 
+    @Autowired
+    private SysConfigMapper sysConfigMapper;
+
 
     @Override
     public ErpOrderResponse addOrder(ErpOrder order) {
@@ -312,7 +317,12 @@ public class DfOrderServiceImpl implements IErpOrderService
                         //已签收
                         deliveryStatus = 3;
                         stateEx = "301"; //退货签收
-                        fsStoreOrderService.getGoods(order.getOrderId());
+                        SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.store");
+                        Map<String, Object> config = (Map<String, Object>) JSON.parse(sysConfig.getConfigValue());
+                        Object isUpdateOrder = config.get("isUpdateOrder");
+                        if (isUpdateOrder == null || "1".equals(isUpdateOrder.toString())) {
+                            fsStoreOrderService.getGoods(order.getOrderId());
+                        }
                         break;
                     case 10:
                         //取消订单

+ 2 - 1
fs-service/src/main/java/com/fs/fastGpt/mapper/FastGptChatMsgMapper.java

@@ -110,7 +110,8 @@ public interface FastGptChatMsgMapper
 
     @Select("select content from fastgpt_chat_msg where msg_id < #{msgId} and user_id = #{userId} and role_id = #{roleId} and send_type = 1  ORDER BY msg_id desc limit 1")
     String selectUserContent(@Param("msgId") Long msgId,@Param("userId") String userId,@Param("roleId") Long roleId);
-    @Select("select * from fastgpt_chat_msg where  session_id =#{sessionId} and msg_type=1 ORDER BY msg_id DESC  limit 20 ")
+
+//    @Select("select * from fastgpt_chat_msg where  session_id =#{sessionId} and msg_type=1 ORDER BY msg_id DESC  limit 20 ")
     List<FastGptChatMsg> selectFastGptChatMsgByMsgSessionId(Long sessionId);
 
     void insertFastGptEventLog(FastGptEventLog fastGptEventLog);

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

+ 29 - 0
fs-service/src/main/java/com/fs/his/enums/FsCourseProductOrderStatusEnum.java

@@ -0,0 +1,29 @@
+package com.fs.his.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.util.stream.Stream;
+
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+public enum FsCourseProductOrderStatusEnum {
+
+    STATUS_NE1(-1L,"申请退款"),
+    STATUS_NE2(-2L,"退款成功"),
+    STATUS_1(1L,"待支付"),
+    STATUS_2(2L,"已支付"),
+    STATUS_3(3L,"已完成");
+
+    private Long value;
+    private String desc;
+
+    public static FsCourseProductOrderStatusEnum toType(int value) {
+        return Stream.of(FsCourseProductOrderStatusEnum.values())
+                .filter(p -> p.value == value)
+                .findAny()
+                .orElse(null);
+    }
+}

+ 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 - 11
fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java

@@ -273,17 +273,7 @@ public interface FsUserMapper
 
     Long selectFsUserPageListCount(FsUserPageListParam param);
 
-    @Select({"<script> " +
-            "select count(1) from fs_user  " +
-            "where 1=1 " +
-            "<if test = 'type != null and  type ==1  '> " +
-            "and  DATE_FORMAT(create_time, '%Y-%m-%d')  = DATE_FORMAT(NOW(), '%Y-%m-%d') " +
-            "</if>" +
-            "<if test = 'companyId != null  '> " +
-            "and  company_id=#{companyId} " +
-            "</if>" +
-            "</script>"})
-    Long selectFsUserCount(@Param("type") int type,@Param("companyId") Long companyId);
+    Long selectFsUserCount(@Param("type") int type,@Param("companyId") Long companyId,@Param("companyUserId") Long companyUserId);
 
 
     int batchUpdateUserCompanyUser(@Param("userIds") List<Long> userIds, @Param("companyUserId") Long companyUserId, @Param("companyId") Long companyId);

+ 10 - 0
fs-service/src/main/java/com/fs/his/param/ApplyCourseProductOrderRefundParam.java

@@ -0,0 +1,10 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+@Data
+public class ApplyCourseProductOrderRefundParam {
+
+    private Long courseOderId;
+    private String refundReason;
+}

+ 8 - 0
fs-service/src/main/java/com/fs/his/param/FsCourseProductOrderCancelParam.java

@@ -0,0 +1,8 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+@Data
+public class FsCourseProductOrderCancelParam {
+    private Long courseOrderId;
+}

+ 11 - 0
fs-service/src/main/java/com/fs/his/param/FsCourseProductOrderComputeParam.java

@@ -0,0 +1,11 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+@Data
+public class FsCourseProductOrderComputeParam {
+
+    private Long userId;
+
+    private Long orderId;
+}

+ 14 - 0
fs-service/src/main/java/com/fs/his/param/FsCourseProductOrderDoPayParam.java

@@ -0,0 +1,14 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class FsCourseProductOrderDoPayParam {
+
+    @NotNull(message = "订单id不能为空")
+    private Long orderId;
+
+    private Long userId;
+}

+ 11 - 0
fs-service/src/main/java/com/fs/his/param/FsCourseProductOrderRefundParam.java

@@ -0,0 +1,11 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+@Data
+public class FsCourseProductOrderRefundParam {
+
+    private Long courseOrderId;
+
+    private String sysUserName;
+}

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

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

@@ -142,7 +142,7 @@ public interface IFsUserService
     TableDataInfo selectFsUserPageListNew(FsUserPageListParam param);
 
     Long selectFsUserCount(FsUserPageListParam param);
-    Long selectFsUserCount(int type,Long companyId);
+    Long selectFsUserCount(int type,Long companyI,Long companyUserId);
 
     Map<String, Long> getUserVipCountByCompanyUserId(Long userId);
 

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

+ 43 - 28
fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java

@@ -115,9 +115,8 @@ import static com.fs.his.utils.PhoneUtil.encryptPhone;
 @Lazy
 @Service
 @Slf4j
-@EnableAspectJAutoProxy(exposeProxy = true,proxyTargetClass = true)
-public class FsStoreOrderServiceImpl implements IFsStoreOrderService
-{
+@EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true)
+public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
     @Autowired
     private WxPayService wxPayService;
     @Autowired
@@ -257,7 +256,6 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService
     @Autowired
     private FsStoreOrderDfMapper fsStoreOrderDfMapper;
 
-
     @Value("${express.omsCode}")
     private String expressOmsCode;
 
@@ -1548,8 +1546,8 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService
                 } else if (erpType == 4) {
                     //瀚智
                     erpOrderService = dfOrderService;
-                }else if(erpType == 5){
-                    erpOrderService=jSTOrderService;
+                } else if (erpType == 5) {
+                    erpOrderService = jSTOrderService;
                 }
                 if (erpOrderService != null && StringUtils.isNotEmpty(order.getExtendOrderId())) {
                     if (!order.getExtendOrderId().equals("HIS")) {
@@ -1609,12 +1607,12 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService
             erpOrderService = hzOMSOrderService;
         } else if (erpType == 4) {
             //代服
-            erpOrderService =  dfOrderService;
-        } else if (erpType == 5){
+            erpOrderService = dfOrderService;
+        } else if (erpType == 5) {
             //聚水潭
-            erpOrderService =  jSTOrderService;
+            erpOrderService = jSTOrderService;
             erpOrder.setShop_code(sysConfig.getErpJstShopCode());
-        }else {
+        } else {
             return;
         }
         FsStoreOrder order = fsStoreOrderMapper.selectFsStoreOrderByOrderId(orderId);
@@ -1836,7 +1834,12 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService
                                 this.updateFsStoreOrder(map);
                                 //如果是正常签收,更新订单状态
                                 if (dto.getState().equals("3") && (dto.getStateEx().equals("301") || dto.getStateEx().equals("302") || dto.getStateEx().equals("304") || dto.getStateEx().equals("311"))) {
-                                    this.getGoods(order.getOrderId());
+                                    SysConfig storeConfig = sysConfigMapper.selectConfigByConfigKey("his.store");
+                                    Map<String, Object> config = (Map<String, Object>) JSON.parse(storeConfig.getConfigValue());
+                                    Object isUpdateOrder = config.get("isUpdateOrder");
+                                    if (isUpdateOrder == null || "1".equals(isUpdateOrder.toString())) {
+                                        this.getGoods(order.getOrderId());
+                                    }
                                 }
                             }
                             if (!dto.isSuccess()) {
@@ -1908,7 +1911,12 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService
         fsStoreOrderMapper.updateFsStoreOrder(map);
         //如果是正常签收,更新订单状态
         if (dto.getState().equals("3") && (dto.getStateEx().equals("301") || dto.getStateEx().equals("302") || dto.getStateEx().equals("304") || dto.getStateEx().equals("311"))) {
-            this.getGoods(order.getOrderId());
+            SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.store");
+            Map<String, Object> config = (Map<String, Object>) JSON.parse(sysConfig.getConfigValue());
+            Object isUpdateOrder = config.get("isUpdateOrder");
+            if (isUpdateOrder == null || "1".equals(isUpdateOrder.toString())) {
+                this.getGoods(order.getOrderId());
+            }
         }
         return R.ok();
     }
@@ -1944,9 +1952,9 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService
                     erpOrderService = hzOMSOrderService;
                 } else if (erpType == 4) {
                     erpOrderService = dfOrderService;
-                }else if (erpType == 5){
+                } else if (erpType == 5) {
                     //聚水潭
-                    erpOrderService =  jSTOrderService;
+                    erpOrderService = jSTOrderService;
                 }
                 ErpOrderQueryResponse response = erpOrderService.getOrder(request);
                 if (response.getOrders() != null && response.getOrders().size() > 0) {
@@ -3166,9 +3174,9 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService
         DFCancelOrderResultRequest cancelParam = JSON.parseObject(body, DFCancelOrderResultRequest.class);
         if (cancelParam.getIsCancelSuss() != null) {
             //取消订单
-            log.info("代服管家取消订单回调,{}",JSON.toJSONString(cancelParam));
+            log.info("代服管家取消订单回调,{}", JSON.toJSONString(cancelParam));
             FsStoreOrder fsStoreOrder = fsStoreOrderMapper.selectFsStoreOrderByOrderCode(cancelParam.getOrderNumber());
-            if (fsStoreOrder != null){
+            if (fsStoreOrder != null) {
 //                //1.修改订单
 //                FsStoreOrderSalesParam afterSalesParam = new FsStoreOrderSalesParam();
 //                afterSalesParam.setOrderId(fsStoreOrder.getOrderId());
@@ -3184,11 +3192,11 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService
             }
             String failMsg = addParam.getFailMsg();
             if (com.hc.openapi.tool.util.StringUtils.isNotBlank(failMsg)) {
-                if (failMsg.equals("暂未结果, 请稍后再查")){
+                if (failMsg.equals("暂未结果, 请稍后再查")) {
                     return R.ok("接收成功").put("code", "ok");
                 }
                 //下单失败 返回未推送状态
-                String  orderNumber = addParam.getOrderNumber();
+                String orderNumber = addParam.getOrderNumber();
                 FsStoreOrder fsStoreOrder = fsStoreOrderMapper.selectFsStoreOrderByOrderCode(orderNumber);
                 FsStoreOrder tempOrder = new FsStoreOrder();
                 tempOrder.setOrderId(fsStoreOrder.getOrderId());
@@ -3254,17 +3262,23 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService
             return R.error(dto.getReason());
         }
         FsStoreOrder map = new FsStoreOrder();
-        if(dto != null && dto.getState() != null){
+        if (dto.getState() != null) {
             map.setDeliveryStatus(Integer.parseInt(dto.getState()));
             map.setOrderId(order.getOrderId());
             map.setDeliveryType(dto.getStateEx());
             fsStoreOrderMapper.updateFsStoreOrder(map);
             //如果是正常签收,更新订单状态
             if (dto.getState().equals("3")) {
-                this.getGoods(order.getOrderId());
-            }
+                SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.store");
+                Map<String, Object> config = (Map<String, Object>) JSON.parse(sysConfig.getConfigValue());
+                Object isUpdateOrder = config.get("isUpdateOrder");
+                if (isUpdateOrder == null || "1".equals(isUpdateOrder.toString())) {
+                    this.getGoods(order.getOrderId());
+                }
 
+            }
         }
+
         return R.ok();
     }
 
@@ -3296,7 +3310,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService
                 }
                 expressInfoDTO.setTraces(tracesDTOS);
                 //匹配原代码物流编码
-                ErpDeliverys item = deliverys.get(deliverys.size()-1);
+                ErpDeliverys item = deliverys.get(deliverys.size() - 1);
                 String opCode = item.getOpCode();
                 if ("54".equals(opCode)) {
                     //54 取件
@@ -3328,6 +3342,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService
 
     /**
      * 代服订单状态推送
+     *
      * @param body
      * @return
      */
@@ -3335,17 +3350,17 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService
     public R receiveWaybillPush(String body) {
         DFApiResponse dfApiResponse = JSON.parseObject(body, DFApiResponse.class);
         Object result = dfApiResponse.getResult();
-        if (result != null){
+        if (result != null) {
             String jsonString = JSON.toJSONString(result);
             List<DFOrderStatusResultRequest> requestList = JSON.parseArray(jsonString, DFOrderStatusResultRequest.class);
-            if (requestList != null && !requestList.isEmpty()){
+            if (requestList != null && !requestList.isEmpty()) {
                 //0待揽收 1已揽收 2运输中 3派送中 4异常件 5退回件 6退回签收 7转寄件 8作废件 9已签收 10 已取消
                 for (DFOrderStatusResultRequest temp : requestList) {
-                    if (temp.getStatus() == 10){
+                    if (temp.getStatus() == 10) {
                         //取消订单
                         String mailNumber = temp.getMailNumber();
                         List<FsStoreOrder> fsStoreOrders = fsStoreOrderMapper.selectFsStoreOrderListByDeliverySn(mailNumber);
-                        if (fsStoreOrders != null && !fsStoreOrders.isEmpty()){
+                        if (fsStoreOrders != null && !fsStoreOrders.isEmpty()) {
                             fsStoreOrders.forEach(order -> {
                                 FsStoreOrderSalesParam afterSalesParam = new FsStoreOrderSalesParam();
                                 afterSalesParam.setOrderId(order.getOrderId());
@@ -3391,9 +3406,9 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService
                 } else if (erpType == 4) {
                     //代服
                     erpOrderService = dfOrderService;
-                }else if (erpType == 5){
+                } else if (erpType == 5) {
                     //聚水潭
-                    erpOrderService =  jSTOrderService;
+                    erpOrderService = jSTOrderService;
                 }
                 return erpOrderService;
 

+ 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 - 7
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,8 +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.FsUserAddress;
-import com.fs.his.domain.FsUserIntegralLogs;
+import com.fs.his.domain.*;
 import com.fs.his.enums.FsUserIntegralLogTypeEnum;
 import com.fs.his.mapper.*;
 import com.fs.his.param.FsUserAddIntegralTemplateParam;
@@ -74,7 +77,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;
@@ -117,7 +119,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;
@@ -287,14 +291,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) {
@@ -666,8 +702,8 @@ public class FsUserServiceImpl implements IFsUserService
     }
 
     @Override
-    public Long selectFsUserCount(int type, Long companyId) {
-        return fsUserMapper.selectFsUserCount(type,companyId);
+    public Long selectFsUserCount(int type,Long companyId,Long companyUserId) {
+        return fsUserMapper.selectFsUserCount(type,companyId,companyUserId);
     }
 
     @Override

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

+ 14 - 0
fs-service/src/main/java/com/fs/huifuPay/service/impl/HuiFuServiceImpl.java

@@ -81,6 +81,7 @@ public class HuiFuServiceImpl implements HuiFuService {
             // 商品描述
             request.setGoodsDesc(order.getGoodsDesc());
             extendInfoMap.put("fq_mer_discount_flag", "N");
+            logger.info("汇付回调地址=================:"+config.getHfPayNotifyUrl());
             extendInfoMap.put("notify_url", config.getHfPayNotifyUrl());
             extendInfoMap.put("remark", "string");
             request.setExtendInfo(extendInfoMap);
@@ -252,6 +253,7 @@ public class HuiFuServiceImpl implements HuiFuService {
         SysConfigMapper sysConfigMapper= SpringUtils.getBean(SysConfigMapper.class);
         SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.pay");
         FsPayConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), FsPayConfig.class);
+
 //        FsPayConfig fsPayConfig = new FsPayConfig();
 //        fsPayConfig.setAppId("wxc3f0a952b7bc2b94");
 //        fsPayConfig.setHfProductId("KAZX");
@@ -262,6 +264,18 @@ public class HuiFuServiceImpl implements HuiFuService {
 //        fsPayConfig.setHfRsaPrivateKey("MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCijLcYLMJEe16TS6BtEG9hUezZyYvp2qgpPVGWaaBbb6lud89ILMUC7jyTWufCo2fUQ0nJzYhVlNeMzmGFtg/zFwhkjJIkuCOW+/Koy1ow66Rom8/sNQLb82szHoeklbv17AnD7WJis7cGyy1+3E6jzfaPOB7PTzidK6KyfCWDByOt0JcGe3+6+9+loQFbFRXJ2RpWPQeN72n9FVtSKSvgkGtJNUzh/qBwMPN6ol6xcU/Z2o1sYrRfKC4tcMqccRi/DvvZFJPVlN+YqkJ6lhgAmJg7eZ2fhIgrmzqc96UKp2YUNm+1v8XHCflD9Wv94E6D2JgL4VbF4Zyf+fKYuR7pAgMBAAECggEAfy5UL6ENmuFgHSVF7y+1xdKA2+IbC60ed63XgTVB12jli15Im3MT7ngSg0TUIvERUv4W5MNgkX10rWHo4eKSViPGWE24JuzAQ+j7cuAwwCgPKh4HMAxGIWwyivuvK7JQL1kwRtEccpekc7dS8HhVO0rySBqj2JZmeGrk0HvcKciSWuMjhjT4dJUwSntD07REV6rVjrpQXuvmY40vH88uvHLdH1IcjmJs2yJRNawUNtd+8FvpOCjami7zpB+er+AQ6S2fvpljNqfE5Kadm3MvzBngDdMS3xRvMHfjCifVwFpLP0rLDP6cSn6PJWbkNYQVZi12w8+wb5f7AVlaKXnfdQKBgQDh7VC5+MOqfcUr9h/n2vhFFhQOaGAZCOBc65n8VBj9aRht8ViXFvRrIRmM+QvUbV9/7taFbtAnZXIzu+12T4vnlZv9DTsy6kKloV5923xZ4CpzIVG8crlwJz1wdALeO6M485RtRLjz6nlNKn2m2VJ1d5XFBDhIz5rWUzagPwwpwwKBgQC4L8Eyu6Yn/zQmv8l6rfAsEfUJzfYtojf1PerPYilARtgFuD20cppcOP5oAk2TTX3qaz0Y9atCfL2z2qxtrgKtw2etfhDBmT6l6+pg04SLuyTrVeZ5dxXHt+LRLJnvBbGgnvAM6rSRKdHXT0gfqiRIMw2qIUtndgRr4RK5hqcd4wKBgBYBFh620t/VFhIdC6h6VDnuV4+7rLhje+6w57OCwVhVFxMGMZmtm6qfc6yeSP+sk2OTcINYcp+TqtbNE+i1AKxSjvnLgxuHY2xcViat7OOYCKpj8WEIT3VT7RD5y5m3d0NBvhASZG0lRiE05T4N5pEYT5b7vTuiNLNxMV3UJiwfAoGBAIb2/1QEqwmN+RIX4TSTNnWkpvELSkRAJU8Akwpp/J5MC0mNqzGJ9NB1Nv7SCTRSSV04PaoHgvoSXBPpvgYUx4O6t0MrKG4ktAJzL+jJtcuKU9Bavqrs9znE5mCulRHQE0wGixJ7/dqNUWW7g7coPrPlLTMoeI+UrEK8x7LJF7ZPAoGALHvtu6zzWVeCdELIPUTersVQrH1R3yZuf6rgubg4XFw3meFcd4W8BvXm4EKGRZxdiyZvCtKlkV9u110Rx3RNSbZCOb3MClmkcow8vPIhmyGWIGymAIxr9JcD0p6HogzPvbjRsLh1nFg/+95OL2E353Bp4/oPIgYIfnYNUfD+0gA=");
 //        fsPayConfig.setHfRsaPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjbkiiy2ewzuPsM5uZbAFMJOBWCRRQ2RtH7Dbr9Evbow6IEyvGoen8XKpiuXzapeps3b2eogETHVFQtLooqRHpVRppFKtU1AHZXA7C6wPocfMldJbTykDCowyJwOSYEaFPBjr9cw6dQcBJMIEHj0YWjBPR1dPVzf+y4sUohbrkS/FANBpp24j+Mu0qEqh8TuVuKlvig7jbmXJiJkAmUJ+Tb3Caj20fFTen6juPd3zR/KM3twki06wZZbb4KyCiM/NwozEqJ9PkWSs6rG7aW+BEfzlo3m1a7MlL0vpKNR3f0lbywq09rFAwtA7R2lssWwLMma4LOqtMMqo3yZdv4vObQIDAQAB");
 //        fsPayConfig.setHfPayOnlineNotifyUrl("https://userapp.his.cdwjyyh.com//app/hfPay/payNotifyUrl");
+
+//        FsPayConfig fsPayConfig = new FsPayConfig();
+//        fsPayConfig.setAppId("wxb48fe0acfdc70a92");
+//        fsPayConfig.setHfProductId("KAZX");
+//        fsPayConfig.setHfSysId("6666000173104153");
+//        fsPayConfig.setHuifuId("6666000173104153");
+//        fsPayConfig.setHfRsaPrivateKey("MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCYzLmE2qBlRQbAosIjPxTZwRItgMgOTT99bRYxa3xQhiq2+YPj2R5lOKu5Y74Po43cg5UG8+7z7r4hV2q+sS3DwvnifHrkytXrnwDuW4ijagiMhr0Am9cEP6WqmuCyy8cMS+MtZ8eBCFefXjDsO4zXDk9/jxpywZ59i85q5Ka03S6lJOW+cq7RToEGJoxF1E98UtewbcPL2FxU5eQnte51RiGGly3drAQh+Tbdt8brjycnfR1SAhEFe/cFAOG6zC1XyJwkCfFynpvihA7SGSrTozBvIxg5ylGTx+HiRPDlYBABzWZkZgtvSGF0V7DQy5Tia/kuksOuePXb59MrUyIBAgMBAAECggEALWH44/2vUAS9aa+tq5xLzBUtGfi68ox9A/rHcaw0AxKmUywuwRi2j2fSkUCPrcNtGga215bR7P+G1w5ItRSYvCEH6P4B3jxkZxQVybXEEo0mtt45+plOtoNU6CQSAujFWOCdO9osBiX9KGdobnGNdj5Y3FEbkOPy9+TzTQpWfTcSWXi3qwsWz05jb04NpqV+xAPDIotAGvDIKJ99kH7/ewlyADvI7axj4JJaHnQOU/UcNHX8gtFgPTxf4e+UGLoPz3TRqFkVM9UIgejFilUUbIcwoCl1sLo3tjdoomYzEYxHPVrtk/8YRRUnzcvThSgydDhO+0GLa8qMCYk+XYrPAQKBgQDaTg+AQqRVQHH2KxYwUmfZXj+RfgBbR1L/v0j5NuxKSdxytBZA6K4I4fX8D/o2PXpkKiGaqyLnf5/wQsmj3fxIzXKyZWcU3lgHE7L18NWl6wPqpz5zJwgKstFcZqJ4HXZgSZw9/iNktIS5K6PZUgsGy+QJ0e4SFqKUED/zRoVKUQKBgQCzLxMsA2rl1n9q93PGOLE9bS0uahtpTePKVLn+ceQ/acDdokCf0MtM3uWJd5ti8BWTMECg4JVXIBUrYeLHwVlZMKvijGZRDYGJUF8hfjWU2pTDI6b2+vSQSVWLkyOdznvzUxrhKDbj21lQNPrKqL/nDfWKH/5QfScfjHviEQ7AsQKBgFXQTaObjsG8XY/pDAXevtfhhpeIslcvSF8kMGlWv7fMJQ4p4H2PeaogOPPmy/K6Y/wv25nTIBtkPdjSSDVUM7HioO2jksvPQ0c05Spsi293XMjHCXN2qmCaPlZWOhOBcWEUTojH993EYE/x6ayp5Y+8Yl3B2hXeM/aEFL9qv0ahAoGADaa7fjHwdfxGjt61aletYTGtLIkW94ngneygkvsYWaBz+i6/X62nn36n3DZJl1sVObaGZftWRWIDWt/FSFS5uurTXZo2vVwbD1wZM1MLQAD7LnbL5Ksv8MI1i0G1h/NQTDR7qsXGkMuIXWz74m7C2BafK1vOo1E1ptisI4gLKLECgYBdCCxkf/jCXcsQEs+hmYWm4gvHahvPIDVI5s2qX/hrJsFx6LaorC1iSmwwJQ7zM/AFqwc/NlCGo2NE44MKFPqIp/08fM4Tx2i8BFQQF3G1Y8oAr/xusqJVSI3CHvw2yD6DDgwTOeQ2TD1v3lnOEB6g0JaamTQQ6NQ0iUNRsDXAPQ==");
+//        fsPayConfig.setHfRsaPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuziAvRIul3mwBlEDSMMvi3v83HEebLpEWoBhcqL/Vlg90tjT51lEO4OksGDU08ypESMaby+Rpvw9rRTFBbdm9oZiiKyKrYChoW9s/Tu5gDIt6k1+YP3204/lOz4Pat9hlRetIhDcgbAiChwDWS/+shfdi6vMX31fO5m5oyo1XlwL477pZYykwxalxgXjWHUkyDRvYGDFquLTELSEq+vpQthYwZ0ghamIkxQV7syjNp06bCMzLmnB9jVEilQuDGqRrlDJpLjKqZkkTwp5JJJRJPLIJag0iLZMJjfdHKmTojcd+y9KRUU+KW0OMUeC2T8SBKpz918ioBKJtuzmUD6YNwIDAQAB");
+//        //fsPayConfig.setHfRsaPrivateKey("MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCijLcYLMJEe16TS6BtEG9hUezZyYvp2qgpPVGWaaBbb6lud89ILMUC7jyTWufCo2fUQ0nJzYhVlNeMzmGFtg/zFwhkjJIkuCOW+/Koy1ow66Rom8/sNQLb82szHoeklbv17AnD7WJis7cGyy1+3E6jzfaPOB7PTzidK6KyfCWDByOt0JcGe3+6+9+loQFbFRXJ2RpWPQeN72n9FVtSKSvgkGtJNUzh/qBwMPN6ol6xcU/Z2o1sYrRfKC4tcMqccRi/DvvZFJPVlN+YqkJ6lhgAmJg7eZ2fhIgrmzqc96UKp2YUNm+1v8XHCflD9Wv94E6D2JgL4VbF4Zyf+fKYuR7pAgMBAAECggEAfy5UL6ENmuFgHSVF7y+1xdKA2+IbC60ed63XgTVB12jli15Im3MT7ngSg0TUIvERUv4W5MNgkX10rWHo4eKSViPGWE24JuzAQ+j7cuAwwCgPKh4HMAxGIWwyivuvK7JQL1kwRtEccpekc7dS8HhVO0rySBqj2JZmeGrk0HvcKciSWuMjhjT4dJUwSntD07REV6rVjrpQXuvmY40vH88uvHLdH1IcjmJs2yJRNawUNtd+8FvpOCjami7zpB+er+AQ6S2fvpljNqfE5Kadm3MvzBngDdMS3xRvMHfjCifVwFpLP0rLDP6cSn6PJWbkNYQVZi12w8+wb5f7AVlaKXnfdQKBgQDh7VC5+MOqfcUr9h/n2vhFFhQOaGAZCOBc65n8VBj9aRht8ViXFvRrIRmM+QvUbV9/7taFbtAnZXIzu+12T4vnlZv9DTsy6kKloV5923xZ4CpzIVG8crlwJz1wdALeO6M485RtRLjz6nlNKn2m2VJ1d5XFBDhIz5rWUzagPwwpwwKBgQC4L8Eyu6Yn/zQmv8l6rfAsEfUJzfYtojf1PerPYilARtgFuD20cppcOP5oAk2TTX3qaz0Y9atCfL2z2qxtrgKtw2etfhDBmT6l6+pg04SLuyTrVeZ5dxXHt+LRLJnvBbGgnvAM6rSRKdHXT0gfqiRIMw2qIUtndgRr4RK5hqcd4wKBgBYBFh620t/VFhIdC6h6VDnuV4+7rLhje+6w57OCwVhVFxMGMZmtm6qfc6yeSP+sk2OTcINYcp+TqtbNE+i1AKxSjvnLgxuHY2xcViat7OOYCKpj8WEIT3VT7RD5y5m3d0NBvhASZG0lRiE05T4N5pEYT5b7vTuiNLNxMV3UJiwfAoGBAIb2/1QEqwmN+RIX4TSTNnWkpvELSkRAJU8Akwpp/J5MC0mNqzGJ9NB1Nv7SCTRSSV04PaoHgvoSXBPpvgYUx4O6t0MrKG4ktAJzL+jJtcuKU9Bavqrs9znE5mCulRHQE0wGixJ7/dqNUWW7g7coPrPlLTMoeI+UrEK8x7LJF7ZPAoGALHvtu6zzWVeCdELIPUTersVQrH1R3yZuf6rgubg4XFw3meFcd4W8BvXm4EKGRZxdiyZvCtKlkV9u110Rx3RNSbZCOb3MClmkcow8vPIhmyGWIGymAIxr9JcD0p6HogzPvbjRsLh1nFg/+95OL2E353Bp4/oPIgYIfnYNUfD+0gA=");
+//        //fsPayConfig.setHfRsaPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjbkiiy2ewzuPsM5uZbAFMJOBWCRRQ2RtH7Dbr9Evbow6IEyvGoen8XKpiuXzapeps3b2eogETHVFQtLooqRHpVRppFKtU1AHZXA7C6wPocfMldJbTykDCowyJwOSYEaFPBjr9cw6dQcBJMIEHj0YWjBPR1dPVzf+y4sUohbrkS/FANBpp24j+Mu0qEqh8TuVuKlvig7jbmXJiJkAmUJ+Tb3Caj20fFTen6juPd3zR/KM3twki06wZZbb4KyCiM/NwozEqJ9PkWSs6rG7aW+BEfzlo3m1a7MlL0vpKNR3f0lbywq09rFAwtA7R2lssWwLMma4LOqtMMqo3yZdv4vObQIDAQAB");
+//        fsPayConfig.setHfPayNotifyUrl("https://userapp.baohetangjinyue.cn//app/hfPay/payNotifyUrl");
+
         config=fsPayConfig;
         MerConfig merConfig = new MerConfig();
         merConfig.setProcutId(fsPayConfig.getHfProductId());

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

+ 85 - 25
fs-service/src/main/java/com/fs/qw/service/impl/QwMaterialServiceImpl.java

@@ -13,6 +13,10 @@ import com.fs.qwApi.Result.QwUploadResult;
 import com.fs.qwApi.service.QwApiService;
 import com.fs.voice.utils.StringUtil;
 import lombok.extern.log4j.Log4j2;
+import org.apache.commons.io.FileUtils;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -21,6 +25,7 @@ import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.net.URL;
+import java.net.URLEncoder;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
@@ -146,36 +151,61 @@ public class QwMaterialServiceImpl extends ServiceImpl<QwMaterialMapper, QwMater
      */
     public static File urlToFile(String fileUrl) throws Exception {
 
-        // 从URL中提取文件名,文件后缀
-        String fileExtension = getFileExtension(new File(fileUrl).getName());
-        String fileName = extractFileName(new URL(fileUrl))+new Date().getTime();
-        File tempFile=null;
-        if (!StringUtil.strIsNullOrEmpty(fileExtension)){
-            // 创建一个临时文件
-            tempFile = File.createTempFile(fileName, "."+fileExtension);
-        }else {
-            tempFile = File.createTempFile(fileName, null);
-        }
-
-
-        // 使用 try-with-resources 语句自动关闭资源
-        try (BufferedInputStream in = new BufferedInputStream(new URL(fileUrl).openStream());
-             FileOutputStream out = new FileOutputStream(tempFile)) {
-
-            byte[] buffer = new byte[1024];
-            int len;
+        // 编码文件名部分
+        String encodedFileUrl = fileUrl.replace(
+                new File(fileUrl).getName(),
+                URLEncoder.encode(new File(fileUrl).getName(), "UTF-8")
+        );
 
-            // 读取数据并写入到临时文件
-            while ((len = in.read(buffer)) != -1) {
-                out.write(buffer, 0, len);
-            }
-            out.flush();
+        // 生成安全的临时文件名
+        String fileExtension = getFileExtension(new File(fileUrl).getName());
+        String safeFileName = "temp_" + System.currentTimeMillis();
+        File tempFile = File.createTempFile(safeFileName, "." + fileExtension);
+
+        // 使用 HttpClient 下载
+        try (CloseableHttpClient client = HttpClients.createDefault()) {
+            HttpGet request = new HttpGet(encodedFileUrl);
+            request.setHeader("User-Agent", "Mozilla/5.0");
+            FileUtils.copyInputStreamToFile(
+                    client.execute(request).getEntity().getContent(),
+                    tempFile
+            );
         } catch (IOException e) {
-            // 处理异常,例如删除创建的临时文件
             tempFile.delete();
-            throw e;
+            throw new RuntimeException("下载文件失败: " + encodedFileUrl, e);
         }
 
+
+//        // 从URL中提取文件名,文件后缀
+//        String fileExtension = getFileExtension(new File(fileUrl).getName());
+//        String fileName = extractFileName(new URL(fileUrl))+new Date().getTime();
+//        File tempFile=null;
+//        if (!StringUtil.strIsNullOrEmpty(fileExtension)){
+//            // 创建一个临时文件
+//            tempFile = File.createTempFile(fileName, "."+fileExtension);
+//        }else {
+//            tempFile = File.createTempFile(fileName, null);
+//        }
+//
+//
+//        // 使用 try-with-resources 语句自动关闭资源
+//        try (BufferedInputStream in = new BufferedInputStream(new URL(fileUrl).openStream());
+//             FileOutputStream out = new FileOutputStream(tempFile)) {
+//
+//            byte[] buffer = new byte[1024];
+//            int len;
+//
+//            // 读取数据并写入到临时文件
+//            while ((len = in.read(buffer)) != -1) {
+//                out.write(buffer, 0, len);
+//            }
+//            out.flush();
+//        } catch (IOException e) {
+//            // 处理异常,例如删除创建的临时文件
+//            tempFile.delete();
+//            throw e;
+//        }
+
         return tempFile;
     }
 
@@ -255,6 +285,36 @@ public class QwMaterialServiceImpl extends ServiceImpl<QwMaterialMapper, QwMater
         List<QwMaterial> qwMaterials = qwMaterialMapper.selectQwMaterialListByMediaIdList();
 
 
+//        qwMaterials.forEach(item->{
+//            // 将URL转换为文件
+//            File materialFile = null;
+//            try {
+//                materialFile = urlToFile(item.getMaterialUrl());
+//            } catch (Exception e) {
+//                throw new RuntimeException(e);
+//            }
+//
+//            // 上传素材到企业微信
+//            QwUploadResult uploadResult = null;
+//            try {
+//                uploadResult = qwApiService.upload(
+//                        materialFile,
+//                        item.getMaterialType(),
+//                        item.getCorpId()
+//                );
+//            } catch (IOException e) {
+//                throw new RuntimeException(e);
+//            }
+//
+//            if (uploadResult.getErrCode() == 0) {
+//                // 设置素材信息
+//                item.setMaterialMediaId(uploadResult.getMediaId());
+//                item.setCreatedAt(Long.valueOf(uploadResult.getCreatedAt()));
+//            } else {
+//                log.error("上传失败:{},{}", uploadResult.getErrMsg(), item);
+//            }
+//        });
+
         // 创建线程安全的集合用于存储处理结果
         ConcurrentLinkedQueue<QwMaterial> successQueue = new ConcurrentLinkedQueue<>();
 

+ 1 - 1
fs-service/src/main/java/com/fs/statis/service/impl/StatisticsCompanyServiceImpl.java

@@ -772,7 +772,7 @@ public class StatisticsCompanyServiceImpl implements IStatisticsCompanyService {
 
     @Override
     public DealerAggregatedDTO dealerAggregated(Long companyId) {
-        Long dayUserCount=userService.selectFsUserCount(1,companyId);
+        Long dayUserCount=userService.selectFsUserCount(1,companyId, null);
         Long storeOrderCount=storeOrderService.selectFsStoreOrderTotalCount(0,companyId);
         Long dayStoreOrderCount=storeOrderService.selectFsStoreOrderTotalCount(1,companyId);
         Long paymentCount=paymentService.selectFsStorePaymentCount(0,companyId);

+ 1 - 1
fs-service/src/main/java/com/fs/statis/service/impl/StatisticsServiceImpl.java

@@ -677,7 +677,7 @@ public class StatisticsServiceImpl implements IStatisticsService {
 
     @Override
     public DealerAggregatedDTO dealerAggregated() {
-        Long dayUserCount=userService.selectFsUserCount(1,null);
+        Long dayUserCount=userService.selectFsUserCount(1,null, null);
         Long storeOrderCount=storeOrderService.selectFsStoreOrderTotalCount(0,null);
         Long dayStoreOrderCount=storeOrderService.selectFsStoreOrderTotalCount(1,null);
         Long paymentCount=paymentService.selectFsStorePaymentCount(0,null);

+ 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 - 1
fs-service/src/main/resources/application-druid-bjczwh.yml

@@ -146,4 +146,6 @@ rocketmq:
         group: common-group
         access-key: ak16xj8o92zp984557f83ba2 # 替换为实际的 accessKey
         secret-key: sk2ff1c6b15b74b888 # 替换为实际的 secretKey
-
+openIM:
+    secret: openIM123
+    userID: imAdmin

+ 3 - 1
fs-service/src/main/resources/application-druid-bnkc.yml

@@ -146,4 +146,6 @@ rocketmq:
         group: common-group
         access-key: ak16xj8o92zp984557f83ba2 # 替换为实际的 accessKey
         secret-key: sk2ff1c6b15b74b888 # 替换为实际的 secretKey
-
+openIM:
+    secret: openIM123
+    userID: imAdmin

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

@@ -138,3 +138,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-hcl.yml

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

+ 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

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

@@ -138,3 +138,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-xfk-test.yml

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

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

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

+ 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, '');

+ 99 - 0
fs-service/src/main/resources/mapper/course/FsCourseProductMapper.xml

@@ -0,0 +1,99 @@
+<?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.course.mapper.FsCourseProductMapper">
+    
+    <resultMap type="FsCourseProduct" id="FsCourseProductResult">
+        <result property="id"    column="id"    />
+        <result property="imgUrl"    column="img_url"    />
+        <result property="images"    column="images"    />
+        <result property="barCode"    column="bar_code"    />
+        <result property="sort"    column="sort"    />
+        <result property="stock"    column="stock"    />
+        <result property="productContent"    column="product_content"    />
+        <result property="productPrice"    column="product_price"    />
+        <result property="productName"    column="product_name"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateTime"    column="update_time"    />
+    </resultMap>
+
+    <sql id="selectFsCourseProductVo">
+        select id, img_url, images, bar_code, sort, stock, product_content, product_price, product_name, create_time, update_time from fs_course_product
+    </sql>
+
+    <select id="selectFsCourseProductList" parameterType="FsCourseProduct" resultMap="FsCourseProductResult">
+        <include refid="selectFsCourseProductVo"/>
+        <where>  
+            <if test="imgUrl != null  and imgUrl != ''"> and img_url = #{imgUrl}</if>
+            <if test="images != null  and images != ''"> and images = #{images}</if>
+            <if test="barCode != null  and barCode != ''"> and bar_code = #{barCode}</if>
+            <if test="sort != null "> and sort = #{sort}</if>
+            <if test="stock != null "> and stock = #{stock}</if>
+            <if test="productContent != null  and productContent != ''"> and product_content = #{productContent}</if>
+            <if test="productPrice != null "> and product_price = #{productPrice}</if>
+            <if test="productName != null  and productName != ''"> and product_name like concat('%', #{productName}, '%')</if>
+        </where>
+    </select>
+    
+    <select id="selectFsCourseProductById" parameterType="Long" resultMap="FsCourseProductResult">
+        <include refid="selectFsCourseProductVo"/>
+        where id = #{id}
+    </select>
+        
+    <insert id="insertFsCourseProduct" parameterType="FsCourseProduct" useGeneratedKeys="true" keyProperty="id">
+        insert into fs_course_product
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="imgUrl != null">img_url,</if>
+            <if test="images != null">images,</if>
+            <if test="barCode != null">bar_code,</if>
+            <if test="sort != null">sort,</if>
+            <if test="stock != null">stock,</if>
+            <if test="productContent != null">product_content,</if>
+            <if test="productPrice != null">product_price,</if>
+            <if test="productName != null">product_name,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateTime != null">update_time,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="imgUrl != null">#{imgUrl},</if>
+            <if test="images != null">#{images},</if>
+            <if test="barCode != null">#{barCode},</if>
+            <if test="sort != null">#{sort},</if>
+            <if test="stock != null">#{stock},</if>
+            <if test="productContent != null">#{productContent},</if>
+            <if test="productPrice != null">#{productPrice},</if>
+            <if test="productName != null">#{productName},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+         </trim>
+    </insert>
+
+    <update id="updateFsCourseProduct" parameterType="FsCourseProduct">
+        update fs_course_product
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="imgUrl != null">img_url = #{imgUrl},</if>
+            <if test="images != null">images = #{images},</if>
+            <if test="barCode != null">bar_code = #{barCode},</if>
+            <if test="sort != null">sort = #{sort},</if>
+            <if test="stock != null">stock = #{stock},</if>
+            <if test="productContent != null">product_content = #{productContent},</if>
+            <if test="productPrice != null">product_price = #{productPrice},</if>
+            <if test="productName != null">product_name = #{productName},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteFsCourseProductById" parameterType="Long">
+        delete from fs_course_product where id = #{id}
+    </delete>
+
+    <delete id="deleteFsCourseProductByIds" parameterType="String">
+        delete from fs_course_product where id in 
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 145 - 0
fs-service/src/main/resources/mapper/course/FsCourseProductOrderMapper.xml

@@ -0,0 +1,145 @@
+<?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.course.mapper.FsCourseProductOrderMapper">
+    
+    <resultMap type="FsCourseProductOrder" id="FsCourseProductOrderResult">
+        <result property="courseOrderId"    column="course_order_id"    />
+        <result property="orderCode"    column="order_code"    />
+        <result property="userId"    column="user_id"    />
+        <result property="userName"    column="user_name"    />
+        <result property="userPhone"    column="user_phone"    />
+        <result property="courseProductId"    column="course_product_id"    />
+        <result property="productJson"    column="product_json"    />
+        <result property="courseId"    column="course_id"    />
+        <result property="videoId"    column="video_id"    />
+        <result property="isPay"    column="is_pay"    />
+        <result property="payTime"    column="pay_time"    />
+        <result property="payType"    column="pay_type"    />
+        <result property="status"    column="status"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="refundTime"    column="refund_time"    />
+        <result property="refundExplain"    column="refund_explain"    />
+        <result property="verifyCode"    column="verify_code"    />
+        <result property="updateTime"    column="update_time"    />
+        <result property="companyId"    column="company_id"    />
+        <result property="companyUserId"    column="company_user_id"    />
+        <result property="extId"    column="ext_id"    />
+    </resultMap>
+
+    <sql id="selectFsCourseProductOrderVo">
+        select course_order_id, order_code, user_id, user_name, user_phone, course_product_id, product_json, course_id, video_id, is_pay, pay_time, pay_type, status, create_time, refund_time, refund_explain, verify_code, update_time, company_id, company_user_id, ext_id from fs_course_product_order
+    </sql>
+
+    <select id="selectFsCourseProductOrderList"  resultType="com.fs.course.vo.FsCourseProductOrderVO">
+        SELECT cpo.*,ucv.title,uc.course_name,c.company_name,cu.user_name as company_user_name,qec.name as ext_name
+        FROM fs_course_product_order cpo
+        LEFT JOIN fs_user_course_video ucv ON ucv.video_id = cpo.video_id
+        LEFT JOIN fs_user_course uc ON uc.course_id = cpo.course_id
+        LEFT JOIN company c ON c.company_id = cpo.company_id
+        LEFT JOIN company_user cu ON cu.user_id = cpo.company_user_id
+        LEFT JOIN qw_external_contact qec ON qec.id = cpo.ext_id
+        <where>  
+            <if test="orderCode != null  and orderCode != ''"> and cpo.order_code = #{orderCode}</if>
+            <if test="userName != null  and userName != ''"> and cpo.user_name like concat('%', #{userName}, '%')</if>
+            <if test="userPhone != null  and userPhone != ''"> and cpo.user_phone = #{userPhone}</if>
+            <if test="isPay != null "> and cpo.is_pay = #{isPay}</if>
+            <if test="payStartTime != null and payEndTime != null"> and cpo.pay_time BETWEEN #{payStartTime} AND #{payEndTime}</if>
+            <if test="status != null "> and cpo.status = #{status}</if>
+            <if test="refundStartTime != null and refundEndTime != null"> and cpo.refund_time BETWEEN #{refundStartTime} AND #{refundEndTime}</if>
+        </where>
+        ORDER BY create_time DESC
+    </select>
+    
+    <select id="selectFsCourseProductOrderByCourseOrderId" parameterType="Long" resultMap="FsCourseProductOrderResult">
+        <include refid="selectFsCourseProductOrderVo"/>
+        where course_order_id = #{courseOrderId}
+    </select>
+        
+    <insert id="insertFsCourseProductOrder" parameterType="FsCourseProductOrder" useGeneratedKeys="true" keyProperty="courseOrderId">
+        insert into fs_course_product_order
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="orderCode != null">order_code,</if>
+            <if test="userId != null">user_id,</if>
+            <if test="userName != null">user_name,</if>
+            <if test="userPhone != null">user_phone,</if>
+            <if test="courseProductId != null">course_product_id,</if>
+            <if test="productJson != null">product_json,</if>
+            <if test="courseId != null">course_id,</if>
+            <if test="videoId != null">video_id,</if>
+            <if test="isPay != null">is_pay,</if>
+            <if test="payTime != null">pay_time,</if>
+            <if test="payType != null">pay_type,</if>
+            <if test="status != null">status,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="refundTime != null">refund_time,</if>
+            <if test="refundExplain != null">refund_explain,</if>
+            <if test="verifyCode != null">verify_code,</if>
+            <if test="updateTime != null">update_time,</if>
+            <if test="companyId != null">company_id,</if>
+            <if test="companyUserId != null">company_user_id,</if>
+            <if test="extId != null">ext_id,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="orderCode != null">#{orderCode},</if>
+            <if test="userId != null">#{userId},</if>
+            <if test="userName != null">#{userName},</if>
+            <if test="userPhone != null">#{userPhone},</if>
+            <if test="courseProductId != null">#{courseProductId},</if>
+            <if test="productJson != null">#{productJson},</if>
+            <if test="courseId != null">#{courseId},</if>
+            <if test="videoId != null">#{videoId},</if>
+            <if test="isPay != null">#{isPay},</if>
+            <if test="payTime != null">#{payTime},</if>
+            <if test="payType != null">#{payType},</if>
+            <if test="status != null">#{status},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="refundTime != null">#{refundTime},</if>
+            <if test="refundExplain != null">#{refundExplain},</if>
+            <if test="verifyCode != null">#{verifyCode},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="companyId != null">#{companyId},</if>
+            <if test="companyUserId != null">#{companyUserId},</if>
+            <if test="extId != null">#{extId},</if>
+         </trim>
+    </insert>
+
+    <update id="updateFsCourseProductOrder" parameterType="FsCourseProductOrder">
+        update fs_course_product_order
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="orderCode != null">order_code = #{orderCode},</if>
+            <if test="userId != null">user_id = #{userId},</if>
+            <if test="userName != null">user_name = #{userName},</if>
+            <if test="userPhone != null">user_phone = #{userPhone},</if>
+            <if test="courseProductId != null">course_product_id = #{courseProductId},</if>
+            <if test="productJson != null">product_json = #{productJson},</if>
+            <if test="courseId != null">course_id = #{courseId},</if>
+            <if test="videoId != null">video_id = #{videoId},</if>
+            <if test="isPay != null">is_pay = #{isPay},</if>
+            <if test="payTime != null">pay_time = #{payTime},</if>
+            <if test="payType != null">pay_type = #{payType},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="refundTime != null">refund_time = #{refundTime},</if>
+            <if test="refundExplain != null">refund_explain = #{refundExplain},</if>
+            <if test="verifyCode != null">verify_code = #{verifyCode},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="companyId != null">company_id = #{companyId},</if>
+            <if test="companyUserId != null">company_user_id = #{companyUserId},</if>
+            <if test="extId != null">ext_id = #{extId},</if>
+        </trim>
+        where course_order_id = #{courseOrderId}
+    </update>
+
+    <delete id="deleteFsCourseProductOrderByCourseOrderId" parameterType="Long">
+        delete from fs_course_product_order where course_order_id = #{courseOrderId}
+    </delete>
+
+    <delete id="deleteFsCourseProductOrderByCourseOrderIds" parameterType="String">
+        delete from fs_course_product_order where course_order_id in 
+        <foreach item="courseOrderId" collection="array" open="(" separator="," close=")">
+            #{courseOrderId}
+        </foreach>
+    </delete>
+</mapper>

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

@@ -24,10 +24,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="sendFinishMsg"    column="send_finish_msg"    />
         <result property="campPeriodTime"    column="camp_period_time"    />
         <result property="lastHeartbeatTime"    column="last_heartbeat_time"    />
+        <result property="project"    column="project"    />
     </resultMap>
 
     <sql id="selectFsCourseWatchLogVo">
-        select log_id, user_id,finish_time,send_finish_msg,sop_id,video_id,reward_type, log_type, create_time, update_time, qw_external_contact_id, duration, qw_user_id, company_user_id, company_id, course_id,camp_period_time from fs_course_watch_log
+        select log_id, user_id,finish_time,send_finish_msg,sop_id,video_id,reward_type, log_type, create_time, update_time, qw_external_contact_id, duration, qw_user_id, company_user_id, company_id, course_id,camp_period_time,project from fs_course_watch_log
     </sql>
 
     <select id="selectFsCourseWatchLogList" parameterType="FsCourseWatchLog" resultMap="FsCourseWatchLogResult">
@@ -44,6 +45,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="courseId != null "> and course_id = #{courseId}</if>
             <if test="sendType != null "> and send_type = #{sendType}</if>
             <if test="campPeriodTime != null "> and camp_period_time = #{campPeriodTime}</if>
+            <if test="project != null "> and project = #{project}</if>
         </where>
     </select>
 
@@ -218,6 +220,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="sendFinishMsg != null">send_finish_msg,</if>
             <if test="campPeriodTime != null">camp_period_time,</if>
             <if test="periodId != null">period_id,</if>
+            <if test="project != null">project,</if>
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="userId != null">#{userId},</if>
@@ -238,6 +241,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="sendFinishMsg != null">#{sendFinishMsg},</if>
             <if test="campPeriodTime != null">#{campPeriodTime},</if>
             <if test="periodId != null">#{periodId},</if>
+            <if test="project != null">#{project},</if>
         </trim>
     </insert>
 
@@ -261,6 +265,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="finishTime != null">finish_time,</if>
             <if test="sendFinishMsg != null">send_finish_msg,</if>
             <if test="campPeriodTime != null">camp_period_time,</if>
+            <if test="project != null">project,</if>
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="userId != null">#{userId},</if>
@@ -280,6 +285,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="finishTime != null">#{finishTime},</if>
             <if test="sendFinishMsg != null">#{sendFinishMsg},</if>
             <if test="campPeriodTime != null">#{campPeriodTime},</if>
+            <if test="project != null">#{project},</if>
         </trim>
         on duplicate key update
         <trim suffixOverrides=",">
@@ -305,7 +311,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         send_type,
         reward_type,
         sop_id,
-        camp_period_time
+        camp_period_time,
+        project
         )
         VALUES
         <foreach collection="watchLogs" item="log" separator=",">
@@ -324,7 +331,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{log.sendType},
             #{log.rewardType},
             #{log.sopId},
-            #{log.campPeriodTime}
+            #{log.campPeriodTime},
+            #{log.project}
             )
         </foreach>
         ON DUPLICATE KEY UPDATE
@@ -354,6 +362,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="sendFinishMsg != null">send_finish_msg = #{sendFinishMsg},</if>
             <if test="lastHeartbeatTime != null">last_heartbeat_time = #{lastHeartbeatTime},</if>
             <if test="periodId != null">period_id = #{periodId},</if>
+            <if test="project != null">project = #{project},</if>
         </trim>
         where log_id = #{logId}
     </update>

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

@@ -58,6 +58,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                 )
             </if>
         </where>
+        order by cr.create_time desc
     </select>
 
     <select id="selectFsUserCourseComplaintRecordByRecordId" parameterType="Long" resultType="com.fs.course.vo.FsUserCourseComplaintRecordPageListVO">

+ 13 - 1
fs-service/src/main/resources/mapper/course/FsUserCourseVideoMapper.xml

@@ -102,6 +102,10 @@
             <if test="lastJoinTime != null">last_join_time,</if>
             <if test="userId != null">user_id,</if>
             <if test="projectId != null">project_id,</if>
+            <if test="isProduct != null">is_product,</if>
+            <if test="productId != null">product_id,</if>
+            <if test="listingStartTime != null">listing_start_time,</if>
+            <if test="listingEndTime != null">listing_end_time,</if>
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="fileId != null">#{fileId},</if>
@@ -133,6 +137,10 @@
             <if test="viewStartTime != null">#{viewStartTime},</if>
             <if test="viewEndTime != null">#{viewEndTime},</if>
             <if test="lastJoinTime != null">#{lastJoinTime},</if>
+            <if test="isProduct != null">#{isProduct},</if>
+            <if test="productId != null">#{productId},</if>
+            <if test="listingStartTime != null">#{listingStartTime},</if>
+            <if test="listingEndTime != null">#{listingEndTime},</if>
             <if test="userId != null">#{userId},</if>
             <if test="projectId != null">#{projectId},</if>
         </trim>
@@ -216,6 +224,10 @@
             <if test="viewStartTime != null">view_start_time = #{viewStartTime},</if>
             <if test="viewEndTime != null">view_end_time = #{viewEndTime},</if>
             <if test="lastJoinTime != null">last_join_time = #{lastJoinTime},</if>
+            <if test="isProduct != null">is_product = #{isProduct},</if>
+            <if test="productId != null">product_id = #{productId},</if>
+            <if test="listingStartTime != null">listing_start_time = #{listingStartTime},</if>
+            <if test="listingEndTime != null">listing_end_time = #{listingEndTime},</if>
             <if test="userId != null">user_id = #{userId},</if>
             <if test="projectId != null">project_id = #{projectId},</if>
         </trim>
@@ -348,7 +360,7 @@
         left join fs_user_course_training_camp c on fcp.training_camp_id = c.training_camp_id
         where course.is_del = 0 and video.video_id = #{videoId}
          and fcp.period_id = #{periodId}
-
+        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">

+ 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>

+ 5 - 3
fs-service/src/main/resources/mapper/his/FsUserMapper.xml

@@ -704,10 +704,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 
     <select id="getUserVipCountByCompanyUserId" resultType="java.util.Map">
         select
-        count(if(date(u.create_time) = curdate(),u.user_id, null)) newVipCount,
-        count(u.user_id) vipCount
+            count(if(date(u.create_time) = curdate(),u.user_id, null)) newVipCount,
+            count(u.user_id) vipCount
         from fs_user u
-        where u.company_user_id = #{companyUserId}
+        left join fs_user_company_user ucu on ucu.user_id = u.user_id
+        left join company_user cu on cu.user_id = ucu.company_user_id
+        where cu.user_id = #{companyUserId}
     </select>
 
     <select id="getUserNumber" resultType="com.fs.store.vo.h5.UserListCountVO">

+ 30 - 0
fs-user-app/src/main/java/com/fs/app/controller/CourseProductController.java

@@ -0,0 +1,30 @@
+package com.fs.app.controller;
+
+import com.fs.common.core.domain.R;
+import com.fs.course.domain.FsCourseProduct;
+import com.fs.course.service.IFsCourseProductService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@Api("拍商品订单接口")
+@RestController
+@RequestMapping(value="/app/courseProduct")
+public class CourseProductController extends AppBaseController{
+
+    @Autowired
+    private IFsCourseProductService courseProductService;
+
+
+
+    @ApiOperation("获取拍商品详情")
+    @GetMapping("/getCourseProductById")
+    public R getCourseProductById(@RequestParam("productId") Long productId) {
+        FsCourseProduct courseProduct = courseProductService.selectFsCourseProductById(productId);
+        return R.ok().put("data", courseProduct);
+    }
+}

+ 87 - 0
fs-user-app/src/main/java/com/fs/app/controller/CourseProductOrderController.java

@@ -0,0 +1,87 @@
+package com.fs.app.controller;
+
+import com.fs.app.annotation.Login;
+import com.fs.common.annotation.RepeatSubmit;
+import com.fs.common.core.domain.R;
+import com.fs.course.param.FsCourseProductOrderCreateParam;
+import com.fs.course.param.FsCourseProductOrderListUParam;
+import com.fs.course.service.IFsCourseProductOrderService;
+import com.fs.course.vo.FsCourseProductOrderListUVO;
+import com.fs.his.param.ApplyCourseProductOrderRefundParam;
+import com.fs.his.param.FsCourseProductOrderComputeParam;
+import com.fs.his.param.FsCourseProductOrderDoPayParam;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.List;
+
+@Api("拍商品订单接口")
+@RestController
+@RequestMapping(value="/app/courseProductOrder")
+public class CourseProductOrderController extends AppBaseController {
+
+    @Autowired
+    private IFsCourseProductOrderService courseProductOrderService;
+
+    @Login
+    @ApiOperation("订单列表")
+    @GetMapping("/getCourseProductOrderList")
+    public R getCourseOrderList(FsCourseProductOrderListUParam param)
+    {
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        param.setUserId(Long.parseLong(getUserId()));
+        List<FsCourseProductOrderListUVO> productOrderListUVOS = courseProductOrderService.selectFsCourseProductOrderListUVO(param);
+        PageInfo<FsCourseProductOrderListUVO> pageInfo = new PageInfo<>(productOrderListUVOS);
+        return R.ok().put("data",pageInfo);
+    }
+
+    @ApiOperation("获取拍商品订单详情")
+    @GetMapping("/getCourseProductByCourseOrderId")
+    public R getCourseProductByCourseOrderId(@RequestParam("courseOrderId") Long courseOrderId) {
+        FsCourseProductOrderListUVO productOrderListUVO = courseProductOrderService.selectCourseProductByCourseOrderId(courseOrderId);
+        return R.ok().put("data", productOrderListUVO);
+    }
+
+    @Login
+    @ApiOperation("创建订单")
+    @PostMapping("/createOrder")
+    public R createOrder(@Validated @RequestBody FsCourseProductOrderCreateParam param, HttpServletRequest request){
+        param.setUserId(Long.parseLong(getUserId()));
+        //param.setCompanyUserId(getCompanyUserId());
+        return courseProductOrderService.createOrder(param);
+    }
+
+    @Login
+    @ApiOperation("计算订单")
+    @PostMapping("/compute")
+    public R payment(HttpServletRequest request, @Validated @RequestBody FsCourseProductOrderComputeParam param)
+    {
+        param.setUserId(Long.parseLong(getUserId()));
+        return courseProductOrderService.computeOrder(param);
+    }
+
+    @Login
+    @RepeatSubmit
+    @ApiOperation("支付")
+    @PostMapping("/payment")
+    public R payment(HttpServletRequest request, @Validated @RequestBody FsCourseProductOrderDoPayParam param)
+    {
+        param.setUserId(Long.parseLong(getUserId()));
+        return courseProductOrderService.payment(param);
+    }
+
+    @Login
+    @RepeatSubmit
+    @ApiOperation("申请退款")
+    @PostMapping("/applyRefund")
+    public R applyRefund(HttpServletRequest request, @Validated @RequestBody ApplyCourseProductOrderRefundParam param)
+    {
+        return courseProductOrderService.applyRefund(param);
+    }
+}

+ 6 - 0
fs-user-app/src/main/java/com/fs/app/controller/HuifuPayController.java

@@ -1,6 +1,7 @@
 package com.fs.app.controller;
 
 import com.alibaba.fastjson.JSON;
+import com.fs.course.service.IFsCourseProductOrderService;
 import com.fs.course.service.IFsUserCourseOrderService;
 import com.fs.course.service.IFsUserVipOrderService;
 import com.fs.his.service.IFsInquiryOrderService;
@@ -31,6 +32,8 @@ public class HuifuPayController {
     private IFsUserVipOrderService vipOrderService;
     @Autowired
     private IFsIntegralOrderService integralOrderService;
+    @Autowired
+    private IFsCourseProductOrderService courseProductOrderService;
 
     org.slf4j.Logger logger= LoggerFactory.getLogger(getClass());
     @RequestMapping("/payNotifyUrl")
@@ -58,6 +61,9 @@ public class HuifuPayController {
                 case "integral":
                     integralOrderService.payConfirm("",orderId[1],huiFuResult.getHf_seq_id(),"",1);
                     break;
+                case "product":
+                    courseProductOrderService.payConfirm("",orderId[1],huiFuResult.getHf_seq_id(),"",1);
+                    break;
             }
         }
 

+ 6 - 0
fs-user-app/src/main/java/com/fs/app/controller/WxPayController.java

@@ -4,6 +4,7 @@ package com.fs.app.controller;
 import cn.hutool.json.JSONUtil;
 import com.fs.course.config.RedPacketConfig;
 import com.fs.course.domain.FsCourseRedPacketLog;
+import com.fs.course.service.IFsCourseProductOrderService;
 import com.fs.course.service.IFsCourseRedPacketLogService;
 import com.fs.his.param.WxSendRedPacketParam;
 import com.fs.common.core.controller.BaseController;
@@ -72,6 +73,9 @@ public class WxPayController {
     @Autowired
     private IFsIntegralOrderService integralOrderService;
 
+    @Autowired
+    private IFsCourseProductOrderService courseProductOrderService;
+
 
     /**
      * 微信回调
@@ -109,6 +113,8 @@ public class WxPayController {
                     case "integral":
                         integralOrderService.payConfirm("",orderId[1],tradeNo,"",1);
                         break;
+                    case "product":
+                        courseProductOrderService.payConfirm("",orderId[1],tradeNo,"",1);
                 }
                 return WxPayNotifyResponse.success("处理成功!");
             }else{

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