Prechádzať zdrojové kódy

直播间总台 销售端直播代码

yuhongqi 1 mesiac pred
rodič
commit
d178c8bc39

+ 11 - 0
fs-admin/src/main/java/com/fs/live/controller/LiveController.java

@@ -51,6 +51,17 @@ public class LiveController extends BaseController {
         return util.exportExcel(list, "直播数据");
     }
 
+    /**
+     * 导出直播列表
+     */
+    @PreAuthorize("@ss.hasPermi('live:live:edit')")
+    @GetMapping("/finishLive")
+    public R finishLive(Live live) {
+        Long userId = getUserId();
+        live.setCompanyUserId(userId);
+        return liveService.finishLive(live);
+    }
+
     /**
      * 获取直播详细信息
      */

+ 64 - 0
fs-common/src/main/java/com/fs/common/utils/DateUtils.java

@@ -8,6 +8,8 @@ import java.time.format.DateTimeFormatter;
 import java.time.temporal.ChronoUnit;
 import java.util.Calendar;
 import java.util.Date;
+import java.util.LinkedList;
+
 import org.apache.commons.lang3.time.DateFormatUtils;
 
 /**
@@ -264,5 +266,67 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
         return endOfDay.format(OUTPUT_FORMATTER);
     }
 
+    /**
+     * 检查两个时间是否跨天
+     * @param startTime 开始时间
+     * @param finishTime 结束时间
+     * @return true表示跨天,false表示未跨天
+     */
+    public static boolean isCrossDay(LocalDateTime startTime, LocalDateTime finishTime) {
+        if (startTime == null || finishTime == null) {
+            throw new IllegalArgumentException("时间参数不能为空");
+        }
+
+        // 如果结束时间早于开始时间,说明参数有误
+        if (finishTime.isBefore(startTime)) {
+            throw new IllegalArgumentException("结束时间不能早于开始时间");
+        }
+
+        LocalDate startDate = startTime.toLocalDate();
+        LocalDate finishDate = finishTime.toLocalDate();
+
+        // 比较日期部分是否相等
+        return !startDate.isEqual(finishDate);
+    }
+
+    /**
+     * 返回时间最近步长 向下(向前)取整
+     * @param startTime 开始时间
+     * @param step 步长
+     * @return 开始时间最近步长
+     */
+    public static LocalDateTime getLiveOrderStartTime(LocalDateTime startTime, int step) {
+
+        // 将startTime按照最近30分钟来取值 比如17:35 就改为17:30
+        int minute = startTime.getMinute();
+        int truncatedMinute = (minute / step) * step;
+        startTime = startTime.withMinute(truncatedMinute).withSecond(0).withNano(0);
+        return startTime;
+    }
+
+    /**
+     * 根据开始时间、结束时间和步长拆分时间
+     *
+     * @param startTime 开始时间
+     * @param endTime 结束时间
+     * @param unit 时间单位 (ChronoUnit.HOURS, ChronoUnit.DAYS等)
+     * @param step 步长
+     * @return 时间点列表
+     */
+    public static LinkedList<LocalDateTime> splitTimeByStep(LocalDateTime startTime,
+                                                            LocalDateTime endTime,
+                                                            ChronoUnit unit,
+                                                            int step) {
+        LinkedList<LocalDateTime> timeSlots = new LinkedList<>();
+        LocalDateTime currentTime = startTime;
+
+        while (!currentTime.isAfter(endTime)) {
+            timeSlots.add(currentTime);
+            currentTime = currentTime.plus(step, unit);
+        }
+
+        return timeSlots;
+    }
+
 
 }

+ 24 - 0
fs-company/src/main/java/com/fs/company/controller/live/LiveController.java

@@ -110,6 +110,30 @@ public class LiveController extends BaseController
         return toAjax(liveService.insertLive(live));
     }
 
+    /**
+     * 结束直播
+     */
+    @PreAuthorize("@ss.hasPermi('live:live:edit')")
+    @GetMapping("/finishLive")
+    public R finishLive(Live live) {
+        CompanyUser user = SecurityUtils.getLoginUser().getUser();
+        live.setCompanyUserId(user.getUserId());
+        live.setCompanyId(user.getCompanyId());
+        return liveService.finishLive(live);
+    }
+
+    /**
+     * 开启直播
+     */
+    @PreAuthorize("@ss.hasPermi('live:live:edit')")
+    @GetMapping("/startLive")
+    public R startLive(Live live) {
+        CompanyUser user = SecurityUtils.getLoginUser().getUser();
+        live.setCompanyUserId(user.getUserId());
+        live.setCompanyId(user.getCompanyId());
+        return liveService.startLive(live);
+    }
+
     /**
      * 修改直播
      */

+ 9 - 0
fs-company/src/main/java/com/fs/company/controller/live/LiveOrderController.java

@@ -15,6 +15,7 @@ import com.fs.his.service.IFsExpressService;
 import com.fs.live.domain.LiveOrder;
 import com.fs.live.enums.LiveOrderCancleReason;
 import com.fs.live.service.ILiveOrderService;
+import com.fs.live.vo.LiveOrderVo;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
@@ -158,5 +159,13 @@ public class LiveOrderController extends BaseController
         return R.ok().put("reason",allCodeDescMap).put("data",byId);
     }
 
+    /**
+     * 按照时间粒度返回订单
+     * */
+    @GetMapping(value = "/getLiveOrderTimeGranularity")
+    public R getLiveOrderTimeGranularity(LiveOrderVo liveOrder){
+        return liveOrderService.getLiveOrderTimeGranularity(liveOrder);
+    }
+
 
 }

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

@@ -19,7 +19,7 @@ import java.time.LocalDateTime;
  */
 @Data
 @EqualsAndHashCode(callSuper = true)
-public class Live extends BaseEntity {
+public class    Live extends BaseEntity {
 
     /** ID */
     @TableId(type = IdType.AUTO)

+ 13 - 0
fs-service/src/main/java/com/fs/live/domain/LiveOrder.java

@@ -4,6 +4,7 @@ import java.math.BigDecimal;
 import java.util.Date;
 
 import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.baomidou.mybatisplus.annotation.TableId;
@@ -35,6 +36,9 @@ public class LiveOrder extends BaseParam {
     @Excel(name = "店铺ID")
     private Long storeId;
 
+    @Excel(name = "商品id")
+    private Long productId;
+
     /** 订单号 */
     @Excel(name = "订单号")
     private String orderCode;
@@ -299,4 +303,13 @@ public class LiveOrder extends BaseParam {
     /** 备注*/
     @Excel(name = "备注")
     private String remark;
+
+    /** 备注*/
+    @Excel(name = "订单名称")
+    private String orderName;
+
+    /** 备注*/
+    @Excel(name = "订单名称")
+    @TableField(exist = false)
+    private String productIntroduce;
 }

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

@@ -92,4 +92,10 @@ public interface LiveMapper extends BaseMapper<Live>
      * @return 更新记录数
      */
     int deleteBatchLiveList(@Param("liveVo") LiveListVo listVo);
+
+    /**
+     * 找一个最近的直播间
+     * @return 直播间
+     */
+    Live selectLiveOne(String s);
 }

+ 10 - 0
fs-service/src/main/java/com/fs/live/mapper/LiveOrderMapper.java

@@ -3,6 +3,8 @@ package com.fs.live.mapper;
 import java.util.List;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.fs.live.domain.LiveOrder;
+import com.fs.live.vo.LiveOrderVo;
+import org.apache.ibatis.annotations.Param;
 
 /**
  * 订单Mapper接口
@@ -58,4 +60,12 @@ public interface LiveOrderMapper extends BaseMapper<LiveOrder>{
      * @return 结果
      */
     int deleteLiveOrderByOrderIds(String[] orderIds);
+
+    /**
+     * 查询订单时间粒度
+     *
+     * @param liveOrder 订单
+     * @return 订单集合
+     */
+    List<LiveOrder> getLiveOrderTimeGranularity(LiveOrderVo liveOrder);
 }

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

@@ -4,6 +4,7 @@ import java.util.List;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.fs.common.core.domain.R;
 import com.fs.live.domain.LiveOrder;
+import com.fs.live.vo.LiveOrderVo;
 
 /**
  * 订单Service接口
@@ -63,4 +64,10 @@ public interface ILiveOrderService extends IService<LiveOrder>{
     void handlePay(LiveOrder liveOrder);
 
     R liveOrderUser(String liveId);
+
+    /**
+     * 获取订单时间粒度
+     * @param liveOrder
+     */
+    R getLiveOrderTimeGranularity(LiveOrderVo liveOrder);
 }

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

@@ -138,4 +138,14 @@ public interface ILiveService extends IService<Live>
      * 批量删除视频
      */
     R handleDeleteSelected(LiveListVo listVo);
+
+    /**
+     * 结束直播
+     */
+    R finishLive(Live live);
+
+    /**
+     * 开始直播
+     */
+    R startLive(Live live);
 }

+ 56 - 1
fs-service/src/main/java/com/fs/live/service/impl/LiveOrderServiceImpl.java

@@ -1,6 +1,11 @@
 package com.fs.live.service.impl;
 
-import java.util.List;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.util.*;
 import java.util.concurrent.TimeUnit;
 
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -8,6 +13,10 @@ import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.DateUtils;
 import com.fs.his.service.IFsUserService;
+import com.fs.live.domain.Live;
+import com.fs.live.mapper.LiveMapper;
+import com.fs.live.vo.LiveOrderVo;
+import org.apache.commons.collections.list.TreeList;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.fs.live.mapper.LiveOrderMapper;
@@ -26,6 +35,9 @@ public class LiveOrderServiceImpl extends ServiceImpl<LiveOrderMapper, LiveOrder
 
     private final RedisCache redisCache;
 
+    @Autowired
+    private LiveMapper liveMapper;
+
     public LiveOrderServiceImpl(RedisCache redisCache) {
         this.redisCache = redisCache;
     }
@@ -139,6 +151,49 @@ public class LiveOrderServiceImpl extends ServiceImpl<LiveOrderMapper, LiveOrder
         return R.ok().put("count",count).put("userName",userName);
     }
 
+    @Override
+    public R getLiveOrderTimeGranularity(LiveOrderVo liveOrder) {
+        LocalDateTime startTime;
+        LocalDateTime finishTime;
+        Live live = liveMapper.selectLiveByLiveId(Long.valueOf(liveOrder.getLiveId()));
+        if (live.getFinishTime() == null) {
+            live.setFinishTime(LocalDateTime.now());
+        }
+        int step = Integer.parseInt(liveOrder.getTimeGranularity());
+        if ("all".equals(liveOrder.getTimeOptions())) {
+            startTime = DateUtils.getLiveOrderStartTime(live.getStartTime(), step);
+            finishTime = live.getFinishTime();
+        } else {
+            int i = Integer.parseInt(liveOrder.getTimeOptions());
+            startTime = DateUtils.getLiveOrderStartTime(live.getFinishTime().minusHours(i), step);
+            Date date1 = Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant());
+            liveOrder.setCreateTime(date1);
+            finishTime = live.getFinishTime();
+        }
+        List<LiveOrder> liveOrderList = baseMapper.getLiveOrderTimeGranularity(liveOrder);
+        LinkedList<LocalDateTime> hourlySlots = DateUtils.splitTimeByStep(startTime, finishTime, ChronoUnit.MINUTES, step);
+        LinkedList<String> resultXLine = new LinkedList<>();
+        LinkedList<Integer> hourlySlotsValue = new LinkedList<>();
+        boolean crossDay = DateUtils.isCrossDay(startTime, finishTime);
+        for (LocalDateTime hourlySlot : hourlySlots) {
+            hourlySlotsValue.add((int) liveOrderList.stream()
+                    .filter(item -> item.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()
+                            .isAfter(hourlySlot) &&
+                            item.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()
+                                    .isBefore(hourlySlot.plus(step, ChronoUnit.MINUTES))).count());
+            if (crossDay) {
+                resultXLine.add(hourlySlot.format(DateTimeFormatter.ofPattern("MM月dd日 HH:mm")));
+            } else {
+                resultXLine.add(hourlySlot.format(DateTimeFormatter.ofPattern("HH:mm")));
+            }
+        }
+        R result = R.ok();
+        result.put("hourlySlots", resultXLine);
+        result.put("hourlySlotsValue", hourlySlotsValue);
+        return result;
+
+    }
+
     /**
      * 订单操作记录
      * */

+ 56 - 4
fs-service/src/main/java/com/fs/live/service/impl/LiveServiceImpl.java

@@ -130,14 +130,12 @@ public class LiveServiceImpl extends ServiceImpl<LiveMapper, Live> implements IL
     public int insertLive(Live live){
 
 
-        Live exist = liveMapper.selectLiveByTalentId(String.valueOf(live.getTalentId()));
-        if (exist != null) {
-            return 0;
-        }
         if(live.getLiveType() == 2 && StringUtils.isEmpty(live.getVideoUrl())) {
             throw new BaseException("录播必须上传视屏");
         }
         live.setCreateTime(DateUtils.getNowDate());
+        live.setIsDel(0);
+        live.setIsAudit(0);
         live.setStatus(1);
         boolean save = save(live);
         LiveVideo liveVideo = new LiveVideo();
@@ -239,6 +237,9 @@ public class LiveServiceImpl extends ServiceImpl<LiveMapper, Live> implements IL
         if (live == null) {
             return R.error("未查询到直播间");
         }
+        if (live.getStatus() != 2 && live.getLiveType() == 1) {
+            return R.error("直播未开始");
+        }
         return R.ok().put("livingUrl", live.getFlvHlsUrl()).put("liveStatus", live.getStatus());
     }
 
@@ -368,6 +369,57 @@ public class LiveServiceImpl extends ServiceImpl<LiveMapper, Live> implements IL
         return R.error();
     }
 
+    @Override
+    public R finishLive(Live live) {
+        Live exist = liveMapper.selectLiveByLiveIdAndCompanyIdAndCompanyUserId(live.getLiveId(),live.getCompanyId(),live.getCompanyUserId());
+        if (exist == null) {
+            return R.error("直播间不存在");
+        }
+        if (exist.getStatus() == 3) {
+            return R.error("直播已结束");
+        }
+
+        exist.setStatus(3);
+        exist.setFinishTime(LocalDateTime.now());
+        exist.setUpdateTime(new Date());
+
+        liveMapper.updateLive(exist);
+
+        return R.ok();
+    }
+
+    @Override
+    public R startLive(Live live) {
+        Live exist = liveMapper.selectLiveByLiveIdAndCompanyIdAndCompanyUserId(live.getLiveId(),live.getCompanyId(),live.getCompanyUserId());
+        if (exist == null) {
+            return R.error("直播间不存在");
+        }
+        if (exist.getStatus() == 2) {
+            return R.error("直播已开始");
+        }
+        if (exist.getIsAudit() != 1) {
+            return R.error("您未通过审核");
+        }
+        if (exist.getIsShow() != 1) {
+            return R.error("您未拥有直播权限");
+        }
+        SysConfig sysConfig = sysConfigService.selectConfigByConfigKey("living.config");
+        Map<String, String> livingConfigMap = JSON.parseObject(sysConfig.getConfigValue(), Map.class);
+        if (livingConfigMap == null || livingConfigMap.isEmpty()) {
+            return R.error("缺失直播配置");
+        }
+        String rtmpPushUrl = generateRtmpPushUrl(livingConfigMap.get("domain"), livingConfigMap.get("app"), exist.getLiveId().toString());
+        String hlvPlayUrl = generateHlvPlayUrl(livingConfigMap.get("http"), livingConfigMap.get("app"), exist.getLiveId().toString());
+        exist.setRtmpUrl(rtmpPushUrl);
+        exist.setFlvHlsUrl(hlvPlayUrl);
+
+        exist.setStatus(2);
+        exist.setUpdateTime(new Date());
+        liveMapper.updateLive(exist);
+
+        return R.ok();
+    }
+
     /**
      * 构建FFmpeg推流命令
      */

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

@@ -141,7 +141,7 @@ public class LiveWatchUserServiceImpl extends ServiceImpl<LiveWatchUserMapper, L
     public LiveWatchUser close(long liveId, long userId) {
         LiveWatchUser liveWatchUser = getByLiveIdAndUserId(liveId, userId);
         liveWatchUser.setUpdateTime(DateUtils.getNowDate());
-        liveWatchUser.setOnline(0);
+        liveWatchUser.setOnline(1);
         super.updateById(liveWatchUser);
         return liveWatchUser;
     }

+ 13 - 0
fs-service/src/main/java/com/fs/live/vo/LiveOrderVo.java

@@ -0,0 +1,13 @@
+package com.fs.live.vo;
+
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class LiveOrderVo {
+    private String timeOptions;
+    private String timeGranularity;
+    private String liveId;
+    private Date createTime;
+}

+ 5 - 1
fs-service/src/main/resources/mapper/live/LiveMapper.xml

@@ -37,7 +37,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </sql>
 
     <select id="selectLiveList" parameterType="Live" resultMap="LiveResult">
-        <include refid="selectLiveVo"/>
+        select a.live_id, a.company_id, a.company_user_id,talent_id, a.live_name, a.is_audit, a.live_desc, a.show_type, a.status, a.anchor_id,
+               a.live_type, a.start_time, a.finish_time, a.live_img_url, a.live_config, a.id_card_url, a.is_show, a.is_del, a.qw_qr_code, a.rtmp_url,
+               a.flv_hls_url, a.create_time, a.create_by, a.update_by, a.update_time, a.remark,config_json, b.video_url from live
+        a
+        left join live_video b on a.live_id = b.live_id
         where 1=1 and is_del = 0
         <if test="companyId != null "> and company_id = #{companyId}</if>
         <if test="companyUserId != null "> and company_user_id = #{companyUserId}</if>

+ 24 - 1
fs-service/src/main/resources/mapper/live/LiveOrderMapper.xml

@@ -72,10 +72,25 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="payIntegral"    column="pay_integral"    />
         <result property="backIntegral"    column="back_integral"    />
         <result property="isEditMoney"    column="is_edit_money"    />
+        <result property="orderName"    column="order_name"    />
+        <result property="productIntroduce"    column="product_introduce"    />
     </resultMap>
 
     <sql id="selectLiveOrderVo">
-        select order_id, live_id, store_id, order_code, user_id, user_name, user_phone, user_address, cart_id, total_num, total_price, pay_price, pay_money, is_pay, pay_time, pay_type, create_time, update_time, status, refund_status, refund_img, refund_explain, refund_time, refund_reason, refund_money, delivery_code, delivery_name, delivery_sn, remark, is_del, cost_price, verify_code, shipping_type, is_channel, finish_time, delivery_time, tui_money, tui_money_status, tui_user_id, item_json, discount_money, user_coupon_id, company_id, company_user_id, store_house_code, extend_order_id, pay_delivery, pay_remain, delivery_status, delivery_pay_status, delivery_pay_time, delivery_type, delivery_pay_money, delivery_import_time, delivery_send_time, is_after_sales, dept_id, channel, source, bill_price, total_postage, pay_postage, gain_integral, use_integral, pay_integral, back_integral, is_edit_money from live_order
+        SELECT
+            a.order_id,a.live_id,	a.product_id,	a.order_name,	a.store_id,	a.order_code,	a.user_id,	a.user_name,
+            a.user_phone,	a.user_address,	a.cart_id,	a.total_num,	a.total_price,	a.pay_price,	a.pay_money,	a.is_pay,
+            a.pay_time,	a.pay_type,	a.create_time,	a.update_time,	a.STATUS,	a.refund_status,	a.refund_img,	a.refund_explain,
+            a.refund_time,	a.refund_reason,	a.refund_money,	a.delivery_code,	a.delivery_name,	a.delivery_sn,
+            a.remark,	a.is_del,	a.cost_price,	a.verify_code,	a.shipping_type,	a.is_channel,	a.finish_time,
+            a.delivery_time,	a.tui_money,	a.tui_money_status,	a.tui_user_id,	a.item_json,	a.discount_money,
+            a.user_coupon_id,	a.company_id,	a.company_user_id,	a.store_house_code,	a.extend_order_id,	a.pay_delivery,
+            a.pay_remain,	a.delivery_status,	a.delivery_pay_status,	a.delivery_pay_time,	a.delivery_type,
+            a.delivery_pay_money,	a.delivery_import_time,	a.delivery_send_time,	a.is_after_sales,	a.dept_id,
+            a.channel,	a.source,	a.bill_price,	a.total_postage,	a.pay_postage,	a.gain_integral,
+            a.use_integral,	a.pay_integral,	a.back_integral,	a.is_edit_money,	b.product_introduce
+        FROM
+            live_order a LEFT JOIN fs_store_product b ON a.product_id = b.product_id
     </sql>
 
     <select id="selectLiveOrderList" parameterType="LiveOrder" resultMap="LiveOrderResult">
@@ -144,6 +159,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="payIntegral != null "> and pay_integral = #{payIntegral}</if>
             <if test="backIntegral != null "> and back_integral = #{backIntegral}</if>
             <if test="isEditMoney != null "> and is_edit_money = #{isEditMoney}</if>
+            <if test="orderName != null "> and order_name = #{orderName}</if>
         </where>
     </select>
 
@@ -375,4 +391,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{orderId}
         </foreach>
     </delete>
+
+    <select id="getLiveOrderTimeGranularity" parameterType="com.fs.live.vo.LiveOrderVo" resultMap="LiveOrderResult">
+        <include refid="selectLiveOrderVo"/>
+        where 1=1
+        <if test="timeOptions != 'all'">and create_time >= #{createTime}</if>
+        <if test="liveId != null">and live_id = #{liveId}</if>
+    </select>
 </mapper>