Quellcode durchsuchen

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

15376779826 vor 3 Tagen
Ursprung
Commit
f1f4d582ef
58 geänderte Dateien mit 587 neuen und 140 gelöschten Zeilen
  1. 3 0
      fs-ad-new-api/src/main/java/com/fs/app/controller/CallbackController.java
  2. 12 1
      fs-ad-new-api/src/main/java/com/fs/app/facade/CallbackProcessingFacadeServiceImpl.java
  3. 1 1
      fs-ad-new-api/src/main/java/com/fs/app/task/DataSyncTask.java
  4. 2 2
      fs-ad-new-api/src/main/resources/application.yml
  5. 1 0
      fs-admin/src/main/java/com/fs/his/controller/FsIntegralGoodsController.java
  6. 33 2
      fs-admin/src/main/java/com/fs/his/controller/FsUserAddressController.java
  7. 9 1
      fs-admin/src/main/java/com/fs/live/controller/LiveVideoController.java
  8. 1 0
      fs-company/src/main/java/com/fs/hisStore/controller/FsIntegralGoodsController.java
  9. 2 2
      fs-company/src/main/resources/application.yml
  10. 130 0
      fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java
  11. 14 4
      fs-ipad-task/src/main/java/com/fs/app/task/SendMsg.java
  12. 32 65
      fs-live-app/src/main/java/com/fs/live/task/LiveCompletionPointsTask.java
  13. 18 6
      fs-live-app/src/main/java/com/fs/live/websocket/service/WebSocketServer.java
  14. 7 2
      fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java
  15. 6 0
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseVideoMapper.java
  16. 4 1
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  17. 1 1
      fs-service/src/main/java/com/fs/his/param/FsIntegralCartParam.java
  18. 7 0
      fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java
  19. 10 0
      fs-service/src/main/java/com/fs/his/utils/RedisCacheUtil.java
  20. 3 0
      fs-service/src/main/java/com/fs/his/vo/FsIntegralCartVO.java
  21. 49 0
      fs-service/src/main/java/com/fs/hisStore/enums/LiveEnum.java
  22. 16 3
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java
  23. 6 0
      fs-service/src/main/java/com/fs/live/domain/LiveVideo.java
  24. 9 0
      fs-service/src/main/java/com/fs/live/mapper/LiveMapper.java
  25. 6 0
      fs-service/src/main/java/com/fs/live/service/ILiveService.java
  26. 18 0
      fs-service/src/main/java/com/fs/live/service/impl/LiveServiceImpl.java
  27. 6 0
      fs-service/src/main/java/com/fs/live/vo/LiveVo.java
  28. 1 1
      fs-service/src/main/java/com/fs/newAdv/domain/Lead.java
  29. 4 0
      fs-service/src/main/java/com/fs/newAdv/domain/Site.java
  30. 1 1
      fs-service/src/main/java/com/fs/newAdv/event/ConversionEventListener.java
  31. 1 1
      fs-service/src/main/java/com/fs/newAdv/integration/client/IApiClient.java
  32. 1 1
      fs-service/src/main/java/com/fs/newAdv/integration/client/advertiser/BaiduApiClient.java
  33. 1 1
      fs-service/src/main/java/com/fs/newAdv/integration/client/advertiser/IQIYIApiClient.java
  34. 1 1
      fs-service/src/main/java/com/fs/newAdv/integration/client/advertiser/OPPOApiClient.java
  35. 88 9
      fs-service/src/main/java/com/fs/newAdv/integration/client/advertiser/OceanEngineApiClient.java
  36. 1 1
      fs-service/src/main/java/com/fs/newAdv/integration/client/advertiser/TencentApiClient.java
  37. 1 1
      fs-service/src/main/java/com/fs/newAdv/integration/client/advertiser/VIVOApiClient.java
  38. 22 18
      fs-service/src/main/java/com/fs/newAdv/service/impl/LeadServiceImpl.java
  39. 4 4
      fs-service/src/main/java/com/fs/newAdv/service/impl/SiteStatisticsServiceImpl.java
  40. 14 1
      fs-service/src/main/java/com/fs/qw/service/impl/QwExternalContactServiceImpl.java
  41. 2 0
      fs-service/src/main/java/com/fs/qw/vo/QwSopCourseFinishTempSetting.java
  42. 2 0
      fs-service/src/main/java/com/fs/qw/vo/QwSopTempSetting.java
  43. 3 1
      fs-service/src/main/java/com/fs/sop/domain/QwSopLogs.java
  44. 7 0
      fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsInfoServiceImpl.java
  45. 1 0
      fs-service/src/main/resources/application-config-druid-cfryt-test.yml
  46. 2 1
      fs-service/src/main/resources/application-config-druid-cfryt.yml
  47. 1 0
      fs-service/src/main/resources/application-config-druid-fby.yml
  48. 1 0
      fs-service/src/main/resources/application-config-druid-gzzdy.yml
  49. 2 1
      fs-service/src/main/resources/application-config-druid-hat.yml
  50. 1 0
      fs-service/src/main/resources/application-config-druid-hst.yml
  51. 2 2
      fs-service/src/main/resources/application-config-druid-hsyy.yml
  52. 1 0
      fs-service/src/main/resources/application-config-druid-kyt.yml
  53. 1 0
      fs-service/src/main/resources/application-config-druid-qdtst.yml
  54. 8 0
      fs-service/src/main/resources/application-config-druid-sft.yml
  55. 2 2
      fs-service/src/main/resources/application-config-druid-sxjz.yml
  56. 2 1
      fs-service/src/main/resources/application-config-druid-syysy.yml
  57. 2 1
      fs-service/src/main/resources/application-config-druid-yxj.yml
  58. 1 0
      fs-service/src/main/resources/mapper/his/FsIntegralCartMapper.xml

+ 3 - 0
fs-ad-new-api/src/main/java/com/fs/app/controller/CallbackController.java

@@ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.servlet.http.HttpServletRequest;
+import java.time.LocalDateTime;
 
 /**
  * 广告商回调接口
@@ -114,10 +115,12 @@ public class CallbackController {
                 .appId(byId.getAppId())
                 .authCode(authCode)
                 .appSecret(byId.getAppSecret())
+                .appSecret(byId.getAppSecret())
                 .build());
         if (ObjectUtil.isNotEmpty(accessToken)) {
             byId.setAccessToken(accessToken.getAccessToken());
             byId.setRefreshToken(accessToken.getRefreshToken());
+            byId.setUpdateTime(LocalDateTime.now());
             promotionAccountService.updateById(byId);
         } else {
             log.error("获取accessToken失败:{}", byId.getId());

+ 12 - 1
fs-ad-new-api/src/main/java/com/fs/app/facade/CallbackProcessingFacadeServiceImpl.java

@@ -5,6 +5,8 @@ import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONArray;
 import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.fs.newAdv.integration.adapter.IAdvertiserAdapter;
 import com.fs.newAdv.integration.factory.AdvertiserHandlerFactory;
 import com.fs.common.exception.base.BusinessException;
@@ -134,10 +136,13 @@ public class CallbackProcessingFacadeServiceImpl implements CallbackProcessingFa
         Lead byTraceId = leadService.getByTraceId(traceId);
         boolean isNewLead = ObjectUtil.isEmpty(byTraceId);
         if (isNewLead) {
-            byTraceId = new Lead();
+            IAdvertiserAdapter advertiserAdapter = handlerFactory.getAdapter(AdvertiserTypeEnum.getByCode(advertiserId));
+            byTraceId = advertiserAdapter.adaptCallbackData(allParams);
             byTraceId.setAdvertiserId(advertiserId);
             byTraceId.setSiteId(siteId);
             byTraceId.setTraceId(traceId);
+            // 设置站点和落地页的关联
+            setSiteByIdeaId(siteId, byTraceId.getIdeaId());
         } else {
             // 检查站点和广告商信息是否异常
             if (!Objects.equals(byTraceId.getSiteId(), siteId)) {
@@ -182,6 +187,12 @@ public class CallbackProcessingFacadeServiceImpl implements CallbackProcessingFa
         return res;
     }
 
+    private void setSiteByIdeaId(Long siteId, String ideaId) {
+        siteService.update(new LambdaUpdateWrapper<Site>()
+                .eq(Site::getId, siteId)
+                .set(Site::getIdeaId, ideaId));
+    }
+
     /**
      * 更新模板中的二维码信息
      */

+ 1 - 1
fs-ad-new-api/src/main/java/com/fs/app/task/DataSyncTask.java

@@ -57,7 +57,7 @@ public class DataSyncTask {
      * 数据同步任务->当日数据
      * cron: 每1小时统计站点数据
      */
-    @Scheduled(cron = "0 0 0/1 * * ?")
+    @Scheduled(cron = "0 0/1 * * * ?")
     public void syncTodayData() {
         String batchNo = DateUtil.format(LocalDateTime.now(), "yyyy-MM-dd");
         statisticsService.syncData(batchNo, 1);

+ 2 - 2
fs-ad-new-api/src/main/resources/application.yml

@@ -4,6 +4,6 @@ server:
 # Spring配置
 spring:
   profiles:
-#    active: dev
-    active: druid-ylrz
+    active: dev
+#    active: druid-ylrz
 

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

@@ -117,6 +117,7 @@ public class FsIntegralGoodsController extends BaseController
     {
 
         redisCacheUtil.delRedisKey("getIntegralGoodsList");
+        redisCacheUtil.delSpringCacheKey("getIntegralGoodsById", fsIntegralGoods.getGoodsId());
         redisCacheUtil.delRedisKey("getIntegralGoodsById");
         return toAjax(fsIntegralGoodsService.updateFsIntegralGoods(fsIntegralGoods));
     }

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

@@ -4,9 +4,12 @@ import java.util.List;
 
 import com.alibaba.fastjson.JSON;
 import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.entity.SysRole;
+import com.fs.common.core.domain.entity.SysUser;
 import com.fs.common.utils.ParseUtils;
 import com.fs.common.utils.SecurityUtils;
 import com.fs.his.dto.AddressInfoDTO;
+import com.fs.system.service.ISysRoleService;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -50,13 +53,41 @@ public class FsUserAddressController extends BaseController
     {
         startPage();
         List<FsUserAddress> list = fsUserAddressService.selectFsUserAddressList(fsUserAddress);
+        SysRole sysRole = null;
+        try {
+            sysRole = isCheckPermission();
+        } catch (Exception e) {
+        }
         for (FsUserAddress userAddress : list) {
-            userAddress.setPhone(decryptAutoPhoneMk(userAddress.getPhone()));
-            userAddress.setDetail(ParseUtils.parseAddress(userAddress.getDetail()));
+            if (sysRole == null || sysRole.getIsCheckPhone() != 1 ) {
+                userAddress.setPhone(decryptAutoPhoneMk(userAddress.getPhone()));
+            }
+            if (sysRole == null || sysRole.getIsCheckAddress() != 1 ) {
+                userAddress.setDetail(ParseUtils.parseAddress(userAddress.getDetail()));
+            }
         }
         return getDataTable(list);
     }
 
+    @Autowired
+    private ISysRoleService sysRoleService;
+    private SysRole isCheckPermission() {
+        SysRole sysRole = new SysRole();
+        SysUser user = getLoginUser().getUser();
+        boolean flag = user.isAdmin();
+        if (flag) {
+            sysRole.setIsCheckPhone(1);
+            sysRole.setIsCheckAddress(1);
+        } else {
+            List<SysRole> roles = user.getRoles();
+            if (roles != null && !roles.isEmpty()) {
+                Long[] roleIds = roles.stream().map(SysRole::getRoleId).toArray(Long[]::new);
+                return sysRoleService.getIsCheckPermission(roleIds);
+            }
+        }
+        return sysRole;
+    }
+
     /**
      * 导出用户地址列表
      */

+ 9 - 1
fs-admin/src/main/java/com/fs/live/controller/LiveVideoController.java

@@ -6,6 +6,9 @@ import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.config.cloud.CloudHostProper;
+import com.fs.hisStore.enums.CompanyEnum;
+import com.fs.hisStore.enums.LiveEnum;
 import com.fs.live.domain.LiveVideo;
 import com.fs.live.service.ILiveVideoService;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -26,7 +29,8 @@ public class LiveVideoController extends BaseController
 {
     @Autowired
     private ILiveVideoService liveVideoService;
-
+    @Autowired
+    private CloudHostProper cloudHostProper;
     /**
      * 查询直播视频列表
      */
@@ -89,6 +93,10 @@ public class LiveVideoController extends BaseController
     @PostMapping
     public AjaxResult add(@RequestBody LiveVideo liveVideo)
     {
+        if (LiveEnum.contains(cloudHostProper.getCompanyName())) {
+            liveVideo.setVideoUrl(liveVideo.getLineOne());
+            liveVideo.setFinishStatus(1);
+        }
         return toAjax(liveVideoService.insertLiveVideo(liveVideo));
     }
 

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

@@ -110,6 +110,7 @@ public class FsIntegralGoodsController extends BaseController
     {
 
         redisCacheUtil.delRedisKey("getIntegralGoodsList");
+        redisCacheUtil.delSpringCacheKey("getIntegralGoodsById", fsIntegralGoods.getGoodsId());
         redisCacheUtil.delRedisKey("getIntegralGoodsById");
         return toAjax(fsIntegralGoodsService.updateFsIntegralGoods(fsIntegralGoods));
     }

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

@@ -1,9 +1,9 @@
 server:
-  port: 7773
+  port: 8006
 # Spring配置
 spring:
   profiles:
-    active: druid-ylrz
+    active: dev
 #    active: druid-jnsyj-test
 #    active: druid-jnmy-test
 #    active: druid-jzzx-test

+ 130 - 0
fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java

@@ -21,6 +21,8 @@ import com.fs.his.domain.FsUser;
 import com.fs.his.mapper.FsUserMapper;
 import com.fs.ipad.IpadSendUtils;
 import com.fs.ipad.vo.*;
+import com.fs.live.domain.LiveWatchLog;
+import com.fs.live.mapper.LiveWatchLogMapper;
 import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.domain.QwUserVideo;
@@ -63,6 +65,8 @@ public class IpadSendServer {
 
 
     private static final List<String> PROJECT_NAMES = Arrays.asList("济南联志健康", "北京存在文化","宽益堂");
+    private final LiveWatchLogMapper liveWatchLogMapper;
+
     private void sendMiniProgram(BaseVo vo, QwSopCourseFinishTempSetting.Setting content, Map<String, FsCoursePlaySourceConfig> miniMap, Long companyId) {
         // 发送参数原本的appid
         String appid = content.getMiniprogramAppid();
@@ -432,6 +436,132 @@ public class IpadSendServer {
         return true;
     }
 
+    /**
+     * 直播间判定消息
+     * @param qwSopLogs
+     * @param setting
+     * @param qwUser
+     * @return
+     */
+    public boolean isSendLogsLive(QwSopLogs qwSopLogs, QwSopCourseFinishTempSetting setting, QwUser qwUser){
+        if(qwSopLogs.getSendStatus() != 3){
+            log.info("直播状态异常不发送:{}, LOGID: {}", qwUser.getQwUserName(), qwSopLogs.getId());
+            return false;
+        }
+        if(redisCache.getCacheObject("qw:user:id:" + qwUser.getId()) != null){
+            log.info("直播频率异常不发送:{}", qwUser.getQwUserName());
+            return false;
+        }
+
+        boolean noSop = qwSopLogs.getSendType() != 3 && qwSopLogs.getSendType() != 7;
+
+        if (qwSopLogs.getExpiryTime() == null && noSop) {
+            // 作废消息
+            log.warn("直播SOP_LOG_ID:{}, 直播SOP任务被删除", qwSopLogs.getId());
+            qwSopLogsService.updateQwSopLogsByWatchLogType(qwSopLogs.getId(), "直播SOP任务被删除");
+            return false;
+        }
+
+        LocalDateTime sendTime = DateUtil.stringToLocalDateTime(qwSopLogs.getSendTime());
+        LocalDateTime expiryDateTime;
+
+        // 判断是否过期
+        if(qwSopLogs.getSendType() == 3 || qwSopLogs.getSendType() == 7){
+            expiryDateTime = sendTime.plusHours(12);
+        }else{
+            expiryDateTime = sendTime.plusHours(qwSopLogs.getExpiryTime());
+        }
+
+        if (LocalDateTime.now().isAfter(expiryDateTime)) {
+            // 作废消息
+            log.warn("直播SOP_LOG_ID:{}, 已过期,不发送", qwSopLogs.getId());
+            qwSopLogsService.updateQwSopLogsByWatchLogType(qwSopLogs.getId(), "已过期,不发送");
+            return false;
+        }
+
+        if (setting.getCourseType() == null && noSop && setting.getType() == 2) {
+            log.warn("直播SOP_LOG_ID:{}, 模板未选消息类型,不发送", qwSopLogs.getId());
+            qwSopLogsService.updateQwSopLogsByWatchLogType(qwSopLogs.getId(), "直播模板未选消息类型,不发送");
+            return false;
+        }
+
+        // 查询视频是否下架
+//        if(setting.getVideoId()!= null){
+//            FsUserCourseVideo video = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId( setting.getVideoId().longValue());
+//            if(video != null){
+//                if(video.getIsOnPut()!=null && video.getIsOnPut() == 1){
+//                    log.warn("SOP_LOG_ID:{}, 视频已下架,不发送", qwSopLogs.getId());
+//                    qwSopLogsService.updateQwSopLogsByWatchLogType(qwSopLogs.getId(), "视频已下架,不发送");
+//                    return false;
+//                }
+//            }
+//        }
+        Long queryLiveId = null;
+        queryLiveId = setting.getLiveId();
+        if(null == queryLiveId){
+            for (QwSopCourseFinishTempSetting.Setting a : setting.getSetting()) {
+                if (StringUtils.isNotBlank(a.getLiveId())) {
+                    queryLiveId = Long.valueOf(a.getLiveId());
+                    break;
+                }
+            }
+        }
+        LiveWatchLog liveWatchLog = liveWatchLogMapper.selectOneLogByLiveIdAndQwUserIdAndExternalId(
+                queryLiveId,
+                String.valueOf(qwUser.getId()),
+                qwSopLogs.getExternalId()
+        );
+        Integer courseType = setting.getCourseType();
+        String logId = qwSopLogs.getId();
+        if(null != liveWatchLog){
+                    if (!QwSopLogsServiceImpl.isCourseTypeValid(courseType, liveWatchLog.getLogType())) {
+                        // 作废消息
+                        log.warn("SOP_LOG_ID:{}, 看课状态未满足,不发送", qwSopLogs.getId());
+                        qwSopLogsService.updateQwSopLogsByWatchLogType(logId, "看课状态未满足,不发送");
+                        return false;
+                    }
+        }
+        else{
+            log.warn("SOP_LOG_ID:{}, 无观看记录,不发送", qwSopLogs.getId());
+            qwSopLogsService.updateQwSopLogsByWatchLogType(logId, "无观看记录,不发送");
+            return false;
+        }
+//        if (qwSopLogs.getSendType() != 6 && noSop) {
+//            // 客户的信息
+////            QwExternalContactHParam contactHParam = new QwExternalContactHParam();
+////            contactHParam.setUserId(qwUser.getQwUserId().trim());
+////            contactHParam.setExternalUserId(qwSopLogs.getExternalUserId().trim());
+////            contactHParam.setCorpId(qwUser.getCorpId().trim());
+//            Integer courseType = setting.getCourseType();
+//            if (setting.getType() == 2 && courseType != 0) {// 课程消息,进行复杂的条件判断
+////                log.debug("企微查询:{}", contactHParam);
+////                Long qwExternalContactId = qwExternalContactMapper.getQwExternalContactId(contactHParam);
+//                FsCourseWatchLog watchLog = watchLogService.getWatchCourseLogVideoBySop(
+//                        setting.getVideoId().longValue(),
+//                        String.valueOf(qwUser.getId()),
+//                        qwSopLogs.getExternalId()
+//                );
+//                log.debug("ID:{}-看课记录参数:videoID:{}, qwUserID:{}, extID:{}", qwSopLogs.getId(), setting.getVideoId().longValue(), qwUser.getId(), qwSopLogs.getExternalId());
+//                log.debug("ID:{}-看课记录:{}", qwSopLogs.getId(), watchLog);
+//                String logId = qwSopLogs.getId();
+//                if (watchLog != null) {
+//                    //新逻辑
+//                    if (!QwSopLogsServiceImpl.isCourseTypeValid(courseType, watchLog.getLogType())) {
+//                        // 作废消息
+//                        log.warn("SOP_LOG_ID:{}, 看课状态未满足,不发送", qwSopLogs.getId());
+//                        qwSopLogsService.updateQwSopLogsByWatchLogType(logId, "看课状态未满足,不发送");
+//                        return false;
+//                    }
+//                } else {
+//                    log.warn("SOP_LOG_ID:{}, 无观看记录,不发送", qwSopLogs.getId());
+//                    qwSopLogsService.updateQwSopLogsByWatchLogType(logId, "无观看记录,不发送");
+//                    return false;
+//                }
+//            }
+//        }
+        return true;
+    }
+
     public void send(QwSopCourseFinishTempSetting.Setting content, QwUser qwUser, QwSopLogs qwSopLogs, Map<String, FsCoursePlaySourceConfig> miniMap, BaseVo parentVo) {
         BaseVo vo = new BaseVo();
         vo.setId(Long.parseLong(qwSopLogs.getId()));

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

@@ -191,10 +191,20 @@ public class SendMsg {
         for (QwSopLogs qwSopLogs : qwSopLogList) {
             long start2 = System.currentTimeMillis();
             QwSopCourseFinishTempSetting setting = JSON.parseObject(qwSopLogs.getContentJson(), QwSopCourseFinishTempSetting.class);
-            // 判断消息状态是否满足发送条件
-            if (!sendServer.isSendLogs(qwSopLogs, setting, user)) {
-                log.info("销售:{}, 消息发送条件未满足:{}", user.getQwUserName(), qwSopLogs.getId());
-                continue;
+            //直播的sendType:20单独走判断 其他的走以前的逻辑
+            boolean isSendLive = Integer.valueOf(20).equals(qwSopLogs.getSendType());
+            if(isSendLive){
+                if (!sendServer.isSendLogsLive(qwSopLogs, setting, user)) {
+                    log.info("销售:{}, 直播消息发送条件未满足:{}", user.getQwUserName(), qwSopLogs.getId());
+                    continue;
+                }
+            }
+            else{
+                // 判断消息状态是否满足发送条件
+                if (!sendServer.isSendLogs(qwSopLogs, setting, user)) {
+                    log.info("销售:{}, 消息发送条件未满足:{}", user.getQwUserName(), qwSopLogs.getId());
+                    continue;
+                }
             }
             log.info("进入发送消息状态:{}", qwSopLogs.getId());
             String key = "qw:logs:pad:send:id:" + qwSopLogs.getId();

+ 32 - 65
fs-live-app/src/main/java/com/fs/live/task/LiveCompletionPointsTask.java

@@ -41,16 +41,20 @@ public class LiveCompletionPointsTask {
     /**
      * 定时检查观看时长并创建完课记录
      * 每分钟执行一次
-     * 优化:使用Hash结构 + 防重复推送
+     * 优化:防重复推送 + 只查询开启了完课积分的直播间
      */
     @Scheduled(cron = "0 */1 * * * ?")
     public void checkCompletionStatus() {
         try {
-            List<Live> activeLives = liveService.selectNoEndLiveList();
+            // 只查询开启了完课积分配置的直播间
+            List<Live> activeLives = liveService.selectLiveListWithCompletionPointsEnabled();
             
             if (activeLives == null || activeLives.isEmpty()) {
+                log.debug("当前没有开启完课积分的直播间");
                 return;
             }
+            
+            log.info("开始检查完课状态, 开启完课积分的直播间数量: {}", activeLives.size());
 
             for (Live live : activeLives) {
                 try {
@@ -61,16 +65,20 @@ public class LiveCompletionPointsTask {
                     Map<Object, Object> userDurations = redisCache.redisTemplate.opsForHash().entries(hashKey);
                     
                     if (userDurations == null || userDurations.isEmpty()) {
+                        log.debug("直播间没有观看时长数据, liveId={}, liveName={}", liveId, live.getLiveName());
                         continue;
                     }
                     
+                    log.info("直播间有观看数据, liveId={}, liveName={}, 用户数: {}", 
+                            liveId, live.getLiveName(), userDurations.size());
+                    
                     // 3. 逐个用户处理
                     for (Map.Entry<Object, Object> entry : userDurations.entrySet()) {
                         try {
                             Long userId = Long.parseLong(entry.getKey().toString());
+                            Long duration = Long.parseLong(entry.getValue().toString());  // 从 Redis 直接获取观看时长
                             
-                            // 4. 检查并创建完课记录(传null,自动累计直播+回放时长)
-                            completionPointsRecordService.checkAndCreateCompletionRecord(liveId, userId, null);
+                            completionPointsRecordService.checkAndCreateCompletionRecord(liveId, userId, duration);
 
                             // 5. 检查是否有新的完课记录待领取,推送弹窗消息(防重复)
                             sendCompletionNotificationOnce(liveId, userId);
@@ -90,70 +98,29 @@ public class LiveCompletionPointsTask {
         }
     }
 
-    /**
-     * 发送完课通知(通过WebSocket推送弹窗) - 防重复版本
-     */
-    private void sendCompletionNotificationOnce(Long liveId, Long userId) {
-        try {
-            // 1. 检查 Redis 是否已推送过(防止每分钟都推送)
-            String notifyKey = "live:completion:notified:" + liveId + ":" + userId;
-            Boolean hasNotified = redisCache.hasKey(notifyKey);
-            
-            if (Boolean.TRUE.equals(hasNotified)) {
-                return;  // 已经推送过,不再重复推送
-            }
-            
-            // 2. 查询未领取的完课记录
-            List<LiveCompletionPointsRecord> unreceivedRecords = 
-                completionPointsRecordService.getUserUnreceivedRecords(liveId, userId);
-            
-            if (unreceivedRecords != null && !unreceivedRecords.isEmpty()) {
-                // 3. 构造弹窗消息
-                SendMsgVo sendMsgVo = new SendMsgVo();
-                sendMsgVo.setLiveId(liveId);
-                sendMsgVo.setUserId(userId);
-                sendMsgVo.setCmd("completionPoints");
-                sendMsgVo.setMsg("完成任务!");
-                sendMsgVo.setData(JSONObject.toJSONString(unreceivedRecords.get(0)));
-
-                // 4. 通过WebSocket发送给特定用户
-                webSocketServer.sendCompletionPointsMessage(liveId, userId, sendMsgVo);
-                
-                // 5. 记录已推送,24小时后过期(第二天可以再次推送)
-                redisCache.setCacheObject(notifyKey, "1", 24, TimeUnit.HOURS);
-                
-                log.info("发送完课积分弹窗通知成功, liveId={}, userId={}, points={}", 
-                        liveId, userId, unreceivedRecords.get(0).getPointsAwarded());
-            }
-        } catch (Exception e) {
-            log.error("发送完课通知失败, liveId={}, userId={}", liveId, userId, e);
+   private void sendCompletionNotificationOnce(Long liveId, Long userId) {
+    try {
+        // 查询未领取的完课记录
+        List<LiveCompletionPointsRecord> unreceivedRecords = 
+            completionPointsRecordService.getUserUnreceivedRecords(liveId, userId);
+        
+        if (unreceivedRecords == null || unreceivedRecords.isEmpty()) {
+            return;
         }
-    }
 
-    /**
-     * 发送完课通知(通过WebSocket推送弹窗) - 旧版本(保留)
-     */
-    private void sendCompletionNotification(Long liveId, Long userId) {
-        try {
-            // 查询未领取的完课记录
-            List<LiveCompletionPointsRecord> unreceivedRecords = completionPointsRecordService.getUserUnreceivedRecords(liveId, userId);
-            
-            if (unreceivedRecords != null && !unreceivedRecords.isEmpty()) {
-                // 构造弹窗消息
-                SendMsgVo sendMsgVo = new SendMsgVo();
-                sendMsgVo.setLiveId(liveId);
-                sendMsgVo.setUserId(userId);
-                sendMsgVo.setCmd("completionPoints");
-                sendMsgVo.setMsg("完成任务!");
-                sendMsgVo.setData(JSONObject.toJSONString(unreceivedRecords.get(0)));
-
-                // 通过WebSocket发送给特定用户(调用已有的发送方法)
-                webSocketServer.sendCompletionPointsMessage(liveId, userId, sendMsgVo);
-                
-                log.info("发送完课积分弹窗通知成功, liveId={}, userId={}", liveId, userId);
-            }
+        SendMsgVo sendMsgVo = new SendMsgVo();
+        sendMsgVo.setLiveId(liveId);
+        sendMsgVo.setUserId(userId);
+        sendMsgVo.setCmd("completionPoints");
+        sendMsgVo.setMsg("完成任务!");
+        sendMsgVo.setData(JSONObject.toJSONString(unreceivedRecords.get(0)));
+        
+        webSocketServer.sendCompletionPointsMessage(liveId, userId, sendMsgVo);
+        
+        log.info("发送完课积分弹窗通知, liveId={}, userId={}, points={}", 
+                liveId, userId, unreceivedRecords.get(0).getPointsAwarded());
         } catch (Exception e) {
-            log.error("发送完课通知失败, liveId={}, userId={}", liveId, userId, e);
+        log.error("发送完课通知失败", e);
         }
     }
 }

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

@@ -4,6 +4,7 @@ package com.fs.live.websocket.service;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.fs.common.constant.LiveKeysConstant;
+import com.fs.common.core.redis.RedisCacheT;
 import com.fs.common.exception.base.BaseException;
 import com.fs.common.utils.date.DateUtil;
 import com.fs.his.domain.FsUser;
@@ -320,30 +321,41 @@ public class WebSocketServer {
 
                     // 心跳时同步更新观看时长到Redis Hash
                     long watchUserId = (long) userProperties.get("userId");
+
+                    log.info("[心跳-观看时长] 接收心跳, liveId={}, userId={}, data={}",
+                            liveId, watchUserId, msg.getData());
                     
                     if (msg.getData() != null && !msg.getData().isEmpty()) {
                         try {
                             Long currentDuration = Long.parseLong(msg.getData());
-                            
+                            log.info("[心跳-观看时长] 解析成功, duration={}", currentDuration);
+
                             // 使用Hash结构存储:一个直播间一个Hash,包含所有用户的时长
                             String hashKey = "live:watch:duration:hash:" + liveId;
                             String userIdField = String.valueOf(watchUserId);
                             
+                            log.info("[心跳-观看时长] 开始处理, liveId={}, userId={}, hashKey={}, userIdField={}, currentDuration={}", 
+                                    liveId, watchUserId, hashKey, userIdField, currentDuration);
+                            
                             // 获取现有时长
-                            Object existingDuration = redisCache.redisTemplate.opsForHash().get(hashKey, userIdField);
+                            Object existingDuration = redisCache.hashGet(hashKey, userIdField);
                             
-                            // 只有当新的时长更大时才更新(避免时间倒退)
+                            // 只有当新的时长更大时才更新
                             if (existingDuration == null || currentDuration > Long.parseLong(existingDuration.toString())) {
                                 // 更新Hash中的用户时长
-                                redisCache.redisTemplate.opsForHash().put(hashKey, userIdField, currentDuration.toString());
+                                redisCache.hashPut(hashKey, userIdField, currentDuration.toString());
                                 // 设置过期时间(2小时)
-                                redisCache.redisTemplate.expire(hashKey, 2, TimeUnit.HOURS);
+                                redisCache.expire(hashKey, 2, TimeUnit.HOURS);
+                                
+                                log.info("[心跳-观看时长] 更新成功, liveId={}, userId={}, duration={}, hashKey={}", 
+                                        liveId, watchUserId, currentDuration, hashKey);
                                 
                                 // 实时更新用户看课状态(仅在直播期间)
                                 updateWatchLogTypeInRealTime(liveId, watchUserId, currentDuration);
                             }
                         } catch (Exception e) {
-                            log.error("心跳更新观看时长失败, liveId={}, userId={}", liveId, watchUserId, e);
+                            log.error("[心跳-观看时长] 更新失败, liveId={}, userId={}, data={}", 
+                                    liveId, watchUserId, msg.getData(), e);
                         }
                     }
                     

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

@@ -950,6 +950,9 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
             switch (setting.getContentType()) {
                 //直播小程序单独
                 case "12":
+                    //直播发送类型
+                    sopLogs.setSendType(20);
+                    clonedContent.setLiveId(setting.getLiveId());
                     String sortLiveLink;
                     sortLiveLink = "/pages_course/living.html?companyId=" + companyId + "&companyUserId=" + companyUserId + "&liveId=" + setting.getLiveId() + "&corpId=" + logVo.getCorpId()+"&qwUserId=" + qwUserId;
                     String json = configService.selectConfigByKey("his.config");
@@ -1198,6 +1201,8 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                     break;
                 //直播小程序单独
                 case "12":
+                    sopLogs.setSendType(20);
+                    clonedContent.setLiveId(setting.getLiveId());
                     String sortLiveLink;
                     sortLiveLink = "/pages_course/living.html?companyId=" + companyId + "&companyUserId=" + companyUserId + "&liveId=" + setting.getLiveId()+"&corpId=" +logVo.getCorpId()+"&qwUserId=" + qwUserId;
                     String json = configService.selectConfigByKey("his.config");
@@ -1984,7 +1989,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
     public void batchInsertLiveWatchLog(List<LiveWatchLog> liveWatchLogToInsert) {
         try {
             List<LiveWatchLog> lastInsertList = new ArrayList<>();
-            //判断是否存在数据 liveId + his_qw_external_contact_id 唯一
+            //判断是否存在数据 liveId + his_qw_external_contact_id + qwUserId 唯一
             for (LiveWatchLog liveWatchLog : liveWatchLogToInsert) {
                 //判断是否存在数据 存在的数据直接更新发送时间
                 if(liveWatchLogMapper.updateLiveWatchLogCondition(liveWatchLog) > 0){
@@ -1997,7 +2002,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
             }
 //            log.info("批量插入 LiveWatchLog 完成,共插入 {} 条记录。", liveWatchLogToInsert.size());
         } catch (Exception e) {
-            log.error("批量插入 LiveWatchLog 失败: {}", e.getMessage(), e);
+            log.error("批量插入 LiveWatchLog 失败: {}", liveWatchLogToInsert, e);
             // 可选:将失败的数据记录到失败队列或持久化存储以便后续重试
         }
     }

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

@@ -246,6 +246,12 @@ public interface FsUserCourseVideoMapper extends BaseMapper<FsUserCourseVideo> {
             "WHERE file_key = #{fileKey}")
     void updateFsUserCourseVideoByFileKey(FsUserCourseVideo courseVideo);
 
+    @Update("UPDATE fs_user_course_video " +
+            "SET line_two = #{lineTwo}, " +
+            "    update_time = NOW() " +  // 添加更新时间
+            "WHERE file_key = #{fileKey}")
+    void updateFsUserCourseVideoByFileKeyForHsy(FsUserCourseVideo courseVideo);
+
     @Select("select title from fs_user_course_video WHERE video_id=#{videoId}")
     String selectFsUserCourseVideoByVideoForTitle(@Param("videoId") Long videoId);
 

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

@@ -2621,10 +2621,13 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
         }
         // 项目看课数限制
         if (!EXCLUDE_PROJECTS.contains(signProjectName) && !CloudHostUtils.hasCloudHostName("弘德堂")) {
+            log.error("进入了看课限制:传入参数:={},watchCourseVideo={}",param, watchCourseVideo);
             Integer logCount = fsUserCourseMapper.selectTodayCourseWatchLogCountByUserIdAndProjectId(param.getUserId(), courseProject);
             if (Objects.isNull(watchCourseVideo) && logCount > 0) {
                 return ResponseResult.fail(504, "超过项目看课数量限制");
             }
+        }else {
+            log.error("没有进入看课限制:传入参数:={},watchCourseVideo={}存在问题 ",param, watchCourseVideo);
         }
         //添加判断:该用户是否已经存在此课程的看课记录,并且看课记录的销售id不是传入的销售id
         if (watchCourseVideo != null) {
@@ -4340,7 +4343,7 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
                 FsUserCourseVideo courseVideo = new FsUserCourseVideo();
                 courseVideo.setFileKey(videoResource.getFileKey());
                 courseVideo.setLineTwo(url);
-                fsUserCourseVideoMapper.updateFsUserCourseVideoByFileKey(courseVideo);
+                fsUserCourseVideoMapper.updateFsUserCourseVideoByFileKeyForHsy(courseVideo);
 
             }
             System.out.println(resp);

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

@@ -16,7 +16,7 @@ public class FsIntegralCartParam {
 
     @NotNull(message = "添加数量不能为空")
     @Min(value = 1, message = "数量不再合法范围内")
-    @Max(value = 999, message = "数量不再合法范围内")
+    @Max(value = 9999, message = "数量不再合法范围内")
     @ApiModelProperty("数量")
     private Integer cartNum;
 

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

@@ -921,6 +921,13 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
             return R.ok("发送红包成功").put("orderCode", transferBatchesResult.getOutBatchNo()).put("batchId", transferBatchesResult.getBatchId()).put("mchId", config.getMchId());
         } catch (Exception e) {
             logger.error("商家转账支付失败:参数: {} :原因: {}",JSON.toJSONString(param), e.getMessage(),e);
+            if (e instanceof WxPayException && "济南联志健康".equals(signProjectName)) {
+                WxPayException wxPayException = (WxPayException) e;
+                String customErrorMsg = wxPayException.getCustomErrorMsg();
+                if (null != customErrorMsg && customErrorMsg.startsWith("商户运营账户资金不足")) {
+                    return R.error("[红包领取] 账户余额不足,请联系管理员!");
+                }
+            }
             throw new RuntimeException(e);
         }
     }

+ 10 - 0
fs-service/src/main/java/com/fs/his/utils/RedisCacheUtil.java

@@ -20,4 +20,14 @@ public class RedisCacheUtil {
             redisCache.deleteObject(key);
         }
     }
+
+    /**
+     * 删除 Spring Cache 格式的缓存(带双冒号)
+     * @param cacheName 缓存名称(如 getIntegralGoodsById)
+     * @param cacheKey 缓存key(如 商品ID)
+     */
+    public void delSpringCacheKey(String cacheName, Object cacheKey) {
+        String key = cacheName + "::" + cacheKey;
+        redisCache.deleteObject(key);
+    }
 }

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

@@ -34,6 +34,9 @@ public class FsIntegralCartVO {
     @ApiModelProperty("最新所需金额")
     private BigDecimal newCash;
 
+    @ApiModelProperty("库存")
+    private Long stock;
+
     @ApiModelProperty("数量")
     private Integer cartNum;
 

+ 49 - 0
fs-service/src/main/java/com/fs/hisStore/enums/LiveEnum.java

@@ -0,0 +1,49 @@
+package com.fs.hisStore.enums;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * 设置不转码的项目
+ */
+public enum LiveEnum {
+    KANGNIAN_TANG("康年堂"),
+    SIFU_TANG("四福堂"),
+    NMG_MYT("内蒙古一贴"),
+    CQ_TYT("重庆泰医堂"),
+    HDT("弘德堂"),
+    JNMY("金牛明医"),
+    HYT("鹤颜堂"),
+    Z_K("中康");
+
+    private final String companyName;
+
+    LiveEnum(String companyName) {
+        this.companyName = companyName;
+    }
+
+    public String getCompanyName() {
+        return companyName;
+    }
+
+    /**
+     * 静态集合,避免每次调用都重新创建
+     */
+    private static final Set<String> COMPANY_NAMES = Collections.unmodifiableSet(
+            Arrays.stream(values())
+                    .map(LiveEnum::getCompanyName)
+                    .collect(Collectors.toSet())
+    );
+
+    /**
+     * 比较是否存在
+     *
+     * @param companyName
+     * @return
+     */
+    public static boolean contains(String companyName) {
+        return COMPANY_NAMES.contains(companyName);
+    }
+}

+ 16 - 3
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java

@@ -3111,10 +3111,23 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
 
             //获取运费模板区域列表按照城市排序
             List<FsShippingTemplatesRegionScrm> shippingTemplatesRegionList = shippingTemplatesRegionService.selectFsShippingTemplatesRegionListByTempIdsAndCityIds(StringUtils.join(tempIds, ","), StringUtils.join(citys, ","));
-
+            boolean isQg = false;
+
+            if (CollectionUtils.isEmpty(shippingTemplatesRegionList)&&CollectionUtils.isNotEmpty(shippingTemplatesList)&&shippingTemplatesList.size()<2) {
+                List<RegionInfoDTO> regionList = JSONObject.parseArray(
+                        shippingTemplatesList.get(0).getRegionInfo(),
+                        RegionInfoDTO.class
+                );
+                if (regionList != null && !regionList.isEmpty()) {
+                    RegionInfoDTO regionDTO = regionList.get(0);
+                    if ("默认全国".equals(regionDTO.getRegionName())) {
+                        isQg = true;
+                    }
+                }
+            }
             // 有运费模板,但当前城市没有匹配的区域
             if (shippingTemplatesList != null && !shippingTemplatesList.isEmpty()
-                    && (shippingTemplatesRegionList == null || shippingTemplatesRegionList.isEmpty())) {
+                    && (shippingTemplatesRegionList == null || shippingTemplatesRegionList.isEmpty())&&!isQg) {
                 logger.error("运费模板存在,但城市不在运费模板区域内,cityId: {}", cityId);
                 return badCode;
             }
@@ -3143,7 +3156,7 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                 // 如果商品有运费模板,但没有找到对应的区域配置,返回错误码
                 if (shippingTemplatesList != null && !shippingTemplatesList.isEmpty()
                         && shippingTemplatesList.stream().anyMatch(t -> t.getId().equals(tempId))
-                        && shippingTemplatesRegion == null) {
+                        && shippingTemplatesRegion == null&&!isQg) {
                     logger.error("商品运费模板存在,但城市不在运费模板区域内,tempId: {}, cityId: {}", tempId, cityId);
                     return badCode;
                 }

+ 6 - 0
fs-service/src/main/java/com/fs/live/domain/LiveVideo.java

@@ -43,4 +43,10 @@ public class LiveVideo extends BaseEntity {
     private Long sort;
     @Excel(name = "转码状态")
     private Integer finishStatus;
+
+
+    /**
+     * 未转码数据
+     */
+    private String lineOne;
 }

+ 9 - 0
fs-service/src/main/java/com/fs/live/mapper/LiveMapper.java

@@ -118,6 +118,15 @@ public interface LiveMapper
     @Select("select * from live where status != 3 and live_type in (2,3) and is_audit = 1")
     List<Live> selectNoEndLiveList();
 
+    /**
+     * 查询开启了完课积分配置的直播间(用于完课积分定时任务)
+     * @return 直播列表
+     */
+    @Select("select * from live where status != 3 and live_type in (2,3) and is_audit = 1 " +
+            "and config_json is not null " +
+            "and JSON_EXTRACT(config_json, '$.enabled') = true")
+    List<Live> selectLiveListWithCompletionPointsEnabled();
+
     void updateStatusAndTimeBatchById(@Param("liveList") List<Live> list);
 
     @Select("select * from live where (company_id = #{companyId} or company_id is null)  and is_audit = 1 and is_del = 0 and is_show = 1 and status != 3\n")

+ 6 - 0
fs-service/src/main/java/com/fs/live/service/ILiveService.java

@@ -164,6 +164,12 @@ public interface ILiveService
 
     List<Live> selectNoEndLiveList();
 
+    /**
+     * 查询开启了完课积分配置的直播间
+     * @return 直播列表
+     */
+    List<Live> selectLiveListWithCompletionPointsEnabled();
+
     void updateBatchById(List<Live> list);
 
     void updateStatusAndTimeBatchById(List<Live> list);

+ 18 - 0
fs-service/src/main/java/com/fs/live/service/impl/LiveServiceImpl.java

@@ -228,6 +228,11 @@ public class LiveServiceImpl implements ILiveService
         return baseMapper.selectNoEndLiveList();
     }
 
+    @Override
+    public List<Live> selectLiveListWithCompletionPointsEnabled() {
+        return baseMapper.selectLiveListWithCompletionPointsEnabled();
+    }
+
     @Override
     public void updateBatchById(List<Live> list) {
         baseMapper.updateLiveList(list);
@@ -265,6 +270,19 @@ public class LiveServiceImpl implements ILiveService
         // liveVo.setStoreId(storeId);
 		BeanUtils.copyProperties(live, liveVo);
 		liveVo.setNowDuration(200L);
+
+        Boolean completionPointsEnabled = false;
+        String configJson = live.getConfigJson();
+        if (StringUtils.isNotEmpty(configJson)) {
+            try {
+                JSONObject jsonConfig = JSON.parseObject(configJson);
+                completionPointsEnabled = jsonConfig.getBooleanValue("enabled");
+            } catch (Exception e) {
+                log.warn("解析直播完课积分配置失败, liveId={}", id, e);
+            }
+        }
+        liveVo.setCompletionPointsEnabled(completionPointsEnabled);
+        
         LiveVideo liveVideo = liveVideoService.selectLiveVideoByLiveIdAndType(id, 3);
         if (liveVideo != null) {
             liveVo.setPreviewUrl(liveVideo.getVideoUrl());

+ 6 - 0
fs-service/src/main/java/com/fs/live/vo/LiveVo.java

@@ -33,6 +33,9 @@ public class LiveVo {
     private String liveImgUrl;
 
     private String liveConfig;
+    
+    /** 直播配置 */
+    private String configJson;
 
     private String videoUrl;
     private Long videoId;
@@ -55,4 +58,7 @@ public class LiveVo {
     private Integer previewVideoType;
     private Long previewVideoId;
     private Integer globalVisible;
+    
+    /** 是否开启直播完课积分功能 */
+    private Boolean completionPointsEnabled;
 }

+ 1 - 1
fs-service/src/main/java/com/fs/newAdv/domain/Lead.java

@@ -148,7 +148,7 @@ public class Lead implements Serializable {
      */
     private String unitId;
     /**
-     * 创意ID
+     * 广告投流的最小单元 创意ID
      */
     private String ideaId;
     /**

+ 4 - 0
fs-service/src/main/java/com/fs/newAdv/domain/Site.java

@@ -120,6 +120,10 @@ public class Site implements Serializable {
      */
     private Long allocationRuleId;
 
+    /**
+     * 广告投流的最小单元 创意ID
+     */
+    private String ideaId;
     /**
      * 创建时间
      */

+ 1 - 1
fs-service/src/main/java/com/fs/newAdv/event/ConversionEventListener.java

@@ -35,7 +35,7 @@ public class ConversionEventListener {
      *
      * @param event 转化事件
      */
-    @Async("asyncExecutor")
+    @Async
     @EventListener
     public void handleConversionEvent(ConversionEvent event) {
         String traceId = event.getTraceId();

+ 1 - 1
fs-service/src/main/java/com/fs/newAdv/integration/client/IApiClient.java

@@ -20,6 +20,6 @@ public interface IApiClient {
 
     AdvertiserTypeEnum getAdvertiserType();
 
-    SiteStatistics getDataReport(PromotionAccount account,String startDate,String endDate);
+    SiteStatistics getDataReport(PromotionAccount account,String ideaId,String startDate,String endDate);
 }
 

+ 1 - 1
fs-service/src/main/java/com/fs/newAdv/integration/client/advertiser/BaiduApiClient.java

@@ -118,7 +118,7 @@ public class BaiduApiClient extends AbstractApiClient implements IAccessTokenCli
     }
 
     @Override
-    public SiteStatistics getDataReport(PromotionAccount account, String startDate, String endDate) {
+    public SiteStatistics getDataReport(PromotionAccount account,String ideaId, String startDate, String endDate) {
         // 构建请求参数
         Map<String, Object> map = new HashMap<>();
         Map<String, Object> header = new HashMap<>();

+ 1 - 1
fs-service/src/main/java/com/fs/newAdv/integration/client/advertiser/IQIYIApiClient.java

@@ -70,7 +70,7 @@ public class IQIYIApiClient extends AbstractApiClient {
     }
 
     @Override
-    public SiteStatistics getDataReport(PromotionAccount account,String startDate,String endDate) {
+    public SiteStatistics getDataReport(PromotionAccount account,String ideaId,String startDate,String endDate) {
         return null;
     }
 }

+ 1 - 1
fs-service/src/main/java/com/fs/newAdv/integration/client/advertiser/OPPOApiClient.java

@@ -92,7 +92,7 @@ public class OPPOApiClient extends AbstractApiClient {
     }
 
     @Override
-    public SiteStatistics getDataReport(PromotionAccount account,String startDate,String endDate) {
+    public SiteStatistics getDataReport(PromotionAccount account,String ideaId,String startDate,String endDate) {
         return null;
     }
 }

+ 88 - 9
fs-service/src/main/java/com/fs/newAdv/integration/client/advertiser/OceanEngineApiClient.java

@@ -3,22 +3,28 @@ package com.fs.newAdv.integration.client.advertiser;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.http.HttpRequest;
 import cn.hutool.http.HttpResponse;
+import cn.hutool.json.JSONArray;
 import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
-import com.fs.newAdv.integration.client.AbstractApiClient;
-import com.fs.newAdv.integration.client.IAccessTokenClient;
+import com.baidu.dev2.thirdparty.jackson.core.JsonProcessingException;
+import com.baidu.dev2.thirdparty.jackson.databind.ObjectMapper;
 import com.fs.common.constant.SystemConstant;
 import com.fs.common.exception.ThirdPartyException;
 import com.fs.newAdv.domain.PromotionAccount;
 import com.fs.newAdv.domain.SiteStatistics;
 import com.fs.newAdv.enums.AdvertiserTypeEnum;
+import com.fs.newAdv.integration.client.AbstractApiClient;
+import com.fs.newAdv.integration.client.IAccessTokenClient;
 import com.fs.newAdv.vo.AccessTokenByAuthCodeVo;
 import com.fs.newAdv.vo.AccessTokenVo;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.http.client.utils.URIBuilder;
 import org.springframework.stereotype.Component;
 
-import java.util.HashMap;
-import java.util.Map;
+import java.math.BigDecimal;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.*;
 
 /**
  * 巨量引擎API客户端
@@ -35,7 +41,8 @@ public class OceanEngineApiClient extends AbstractApiClient implements IAccessTo
     /**
      * 巨量引擎转化回传API地址
      */
-    private static final String CONVERSION_API_URL = "https://ad.oceanengine.com/track/activate";
+    private static final String CONVERSION_API_URL = "https://ad.oceanengine.com/track/activate/";
+    private static final String REPORT_API_URL = "https://api.oceanengine.com/open_api/v3.0/report/custom/get/";
     /**
      * 获取Access Token
      */
@@ -127,13 +134,83 @@ public class OceanEngineApiClient extends AbstractApiClient implements IAccessTo
     }
 
     @Override
-    public SiteStatistics getDataReport(PromotionAccount account,String startDate,String endDate) {
-        return null;
+    public SiteStatistics getDataReport(PromotionAccount account,String ideaId, String startDate, String endDate) {
+        // 构建请求参数
+        Map<String, Object> map = new HashMap<>();
+        map.put("advertiser_id", Long.valueOf(account.getAdAccountId()));
+        // 纬度--天
+        map.put("dimensions", Arrays.asList("stat_time_day"));
+        // 过滤条件
+        Map<String,Object> filters = new HashMap<>();
+        filters.put("field","cdp_promotion_id");
+        filters.put("type",2);
+        filters.put("operator",1);
+        filters.put("values ",Arrays.asList(ideaId));
+        map.put("filters", Arrays.asList(filters));
+        /**
+         * stat_cost 消耗(元)
+         * show_cnt 展示数
+         * cpm_platform 平均千次展现费用(元)
+         * click_cnt 点击数
+         * ctr 点击率
+         * cpc_platform 平均点击单价(元)
+         * convert_cnt 转化数
+         * conversion_cost 平均转化成本
+         * conversion_rate 转化率
+         */
+        map.put("metrics", Arrays.asList("stat_cost",
+                "show_cnt", "cpm_platform", "click_cnt", "ctr", "cpc_platform", "cpc_platform", "convert_cnt",
+                "conversion_cost", "conversion_rate"));
+        map.put("start_time", startDate);
+        map.put("end_time", endDate);
+        map.put("order_by", Collections.emptyList());
+        String url;
+        try {
+            URIBuilder ub = new URIBuilder(REPORT_API_URL);
+            ObjectMapper objectMapper = new ObjectMapper();
+            map.forEach((k, v) -> {
+                try {
+                    ub.addParameter(k, v instanceof String ? (String) v : objectMapper.writeValueAsString(v));
+                } catch (JsonProcessingException e) {
+                    throw new RuntimeException(e);
+                }
+            });
+            url = ub.build().toURL().toString();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        HttpResponse execute = HttpRequest.get(url)
+                .header("Access-Token", account.getAccessToken())
+                .timeout(SystemConstant.API_TIMEOUT)
+                .execute();
+        JSONObject jsonObject = JSONUtil.parseObj(execute.body());
+        if (jsonObject.getInt("code") != 0) {
+            // 刷新token重新请求
+            log.info("巨量刷新token重新请求");
+            AccessTokenVo accessTokenVo = refreshAccessToken(account.getAppId(), account.getAppSecret(), account.getRefreshToken());
+            execute = HttpRequest.get(url)
+                    .header("Access-Token", accessTokenVo.getAccessToken())
+                    .timeout(SystemConstant.API_TIMEOUT)
+                    .execute();
+            jsonObject = JSONUtil.parseObj(execute.body());
+        }
+        JSONObject data = jsonObject.getJSONObject("data");
+        JSONArray rows = data.getJSONArray("rows");
+        JSONObject jsonObject1 = rows.getJSONObject(0);
+        JSONObject jsonObject2 = jsonObject1.getJSONObject("metrics");
+        SiteStatistics siteStatistics = new SiteStatistics();
+        siteStatistics.setImpressionCount(Integer.valueOf(jsonObject2.getStr("show_cnt")));
+        siteStatistics.setClickCount(Integer.valueOf(jsonObject2.getStr("click_cnt")));
+        siteStatistics.setActualCost(new BigDecimal(jsonObject2.getStr("stat_cost")));
+        siteStatistics.setAccountCost(new BigDecimal(jsonObject2.getStr("stat_cost")));
+        siteStatistics.setClickRate(new BigDecimal(jsonObject2.getStr("ctr")));
+        siteStatistics.setAvgClickPrice(new BigDecimal(jsonObject2.getStr("cpc_platform")));
+        return siteStatistics;
     }
 
     @Override
     public AccessTokenVo refreshAccessToken(String appId, String appSecret, String refreshToken) {
-        Map<String,Object> map = new HashMap<>();
+        Map<String, Object> map = new HashMap<>();
         map.put("app_id", appId);
         map.put("secret", appSecret);
         map.put("refresh_token", refreshToken);
@@ -157,7 +234,7 @@ public class OceanEngineApiClient extends AbstractApiClient implements IAccessTo
 
     @Override
     public AccessTokenVo getAccessTokenByAuthCode(AccessTokenByAuthCodeVo request) {
-        Map<String,Object> map = new HashMap<>();
+        Map<String, Object> map = new HashMap<>();
         map.put("app_id", request.getAppId());
         map.put("secret", request.getAppSecret());
         map.put("auth_code", request.getAuthCode());
@@ -179,5 +256,7 @@ public class OceanEngineApiClient extends AbstractApiClient implements IAccessTo
         }
         return null;
     }
+
+
 }
 

+ 1 - 1
fs-service/src/main/java/com/fs/newAdv/integration/client/advertiser/TencentApiClient.java

@@ -83,7 +83,7 @@ public class TencentApiClient extends AbstractApiClient implements IAccessTokenC
     }
 
     @Override
-    public SiteStatistics getDataReport(PromotionAccount account, String startDate, String endDate) {
+    public SiteStatistics getDataReport(PromotionAccount account,String ideaId, String startDate, String endDate) {
         return null;
     }
 

+ 1 - 1
fs-service/src/main/java/com/fs/newAdv/integration/client/advertiser/VIVOApiClient.java

@@ -86,7 +86,7 @@ public class VIVOApiClient extends AbstractApiClient {
     }
 
     @Override
-    public SiteStatistics getDataReport(PromotionAccount account,String startDate,String endDate) {
+    public SiteStatistics getDataReport(PromotionAccount account,String ideaId,String startDate,String endDate) {
         return null;
     }
 }

+ 22 - 18
fs-service/src/main/java/com/fs/newAdv/service/impl/LeadServiceImpl.java

@@ -53,7 +53,7 @@ public class LeadServiceImpl extends ServiceImpl<LeadMapper, Lead> implements IL
     }
 
     @Override
-    @Async("asyncExecutor")
+    @Async
     public void updateGroupAddMemberLead(String userId, String chatId, String corpId, String unionid) {
         // 末次归因逻辑
         Lead lead = this.getOne(new LambdaQueryWrapper<Lead>()
@@ -79,7 +79,7 @@ public class LeadServiceImpl extends ServiceImpl<LeadMapper, Lead> implements IL
     }
 
     @Override
-    @Async("asyncExecutor")
+    @Async
     public CompletableFuture<String> updateAddMemberLead(String externalUserID, String userID, String corpId, String state) {
         QwExternalContactResult externalContactResult = qwApiService.getExternalcontact(externalUserID, corpId);
         String unionid = externalContactResult.getExternal_contact().getUnionid();
@@ -117,26 +117,30 @@ public class LeadServiceImpl extends ServiceImpl<LeadMapper, Lead> implements IL
     }
 
     @Override
-    @Async("asyncExecutor")
+    @Async
     public void weChatAuthorizationLead(String traceId, String unionId, String mpOpenId, String phone) {
-        Lead byTraceId = this.getByTraceId(traceId);
-        if (byTraceId == null) {
-            return;
-        }
-        this.update(new LambdaUpdateWrapper<Lead>()
-                .eq(Lead::getTraceId, traceId)
-                .set(Lead::getUnionid, unionId)
-                .set(Lead::getPhone, phone)
-                .set(Lead::getOpenid, mpOpenId)
-                .set(Lead::getMiniAuth, 1));
-        if (ObjectUtil.isNotEmpty(byTraceId.getLandingPageTs()) && byTraceId.getLandingPageTs().toLocalDate().isEqual(LocalDate.now())) {
-            // 微信授权且当日创建事件
-            conversionEventPublisher.publishConversionEvent(traceId, SystemEventTypeEnum.AUTH_TODAY_CREATE);
-        }
+       try{
+           Lead byTraceId = this.getByTraceId(traceId);
+           if (byTraceId == null) {
+               return;
+           }
+           this.update(new LambdaUpdateWrapper<Lead>()
+                   .eq(Lead::getTraceId, traceId)
+                   .set(Lead::getUnionid, unionId)
+                   .set(Lead::getPhone, phone)
+                   .set(Lead::getOpenid, mpOpenId)
+                   .set(Lead::getMiniAuth, 1));
+           if (ObjectUtil.isNotEmpty(byTraceId.getLandingPageTs()) && byTraceId.getLandingPageTs().toLocalDate().isEqual(LocalDate.now())) {
+               // 微信授权且当日创建事件
+               conversionEventPublisher.publishConversionEvent(traceId, SystemEventTypeEnum.AUTH_TODAY_CREATE);
+           }
+       }catch (Exception e){
+           e.printStackTrace();
+       }
     }
 
     @Override
-    @Async("asyncExecutor")
+    @Async
     public void updateAuthIndex(String traceId, Integer type) {
         LambdaUpdateWrapper<Lead> eq = new LambdaUpdateWrapper<Lead>().eq(Lead::getTraceId, traceId);
         if (type == 1) {

+ 4 - 4
fs-service/src/main/java/com/fs/newAdv/service/impl/SiteStatisticsServiceImpl.java

@@ -82,7 +82,7 @@ public class SiteStatisticsServiceImpl extends ServiceImpl<SiteStatisticsMapper,
                                 log.warn("账户 {} 未关联站点,跳过同步", account.getAccountName());
                                 return false;
                             }
-                            syncAccountData(account, site.getId(), batchNo);
+                            syncAccountData(account, site.getId(),site.getIdeaId(), batchNo);
                             return true;
                         } catch (Exception e) {
                             log.error("同步账户 {} 数据失败", account.getAccountName(), e);
@@ -98,9 +98,9 @@ public class SiteStatisticsServiceImpl extends ServiceImpl<SiteStatisticsMapper,
     }
 
     /**
-     * 同步账户数据
+     * 同步账户广告数据
      */
-    private void syncAccountData(PromotionAccount account, Long siteId, String batchNo) {
+    private void syncAccountData(PromotionAccount account, Long siteId,String ideaId, String batchNo) {
         log.info("开始同步账户:{}", account.getAccountName());
 
         // 查询现有统计记录
@@ -115,7 +115,7 @@ public class SiteStatisticsServiceImpl extends ServiceImpl<SiteStatisticsMapper,
         if (Integer.valueOf(1).equals(account.getApiSwitch())) {
             IApiClient apiClient = advertiserHandlerFactory.getApiClient(AdvertiserTypeEnum.getByCode(account.getAdvertiserId()));
             try {
-                siteStatistics = apiClient.getDataReport(account, batchNo, batchNo);
+                siteStatistics = apiClient.getDataReport(account,ideaId, batchNo, batchNo);
             } catch (Exception e) {
                 siteStatistics = new SiteStatistics();
                 log.error("获取账户数据失败:{} {}", account.getAccountName(), siteId, e);

+ 14 - 1
fs-service/src/main/java/com/fs/qw/service/impl/QwExternalContactServiceImpl.java

@@ -5,7 +5,9 @@ import cn.hutool.core.date.DateUtil;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONException;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fs.ad.enums.AdUploadType;
@@ -15,6 +17,7 @@ import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.PubFun;
 import com.fs.common.utils.StringUtils;
 import com.fs.company.service.ICompanyConfigService;
+import com.fs.config.cloud.CloudHostProper;
 import com.fs.course.domain.FsCourseSop;
 import com.fs.course.domain.FsCourseSopLogs;
 import com.fs.course.domain.FsCourseWatchLog;
@@ -212,7 +215,8 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
     private AsyncQwAiChatSopService asyncQwAiChatSopService;
     @Autowired
     private QwExternalContactTransferCompanyAuditUserMapper companyAuditUserMapper;
-
+    @Autowired
+    private CloudHostProper cloudHostProper;
 
     Logger logger = LoggerFactory.getLogger(getClass());
 
@@ -2883,6 +2887,15 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
                 qwContactWayMapper.addInformationNum(wayId.getInformationId());
             }
         }
+        /*只有ddgy加重粉*/
+        if (("叮当国医".equals(cloudHostProper.getCompanyName()))) {
+            if (qwExternalContactMapper.selectCount(new LambdaQueryWrapper<QwExternalContact>().eq(QwExternalContact::getExternalUserId, qwExternalContact.getExternalUserId()))
+            >1){
+                qwExternalContact.setIsRepeat(1);
+                qwExternalContactMapper.update(null,new LambdaUpdateWrapper<QwExternalContact>().eq(QwExternalContact::getId,qwExternalContact.getId())
+                        .set(QwExternalContact::getIsRepeat,1));
+            }
+        }
     }
     public void checkHaveQwSop(Set<String> combinedTagsSet,QwUser qwUser,String corpId,List<String> combinedTagsList,
                                String userID,String externalUserID,ExternalContact externalContact,QwExternalContact contact,

+ 2 - 0
fs-service/src/main/java/com/fs/qw/vo/QwSopCourseFinishTempSetting.java

@@ -23,6 +23,8 @@ public class QwSopCourseFinishTempSetting implements Serializable,Cloneable{
     //课节
     private Integer videoId;
 
+    private Long liveId;
+
     private List<Setting> setting;
 
     @Override

+ 2 - 0
fs-service/src/main/java/com/fs/qw/vo/QwSopTempSetting.java

@@ -47,6 +47,8 @@ public class QwSopTempSetting implements Serializable{
         
         private Integer isAtAll;
 
+        private Long liveId;
+
         @Override
         public Content clone() {
             try {

+ 3 - 1
fs-service/src/main/java/com/fs/sop/domain/QwSopLogs.java

@@ -61,7 +61,9 @@ public class QwSopLogs implements Serializable {
     private String msgId;
 
     /**
-    * 发送类型 1企微发送 2 Ai接口发送  3:完课发送  4:AI对话 5一键群发 6一键群发app
+    * 发送类型  1企微发送 2 Ai接口发送  3:完课发送  4:AI对话 5一键群发 6客户群群发
+     * 7欢迎语补发 8AI 9清除草稿 10发送草稿 11 课程模板类型 12 一键群发APP
+     * 13 注册链接 14 福袋  20直播间发送
     */
     private Integer sendType;
 

+ 7 - 0
fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsInfoServiceImpl.java

@@ -690,6 +690,8 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                                 break;
                             //直播小程序单独
                             case "12":
+                                sopLogs.setSendType(20);
+                                setting.setLiveId(Long.valueOf(st.getLiveId()));
                                 String sortLiveLink = "/pages_course/living.html?companyId=" + qwUser.getCompanyUserId() + "&companyUserId=" + companyUserId + "&liveId=" + st.getLiveId() + "&corpId=" + param.getCorpId()+"&qwUserId=" + qwUser.getId() +"&externalId=" + vo.getId().toString();
                                 st.setContentType("4");
                                 String js = configService.selectConfigByKey("his.config");
@@ -881,6 +883,8 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                                 break;
                             //直播小程序单独
                             case "12":
+                                sopLogs.setSendType(20);
+                                setting.setLiveId(setting.getLiveId());
                                 String sortLiveLink = "/pages_course/living.html?companyId=" + qwUser.getCompanyUserId() + "&companyUserId=" + qwUser.getCompanyUserId() + "&liveId=" + st.getLiveId() + "&corpId=" +param.getCorpId()+"&qwUserId=" + qwUser.getId() + "&chatId=" + groupChat.getChatId();
                                 st.setContentType("4");
                                 String js = configService.selectConfigByKey("his.config");
@@ -1154,6 +1158,8 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                             break;
                         //直播小程序单独
                         case "12":
+                            sopLogs.setSendType(20);
+                            setting.setLiveId(Long.valueOf(st.getLiveId()));
                             String sortLiveLink = "/pages_course/living.html?companyId=" + qwUser.getCompanyUserId() + "&companyUserId=" + qwUser.getCompanyUserId() + "&liveId=" + st.getLiveId() + "&corpId=" + param.getCorpId()+"&qwUserId=" + qwUserId +"&externalId=" + item.getExternalId().toString();
                             st.setContentType("4");
                             String js = configService.selectConfigByKey("his.config");
@@ -1746,6 +1752,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                 //直播小程序单独
                 case "12":
                     String sortLiveLink;
+                    sopLogs.setSendType(20);
                     sortLiveLink = "/pages_course/living.html?companyId=" + companyId + "&companyUserId=" + companyUserId + "&liveId=" + st.getLiveId() + "&corpId=" + param.getCorpId()+"&qwUserId=" + qwUser.getId() +"&externalId=" + item.getExternalId().toString();
 
 

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

@@ -77,6 +77,7 @@ cloud_host:
   company_name: 赤峰润
   projectCode: ryt
   spaceName:
+  volcengineUrl:
 #看课授权时显示的头像
 headerImg:
   imgUrl: https://ysy-1329817240.cos.ap-guangzhou.myqcloud.com/ysy/20250820/2c47e4f105b641b4a49df50a77338e32.png

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

@@ -82,7 +82,8 @@ tencent_cloud_config:
 cloud_host:
   company_name: 赤峰润
   projectCode: ryt
-  spaceName:
+  spaceName: ryt-2114522511
+  volcengineUrl: https://rytvolcengine.ylrztop.com
 #看课授权时显示的头像
 headerImg:
   imgUrl: https://ysy-1329817240.cos.ap-guangzhou.myqcloud.com/ysy/20250820/2c47e4f105b641b4a49df50a77338e32.png

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

@@ -107,6 +107,7 @@ cloud_host:
   company_name: 福本源
   projectCode: FBY
   spaceName:
+  volcengineUrl:
 headerImg:
   imgUrl: https://fbylive.obs.cn-southwest-2.myhuaweicloud.com/fs/20250730/1753840024082.png
 ipad:

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

@@ -84,6 +84,7 @@ cloud_host:
   company_name: 广州郑多燕
   projectCode: GZZDY
   spaceName:
+  volcengineUrl:
 #看课授权时显示的头像
 headerImg:
   imgUrl:

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

@@ -87,7 +87,8 @@ tencent_cloud_config:
 cloud_host:
   company_name: 恒安图
   projectCode: HAT
-  spaceName:
+  spaceName: hat-2114522511
+  volcengineUrl: https://hatvolcengine.ylrztop.com
 #看课授权时显示的头像
 headerImg:
   imgUrl: https://hat-1323137866.cos.ap-chongqing.myqcloud.com/fs/20250928/hatlogo.png

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

@@ -84,6 +84,7 @@ cloud_host:
   company_name: 鸿森堂
   projectCode: HST
   spaceName:
+  volcengineUrl:
 #看课授权时显示的头像
 headerImg:
   imgUrl:

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

@@ -82,8 +82,8 @@ tencent_cloud_config:
 cloud_host:
   company_name: 河山医院
   projectCode: heshanyy
-  spaceName:
-  volcengineUrl:
+  spaceName: heshanyy-2114522511
+  volcengineUrl: https://heshanyyvolcengine.ylrztop.com
 #看课授权时显示的头像
 headerImg:
   imgUrl: https://hsyy-1348049832.cos.ap-chongqing.myqcloud.com/hsyy.jpg

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

@@ -84,6 +84,7 @@ cloud_host:
   company_name: 宽益堂
   projectCode: KYT
   spaceName:
+  volcengineUrl:
 #看课授权时显示的头像
 headerImg:
   imgUrl: https://kuanyitang-1317640934.cos.ap-shanghai.myqcloud.com/kuanyitang/20250813/6b3b62e01672407c98f0561b73e35f6a.jpg

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

@@ -91,6 +91,7 @@ cloud_host:
   company_name: 同顺堂
   projectCode: QDTST
   spaceName:
+  volcengineUrl:
 #看课授权时显示的头像
 headerImg:
   imgUrl: https://qdtst-1360717104.cos.ap-nanjing.myqcloud.com/qdtst-1360717104/20250624/937019e4090f46788ef29c4e7df479c3.jpg

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

@@ -62,6 +62,12 @@ watch:
 fs :
   commonApi: http://172.30.0.11:8010
   h5CommonApi: http://119.29.195.254:8010
+  jwt:
+    # 加密秘钥
+    secret: 9a3f7b1c2e8d45a0f632b819e4c56d12
+    # token有效时长,7天,单位秒
+    expire: 31536000
+    header: AppToken
 nuonuo:
   key: 10924508
   secret: A2EB20764D304D16
@@ -77,6 +83,8 @@ cloud_host:
   company_name: 四福堂
   projectCode: SFT
   spaceName:
+  volcengineUrl:
+
 #看课授权时显示的头像
 headerImg:
   imgUrl: https://sft-1361917636.cos.ap-chongqing.myqcloud.com/sft/20250606/b08b1a6212f44f2998423c8c5d7712ee.png

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

@@ -87,8 +87,8 @@ tencent_cloud_config:
 cloud_host:
   company_name: 今正科技
   projectCode: SXJZ
-  spaceName:
-  volcengineUrl:
+  spaceName: sxjz-2114522511
+  volcengineUrl: https://sxjzvolcengine.ylrztop.com
 #看课授权时显示的头像
 headerImg:
   imgUrl: https://jz-cos-1356808054.cos.ap-chengdu.myqcloud.com/fs/20250515/0877754b59814ea8a428fa3697b20e68.png

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

@@ -76,7 +76,8 @@ tencent_cloud_config:
 cloud_host:
   company_name: 益善缘
   projectCode: SYYSY
-  spaceName:
+  spaceName: syysy-2114522511
+  volcengineUrl: https://syysyvolcengine.ylrztop.com
 #看课授权时显示的头像
 headerImg:
   imgUrl: https://ysy-1329817240.cos.ap-guangzhou.myqcloud.com/ysy/20250820/2c47e4f105b641b4a49df50a77338e32.png

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

@@ -82,7 +82,8 @@ tencent_cloud_config:
 cloud_host:
   company_name: 易行健
   projectCode: whyxj
-  spaceName:
+  spaceName: whyxj-2114522511
+  volcengineUrl: https://whyxjvolcengine.ylrztop.com
 #看课授权时显示的头像
 headerImg:
   imgUrl: https://yxj-1323137866.cos.ap-chongqing.myqcloud.com/app/yxj.jpg

+ 1 - 0
fs-service/src/main/resources/mapper/his/FsIntegralCartMapper.xml

@@ -61,6 +61,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             ic.cash,
             ig.integral newIntegral,
             ig.cash newCash,
+            ig.stock,
             ic.cart_num,
             ic.create_time,
             ic.update_time