Преглед на файлове

Merge remote-tracking branch 'origin/master'

xgb преди 1 седмица
родител
ревизия
e38cb0e5f1
променени са 25 файла, в които са добавени 791 реда и са изтрити 42 реда
  1. 139 0
      deploy.sh
  2. 1 1
      fs-admin/src/main/resources/application.yml
  3. 3 0
      fs-live-app/src/main/java/com/fs/live/websocket/auth/WebSocketConfigurator.java
  4. 1 0
      fs-live-app/src/main/java/com/fs/live/websocket/constant/AttrConstant.java
  5. 71 1
      fs-live-app/src/main/java/com/fs/live/websocket/service/WebSocketServer.java
  6. 6 2
      fs-service/src/main/java/com/fs/live/domain/LiveCoupon.java
  7. 7 0
      fs-service/src/main/java/com/fs/live/domain/LiveData.java
  8. 8 0
      fs-service/src/main/java/com/fs/live/domain/LiveMsg.java
  9. 12 0
      fs-service/src/main/java/com/fs/live/domain/LiveWatchUser.java
  10. 11 0
      fs-service/src/main/java/com/fs/live/mapper/LiveCouponIssueUserMapper.java
  11. 4 2
      fs-service/src/main/java/com/fs/live/mapper/LiveDataMapper.java
  12. 8 0
      fs-service/src/main/java/com/fs/live/mapper/LiveGoodsMapper.java
  13. 4 1
      fs-service/src/main/java/com/fs/live/mapper/LiveMsgMapper.java
  14. 4 2
      fs-service/src/main/java/com/fs/live/mapper/LiveWatchUserMapper.java
  15. 7 0
      fs-service/src/main/java/com/fs/live/service/ILiveCouponService.java
  16. 7 0
      fs-service/src/main/java/com/fs/live/service/ILiveGoodsService.java
  17. 1 1
      fs-service/src/main/java/com/fs/live/service/ILiveWatchUserService.java
  18. 47 0
      fs-service/src/main/java/com/fs/live/service/impl/LiveAutoTaskServiceImpl.java
  19. 62 6
      fs-service/src/main/java/com/fs/live/service/impl/LiveCouponServiceImpl.java
  20. 52 12
      fs-service/src/main/java/com/fs/live/service/impl/LiveDataServiceImpl.java
  21. 5 0
      fs-service/src/main/java/com/fs/live/service/impl/LiveGoodsServiceImpl.java
  22. 48 4
      fs-service/src/main/java/com/fs/live/service/impl/LiveWatchUserServiceImpl.java
  23. 25 10
      fs-service/src/main/java/com/fs/live/vo/LiveDashBoardDataVo.java
  24. 100 0
      fs-service/src/main/resources/application-config-druid-bjzm-test.yml
  25. 158 0
      fs-service/src/main/resources/application-druid-bjzm-test.yml

+ 139 - 0
deploy.sh

@@ -0,0 +1,139 @@
+#!/bin/bash
+
+# 各服务对应的远程服务器配置 北京卓美
+declare -A SERVER_CONFIG=(
+    # 服务名:IP地址
+    ["fs-live-app"]="114.132.218.150"
+)
+
+# 通用配置(所有服务器相同)
+REMOTE_USER="root"
+REMOTE_BASE_DIR="/home/software"
+
+# 本地 JAR 包路径
+LOCAL_FS_LIVE_SOCKET_JAR="./fs-live-app/target/fs-live-app.jar"
+
+# 函数:检查本地文件是否存在
+check_local_file() {
+    if [ ! -f "$1" ]; then
+        echo "错误: 本地文件 $1 不存在。"
+        exit 1
+    fi
+}
+
+# 停止远程服务器上可能正在运行的旧版本
+stop_remote_app() {
+    local remote_user=$1
+    local remote_host=$2
+    local app_name=$3
+
+    echo "正在停止 $remote_host 上的 $app_name 服务..."
+    ssh "$remote_user@$remote_host" "pkill -f $app_name || echo '没有找到运行中的进程'"
+}
+
+# 检查服务器连通性
+check_server_connectivity() {
+    local remote_user=$1
+    local remote_host=$2
+
+    if ! ssh -o ConnectTimeout=5 "$remote_user@$remote_host" "echo '连接成功'" &>/dev/null; then
+        echo "错误: 无法连接到服务器 $remote_host"
+        return 1
+    fi
+    return 0
+}
+
+# 部署单个 JAR 包到指定服务器
+deploy_jar() {
+    local local_jar=$1
+    local service_name=$2  # 服务名,用于确定目标服务器
+    local remote_dir=$3     # 远程目录名
+
+    # 获取服务对应的服务器IP
+    local remote_host="${SERVER_CONFIG[$service_name]}"
+    if [ -z "$remote_host" ]; then
+        echo "错误: 未找到服务 $service_name 的服务器配置"
+        return 1
+    fi
+
+    local app_name=$(basename "$local_jar" .jar)
+
+    echo "========================================"
+    echo "开始部署 $service_name 到服务器 $remote_host"
+    echo "本地文件: $local_jar"
+    echo "远程目录: $REMOTE_BASE_DIR/$remote_dir"
+    echo "========================================"
+
+    # 检查本地文件
+    check_local_file "$local_jar"
+
+    # 检查服务器连通性
+    if ! check_server_connectivity "$REMOTE_USER" "$remote_host"; then
+        return 1
+    fi
+
+    # 创建远程目录(如果不存在)
+    echo "创建远程目录..."
+    ssh "$REMOTE_USER@$remote_host" "mkdir -p $REMOTE_BASE_DIR/$remote_dir"
+
+    # 停止旧版本
+    stop_remote_app "$REMOTE_USER" "$remote_host" "$app_name"
+
+    # 上传 JAR 包
+    echo "上传 JAR 包..."
+    scp "$local_jar" "$REMOTE_USER@$remote_host:$REMOTE_BASE_DIR/$remote_dir/"
+
+    # 在后台启动 JAR 包
+    echo "启动服务..."
+    ssh -f "$REMOTE_USER@$remote_host" \
+    "cd $REMOTE_BASE_DIR/$remote_dir && \
+     nohup java -jar  -Dfile.encoding=UTF-8 $app_name.jar --spring.profiles.active=druid-bjzm --server.port=7114  \
+     >> $app_name.log 2>&1 &"
+
+    # 检查进程是否启动成功
+    if ssh "$REMOTE_USER@$remote_host" "pgrep -f $app_name" &>/dev/null; then
+        echo "✓ $service_name 部署成功到 $remote_host"
+    else
+        echo "✗ $service_name 启动失败,请检查日志: $REMOTE_BASE_DIR/$remote_dir/$app_name.log"
+        return 1
+    fi
+
+    echo ""
+}
+
+# 主要部署流程
+echo "开始多服务器分布式部署..."
+echo "部署配置:"
+for service in "${!SERVER_CONFIG[@]}"; do
+    echo "  $service -> ${SERVER_CONFIG[$service]}"
+done
+echo ""
+
+# 部署 fs-live-app
+deploy_jar "$LOCAL_FS_LIVE_SOCKET_JAR" "fs-live-app" "fs-live-app"
+
+# 部署 fs-sync (注意:这里使用了不同的JAR命名方式)
+#deploy_jar "$LOCAL_FS_SYNC_APP_JAR" "fs-sync" "fs-sync"
+
+echo "========================================"
+echo "分布式部署完成!"
+echo "各服务部署状态:"
+for service in "${!SERVER_CONFIG[@]}"; do
+    remote_host="${SERVER_CONFIG[$service]}"
+    echo "  $service -> $remote_host"
+done
+echo "========================================"
+
+# 可选:显示各服务进程状态
+#echo "服务进程状态检查:"
+#for service in "${!SERVER_CONFIG[@]}"; do
+#    remote_host="${SERVER_CONFIG[$service]}"
+#    app_name="$service"  # 简化处理,实际可能需要根据JAR文件名调整
+#    if ssh "$REMOTE_USER@$remote_host" "pgrep -f $app_name" &>/dev/null; then
+#        echo "  ✓ $service 在 $remote_host 上运行正常"
+#    else
+#        echo "  ✗ $service 在 $remote_host 上未运行"
+#    fi
+#done
+
+# 251105 0953

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

@@ -4,7 +4,7 @@ server:
 # Spring配置
 spring:
   profiles:
-    active: dev
+    active: druid-bjzm-test
 #    active: druid-hdt
 #    active: druid-yzt
 #    active: druid-sxjz-test

+ 3 - 0
fs-live-app/src/main/java/com/fs/live/websocket/auth/WebSocketConfigurator.java

@@ -52,6 +52,9 @@ public class WebSocketConfigurator extends ServerEndpointConfig.Configurator {
         if (parameterMap.containsKey(AttrConstant.COMPANY_USER_ID)) {
             userProperties.put(AttrConstant.COMPANY_USER_ID, Long.valueOf(parameterMap.get(AttrConstant.COMPANY_USER_ID).get(0)));
         }
+        if (parameterMap.containsKey(AttrConstant.LOCATION)) {
+            userProperties.put(AttrConstant.LOCATION, parameterMap.get(AttrConstant.LOCATION).get(0));
+        }
 
         // 验证token
         if (parameterMap.containsKey(tokenKey)) {

+ 1 - 0
fs-live-app/src/main/java/com/fs/live/websocket/constant/AttrConstant.java

@@ -12,6 +12,7 @@ public class AttrConstant {
     public static final String SIGNATURE = "signature";
     public static final String COMPANY_ID = "companyId";
     public static final String COMPANY_USER_ID = "companyUserId";
+    public static final String LOCATION = "location";
 
     // 定义 AttributeKey 保存必要参数
     public static final AttributeKey<Long> ATTR_LIVE_ID = AttributeKey.valueOf(LIVE_ID);

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

@@ -72,6 +72,8 @@ public class WebSocketServer {
         long liveId = (long) userProperties.get("liveId");
         long userId = (long) userProperties.get("userId");
         long userType = (long) userProperties.get("userType");
+        String location = (String) userProperties.get("location");  // 获取location参数
+
         Live live = liveService.selectLiveByLiveId(liveId);
         if (live == null) {
             throw new BaseException("未找到直播间");
@@ -96,7 +98,7 @@ public class WebSocketServer {
                 throw new BaseException("用户信息错误");
             }
 
-            LiveWatchUser liveWatchUserVO = liveWatchUserService.join(liveId, userId);
+            LiveWatchUser liveWatchUserVO = liveWatchUserService.join(liveId, userId, location);
             room.put(userId, session);
             // 直播间浏览量 +1
             redisCache.incr(PAGE_VIEWS_KEY + liveId, 1);
@@ -262,6 +264,22 @@ public class WebSocketServer {
                             return;
                         }
 
+                        // 根据直播状态设置live_flag或replay_flag
+                        Live msgLive = liveService.selectLiveByLiveId(msg.getLiveId());
+                        if (msgLive != null && msgLive.getFinishTime() != null) {
+                            Date finishTime = java.sql.Timestamp.valueOf(msgLive.getFinishTime());
+                            if (new Date().after(finishTime)) {
+                                liveMsg.setReplayFlag(1);
+                                liveMsg.setLiveFlag(0);
+                            } else {
+                                liveMsg.setLiveFlag(1);
+                                liveMsg.setReplayFlag(0);
+                            }
+                        } else {
+                            liveMsg.setLiveFlag(1);
+                            liveMsg.setReplayFlag(0);
+                        }
+
                         liveMsgService.insertLiveMsg(liveMsg);
                     }
 
@@ -281,6 +299,23 @@ public class WebSocketServer {
                     liveMsg.setAvatar(msg.getAvatar());
                     liveMsg.setMsg(msg.getMsg());
                     liveMsg.setCreateTime(new Date());
+
+                    // 根据直播状态设置live_flag或replay_flag
+                    Live normalMsgLive = liveService.selectLiveByLiveId(msg.getLiveId());
+                    if (normalMsgLive != null && normalMsgLive.getFinishTime() != null) {
+                        Date finishTime = java.sql.Timestamp.valueOf(normalMsgLive.getFinishTime());
+                        if (new Date().after(finishTime)) {
+                            liveMsg.setReplayFlag(1);
+                            liveMsg.setLiveFlag(0);
+                        } else {
+                            liveMsg.setLiveFlag(1);
+                            liveMsg.setReplayFlag(0);
+                        }
+                    } else {
+                        liveMsg.setLiveFlag(1);
+                        liveMsg.setReplayFlag(0);
+                    }
+
                     liveMsgService.insertLiveMsg(liveMsg);
                     msg.setOn(true);
                     msg.setData(JSONObject.toJSONString(liveMsg));
@@ -302,6 +337,20 @@ public class WebSocketServer {
                     // 广播消息
                     broadcastMessage(liveId, JSONObject.toJSONString(R.ok().put("data", msg)));
                     break;
+                case "sendTopMsg":
+                    msg.setMsg(productionWordFilter.filter(msg.getMsg()).getFilteredText());
+                    if(StringUtils.isEmpty(msg.getMsg())) return;
+                    liveMsg = new LiveMsg();
+                    liveMsg.setLiveId(msg.getLiveId());
+                    liveMsg.setUserId(msg.getUserId());
+                    liveMsg.setNickName(msg.getNickName());
+                    liveMsg.setAvatar(msg.getAvatar());
+                    liveMsg.setMsg(msg.getMsg());
+                    msg.setOn(true);
+                    msg.setData(JSONObject.toJSONString(liveMsg));
+                    // 广播消息
+                    broadcastMessage(liveId, JSONObject.toJSONString(R.ok().put("data", msg)));
+                    break;
                 case "globalVisible":
                     msg.setOn(true);
                     liveWatchUserService.updateGlobalVisible(liveId, msg.getStatus());
@@ -629,6 +678,27 @@ public class WebSocketServer {
                 data.put("couponTime", liveCoupon.getCouponTime());
                 msg.setData(JSON.toJSONString(data));
                 liveCouponMapper.updateChangeShow(task.getLiveId(), liveCouponIssue.getId());
+            } else if (task.getTaskType() == 6L) {
+                // 上架/下架商品
+                msg.setCmd("goods");
+                JSONObject jsonObject = JSON.parseObject(task.getContent());
+                Long goodsId = jsonObject.getLong("goodsId");
+                Integer status = jsonObject.getInteger("status");
+                if (goodsId == null || status == null) {
+                    log.error("商品ID或状态为空");
+                    return;
+                }
+                // 更新商品上下架状态
+                liveGoodsService.updateLiveGoodsStatus(goodsId, status);
+                return ;
+                // 更新直播间配置缓存
+//                liveService.asyncToCacheLiveConfig(task.getLiveId());
+                // 查询商品信息并广播
+//                LiveGoodsVo liveGoodsVo = liveGoodsService.selectLiveGoodsVoByGoodsId(goodsId);
+//                if (liveGoodsVo != null) {
+//                    msg.setData(JSON.toJSONString(liveGoodsVo));
+//                    msg.setStatus(status);
+//                }
             }
             msg.setStatus(1);
             broadcastMessage(task.getLiveId(), JSONObject.toJSONString(R.ok().put("data", msg)));

+ 6 - 2
fs-service/src/main/java/com/fs/live/domain/LiveCoupon.java

@@ -59,14 +59,18 @@ public class LiveCoupon extends BaseEntity
     @Excel(name = "套餐分类ids")
     private String packageCateIds;
 
-    /** 优惠券类型 0-通用 1-商品券 */
-    @Excel(name = "优惠券类型 0-通用 1-商品券")
+    /** 优惠券类型 0-通用 1-商品券 2-无门槛券 */
+    @Excel(name = "优惠券类型 0-通用 1-商品券 2-无门槛券")
     private Long type;
 
     /** 是否删除 */
     @Excel(name = "是否删除")
     private Integer isDel;
 
+    /** 限制领取次数(针对无门槛优惠券,每个用户可以领取的最大张数) */
+    @Excel(name = "限制领取次数")
+    private Integer limitReceiveCount;
+
     private Long id;
     private Integer isShow;
     private Long goodsId;

+ 7 - 0
fs-service/src/main/java/com/fs/live/domain/LiveData.java

@@ -76,5 +76,12 @@ public class LiveData{
     @Excel(name = "关注数")
     private Long followNum;
 
+    /** 回放观看人次 */
+    @Excel(name = "回放观看人次")
+    private Long replayViewNum;
+
+    /** 回放点赞数 */
+    @Excel(name = "回放点赞数")
+    private Long replayLikeNum;
 
 }

+ 8 - 0
fs-service/src/main/java/com/fs/live/domain/LiveMsg.java

@@ -44,4 +44,12 @@ public class LiveMsg extends BaseEntity {
 
     @TableField(exist = false)
     private Integer singleVisible;
+
+    /** 直播消息标记:0-否 1-是 */
+    @Excel(name = "直播消息标记")
+    private Integer liveFlag = 0;
+
+    /** 回放消息标记:0-否 1-是 */
+    @Excel(name = "回放消息标记")
+    private Integer replayFlag = 0;
 }

+ 12 - 0
fs-service/src/main/java/com/fs/live/domain/LiveWatchUser.java

@@ -50,4 +50,16 @@ public class LiveWatchUser extends BaseEntity {
     private String nickName;
     private String tabName;
 
+    /** 直播进入标记:0-否 1-是 */
+    @Excel(name = "直播进入标记")
+    private Integer liveFlag = 0;
+
+    /** 回放进入标记:0-否 1-是 */
+    @Excel(name = "回放进入标记")
+    private Integer replayFlag = 0;
+
+    /** 用户所在位置 */
+    @Excel(name = "用户所在位置")
+    private String location;
+
 }

+ 11 - 0
fs-service/src/main/java/com/fs/live/mapper/LiveCouponIssueUserMapper.java

@@ -4,6 +4,8 @@ import java.util.List;
 import com.fs.live.domain.LiveCouponIssueUser;
 import com.fs.live.domain.LiveCouponUser;
 import com.fs.live.param.CouponPO;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
 
 /**
  * 优惠券用户领取记录Mapper接口
@@ -63,4 +65,13 @@ public interface LiveCouponIssueUserMapper
 
 
     List<LiveCouponUser> selectLiveCouponUserByCouponPO(CouponPO coupon);
+
+    /**
+     * 查询用户领取某个优惠券的次数
+     * @param userId 用户ID
+     * @param issueId 优惠券发放ID
+     * @return 领取次数
+     */
+    @Select("SELECT COUNT(1) FROM live_coupon_issue_user WHERE user_id = #{userId} AND issue_id = #{issueId} AND is_del = 0")
+    int countUserReceivedCoupon(@Param("userId") Long userId, @Param("issueId") Long issueId);
 }

+ 4 - 2
fs-service/src/main/java/com/fs/live/mapper/LiveDataMapper.java

@@ -131,8 +131,10 @@ public interface LiveDataMapper {
     List<Map<String, Object>> getCompanyChartData(@Param("chartStartDate") String chartStartDate,@Param("chartEndDate") String chartEndDate, @Param("format") String format,@Param("category") String category,@Param("companyId") Long companyId);
 
     @Select("SELECT " +
-            "    ld.total_views AS viewNum,                        " +
-            "    ld.likes AS likeNum                        " +
+            "    ld.total_views AS liveViewNum, " +
+            "    ld.replay_view_num AS replayViewNum, " +
+            "    ld.likes AS liveLikeNum, " +
+            "    ld.replay_like_num AS replayLikeNum " +
             "FROM " +
             "    live_data ld " +
             "where ld.live_id=#{liveId}")

+ 8 - 0
fs-service/src/main/java/com/fs/live/mapper/LiveGoodsMapper.java

@@ -149,4 +149,12 @@ public interface LiveGoodsMapper {
             "ELSE 0 END where live_id = #{liveId}" +
             "</script>"})
     void updateLiveIsShow(@Param("goodsId")Long goodsId,@Param("liveId") Long liveId);
+
+    /**
+     * 根据goodsId更新商品上下架状态
+     * @param goodsId 商品ID
+     * @param status 状态:1-上架 0-下架
+     */
+    @Update("update live_goods set is_show = #{status} where goods_id = #{goodsId}")
+    void updateLiveGoodsStatus(@Param("goodsId") Long goodsId, @Param("status") Integer status);
 }

+ 4 - 1
fs-service/src/main/java/com/fs/live/mapper/LiveMsgMapper.java

@@ -77,7 +77,10 @@ public interface LiveMsgMapper
     @Select("select * from live_msg where live_id = #{liveId} order by create_time desc limit 30")
     List<LiveMsg> listRecentMsg(@Param("liveId")Long liveId);
 
-    @Select("SELECT count(1) as commentNum from live_msg where live_id = #{liveId}")
+    @Select("SELECT " +
+            "    SUM(CASE WHEN live_flag = 1 THEN 1 ELSE 0 END) AS liveCommentNum, " +
+            "    SUM(CASE WHEN replay_flag = 1 THEN 1 ELSE 0 END) AS replayCommentNum " +
+            "FROM live_msg WHERE live_id = #{liveId}")
     Map<String, Long> selectDashboardCount(@Param("liveId") Long liveId);
 
     List<LiveMsg> selectLiveMsgSingleList(LiveMsg liveMsg);

+ 4 - 2
fs-service/src/main/java/com/fs/live/mapper/LiveWatchUserMapper.java

@@ -120,8 +120,10 @@ public interface LiveWatchUserMapper {
 
     @Select("SELECT " +
             "    SUM(CASE WHEN online = 0 and msg_status = 0 THEN 1 ELSE 0 END) AS onlineNum, " +
-            "    SUM(CASE WHEN user_id > 0 THEN 1 ELSE 0 END) AS newUserNum, " +
-            "    SUM(CASE WHEN user_id > 0 THEN 1 ELSE 0 END) AS oldUserNum " +
+            "    SUM(CASE WHEN user_id > 0 AND live_flag = 1 THEN 1 ELSE 0 END) AS liveNewUserNum, " +
+            "    SUM(CASE WHEN user_id > 0 AND live_flag = 1 THEN 1 ELSE 0 END) AS liveOldUserNum, " +
+            "    SUM(CASE WHEN user_id > 0 AND replay_flag = 1 THEN 1 ELSE 0 END) AS replayNewUserNum, " +
+            "    SUM(CASE WHEN user_id > 0 AND replay_flag = 1 THEN 1 ELSE 0 END) AS replayOldUserNum " +
             "FROM " +
             "    live_watch_user where live_id=#{liveId}"
     )

+ 7 - 0
fs-service/src/main/java/com/fs/live/service/ILiveCouponService.java

@@ -88,4 +88,11 @@ public interface ILiveCouponService
     R curCoupon(CouponPO coupon);
 
     List<LiveCoupon> listOn(Long liveId);
+
+    /**
+     * 使用无门槛优惠券(新方法,跳过普通优惠券的校验逻辑)
+     * @param coupon 优惠券参数
+     * @return 结果
+     */
+    R useNoThresholdCoupon(CouponPO coupon);
 }

+ 7 - 0
fs-service/src/main/java/com/fs/live/service/ILiveGoodsService.java

@@ -124,4 +124,11 @@ public interface ILiveGoodsService {
     void updateLiveIsShow(Long goodsId, Long liveId);
 
     R getStoreByLiveId(Long liveId, String key, String userId);
+
+    /**
+     * 根据商品ID更新商品上下架状态
+     * @param goodsId 商品ID
+     * @param status 状态:1-上架 0-下架
+     */
+    void updateLiveGoodsStatus(Long goodsId, Integer status);
 }

+ 1 - 1
fs-service/src/main/java/com/fs/live/service/ILiveWatchUserService.java

@@ -75,7 +75,7 @@ public interface ILiveWatchUserService {
 
     LiveWatchUser getByLiveIdAndUserId(long liveId, long userId);
 
-    LiveWatchUser join(long liveId, long userId);
+    LiveWatchUser join(long liveId, long userId, String location);
     LiveWatchUser close(long liveId, long userId);
 
     /**

+ 47 - 0
fs-service/src/main/java/com/fs/live/service/impl/LiveAutoTaskServiceImpl.java

@@ -151,6 +151,30 @@ public class LiveAutoTaskServiceImpl implements ILiveAutoTaskService {
             liveCoupon.setGoodsId(liveCouponIssueRelation.getGoodsId());
             liveAutoTask.setContent(JSON.toJSONString(liveCoupon));
             baseMapper.insertLiveAutoTask(liveAutoTask);
+        } else if (liveAutoTask.getTaskType() == 6L) {
+            // 上架/下架商品
+            try {
+                com.alibaba.fastjson.JSONObject jsonObject = JSON.parseObject(liveAutoTask.getContent());
+                Long goodsId = jsonObject.getLong("goodsId");
+                Integer status = jsonObject.getInteger("status");
+                if (goodsId == null) return R.error("商品ID不能为空");
+                if (status == null) return R.error("状态不能为空");
+
+                // 查询商品信息
+                LiveGoodsVo liveGoodsVo = goodsService.selectLiveGoodsVoByGoodsId(goodsId);
+                if(liveGoodsVo == null) return R.error("商品不存在");
+
+                // 保存商品信息和上下架状态
+                com.alibaba.fastjson.JSONObject content = new com.alibaba.fastjson.JSONObject();
+                content.put("goodsId", liveGoodsVo.getGoodsId());
+                content.put("productId", liveGoodsVo.getProductId());
+                content.put("productName", liveGoodsVo.getProductName());
+                content.put("status", status);
+                liveAutoTask.setContent(content.toJSONString());
+                baseMapper.insertLiveAutoTask(liveAutoTask);
+            } catch (Exception e) {
+                return R.error("内容格式错误,应为{\"goodsId\":123,\"status\":1}");
+            }
         } else if(liveAutoTask.getTaskType() == 3L){
             baseMapper.insertLiveAutoTask(liveAutoTask);
 
@@ -267,6 +291,29 @@ public class LiveAutoTaskServiceImpl implements ILiveAutoTaskService {
             liveCoupon.setGoodsId(liveCouponIssueRelation.getGoodsId());
             liveAutoTask.setContent(JSON.toJSONString(liveCoupon));
             return baseMapper.updateLiveAutoTask(liveAutoTask);
+        } else if (liveAutoTask.getTaskType() == 6L) {
+            // 上架/下架商品
+            try {
+                com.alibaba.fastjson.JSONObject jsonObject = JSON.parseObject(liveAutoTask.getContent());
+                Long goodsId = jsonObject.getLong("goodsId");
+                Integer status = jsonObject.getInteger("status");
+                if (goodsId == null || status == null) return -1;
+
+                // 查询商品信息
+                LiveGoodsVo liveGoodsVo = goodsService.selectLiveGoodsVoByGoodsId(goodsId);
+                if(liveGoodsVo == null) return -1;
+
+                // 保存商品信息和上下架状态
+                com.alibaba.fastjson.JSONObject content = new com.alibaba.fastjson.JSONObject();
+                content.put("goodsId", liveGoodsVo.getGoodsId());
+                content.put("productId", liveGoodsVo.getProductId());
+                content.put("productName", liveGoodsVo.getProductName());
+                content.put("status", status);
+                liveAutoTask.setContent(content.toJSONString());
+                return baseMapper.updateLiveAutoTask(liveAutoTask);
+            } catch (Exception e) {
+                return -1;
+            }
         } else {
             return -1;
         }

+ 62 - 6
fs-service/src/main/java/com/fs/live/service/impl/LiveCouponServiceImpl.java

@@ -11,6 +11,7 @@ import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.live.domain.*;
+import com.fs.live.mapper.LiveCouponIssueUserMapper;
 import com.fs.live.mapper.LiveMapper;
 import com.fs.live.param.CouponPO;
 import com.fs.live.service.ILiveCouponIssueService;
@@ -48,6 +49,8 @@ public class LiveCouponServiceImpl implements ILiveCouponService
     private ILiveCouponUserService liveCouponUserService;
     @Autowired
     private ILiveCouponIssueService liveCouponIssueService;
+    @Autowired
+    private LiveCouponIssueUserMapper liveCouponIssueUserMapper;
 
     /**
      * 查询优惠券
@@ -196,18 +199,35 @@ public class LiveCouponServiceImpl implements ILiveCouponService
     @Override
     @Transactional
     public R claimCoupon(CouponPO coupon) {
-        Object o = redisCache.hashGet(String.format(LiveKeysConstant.LIVE_HOME_PAGE_CONFIG_COUPON, coupon.getLiveId(), coupon.getCouponIssueId()), String.valueOf(coupon.getUserId()));
-        if (ObjectUtil.isNotEmpty(o)) {
-            return R.error("您已经领取过优惠券了!");
-        }
         LiveCouponIssue issue = liveCouponMapper.selectLiveCouponIssueByLiveIdAndCouponId(coupon.getLiveId(), coupon.getCouponIssueId());
         if (coupon == null || issue.getStatus() != 1) {
             return R.error("优惠券不存在或者已下架!");
         }
-        Long decrement = redisCache.decrement(String.format(LiveKeysConstant.LIVE_COUPON_NUM , coupon.getCouponIssueId()));
 
         LiveCoupon liveCoupon = liveCouponMapper.selectLiveCouponById(issue.getCouponId());
+        if (liveCoupon == null) {
+            return R.error("优惠券配置不存在!");
+        }
 
+        // 判断是否为无门槛优惠券(type=2)
+        boolean isNoThresholdCoupon = liveCoupon.getType() != null && liveCoupon.getType() == 2L;
+
+        if (!isNoThresholdCoupon) {
+            // 普通优惠券:检查是否已领取
+            Object o = redisCache.hashGet(String.format(LiveKeysConstant.LIVE_HOME_PAGE_CONFIG_COUPON, coupon.getLiveId(), coupon.getCouponIssueId()), String.valueOf(coupon.getUserId()));
+            if (ObjectUtil.isNotEmpty(o)) {
+                return R.error("您已经领取过优惠券了!");
+            }
+        } else {
+            // 无门槛优惠券:检查领取次数是否超过限制
+            int receivedCount = liveCouponIssueUserMapper.countUserReceivedCoupon(coupon.getUserId(), issue.getId());
+            Integer limitCount = liveCoupon.getLimitReceiveCount() != null ? liveCoupon.getLimitReceiveCount() : 1;
+            if (receivedCount >= limitCount) {
+                return R.error("您已达到该优惠券的领取次数上限!");
+            }
+        }
+
+        Long decrement = redisCache.decrement(String.format(LiveKeysConstant.LIVE_COUPON_NUM , coupon.getCouponIssueId()));
 
         if (decrement < 0L) {
             issue.setStatus(-1);
@@ -243,7 +263,12 @@ public class LiveCouponServiceImpl implements ILiveCouponService
         userRecord.setType("live-"+coupon.getLiveId());
         liveCouponUserService.insertLiveCouponUser(userRecord);
         liveCouponIssueUserService.insertLiveCouponIssueUser(record);
-        redisCache.hashPut(String.format(LiveKeysConstant.LIVE_HOME_PAGE_CONFIG_COUPON, coupon.getLiveId(), coupon.getCouponIssueId()), String.valueOf(coupon.getUserId()), JSONUtil.toJsonStr(record));
+
+        // 对于非无门槛优惠券,记录到Redis(防止重复领取)
+        if (!isNoThresholdCoupon) {
+            redisCache.hashPut(String.format(LiveKeysConstant.LIVE_HOME_PAGE_CONFIG_COUPON, coupon.getLiveId(), coupon.getCouponIssueId()), String.valueOf(coupon.getUserId()), JSONUtil.toJsonStr(record));
+        }
+
         return R.ok("恭喜您抢到优惠券");
     }
 
@@ -264,6 +289,37 @@ public class LiveCouponServiceImpl implements ILiveCouponService
         return liveCouponMapper.listOn(liveId);
     }
 
+    /**
+     * 使用无门槛优惠券(新方法,跳过普通优惠券的校验逻辑)
+     */
+    @Override
+    @Transactional
+    public R useNoThresholdCoupon(CouponPO coupon) {
+//        // 查询优惠券信息
+//        LiveCouponUser liveCouponUser = liveCouponUserService.selectLiveCouponUserById(coupon.getCouponUserId());
+//        if (liveCouponUser == null) {
+//            return R.error("优惠券不存在!");
+//        }
+//
+//        // 检查优惠券是否已使用
+//        if (liveCouponUser.getStatus() == 1) {
+//            return R.error("优惠券已使用!");
+//        }
+//
+//        // 检查优惠券是否已过期
+//        if (liveCouponUser.getIsFail() == 0) {
+//            return R.error("优惠券已过期!");
+//        }
+//
+//        // 标记优惠券为已使用
+//        liveCouponUser.setStatus(1);
+//        liveCouponUser.setUpdateTime(DateUtils.getNowDate());
+//        liveCouponUserService.updateLiveCouponUser(liveCouponUser);
+//
+//        return R.ok("优惠券使用成功").put("couponPrice", liveCouponUser.getCouponPrice());
+        return null;
+    }
+
 
 
 }

+ 52 - 12
fs-service/src/main/java/com/fs/live/service/impl/LiveDataServiceImpl.java

@@ -72,21 +72,61 @@ public class LiveDataServiceImpl implements ILiveDataService {
     /* 直播大屏展示 数据接口 */
     @Override
     public R dashboardData(Long liveId) {
-        Map<String,BigDecimal> map1 = liveWatchUserMapper.selectDashboardCount(liveId);
-        Map<String,Integer> map2 = baseMapper.selectDashboardCount(liveId);
-        Map<String, Long> map3 = liveMsgMapper.selectDashboardCount(liveId);
-        Map<String,BigDecimal> map4 = liveUserFirstEntryMapper.selectDashboardCount(liveId);
+        // 查询用户统计数据(直播和回放)
+        Map<String, BigDecimal> watchUserMap = liveWatchUserMapper.selectDashboardCount(liveId);
+        // 查询观看和点赞数据(直播和回放)
+        Map<String, Integer> liveDataMap = baseMapper.selectDashboardCount(liveId);
+        // 查询评论数据(直播和回放)
+        Map<String, Long> msgMap = liveMsgMapper.selectDashboardCount(liveId);
+        // 查询分享和直接访问数据
+        Map<String, BigDecimal> firstEntryMap = liveUserFirstEntryMapper.selectDashboardCount(liveId);
+        
         LiveDashBoardDataVo result = new LiveDashBoardDataVo();
-        result.setOnlineNum(map1 == null ? BigDecimal.valueOf(0) : map1.getOrDefault("onlineNum", BigDecimal.valueOf(0)));
-        result.setOldUserNum(map1 == null ? BigDecimal.valueOf(0) :map1.getOrDefault("oldUserNum", BigDecimal.valueOf(0)));
-        result.setNewUserNum(map1 == null ? BigDecimal.valueOf(0) :map1.getOrDefault("newUserNum", BigDecimal.valueOf(0)));
-        result.setViewNum(map2 == null ? 0 :map2.getOrDefault("viewNum", 0));
-        result.setLikeNum(map2 == null ? 0 :map2.getOrDefault("likeNum", 0));
-        result.setCommentNum(map3 == null ? 0L :map3.getOrDefault("commentNum", 0L));
-        result.setShareUrlNum(map4 == null ? BigDecimal.valueOf(0) :map4.getOrDefault("shareUrlNum", BigDecimal.valueOf(0)));
-        result.setDirectAccessNum(map4 == null ? BigDecimal.valueOf(0) :map4.getOrDefault("directAccessNum", BigDecimal.valueOf(0)));
+        
+        // 在线人数
+        result.setOnlineNum(watchUserMap == null ? BigDecimal.valueOf(0) : 
+            watchUserMap.getOrDefault("onlineNum", BigDecimal.valueOf(0)));
+        
+        // 直播用户数据
+        result.setLiveNewUserNum(watchUserMap == null ? BigDecimal.valueOf(0) : 
+            watchUserMap.getOrDefault("liveNewUserNum", BigDecimal.valueOf(0)));
+        result.setLiveOldUserNum(watchUserMap == null ? BigDecimal.valueOf(0) : 
+            watchUserMap.getOrDefault("liveOldUserNum", BigDecimal.valueOf(0)));
+        
+        // 回放用户数据
+        result.setReplayNewUserNum(watchUserMap == null ? BigDecimal.valueOf(0) : 
+            watchUserMap.getOrDefault("replayNewUserNum", BigDecimal.valueOf(0)));
+        result.setReplayOldUserNum(watchUserMap == null ? BigDecimal.valueOf(0) : 
+            watchUserMap.getOrDefault("replayOldUserNum", BigDecimal.valueOf(0)));
+        
+        // 直播观看和点赞数据
+        result.setLiveViewNum(liveDataMap == null ? 0 : 
+            liveDataMap.getOrDefault("liveViewNum", 0));
+        result.setLiveLikeNum(liveDataMap == null ? 0 : 
+            liveDataMap.getOrDefault("liveLikeNum", 0));
+        
+        // 回放观看和点赞数据
+        result.setReplayViewNum(liveDataMap == null ? 0 : 
+            liveDataMap.getOrDefault("replayViewNum", 0));
+        result.setReplayLikeNum(liveDataMap == null ? 0 : 
+            liveDataMap.getOrDefault("replayLikeNum", 0));
+        
+        // 直播和回放评论数据
+        result.setLiveCommentNum(msgMap == null ? 0L : 
+            msgMap.getOrDefault("liveCommentNum", 0L));
+        result.setReplayCommentNum(msgMap == null ? 0L : 
+            msgMap.getOrDefault("replayCommentNum", 0L));
+        
+        // 分享和直接访问数据
+        result.setShareUrlNum(firstEntryMap == null ? BigDecimal.valueOf(0) : 
+            firstEntryMap.getOrDefault("shareUrlNum", BigDecimal.valueOf(0)));
+        result.setDirectAccessNum(firstEntryMap == null ? BigDecimal.valueOf(0) : 
+            firstEntryMap.getOrDefault("directAccessNum", BigDecimal.valueOf(0)));
+        
+        // 邀请用户列表
         List<LiveUserFirstVo> liveUserFirstVos = liveUserFirstEntryMapper.selectDashboardInviteCount(liveId);
         result.setInviteUserList(liveUserFirstVos);
+        
         return R.ok().put("data", result);
     }
 

+ 5 - 0
fs-service/src/main/java/com/fs/live/service/impl/LiveGoodsServiceImpl.java

@@ -161,6 +161,11 @@ public class LiveGoodsServiceImpl  implements ILiveGoodsService {
         baseMapper.updateLiveIsShow(goodsId, liveId);
     }
 
+    @Override
+    public void updateLiveGoodsStatus(Long goodsId, Integer status) {
+        baseMapper.updateLiveGoodsStatus(goodsId, status);
+    }
+
     @Override
     public R getStoreByLiveId(Long liveId, String key, String userId) {
         LiveGoods liveGoods = new LiveGoods();

+ 48 - 4
fs-service/src/main/java/com/fs/live/service/impl/LiveWatchUserServiceImpl.java

@@ -9,11 +9,15 @@ import com.fs.common.constant.LiveKeysConstant;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.StringUtils;
 import com.fs.his.domain.FsUser;
 import com.fs.his.service.IFsUserService;
 import com.fs.live.domain.Live;
+import com.fs.live.domain.LiveVideo;
 import com.fs.live.domain.LiveWatchUser;
 import com.fs.live.mapper.LiveWatchUserMapper;
+import com.fs.live.mapper.LiveMapper;
+import com.fs.live.mapper.LiveVideoMapper;
 import com.fs.live.service.ILiveWatchUserService;
 import com.fs.live.vo.LiveWatchUserStatistics;
 import com.fs.live.vo.LiveWatchUserVO;
@@ -42,6 +46,10 @@ public class LiveWatchUserServiceImpl implements ILiveWatchUserService {
     private IFsUserService fsUserService;
     @Autowired
     private LiveWatchUserMapper baseMapper;
+    @Autowired
+    private LiveMapper liveMapper;
+    @Autowired
+    private LiveVideoMapper liveVideoMapper;
 
 
     /**
@@ -144,12 +152,37 @@ public class LiveWatchUserServiceImpl implements ILiveWatchUserService {
     }
 
     @Override
-    public LiveWatchUser join(long liveId, long userId) {
+    public LiveWatchUser join(long liveId, long userId, String location) {
         LiveWatchUser liveWatchUser = getByLiveIdAndUserId(liveId, userId);
         FsUser fsUserVO = fsUserService.selectFsUserByUserId(userId);
+        Date now = DateUtils.getNowDate();
+        
+        // 查询直播间信息
+        Live live = liveMapper.selectLiveByLiveId(liveId);
+        
+        // 判断用户进入时间:如果进入时间大于直播结束时间,说明是回放
+        boolean isReplay = false;
+        if (live != null && live.getFinishTime() != null) {
+            Date finishTime = java.sql.Timestamp.valueOf(live.getFinishTime());
+            isReplay = now.after(finishTime);
+        }
+        
         if(liveWatchUser != null) {
-            liveWatchUser.setUpdateTime(DateUtils.getNowDate());
+            liveWatchUser.setUpdateTime(now);
             liveWatchUser.setOnline(0);
+            
+            // 更新location
+            if (StringUtils.isNotEmpty(location)) {
+                liveWatchUser.setLocation(location);
+            }
+            
+            // 更新进入标记
+            if (isReplay) {
+                liveWatchUser.setReplayFlag(1);
+            } else {
+                liveWatchUser.setLiveFlag(1);
+            }
+            
             baseMapper.updateLiveWatchUser(liveWatchUser);
         }else{
             liveWatchUser = new LiveWatchUser();
@@ -158,8 +191,19 @@ public class LiveWatchUserServiceImpl implements ILiveWatchUserService {
             liveWatchUser.setAvatar(fsUserVO.getAvatar());
             liveWatchUser.setMsgStatus(0);
             liveWatchUser.setOnline(0);
-            liveWatchUser.setCreateTime(DateUtils.getNowDate());
-            liveWatchUser.setUpdateTime(DateUtils.getNowDate());
+            liveWatchUser.setLocation(location);
+            
+            // 设置进入标记
+            if (isReplay) {
+                liveWatchUser.setReplayFlag(1);
+                liveWatchUser.setLiveFlag(0);
+            } else {
+                liveWatchUser.setLiveFlag(1);
+                liveWatchUser.setReplayFlag(0);
+            }
+            
+            liveWatchUser.setCreateTime(now);
+            liveWatchUser.setUpdateTime(now);
             baseMapper.insertLiveWatchUser(liveWatchUser);
         }
         liveWatchUser.setAvatar(fsUserVO.getAvatar());

+ 25 - 10
fs-service/src/main/java/com/fs/live/vo/LiveDashBoardDataVo.java

@@ -11,20 +11,35 @@ public class LiveDashBoardDataVo {
     // 在线人数 liveWatchUser
     private BigDecimal onlineNum;
 
-    // 观看人数 liveData
-    private Integer viewNum;
+    // 直播观看人数 liveData (原viewNum,现在区分直播)
+    private Integer liveViewNum;
 
-    // 点赞数量 liveData
-    private Integer likeNum;
+    // 回放观看人数 liveData
+    private Integer replayViewNum;
 
-    // 评论数量 liveMsg
-    private Long commentNum;
+    // 直播点赞数量 liveData (原likeNum,现在区分直播)
+    private Integer liveLikeNum;
 
-    // 新用户数量 liveWatchUser
-    private BigDecimal newUserNum;
+    // 回放点赞数量 liveData
+    private Integer replayLikeNum;
 
-    // 老用户数量 liveWatchUser
-    private BigDecimal oldUserNum;
+    // 直播评论数量 liveMsg
+    private Long liveCommentNum;
+
+    // 回放评论数量 liveMsg
+    private Long replayCommentNum;
+
+    // 直播新用户数量 liveWatchUser
+    private BigDecimal liveNewUserNum;
+
+    // 回放新用户数量 liveWatchUser
+    private BigDecimal replayNewUserNum;
+
+    // 直播老用户数量 liveWatchUser
+    private BigDecimal liveOldUserNum;
+
+    // 回放老用户数量 liveWatchUser
+    private BigDecimal replayOldUserNum;
 
     // 分享链接来源数量 liveUserFirstEntry
     private BigDecimal shareUrlNum;

+ 100 - 0
fs-service/src/main/resources/application-config-druid-bjzm-test.yml

@@ -0,0 +1,100 @@
+baidu:
+  token: 12313231232
+  back-domain: https://www.xxxx.com
+#配置
+logging:
+  level:
+    org.springframework.web: INFO
+    com.github.binarywang.demo.wx.cp: DEBUG
+    me.chanjar.weixin: DEBUG
+wx:
+  miniapp:
+    configs:
+      - appid: wx94951f52d3ac5e25   #北京存在文化
+        secret: bfe27b20c6e3c4232a1d4ef36228e84b #北京存在文化
+        token: Ncbnd7lJvkripxxna6NAWCxCrvC
+        aesKey: HlEiBB55eaWUaeBVAQO3cWKWPYv1vOVQSq7nFNICw4E
+        msgDataFormat: JSON
+  cp:
+    corpId: wwa46ffb9ff6ac35b8 #企业ID北京存在文化
+    appConfigs:
+      - agentId: 1000070       #北京存在文化
+        secret: pu2EFz6gY2Fo2K-aRUxLPaAkKIaMJJRp8ES9JdpHkp4 #北京存在文化
+        token: PPKOdAlCoMO
+        aesKey: PKvaxtpSv8NGpfTDm7VUHIK8Wok2ESyYX24qpXJAdMP
+  pay:
+    appId:  #微信公众号或者小程序等的appid
+    mchId:  #微信支付商户号
+    mchKey:  #微信支付商户密钥
+    subAppId:  #服务商模式下的子商户公众账号ID
+    subMchId:  #服务商模式下的子商户号
+    keyPath: c:\\cert\\apiclient_cert.p12 # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)
+    notifyUrl: https://userapp.his.runtzh.com/app/wxpay/wxPayNotify
+  mp:
+    useRedis: false
+    redisConfig:
+      host: 127.0.0.1
+      port: 6379
+      timeout: 2000
+    configs:
+      - appId: wxc8534f3a7c4f306c # 第一个公众号的appid  //公众号名称:德瑞康
+        secret: 7a4bac8d7628c2adf70575628826e2b8 # 公众号的appsecret--德瑞康
+        token: PPKOdAlCoMO # 接口配置里的Token值
+        aesKey: Eswa6VjwtVMCcw03qZy6fWllgrv5aytIA1SZPEU0kU2 # 接口配置里的EncodingAESKey值
+aifabu:  #爱链接
+  appKey: 7b471be905ab17e00f3b858c6710dd117601d008
+watch:
+  watchUrl: watch.ylrzcloud.com/prod-api
+  #  account: tcloud
+  #  password: mdf-m2h_6yw2$hq
+  account1: ccif #866655060138751
+  password1: cp-t5or_6xw7$mt
+  account2: tcloud #rt500台
+  password2: mdf-m2h_6yw2$hq
+  account3: whr
+  password3: v9xsKuqn_$d2y
+
+fs :
+  jwt:
+    # 加密秘钥
+    secret: f4e2e52021218f86b67cde581c0f9eb5
+    # token有效时长,7天,单位秒
+    expire: 31536000
+    header: AppToken
+  commonApi: http://172.16.16.6:7771
+  h5CommonApi: http://172.16.16.6:7771
+nuonuo:
+  key: 10924508
+  secret: A2EB20764D304D16
+
+# 存储捅配置
+tencent_cloud_config:
+  secret_id: AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT
+  secret_key: u5SuS80342xzx8FRBukza9lVNHKNMSaB
+  bucket: bjzmky-1323137866
+  app_id: 1323137866
+  region: ap-guangzhou
+  proxy: bjzm
+tmp_secret_config:
+  secret_id: AKIDCj7NSNAovtqeJpBau8GZ4CGB71thXIxX
+  secret_key: lTB5zwqqz7CNhzDOWivFWedgfTBgxgBT
+  bucket: fs-1319721001
+  app_id: 1319721001
+  region: ap-chongqing
+  proxy: fs
+cloud_host:
+  company_name: 北京卓美
+  projectCode: BJZM
+headerImg:
+  imgUrl:
+
+ipad:
+  ipadUrl: http://ipad.cdwjyyh.com
+  aiApi: 1212121212
+  voiceApi:
+  commonApi:
+wx_miniapp_temp:
+  pay_order_temp_id:
+  inquiry_temp_id:
+
+

+ 158 - 0
fs-service/src/main/resources/application-druid-bjzm-test.yml

@@ -0,0 +1,158 @@
+# 数据源配置
+spring:
+    profiles:
+        include: config-druid-bjzm-test,common
+    # redis 配置
+    redis:
+        host: 127.0.0.1
+        port: 6379
+        # 数据库索引
+        database: 0
+        # 密码
+        password:
+        # 连接超时时间
+        timeout: 10s
+        lettuce:
+            pool:
+                # 连接池中的最小空闲连接
+                min-idle: 0
+                # 连接池中的最大空闲连接
+                max-idle: 8
+                # 连接池的最大数据库连接数
+                max-active: 100
+                # #连接池最大阻塞等待时间(使用负值表示没有限制)
+                max-wait: -1ms
+    datasource:
+#        clickhouse:
+#            type: com.alibaba.druid.pool.DruidDataSource
+#            driverClassName: com.clickhouse.jdbc.ClickHouseDriver
+#            url: jdbc:clickhouse://1.14.104.71:8123/sop_test?compress=0&use_server_time_zone=true&use_client_time_zone=false&timezone=Asia/Shanghai
+#            username: rt_2024
+#            password: Yzx_19860213
+#            initialSize: 10
+#            maxActive: 100
+#            minIdle: 10
+#            maxWait: 6000
+        mysql:
+            type: com.alibaba.druid.pool.DruidDataSource
+            driverClassName: com.mysql.cj.jdbc.Driver
+            druid:
+                # 主库数据源
+                master:
+                  url: jdbc:mysql://gz-cdb-ofgnuz1n.sql.tencentcdb.com:26872/fs_his?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                  username: root
+                  password: Ylrz_1q2w3e4r5t6y
+                # 从库数据源
+                slave:
+                    # 从数据源开关/默认关闭
+                    enabled: false
+                    url:
+                    username:
+                    password:
+                # 初始连接数
+                initialSize: 5
+                # 最小连接池数量
+                minIdle: 10
+                # 最大连接池数量
+                maxActive: 20
+                # 配置获取连接等待超时的时间
+                maxWait: 60000
+                # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+                timeBetweenEvictionRunsMillis: 60000
+                # 配置一个连接在池中最小生存的时间,单位是毫秒
+                minEvictableIdleTimeMillis: 300000
+                # 配置一个连接在池中最大生存的时间,单位是毫秒
+                maxEvictableIdleTimeMillis: 900000
+                # 配置检测连接是否有效
+                validationQuery: SELECT 1 FROM DUAL
+                testWhileIdle: true
+                testOnBorrow: false
+                testOnReturn: false
+                webStatFilter:
+                    enabled: true
+                statViewServlet:
+                    enabled: true
+                    # 设置白名单,不填则允许所有访问
+                    allow:
+                    url-pattern: /druid/*
+                    # 控制台管理用户名和密码
+                    login-username: fs
+                    login-password: 123456
+                filter:
+                    stat:
+                        enabled: true
+                        # 慢SQL记录
+                        log-slow-sql: true
+                        slow-sql-millis: 1000
+                        merge-sql: true
+                    wall:
+                        config:
+                            multi-statement-allow: true
+        sop:
+            type: com.alibaba.druid.pool.DruidDataSource
+            driverClassName: com.mysql.cj.jdbc.Driver
+            druid:
+                # 主库数据源
+                master:
+                    url: jdbc:mysql://gz-cdb-ofgnuz1n.sql.tencentcdb.com:26872/fs_his_sop?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                    username: root
+                    password: Ylrz_1q2w3e4r5t6y
+                # 初始连接数
+                initialSize: 5
+                # 最小连接池数量
+                minIdle: 10
+                # 最大连接池数量
+                maxActive: 20
+                # 配置获取连接等待超时的时间
+                maxWait: 60000
+                # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+                timeBetweenEvictionRunsMillis: 60000
+                # 配置一个连接在池中最小生存的时间,单位是毫秒
+                minEvictableIdleTimeMillis: 300000
+                # 配置一个连接在池中最大生存的时间,单位是毫秒
+                maxEvictableIdleTimeMillis: 900000
+                # 配置检测连接是否有效
+                validationQuery: SELECT 1 FROM DUAL
+                testWhileIdle: true
+                testOnBorrow: false
+                testOnReturn: false
+                webStatFilter:
+                    enabled: true
+                statViewServlet:
+                    enabled: true
+                    # 设置白名单,不填则允许所有访问
+                    allow:
+                    url-pattern: /druid/*
+                    # 控制台管理用户名和密码
+                    login-username: fs
+                    login-password: 123456
+                filter:
+                    stat:
+                        enabled: true
+                        # 慢SQL记录
+                        log-slow-sql: true
+                        slow-sql-millis: 1000
+                        merge-sql: true
+                    wall:
+                        config:
+                            multi-statement-allow: true
+rocketmq:
+    name-server: localhost:8080
+    producer:
+        group: my-producer-group
+        access-key: ak16xj8o92zp984557f83ba2 # 替换为实际的 accessKey
+        secret-key: sk2ff1c6b15b74b888 # 替换为实际的 secretKey
+    consumer:
+        group: common-group
+        access-key: ak16xj8o92zp984557f83ba2 # 替换为实际的 accessKey
+        secret-key: sk2ff1c6b15b74b888 # 替换为实际的 secretKey
+openIM:
+    secret: openIM123
+    userID: imAdmin
+    url: https://localhost/api
+#是否为新商户,新商户不走mpOpenId
+isNewWxMerchant: true
+#是否使用新im
+im:
+    type: NONE
+