Переглянути джерело

Merge branch 'refs/heads/master' into master-clq-temp

caoliqin 3 тижнів тому
батько
коміт
7007b5c59a
100 змінених файлів з 2887 додано та 150 видалено
  1. 37 4
      fs-admin/src/main/java/com/fs/company/controller/CompanyConfigController.java
  2. 7 0
      fs-admin/src/main/java/com/fs/course/controller/FsCourseRedPacketLogController.java
  3. 38 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseCommentController.java
  4. 5 0
      fs-admin/src/main/java/com/fs/his/controller/FsCourseCouponController.java
  5. 24 0
      fs-admin/src/main/java/com/fs/his/controller/FsDoctorController.java
  6. 7 0
      fs-admin/src/main/java/com/fs/his/controller/FsIntegralGoodsController.java
  7. 22 0
      fs-admin/src/main/java/com/fs/his/task/Task.java
  8. 1 1
      fs-admin/src/main/java/com/fs/his/task/userIntegralTask.java
  9. 1 1
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreHealthOrderScrmController.java
  10. 17 5
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreOrderScrmController.java
  11. 56 0
      fs-admin/src/main/java/com/fs/qw/controller/CorporateWeChatSpaceController.java
  12. 9 0
      fs-admin/src/main/java/com/fs/qw/controller/QwUserController.java
  13. 1 1
      fs-admin/src/main/java/com/fs/third/controller/WeizouController.java
  14. 12 0
      fs-admin/src/main/java/com/fs/web/controller/system/SysConfigController.java
  15. 1 0
      fs-company/src/main/java/com/fs/company/controller/common/CommonController.java
  16. 37 0
      fs-company/src/main/java/com/fs/company/controller/company/SysConfigController.java
  17. 7 0
      fs-company/src/main/java/com/fs/company/controller/course/FsCourseRedPacketLogController.java
  18. 12 0
      fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactController.java
  19. 8 1
      fs-company/src/main/java/com/fs/hisStore/controller/FsStoreOrderScrmController.java
  20. 3 1
      fs-live-app/src/main/java/com/fs/live/task/Task.java
  21. 1 1
      fs-live-app/src/main/java/com/fs/live/websocket/service/WebSocketServer.java
  22. 17 5
      fs-qw-api-msg/src/main/java/com/fs/app/controller/QwMsgController.java
  23. 11 0
      fs-service/src/main/java/com/fs/common/service/ISmsService.java
  24. 150 5
      fs-service/src/main/java/com/fs/common/service/impl/SmsServiceImpl.java
  25. 15 9
      fs-service/src/main/java/com/fs/company/domain/CompanySms.java
  26. 19 0
      fs-service/src/main/java/com/fs/company/mapper/CompanySmsMapper.java
  27. 49 8
      fs-service/src/main/java/com/fs/company/service/ICompanySmsService.java
  28. 164 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanySmsServiceImpl.java
  29. 0 0
      fs-service/src/main/java/com/fs/company/service/impl/GeneralCustomerEntryServiceImpl.java
  30. 3 0
      fs-service/src/main/java/com/fs/config/ai/AiHostProper.java
  31. 1 0
      fs-service/src/main/java/com/fs/course/config/CourseConfig.java
  32. 1 1
      fs-service/src/main/java/com/fs/course/domain/FsCourseAnswerReward.java
  33. 8 0
      fs-service/src/main/java/com/fs/course/domain/FsCoursePlaySourceConfig.java
  34. 3 0
      fs-service/src/main/java/com/fs/course/domain/FsUserCourseComment.java
  35. 5 0
      fs-service/src/main/java/com/fs/course/domain/FsUserCourseVideo.java
  36. 2 2
      fs-service/src/main/java/com/fs/course/domain/LuckyBagCollectRecord.java
  37. 1 1
      fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java
  38. 16 7
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseCommentMapper.java
  39. 1 1
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseStudyMapper.java
  40. 4 1
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseVideoMapper.java
  41. 3 0
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseVideoRedPackageMapper.java
  42. 8 0
      fs-service/src/main/java/com/fs/course/param/FsCoursePlaySourceConfigCreateParam.java
  43. 8 0
      fs-service/src/main/java/com/fs/course/param/FsCoursePlaySourceConfigEditParam.java
  44. 6 0
      fs-service/src/main/java/com/fs/course/param/FsUserCourseCommentParam.java
  45. 20 2
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseCommentServiceImpl.java
  46. 2 2
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseServiceImpl.java
  47. 4 1
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  48. 9 0
      fs-service/src/main/java/com/fs/course/vo/FsCoursePlaySourceConfigVO.java
  49. 3 3
      fs-service/src/main/java/com/fs/course/vo/FsCourseWatchLogListVO.java
  50. 4 0
      fs-service/src/main/java/com/fs/course/vo/FsUserCourseCommentListUVO.java
  51. 4 0
      fs-service/src/main/java/com/fs/course/vo/FsUserCourseCommentListVO.java
  52. 5 0
      fs-service/src/main/java/com/fs/course/vo/FsUserCourseVideoQVO.java
  53. 1 1
      fs-service/src/main/java/com/fs/crm/utils/CrmCustomerAiTagUtil.java
  54. 90 0
      fs-service/src/main/java/com/fs/fastgptApi/param/ChatImgParam.java
  55. 2 0
      fs-service/src/main/java/com/fs/fastgptApi/service/ChatService.java
  56. 90 0
      fs-service/src/main/java/com/fs/fastgptApi/service/Impl/ChatServiceImpl.java
  57. 5 0
      fs-service/src/main/java/com/fs/his/domain/FsCourseCouponUser.java
  58. 17 7
      fs-service/src/main/java/com/fs/his/domain/FsIntegralCount.java
  59. 4 0
      fs-service/src/main/java/com/fs/his/mapper/FsCourseCouponMapper.java
  60. 5 0
      fs-service/src/main/java/com/fs/his/mapper/FsCourseCouponUserMapper.java
  61. 26 0
      fs-service/src/main/java/com/fs/his/mapper/FsDoctorMapper.java
  62. 12 0
      fs-service/src/main/java/com/fs/his/mapper/FsIntegralGoodsMapper.java
  63. 3 0
      fs-service/src/main/java/com/fs/his/mapper/FsIntegralOrderMapper.java
  64. 5 3
      fs-service/src/main/java/com/fs/his/mapper/FsUserIntegralLogsMapper.java
  65. 17 0
      fs-service/src/main/java/com/fs/his/param/CourseFinishRewardParam.java
  66. 50 0
      fs-service/src/main/java/com/fs/his/param/DoctorPrescriptionImgLogParam.java
  67. 75 0
      fs-service/src/main/java/com/fs/his/param/DoctorPrescriptionParam.java
  68. 19 0
      fs-service/src/main/java/com/fs/his/param/FsCourseCouponUserUParam.java
  69. 22 0
      fs-service/src/main/java/com/fs/his/param/FsIntegralGoodsParam.java
  70. 11 0
      fs-service/src/main/java/com/fs/his/service/IFsCourseCouponService.java
  71. 3 0
      fs-service/src/main/java/com/fs/his/service/IFsCourseCouponUserService.java
  72. 27 3
      fs-service/src/main/java/com/fs/his/service/IFsDoctorService.java
  73. 9 0
      fs-service/src/main/java/com/fs/his/service/IFsIntegralGoodsService.java
  74. 4 0
      fs-service/src/main/java/com/fs/his/service/IFsStoreOrderService.java
  75. 184 0
      fs-service/src/main/java/com/fs/his/service/impl/FsCourseCouponServiceImpl.java
  76. 30 0
      fs-service/src/main/java/com/fs/his/service/impl/FsCourseCouponUserServiceImpl.java
  77. 684 3
      fs-service/src/main/java/com/fs/his/service/impl/FsDoctorServiceImpl.java
  78. 22 0
      fs-service/src/main/java/com/fs/his/service/impl/FsIntegralGoodsServiceImpl.java
  79. 428 43
      fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java
  80. 2 2
      fs-service/src/main/java/com/fs/his/service/impl/FsUserInvitedServiceImpl.java
  81. 15 0
      fs-service/src/main/java/com/fs/his/vo/CourseFinishRewardVO.java
  82. 3 0
      fs-service/src/main/java/com/fs/his/vo/FsIntegralGoodsVo.java
  83. 1 1
      fs-service/src/main/java/com/fs/his/vo/GetFsIntegralCartDetailsVo.java
  84. 1 1
      fs-service/src/main/java/com/fs/his/vo/GetFsIntegralCartListVo.java
  85. 1 0
      fs-service/src/main/java/com/fs/his/vo/OptionsVO.java
  86. 7 0
      fs-service/src/main/java/com/fs/hisStore/domain/FsStoreAfterSalesScrm.java
  87. 8 0
      fs-service/src/main/java/com/fs/hisStore/domain/FsStoreOrderScrm.java
  88. 4 0
      fs-service/src/main/java/com/fs/hisStore/domain/FsStoreProductScrm.java
  89. 2 0
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreAfterSalesScrmMapper.java
  90. 3 3
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderItemScrmMapper.java
  91. 31 2
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderScrmMapper.java
  92. 2 0
      fs-service/src/main/java/com/fs/hisStore/param/FsMyStoreOrderQueryParam.java
  93. 1 0
      fs-service/src/main/java/com/fs/hisStore/param/FsStoreAfterSalesQueryParam.java
  94. 3 1
      fs-service/src/main/java/com/fs/hisStore/param/FsStoreOrderCreateParam.java
  95. 2 0
      fs-service/src/main/java/com/fs/hisStore/service/IFsStoreOrderScrmService.java
  96. 1 1
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreAfterSalesScrmServiceImpl.java
  97. 68 15
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java
  98. 27 1
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreProductScrmServiceImpl.java
  99. 4 0
      fs-service/src/main/java/com/fs/hisStore/vo/FsMyStoreOrderListQueryVO.java
  100. 4 0
      fs-service/src/main/java/com/fs/hisStore/vo/FsStoreAfterSalesQueryVO.java

+ 37 - 4
fs-admin/src/main/java/com/fs/company/controller/CompanyConfigController.java

@@ -3,14 +3,17 @@ package com.fs.company.controller;
 
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.utils.ServletUtils;
+import com.fs.company.domain.CompanyConfig;
 import com.fs.company.service.ICompanyConfigService;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.service.ISysConfigService;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
 
 /**
  * 系统配置
@@ -44,5 +47,35 @@ public class CompanyConfigController extends BaseController
     }
 
 
+    /**
+    * 修改的是 销售端的配置
+    */
+    @PostMapping(value = "/editCompanyConfig")
+    public R edit(@Validated @RequestBody CompanyConfig companyConfig)
+    {
+        companyConfigService.updateCompanyConfig(companyConfig);
+        return R.ok("操作成功");
+    }
+
+
+    /**
+     * 根据参数键名查询参数值
+     */
+    @GetMapping(value = "/getCompanyConfigKey/{configKey}/{companyId}")
+    public R getConfigKey(@PathVariable String configKey,@PathVariable Long companyId)
+    {
+        CompanyConfig config=companyConfigService.selectCompanyConfigByKey(companyId,configKey);
+        if(config==null){
+            config=new CompanyConfig();
+            config.setCompanyId(companyId);
+            config.setConfigKey(configKey);
+            config.setConfigType("N");
+            companyConfigService.insertCompanyConfig(config);
+
+        }
+        return R.ok().put("data",config);
+
+    }
+
 
 }

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

@@ -211,6 +211,13 @@ public class FsCourseRedPacketLogController extends BaseController
         return R.ok().put("list", optionsVOS);
     }
 
+    @GetMapping(value = "/videoListByWatch/{id}")
+    public R videoListByWatch(@PathVariable("id") Long id)
+    {
+        List<OptionsVO> optionsVOS = fsUserCourseVideoMapper.selectFsUserCourseVodeAllListByWatch(id);
+        return R.ok().put("list", optionsVOS);
+    }
+
 
     /**
     * 红包消耗统计

+ 38 - 0
fs-admin/src/main/java/com/fs/course/controller/FsUserCourseCommentController.java

@@ -270,6 +270,44 @@ public class FsUserCourseCommentController extends BaseController
         }
     }
 
+    /**
+     * 修改用户留言可见范围(0-自己可见,1-全部人可见)
+     */
+    @PreAuthorize("@ss.hasPermi('course:userCourseComment:edit')")
+    @Log(title = "用户留言可见范围", businessType = BusinessType.UPDATE)
+    @PutMapping("/updateVisibleAll")
+    public AjaxResult updateVisibleAll(@RequestBody FsUserCourseComment param) {
+        if (param.getCommentId() == null || param.getVisibleAll() == null) {
+            return AjaxResult.error("参数不完整");
+        }
+        if (param.getVisibleAll() != 0 && param.getVisibleAll() != 1) {
+            return AjaxResult.error("可见范围参数无效");
+        }
+        FsUserCourseComment update = new FsUserCourseComment();
+        update.setCommentId(param.getCommentId());
+        update.setVisibleAll(param.getVisibleAll());
+        return toAjax(fsUserCourseCommentService.updateFsUserCourseComment(update));
+    }
+
+    /**
+     * 查询指定课程小节下的用户留言(排除精选留言 type=3,支持分页)
+     */
+    @PreAuthorize("@ss.hasPermi('course:userCourseComment:list')")
+    @GetMapping("/sectionUserComments")
+    public TableDataInfo sectionUserComments(
+            @RequestParam Long courseId,
+            @RequestParam Long videoId,
+            @RequestParam(value = "nickName", required = false) String nickName) {
+        startPage();
+        FsUserCourseCommentParam param = new FsUserCourseCommentParam();
+        param.setCourseId(courseId);
+        param.setVideoId(videoId);
+        param.setNickName(nickName);
+        param.setExcludeFeatured(true);
+        List<FsUserCourseCommentListVO> list = fsUserCourseCommentService.selectFsUserCourseCommentListVO(param);
+        return getDataTable(list);
+    }
+
     /**
      * 查询精选留言历史列表(type=3)
      */

+ 5 - 0
fs-admin/src/main/java/com/fs/his/controller/FsCourseCouponController.java

@@ -108,4 +108,9 @@ public class FsCourseCouponController extends BaseController
     {
         return toAjax(fsCourseCouponService.deleteFsCourseCouponByIds(ids));
     }
+
+    @GetMapping("/options")
+    public AjaxResult selectFsCourseCouponOptions(){
+        return AjaxResult.success(fsCourseCouponService.selectFsCourseCouponOptions());
+    }
 }

+ 24 - 0
fs-admin/src/main/java/com/fs/his/controller/FsDoctorController.java

@@ -63,6 +63,30 @@ public class FsDoctorController extends BaseController
         return getDataTable(list);
     }
 
+    /**
+     * 处方图片列表审核
+     * @param param
+     * @return
+     */
+    @PostMapping("/prescriptionList")
+    public TableDataInfo prescriptionList(@RequestBody DoctorPrescriptionImgLogParam param)
+    {
+        startPage();
+        List<DoctorPrescriptionImgLogParam> doctorList = fsDoctorService.selectPrescriptionLogList(param);
+        return getDataTable(doctorList);
+    }
+
+    /**
+     * 处方图片审核
+     * @param param
+     * @return
+     */
+    @PostMapping("/auditPrescription")
+    public AjaxResult auditPrescription(@RequestBody DoctorPrescriptionParam param)
+    {
+        return toAjax(fsDoctorService.updateFsDoctorPrescription(param));
+    }
+
     /**
      * 导出医生管理列表
      */

+ 7 - 0
fs-admin/src/main/java/com/fs/his/controller/FsIntegralGoodsController.java

@@ -8,6 +8,7 @@ import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.his.domain.FsIntegralGoods;
+import com.fs.his.param.FsIntegralGoodsParam;
 import com.fs.his.service.IFsIntegralGoodsService;
 import com.fs.his.utils.RedisCacheUtil;
 import com.fs.his.vo.FsIntegralGoodsChooseVO;
@@ -148,4 +149,10 @@ public class FsIntegralGoodsController extends BaseController
         List<FsIntegralGoodsChooseVO> list = fsIntegralGoodsService.getChooseIntegralGoodsListByMap(params);
         return R.ok().put("data", new PageInfo<>(list));
     }
+
+    @PostMapping("/batchUpdateIntegralGoods")
+    public R batchUpdateIntegralGoods(@RequestBody FsIntegralGoodsParam integralGoodsParam) {
+        fsIntegralGoodsService.batchUpdateIntegralGoods(integralGoodsParam);
+        return R.ok();
+    }
 }

+ 22 - 0
fs-admin/src/main/java/com/fs/his/task/Task.java

@@ -53,6 +53,7 @@ import com.fs.his.utils.ConfigUtil;
 import com.fs.his.vo.FsSubOrderResultVO;
 import com.fs.hisStore.domain.FsStoreOrderScrm;
 import com.fs.hisStore.domain.FsStorePaymentScrm;
+import com.fs.hisStore.mapper.FsStoreOrderScrmMapper;
 import com.fs.hisStore.mapper.FsStorePaymentScrmMapper;
 import com.fs.hisStore.service.IFsStoreOrderScrmService;
 import com.fs.hisStore.service.IFsStorePaymentScrmService;
@@ -239,6 +240,8 @@ public class Task {
 
     @Autowired
     private FsUserCompanyUserMapper fsUserCompanyUserMapper;
+    @Autowired
+    private FsStoreOrderScrmMapper fsStoreOrderScrmMapper;
 
     /**
      * 定时任务,处理ai禁止回复之后的消息
@@ -924,7 +927,12 @@ public class Task {
 
     public void CreateWeizouErpPush() {
         List<Long> omsList = fsStoreOrderMapper.selectFsStoreOrderNoCreateOms();
+        List<Long> integrals = fsIntegralOrderMapper.selectFsStoreOrderNoCreateOms();
+        List<Long> scrms = fsStoreOrderScrmMapper.selectFsStoreOrderNoCreateOms();
         logger.info("推送订单id====>{}", omsList);
+        logger.info("推送积分订单id====>{}", integrals);
+        logger.info("推送SCRM订单id====>{}", scrms);
+
         for (Long l : omsList) {
             try {
                 fsStoreOrderService.weizouPush(l);
@@ -932,6 +940,20 @@ public class Task {
                 logger.error("推送订单异常:", e);
             }
         }
+        for (Long l : integrals) {
+            try {
+                fsStoreOrderService.weizouPushIntergral(l);
+            } catch (Exception e) {
+                logger.error("推送积分订单异常:", e);
+            }
+        }
+        for (Long l : scrms) {
+            try {
+                fsStoreOrderService.weizouPushScrm(l);
+            } catch (Exception e) {
+                logger.error("推送SCRM订单异常:", e);
+            }
+        }
     }
     public void CreateOmsAndHis() {
         List<Long> omsList = fsStoreOrderMapper.selectFsStoreOrderNoCreateOms();

+ 1 - 1
fs-admin/src/main/java/com/fs/his/task/userIntegralTask.java

@@ -22,7 +22,7 @@ public class userIntegralTask {
     @Autowired
     private IFsIntegralCountService integralCountService;
 
-    public void UserIntegralCount(){
+    public void userIntegralCount(){
         log.info("=====用户积分每日消耗统计开始=====");
         try {
             List<FsIntegralCount> list = integralLogsService.selectYesterdayIntegralGroupByLogType();

+ 1 - 1
fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreHealthOrderScrmController.java

@@ -99,7 +99,7 @@ public class FsStoreHealthOrderScrmController extends BaseController {
         if(!StringUtils.isEmpty(param.getDeliverySendTimeRange())){
             param.setDeliverySendTimeList(param.getDeliverySendTimeRange().split("--"));
         }
-        param.setIsHealth("1");
+//        param.setIsHealth("1");
         List<FsStoreOrderVO> list = fsStoreOrderService.selectFsStoreOrderListVO(param);
         //金牛需求 区别其他项目 status = 6 (金牛代服管家) ,其他项目请避免使用订单状态status = 6
         TableDataInfo dataTable = getDataTable(list);

+ 17 - 5
fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreOrderScrmController.java

@@ -681,14 +681,19 @@ public class FsStoreOrderScrmController extends BaseController {
             user.setPhone(ParseUtils.parsePhone(user.getPhone()));
         }
 
+
         if (order.getCompanyUserId() != null) {
             CompanyUser companyUser = companyUserService.selectCompanyUserByUserId(order.getCompanyUserId());
-            Company company = companyService.selectCompanyById(companyUser.getCompanyId());
-            order.setCompanyUserName(companyUser.getNickName());
-            order.setCompanyName(company.getCompanyName());
+            if (companyUser != null) {
+                Company company = companyService.selectCompanyById(companyUser.getCompanyId());
+                order.setCompanyUserName(companyUser.getNickName());
+                order.setCompanyName(company.getCompanyName());
+            }
         } else if (order.getCompanyId() != null) {
             Company company = companyService.selectCompanyById(order.getCompanyId());
-            order.setCompanyName(company.getCompanyName());
+            if (company != null) {
+                order.setCompanyName(company.getCompanyName());
+            }
         }
 
         if (order.getOrderType() != null && order.getOrderType() == 3) {
@@ -762,10 +767,17 @@ public class FsStoreOrderScrmController extends BaseController {
                 if("恒春来".equals(cloudHostProper.getCompanyName())
                         && ObjectUtil.isNotEmpty(lastFourNumber = order.getVirtualPhone())){
                     if (lastFourNumber.contains("-")) {
-                        lastFourNumber = lastFourNumber.length() >= 4 ? lastFourNumber.substring(lastFourNumber.length() - 4) : lastFourNumber;
+                        String beforeDash = lastFourNumber.split("-")[0];
+                        lastFourNumber = beforeDash.length() >= 4 ? beforeDash.substring(beforeDash.length() - 4) : beforeDash;
                     }else{
                         lastFourNumber = StrUtil.sub(lastFourNumber, lastFourNumber.length(), -4);
                     }
+                    expressInfoDTO=expressService.getExpressInfo(order.getOrderCode(),order.getDeliverySn(),order.getDeliveryId(),lastFourNumber);
+                    if(expressInfoDTO!=null && !expressInfoDTO.isSuccess()){
+                        lastFourNumber = StrUtil.sub(order.getVirtualPhone(), order.getVirtualPhone().length(), -4);
+                        expressInfoDTO=expressService.getExpressInfo(order.getOrderCode(),order.getDeliverySn(),order.getDeliveryId(),lastFourNumber);
+                    }
+                    return R.ok().put("data",expressInfoDTO);
                 }
                 // 原逻辑
                 else if ((lastFourNumber = order.getUserPhone()).length() == 11) {

+ 56 - 0
fs-admin/src/main/java/com/fs/qw/controller/CorporateWeChatSpaceController.java

@@ -0,0 +1,56 @@
+package com.fs.qw.controller;
+
+import com.alibaba.fastjson.JSONObject;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.exception.CustomException;
+import com.fs.qw.service.ICorporateWeChatSpaceService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 企业微信专区-统一前端 API 接口
+ * */
+@RestController
+@RequestMapping("/weChatSpace")
+@RequiredArgsConstructor
+public class CorporateWeChatSpaceController extends BaseController {
+
+    private final ICorporateWeChatSpaceService weChatSpaceService;
+
+    // 企业微信会话专区中转接口
+    @GetMapping("/conversations")
+    public JSONObject getConversations(
+            @RequestParam(defaultValue = "0") long seq,
+            @RequestParam(defaultValue = "100") long limit,
+            @RequestParam(defaultValue = "0") long proxy,
+            @RequestParam(defaultValue = "30") long timeout,
+            @RequestParam(required = false) String customerId,
+            @RequestParam(required = false) String staffUserId) throws Exception {
+        if (customerId == null|| customerId.isEmpty()) {
+            throw new CustomException("客户id不能为空");
+        }else if (staffUserId == null|| staffUserId.isEmpty()) {
+            throw new CustomException("员工id不能为空");
+        }
+        return weChatSpaceService.fetchConversations(seq, limit, proxy, timeout, customerId,staffUserId);
+    }
+
+
+    // agentConfig 签名
+    @GetMapping("/getAgentConfigSignature")
+    public JSONObject getAgentConfigSignature(@RequestParam("url") String url) {
+        return weChatSpaceService.getAgentConfigSignature(url);
+    }
+
+    // Web 登录
+    @PostMapping("/login")
+    public JSONObject login(@RequestBody JSONObject param) {
+        return weChatSpaceService.login(param.getString("code"));
+    }
+
+    //获取企业微信专区会话配置
+    @GetMapping("/getQwSessionConfig")
+    public AjaxResult getQwSessionConfig() {
+        return AjaxResult.success(weChatSpaceService.getQwSessionConfig());
+    }
+}

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

@@ -157,6 +157,15 @@ public class QwUserController extends BaseController {
         return getDataTable(list);
     }
 
+    /**
+     * 查询所有企微员工列表
+     * */
+    @PreAuthorize("@ss.hasPermi('qw:user:list')")
+    @GetMapping("/listAllQwUserList")
+    public AjaxResult listAllQwUserList(QwUser qwUser) {
+        List<QwUser> list = qwUserService.selectNotDelQwUserList(qwUser);
+        return AjaxResult.success(list);
+    }
 
     /**
      * 导出企微员工列表

+ 1 - 1
fs-admin/src/main/java/com/fs/third/controller/WeizouController.java

@@ -33,7 +33,7 @@ public class WeizouController extends BaseController {
         if (map.get("orderCode") == null) {
             return error("参数异常请核验参数");
         }
-        fsStoreOrder.setOrderId(Long.valueOf((String) map.get("orderCode")));
+        fsStoreOrder.setOrderCode((String) map.get("orderCode"));
         fsStoreOrder.setOperator("-1");
 // 校验物流单号
         if (map.get("deliverySn") == null) {

+ 12 - 0
fs-admin/src/main/java/com/fs/web/controller/system/SysConfigController.java

@@ -3,9 +3,11 @@ package com.fs.web.controller.system;
 import java.util.List;
 
 import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.json.JSONUtil;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.SecurityUtils;
+import com.fs.course.config.CourseConfig;
 import com.fs.sop.service.impl.QwSopServiceImpl;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -136,6 +138,16 @@ public class SysConfigController extends BaseController {
         return AjaxResult.success(config);
     }
 
+    /**
+    * 获取奖励类型配置
+    */
+    @GetMapping(value = "/getCourseConfigByRewardType")
+    public R getCourseConfigByRewardType() {
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        return R.ok().put("rewardType",config.getRewardType());
+    }
+
     @PostMapping(value = "/updateConfigByKey")
     @Log(title = "更改参数", businessType = BusinessType.UPDATE)
     @RepeatSubmit

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

@@ -16,6 +16,7 @@ import com.fs.common.utils.file.FileUtils;
 import com.fs.company.service.ICompanyService;
 import com.fs.company.utils.AudioUtils;
 import com.fs.company.vo.WangUploadVO;
+import com.fs.course.config.CourseConfig;
 import com.fs.course.service.ITencentCloudCosService;
 import com.fs.framework.config.ServerConfig;
 import com.fs.framework.security.LoginUser;

+ 37 - 0
fs-company/src/main/java/com/fs/company/controller/company/SysConfigController.java

@@ -0,0 +1,37 @@
+package com.fs.company.controller.company;
+
+import cn.hutool.json.JSONUtil;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.redis.RedisCache;
+import com.fs.course.config.CourseConfig;
+import com.fs.system.service.ISysConfigService;
+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.RestController;
+
+/**
+ * 参数配置 信息操作处理
+ */
+@RestController
+@RequestMapping("/system/config")
+public class SysConfigController extends BaseController {
+    @Autowired
+    private ISysConfigService configService;
+    @Autowired
+    public RedisCache redisCache;
+
+
+    /**
+    * 获取奖励类型配置
+    */
+    @GetMapping(value = "/getCourseConfigByRewardType")
+    public R getCourseConfigByRewardType() {
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        return R.ok().put("rewardType",config.getRewardType());
+    }
+
+
+}

+ 7 - 0
fs-company/src/main/java/com/fs/company/controller/course/FsCourseRedPacketLogController.java

@@ -267,4 +267,11 @@ public class FsCourseRedPacketLogController extends BaseController
         List<OptionsVO> optionsVOS = fsUserCourseVideoMapper.selectFsUserCourseVodeAllList(id);
         return R.ok().put("list", optionsVOS);
     }
+
+    @GetMapping(value = "/videoListByWatch/{id}")
+    public R videoListByWatch(@PathVariable("id") Long id)
+    {
+        List<OptionsVO> optionsVOS = fsUserCourseVideoMapper.selectFsUserCourseVodeAllListByWatch(id);
+        return R.ok().put("list", optionsVOS);
+    }
 }

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

@@ -35,6 +35,7 @@ import com.fs.qw.param.*;
 import com.fs.qw.service.*;
 import com.fs.qw.vo.QwExternalContactVO;
 import com.fs.qw.vo.QwFsUserVO;
+import com.fs.qw.vo.QwRepeatRecordListVO;
 import com.fs.qw.vo.QwUserDelLossLogVO;
 import com.fs.voice.utils.StringUtil;
 import com.github.pagehelper.PageHelper;
@@ -945,6 +946,7 @@ public class QwExternalContactController extends BaseController
     public R getRepeat(RepeatParam param){
         return  qwExternalContactService.getRepeat(param);
     }
+
     /**
      * 重粉看课记录查询
      */
@@ -957,4 +959,14 @@ public class QwExternalContactController extends BaseController
         return getDataTable(list);
     }
 
+    /**
+     * 同主体下外部联系人全部销售记录(含当前)
+     */
+    @GetMapping("/getRepeatRecordList")
+    public TableDataInfo getRepeatRecordList(RepeatRecordListParam param) {
+        startPage();
+        List<QwRepeatRecordListVO> list = qwExternalContactService.selectRepeatRecordList(param);
+        return getDataTable(list);
+    }
+
 }

+ 8 - 1
fs-company/src/main/java/com/fs/hisStore/controller/FsStoreOrderScrmController.java

@@ -435,10 +435,17 @@ public class FsStoreOrderScrmController extends BaseController
                 if("恒春来".equals(cloudHostProper.getCompanyName())
                         && ObjectUtil.isNotEmpty(lastFourNumber = order.getVirtualPhone())){
                     if (lastFourNumber.contains("-")) {
-                        lastFourNumber = lastFourNumber.length() >= 4 ? lastFourNumber.substring(lastFourNumber.length() - 4) : lastFourNumber;
+                        String beforeDash = lastFourNumber.split("-")[0];
+                        lastFourNumber = beforeDash.length() >= 4 ? beforeDash.substring(beforeDash.length() - 4) : beforeDash;
                     }else{
                         lastFourNumber = StrUtil.sub(lastFourNumber, lastFourNumber.length(), -4);
                     }
+                    expressInfoDTO=expressService.getExpressInfo(order.getOrderCode(),order.getDeliverySn(),order.getDeliveryId(),lastFourNumber);
+                    if(expressInfoDTO!=null && !expressInfoDTO.isSuccess()){
+                        lastFourNumber = StrUtil.sub(order.getVirtualPhone(), order.getVirtualPhone().length(), -4);
+                        expressInfoDTO=expressService.getExpressInfo(order.getOrderCode(),order.getDeliverySn(),order.getDeliveryId(),lastFourNumber);
+                    }
+                    return R.ok().put("data",expressInfoDTO);
                 }
                 // 原逻辑
                 else if ((lastFourNumber = order.getUserPhone()).length() == 11) {

+ 3 - 1
fs-live-app/src/main/java/com/fs/live/task/Task.java

@@ -351,6 +351,8 @@ public class Task {
                     lotteryVo.setPrizeLevel(liveLotteryProductListVo.getPrizeLevel());
                     lotteryVo.setProductName(liveLotteryProductListVo.getProductName());
                     lotteryVo.setProductId(liveLotteryProductListVo.getProductId());
+                    //设置中奖记录id
+                    lotteryVo.setRecordId(record.getId());
                     lotteryVos.add(lotteryVo);
                 }
             }
@@ -431,7 +433,7 @@ public class Task {
                 List<Long> userIds = onlineUser.stream().map(LiveWatchUser::getUserId).collect(Collectors.toList());
                 // 4.保存用户领取记录
                 saveUserRewardRecord(openRewardLive, userIds,config.getScoreAmount());
-                // 5.更新用户积分(芳华币
+                // 5.更新用户积分(积分
                 fsUserService.increaseIntegral(userIds,config.getScoreAmount());
                 // 6.发送websocket事件消息 通知用户自动领取成功
                 userIds.forEach(userId -> webSocketServer.sendIntegralMessage(openRewardLive.getLiveId(),userId,config.getScoreAmount()));

+ 1 - 1
fs-live-app/src/main/java/com/fs/live/websocket/service/WebSocketServer.java

@@ -869,7 +869,7 @@ public class WebSocketServer {
         sendMsgVo.setUserId(userId);
         sendMsgVo.setUserType(0L);
         sendMsgVo.setCmd("Integral");
-        sendMsgVo.setMsg("恭喜你成功获得观看奖励:" + scoreAmount + "芳华币");
+        sendMsgVo.setMsg("恭喜你成功获得观看奖励:" + scoreAmount + "积分");
         sendMsgVo.setData(String.valueOf(scoreAmount));
 
         if(Objects.isNull( session)) return;

+ 17 - 5
fs-qw-api-msg/src/main/java/com/fs/app/controller/QwMsgController.java

@@ -289,7 +289,10 @@ public class QwMsgController {
                 log.info("id:{}, 需要二次验证:"+wxWorkMsgResp.getJson(), id);
 
                 redisCache.setCacheObject("qrCodeUid:"+wxWorkMsgResp.getUuid(),100012,10, TimeUnit.MINUTES);
-
+                QwUser qwUser1 = qwUserMapper.selectQwUserById(id);
+                if(qwUser1.getUid().equals(wxWorkMsgResp.getUuid())){
+                    qwUserService.atMsg(qwUser1, "需要二次验证(在销售后台,企微员工页面点击二次验证)");
+                }
                 break;
             case 100005:
 
@@ -341,14 +344,23 @@ public class QwMsgController {
                         WxwSpeechToTextEntityDTO ste = new WxwSpeechToTextEntityDTO();
                         ste.setMsgid(wxWorkMessageDTO.getMsg_id());
                         ste.setUuid(wxWorkMsgResp.getUuid());
+
                         WxWorkResponseDTO<WxwSpeechToTextEntityRespDTO> dto = wxWorkService.SpeechToTextEntity(ste, serverId);
                         System.out.println(dto);
-                        if(dto.getErrcode() != 0 || Objects.isNull(dto.getData()) || StringUtils.isBlank(dto.getData().getText())){
+
+                        int maxRetries = 3;
+                        int retryCount = 0;
+
+                        while((dto.getErrcode() != 0 || Objects.isNull(dto.getData()) || StringUtils.isBlank(dto.getData().getText()))
+                                && retryCount < maxRetries) {
                             try {
-                                TimeUnit.SECONDS.sleep(2); // 阻塞2秒
+                                TimeUnit.SECONDS.sleep(1);
+                                retryCount++;
+                                log.info("id:{}, 语音转换第{}次重试", id, retryCount);
                             } catch (InterruptedException e) {
-                                Thread.currentThread().interrupt(); // 处理中断异常
-                                log.info("id:{}, 第一次语音转换失败", id);
+                                Thread.currentThread().interrupt();
+                                log.info("id:{}, 语音转换等待被中断", id);
+                                break;
                             }
                             dto = wxWorkService.SpeechToTextEntity(ste, serverId);
                         }

+ 11 - 0
fs-service/src/main/java/com/fs/common/service/ISmsService.java

@@ -1,9 +1,12 @@
 package com.fs.common.service;
 
 import com.fs.common.core.domain.R;
+import com.fs.company.domain.CompanySmsTemp;
 import com.fs.crm.param.SmsSendBatchParam;
 import com.fs.crm.param.SmsSendParam;
 import com.fs.crm.param.SmsSendUserParam;
+import com.fs.qw.bo.SendMsgLogBo;
+import com.fs.qw.enums.SmsLogType;
 
 
 public interface ISmsService
@@ -26,4 +29,12 @@ public interface ISmsService
 
     R sendUrl(String phone, String content, String code,Long uuid,Integer smsIndex,String deleteKey,Long companyId,Long companyUserId);
 
+    /**
+     *  根据号码、内容、模板发送短信(简洁版)
+     *  @param phone 号码
+     *  @param content 内容
+     *  @param temp 模板
+     * */
+    R simpleSmsSend(String phone, String content, CompanySmsTemp temp, SmsLogType logType, SendMsgLogBo sendMsgLogBo);
+
 }

+ 150 - 5
fs-service/src/main/java/com/fs/common/service/impl/SmsServiceImpl.java

@@ -9,6 +9,7 @@ import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
 
 import com.fs.common.service.ISmsService;
+import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.vo.SmsNotifyVO;
 import com.fs.common.vo.SmsSendItemVO;
@@ -23,6 +24,7 @@ import com.fs.company.service.ICompanySmsTempService;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.company.service.impl.CompanyVoiceRoboticCallBlacklistServiceImpl;
 import com.fs.company.vo.CompanyVoiceRoboticCallBlacklistCheckVO;
+import com.fs.course.config.CourseConfig;
 import com.fs.crm.domain.CrmCustomer;
 import com.fs.crm.param.SmsSendBatchParam;
 import com.fs.crm.param.SmsSendParam;
@@ -34,15 +36,22 @@ import com.fs.his.domain.FsStoreOrder;
 import com.fs.his.mapper.FsPackageOrderMapper;
 import com.fs.his.mapper.FsStoreOrderMapper;
 import com.fs.his.vo.FsPackageOrderVO;
+import com.fs.qw.bo.SendMsgLogBo;
+import com.fs.qw.domain.QwAcquisitionLinkInfo;
 import com.fs.qw.domain.QwSopSmsLogs;
+import com.fs.qw.enums.SmsLogType;
+import com.fs.qw.mapper.QwAcquisitionLinkInfoMapper;
 import com.fs.qw.mapper.QwSopSmsLogsMapper;
 import com.fs.qw.service.IQwSopSmsLogsService;
+import com.fs.qw.strategy.SmsLogStrategyManager;
 import com.fs.sms.domain.SendSmsReturn;
 import com.fs.sms.service.impl.SmsTServiceImpl;
 import com.fs.sop.domain.QwSopLogs;
 import com.fs.sop.mapper.QwSopLogsMapper;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.mapper.SysConfigMapper;
+import com.fs.system.service.ISysConfigService;
+import com.fs.utils.ShortCodeGeneratorUtils;
 import com.google.gson.Gson;
 import lombok.Synchronized;
 import lombok.extern.slf4j.Slf4j;
@@ -61,6 +70,8 @@ import com.fs.company.service.ICompanySmsCommonLogsService;
 import org.redisson.api.RLock;
 import org.redisson.api.RedissonClient;
 
+import static com.fs.his.utils.PhoneUtil.encryptPhone;
+
 @Service
 @Slf4j
 public class SmsServiceImpl implements ISmsService
@@ -109,6 +120,20 @@ public class SmsServiceImpl implements ISmsService
     @Autowired
     private RedissonClient redissonClient;
 
+    //获客链接短信模板code
+    private static final String  SMS_LINK_TEMPLATE_CODE = "获客链接短信模板";
+
+    @Autowired
+    private QwAcquisitionLinkInfoMapper qwAcquisitionLinkInfoMapper;
+
+    @Autowired
+    private SmsLogStrategyManager smsLogStrategyManager;
+
+    @Autowired
+    private ISysConfigService configService;
+
+    private static final String  LINK_SUFFIX = "?customer_channel=up:";
+
     @Override
     public R sendTSms(String mobile, String code) {
 //        try{
@@ -785,7 +810,88 @@ public class SmsServiceImpl implements ISmsService
         return R.ok();
     }
 
+    /**
+     * 发送简单短信
+     * @param phone 接收方手机号
+     * @param content 短信内容
+     * @param temp 短信模板
+     * @param logType 日志记录类型,用于区分调用方
+     * @param sendMsgLogBo 特定业务的上下文对象,如qwAcquisitionId或externalContactId
+     * @return R 响应结果
+     */
+    @Override
+    public R simpleSmsSend(String phone, String content, CompanySmsTemp temp, SmsLogType logType, SendMsgLogBo sendMsgLogBo) {
+        String urls = null;
+        R response; // 存储最终响应
+        Integer number = calculateSmsCount(content);
+        SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.sms");
+        FsSmsConfig sms = JSON.parseObject(sysConfig.getConfigValue(), FsSmsConfig.class);
+
+        try {
+            urls = sms.getRfUrl2() + "sms?action=send&account=" + sms.getRfAccount2() + "&password=" + sms.getRfPassword2() + "&mobile=" + phone + "&content=" + URLEncoder.encode(content, "UTF-8") + "&extno=" + sms.getRfCode2() + "&rt=json";
+        } catch (UnsupportedEncodingException e) {
+            log.error("{}发送失败", phone, e);
+            response = R.error("短信发送失败:" + e.getMessage());
+            // 发送失败也要记录特定业务日志
+            smsLogStrategyManager.executeLogStrategy(logType, response, content, phone, temp.getTempId(), sms.getType(), number, sendMsgLogBo);
+            return response;
+        }
+
+        String post = HttpRequest.get(urls).execute().body();
+        SmsSendVO vo = JSONUtil.toBean(post, SmsSendVO.class);
+
+        if (vo.getStatus().equals(0)) {
+            boolean anySuccess = false;
+            for (SmsSendItemVO itemVO : vo.getList()) {
+                if (itemVO.getResult().equals("0")) {
+                    anySuccess = true;
+                    // 记录通用日志
+                    CompanySmsLogs logs = new CompanySmsLogs();
+                    logs.setContent(content);
+                    logs.setTempCode(temp.getTempCode());
+                    logs.setTempId(temp.getTempId());
+                    logs.setPhone(phone);
+                    logs.setSendTime(new Date());
+                    logs.setStatus(0);
+                    logs.setType(sms.getType());
+                    logs.setMid(itemVO.getMid());
+                    logs.setNumber(number);
+                    logs.setCompanyId(sendMsgLogBo.getCompanyId());
+                    logs.setCompanyUserId(sendMsgLogBo.getCompanyUserId());
+                    logs.setCustomerId(sendMsgLogBo.getCustomerId());
+                    smsLogsService.insertCompanySmsLogs(logs);
+                    //子记录表关联主表的id
+                    sendMsgLogBo.setCompanySmsLogsId(logs.getLogsId());
+                }
+            }
+            if(anySuccess) {
+                response = R.ok();
+                // 记录特定业务日志
+                smsLogStrategyManager.executeLogStrategy(logType, response, content, phone, temp.getTempId(), sms.getType(), number, sendMsgLogBo);
+            } else {
+                response = R.error("发送短信失败,服务商返回无成功项!");
+                smsLogStrategyManager.executeLogStrategy(logType, response, content, phone, temp.getTempId(), sms.getType(), number, sendMsgLogBo);
+            }
+        } else {
+            response = R.error("发送短信失败!状态码: " + vo.getStatus());
+            // 发送失败也要记录特定业务日志
+            smsLogStrategyManager.executeLogStrategy(logType, response, content, phone, temp.getTempId(), sms.getType(), number, sendMsgLogBo);
+        }
+        return response;
+    }
 
+    // 将计算短信条数的逻辑提取出来,方便复用
+    private int calculateSmsCount(String content) {
+        if (content == null) return 1;
+        int counts = content.length() / 67;
+        if (content.length() % 67 > 0) {
+            counts = counts + 1;
+        }
+        if (counts == 0) {
+            counts = 1;
+        }
+        return counts;
+    }
 
     @Override
     @Synchronized
@@ -965,6 +1071,19 @@ public class SmsServiceImpl implements ISmsService
                 content=content.replace("${sms.senderName}",param.getSenderName());
             }
 
+            if (param.getTempCode()!=null &&SMS_LINK_TEMPLATE_CODE.equals(temp.getTempCode())){
+
+                String json = configService.selectConfigByKey("course.config");
+                CourseConfig config = JSON.parseObject(json, CourseConfig.class);
+
+                String randomStr = ShortCodeGeneratorUtils.generate8();
+                String replaceText=config.getSmsAcquisitionName()+randomStr;
+                content = content.replace("${sms.friendLink}",replaceText);
+                //添加获客链接记录
+                addAcquisitionLinkInfo(null,crmCustomer.getMobile(),param.getCardUrl(),randomStr, param.getCompanyUserId());
+            }
+
+
             String urls= null;
             // 通知类的不加 退订回T 只有营销类的加
             //最多500个手机号
@@ -972,12 +1091,18 @@ public class SmsServiceImpl implements ISmsService
             FsSmsConfig sms = JSON.parseObject(sysConfig.getConfigValue(), FsSmsConfig.class);
             if (sms.getType().equals("rf")){
                 try {
-                    if(temp.getTempType().equals(1)){
-                        urls = sms.getRfUrl1()+"sms?action=send&account="+sms.getRfAccount1()+"&password="+sms.getRfPassword1()+"&mobile="+crmCustomer.getMobile()+"&content="+ URLEncoder.encode(sms.getRfSign()+content, "UTF-8")+"&extno="+sms.getRfCode1()+"&rt=json";
-                    }
-                    else if(temp.getTempType().equals(2)){
-                        urls = sms.getRfUrl2()+"sms?action=send&account="+sms.getRfAccount2()+"&password="+sms.getRfPassword2()+"&mobile="+crmCustomer.getMobile()+"&content="+ URLEncoder.encode(sms.getRfSign()+content+"拒收请回复R", "UTF-8")+"&extno="+sms.getRfCode2()+"&rt=json";
+
+                    if (temp.getTempType().equals(2) && SMS_LINK_TEMPLATE_CODE.equals(temp.getTempCode())){
+                        urls = sms.getRfUrl2() + "sms?action=send&account=" + sms.getRfAccount2() + "&password=" + sms.getRfPassword2() + "&mobile=" + crmCustomer.getMobile() + "&content=" + URLEncoder.encode(content, "UTF-8") + "&extno=" + sms.getRfCode2() + "&rt=json";
+                    } else {
+                        if(temp.getTempType().equals(1)){
+                            urls = sms.getRfUrl1()+"sms?action=send&account="+sms.getRfAccount1()+"&password="+sms.getRfPassword1()+"&mobile="+crmCustomer.getMobile()+"&content="+ URLEncoder.encode(sms.getRfSign()+content, "UTF-8")+"&extno="+sms.getRfCode1()+"&rt=json";
+                        }
+                        else if(temp.getTempType().equals(2)){
+                            urls = sms.getRfUrl2()+"sms?action=send&account="+sms.getRfAccount2()+"&password="+sms.getRfPassword2()+"&mobile="+crmCustomer.getMobile()+"&content="+ URLEncoder.encode(sms.getRfSign()+content+"拒收请回复R", "UTF-8")+"&extno="+sms.getRfCode2()+"&rt=json";
+                        }
                     }
+
                 } catch (UnsupportedEncodingException e) {
                     e.printStackTrace();
                 }
@@ -1074,6 +1199,26 @@ public class SmsServiceImpl implements ISmsService
         }
     }
 
+
+
+    /**
+     * 添加链接生成记录
+     * */
+    public int addAcquisitionLinkInfo(Long qwAcquisitionAssistantId,String originalPhone,String originalLink,String randomStr,Long createBy){
+        QwAcquisitionLinkInfo qwAcquisitionLinkInfo=new QwAcquisitionLinkInfo();
+        qwAcquisitionLinkInfo.setQwAcquisitionAssistantId(qwAcquisitionAssistantId);
+        qwAcquisitionLinkInfo.setCreateBy(createBy);
+        qwAcquisitionLinkInfo.setCreateTime(DateUtils.getTime());
+        qwAcquisitionLinkInfo.setPhone(originalPhone);//这里存储原始手机号
+        //加密手机号
+        String phonePlus = encryptPhone(originalPhone);
+        String linkPlus=originalLink+LINK_SUFFIX+ phonePlus;
+        qwAcquisitionLinkInfo.setLink(linkPlus);
+        qwAcquisitionLinkInfo.setRandomStr(randomStr);
+        int addResult=qwAcquisitionLinkInfoMapper.insertQwAcquisitionLinkInfo(qwAcquisitionLinkInfo);
+        return addResult;
+    }
+
     /**
      * 根据 uuid(QwSopSmsLogs.id)和索引更新子记录,并检查主记录完成状态
      */

+ 15 - 9
fs-service/src/main/java/com/fs/company/domain/CompanySms.java

@@ -7,7 +7,7 @@ import org.apache.commons.lang3.builder.ToStringStyle;
 
 /**
  * 公司短信对象 company_sms
- * 
+ *
  * @author fs
  * @date 2023-01-09
  */
@@ -30,43 +30,49 @@ public class CompanySms extends BaseEntity
     @Excel(name = "总短信数")
     private Long totalSmsCount;
 
-    public void setSmsId(Long smsId) 
+    /** 乐观锁版本号 */
+    private Long version;
+
+    public void setSmsId(Long smsId)
     {
         this.smsId = smsId;
     }
 
-    public Long getSmsId() 
+    public Long getSmsId()
     {
         return smsId;
     }
-    public void setCompanyId(Long companyId) 
+    public void setCompanyId(Long companyId)
     {
         this.companyId = companyId;
     }
 
-    public Long getCompanyId() 
+    public Long getCompanyId()
     {
         return companyId;
     }
-    public void setRemainSmsCount(Long remainSmsCount) 
+    public void setRemainSmsCount(Long remainSmsCount)
     {
         this.remainSmsCount = remainSmsCount;
     }
 
-    public Long getRemainSmsCount() 
+    public Long getRemainSmsCount()
     {
         return remainSmsCount;
     }
-    public void setTotalSmsCount(Long totalSmsCount) 
+    public void setTotalSmsCount(Long totalSmsCount)
     {
         this.totalSmsCount = totalSmsCount;
     }
 
-    public Long getTotalSmsCount() 
+    public Long getTotalSmsCount()
     {
         return totalSmsCount;
     }
 
+    public Long getVersion() {
+        return version;
+    }
     @Override
     public String toString() {
         return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)

+ 19 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanySmsMapper.java

@@ -90,4 +90,23 @@ public interface CompanySmsMapper {
     Long debitSmsCount(Long companyId);
 
 
+    // ========== 扣减/增加方法 ==========
+    /** 直接扣减(配合悲观锁) */
+    int decrementRemainSmsCount(@Param("companyId") Long companyId,
+                                @Param("number") int number);
+
+    /** 直接增加(配合悲观锁) */
+    int incrementRemainSmsCount(@Param("companyId") Long companyId,
+                                @Param("number") int number);
+
+    /** 乐观锁扣减 */
+    int decrementRemainSmsCountWithVersion(@Param("companyId") Long companyId,
+                                           @Param("number") int number,
+                                           @Param("currentVersion") Long currentVersion);
+
+    /** 乐观锁增加 */
+    int incrementRemainSmsCountWithVersion(@Param("companyId") Long companyId,
+                                           @Param("number") int number,
+                                           @Param("currentVersion") Long currentVersion);
+
 }

+ 49 - 8
fs-service/src/main/java/com/fs/company/service/ICompanySmsService.java

@@ -6,15 +6,15 @@ import com.fs.company.vo.CompanySmsListVO;
 
 /**
  * 公司短信Service接口
- * 
+ *
  * @author fs
  * @date 2023-01-09
  */
-public interface ICompanySmsService 
+public interface ICompanySmsService
 {
     /**
      * 查询公司短信
-     * 
+     *
      * @param smsId 公司短信ID
      * @return 公司短信
      */
@@ -22,7 +22,7 @@ public interface ICompanySmsService
 
     /**
      * 查询公司短信列表
-     * 
+     *
      * @param companySms 公司短信
      * @return 公司短信集合
      */
@@ -30,7 +30,7 @@ public interface ICompanySmsService
 
     /**
      * 新增公司短信
-     * 
+     *
      * @param companySms 公司短信
      * @return 结果
      */
@@ -38,7 +38,7 @@ public interface ICompanySmsService
 
     /**
      * 修改公司短信
-     * 
+     *
      * @param companySms 公司短信
      * @return 结果
      */
@@ -46,7 +46,7 @@ public interface ICompanySmsService
 
     /**
      * 批量删除公司短信
-     * 
+     *
      * @param smsIds 需要删除的公司短信ID
      * @return 结果
      */
@@ -54,7 +54,7 @@ public interface ICompanySmsService
 
     /**
      * 删除公司短信信息
-     * 
+     *
      * @param smsId 公司短信ID
      * @return 结果
      */
@@ -68,4 +68,45 @@ public interface ICompanySmsService
     int addCompanySms(Long companyId, int number);
 
     CompanySms selectCompanySmsByCompanyIdForUpdate(Long companyId);
+
+
+    // ========== 查询方法 ==========
+    /** 普通查询(不带锁) */
+    CompanySms selectCompanySms(Long companyId);
+
+    /** 悲观锁查询(for update) */
+    CompanySms selectCompanySmsForUpdate(Long companyId);
+
+    // ========== 扣减/增加方法 ==========
+    /** 直接扣减(配合悲观锁使用) */
+    int decrementRemainSmsCount(Long companyId, int number);
+
+    /** 直接增加(配合悲观锁使用) */
+    int incrementRemainSmsCount(Long companyId, int number);
+
+    /** 乐观锁扣减(配合重试机制使用) */
+    int decrementRemainSmsCountWithVersion(Long companyId, int number, Long currentVersion);
+
+    /** 乐观锁增加(配合重试机制使用) */
+    int incrementRemainSmsCountWithVersion(Long companyId, int number, Long currentVersion);
+
+    // ========== 缓存方法 ==========
+    /** 获取余额(优先从缓存获取) */
+    Long getBalance(Long companyId);
+
+    /** 删除缓存(数据库变更后调用) */
+    void evictBalance(Long companyId);
+
+    /**
+     * 更新缓存中的余额(数据库更新后调用)
+     */
+    void updateCacheBalance(Long companyId, int delta);
+
+    /**
+     * 充值短信条数(带缓存更新)
+     * @param companyId 公司ID
+     * @param number 充值条数
+     * @return 是否成功
+     */
+    boolean rechargeSms(Long companyId, int number);
 }

+ 164 - 0
fs-service/src/main/java/com/fs/company/service/impl/CompanySmsServiceImpl.java

@@ -1,13 +1,17 @@
 package com.fs.company.service.impl;
 
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
+import com.fs.common.core.redis.RedisCache;
 import com.fs.company.vo.CompanySmsListVO;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.fs.company.mapper.CompanySmsMapper;
 import com.fs.company.domain.CompanySms;
 import com.fs.company.service.ICompanySmsService;
+import org.springframework.transaction.annotation.Transactional;
 
 /**
  * 公司短信Service业务层处理
@@ -15,12 +19,23 @@ import com.fs.company.service.ICompanySmsService;
  * @author fs
  * @date 2023-01-09
  */
+@Slf4j
 @Service
 public class CompanySmsServiceImpl implements ICompanySmsService
 {
     @Autowired
     private CompanySmsMapper companySmsMapper;
 
+    @Autowired
+    private RedisCache redisCache;
+
+    // 公司短信余额缓存key前缀
+    private static final String BALANCE_KEY_PREFIX = "sms:balance:";
+    // 缓存有效期
+    private static final int CACHE_EXPIRE_SECONDS = 18000; // 300分钟
+    // 最大重试次数
+    private static final int MAX_RETRY_TIMES = 3;
+
     /**
      * 查询公司短信
      *
@@ -119,4 +134,153 @@ public class CompanySmsServiceImpl implements ICompanySmsService
     public CompanySms selectCompanySmsByCompanyIdForUpdate(Long companyId) {
         return companySmsMapper.selectCompanySmsByCompanyIdForUpdate(companyId);
     }
+
+    // ========== 查询方法 ==========
+    @Override
+    public CompanySms selectCompanySms(Long companyId) {
+        return companySmsMapper.selectCompanySmsByCompanyId(companyId);
+    }
+
+    @Override
+    public CompanySms selectCompanySmsForUpdate(Long companyId) {
+        return companySmsMapper.selectCompanySmsByCompanyIdForUpdate(companyId);
+    }
+
+    // ========== 扣减/增加方法 ==========
+    @Override
+    public int decrementRemainSmsCount(Long companyId, int number) {
+        return companySmsMapper.decrementRemainSmsCount(companyId, number);
+    }
+
+    @Override
+    public int incrementRemainSmsCount(Long companyId, int number) {
+        return companySmsMapper.incrementRemainSmsCount(companyId, number);
+    }
+
+    @Override
+    public int decrementRemainSmsCountWithVersion(Long companyId, int number, Long currentVersion) {
+        return companySmsMapper.decrementRemainSmsCountWithVersion(companyId, number, currentVersion);
+    }
+
+    @Override
+    public int incrementRemainSmsCountWithVersion(Long companyId, int number, Long currentVersion) {
+        return companySmsMapper.incrementRemainSmsCountWithVersion(companyId, number, currentVersion);
+    }
+
+    // ========== 缓存方法 ==========
+    @Override
+    public Long getBalance(Long companyId) {
+        String cacheKey = BALANCE_KEY_PREFIX + companyId;
+        try {
+            Long balance = redisCache.getCacheObject(cacheKey);
+            if (balance != null) {
+                log.debug("从缓存获取余额成功, companyId={}, balance={}", companyId, balance);
+                return balance;
+            }
+            CompanySms companySms = companySmsMapper.selectCompanySmsByCompanyId(companyId);
+            if (companySms == null) {
+                return null;
+            }
+            Long realBalance = companySms.getRemainSmsCount();
+            redisCache.setCacheObject(cacheKey, realBalance, CACHE_EXPIRE_SECONDS, TimeUnit.SECONDS);
+            log.debug("从数据库加载余额并写入缓存, companyId={}, balance={}", companyId, realBalance);
+            return realBalance;
+        } catch (Exception e) {
+            log.error("获取余额缓存失败, companyId={}", companyId, e);
+            CompanySms companySms = companySmsMapper.selectCompanySmsByCompanyId(companyId);
+            return companySms != null ? companySms.getRemainSmsCount() : null;
+        }
+    }
+
+    @Override
+    public void updateCacheBalance(Long companyId, int delta) {
+        String cacheKey = BALANCE_KEY_PREFIX + companyId;
+        String lockKey = "sms:balance:lock:" + companyId;
+
+        try {
+            Boolean locked = redisCache.setIfAbsent(lockKey, "1", 3, TimeUnit.SECONDS);
+
+            if (Boolean.TRUE.equals(locked)) {
+                try {
+                    Long currentBalance = redisCache.getCacheObject(cacheKey);
+                    if (currentBalance != null) {
+                        Long newBalance = currentBalance + delta;
+                        redisCache.setCacheObject(cacheKey, newBalance, CACHE_EXPIRE_SECONDS, TimeUnit.SECONDS);
+                        log.debug("更新缓存余额成功, companyId={}, old={}, new={}, delta={}",
+                                companyId, currentBalance, newBalance, delta);
+                    } else {
+                        log.debug("缓存不存在,跳过更新, companyId={}", companyId);
+                    }
+                } finally {
+                    redisCache.deleteObject(lockKey);
+                }
+            } else {
+                log.warn("获取缓存锁失败,删除缓存, companyId={}", companyId);
+                redisCache.deleteObject(cacheKey);
+            }
+        } catch (Exception e) {
+            log.error("更新缓存余额失败, companyId={}, delta={}", companyId, delta, e);
+            redisCache.deleteObject(cacheKey);
+        }
+    }
+
+    @Override
+    public void evictBalance(Long companyId) {
+        String cacheKey = BALANCE_KEY_PREFIX + companyId;
+        try {
+            redisCache.deleteObject(cacheKey);
+            log.debug("删除余额缓存成功, companyId={}", companyId);
+        } catch (Exception e) {
+            log.error("删除余额缓存失败, companyId={}", companyId, e);
+        }
+    }
+
+    // ========== 充值方法 ==========
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean rechargeSms(Long companyId, int number) {
+        if (number <= 0) {
+            log.warn("充值条数无效, companyId={}, number={}", companyId, number);
+            return false;
+        }
+
+        int maxRetries = 3;
+
+        for (int retryCount = 0; retryCount < maxRetries; retryCount++) {
+            // 获取最新数据(含version)
+            CompanySms latestSms = selectCompanySms(companyId);
+            if (latestSms == null) {
+                log.error("充值失败,公司短信配置不存在, companyId={}", companyId);
+                return false;
+            }
+
+            Long version = latestSms.getVersion() != null ? latestSms.getVersion() : 0L;
+            int updateCount = companySmsMapper.incrementRemainSmsCountWithVersion(companyId, number, version);
+
+            if (updateCount > 0) {
+                // 充值成功,更新缓存
+                updateCacheBalance(companyId, number);
+                log.info("充值成功, companyId={}, number={}, newBalance={}",
+                        companyId, number, latestSms.getRemainSmsCount() + number);
+                return true;
+            }
+
+            log.warn("乐观锁充值失败,第{}次重试, companyId={}", retryCount + 1, companyId);
+
+            if (retryCount == maxRetries - 1) {
+                log.error("充值失败,重试次数用尽, companyId={}, number={}", companyId, number);
+                return false;
+            }
+
+            try {
+                Thread.sleep(50L * (retryCount + 1));
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                log.error("充值被中断, companyId={}", companyId);
+                return false;
+            }
+        }
+
+        return false;
+    }
 }

Різницю між файлами не показано, бо вона завелика
+ 0 - 0
fs-service/src/main/java/com/fs/company/service/impl/GeneralCustomerEntryServiceImpl.java


+ 3 - 0
fs-service/src/main/java/com/fs/config/ai/AiHostProper.java

@@ -20,6 +20,9 @@ public class AiHostProper {
     @Value("${ipad.commonApi}")
     private String commonApi;
 
+    @Value("${ipad.aiApiV2:http://1.95.196.10:3000/api}")
+    private String aiApiV2;
+
 
 
 }

+ 1 - 0
fs-service/src/main/java/com/fs/course/config/CourseConfig.java

@@ -28,6 +28,7 @@ public class CourseConfig implements Serializable {
     private String realLinkH5LiveName;//H5通用直播域名
     private String authDomainName;//网页授权域名
     private String smsDomainName;//短信推送域名
+    private String smsAcquisitionName;//短信推送域名
     private String smsDomain;//短信推送域名
     private String mpAppId;//看课公众号APPID
     private String registerDomainName;//注册域名

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

@@ -24,7 +24,7 @@ public class FsCourseAnswerReward {
     private List<RewardProduct> products;
 
     /**
-     * 本次获得的芳华币数量
+     * 本次获得的积分数量
      */
     private Integer availableCoins;
 

+ 8 - 0
fs-service/src/main/java/com/fs/course/domain/FsCoursePlaySourceConfig.java

@@ -109,4 +109,12 @@ public class FsCoursePlaySourceConfig {
      * 商户支付配置id
      */
     private Long merchantConfigId;
+    /**
+    * 客服电话
+    */
+    private Long customerNum;
+    /**
+    * 备案号
+    */
+    private String recordNumber;
 }

+ 3 - 0
fs-service/src/main/java/com/fs/course/domain/FsUserCourseComment.java

@@ -61,4 +61,7 @@ public class FsUserCourseComment extends BaseEntity
     /** 视频ID */
     private Long videoId;
 
+    /** 是否全部人可见:0-自己可见,1-全部人可见 */
+    private Integer visibleAll;
+
 }

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

@@ -142,6 +142,11 @@ public class FsUserCourseVideo extends BaseEntity
     /** 课程介绍图片URL */
     private String courseIntroImg;
 
+    /**
+     * 课程优惠券ID
+     */
+    private Long courseCouponId;
+
     @TableField(exist = false)
     private Integer showProduct; //1不展示疗法,0展示疗法
 

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

@@ -60,8 +60,8 @@ public class LuckyBagCollectRecord extends BaseEntity{
     @Excel(name = "公司名称")
     private String companyName;
 
-    /** 芳华币数量 */
-    @Excel(name = "芳华币数量")
+    /** 积分数量 */
+    @Excel(name = "积分数量")
     private BigDecimal coinAmount;
 
     /** 发放时间 */

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

@@ -948,7 +948,7 @@ public interface FsCourseWatchLogMapper extends BaseMapper<FsCourseWatchLog> {
             "WHERE user_id = #{userId} " +
             "AND duration > 0 " +
             "AND (send_type = 1 OR send_type = 2) " +
-            "ORDER BY create_time DESC " +
+            "ORDER BY update_time DESC " +
             "LIMIT 1")
     FsCourseWatchLog selectLatestWatchLogByUserId(@Param("userId") Long userId);
 }

+ 16 - 7
fs-service/src/main/java/com/fs/course/mapper/FsUserCourseCommentMapper.java

@@ -70,17 +70,20 @@ public interface FsUserCourseCommentMapper
     public int deleteFsUserCourseCommentByCommentIds(Long[] commentIds);
 
     @Select({"<script> " +
-            "select c.*,u.nick_name,u.phone,u.avatar from fs_user_course_comment c LEFT JOIN fs_user u ON c.user_id=u.user_id"+
+            "select c.*,u.nick_name as nickNameOriginal,u.phone,u.avatar from fs_user_course_comment c LEFT JOIN fs_user u ON c.user_id=u.user_id"+
             "<where>  \n" +
             "            <if test=\"userId != null \"> and c.user_id = #{userId}</if>\n" +
             "            <if test=\"courseId != null \"> and c.course_id = #{courseId}</if>\n" +
+            "            <if test=\"videoId != null \"> and c.video_id = #{videoId}</if>\n" +
             "            <if test=\"type != null \"> and c.type = #{type}</if>\n" +
+            "            <if test=\"excludeFeatured != null and excludeFeatured == true\"> and (c.type is null or c.type != 3) and (c.is_del = 0 or c.is_del is null)</if>\n" +
             "            <if test=\"parentId != null \"> and c.parent_id = #{parentId}</if>\n" +
             "            <if test=\"content != null  and content != ''\"> and c.content = #{content}</if>\n" +
             "            <if test=\"replyCount != null \"> and c.reply_count = #{replyCount}</if>\n" +
+            "            <if test=\"nickName != null and nickName != ''\"> and (u.nick_name like concat('%', #{nickName}, '%') or c.nick_name like concat('%', #{nickName}, '%'))</if>\n" +
             "            <if test=\"phone != null \"> and u.phone = #{phone}</if>\n" +
             "        </where>" +
-            "order by comment_id desc"+
+            "order by c.comment_id desc"+
             "</script>"})
     List<FsUserCourseCommentListVO> selectFsUserCourseCommentListVO(FsUserCourseCommentParam fsUserCourseComment);
     @Select("select c.*,u.nick_name,u.phone from fs_user_course_comment c LEFT JOIN fs_user u ON c.user_id=u.user_id where comment_id=#{commentId}")
@@ -88,20 +91,26 @@ public interface FsUserCourseCommentMapper
     @Select("select c.*,u.nick_name,u.phone,u,avatar from fs_user_course_comment c LEFT JOIN fs_user u ON c.user_id=u.user_id where parent_id=#{pid}")
     List<FsUserCourseCommentVO> selectFsUserCourseCommentAllListVO(Long pid);
     @Select({"<script> " +
-            "select c.*,u.nick_name,u.avatar,tu.nick_name to_nick_name, IFNULL(l.id, 0) AS is_like from fs_user_course_comment c " +
+            "select c.*,u.nick_name as nickNameOriginal,u.avatar,tu.nick_name to_nick_name, IFNULL(l.id, 0) AS is_like from fs_user_course_comment c " +
             "LEFT JOIN fs_user u ON c.user_id=u.user_id " +
             "LEFT  JOIN fs_user tu ON tu.user_id =c.to_user_id " +
             "LEFT JOIN fs_user_course_comment_like l ON c.comment_id=l.comment_id and #{userId}=l.user_id "+
-            "where c.is_del = 0 and  c.type = 1  \n" +
+            "where c.is_del = 0 and c.type = 1 \n" +
             "<if test=\"courseId != null \"> and c.course_id = #{courseId}</if>\n" +
             "<if test=\"videoId != null \"> and c.video_id = #{videoId}</if>\n" +
+            "<if test=\"userId != null\"> and (c.visible_all = 1 or c.user_id = #{userId})</if>\n" +
+            "<if test=\"userId == null\"> and c.visible_all = 1</if>\n" +
             "<if test=\"sortType != null and sortType == 1\"> order by c.likes desc </if>" +
             "<if test=\"sortType != null and sortType == 2\"> order by c.comment_id desc </if>" +
             "</script>"})
     List<FsUserCourseCommentListUVO> selectFsUserCourseCommentListUVO(FsUserCourseCommentUParam param);
     @Select({"<script> " +
-            "select c.*,u.nick_name,u.avatar,tu.nick_name to_nick_name from fs_user_course_comment c LEFT JOIN fs_user u ON c.user_id=u.user_id LEFT  JOIN fs_user tu ON tu.user_id =c.to_user_id " +
-            "where c.user_id=#{userId} " +
+            "select c.*,u.nick_name as nickNameOriginal,u.avatar,tu.nick_name to_nick_name from fs_user_course_comment c " +
+            "LEFT JOIN fs_user u ON c.user_id=u.user_id " +
+            "LEFT JOIN fs_user tu ON tu.user_id =c.to_user_id " +
+            "where (c.is_del = 0 or c.is_del is null) " +
+            "and (c.type is null or c.type != 3) " +
+            "and (c.user_id = #{userId} or c.visible_all = 1) " +
             "<if test='courseId != null'> and c.course_id = #{courseId}</if>" +
             "<if test='videoId != null'> and c.video_id = #{videoId}</if>" +
             " order by c.create_time desc" +
@@ -143,7 +152,7 @@ public interface FsUserCourseCommentMapper
     List<FsUserCourseCommentReplyListUVO> selectFsUserCourseCommentReplyListUVO(@Param("commentId") Long commentId, @Param("userId") String userId);
 
     @Select({"<script> " +
-            "select c.*,u.nick_name,u.avatar,tu.nick_name to_nick_name from fs_user_course_comment c " +
+            "select c.*,u.nick_name as nickNameOriginal,u.avatar,tu.nick_name to_nick_name from fs_user_course_comment c " +
             "LEFT JOIN fs_user u ON c.user_id=u.user_id " +
             "LEFT  JOIN fs_user tu ON tu.user_id =c.to_user_id " +
             "where c.is_del = 0 and  c.type = 1  \n" +

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

@@ -74,7 +74,7 @@ public interface FsUserCourseStudyMapper
             "<if test = ' maps.courseType != null and maps.courseType == 1 '> " +
             "and c.cate_id = (select cate_id from fs_user_course_category WHERE cate_name like '%央广原乡行%' AND cate_type = 1 limit 1) " +
             "</if>" +
-            "<if test = ' maps.courseType == null  '> " +
+            "<if test = ' maps.courseType == null  or maps.courseType == 0'> " +
             "and c.cate_id != (select cate_id from fs_user_course_category WHERE cate_name like '%央广原乡行%' AND cate_type = 1 limit 1) " +
             "</if>" +
             " order by s.study_id  "+

+ 4 - 1
fs-service/src/main/java/com/fs/course/mapper/FsUserCourseVideoMapper.java

@@ -158,6 +158,9 @@ public interface FsUserCourseVideoMapper extends BaseMapper<FsUserCourseVideo> {
     @Select("select video_id dict_value, title dict_label  from fs_user_course_video where course_id=#{id} and is_del = 0 order by course_sort")
     List<OptionsVO> selectFsUserCourseVodeAllList(Long id);
 
+    @Select("select video_id dict_value, title dict_label,is_del  from fs_user_course_video where course_id=#{id}  order by course_sort")
+    List<OptionsVO> selectFsUserCourseVodeAllListByWatch(Long id);
+
     @Select("select video_id dict_value, title dict_label  from fs_user_course_video where course_id=#{id} and is_del = 0 and is_on_put = 0 order by course_sort, video_id")
     List<OptionsVO> selectFsUserCourseVideoAllListV2(@Param("id") Long id);
 
@@ -166,7 +169,7 @@ public interface FsUserCourseVideoMapper extends BaseMapper<FsUserCourseVideo> {
             "LEFT JOIN fs_user_course_video_red_package p on p.video_id= v.video_id and p.company_id =#{maps.companyId} and p.data_type = 1 " +
             "where v.is_del = 0 and  v.course_id = #{maps.courseId}   " +
             "<if test = ' maps.title!=null and maps.title != \"\" '> " +
-            "and v.title = #{maps.title} " +
+            "and v.title like concat('%', #{maps.title}, '%')  " +
             "</if>" +
             " order by v.course_sort  " +
             "</script>"})

+ 3 - 0
fs-service/src/main/java/com/fs/course/mapper/FsUserCourseVideoRedPackageMapper.java

@@ -113,4 +113,7 @@ public interface FsUserCourseVideoRedPackageMapper
 
 
     Integer selectRedPacketByCompanyCount(@Param("videoId") Long videoId,@Param("companyId") Long companyId, @Param("periodId") Long periodId);
+
+    @Select("select * from fs_user_course_video_red_package where video_id =#{videoId} and company_id = #{companyId} and data_type = #{dataType}")
+    FsUserCourseVideoRedPackage selectRedPacketByVideoIdAndType(@Param("videoId") Long videoId,@Param("companyId") Long companyId,@Param("dataType") Integer dataType);
 }

+ 8 - 0
fs-service/src/main/java/com/fs/course/param/FsCoursePlaySourceConfigCreateParam.java

@@ -57,4 +57,12 @@ public class FsCoursePlaySourceConfigCreateParam {
 
     @ApiModelProperty("小程序状态:0正常,1半封禁,2封禁")
     private Integer status;
+    /**
+    * 客服电话
+    */
+    private Long customerNum;
+    /**
+    * 备案号
+    */
+    private String recordNumber;
 }

+ 8 - 0
fs-service/src/main/java/com/fs/course/param/FsCoursePlaySourceConfigEditParam.java

@@ -58,4 +58,12 @@ public class FsCoursePlaySourceConfigEditParam {
 
     @ApiModelProperty("商户支付配置id")
     private Long merchantConfigId;
+    /**
+    * 客服电话
+    */
+    private Long customerNum;
+    /**
+    * 备案号
+    */
+    private String recordNumber;
 }

+ 6 - 0
fs-service/src/main/java/com/fs/course/param/FsUserCourseCommentParam.java

@@ -43,4 +43,10 @@ public class FsUserCourseCommentParam {
     private Date createTime;
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date updateTime;
+
+    /** 视频小节 id */
+    private Long videoId;
+
+    /** 为 true 时排除精选留言(type=3) */
+    private Boolean excludeFeatured;
 }

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

@@ -3,6 +3,7 @@ package com.fs.course.service.impl;
 import java.util.Collections;
 import java.util.List;
 import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.StringUtils;
 import com.fs.course.param.FsUserCourseCommentParam;
 import com.fs.course.param.FsUserCourseCommentUParam;
 import com.fs.course.vo.FsUserCourseCommentListUVO;
@@ -103,7 +104,13 @@ public class FsUserCourseCommentServiceImpl implements IFsUserCourseCommentServi
 
     @Override
     public List<FsUserCourseCommentListVO> selectFsUserCourseCommentListVO(FsUserCourseCommentParam fsUserCourseComment) {
-        return fsUserCourseCommentMapper.selectFsUserCourseCommentListVO(fsUserCourseComment);
+        List<FsUserCourseCommentListVO> list = fsUserCourseCommentMapper.selectFsUserCourseCommentListVO(fsUserCourseComment);
+        list.forEach(comment -> {
+            if (StringUtils.isEmpty(comment.getNickName())) {
+                comment.setNickName(comment.getNickNameOriginal());
+            }
+        });
+        return list;
     }
 
     @Override
@@ -124,12 +131,23 @@ public class FsUserCourseCommentServiceImpl implements IFsUserCourseCommentServi
         }else {
             list = fsUserCourseCommentMapper.selectFsUserCourseCommentListUVO(param);
         }
+        list.forEach(comment -> {
+            if (StringUtils.isEmpty(comment.getNickName())) {
+                comment.setNickName(comment.getNickNameOriginal());
+            }
+        });
         return list;
     }
 
     @Override
     public List<FsUserCourseCommentListUVO> selectFsUserCourseCommentMyListUVO(FsUserCourseCommentUParam param) {
-        return fsUserCourseCommentMapper.selectFsUserCourseCommentMyListUVO(param);
+        List<FsUserCourseCommentListUVO> list = fsUserCourseCommentMapper.selectFsUserCourseCommentMyListUVO(param);
+        list.forEach(comment -> {
+            if (StringUtils.isEmpty(comment.getNickName())) {
+                comment.setNickName(comment.getNickNameOriginal());
+            }
+        });
+        return list;
     }
 
     @Override

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

@@ -465,7 +465,7 @@ public class FsUserCourseServiceImpl implements IFsUserCourseService
             todayTotalIntegral=0;
         }
         if (todayTotalIntegral>=config.getIntegralByOneDay()){
-            return R.error("当天芳华币已达限额");
+            return R.error("当天积分已达限额");
         }
         int rate = (int)((double)param.getDuration() / video.getDuration() * 100);
         if (rate>=90){
@@ -493,7 +493,7 @@ public class FsUserCourseServiceImpl implements IFsUserCourseService
 //            integralLogs.setBusinessId(video.getVideoId().toString());
 //            integralLogs.setCreateTime(new Date());
 //            fsUserIntegralLogsMapper.insertFsUserIntegralLogs(integralLogs);
-//            return R.ok("恭喜您获得"+config.getIntegralCourse()+"芳华币");
+//            return R.ok("恭喜您获得"+config.getIntegralCourse()+"积分");
         }
         return R.error("观看进度不满百分之九十");
     }

+ 4 - 1
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -4738,7 +4738,10 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
                     fsStoreProductScrm.setOffShelfTime(offShelfTime);
                     fsStoreProductScrm.setCardPopupTime(cardPopupTime);
                     fsStoreProductScrm.setCardCloseTime(cardCloseTime);
-
+                    if (originalNode != null && originalNode.has("hotSaleTags") && !originalNode.path("hotSaleTags").isNull()) {
+                        String hotSaleTags = originalNode.path("hotSaleTags").asText();
+                        fsStoreProductScrm.setHotSaleTags(StringUtils.isNotBlank(hotSaleTags) ? hotSaleTags : null);
+                    }
 
                     fsPackageListVOS.add(fsStoreProductScrm);
                 }

+ 9 - 0
fs-service/src/main/java/com/fs/course/vo/FsCoursePlaySourceConfigVO.java

@@ -67,4 +67,13 @@ public class FsCoursePlaySourceConfigVO {
 
     @ApiModelProperty("小程序支付配置id")
     private Long merchantConfigId;
+
+    /**
+     * 客服电话
+     */
+    private Long customerNum;
+    /**
+     * 备案号
+     */
+    private String recordNumber;
 }

+ 3 - 3
fs-service/src/main/java/com/fs/course/vo/FsCourseWatchLogListVO.java

@@ -23,7 +23,7 @@ public class FsCourseWatchLogListVO extends BaseEntity
     private Long logId;
 
     /** 会员id */
-//    @Excel(name = "会员id")
+    @Excel(name = "用户ID")
     private Long userId;
 
     /** 小程序昵称 */
@@ -96,8 +96,8 @@ public class FsCourseWatchLogListVO extends BaseEntity
     @JsonFormat(pattern = "yyyy-MM-dd")
     private Date campPeriodTime;
 
-    /** 所属团队 */
-//    @Excel(name = "所属团队")
+    /** 所属公司 */
+    @Excel(name = "所属公司")
     private String companyName;
 
     /** 所属团队编号 */

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

@@ -20,6 +20,7 @@ public class FsUserCourseCommentListUVO {
     @Excel(name = "课堂id")
     private Long courseId;
     private String nickName;
+    private String nickNameOriginal;
     private String toNickName;
     private String avatar;
     /** 评论类型 1:评论,2:回复 */
@@ -48,4 +49,7 @@ public class FsUserCourseCommentListUVO {
     private List<FsUserCourseCommentReplyListUVO> replyList;
     //是否点赞 1是 0否
     private Integer isLike;
+
+    /** 是否全部人可见:0-自己可见,1-全部人可见 */
+    private Integer visibleAll;
 }

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

@@ -18,6 +18,7 @@ public class FsUserCourseCommentListVO {
     @Excel(name = "课堂id")
     private Long courseId;
     private String nickName;
+    private String nickNameOriginal;
     private String phone;
     private String avatar;
 
@@ -44,4 +45,7 @@ public class FsUserCourseCommentListVO {
     private Date createTime;
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date updateTime;
+
+    /** 是否全部人可见:0-自己可见,1-全部人可见 */
+    private Integer visibleAll;
 }

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

@@ -113,4 +113,9 @@ public class FsUserCourseVideoQVO extends BaseEntity {
 
     // 是否上架 0:上架,1:下架
     private Integer isOnPut;
+
+    /**
+     * 课程优惠券ID
+     */
+    private Long courseCouponId;
 }

+ 1 - 1
fs-service/src/main/java/com/fs/crm/utils/CrmCustomerAiTagUtil.java

@@ -145,7 +145,7 @@ public class CrmCustomerAiTagUtil {
             ChatService chatService = SpringUtils.getBean(ChatService.class);
             AiHostProper aiHost = SpringUtils.getBean(AiHostProper.class);
 
-            return chatService.initiatingTakeChat(param, aiHost.getAiApi(), appKey);
+            return chatService.initiatingTakeChat(param, aiHost.getAiApiV2(), appKey);
         } catch (Exception e) {
             throw new RuntimeException("AI服务调用失败", e);
         }

+ 90 - 0
fs-service/src/main/java/com/fs/fastgptApi/param/ChatImgParam.java

@@ -0,0 +1,90 @@
+package com.fs.fastgptApi.param;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+* 对话接口
+*/
+@Data
+public class ChatImgParam {
+
+    /**
+    * 聊天id
+    */
+    private String chatId;
+
+    //知识库id
+//    private String dataId;
+//    private String datasetId;
+
+    /**
+    * 是否开启 stream模式 (stream模式下会通过event进行区分/非stream模式结果保存在responseData)
+    */
+    private Boolean stream;
+
+    /**
+    * 是否返回中间值(模块状态,响应的完整结果等)
+    */
+    private Boolean detail;
+
+
+    /**
+    * 模块变量,一个对象,会替换模块中,输入框内容里的{{key}}
+    */
+    private Variables variables;
+
+    /**
+    * 聊天信息(对话框)
+    */
+    private List<Message> messages;
+
+
+    @Data
+    public static class Variables {
+        //客户的id?
+        private String uid;
+        /**
+        * 客户名称
+        */
+        private String name;
+
+    }
+
+
+    @Data
+    public static class Message {
+        //知识库id
+        private String dataId;
+//        private String datasetId;
+
+        /**
+        *  问题
+        */
+        private List<content> content;
+        /**
+        * 用户权限
+         * 字段用来定义消息的发送者角色,具体包括三种选择:system、user、和 assistant。
+         *
+         * system(系统):通常用于设置聊天的上下文或者提供系统级别的指示和配置信息。
+         * user(用户):代表实际的用户输入,即用户向聊天系统提出的问题或者发起的对话内容。
+         * assistant(助手):代表智能助手的回复或者动作,是模型根据用户输入给出的响应。
+        */
+        private String role;
+
+        @Data
+        public static class content {
+            private String type;
+            private String text;
+            private ImageUrl image_url;
+        }
+
+        @Data
+        public static class ImageUrl {
+            private String url;
+        }
+
+    }
+
+}

+ 2 - 0
fs-service/src/main/java/com/fs/fastgptApi/service/ChatService.java

@@ -2,6 +2,7 @@ package com.fs.fastgptApi.service;
 
 
 import com.fs.common.core.domain.R;
+import com.fs.fastgptApi.param.ChatImgParam;
 import com.fs.fastgptApi.param.ChatParam;
 
 /**
@@ -13,4 +14,5 @@ public interface ChatService {
     * 发起对话
     */
     R initiatingTakeChat(ChatParam param,String url,String appKey);
+    R initiatingTakeChatNew(ChatImgParam param, String url, String appKey);
 }

+ 90 - 0
fs-service/src/main/java/com/fs/fastgptApi/service/Impl/ChatServiceImpl.java

@@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.fs.common.core.domain.R;
 import com.fs.fastgptApi.config.FastGptApiConfig;
+import com.fs.fastgptApi.param.ChatImgParam;
 import com.fs.fastgptApi.param.ChatParam;
 import com.fs.fastgptApi.result.ChatDetailFStreamFResult;
 import com.fs.fastgptApi.result.ChatDetailTStreamFResult;
@@ -116,6 +117,95 @@ public class ChatServiceImpl implements ChatService {
         return null;
     }
 
+    @Override
+    public R initiatingTakeChatNew(ChatImgParam param, String url, String appKey) {
+
+        String json = HttpUtil.sendPost(param, url+FastGptApiConfig.completionsUrl, appKey);
+
+        JSONObject jsonObject = JSON.parseObject(json);
+
+        // 判断是否有回应消息
+        if(jsonObject.containsKey("choices")){
+            // 获取消息列表
+            JSONArray choices = jsonObject.getJSONArray("choices");
+            // 回复消息不为空
+            if(!choices.isEmpty()){
+                // 判断是否转人工
+                if(JSON.parseObject(choices.get(0).toString()).getJSONObject("message").getString("content").contains("【转人工】")){
+                    jsonObject.put("artificial", true);
+                }
+                if(JSON.parseObject(choices.get(0).toString()).getJSONObject("message").getString("content").contains("FunctionCallBegin")){
+                    jsonObject.put("artificial", true);
+                }
+                if(JSON.parseObject(choices.get(0).toString()).getJSONObject("message").getString("content").contains("【长对话】")){
+                    jsonObject.put("longText", true);
+                }
+
+
+
+                // 替换AI回复里面的所有的【】包括里面的字符串
+                List<JSONObject> list = choices.stream().map(e -> {
+                    JSONObject result = JSON.parseObject(e.toString());
+                    JSONObject message = result.getJSONObject("message");
+                    message.put("content", message.getString("content"));
+                    return result;
+                }).collect(Collectors.toList());
+                jsonObject.put("choices", list);
+            }
+        }
+        // 判断是否匹配知识库逻辑
+        if(jsonObject.containsKey("responseData")){
+            // 遍历查找主对话框
+            JSONArray responseData = jsonObject.getJSONArray("responseData");
+            // 筛选出主对话框里面的信息,里面的historyPreview是匹配信息
+            responseData.stream().filter(e -> "主对话框".equals(JSON.parseObject(e.toString()).getString("moduleName"))).findFirst().ifPresent(e -> {
+                // 进入方法证明以及查找主对话框
+                JSONObject eJson = JSON.parseObject(e.toString());
+                // 如果主对话框里面信息为空则不处理
+                if(!eJson.containsKey("historyPreview") || StringUtils.isEmpty(eJson.getString("historyPreview"))) return;
+                // 循环里面的所有数据
+                JSONArray historyPreview = eJson.getJSONArray("historyPreview");
+                // 判断是否包含未匹配信息  -> true:未匹配到知识库  false:已匹配到知识库
+                boolean knowledge = historyPreview.stream().anyMatch(h -> {
+                    JSONObject hJson = JSON.parseObject(h.toString());
+                    return hJson.getString("value").contains("<Data>\n\n</Data>");
+                });
+                // 之所以取反,是为了后面实体类方便查看
+                jsonObject.put("knowledge", !knowledge);
+            });
+        }
+
+
+        if (jsonObject.containsKey("code") && !("200".equals(jsonObject.getString("code")))) {
+            return R.error().put("data", JSON.parseObject(json, KnowledgeBaseResult.class));
+        }
+        if (!param.getDetail() && !param.getStream()){
+
+            ChatDetailFStreamFResult result = jsonObject.toJavaObject(ChatDetailFStreamFResult.class);
+
+            return R.ok().put("data", result);
+        }
+        // flase true 的方式不建议(即stream流的方式),都是输出完才返回,没意义
+        if (!param.getDetail() && param.getStream()){
+
+//            ChatDetailFStreamTResult result = jsonObject.toJavaObject(ChatDetailFStreamTResult.class);
+
+            return R.ok().put("data", json);
+        }
+
+        if (param.getDetail()&&!param.getStream()){
+            ChatDetailTStreamFResult result = jsonObject.toJavaObject(ChatDetailTStreamFResult.class);
+            return R.ok().put("data", result);
+        }
+
+        // true true 的方式不建议(即stream流的方式),都是输出完才返回,没意义
+        if (param.getDetail()&&param.getStream()){
+
+            return R.ok().put("data", json);
+        }
+        return null;
+    }
+
 
 
 

+ 5 - 0
fs-service/src/main/java/com/fs/his/domain/FsCourseCouponUser.java

@@ -43,5 +43,10 @@ public class FsCourseCouponUser extends BaseEntity{
     @Excel(name = "核销状态 0-未核销 1-已核销")
     private Integer status;
 
+    /**
+     * 课程小节ID
+     */
+    private Long videoId;
+
 
 }

+ 17 - 7
fs-service/src/main/java/com/fs/his/domain/FsIntegralCount.java

@@ -1,12 +1,13 @@
 package com.fs.his.domain;
 
-import java.util.Date;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.baomidou.mybatisplus.annotation.TableId;
+
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.fs.common.annotation.Excel;
 import lombok.Data;
-import com.fs.common.core.domain.BaseEntity;
-import lombok.EqualsAndHashCode;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+import java.util.Date;
 
 /**
  * 通用积分消耗退还统计(不含看课领的积分)对象 fs_integral_count
@@ -21,9 +22,17 @@ public class FsIntegralCount{
     private Long id;
 
     /** $column.columnComment */
-    @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
+    @Excel(name = "时间",dateFormat = "yyyy-MM-dd")
     private Date consumptionDate;
 
+    @TableField(exist = false)
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private String beginDate;
+
+    @TableField(exist = false)
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private String endDate;
+
     /** 通用的积分消耗 */
     @Excel(name = "通用的积分消耗")
     private String integralConsume;
@@ -35,5 +44,6 @@ public class FsIntegralCount{
     @Excel(name = "积分类型",dictType="sys_integral_log_type")
     private Integer logType;
 
-
+    @Excel(name = "时间",dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime createTime;
 }

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

@@ -3,6 +3,7 @@ package com.fs.his.mapper;
 import java.util.List;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.fs.his.domain.FsCourseCoupon;
+import org.apache.ibatis.annotations.Select;
 
 /**
  * 课程优惠券Mapper接口
@@ -58,4 +59,7 @@ public interface FsCourseCouponMapper extends BaseMapper<FsCourseCoupon>{
      * @return 结果
      */
     int deleteFsCourseCouponByIds(Long[] ids);
+
+    @Select("SELECT id,title FROM fs_course_coupon WHERE `status` = 1")
+    List<FsCourseCoupon> selectFsCourseCouponOptions();
 }

+ 5 - 0
fs-service/src/main/java/com/fs/his/mapper/FsCourseCouponUserMapper.java

@@ -3,6 +3,8 @@ package com.fs.his.mapper;
 import java.util.List;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.fs.his.domain.FsCourseCouponUser;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
 
 /**
  * 用户看课优惠券Mapper接口
@@ -58,4 +60,7 @@ public interface FsCourseCouponUserMapper extends BaseMapper<FsCourseCouponUser>
      * @return 结果
      */
     int deleteFsCourseCouponUserByIds(Long[] ids);
+
+    @Select("SELECT count(*) FROM fs_course_coupon_user WHERE user_id = #{userId}  AND coupon_id = #{couponId}")
+    Integer selectCountByUserIdAndCouponId(@Param("userId") Long userId,@Param("couponId") Long couponId);
 }

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

@@ -5,6 +5,8 @@ import java.util.Map;
 
 import com.fs.common.core.domain.R;
 import com.fs.his.domain.FsDoctor;
+import com.fs.his.param.DoctorPrescriptionImgLogParam;
+import com.fs.his.param.DoctorPrescriptionParam;
 import com.fs.his.param.FsDoctorListUParam;
 import com.fs.his.param.FsDoctorParam;
 import com.fs.his.vo.*;
@@ -223,4 +225,28 @@ public interface FsDoctorMapper
      */
     List<FsDoctorListUVO> getFsDoctorListUVOListByIds(@Param("doctorIds") List<Long> doctorIds);
     String selectDoctorNameByIds(@Param("doctorIds") String doctorIds);
+
+    Integer selectFsDoctorPrescriptionByCode(@Param("code") String prescriptionCode);
+
+    int insertFsDoctorPrescription(DoctorPrescriptionParam processResult);
+
+    int insertFsDoctorPrescriptionImgLog(DoctorPrescriptionImgLogParam imgLogParam);
+
+    List<DoctorPrescriptionImgLogParam> selectFsDoctorPrescribeImgByDoctorId(DoctorPrescriptionImgLogParam imgLogParam);
+
+    int updateFsDoctorPrescriptionImgLog(DoctorPrescriptionImgLogParam param1);
+
+    List<DoctorPrescriptionImgLogParam> selectAllPrescriptionImgList(@Param("doctorId") String doctorId,@Param("param") DoctorPrescriptionImgLogParam param);
+
+    DoctorPrescriptionParam selectPrescriptionImgInfo(@Param("id") Long prescriptionId);
+
+    int updateFsDoctorPrescription(DoctorPrescriptionParam processResult);
+
+    int updateFsDoctorPrescriptionByLogId(DoctorPrescriptionParam param);
+
+    DoctorPrescriptionParam selectPrescriptionImgInfoByLogId(@Param("logId") Long logId);
+
+    DoctorPrescriptionImgLogParam selectFsDoctorPrescribeImgById(@Param("id") Long imgLogId);
+
+    List<DoctorPrescriptionImgLogParam> selectPrescriptionLogList(@Param("param") DoctorPrescriptionImgLogParam param);
 }

+ 12 - 0
fs-service/src/main/java/com/fs/his/mapper/FsIntegralGoodsMapper.java

@@ -121,4 +121,16 @@ public interface FsIntegralGoodsMapper
     List<FsGoodsVO> getFsGoodsVOListByIds(@Param("goodsIds") List<Long> goodsIds);
 
     List<FsIntegralGoodsVo> selectAllByGoodsIds(@Param("goodsIds") Set<Long> goodsIds);
+
+    /**
+     * 批量更新积分商品信息
+     *
+     * @param goodsIds 商品ID数组
+     * @param integral 所需积分
+     * @param cash 支付金额
+     * @return 结果
+     */
+    int batchUpdateIntegralGoods(@Param("goodsIds") Long[] goodsIds,
+                                 @Param("integral") Long integral,
+                                 @Param("cash") java.math.BigDecimal cash);
 }

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

@@ -123,4 +123,7 @@ public interface FsIntegralOrderMapper extends BaseMapper<FsIntegralOrder>
     List<FsIntegralOrder> findOrderByIds(@Param("orderIds") List<Long> orderIds);
 
     List<FsIntegralOrderListVO> selectFsIntegralOrderListJn(FsIntegralOrderParam fsIntegralOrder);
+
+    @Select("select order_id from fs_integral_order WHERE `status`= 1 and  extend_order_id is null ")
+    List<Long> selectFsStoreOrderNoCreateOms();
 }

+ 5 - 3
fs-service/src/main/java/com/fs/his/mapper/FsUserIntegralLogsMapper.java

@@ -72,9 +72,12 @@ public interface FsUserIntegralLogsMapper
      */
     public int deleteFsUserIntegralLogsByIds(Long[] ids);
     @Select({"<script> " +
-            "select l.*,u.nick_name,u.phone from fs_user_integral_logs l LEFT JOIN fs_user u ON u.user_id=l.user_id "+
+            "select l.id,l.user_id,l.log_type,l.integral,l.balance,l.business_id,l.create_time,l.business_type,l.status,u.nick_name,u.phone " +
+            "from fs_user_integral_logs l " +
+            "LEFT JOIN fs_user u ON u.user_id=l.user_id "+
             " <where>  \n" +
             "            <if test=\"userId != null \"> and l.user_id = #{userId}</if>\n" +
+            "            <if test=\"nick_name != null \"> and u.nick_name = #{nickName}</if>\n" +
             "            <if test=\"logType != null  and logType != ''\"> and log_type = #{logType}</if>\n" +
             "            <if test=\"phone != null \"> and u.phone = #{phone}</if>\n" +
             "            <if test=\"businessId != null  and businessId != ''\"> and business_id = #{businessId}</if>\n" +
@@ -169,8 +172,7 @@ public interface FsUserIntegralLogsMapper
             "SUM(CASE WHEN integral < 0 THEN ABS(integral) ELSE 0 END) AS integral_refund, " +
             "DATE(create_time) AS consumption_date " +
             "FROM fs_user_integral_logs " +
-            "WHERE log_type != 17 " +
-            "AND create_time >= DATE_SUB(CURDATE(), INTERVAL 1 DAY)\n" +
+            "WHERE create_time >= DATE_SUB(CURDATE(), INTERVAL 1 DAY)\n" +
             "  AND create_time < CURDATE() " +
             "GROUP BY log_type, DATE(create_time)")
     List<FsIntegralCount> selectYesterdayIntegralGroupByLogType();

+ 17 - 0
fs-service/src/main/java/com/fs/his/param/CourseFinishRewardParam.java

@@ -0,0 +1,17 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+@Data
+public class CourseFinishRewardParam {
+
+    private Long companyId;
+
+    private Long periodId;
+
+    private Long userId;
+
+    private Long videoId;
+
+
+}

+ 50 - 0
fs-service/src/main/java/com/fs/his/param/DoctorPrescriptionImgLogParam.java

@@ -0,0 +1,50 @@
+package com.fs.his.param;
+
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+public class DoctorPrescriptionImgLogParam extends BaseEntity {
+
+    @Excel(name = "ID")
+    private Long id;
+
+    @Excel(name = "医生id")
+    private Long doctorId;
+
+    @Excel(name = "医生名称")
+    private String doctorName;
+
+    @Excel(name = "图片链接")
+    private String url;
+
+    /**
+     *  状态 0上传成功 1解析成功 2解析失败 3解析中
+     */
+    @Excel(name = "状态 0上传成功 1解析成功 2解析失败 3解析中")
+    private Integer status;
+
+    @Excel(name = "是否删除")
+    private Integer isDel;
+
+    @Excel(name = "备注")
+    private String remark;
+
+    @ApiModelProperty(value = "处方信息对象")
+    private DoctorPrescriptionParam prescription;
+
+    @ApiModelProperty(value = "医生信息对象")
+    private FsDoctorParam doctorInfo;
+
+    @ApiModelProperty(value = "页码,默认为1")
+    private Integer pageNum =1;
+    @ApiModelProperty(value = "页大小,默认为10")
+    private Integer pageSize = 10;
+    @ApiModelProperty(value = "开始时间")
+    private String beginTime;
+    @ApiModelProperty(value = "结束时间")
+    private String endTime;
+
+}

+ 75 - 0
fs-service/src/main/java/com/fs/his/param/DoctorPrescriptionParam.java

@@ -0,0 +1,75 @@
+package com.fs.his.param;
+
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class DoctorPrescriptionParam extends BaseEntity {
+
+    @Excel(name = "ID")
+    private Long id;
+
+    @Excel(name = "是否解析")
+    private Integer isParse;
+
+    @Excel(name = "处方编号")
+    private String prescriptionCode;
+
+    @Excel(name = "年龄")
+    private Integer age;
+
+    @Excel(name = "性别",readConverterExp = "1=男,2=女,0=未知")
+    private Integer sex;
+
+    @NotNull(message = "处方图片不能为空")
+    private String prescriptionImg;
+
+    @Excel(name = "处方信息")
+    private String prescriptionInfo;
+
+    @Excel(name = "主诉")
+    private String chiefComplaint;
+
+    @Excel(name = "现病史")
+    private String historyOfPresentIllness;
+
+    @Excel(name = "既往史")
+    private String pastMedicalHistory;
+
+    @Excel(name = "个人史")
+    private String personalHistory;
+
+    @Excel(name = "婚育史")
+    private String obstetricHistory;
+
+    @Excel(name = "家族史")
+    private String familyHistory;
+
+    @Excel(name = "建议")
+    private String suggest;
+
+    /**
+     * 状态 0=待完善、1=已创建、2=待提交、3=待审核、4=审核通过、5=审核驳回、6=已完成
+     */
+    @Excel(name = "状态",readConverterExp = "状态 0=待完善、1=已创建、2=待提交、3=待审核、4=审核通过、5=审核驳回、6=已完成")
+    private Integer status;
+
+    private Integer isDel;
+
+    @Excel(name = "医生ID")
+    private Long doctorId;
+
+    @Excel(name = "日志ID")
+    private Long logId;
+
+    /*@Excel(name = "备注")
+    private String remark;*/
+
+
+
+
+}

+ 19 - 0
fs-service/src/main/java/com/fs/his/param/FsCourseCouponUserUParam.java

@@ -0,0 +1,19 @@
+package com.fs.his.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+
+@Data
+public class FsCourseCouponUserUParam {
+
+    private Long userId;
+
+    //状态 0-未核销 1-已核销
+    private Integer status;
+
+    @ApiModelProperty(value = "页码,默认为1")
+    private Integer pageNum =1;
+    @ApiModelProperty(value = "页大小,默认为10")
+    private Integer pageSize = 10;
+}

+ 22 - 0
fs-service/src/main/java/com/fs/his/param/FsIntegralGoodsParam.java

@@ -0,0 +1,22 @@
+package com.fs.his.param;
+
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+public class FsIntegralGoodsParam {
+
+     /**
+     * 商品id
+     */
+     private Long[] goodsIds;
+
+     /** 所需积分 */
+     private Long integral;
+
+     /** 支付金额 */
+     private BigDecimal cash;
+
+}

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

@@ -2,6 +2,7 @@ package com.fs.his.service;
 
 import java.util.List;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.common.core.domain.R;
 import com.fs.his.domain.FsCourseCoupon;
 
 /**
@@ -58,4 +59,14 @@ public interface IFsCourseCouponService extends IService<FsCourseCoupon>{
      * @return 结果
      */
     int deleteFsCourseCouponById(Long id);
+
+    List<FsCourseCoupon> selectFsCourseCouponOptions();
+
+    /**
+     * 发送课程优惠券
+     * @param videoId 小节Id
+     * @param userId 用户Id
+     */
+    R sendAutoCourseCoupon(Long videoId, Long userId,Long companyId);
+    R sendCourseCoupon(Long videoId, Long userId,Long companyId,Long periodId);
 }

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

@@ -2,6 +2,7 @@ package com.fs.his.service;
 
 import java.util.List;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.common.core.domain.R;
 import com.fs.his.domain.FsCourseCouponUser;
 
 /**
@@ -58,4 +59,6 @@ public interface IFsCourseCouponUserService extends IService<FsCourseCouponUser>
      * @return 结果
      */
     int deleteFsCourseCouponUserById(Long id);
+
+    R useCoupon(Long userId,Long couponUserId);
 }

+ 27 - 3
fs-service/src/main/java/com/fs/his/service/IFsDoctorService.java

@@ -1,10 +1,10 @@
 package com.fs.his.service;
 
+import com.fs.common.core.domain.R;
 import com.fs.his.domain.FsDoctor;
-import com.fs.his.param.FsDoctorListUParam;
-import com.fs.his.param.FsDoctorParam;
-import com.fs.his.param.FsUpdateFollowParam;
+import com.fs.his.param.*;
 import com.fs.his.vo.*;
+import org.springframework.web.multipart.MultipartFile;
 
 import java.util.List;
 import java.util.Map;
@@ -115,4 +115,28 @@ public interface IFsDoctorService
      * 查询医生选择列表
      */
     List<FsDoctorChooseVO> getChooseDoctorListByMap(Map<String, Object> params);
+
+    R uploadPrescriptionImg(MultipartFile file,String doctorId);
+
+    R cleanPrescriptionImg(String doctorId);
+
+    R selectPrescriptionImgList(String doctorId, DoctorPrescriptionImgLogParam param);
+
+    R selectPrescriptionImgInfo(Long prescriptionId);
+
+    R cleanPrescriptionImgSecond(Long prescriptionId);
+
+    R uploadPrescriptionImg(MultipartFile file, Long logId);
+
+    R deletePrescription(Long imgLogId, Long doctorId);
+
+    R cleanPrescriptionImgOne(Long imgLogId);
+
+    R savePrescriptionInfo(DoctorPrescriptionParam param);
+
+    R commitPrescriptionInfo(DoctorPrescriptionParam param);
+
+    List<DoctorPrescriptionImgLogParam> selectPrescriptionLogList(DoctorPrescriptionImgLogParam param);
+
+    int updateFsDoctorPrescription(DoctorPrescriptionParam param);
 }

+ 9 - 0
fs-service/src/main/java/com/fs/his/service/IFsIntegralGoodsService.java

@@ -3,6 +3,7 @@ package com.fs.his.service;
 import com.fs.common.core.domain.R;
 import com.fs.his.domain.FsIntegralGoods;
 import com.fs.his.param.FsIntegralGoodsListUParam;
+import com.fs.his.param.FsIntegralGoodsParam;
 import com.fs.his.vo.FsIntegralGoodsChooseVO;
 import com.fs.his.vo.FsIntegralGoodsListUVO;
 import com.fs.his.vo.FsIntegralGoodsListVO;
@@ -78,4 +79,12 @@ public interface IFsIntegralGoodsService
      * 获取选择积分商品列表
      */
     List<FsIntegralGoodsChooseVO> getChooseIntegralGoodsListByMap(Map<String, Object> params);
+
+    /**
+     * 批量更新积分商品信息
+     *
+     * @param param 批量更新参数
+     */
+    void batchUpdateIntegralGoods(FsIntegralGoodsParam param);
+
 }

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

@@ -290,4 +290,8 @@ public interface IFsStoreOrderService
     Integer sendGoodsWeizou(FsStoreOrder fsStoreOrder);
 
     BigDecimal selectPayPriceByYear(String userId);
+
+    void weizouPushIntergral(Long l);
+
+    void weizouPushScrm(Long l);
 }

+ 184 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsCourseCouponServiceImpl.java

@@ -1,13 +1,29 @@
 package com.fs.his.service.impl;
 
+import java.math.BigDecimal;
+import java.util.Collections;
+import java.util.Date;
 import java.util.List;
+
+import cn.hutool.json.JSONUtil;
+import com.fs.common.core.domain.R;
 import com.fs.common.utils.DateUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.course.config.CourseConfig;
+import com.fs.course.domain.FsUserCourseVideo;
+import com.fs.course.domain.FsUserCourseVideoRedPackage;
+import com.fs.course.mapper.FsUserCourseVideoMapper;
+import com.fs.course.mapper.FsUserCourseVideoRedPackageMapper;
+import com.fs.his.domain.FsCourseCouponUser;
+import com.fs.his.mapper.FsCourseCouponUserMapper;
+import com.fs.his.vo.CourseFinishRewardVO;
+import com.fs.system.service.ISysConfigService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.fs.his.mapper.FsCourseCouponMapper;
 import com.fs.his.domain.FsCourseCoupon;
 import com.fs.his.service.IFsCourseCouponService;
+import org.springframework.transaction.annotation.Transactional;
 
 /**
  * 课程优惠券Service业务层处理
@@ -18,6 +34,17 @@ import com.fs.his.service.IFsCourseCouponService;
 @Service
 public class FsCourseCouponServiceImpl extends ServiceImpl<FsCourseCouponMapper, FsCourseCoupon> implements IFsCourseCouponService {
 
+    @Autowired
+    private FsCourseCouponUserMapper courseCouponUserMapper;
+
+    @Autowired
+    private FsUserCourseVideoMapper userCourseVideoMapper;
+
+    @Autowired
+    private ISysConfigService configService;
+
+    @Autowired
+    private FsUserCourseVideoRedPackageMapper fsUserCourseVideoRedPackageMapper;
     /**
      * 查询课程优惠券
      * 
@@ -92,4 +119,161 @@ public class FsCourseCouponServiceImpl extends ServiceImpl<FsCourseCouponMapper,
     {
         return baseMapper.deleteFsCourseCouponById(id);
     }
+
+    @Override
+    public List<FsCourseCoupon> selectFsCourseCouponOptions() {
+        return baseMapper.selectFsCourseCouponOptions();
+    }
+
+    //自动
+    @Override
+    @Transactional
+    public R sendAutoCourseCoupon(Long videoId, Long userId,Long companyId) {
+        CourseFinishRewardVO rewardVO = new CourseFinishRewardVO();
+
+        Integer integral = null;
+        BigDecimal amount = null;
+        String couponName = null;
+
+        boolean isSend = true;
+        //课程小节信息
+        FsUserCourseVideo courseVideo = userCourseVideoMapper.selectFsUserCourseVideoByVideoId(videoId);
+        if (courseVideo == null) {
+            return R.error("课程小节不存在");
+        }
+
+        //优惠券
+        FsCourseCoupon fsCourseCoupon = baseMapper.selectFsCourseCouponById(courseVideo.getCourseCouponId());
+        if (fsCourseCoupon != null) {
+            if (fsCourseCoupon.getStatus() != 1) {
+                isSend = false;
+            }
+            if (fsCourseCoupon.getRemainNumber() <= 0) {
+                isSend = false;
+            }
+            //用户领取优惠券总数
+            Integer count = courseCouponUserMapper.selectCountByUserIdAndCouponId(userId, courseVideo.getCourseCouponId());
+            if (count >= fsCourseCoupon.getLimitCount()) {
+                isSend = false;
+            }
+        } else {
+            isSend = false;
+        }
+
+        if (isSend) {
+            //发放优惠券
+            FsCourseCouponUser couponUser = new FsCourseCouponUser();
+            couponUser.setCouponId(courseVideo.getCourseCouponId());
+            couponUser.setUserId(userId);
+            couponUser.setStartTime(new Date());
+            couponUser.setLimitTime(fsCourseCoupon.getLimitTime());
+            couponUser.setCreateTime(new Date());
+            int i = courseCouponUserMapper.insertFsCourseCouponUser(couponUser);
+
+            //返回的优惠券名称
+            couponName = fsCourseCoupon.getTitle();
+            if (i > 0) {
+                FsCourseCoupon coupon = new FsCourseCoupon();
+                coupon.setId(courseVideo.getCourseCouponId());
+                coupon.setRemainNumber(fsCourseCoupon.getRemainNumber() - 1);
+                baseMapper.updateFsCourseCoupon(coupon);
+            }
+        }
+        // 获取配置信息
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        Integer rewardType = config.getRewardType();
+
+        if (rewardType == 1) {
+            FsUserCourseVideoRedPackage redPackage = fsUserCourseVideoRedPackageMapper.selectRedPacketByVideoIdAndType(videoId, companyId, 1);
+            if (redPackage != null && redPackage.getRedPacketMoney() != null) {
+                amount = redPackage.getRedPacketMoney();
+            } else if (courseVideo.getRedPacketMoney() != null) {
+                amount = courseVideo.getRedPacketMoney();
+            }
+        }
+        if (rewardType == 2) {
+            integral = config.getAnswerIntegral();
+        }
+        rewardVO.setCouponName(couponName);
+        rewardVO.setIntegral(integral);
+        rewardVO.setRedPacketMoney(amount);
+        return R.ok().put("data",rewardVO);
+    }
+
+    //手动
+    @Transactional
+    @Override
+    public R sendCourseCoupon(Long videoId, Long userId,Long companyId,Long periodId) {
+        CourseFinishRewardVO rewardVO = new CourseFinishRewardVO();
+
+        Integer integral = null;
+        BigDecimal amount = null;
+        String couponName = null;
+
+        boolean isSend = true;
+        //课程小节信息
+        FsUserCourseVideo courseVideo = userCourseVideoMapper.selectFsUserCourseVideoByVideoId(videoId);
+        if (courseVideo == null) {
+            return R.error("课程小节不存在");
+        }
+
+        //优惠券
+        FsCourseCoupon fsCourseCoupon = baseMapper.selectFsCourseCouponById(courseVideo.getCourseCouponId());
+        if (fsCourseCoupon != null) {
+            if (fsCourseCoupon.getStatus() != 1) {
+                isSend = false;
+            }
+            if (fsCourseCoupon.getRemainNumber() <= 0) {
+                isSend = false;
+            }
+            //用户领取优惠券总数
+            Integer count = courseCouponUserMapper.selectCountByUserIdAndCouponId(userId, courseVideo.getCourseCouponId());
+            if (count >= fsCourseCoupon.getLimitCount()) {
+                isSend = false;
+            }
+        } else {
+            isSend = false;
+        }
+
+        if (isSend) {
+            //发放优惠券
+            FsCourseCouponUser couponUser = new FsCourseCouponUser();
+            couponUser.setCouponId(courseVideo.getCourseCouponId());
+            couponUser.setUserId(userId);
+            couponUser.setStartTime(new Date());
+            couponUser.setLimitTime(fsCourseCoupon.getLimitTime());
+            couponUser.setCreateTime(new Date());
+            int i = courseCouponUserMapper.insertFsCourseCouponUser(couponUser);
+
+            //返回的优惠券名称
+            couponName = fsCourseCoupon.getTitle();
+            if (i > 0) {
+                FsCourseCoupon coupon = new FsCourseCoupon();
+                coupon.setId(courseVideo.getCourseCouponId());
+                coupon.setRemainNumber(fsCourseCoupon.getRemainNumber() - 1);
+                baseMapper.updateFsCourseCoupon(coupon);
+            }
+        }
+        // 获取配置信息
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        Integer rewardType = config.getRewardType();
+
+        if (rewardType == 1) {
+            FsUserCourseVideoRedPackage redPackage = fsUserCourseVideoRedPackageMapper.selectRedPacketByCompanyId(videoId,companyId,periodId);
+            if (redPackage != null && redPackage.getRedPacketMoney() != null) {
+                amount = redPackage.getRedPacketMoney();
+            } else if (courseVideo.getRedPacketMoney() != null) {
+                amount = courseVideo.getRedPacketMoney();
+            }
+        }
+        if (rewardType == 2) {
+            integral = config.getAnswerIntegral();
+        }
+        rewardVO.setCouponName(couponName);
+        rewardVO.setIntegral(integral);
+        rewardVO.setRedPacketMoney(amount);
+        return R.ok().put("data",rewardVO);
+    }
 }

+ 30 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsCourseCouponUserServiceImpl.java

@@ -1,6 +1,10 @@
 package com.fs.his.service.impl;
 
+import java.util.Date;
 import java.util.List;
+import java.util.Objects;
+
+import com.fs.common.core.domain.R;
 import com.fs.common.utils.DateUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -91,4 +95,30 @@ public class FsCourseCouponUserServiceImpl extends ServiceImpl<FsCourseCouponUse
     {
         return baseMapper.deleteFsCourseCouponUserById(id);
     }
+
+    @Override
+    public R useCoupon(Long userId, Long couponUserId) {
+        FsCourseCouponUser couponUser = baseMapper.selectFsCourseCouponUserById(couponUserId);
+        if (couponUser == null) {
+            return R.error("优惠券不存在");
+        }
+        if (couponUser.getStatus() != 0) {
+            return R.error("优惠券已使用");
+        }
+        if (!Objects.equals(couponUser.getUserId(), userId)) {
+            return R.error("优惠券不属于当前用户");
+        }
+        Date now = new Date();
+        if (now.after(couponUser.getLimitTime())) {
+            return R.error("优惠券已过期");
+        }
+        FsCourseCouponUser map = new FsCourseCouponUser();
+        map.setId(couponUser.getCouponId());
+        map.setStatus(1);
+        int i = baseMapper.updateById(map);
+        if (i > 0) {
+            return R.ok("优惠券使用成功");
+        }
+        return R.error("优惠券使用失败");
+    }
 }

+ 684 - 3
fs-service/src/main/java/com/fs/his/service/impl/FsDoctorServiceImpl.java

@@ -3,20 +3,23 @@ package com.fs.his.service.impl;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fs.common.core.domain.R;
 import com.fs.common.enums.ImTypeEnum;
 import com.fs.common.exception.CustomException;
+import com.fs.common.exception.file.OssException;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.SecurityUtils;
 import com.fs.common.utils.sign.Md5Utils;
+import com.fs.fastgptApi.param.ChatImgParam;
+import com.fs.fastgptApi.result.ChatDetailTStreamFResult;
+import com.fs.fastgptApi.service.ChatService;
 import com.fs.his.config.FsSysConfig;
 import com.fs.his.domain.*;
 import com.fs.his.mapper.FsDoctorMapper;
 import com.fs.his.mapper.FsFollowMapper;
 import com.fs.his.mapper.FsFollowTempMapper;
 import com.fs.his.mapper.FsStoreOrderMapper;
-import com.fs.his.param.FsDoctorListUParam;
-import com.fs.his.param.FsDoctorParam;
-import com.fs.his.param.FsUpdateFollowParam;
+import com.fs.his.param.*;
 import com.fs.his.service.IFsDoctorService;
 import com.fs.his.service.IFsPrescribeService;
 import com.fs.his.utils.ConfigUtil;
@@ -32,12 +35,16 @@ import com.fs.system.domain.SysConfig;
 import com.fs.system.mapper.SysConfigMapper;
 import com.fs.system.oss.CloudStorageService;
 import com.fs.system.oss.OSSFactory;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
 import com.google.common.reflect.TypeToken;
 import com.google.gson.Gson;
 import com.google.zxing.WriterException;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
 
 import javax.imageio.ImageIO;
 import java.awt.*;
@@ -78,6 +85,9 @@ public class FsDoctorServiceImpl implements IFsDoctorService
     @Autowired
     private OpenIMService openIMService;
 
+    @Autowired
+    private ChatService chatService;
+
     /**
      * 查询医生管理
      *
@@ -551,4 +561,675 @@ public class FsDoctorServiceImpl implements IFsDoctorService
         return fsDoctorMapper.getChooseDoctorListByMap(params);
     }
 
+    /**
+     * 上传处方图片
+     * @param file
+     * @param doctorId
+     * @return
+     */
+    @Override
+    public R uploadPrescriptionImg(MultipartFile file, String doctorId) {
+        if (file == null) {
+            return R.error("请选择要上传的文件");
+        }
+
+        return uploadSingleFile(file, doctorId);
+
+    }
+
+    /*//上传处方图片
+    @Override
+    public R uploadPrescriptionImg(MultipartFile[] files, String doctorId) {
+        if (files == null || files.length == 0) {
+            return R.error("请选择要上传的文件");
+        }
+
+        List<Map<String, Object>> resultList = new ArrayList<>();
+        int total = files.length;
+        int successCount = 0;
+        int failCount = 0;
+
+        for (MultipartFile file : files) {
+            Map<String, Object> resultMap = uploadSingleFile(file, doctorId);
+            resultList.add(resultMap);
+
+            if ("success".equals(resultMap.get("status"))) {
+                successCount++;
+            } else {
+                failCount++;
+            }
+        }
+
+        return R.ok()
+                .put("total", total)
+                .put("successCount", successCount)
+                .put("failCount", failCount)
+                .put("data", resultList);
+    }*/
+
+    private R uploadSingleFile(MultipartFile file, String doctorId) {
+        Map<String, Object> resultMap = new HashMap<>();
+        String fileName = file.getOriginalFilename();
+        resultMap.put("name", fileName);
+
+        try {
+            //validateFile(file, fileName);
+
+            CloudStorageService storage = OSSFactory.build();
+            String suffix = getFileSuffix(fileName);
+            String url = storage.uploadSuffix(file.getBytes(), suffix);
+
+            DoctorPrescriptionImgLogParam imgLogParam = new DoctorPrescriptionImgLogParam();
+            boolean saveSuccess = savePrescriptionLog(imgLogParam,url, doctorId);
+
+            if (saveSuccess) {
+                resultMap.put("id", imgLogParam.getId());
+                resultMap.put("url", url);
+                return R.ok().put("result",resultMap).put("msg", "图片上传成功!");
+            } else {
+                resultMap.put("id", imgLogParam.getId());
+                resultMap.put("url", "");
+                return R.error().put("result",resultMap).put("msg", "保存记录失败!");
+            }
+        } catch (OssException e) {
+            log.error("图片格式或内容校验失败:{}", fileName, e);
+            resultMap.put("url", "");
+            return R.error().put("result",resultMap).put("msg", e.getMessage());
+        } catch (IOException e) {
+            log.error("读取文件失败:{}", fileName, e);
+            resultMap.put("url", "");
+            return R.error().put("result",resultMap).put("msg", "文件读取失败!");
+        } catch (Exception e) {
+            log.error("图片上传失败:{}", fileName, e);
+            resultMap.put("url", "");
+            resultMap.put("msg", "");
+            return R.error().put("result",resultMap).put("msg", "图片上传失败!");
+        }
+    }
+
+    private void validateFile(MultipartFile file, String fileName) throws OssException {
+        if (file.isEmpty()) {
+            throw new OssException("上传文件不能为空");
+        }
+
+        if (fileName == null || fileName.isEmpty()) {
+            throw new OssException("文件名不能为空");
+        }
+
+        String suffix = getFileSuffix(fileName).toLowerCase();
+        if (!isValidImageType(suffix)) {
+            throw new OssException("只支持上传图片格式(jpg、png、gif、bmp)");
+        }
+
+        long fileSize = file.getSize();
+        if (fileSize > 10 * 1024 * 1024) {
+            throw new OssException("文件大小不能超过10MB");
+        }
+    }
+
+    private String getFileSuffix(String fileName) {
+        int lastDotIndex = fileName.lastIndexOf(".");
+        if (lastDotIndex > 0 && lastDotIndex < fileName.length() - 1) {
+            return fileName.substring(lastDotIndex);
+        }
+        return "";
+    }
+
+    private boolean isValidImageType(String suffix) {
+        return ".jpg".equals(suffix) || ".jpeg".equals(suffix)
+                || ".png".equals(suffix) || ".gif".equals(suffix)
+                || ".bmp".equals(suffix) || ".webp".equals(suffix);
+    }
+
+    private boolean savePrescriptionLog(DoctorPrescriptionImgLogParam imgLogParam,String url, String doctorId) {
+        try {
+            imgLogParam.setDoctorId(Long.parseLong(doctorId));
+            imgLogParam.setUrl(url);
+            imgLogParam.setStatus(0);
+
+            int insertResult = fsDoctorMapper.insertFsDoctorPrescriptionImgLog(imgLogParam);
+
+            if (insertResult != 1) {
+                log.error("插入处方图片日志失败,doctorId: {}, url: {}", doctorId, url);
+                return false;
+            }
+
+            DoctorPrescriptionParam prescriptionParam = new DoctorPrescriptionParam();
+            prescriptionParam.setPrescriptionImg(url);
+            prescriptionParam.setDoctorId(Long.parseLong(doctorId));
+            prescriptionParam.setIsParse(0);
+            prescriptionParam.setStatus(0);
+            prescriptionParam.setLogId(imgLogParam.getId());
+
+            int prescriptionResult = fsDoctorMapper.insertFsDoctorPrescription(prescriptionParam);
+
+            if (prescriptionResult != 1) {
+                log.error("插入处方记录失败,logId: {}, url: {}", imgLogParam.getId(), url);
+                return false;
+            }
+
+            return true;
+        } catch (NumberFormatException e) {
+            log.error("医生ID格式错误:{}", doctorId, e);
+            return false;
+        } catch (Exception e) {
+            log.error("保存处方记录异常,doctorId: {}, url: {}", doctorId, url, e);
+            return false;
+        }
+    }
+
+
+    /**
+     * 解析处方图片
+     */
+    @Override
+    public R cleanPrescriptionImg(String doctorId) {
+        List<Map<String, Object>> resultList = new ArrayList<>();
+        DoctorPrescriptionImgLogParam imgLogParam = new DoctorPrescriptionImgLogParam();
+        imgLogParam.setDoctorId(Long.parseLong(doctorId));
+        imgLogParam.setStatus(1);
+        List<DoctorPrescriptionImgLogParam> paramList = fsDoctorMapper.selectFsDoctorPrescribeImgByDoctorId(imgLogParam);
+
+        if (paramList == null || paramList.isEmpty()) {
+            return R.error("请先上传能解析的图片")
+                    .put("data", resultList);
+        }
+
+        int total = paramList.size();
+        int successCount = 0;
+        int failCount = 0;
+
+        for (DoctorPrescriptionImgLogParam logParam : paramList) {
+            Map<String, Object> resultMap = processSingleImage(logParam, doctorId);
+            resultList.add(resultMap);
+
+            if ((Boolean) resultMap.get("status")) {
+                successCount++;
+            } else {
+                failCount++;
+            }
+        }
+
+        return R.ok()
+                .put("total", total)
+                .put("successCount", successCount)
+                .put("failCount", failCount)
+                .put("data", resultList);
+    }
+
+    private Map<String, Object> processSingleImage(DoctorPrescriptionImgLogParam logParam, String doctorId) {
+        Map<String, Object> resultMap = new HashMap<>();
+        String url = logParam.getUrl();
+        resultMap.put("url", url);
+
+        DoctorPrescriptionImgLogParam updateParam = new DoctorPrescriptionImgLogParam();
+        updateParam.setId(logParam.getId());
+        updateParam.setStatus(3);
+        updateParam.setRemark("图像解析中...");
+        fsDoctorMapper.updateFsDoctorPrescriptionImgLog(updateParam);
+
+        try {
+            DoctorPrescriptionParam processResult = imageProcess(url, doctorId);
+            processResult.setLogId(logParam.getId());
+
+            if (processResult.getIsParse() != 1 || processResult.getPrescriptionCode() == null) {
+                updateParam.setStatus(2);
+                updateParam.setRemark("图像解析失败,请重新上传!");
+                resultMap.put("status", false);
+                resultMap.put("result", "图像解析失败,请重新上传!");
+            } else {
+                Integer existCount = fsDoctorMapper.selectFsDoctorPrescriptionByCode(processResult.getPrescriptionCode());
+                if (existCount >= 1) {
+                    updateParam.setStatus(2);
+                    updateParam.setRemark("处方单号已存在,请重新上传!");
+                    resultMap.put("status", false);
+                    resultMap.put("result", "处方单号已存在,请重新上传!");
+                } else {
+                    boolean saveSuccess = savePrescription(processResult, logParam.getId());
+                    if (saveSuccess) {
+                        updateParam.setStatus(1);
+                        updateParam.setRemark("解析成功");
+                        resultMap.put("status", true);
+                        resultMap.put("result", processResult);
+                    } else {
+                        updateParam.setStatus(2);
+                        updateParam.setRemark("保存失败,请重新解析!");
+                        resultMap.put("status", false);
+                        resultMap.put("result", "保存失败,请重新解析!");
+                    }
+                }
+            }
+        } catch (Exception e) {
+            updateParam.setStatus(2);
+            updateParam.setRemark("处理异常:" + e.getMessage());
+            resultMap.put("status", false);
+            resultMap.put("result", "处理异常,请稍后重试!");
+        }
+
+        fsDoctorMapper.updateFsDoctorPrescriptionImgLog(updateParam);
+        return resultMap;
+    }
+
+    private boolean savePrescription(DoctorPrescriptionParam processResult, Long logId) {
+        DoctorPrescriptionParam existingParam = fsDoctorMapper.selectPrescriptionImgInfoByLogId(logId);
+
+        if (existingParam != null) {
+            processResult.setId(existingParam.getId());
+            processResult.setStatus(0);
+            return fsDoctorMapper.updateFsDoctorPrescription(processResult) > 0;
+        } else {
+            processResult.setStatus(0);
+            return fsDoctorMapper.insertFsDoctorPrescription(processResult) > 0;
+        }
+    }
+
+
+    @Override
+    public R selectPrescriptionImgList(String doctorId, DoctorPrescriptionImgLogParam param) {
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<DoctorPrescriptionImgLogParam> param1 = fsDoctorMapper.selectAllPrescriptionImgList(doctorId,param);
+        return R.ok().put("result",new PageInfo<>(param1));
+    }
+
+    @Override
+    public R selectPrescriptionImgInfo(Long imgLogId) {
+        DoctorPrescriptionParam param = fsDoctorMapper.selectPrescriptionImgInfoByLogId(imgLogId);
+        return R.ok().put("result",param);
+    }
+
+    @Override
+    public R cleanPrescriptionImgSecond(Long prescriptionId) {
+        if (prescriptionId == null) {
+            return R.error("处方ID不能为空");
+        }
+
+        DoctorPrescriptionParam param = fsDoctorMapper.selectPrescriptionImgInfo(prescriptionId);
+        if (param == null) {
+            return R.error("未找到对应的处方记录");
+        }
+
+        String url = param.getPrescriptionImg();
+        if (url == null || url.isEmpty()) {
+            return R.error("处方图片不存在");
+        }
+
+        Map<String, Object> resultMap = reprocessPrescriptionImage(param, url);
+        return R.ok().put("data", resultMap);
+    }
+
+    private Map<String, Object> reprocessPrescriptionImage(DoctorPrescriptionParam prescriptionParam, String url) {
+        Map<String, Object> resultMap = new HashMap<>();
+        resultMap.put("url", url);
+
+        DoctorPrescriptionImgLogParam logUpdateParam = new DoctorPrescriptionImgLogParam();
+        logUpdateParam.setId(prescriptionParam.getLogId());
+
+        try {
+            DoctorPrescriptionParam processResult = imageProcess(url, String.valueOf(prescriptionParam.getDoctorId()));
+
+            if (processResult.getIsParse() != 1 || processResult.getPrescriptionCode() == null) {
+                updateLogStatus(logUpdateParam, 2, "图像解析失败,请重新上传!");
+                resultMap.put("status", false);
+                resultMap.put("result", "图像解析失败,请重新上传!");
+            } else {
+                handleParsedPrescription(processResult, logUpdateParam, resultMap);
+            }
+        } catch (Exception e) {
+            log.error("重新解析处方图片失败,prescriptionId: {}", prescriptionParam.getId(), e);
+            updateLogStatus(logUpdateParam, 2, "解析异常:" + e.getMessage());
+            resultMap.put("status", false);
+            resultMap.put("result", "解析异常,请稍后重试!");
+        }
+
+        return resultMap;
+    }
+
+    private void handleParsedPrescription(DoctorPrescriptionParam processResult,
+                                          DoctorPrescriptionImgLogParam logUpdateParam,
+                                          Map<String, Object> resultMap) {
+        Integer existCount = fsDoctorMapper.selectFsDoctorPrescriptionByCode(processResult.getPrescriptionCode());
+        DoctorPrescriptionParam param = fsDoctorMapper.selectPrescriptionImgInfoByLogId(logUpdateParam.getId());
+        boolean status = param != null && !processResult.getPrescriptionCode().equals(param.getPrescriptionCode()) && param.getIsDel() == 0;
+        if (existCount >= 1 && status) {
+            updateLogStatus(logUpdateParam, 2, "处方单号已存在,请重新上传!");
+            resultMap.put("status", false);
+            resultMap.put("result", "处方单号已存在,请重新上传!");
+        } else {
+            processResult.setLogId(logUpdateParam.getId());
+            resultMap.put("status", true);
+            resultMap.put("result", processResult);
+
+            /*boolean saveSuccess = saveNewPrescription(processResult);
+            if (saveSuccess) {
+                updateLogStatus(logUpdateParam, 1, "解析成功");
+                resultMap.put("status", true);
+                resultMap.put("result", processResult);
+            } else {
+                updateLogStatus(logUpdateParam, 2, "保存失败,请重新解析!");
+                resultMap.put("status", false);
+                resultMap.put("result", "保存失败,请重新解析!");
+            }*/
+        }
+    }
+
+    private boolean saveNewPrescription(DoctorPrescriptionParam processResult) {
+        try {
+            processResult.setStatus(0);
+            int updated = fsDoctorMapper.updateFsDoctorPrescriptionByLogId(processResult);
+            return updated > 0;
+        } catch (Exception e) {
+            log.error("保存新处方记录失败,处方号: {}", processResult.getPrescriptionCode(), e);
+            return false;
+        }
+    }
+
+    @Override
+    public R uploadPrescriptionImg(MultipartFile file, Long logId) {
+        if (file == null || file.isEmpty()) {
+            return R.error("上传文件不能为空");
+        }
+
+        if (logId == null) {
+            return R.error("日志ID不能为空");
+        }
+
+
+        Map<String, Object> resultMap = uploadAndUpdateSingleFile(file, logId);
+
+        if ("success".equals(resultMap.get("status"))) {
+            return R.ok().put("data", resultMap);
+        } else {
+            return R.error((String) resultMap.get("message")).put("data", resultMap);
+        }
+    }
+
+    private Map<String, Object> uploadAndUpdateSingleFile(MultipartFile file, Long logId) {
+        Map<String, Object> resultMap = new HashMap<>();
+        String fileName = file.getOriginalFilename();
+        resultMap.put("name", fileName);
+
+        try {
+            validateFile(file, fileName);
+
+            CloudStorageService storage = OSSFactory.build();
+            String suffix = getFileSuffix(fileName);
+            String url = storage.uploadSuffix(file.getBytes(), suffix);
+
+            boolean updateSuccess = updatePrescriptionWithNewImage(url, logId);
+
+            if (updateSuccess) {
+                resultMap.put("id", logId);
+                resultMap.put("status", "success");
+                resultMap.put("url", url);
+                resultMap.put("message", "图片上传成功!");
+            } else {
+                resultMap.put("id", 0);
+                resultMap.put("status", "error");
+                resultMap.put("url", "");
+                resultMap.put("message", "更新记录失败!");
+            }
+        } catch (OssException e) {
+            log.error("图片格式或内容校验失败:{}", fileName, e);
+            resultMap.put("id", 0);
+            resultMap.put("status", "error");
+            resultMap.put("url", "");
+            resultMap.put("message", e.getMessage());
+        } catch (IOException e) {
+            log.error("读取文件失败:{}", fileName, e);
+            resultMap.put("id", 0);
+            resultMap.put("status", "error");
+            resultMap.put("url", "");
+            resultMap.put("message", "文件读取失败!");
+        } catch (Exception e) {
+            log.error("图片上传失败:{}", fileName, e);
+            resultMap.put("id", 0);
+            resultMap.put("status", "error");
+            resultMap.put("url", "");
+            resultMap.put("message", "图片上传失败!");
+        }
+
+        return resultMap;
+    }
+
+    private boolean updatePrescriptionWithNewImage(String url, Long logId) {
+        try {
+            DoctorPrescriptionImgLogParam imgLogParam = new DoctorPrescriptionImgLogParam();
+            imgLogParam.setUrl(url);
+            imgLogParam.setId(logId);
+
+            int logUpdateResult = fsDoctorMapper.updateFsDoctorPrescriptionImgLog(imgLogParam);
+            if (logUpdateResult != 1) {
+                log.error("更新处方图片日志失败,logId: {}, url: {}", logId, url);
+                return false;
+            }
+
+            DoctorPrescriptionParam prescriptionParam = new DoctorPrescriptionParam();
+            prescriptionParam.setPrescriptionImg(url);
+            prescriptionParam.setLogId(logId);
+            prescriptionParam.setIsParse(0);
+
+            int prescriptionUpdateResult = fsDoctorMapper.updateFsDoctorPrescriptionByLogId(prescriptionParam);
+            if (prescriptionUpdateResult < 1) {
+                log.error("更新处方记录失败,logId: {}, url: {}", logId, url);
+                return false;
+            }
+
+            return true;
+        } catch (Exception e) {
+            log.error("更新处方记录异常,logId: {}, url: {}", logId, url, e);
+            return false;
+        }
+    }
+
+    private void updateLogStatus(DoctorPrescriptionImgLogParam logParam, Integer status, String remark) {
+        logParam.setStatus(status);
+        logParam.setRemark(remark);
+        fsDoctorMapper.updateFsDoctorPrescriptionImgLog(logParam);
+    }
+
+
+    // 自定义图片处理方法
+    private DoctorPrescriptionParam imageProcess(String url,String doctorId) {
+        ChatImgParam param=new ChatImgParam();
+        param.setChatId(doctorId);
+        param.setStream(false);
+        param.setDetail(true);
+        List<ChatImgParam.Message> messageList=new ArrayList<ChatImgParam.Message>();
+        ChatImgParam.Message message = new ChatImgParam.Message();
+        message.setRole("user");
+        List<ChatImgParam.Message.content> contents = new ArrayList<>();
+
+        ChatImgParam.Message.content content = new ChatImgParam.Message.content();
+        content.setType("text");
+        content.setText("请根据提示词识别图片内容");
+        contents.add(content);
+
+        //设置上传的图片
+        ChatImgParam.Message.content contentImg = new ChatImgParam.Message.content();
+        contentImg.setType("image_url");
+        ChatImgParam.Message.ImageUrl imageUrl = new ChatImgParam.Message.ImageUrl();
+        imageUrl.setUrl(url);
+        contentImg.setImage_url(imageUrl);
+        contents.add(contentImg);
+
+        message.setContent(contents);
+        messageList.add(message);
+        param.setMessages(messageList);
+
+        R r = chatService.initiatingTakeChatNew(param, "http://129.28.170.206:3000/api", "fastgpt-t3Z1s8Lb6pKMILsSNUHDCOZ4PWgcRlwcWJT7DvrxtvqJfyZbEyWLqS8Up");
+        if(!r.get("code").equals(200)){
+            DoctorPrescriptionParam doctorPrescriptionParam = new DoctorPrescriptionParam();
+            doctorPrescriptionParam.setIsParse(0);
+            return doctorPrescriptionParam;
+        }
+        ChatDetailTStreamFResult result=(ChatDetailTStreamFResult)r.get("data");
+
+        String contentKh = result.getChoices().get(0).getMessage().getContent();
+        System.out.println("模型解析图片结果:"+contentKh);
+        Gson gson = new Gson();
+        DoctorPrescriptionParam fromJson = gson.fromJson(contentKh, DoctorPrescriptionParam.class);
+        fromJson.setPrescriptionImg(url);
+        fromJson.setDoctorId(Long.parseLong(doctorId));
+        return fromJson;
+    }
+
+    @Override
+    @Transactional
+    public R deletePrescription(Long imgLogId, Long doctorId) {
+        DoctorPrescriptionParam param = fsDoctorMapper.selectPrescriptionImgInfoByLogId(imgLogId);
+        if(param == null || param.getId()==null){
+            return R.error("未找到对应的处方记录");
+        }
+        Long prescriptionId = param.getId();
+
+        if (doctorId == null) {
+            return R.error("医生ID不能为空");
+        }
+
+        DoctorPrescriptionParam prescription = fsDoctorMapper.selectPrescriptionImgInfo(prescriptionId);
+        if (prescription == null) {
+            return R.error("未找到对应的处方记录");
+        }
+
+        if (!prescription.getDoctorId().equals(doctorId)) {
+            return R.error("无权删除该处方记录");
+        }
+
+        if (prescription.getIsDel() != null && prescription.getIsDel() == 1) {
+            return R.error("该处方已被删除");
+        }
+
+        Integer status = prescription.getStatus();
+        if (status != null && (status == 3 || status == 4 || status == 6)) {
+            String statusMsg = getStatusDescription(status);
+            return R.error("当前处方状态为" + statusMsg + ",不允许删除");
+        }
+
+        try {
+            DoctorPrescriptionParam updateParam = new DoctorPrescriptionParam();
+            updateParam.setId(prescriptionId);
+            updateParam.setIsDel(1);
+            int prescriptionResult = fsDoctorMapper.updateFsDoctorPrescription(updateParam);
+
+            if (prescriptionResult <= 0) {
+                log.error("软删除处方记录失败,prescriptionId: {}", prescriptionId);
+                return R.error("删除处方记录失败");
+            }
+
+            if (prescription.getLogId() != null) {
+                DoctorPrescriptionImgLogParam logUpdateParam = new DoctorPrescriptionImgLogParam();
+                logUpdateParam.setId(prescription.getLogId());
+                logUpdateParam.setIsDel(1);
+                int logResult = fsDoctorMapper.updateFsDoctorPrescriptionImgLog(logUpdateParam);
+
+                if (logResult <= 0) {
+                    log.warn("更新处方图片日志状态失败,logId: {}", prescription.getLogId());
+                }
+            }
+
+            log.info("成功删除处方记录,prescriptionId: {}, doctorId: {}", prescriptionId, doctorId);
+            return R.ok("删除成功");
+        } catch (Exception e) {
+            log.error("删除处方记录异常,prescriptionId: {}", prescriptionId, e);
+            throw new RuntimeException("删除处方记录失败");
+        }
+    }
+
+    @Override
+    public R cleanPrescriptionImgOne(Long imgLogId) {
+        DoctorPrescriptionParam param = fsDoctorMapper.selectPrescriptionImgInfoByLogId(imgLogId);
+        if(param == null || param.getId()==null){
+            return R.error("未找到对应的处方记录");
+        }
+        return this.cleanPrescriptionImgSecond(param.getId());
+    }
+
+    @Override
+    public R savePrescriptionInfo(DoctorPrescriptionParam param) {
+        Map<String, Object> resultMap = new HashMap<>();
+        Integer existCount = fsDoctorMapper.selectFsDoctorPrescriptionByCode(param.getPrescriptionCode());
+        DoctorPrescriptionParam paramDb = fsDoctorMapper.selectPrescriptionImgInfoByLogId(param.getId());
+        boolean status1 = paramDb != null && !param.getPrescriptionCode().equals(paramDb.getPrescriptionCode()) && paramDb.getIsDel() == 0;
+        if (existCount >= 1 && status1) {
+            DoctorPrescriptionImgLogParam imgLogParam = new DoctorPrescriptionImgLogParam();
+            imgLogParam.setId(param.getLogId());
+            updateLogStatus(imgLogParam, 2, "处方单号已存在,请重新上传!");
+            resultMap.put("status", false);
+            resultMap.put("result", "处方单号已存在,请重新上传!");
+        }
+
+        Integer status = param.getStatus();
+        if(status == 0){
+            int i = fsDoctorMapper.updateFsDoctorPrescriptionByLogId(param);
+            if(i <= 0){
+                resultMap.put("msg", "暂存处方信息失败");
+                return R.error().put("result", resultMap);
+            }
+            resultMap.put("msg", "暂存处方信息成功");
+            return R.ok().put("result", resultMap);
+        }else if(status == 1){
+            if(param.getPrescriptionCode() == null){
+                resultMap.put("msg", "处方单号未填,请重新上传!");
+                return R.error().put("result", resultMap);
+            }
+            if(param.getAge() == null){
+                resultMap.put("msg", "年龄未填,请重新上传!");
+                return R.error().put("result", resultMap);
+            }
+            if(param.getSex() == null){
+                resultMap.put("msg", "性别未填,请重新上传!");
+                return R.error().put("result", resultMap);
+            }
+            if(param.getChiefComplaint() == null){
+                resultMap.put("msg", "主诉未填,请重新上传!");
+                return R.error().put("result", resultMap);
+            }
+            if(param.getHistoryOfPresentIllness() == null){
+                resultMap.put("msg", "现病史未填,请重新上传!");
+                return R.error().put("result", resultMap);
+            }
+            if(param.getSuggest() == null){
+                resultMap.put("msg", "医生建议未填,请重新上传!");
+                return R.error().put("result", resultMap);
+            }
+            if(param.getPrescriptionInfo() == null){
+                resultMap.put("msg", "处方信息未填,请重新上传!");
+                return R.error().put("result", resultMap);
+            }
+            fsDoctorMapper.updateFsDoctorPrescriptionByLogId(param);
+            resultMap.put("msg", "保存处方信息成功");
+            return R.ok().put("result", resultMap);
+        }
+        return null;
+    }
+
+    @Override
+    public R commitPrescriptionInfo(DoctorPrescriptionParam param) {
+        int i = fsDoctorMapper.updateFsDoctorPrescriptionByLogId(param);
+        boolean status = i > 0;
+        return R.ok().put("success", status);
+    }
+
+    @Override
+    public List<DoctorPrescriptionImgLogParam> selectPrescriptionLogList(DoctorPrescriptionImgLogParam param) {
+        return fsDoctorMapper.selectPrescriptionLogList(param);
+    }
+
+    @Override
+    public int updateFsDoctorPrescription(DoctorPrescriptionParam param) {
+        return fsDoctorMapper.updateFsDoctorPrescriptionByLogId(param);
+    }
+
+    private String getStatusDescription(Integer status) {
+        switch (status) {
+            case 3:
+                return "待审核";
+            case 4:
+                return "审核通过";
+            case 6:
+                return "已完成";
+            default:
+                return "状态" + status;
+        }
+    }
 }

+ 22 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsIntegralGoodsServiceImpl.java

@@ -282,4 +282,26 @@ public class FsIntegralGoodsServiceImpl implements IFsIntegralGoodsService
     public List<FsIntegralGoodsChooseVO> getChooseIntegralGoodsListByMap(Map<String, Object> params) {
         return fsIntegralGoodsMapper.getChooseIntegralGoodsListByMap(params);
     }
+
+    /**
+     * 批量更新积分商品信息
+     *
+     * @param param 批量更新参数
+     */
+    @Override
+    public void batchUpdateIntegralGoods(com.fs.his.param.FsIntegralGoodsParam param) {
+        if (param.getGoodsIds() == null || param.getGoodsIds().length == 0) {
+            throw new ServiceException("请选择要更新的商品");
+        }
+
+        int result = fsIntegralGoodsMapper.batchUpdateIntegralGoods(
+                param.getGoodsIds(),
+                param.getIntegral(),
+                param.getCash()
+        );
+
+        if (result <= 0) {
+            throw new ServiceException("批量更新失败");
+        }
+    }
 }

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

@@ -59,9 +59,10 @@ import com.fs.his.service.*;
 import com.fs.his.utils.ConfigUtil;
 import com.fs.his.utils.PhoneUtil;
 import com.fs.his.vo.*;
+import com.fs.hisStore.domain.FsStoreOrderLogsScrm;
 import com.fs.hisStore.domain.FsStoreOrderScrm;
-import com.fs.hisStore.mapper.FsStoreOrderScrmMapper;
-import com.fs.hisStore.mapper.FsStorePaymentScrmMapper;
+import com.fs.hisStore.domain.FsStoreProductScrm;
+import com.fs.hisStore.mapper.*;
 import com.fs.hisStore.param.FsStoreOrderRefundByProductParam;
 import com.fs.hisStore.service.IFsStoreOrderLogsScrmService;
 import com.fs.hisStore.service.IFsStoreOrderScrmService;
@@ -131,6 +132,7 @@ import java.text.SimpleDateFormat;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
+import java.util.concurrent.CompletableFuture;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
@@ -328,6 +330,21 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
     private IFsStoreOrderScrmService orderScrmService;
     @Autowired
     private IFsStoreProductService fsStoreProductService;
+    @Autowired
+    private FsIntegralOrderMapper fsIntegralOrderMapper;
+    @Autowired
+    private FsIntegralGoodsMapper fsIntegralGoodsMapper;
+    @Autowired
+    private FsStoreOrderScrmMapper fsStoreOrderScrmMapper;
+    @Autowired
+    private FsStoreOrderItemScrmMapper fsStoreOrderItemScrmMapper;
+    @Autowired
+    private FsStoreProductScrmMapper fsStoreProductScrmMapper;
+    @Autowired
+    private FsIntegralOrderLogsMapper fsIntegralOrderLogsMapper;
+    @Autowired
+    private FsStoreOrderLogsScrmMapper fsStoreOrderLogsScrmMapper;
+
     @PostConstruct
     public void initErpServiceMap() {
         erpServiceMap = new HashMap<>();
@@ -4634,7 +4651,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         if (order.getShippingType() != null && order.getShippingType() == 2)return;
         WeizouApiPushOrderParam param = new WeizouApiPushOrderParam();
         param.setRealName(order.getUserName()).setPhone(order.getUserPhone().length() > 11 ? decryptPhone(order.getUserPhone()) : order.getUserPhone())
-                .setFreightPrice(order.getFreightPrice()).setExtendOrderId(order.getOrderId().toString())
+                .setFreightPrice(order.getFreightPrice()).setExtendOrderId(order.getOrderCode())
         ;
         //全款
         if (order.getPayType().equals(1)) {
@@ -4684,7 +4701,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
 
             } else {
                 param.setProvince(address[0]).setCity(address[1]).setDistrict(address[2]);
-                //处理地址多空问题
+                //处理地址多空问题
                 if (address.length > 3) {
                     StringBuffer addrs = new StringBuffer();
                     for (int i = 3; i < address.length; i++) {
@@ -4717,13 +4734,23 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         // 1. 参数校验
 //        validateSendGoodsParams(fsStoreOrder, opeName);//controller处理了
 
-        // 2. 查询原始订单
-        FsStoreOrder originalOrder = fsStoreOrderMapper.selectFsStoreOrderByOrderId(fsStoreOrder.getOrderId());
+
+        Object originalOrder = findFirstNonNull(
+                CompletableFuture.supplyAsync(() ->
+                        fsStoreOrderMapper.selectFsStoreOrderByOrderCode(fsStoreOrder.getOrderCode())
+                ),
+                CompletableFuture.supplyAsync(() ->
+                        fsStoreOrderMapper.selectFsStoreOrderScrmByOrderCode(fsStoreOrder.getOrderCode())
+                ),
+                CompletableFuture.supplyAsync(() ->
+                        fsIntegralOrderMapper.selectFsIntegralOrderByOrderCode(fsStoreOrder.getOrderCode())
+                )
+        );
+
         if (originalOrder == null) {
             throw new CustomException("订单不存在");
         }
 
-        // 3. 根据操作类型分发处理
         if (OPERATOR_CANCEL.equals(fsStoreOrder.getOperator())) {
             return processCancelDelivery(originalOrder, fsStoreOrder, "微走取消订单");
         }
@@ -4733,57 +4760,124 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
             return processUpdateDelivery(originalOrder, fsStoreOrder, "微走订单更新");        }
     }
 
-    /**
-     * 处理订单状态更新//todo 到货后续业务逻辑需要对接
-     */
-    private int processUpdateDelivery(FsStoreOrder originalOrder, FsStoreOrder fsStoreOrder, String opeName) {
-        //微走有多个状态,需要分别记录
-        if (originalOrder.getStatus() == STATUS_SHIPPED) {
-            updateOrderToEvaluated(fsStoreOrder);
+    @SafeVarargs
+    private final <T> T findFirstNonNull(CompletableFuture<? extends T>... futures) {
+        CompletableFuture.allOf(futures).join();
+        for (CompletableFuture<? extends T> future : futures) {
+            try {
+                T result = future.get();
+                if (result != null) {
+                    return result;
+                }
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
         }
+        return null;
+    }
 
-        // 记录日志
-        log.info("微走快递送达, 订单号: {}",
-                fsStoreOrder.getOrderId());
-        return saveOrderLog(fsStoreOrder, WeizouOrderExpressEnum.getDescByCode(fsStoreOrder.getOperator()), opeName);
+    private int processUpdateDelivery(Object order, FsStoreOrder fsStoreOrder, String opeName) {
+        OrderLogSaver logSaver = dispatchUpdate(order, fsStoreOrder);
+        log.info("微走快递送达, 订单号: {}", fsStoreOrder.getOrderId());
+        return logSaver.save(fsStoreOrder, WeizouOrderExpressEnum.getDescByCode(fsStoreOrder.getOperator()), opeName);
     }
     /**
      * 处理取消发货
      */
-    private int processCancelDelivery(FsStoreOrder originalOrder, FsStoreOrder fsStoreOrder, String opeName) {
-        // 待发货状态才更新订单状态
-        if (originalOrder.getStatus() == STATUS_PENDING_SHIPMENT) {
-            updateOrderToCancelled(fsStoreOrder);
-        }
-
-        // 调用退款服务
-//        SpringUtils.getBean(IFsStoreOrderScrmService.class).refundOrder(fsStoreOrder.getOrderId());//todo 推给售后
-
-        // 记录日志
-        log.info("微走取消发货, 订单号: {}",
-                fsStoreOrder.getOrderId());
-
-        return saveOrderLog(fsStoreOrder, fsStoreOrder.getOperator(), opeName);
+    private int processCancelDelivery(Object order, FsStoreOrder fsStoreOrder, String opeName) {
+        OrderLogSaver logSaver = dispatchCancel(order, fsStoreOrder);
+        log.info("微走取消发货, 订单号: {}", fsStoreOrder.getOrderId());
+        return logSaver.save(fsStoreOrder, fsStoreOrder.getOperator(), opeName);
     }
 
     /**
      * 处理正常发货/修改快递
      */
-    private int processNormalDelivery(FsStoreOrder originalOrder, FsStoreOrder fsStoreOrder, String opeName) {
-        int result;
+    private int processNormalDelivery(Object order, FsStoreOrder fsStoreOrder, String opeName) {
+        if (order instanceof FsStoreOrder) {
+            FsStoreOrder o = (FsStoreOrder) order;
+            fsStoreOrder.setOrderId(o.getOrderId());
+            if (o.getStatus() == STATUS_PENDING_SHIPMENT) {
+                executeShipOrder(o, fsStoreOrder, opeName);
+            } else {
+                updateDeliveryInfo(o, fsStoreOrder, opeName);
+            }
+
+        }else
+        if (order instanceof FsStoreOrderScrm) {
+            FsStoreOrderScrm o = (FsStoreOrderScrm) order;
+            fsStoreOrder.setOrderId(o.getId());
+            if (o.getStatus() == STATUS_PENDING_SHIPMENT) {
+                executeShipOrderScrm(o, fsStoreOrder, opeName);
+            } else {
+                updateDeliveryInfoScrm(o, fsStoreOrder, opeName);
+            }
+
+        }else{
+            FsIntegralOrder o = (FsIntegralOrder) order;
+            fsStoreOrder.setOrderId(o.getOrderId());
+            if (o.getStatus() == STATUS_PENDING_SHIPMENT) {
+                executeShipOrderIntegral(o, fsStoreOrder, opeName);
+            } else {
+                updateDeliveryInfoIntegral(o, fsStoreOrder, opeName);
+            }
 
-        if (originalOrder.getStatus() == STATUS_PENDING_SHIPMENT) {
-            // 待发货状态:执行发货操作
-            result = executeShipOrder(originalOrder, fsStoreOrder, opeName);
-        } else {
-            // 其他状态:只更新快递信息
-            result = updateDeliveryInfo(originalOrder, fsStoreOrder, opeName);
         }
+        log.info("微走取消发货, 订单号: {}", fsStoreOrder.getOrderId());
+        return 1;
+    }
 
-        // 订阅快递信息(两种场景都需要)
-//        subscribeExpress(originalOrder, fsStoreOrder);//2026-3-20沟通后今正用微走接口调用的方式更新物流状态
+    @FunctionalInterface
+    private interface OrderLogSaver {
+        int save(FsStoreOrder order, String operator, String message);
+    }
 
-        return result;
+    private OrderLogSaver dispatchCancel(Object order, FsStoreOrder fsStoreOrder) {
+        if (order instanceof FsStoreOrder) {
+            FsStoreOrder o = (FsStoreOrder) order;
+            if (o.getStatus() == STATUS_PENDING_SHIPMENT) {
+                fsStoreOrder.setOrderId(o.getOrderId());
+                updateOrderToCancelled(fsStoreOrder);
+            }
+            return this::saveOrderLog;
+        }
+        if (order instanceof FsStoreOrderScrm) {
+            FsStoreOrderScrm o = (FsStoreOrderScrm) order;
+            if (o.getStatus() == STATUS_PENDING_SHIPMENT) {
+                fsStoreOrder.setOrderId(o.getId());
+                updateOrderToCancelledScrm(fsStoreOrder);
+            }
+            return this::saveOrderLogScrm;
+        }
+        FsIntegralOrder o = (FsIntegralOrder) order;
+        if (o.getStatus() == STATUS_PENDING_SHIPMENT) {
+            fsStoreOrder.setOrderId(o.getOrderId());
+            updateOrderToCancelledIntegral(fsStoreOrder);
+        }
+        return this::saveOrderLogIntegral;
+    }
+
+    private OrderLogSaver dispatchUpdate(Object order, FsStoreOrder fsStoreOrder) {
+        if (order instanceof FsStoreOrder) {
+            FsStoreOrder o = (FsStoreOrder) order;
+            if (o.getStatus() == STATUS_SHIPPED) {
+                fsStoreOrder.setOrderId(o.getOrderId());
+                updateOrderToEvaluated(fsStoreOrder);
+            }
+            return this::saveOrderLog;
+        }
+        if (order instanceof FsStoreOrderScrm) {
+            FsStoreOrderScrm o = (FsStoreOrderScrm) order;
+            if (o.getStatus() == STATUS_SHIPPED) {
+                fsStoreOrder.setOrderId(o.getId());
+            }
+            return this::saveOrderLogScrm;
+        }
+        FsIntegralOrder o = (FsIntegralOrder) order;
+        if (o.getStatus() == STATUS_SHIPPED) {
+            fsStoreOrder.setOrderId(o.getOrderId());
+        }
+        return this::saveOrderLogIntegral;
     }
 
     /**
@@ -4810,6 +4904,47 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
 
         return result;
     }
+    private int executeShipOrderScrm(FsStoreOrderScrm originalOrder, FsStoreOrder fsStoreOrder, String opeName) {
+        // 1. 更新订单为已发货
+        FsStoreOrderScrm updateOrder = new FsStoreOrderScrm();
+        updateOrder.setId(fsStoreOrder.getOrderId());
+        updateOrder.setStatus(STATUS_PENDING_SHIPMENT);
+        updateOrder.setUpdateTime(new DateTime());
+        updateOrder.setDeliveryCode(fsStoreOrder.getDeliveryCode());
+        updateOrder.setDeliveryName(fsStoreOrder.getDeliveryName());
+        updateOrder.setDeliverySn(fsStoreOrder.getDeliverySn());
+        updateOrder.setDeliveryTime(getCurrentDateTimeString());
+        int result = fsStoreOrderScrmMapper.updateFsStoreOrder(updateOrder);
+        // 2. 处理公司扣款
+        if (originalOrder.getCompanyId() != null) {
+            companyService.subtractCompanyMoneyScrm(originalOrder);
+        }
+        // 3. 记录日志
+        String logMessage = opeName + " 订单发货";
+        saveOrderLogScrm(fsStoreOrder, opeName, logMessage);
+        log.info("微走订单发货成功, 订单号: {}, 快递公司: {}, 快递单号: {}",
+                fsStoreOrder.getOrderId(),
+                fsStoreOrder.getDeliveryName(),
+                fsStoreOrder.getDeliverySn());
+        return result;
+    }
+    private int executeShipOrderIntegral(FsIntegralOrder originalOrder, FsStoreOrder fsStoreOrder, String opeName) {
+        // 1. 更新订单为已发货
+        FsIntegralOrder updateOrder = buildShipOrderUpdateIntegral(fsStoreOrder);
+        int result = fsIntegralOrderMapper.updateFsIntegralOrder(updateOrder);
+        // 2. 处理公司扣款 //积分商品暂未找到
+//        if (originalOrder.getCompanyId() != null) {
+//            companyService.subtractCompanyMoney(originalOrder);
+//        }
+        // 3. 记录日志
+        String logMessage = opeName + " 订单发货";
+        saveOrderLogIntegral(fsStoreOrder, opeName, logMessage);
+        log.info("微走订单发货成功, 订单号: {}, 快递公司: {}, 快递单号: {}",
+                fsStoreOrder.getOrderId(),
+                fsStoreOrder.getDeliveryName(),
+                fsStoreOrder.getDeliverySn());
+        return result;
+    }
 
     /**
      * 更新快递信息
@@ -4828,6 +4963,34 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
 
         return result;
     }
+    private int updateDeliveryInfoScrm(FsStoreOrderScrm originalOrder, FsStoreOrder fsStoreOrder, String opeName) {
+        // 1. 只更新快递相关信息
+        FsStoreOrderScrm updateOrder = buildDeliveryInfoUpdateScrm(fsStoreOrder);
+        int result = fsStoreOrderScrmMapper.updateFsStoreOrder(updateOrder);
+
+        // 2. 记录日志
+        String logMessage = opeName + " 订单单号更新";
+        saveOrderLogScrm(fsStoreOrder, opeName, logMessage);
+
+        log.info("微走修改快递单号, 订单号: {}, 新快递单号: {}",
+                fsStoreOrder.getOrderId(), fsStoreOrder.getDeliverySn());
+
+        return result;
+    }
+    private int updateDeliveryInfoIntegral(FsIntegralOrder originalOrder, FsStoreOrder fsStoreOrder, String opeName) {
+        // 1. 只更新快递相关信息
+        FsIntegralOrder updateOrder = buildDeliveryInfoUpdateIntegral(fsStoreOrder);
+        int result = fsIntegralOrderMapper.updateFsIntegralOrder(updateOrder);
+
+        // 2. 记录日志
+        String logMessage = opeName + " 订单单号更新";
+        saveOrderLogIntegral(fsStoreOrder, opeName, logMessage);
+
+        log.info("微走修改快递单号, 订单号: {}, 新快递单号: {}",
+                fsStoreOrder.getOrderId(), fsStoreOrder.getDeliverySn());
+
+        return result;
+    }
 
     /**
      * 更新订单为已取消状态
@@ -4841,6 +5004,24 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
 
         fsStoreOrderMapper.updateFsStoreOrder(updateOrder);
     }
+    private void updateOrderToCancelledScrm(FsStoreOrder fsStoreOrder) {
+        FsStoreOrderScrm updateOrder = new FsStoreOrderScrm();
+        updateOrder.setId(fsStoreOrder.getOrderId());
+        updateOrder.setStatus(STATUS_PENDING_SHIPMENT);//待发货
+        updateOrder.setUpdateTime(new DateTime());
+        updateOrder.setDeliveryTime(getCurrentDateTimeString());
+
+        fsStoreOrderScrmMapper.updateFsStoreOrder(updateOrder);
+    }
+    private void updateOrderToCancelledIntegral(FsStoreOrder fsStoreOrder) {
+        FsIntegralOrder updateOrder = new FsIntegralOrder();
+        updateOrder.setOrderId(fsStoreOrder.getOrderId());
+        updateOrder.setStatus(STATUS_PENDING_SHIPMENT);//待发货
+        updateOrder.setUpdateTime(new DateTime());
+        updateOrder.setDeliveryTime(new DateTime());
+
+        fsIntegralOrderMapper.updateFsIntegralOrder(updateOrder);
+    }
     /**
      * 更新订单为待评价状态
      */
@@ -4869,6 +5050,19 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
 
         return updateOrder;
     }
+    private FsIntegralOrder buildShipOrderUpdateIntegral(FsStoreOrder fsStoreOrder) {
+        FsIntegralOrder updateOrder = new FsIntegralOrder();
+        updateOrder.setOrderId(fsStoreOrder.getOrderId());
+        updateOrder.setStatus(STATUS_PENDING_SHIPMENT);
+        updateOrder.setUpdateTime(new DateTime());
+        updateOrder.setDeliveryCode(fsStoreOrder.getDeliveryCode());
+        updateOrder.setDeliveryName(fsStoreOrder.getDeliveryName());
+        updateOrder.setDeliverySn(fsStoreOrder.getDeliverySn());
+        updateOrder.setDeliveryTime(new DateTime());
+
+        return updateOrder;
+    }
+
 
     /**
      * 构建快递信息更新对象
@@ -4884,6 +5078,29 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
 
         return updateOrder;
     }
+    private FsStoreOrderScrm buildDeliveryInfoUpdateScrm(FsStoreOrder fsStoreOrder) {
+        FsStoreOrderScrm updateOrder = new FsStoreOrderScrm();
+        updateOrder.setId(fsStoreOrder.getOrderId());
+        updateOrder.setDeliveryCode(fsStoreOrder.getDeliveryCode());
+        updateOrder.setDeliveryName(fsStoreOrder.getDeliveryName());
+        updateOrder.setDeliverySn(fsStoreOrder.getDeliverySn());
+        updateOrder.setUpdateTime(new DateTime());
+        // 注意:这里不更新状态和发货时间
+
+        return updateOrder;
+    }
+    private FsIntegralOrder buildDeliveryInfoUpdateIntegral(FsStoreOrder fsStoreOrder) {
+        FsIntegralOrder updateOrder = new FsIntegralOrder();
+        updateOrder.setOrderId(fsStoreOrder.getOrderId());
+        updateOrder.setDeliveryCode(fsStoreOrder.getDeliveryCode());
+        updateOrder.setDeliveryName(fsStoreOrder.getDeliveryName());
+        updateOrder.setDeliverySn(fsStoreOrder.getDeliverySn());
+        updateOrder.setUpdateTime(new DateTime());
+        // 注意:这里不更新状态和发货时间
+
+        return updateOrder;
+    }
+
 
     /**
      * 保存订单日志
@@ -4898,7 +5115,26 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
 
         return fsStoreOrderLogsMapper.insertFsStoreOrderLogs(logs);
     }
+    private int saveOrderLogScrm(FsStoreOrder fsStoreOrder, String operator, String message) {
+        FsStoreOrderLogsScrm logs = new FsStoreOrderLogsScrm();
+        logs.setChangeMessage(message);
+        logs.setOrderId(fsStoreOrder.getOrderId());
+        logs.setChangeTime(new DateTime());
+        logs.setChangeType(LOG_TYPE_DELIVERY);
+        logs.setOperator(operator);
 
+        return fsStoreOrderLogsScrmMapper.insertFsStoreOrderLogs(logs);
+    }
+    private int saveOrderLogIntegral(FsStoreOrder fsStoreOrder, String operator, String message) {
+        FsIntegralOrderLogs logs = new FsIntegralOrderLogs();
+        logs.setChangeMessage(message);
+        logs.setOrderId(fsStoreOrder.getOrderId());
+        logs.setChangeTime(LocalDateTime.now());
+        logs.setChangeType(LOG_TYPE_DELIVERY);
+        logs.setOperator(operator);
+
+        return fsIntegralOrderLogsMapper.insertFsIntegralOrderLogs(logs);
+    }
     /**
      * 订阅快递信息
      */
@@ -4966,4 +5202,153 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
     public BigDecimal selectPayPriceByYear(String userId){
         return fsStoreOrderItemMapper.selectPayPriceByYear(userId);
     }
+
+    @Override
+    public void weizouPushIntergral(Long l) {
+        FsIntegralOrder order = fsIntegralOrderMapper.selectFsIntegralOrderByOrderId(l);
+        WeizouApiPushOrderParam param = new WeizouApiPushOrderParam();
+        param.setRealName(order.getUserName()).setPhone(order.getUserPhone().length() > 11 ? decryptPhone(order.getUserPhone()) : order.getUserPhone())
+                .setExtendOrderId(order.getOrderCode())
+        ;
+        // 积分订单全款
+            param.setPaymentType("01").setPaid(1)
+                    .setPayType("02").setDeliveryType("顺丰快递")
+//                    .setPayType("01").setDeliveryType("邮政快递")
+            ;
+        com.alibaba.fastjson.JSONArray goods = com.alibaba.fastjson.JSONArray.parseArray(order.getItemJson());
+        Set<Long> goodIds =
+        goods.stream().map(item -> ((com.alibaba.fastjson.JSONObject) item).getLong("goodsId")).collect(Collectors.toSet());
+        List<FsIntegralGoodsVo> fsIntegralGoodsVos = fsIntegralGoodsMapper.selectAllByGoodsIds(goodIds);
+        Map<Long, FsIntegralGoodsVo> goodsMap = fsIntegralGoodsVos.stream().collect(Collectors.toMap(FsIntegralGoodsVo::getGoodsId, Function.identity()));
+        //商品
+        ArrayList<WeizouOrderEntry> orders = new ArrayList<>();
+        goods.forEach(item -> {
+            WeizouOrderEntry entry = new WeizouOrderEntry();
+            FsIntegralGoodsVo good = goodsMap.get(((com.alibaba.fastjson.JSONObject) item).getLong("goodsId"));
+            entry.setSkuNumber(good.getBarCode()).setRetailPrice(good.getOtPrice())
+                    .setTaxPrice(good.getCash()).setTaxTotalAmount(good.getCash().multiply(new BigDecimal(((com.alibaba.fastjson.JSONObject) item).getInteger("num"))))
+                    .setCount(((com.alibaba.fastjson.JSONObject) item).getInteger("num"));
+            orders.add(entry);
+        });
+        //设置地址-省市区
+        String[] address = order.getUserAddress().split(" ");
+        try{
+            if (address.length < 3) {
+                String kdnAddress = fsUserAddressService.getKdnAddress(order.getUserAddress());
+                Map<String, Object> addDAta = (Map<String, Object>) JSON.parse(kdnAddress);
+                Map<String, String> add = (Map<String, String>) addDAta.get("Data");
+                param.setProvince(add.get("ProvinceName")).setCity(add.get("CityName"))
+                        .setDistrict(add.get("ExpAreaName"))
+                        .setUserAddress(add.get("StreetName") + add.get("Address"));
+
+            } else {
+                param.setProvince(address[0]).setCity(address[1]).setDistrict(address[2]);
+                //处理地址多空格问题
+                if (address.length > 3) {
+                    StringBuffer addrs = new StringBuffer();
+                    for (int i = 3; i < address.length; i++) {
+                        addrs.append(address[i]);
+                    }
+                    param.setUserAddress(addrs.toString());
+                } else {
+                    param.setUserAddress(address[2]);
+                }
+            }
+        }catch (Exception e){
+            log.error("地址错误:{}",e);
+            throw new CustomException("地址格式不对请正确写入详细地址!!");
+        }
+        param.setEntryList(orders);
+        String s ="";
+        try {
+            s = WeizouApiClient.pushOrder(param);
+
+        }catch (IOException e){
+            log.error("微走推送异常:{}",e);
+            return;
+        }
+        log.info("微走推送结果:{}",s);
+    }
+
+    @Override
+    public void weizouPushScrm(Long l) {
+        FsStoreOrderScrm order = fsStoreOrderScrmMapper.selectFsStoreOrderById(l);
+        if (order.getShippingType() != null && order.getShippingType() == 2)return;
+        WeizouApiPushOrderParam param = new WeizouApiPushOrderParam();
+        param.setRealName(order.getRealName()).setPhone(order.getUserPhone().length() > 11 ? decryptPhone(order.getUserPhone()) : order.getUserPhone())
+                .setFreightPrice(order.getFreightPrice()).setExtendOrderId(order.getOrderCode())
+        ;
+        //全款
+        if (order.getPayType().equals(1)) {
+            param.setPaymentType("01").setPaid(1)
+                    .setPayType("02").setDeliveryType("顺丰快递")
+//                    .setPayType("01").setDeliveryType("邮政快递")
+            ;
+            //部分支付
+        } else if (order.getPayType().equals(2)) {
+            param.setPaymentType("02").setPaid(2).setPrecollection(order.getPayPrice())
+                    .setPayType("04").setDeliveryType("顺丰快递")
+//                    .setPayType("03").setDeliveryType("邮政快递")
+            ;
+            //未付款
+        } else if (order.getPayType().equals(3)) {
+            param.setPaymentType("02").setPaid(0)
+                    .setPayType("04").setDeliveryType("顺丰快递")
+//                    .setPayType("03").setDeliveryType("邮政快递")
+            ;
+        }
+        //商品
+        List<com.fs.hisStore.vo.FsStoreOrderItemVO> items = fsStoreOrderItemScrmMapper.selectFsStoreOrderItemListByOrderId(order.getId());
+        ArrayList<WeizouOrderEntry> orders = new ArrayList<>();
+
+        items.forEach(item -> {
+            FsStoreProductScrm product = fsStoreProductScrmMapper.selectFsStoreProductById(item.getProductId());
+
+            WeizouOrderEntry entry = new WeizouOrderEntry();
+
+            entry.setSkuNumber(product.getBarCode()).setRetailPrice(product.getPrice())
+                    .setTaxPrice(product.getPrice()).setTaxTotalAmount(product.getPrice().multiply(new BigDecimal(item.getNum())))
+                    .setCount(Integer.parseInt(item.getNum().toString()));
+            orders.add(entry);
+        });
+
+        //设置地址-省市区
+        String[] address = order.getUserAddress().split(" ");
+        try{
+            if (address.length < 3) {
+                String kdnAddress = fsUserAddressService.getKdnAddress(order.getUserAddress());
+                Map<String, Object> addDAta = (Map<String, Object>) JSON.parse(kdnAddress);
+                Map<String, String> add = (Map<String, String>) addDAta.get("Data");
+                param.setProvince(add.get("ProvinceName")).setCity(add.get("CityName"))
+                        .setDistrict(add.get("ExpAreaName"))
+                        .setUserAddress(add.get("StreetName") + add.get("Address"));
+
+            } else {
+                param.setProvince(address[0]).setCity(address[1]).setDistrict(address[2]);
+                //处理地址多空格问题
+                if (address.length > 3) {
+                    StringBuffer addrs = new StringBuffer();
+                    for (int i = 3; i < address.length; i++) {
+                        addrs.append(address[i]);
+                    }
+                    param.setUserAddress(addrs.toString());
+                } else {
+                    param.setUserAddress(address[2]);
+                }
+            }
+        }catch (Exception e){
+            log.error("地址错误:{}",e);
+            throw new CustomException("地址格式不对请正确写入详细地址!!");
+        }
+        param.setEntryList(orders);
+        String s ="";
+        try {
+            s = WeizouApiClient.pushOrder(param);
+
+        }catch (IOException e){
+            log.error("微走推送异常:{}",e);
+            return;
+        }
+        log.info("微走推送结果:{}",s);
+    }
 }

+ 2 - 2
fs-service/src/main/java/com/fs/his/service/impl/FsUserInvitedServiceImpl.java

@@ -188,13 +188,13 @@ public class FsUserInvitedServiceImpl extends ServiceImpl<FsUserInvitedMapper, F
 //            }
 //        }
         //2.添加奖励
-        //2.1被邀请人获得2000芳华币
+        //2.1被邀请人获得2000积分
         FsUserAddIntegralTemplateParam invitedParam = new FsUserAddIntegralTemplateParam();
         invitedParam.setLogType(FsUserIntegralLogTypeEnum.TYPE_19.getValue());
         invitedParam.setUserId(invitedUserId);
         invitedParam.setBusinessId(userId.toString());
         R invitedR = integralLogsService.addIntegralTemplate(invitedParam);
-        //2.2邀请人A获得1000芳华币
+        //2.2邀请人A获得1000积分
         FsUserAddIntegralTemplateParam param = new FsUserAddIntegralTemplateParam();
         param.setUserId(userId);
         param.setLogType(FsUserIntegralLogTypeEnum.TYPE_18.getValue());

+ 15 - 0
fs-service/src/main/java/com/fs/his/vo/CourseFinishRewardVO.java

@@ -0,0 +1,15 @@
+package com.fs.his.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+public class CourseFinishRewardVO {
+
+    private String couponName;
+
+    private BigDecimal redPacketMoney;
+
+    private Integer integral;
+}

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

@@ -47,4 +47,7 @@ public class FsIntegralGoodsVo {
 
     @ApiModelProperty("商品数量")
     private Integer quantity;
+
+    @ApiModelProperty("需支付金额")
+    private BigDecimal cash;
 }

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

@@ -27,7 +27,7 @@ public class GetFsIntegralCartDetailsVo {
     @ApiModelProperty("所有商品所需积分之和")
     private Long goodsIntegralTotal;
 
-    @ApiModelProperty("用户的芳华币总数")
+    @ApiModelProperty("用户的积分总数")
     private BigDecimal userIntegral;
 
     @ApiModelProperty("商品信息")

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

@@ -56,7 +56,7 @@ public class GetFsIntegralCartListVo {
     @ApiModelProperty("购买的商品数量")
     private Integer cartNum;
 
-    @ApiModelProperty("用户的芳华币总数")
+    @ApiModelProperty("用户的积分总数")
     private BigDecimal userIntegral;
 
     @ApiModelProperty("是否选中:1是,0否")

+ 1 - 0
fs-service/src/main/java/com/fs/his/vo/OptionsVO.java

@@ -8,4 +8,5 @@ public class OptionsVO implements Serializable {
     Long dictValue;
     String dictLabel;
     String dictImgUrl;
+    Integer isDel;
 }

+ 7 - 0
fs-service/src/main/java/com/fs/hisStore/domain/FsStoreAfterSalesScrm.java

@@ -146,6 +146,7 @@ public class FsStoreAfterSalesScrm extends BaseEntity
     /** 退款原因字典二级 ID */
     private Long reasonId2;
 
+
     /** 售后一级原因(文字,与 reason_id1 对应名称快照) */
     private String reasonLevel1Text;
 
@@ -180,4 +181,10 @@ public class FsStoreAfterSalesScrm extends BaseEntity
     @TableField(exist = false)
     private String bankTransactionId;
 
+    /**
+    * 订单类型
+    */
+    @TableField(exist = false)
+    private Integer orderType;
+
 }

+ 8 - 0
fs-service/src/main/java/com/fs/hisStore/domain/FsStoreOrderScrm.java

@@ -3,7 +3,9 @@ package com.fs.hisStore.domain;
 import java.math.BigDecimal;
 import java.util.Date;
 
+import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fs.common.annotation.Excel;
 import com.fs.common.core.domain.BaseEntity;
@@ -21,6 +23,7 @@ public class FsStoreOrderScrm extends BaseEntity
     private static final long serialVersionUID = 1L;
 
     /** 订单ID */
+    @TableId(type = IdType.AUTO)
     private Long id;
 
     /** 订单号 */
@@ -203,6 +206,8 @@ public class FsStoreOrderScrm extends BaseEntity
     private String itemJson;
 
     // 直播订单类型:2
+    /**订单类型(0商城,2直播,3点播,5直播中奖,6秒杀,7限时折扣)
+     */
     private Integer orderType;
 
     private Long packageId;
@@ -420,4 +425,7 @@ public class FsStoreOrderScrm extends BaseEntity
     /** 产品是否标记不分润(不入库;分佣流程传参,佣金按 0 入账并仍写公司流水) */
     @TableField(exist = false)
     private Boolean noCommission;
+
+    //直播间id
+    private Long liveId;
 }

+ 4 - 0
fs-service/src/main/java/com/fs/hisStore/domain/FsStoreProductScrm.java

@@ -379,6 +379,10 @@ public class FsStoreProductScrm extends BaseEntity
     @TableField(exist = false)
     private String offShelfTime;
 
+    /** 热卖标签(逗号分隔,最多3个,可为空) */
+    @TableField(exist = false)
+    private String hotSaleTags;
+
     /** 过滤商品id */
     private Long[] excludeProductIds;
 

+ 2 - 0
fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreAfterSalesScrmMapper.java

@@ -327,4 +327,6 @@ public interface FsStoreAfterSalesScrmMapper
     @Select("SELECT s.*, s.reason_level1_text AS reasonValue1, s.reason_level2_text AS reasonValue2 " +
             "FROM fs_store_after_sales_scrm s WHERE s.id = #{id}")
     FsStoreAfterSalesScrm selectFsStoreAfterSalesByIdForDetail(@Param("id") Long id);
+
+    List<FsStoreAfterSalesQueryVO> selectFsStoreAfterSalesListQueryNew(@Param("maps") FsStoreAfterSalesQueryParam storeAfterSalesParam);
 }

+ 3 - 3
fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderItemScrmMapper.java

@@ -76,7 +76,7 @@ public interface FsStoreOrderItemScrmMapper
     List<FsStoreOrderItemVO> selectFsStoreOrderItemListAndProductByOrderId(Long id);
 
     @Select({"<script> " +
-            "select i.*,o.user_id,psps.cost,o.pay_postage,o.total_num,o.status,fspcs.cate_name, o.real_name,o.user_phone,o.user_address,o.create_time,o.pay_time,o.delivery_sn,o.delivery_name,o.delivery_id, c.company_name ,cu.nick_name as company_user_nick_name ,cu.phonenumber as company_usere_phonenumber,o.upload_time ,CASE WHEN o.certificates IS NULL OR o.certificates = '' THEN 0 ELSE 1 END AS is_upload,p.title as package_name,cts.name as scheduleName,sp_latest.pay_money, sp_latest.bank_transaction_id as bankTransactionId, o.delivery_send_time," +
+            "select i.*,o.user_id,u.nick_name,psps.cost,o.pay_postage,o.total_num,o.status,fspcs.cate_name, o.real_name,o.user_phone,o.user_address,o.create_time,o.pay_time,o.delivery_sn,o.delivery_name,o.delivery_id, c.company_name ,cu.nick_name as company_user_nick_name ,cu.phonenumber as company_usere_phonenumber,o.upload_time ,CASE WHEN o.certificates IS NULL OR o.certificates = '' THEN 0 ELSE 1 END AS is_upload,p.title as package_name,cts.name as scheduleName,sp_latest.pay_money, sp_latest.bank_transaction_id as bankTransactionId, o.delivery_send_time," +
             " o.order_code, o.pay_price, o.pay_money, o.deduction_price,o.pay_delivery, o.order_type,psps.price " +
             ", CASE o.is_audit WHEN 1 THEN '是' ELSE '否' END AS isAudit " +
             ", sas.audit_remark as auditRemark, sas.reason_level1_text as reasonValue1, sas.reason_level2_text as reasonValue2 " +
@@ -125,7 +125,7 @@ public interface FsStoreOrderItemScrmMapper
             " and o.delivery_id =#{maps.deliveryId} " +
             "</if>" +
             "<if test = 'maps.nickname != null and  maps.nickname !=\"\"     '> " +
-            "and u.nickname like CONCAT('%',#{maps.nickname},'%') " +
+            "and u.nick_name like CONCAT('%',#{maps.nickname},'%') " +
             "</if>" +
             "<if test=\"maps.realName != null and  maps.realName !=''\">" +
             " and o.real_name like CONCAT('%',#{maps.realName},'%') " +
@@ -280,7 +280,7 @@ public interface FsStoreOrderItemScrmMapper
             " and o.delivery_id =#{maps.deliveryId} " +
             "</if>" +
             "<if test = 'maps.nickname != null and  maps.nickname !=\"\"     '> " +
-            "and u.nickname like CONCAT('%',#{maps.nickname},'%') " +
+            "and u.nick_name like CONCAT('%',#{maps.nickname},'%') " +
             "</if>" +
             "<if test=\"maps.realName != null and  maps.realName !=''\">" +
             " and o.real_name like CONCAT('%',#{maps.realName},'%') " +

+ 31 - 2
fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderScrmMapper.java

@@ -53,7 +53,7 @@ public interface FsStoreOrderScrmMapper
      * @return 订单集合
      */
     public List<FsStoreOrderScrm> selectFsStoreOrderList(FsStoreOrderScrm fsStoreOrder);
-    
+
         /**
          * 查询待发放购物积分的订单列表
          */
@@ -479,7 +479,9 @@ public interface FsStoreOrderScrmMapper
     List<FsPromotionOrderVO> selectFsPromotionOrderListVO(@Param("maps")FsStoreOrderParam param);
 
     @Select({"<script> " +
-            "select o.id,o.order_code,o.item_json,o.pay_price,o.status,o.is_package,o.package_json,o.delivery_id,o.finish_time,o.company_id,o.company_user_id  from fs_store_order_scrm o  " +
+            "select o.id,o.order_code,o.item_json,o.pay_price,o.status,o.is_package,o.package_json,o.delivery_id,o.finish_time,o.company_id," +
+            "o.company_user_id,o.live_id,o.order_type " +
+            "from fs_store_order_scrm o  " +
             "where o.is_del=0 and o.is_sys_del=0 " +
             "<if test = 'maps.status != null and maps.status != \"\"     '> " +
             "and o.status =#{maps.status} " +
@@ -1557,6 +1559,33 @@ public interface FsStoreOrderScrmMapper
      */
     @Select("SELECT * FROM fs_store_order_scrm WHERE status = 0 AND paid = 0 AND create_time < DATE_SUB(NOW(), INTERVAL #{unPayTime} MINUTE)")
     List<FsStoreOrderScrm> selectUnpayTimeoutOrderList(@Param("unPayTime") Integer unPayTime);
+    @Select({"<script> " +
+            "select o.id,o.order_code,o.item_json,o.pay_price,o.status,o.is_package,o.package_json,o.delivery_id,o.finish_time,o.company_id,o.company_user_id,o.live_id  from fs_store_order_scrm o  " +
+            "where o.is_del=0 and o.is_sys_del=0 " +
+            "<if test = 'maps.status != null and maps.status != \"\"     '> " +
+            "and o.status =#{maps.status} " +
+            "</if>" +
+            "<if test = 'maps.keyword != null and  maps.keyword !=\"\"    '> " +
+            "and o.order_code like CONCAT('%',#{maps.keyword},'%') " +
+            "</if>" +
+            "<if test = 'maps.deliveryStatus != null     '> " +
+            "and o.delivery_status =#{maps.deliveryStatus} " +
+            "</if>" +
+            "<if test = 'maps.liveId == null '> " +
+            "and o.live_id is null " +
+            "</if>" +
+            "<if test = 'maps.liveId != null and maps.liveId == 0 '> " +
+            "and o.live_id is not null " +
+            "</if>" +
+            "<if test = 'maps.userId != null     '> " +
+            "and o.user_id=#{maps.userId} " +
+            "</if>" +
+            "<if test = 'maps.appId != null and  maps.appId !=\"\"    '> " +
+            "and o.app_id =#{maps.appId} " +
+            "</if>" +
+            " order by o.id desc "+
+            "</script>"})
+    List<FsMyStoreOrderListQueryVO> selectFsMyStoreOrderListVONew(@Param("maps")FsMyStoreOrderQueryParam param);
 
     @Select("SELECT status FROM fs_store_order_scrm WHERE id = #{orderId}")
     FsStoreOrderScrm selectStatusById(@Param("orderId") Long orderId);

+ 2 - 0
fs-service/src/main/java/com/fs/hisStore/param/FsMyStoreOrderQueryParam.java

@@ -16,4 +16,6 @@ public class FsMyStoreOrderQueryParam extends BaseQueryParam implements Serializ
     private Integer deliveryStatus;
     @ApiModelProperty(value = "当前的appid")
     private String appId;
+    @ApiModelProperty(value = "直播间ID,null表示查询商城订单,0表示查询直播订单")
+    private Long liveId;
 }

+ 1 - 0
fs-service/src/main/java/com/fs/hisStore/param/FsStoreAfterSalesQueryParam.java

@@ -11,5 +11,6 @@ public class FsStoreAfterSalesQueryParam extends BaseQueryParam implements Seria
 
     private Integer status;
     private Long userId;
+    private Long liveId;
 
 }

+ 3 - 1
fs-service/src/main/java/com/fs/hisStore/param/FsStoreOrderCreateParam.java

@@ -48,11 +48,13 @@ public class FsStoreOrderCreateParam implements Serializable
     //订单创建类型 1普通订单 2套餐订单 3制单
     private Integer orderCreateType;
 
+    private Integer orderType; //订单类型(0商城,2直播,3点播,5直播中奖,6秒杀,7限时折扣)
+
     private Long customerId;
 
     private BigDecimal amount; //货到付款代收金额
 
-    private Integer orderType; //订单类型
+
     private Integer orderMedium; //媒体来源
 
     private Boolean isUserApp = true;

+ 2 - 0
fs-service/src/main/java/com/fs/hisStore/service/IFsStoreOrderScrmService.java

@@ -416,6 +416,8 @@ public interface IFsStoreOrderScrmService
 
     R zfbPayment(FsStoreOrderDoPayParam param);
 
+    List<FsMyStoreOrderListQueryVO> selectFsMyStoreOrderListVONew(FsMyStoreOrderQueryParam param);
+
 //    R getExpressMulti(FsStoreOrder order);
 
     R sendExpressInfoToWx(@PathVariable Long orderId);

+ 1 - 1
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreAfterSalesScrmServiceImpl.java

@@ -626,7 +626,7 @@ public class FsStoreAfterSalesScrmServiceImpl implements IFsStoreAfterSalesScrmS
 
     @Override
     public List<FsStoreAfterSalesQueryVO> selectFsStoreAfterSalesListQuery(FsStoreAfterSalesQueryParam storeAfterSalesParam) {
-        List<FsStoreAfterSalesQueryVO>  list=fsStoreAfterSalesMapper.selectFsStoreAfterSalesListQuery(storeAfterSalesParam);
+        List<FsStoreAfterSalesQueryVO>  list=fsStoreAfterSalesMapper.selectFsStoreAfterSalesListQueryNew(storeAfterSalesParam);
         for(FsStoreAfterSalesQueryVO vo:list){
             FsStoreAfterSalesItemScrm map=new FsStoreAfterSalesItemScrm();
              map.setStoreAfterSalesId(vo.getId());

+ 68 - 15
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java

@@ -154,6 +154,7 @@ import com.github.binarywang.wxpay.exception.WxPayException;
 import com.github.binarywang.wxpay.service.WxPayService;
 import com.google.common.base.Joiner;
 import com.google.gson.Gson;
+import jodd.util.StringUtil;
 import lombok.Synchronized;
 import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.error.WxErrorException;
@@ -644,6 +645,13 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                     oldStatus = existing.getStatus();
                 }
             }
+            if (StringUtil.isNotBlank(fsStoreOrder.getDeliveryId())) {
+                StringBuilder stringBuilder = new StringBuilder();
+                FsExpressScrm fsExpressScrm = tryResolveExpressByLogisticCode(fsStoreOrder.getDeliveryId(), fsStoreOrder.getOrderCode(), stringBuilder);
+                fsStoreOrder.setDeliveryName(fsExpressScrm == null ? " ": fsExpressScrm.getName());
+                fsStoreOrder.setDeliverySn(fsExpressScrm == null ? " ": fsExpressScrm.getCode());
+            }
+
             int rows = fsStoreOrderMapper.updateFsStoreOrder(fsStoreOrder);
             if (rows > 0 && orderId != null && newStatus != null && (newStatus == 2 || newStatus == 3)
                     && (oldStatus == null || !oldStatus.equals(newStatus))) {
@@ -1070,7 +1078,6 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                 return R.error("地址不能为空!");
             }
         }
-
         FsStoreOrderComputedParam computedParam = new FsStoreOrderComputedParam();
         BeanUtils.copyProperties(param, computedParam);
         //计算金额
@@ -1304,7 +1311,7 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
 
             // 商城订单归属绑定
             if (hisStoreConfig != null && Boolean.TRUE.equals(hisStoreConfig.getEnableStoreOrderAttribution())
-                    && storeOrder.getOrderType() == null ) {
+                    && storeOrder.getOrderType() == null && storeOrder.getCompanyUserId() == null) {
                 try {
                     bindStoreOrderAttribution(storeOrder, userId);
                 } catch (Exception e) {
@@ -2292,18 +2299,20 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
             if (express == null) {
                 express = selectExpressByOmsDeliverCode(deliverCode);
             }
+
+            if (kdnDeliverName.length() > 0) {
+                deliverName = kdnDeliverName.toString();
+            }
+            // 卓美需求,查询失败,也要修改订单号码
+            order.setDeliveryName(deliverName);
+            order.setDeliverySn(express == null ? "" :  express.getCode());
+            order.setDeliveryId(deliveryId);
+            order.setDeliverySendTime(new Date());
+            fsStoreOrderMapper.updateFsStoreOrder(order);
+            orderStatusService.create(order.getId(), OrderLogEnum.DELIVERY_GOODS.getValue(),
+                    OrderLogEnum.DELIVERY_GOODS.getDesc());
+            //订阅物流回调
             if (express != null) {
-                if (kdnDeliverName.length() > 0) {
-                    deliverName = kdnDeliverName.toString();
-                }
-                order.setDeliveryName(deliverName);
-                order.setDeliverySn(express.getCode());
-                order.setDeliveryId(deliveryId);
-                order.setDeliverySendTime(new Date());
-                fsStoreOrderMapper.updateFsStoreOrder(order);
-                orderStatusService.create(order.getId(), OrderLogEnum.DELIVERY_GOODS.getValue(),
-                        OrderLogEnum.DELIVERY_GOODS.getDesc());
-                //订阅物流回调
                 String lastFourNumber = "";
                 if (express.getCode().equals(ShipperCodeEnum.SF.getValue())  || express.getCode().equals(ShipperCodeEnum.ZTO.getValue())) {
                     lastFourNumber = order.getUserPhone();
@@ -3719,21 +3728,27 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
     public R syncExpress(FsStoreOrderExpressEditParam param) {
         FsStoreOrderScrm order = fsStoreOrderMapper.selectFsStoreOrderById(param.getOrderId());
         String lastFourNumber = "";
+        ExpressInfoDTO dto = null;
         if (order.getDeliverySn().equals(ShipperCodeEnum.SF.getValue()) || order.getDeliverySn().equals(ShipperCodeEnum.ZTO.getValue())) {
             if("恒春来".equals(cloudHostProper.getCompanyName())
                     && ObjectUtil.isNotEmpty(lastFourNumber = order.getVirtualPhone())){
                 if (lastFourNumber.contains("-")) {
-                    lastFourNumber = lastFourNumber.length() >= 4 ? lastFourNumber.substring(lastFourNumber.length() - 4) : lastFourNumber;
+                    String beforeDash = lastFourNumber.split("-")[0];
+                    lastFourNumber = beforeDash.length() >= 4 ? beforeDash.substring(beforeDash.length() - 4) : beforeDash;
                 }else{
                     lastFourNumber = StrUtil.sub(lastFourNumber, lastFourNumber.length(), -4);
                 }
+                dto=expressService.getExpressInfo(order.getOrderCode(),order.getDeliverySn(),order.getDeliveryId(),lastFourNumber);
+                if(dto!=null && !dto.isSuccess()){
+                    lastFourNumber = StrUtil.sub(order.getVirtualPhone(), order.getVirtualPhone().length(), -4);
+                }
             }
             // 原逻辑
             else if ((lastFourNumber = order.getUserPhone()).length() == 11) {
                 lastFourNumber = StrUtil.sub(lastFourNumber, lastFourNumber.length(), -4);
             }
         }
-        ExpressInfoDTO dto = expressService.getExpressInfo(order.getOrderCode(), order.getDeliverySn(), order.getDeliveryId(), lastFourNumber);
+        dto = expressService.getExpressInfo(order.getOrderCode(), order.getDeliverySn(), order.getDeliveryId(), lastFourNumber);
         if (dto == null || dto.getState() == null || dto.getStateEx() == null) {
             return null;
         }
@@ -7209,6 +7224,44 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
         return R.error();
     }
 
+    @Override
+    public List<FsMyStoreOrderListQueryVO> selectFsMyStoreOrderListVONew(FsMyStoreOrderQueryParam param) {
+        List<FsMyStoreOrderListQueryVO> list = fsStoreOrderMapper.selectFsMyStoreOrderListVONew(param);
+        for (FsMyStoreOrderListQueryVO vo : list) {
+//          List<FsStoreOrderItemVO> items=fsStoreOrderItemMapper.selectMyFsStoreOrderItemListByOrderId(vo.getId());
+//          vo.setItems(items);
+            if (StringUtils.isNotEmpty(vo.getItemJson())) {
+                JSONArray jsonArray = JSONUtil.parseArray(vo.getItemJson());
+                List<FsStoreOrderItemVO> items = JSONUtil.toList(jsonArray, FsStoreOrderItemVO.class);
+                if (items.size() > 0) {
+                    vo.setItems(items);
+                }
+            }
+            //处理是否可以申请售后
+            vo.setIsAfterSales(0);
+            if (vo.getStatus().equals(OrderInfoEnum.STATUS_3.getValue())) {
+                //已完成订单
+                vo.setIsAfterSales(1);
+                if (vo.getFinishTime() != null) {
+                    String json = configService.selectConfigByKey("store.config");
+                    StoreConfig storeConfig = JSONUtil.toBean(json, StoreConfig.class);
+                    if (storeConfig.getStoreAfterSalesDay() != null && storeConfig.getStoreAfterSalesDay() > 0) {
+                        //判断完成时间是否超过指定时间
+                        Calendar calendar = new GregorianCalendar();
+                        calendar.setTime(vo.getFinishTime());
+                        calendar.add(calendar.DATE, storeConfig.getStoreAfterSalesDay()); //把日期往后增加一天,整数  往后推,负数往前移动
+                        if (calendar.getTime().getTime() < new Date().getTime()) {
+                            vo.setIsAfterSales(0);
+                        }
+                    }
+                }
+            } else if (vo.getStatus() == 1 || vo.getStatus() == 2) {
+                vo.setIsAfterSales(1);
+            }
+        }
+        return list;
+    }
+
 
     /**
      * 综合参数

+ 27 - 1
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreProductScrmServiceImpl.java

@@ -1280,7 +1280,33 @@ public class FsStoreProductScrmServiceImpl implements IFsStoreProductScrmService
 
     @Override
     public List<FsStoreProductListQueryVO> selectFsStoreProductGoodListQuery(BaseQueryParam param) {
-        return fsStoreProductMapper.selectFsStoreProductGoodListQuery(medicalMallConfig, param);
+        List<FsStoreProductListQueryVO> list = fsStoreProductMapper.selectFsStoreProductGoodListQuery(medicalMallConfig, param);
+        if (list == null || list.isEmpty()) {
+            return list;
+        }
+        try {
+            List<Long> productIds = list.stream()
+                    .map(FsStoreProductListQueryVO::getProductId)
+                    .filter(Objects::nonNull)
+                    .distinct()
+                    .collect(Collectors.toList());
+            if (productIds.isEmpty()) {
+                return list;
+            }
+            List<FsStoreProductTagNameVO> tagNames = fsStoreProductTagRelationScrmMapper.selectProductTagNamesByProductIds(productIds);
+            Map<Long, List<String>> tagMap = new LinkedHashMap<>();
+            for (FsStoreProductTagNameVO tn : tagNames) {
+                tagMap.computeIfAbsent(tn.getProductId(), k -> new ArrayList<>()).add(tn.getTagName());
+            }
+            for (FsStoreProductListQueryVO vo : list) {
+                if (vo.getProductId() != null) {
+                    vo.setTagList(tagMap.getOrDefault(vo.getProductId(), new ArrayList<>()));
+                }
+            }
+        } catch (Exception e) {
+            log.error("批量查询商品标签失败", e);
+        }
+        return list;
     }
 
     @Override

+ 4 - 0
fs-service/src/main/java/com/fs/hisStore/vo/FsMyStoreOrderListQueryVO.java

@@ -47,5 +47,9 @@ public class FsMyStoreOrderListQueryVO implements Serializable
 
     private List<FsStoreOrderItemVO> items;
 
+    private Long liveId;
+
+    private Long orderType;
+
 
 }

+ 4 - 0
fs-service/src/main/java/com/fs/hisStore/vo/FsStoreAfterSalesQueryVO.java

@@ -87,6 +87,10 @@ public class FsStoreAfterSalesQueryVO implements Serializable
 
     private String packageJson;
 
+    private Long liveId;
+
+    private Long orderType;
+
 
     List<FsStoreAfterSalesItemScrm> items;
 

Деякі файли не було показано, через те що забагато файлів було змінено