diff --git a/src/main/java/com/upchina/app/service/CouponService.java~ b/src/main/java/com/upchina/app/service/CouponService.java~ deleted file mode 100644 index 2da5580..0000000 --- a/src/main/java/com/upchina/app/service/CouponService.java~ +++ /dev/null @@ -1,73 +0,0 @@ -package com.upchina.app.service; - -import cn.hutool.core.util.StrUtil; -import com.hazelcast.org.apache.calcite.util.Holder; -import com.upchina.common.util.LoggerUtil; -import org.springframework.stereotype.Service; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; - -@Service -public class CouponService { - - private final int pageSize = 100; - - /** - * 查询视频优惠券 - * - * @param videoId 视频ID - * @return 优惠券Map key: 用户ID value: 优惠券列表 - */ - public Map> queryVideoCoupon(Integer videoId) { - return null; - } - - /** - * 查询用户优惠券 - * - * @param userId 用户ID - * @return 优惠券Map key: 视频ID value: 优惠券列表 - */ - public Map> queryUserCoupon(String userId) { - return null; - } - - public int queryCouponCount(Integer videoId) { - return 0; - } - - private List queryCoupon(Integer videoId, String userId) { - List results = new ArrayList<>(); - // 先查第一页,获取总数 - LiveCouponReq req = new LiveCouponReq(); - if (videoId != null && videoId > 0) { - req.setLiveId(videoId); - } - if (StrUtil.isNotEmpty(userId)) { - req.setFundId(userId); - } - req.setCurrent(1); - req.setSize(pageSize); - Holder holder = new Holder<>(); - orderSystemPrx.getLiveCoupons(req, holder); - LiveCouponRsp firstPage = holder.getValue(); - results.addAll(firstPage.getUserCoupon()); - // 计算总页数,如果总页数超过1,再查剩下的页 - long total = firstPage.getTotal(); - int totalPage = total % pageSize == 0 ? (int) (total / pageSize) : (int) (total / pageSize) + 1; - LoggerUtil.info("优惠券总数:" + total, "页数:" + totalPage); - for (int i = 2; i <= totalPage; i++) { - req.setCurrent(i); - holder = new Holder<>(); - orderSystemPrx.getLiveCoupons(req, holder); - LiveCouponRsp page = holder.getValue(); - results.addAll(page.getUserCoupon()); - } - return results; - } - -} diff --git a/src/main/java/com/upchina/common/aspect/WebSocketAspect.java~ b/src/main/java/com/upchina/common/aspect/WebSocketAspect.java~ deleted file mode 100644 index 3335ffe..0000000 --- a/src/main/java/com/upchina/common/aspect/WebSocketAspect.java~ +++ /dev/null @@ -1,78 +0,0 @@ -package com.upchina.common.aspect; - -import com.alibaba.fastjson.JSONObject; -import com.auth0.jwt.exceptions.TokenExpiredException; -import com.upchina.common.handler.BizException; -import com.upchina.common.result.ResponseStatus; -import com.upchina.common.util.LoggerUtil; -import com.upchina.common.util.RequestIdUtil; -import com.upchina.common.vo.BackendUserVO; -import com.upchina.common.vo.FrontUserVO; -import org.aspectj.lang.JoinPoint; -import org.aspectj.lang.annotation.AfterThrowing; -import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Before; -import org.aspectj.lang.annotation.Pointcut; -import org.aspectj.lang.reflect.MethodSignature; -import org.springframework.messaging.simp.SimpMessageHeaderAccessor; -import org.springframework.stereotype.Component; - -import java.util.*; - -@Aspect -@Component -public class WebSocketAspect { - - @Pointcut("@annotation(org.springframework.messaging.handler.annotation.MessageMapping)") - private void pointcut() { - } - - @Before("pointcut()") - public void before(JoinPoint joinPoint) { - RequestIdUtil.setValue(); - Object[] args = joinPoint.getArgs(); - List arguments = new ArrayList<>(); - String destination = ""; - for (Object arg : args) { - if (arg instanceof SimpMessageHeaderAccessor) { - SimpMessageHeaderAccessor accessor = (SimpMessageHeaderAccessor) arg; - destination = accessor.getDestination(); - Map attributes = accessor.getSessionAttributes(); - BackendUserVO backendUser = (BackendUserVO) attributes.get("backendUser"); - FrontUserVO frontUser = (FrontUserVO) attributes.get("frontUser"); - if (backendUser != null) { - arguments.add(backendUser); - } - if (frontUser != null) { - arguments.add(frontUser); - } - } else { - arguments.add(arg); - } - } - LoggerUtil.info(String.format("%s:param:%s", destination, JSONObject.toJSONString(arguments))); - } - - @AfterThrowing(value = "pointcut()", throwing = "ex") - public void afterThrowing(JoinPoint joinPoint, Exception ex) { - MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); - Class clazz = methodSignature.getDeclaringType(); - Object[] args = joinPoint.getArgs(); - Optional accessorOptional = Arrays.stream(args).filter(obj -> obj instanceof SimpMessageHeaderAccessor).findFirst(); - if (!accessorOptional.isPresent()) { - throw new BizException(ResponseStatus.PARM_ERROR, "WebSocket异常拦截未检查到accessor,请检查:" + clazz.getSimpleName() + "." + methodSignature.getMethod().getName() + "的入参"); - } - SimpMessageHeaderAccessor accessor = (SimpMessageHeaderAccessor) accessorOptional.get(); - Map attributes = accessor.getSessionAttributes(); -// String sessionId = (String) attributes.get("sessionId"); -// if (StringUtils.isEmpty(sessionId)) { -// throw new BizException(ResponseStatus.PARM_ERROR, "header里没有包含sessionId"); -// } -// BackendUserVO backendUser = (BackendUserVO) attributes.get("backendUser"); -// FrontUserVO frontUser = (FrontUserVO) attributes.get("frontUser"); - if (ex instanceof TokenExpiredException) { - throw new BizException(ResponseStatus.SESSION_USER_LOGOUT); - } - } - -} diff --git a/src/main/java/com/upchina/common/generator/CodeGenerator.java~ b/src/main/java/com/upchina/common/generator/CodeGenerator.java~ deleted file mode 100644 index c4697b8..0000000 --- a/src/main/java/com/upchina/common/generator/CodeGenerator.java~ +++ /dev/null @@ -1,84 +0,0 @@ -package com.upchina.common.generator; - -import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException; -import com.baomidou.mybatisplus.generator.AutoGenerator; -import com.baomidou.mybatisplus.generator.config.*; -import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; -import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; -import org.apache.commons.lang3.StringUtils; - -import java.util.Scanner; - -// 演示例子,执行 main 方法控制台输入模块表名回车自动生成对应项目目录中 -public class CodeGenerator { - - public static String scanner(String tip) { - Scanner scanner = new Scanner(System.in); - String help = "请输入" + tip + ":"; - System.out.println(help); - if (scanner.hasNext()) { - String ipt = scanner.nextLine(); - if (StrUtil.isNotBlank(ipt)) { - return ipt; - } - } - throw new MybatisPlusException("请输入正确的" + tip + "!"); - } - - public static void main(String[] args) { - DataSourceConfig dsc = new DataSourceConfig - .Builder("jdbc:mysql://172.16.8.64/video_demo_wx?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8", - "root", - "123456") -// .Builder("jdbc:mysql://172.16.9.44:3306/db_crm_dyqh?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false", -// "taf", -// "taf2015") - .build(); - // 代码生成器 - AutoGenerator mpg = new AutoGenerator(dsc); - - String moduleName = scanner("模块名"); - String projectPath = System.getProperty("user.dir") + "/AdvisorServer"; - - // 全局配置 - GlobalConfig globalConfig = new GlobalConfig - .Builder() - .outputDir(projectPath + "/src/main/java") - .author("easonzhu") - .openDir(false) - .fileOverride() - .build(); - - // 包配置 - PackageConfig packageConfig = new PackageConfig - .Builder() - .parent("com.upchina") - .moduleName(moduleName) - .build(); - - // 配置模板 - TemplateConfig templateConfig = new TemplateConfig - .Builder() - .mapperXml(null) - .service(null, null) - .controller(null) - .build(); - - // 策略配置 - StrategyConfig strategyConfig = new StrategyConfig - .Builder() - .addInclude(scanner("表名,多个英文逗号分割").split(",")) - .entityBuilder() - .naming(NamingStrategy.underline_to_camel) - .controllerBuilder() - .enableRestStyle() - .build(); - - mpg.global(globalConfig); - mpg.packageInfo(packageConfig); - mpg.template(templateConfig); - mpg.strategy(strategyConfig); - mpg.execute(new FreemarkerTemplateEngine()); - } - -} \ No newline at end of file diff --git a/src/main/java/com/upchina/common/handler/WebSocketErrorHandler.java~ b/src/main/java/com/upchina/common/handler/WebSocketErrorHandler.java~ deleted file mode 100644 index fc6b26e..0000000 --- a/src/main/java/com/upchina/common/handler/WebSocketErrorHandler.java~ +++ /dev/null @@ -1,50 +0,0 @@ -package com.upchina.common.handler; - -import cn.hutool.core.util.StrUtil; -import com.upchina.common.result.ResponseStatus; -import com.upchina.common.vo.WsVO; -import com.upchina.video.constant.VideoWsMessageType; -import org.springframework.messaging.Message; -import org.springframework.messaging.simp.stomp.StompHeaderAccessor; -import org.springframework.messaging.support.MessageBuilder; -import org.springframework.stereotype.Component; -import org.springframework.web.socket.messaging.StompSubProtocolErrorHandler; - -import javax.annotation.Nonnull; -import java.nio.charset.StandardCharsets; - -/** - *

- * WebSocket处理ERROR指令错误 - *

- * - * @author fangliangbao - * @since 2023-02-24 - */ -@Component -public class WebSocketErrorHandler extends StompSubProtocolErrorHandler { - - public static String exceptionToJson(Throwable throwable) { - BizException exception; - if (throwable == null) { - exception = new BizException(ResponseStatus.SYS_BUSY); - } else if (throwable instanceof BizException) { - exception = (BizException) throwable; - } else { - exception = new BizException(ResponseStatus.SYS_BUSY, throwable.getLocalizedMessage()); - } - return JsonUtil.toJson(WsVO.errorUserMsg(exception, null, null, VideoWsMessageType.ERROR_MSG)); - } - - @Override - @Nonnull - protected Message handleInternal(@Nonnull StompHeaderAccessor accessor, @Nonnull byte[] ignored1, Throwable cause, StompHeaderAccessor ignored2) { - String errMessage = accessor.getFirstNativeHeader("message"); - if (StrUtil.isEmpty(errMessage)) { - errMessage = WebSocketErrorHandler.exceptionToJson(cause == null ? null : cause.getCause()); - } - accessor.setMessage(null); - return MessageBuilder.createMessage(errMessage.getBytes(StandardCharsets.UTF_8), accessor.getMessageHeaders()); - } - -} diff --git a/src/main/java/com/upchina/common/interceptor/WebSocketAuthChannelInterceptor.java~ b/src/main/java/com/upchina/common/interceptor/WebSocketAuthChannelInterceptor.java~ deleted file mode 100644 index 69ddb9a..0000000 --- a/src/main/java/com/upchina/common/interceptor/WebSocketAuthChannelInterceptor.java~ +++ /dev/null @@ -1,160 +0,0 @@ -package com.upchina.common.interceptor; - -import com.hazelcast.map.IMap; -import cn.hutool.core.util.StrUtil; -import com.upchina.common.constant.IsOrNot; -import com.upchina.common.filter.AuthFilter; -import com.upchina.common.handler.BizException; -import com.upchina.common.result.ResponseStatus; -import com.upchina.common.vo.BackendUserVO; -import com.upchina.common.vo.FrontUserVO; -import com.upchina.video.entity.OnlineUser; -import com.upchina.video.service.common.VideoCacheService; -import com.upchina.video.service.common.VideoMessageService; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; -import org.springframework.lang.NonNull; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.simp.stomp.StompCommand; -import org.springframework.messaging.simp.stomp.StompHeaderAccessor; -import org.springframework.messaging.support.ChannelInterceptor; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; -import java.time.LocalDateTime; -import java.util.Map; - -/** - *

- * WebSocket连结token鉴权 - *

- * - * @author fangliangbao - * @since 2022-09-25 - */ -@Component -@Order(Ordered.HIGHEST_PRECEDENCE + 99) -public class WebSocketAuthChannelInterceptor implements ChannelInterceptor { - - @Resource - private AuthFilter authFilter; - - @Resource - private VideoCacheService videoCacheService; - - @Resource - private VideoMessageService videoMessageService; - - /** - * 发送前监听是否为登录用户 - */ - @Override - public Message preSend(@NonNull Message message, @NonNull MessageChannel channel) { - StompHeaderAccessor header = StompHeaderAccessor.wrap(message); - if (header == null || header.getCommand() == null) { - return message; - } - // 只处理连接消息 - if (!header.getCommand().equals(StompCommand.CONNECT)) { - return message; - } - String sessionId = header.getFirstNativeHeader("sessionId"); - if (StringUtils.isEmpty(sessionId)) { - throw new BizException(ResponseStatus.PARM_ERROR, "header里没有包含sessionId"); - } - String groupId = header.getFirstNativeHeader("GroupId"); - Integer videoId = StringUtils.isNotEmpty(groupId) ? Integer.parseInt(groupId) : null; - if (videoId == null) { - throw new BizException(ResponseStatus.PARM_ERROR, "header里没有包含videoId"); - } - Map attributes = header.getSessionAttributes(); - if (attributes == null) { - throw new BizException(ResponseStatus.PARM_ERROR, "header里没有包含attributes"); - } - String userId = null; - String authorization = header.getFirstNativeHeader("Authorization"); - if (StringUtils.isNotEmpty(authorization)) { - BackendUserVO backendUser = authFilter.parseBackendUser(authorization); - attributes.put("backendUser", backendUser); - userId = backendUser.getUserId().toString(); - } else { - String token = header.getFirstNativeHeader("token"); - if (StringUtils.isNotEmpty(token)) { - FrontUserVO frontUser = authFilter.parseFrontUser(token); - attributes.put("frontUser", frontUser); - userId = frontUser.getUserId(); - } - } - if (userId == null) { - throw new BizException(ResponseStatus.SESSION_EXPIRY); - } - attributes.put("userId", userId); - attributes.put("sessionId", sessionId); - attributes.put("videoId", videoId); - attributes.put("sessionKey", userId + "-" + sessionId); - return message; - } - - @Override - public void postSend(Message message, MessageChannel channel, boolean sent) { - StompHeaderAccessor header = StompHeaderAccessor.wrap(message); - if (header == null || header.getCommand() == null) { - return; - } - Map attributes = header.getSessionAttributes(); - FrontUserVO frontUser = (FrontUserVO) attributes.get("frontUser"); - if (frontUser == null) { - return; - } - String userId = (String) attributes.get("userId"); - Integer videoId = (Integer) attributes.get("videoId"); - String sessionId = (String) attributes.get("sessionId"); - String sessionKey = (String) attributes.get("sessionKey"); - if (userId == null || videoId == null || sessionId == null || sessionKey == null) { - return; - } - LocalDateTime now = LocalDateTime.now(); - switch (header.getCommand()) { - case CONNECT: { - IMap totalOnlineMap = videoCacheService.getTotalOnlineMap(videoId); - OnlineUser onlineUser = new OnlineUser( - videoId, - userId, - frontUser.getUserName(), - frontUser.getImgUrl(), - sessionId, - IsOrNot.IS.value, - IsOrNot.NOT.value, - now - ); - totalOnlineMap.put(sessionKey, onlineUser); - //上线通知 -// LoggerUtil.websocket.info("上线通知:" + JSONObject.toJSONString(onlineUser)); - videoMessageService.memberNotify(videoId, onlineUser); - videoMessageService.publishEnterMessage(videoId, frontUser); - break; - } - case DISCONNECT: { - IMap totalOnlineMap = videoCacheService.getTotalOnlineMap(videoId); - OnlineUser onlineUser = totalOnlineMap.get(sessionKey); - if (onlineUser != null) { - onlineUser.setIsOnline(IsOrNot.NOT.value); - onlineUser.setIsPlay(IsOrNot.NOT.value); - onlineUser.setExitTime(now); - totalOnlineMap.put(sessionKey, onlineUser); - //下线通知 -// LoggerUtil.websocket.info("下线通知:" + JSONObject.toJSONString(onlineUser)); - videoMessageService.memberNotify(videoId, onlineUser); - } - break; - } - } - } - - @Override - public void afterSendCompletion(Message message, MessageChannel channel, boolean sent, Exception ex) { - - } - -} diff --git a/src/main/java/com/upchina/common/service/AdvertService.java~ b/src/main/java/com/upchina/common/service/AdvertService.java~ deleted file mode 100644 index 566db44..0000000 --- a/src/main/java/com/upchina/common/service/AdvertService.java~ +++ /dev/null @@ -1,203 +0,0 @@ -package com.upchina.common.service; - -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.toolkit.Wrappers; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import com.google.common.collect.Table; -import com.hazelcast.core.HazelcastInstance; -import com.upchina.common.config.cache.CacheKey; -import com.upchina.common.constant.AdvertPosition; -import com.upchina.common.constant.ProductType; -import com.upchina.common.entity.Advert; -import com.upchina.common.handler.BizException; -import com.upchina.common.mapper.AdvertMapper; -import com.upchina.common.query.ListAdvertQuery; -import com.upchina.common.query.OnlyIdQuery; -import com.upchina.common.query.SaveAdvertQuery; -import com.upchina.common.query.UpdateAdvertQuery; -import com.upchina.common.result.Pager; -import com.upchina.common.result.ResponseStatus; -import com.upchina.common.vo.AdvertAppVO; -import com.upchina.common.vo.AdvertVO; -import com.upchina.common.vo.BackendUserVO; -import com.upchina.common.vo.MergeProductInfoVO; -import com.upchina.rbac.entity.UserDept; -import com.upchina.rbac.service.UserService; -import org.springframework.dao.DuplicateKeyException; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.StringUtils; - -import javax.annotation.Resource; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -@Service -public class AdvertService { - - @Resource - private AdvertMapper advertMapper; - - @Resource - private UserService userService; - - @Resource - private MergeProductService mergeProductService; - - @Resource - private CacheService cacheService; - - @Resource - private HazelcastInstance hazelcastInstance; - - @Resource - private RecommendService recommendService; - - /** - * 推荐位置和对应类型 - * 首页(投顾社区首页):所有类型,包括H5 - */ - // 推荐位置和产品类型关系 - private static final Multimap positionProductTypeMap = HashMultimap.create(); - // 产品类型和推荐位置关系 - private static final Multimap productTypePositionMap = HashMultimap.create(); - - private static void putRelation(Integer advertPosition, Collection productTypes) { - productTypes.forEach(productType -> { - positionProductTypeMap.put(advertPosition, productType); - productTypePositionMap.put(productType, advertPosition); - }); - } - - static { - putRelation(AdvertPosition.HOME_PAGE.value, Arrays.stream(ProductType.values()).map(ProductType::getValue).collect(Collectors.toSet())); - } - - public Pager list(ListAdvertQuery query) { - Integer productType = query.getProductType(); - Integer productId = query.getProductId(); - String name = query.getName(); - Integer position = query.getPosition(); - Integer createUserId = query.getCreateUserId(); - QueryWrapper wrapper = Wrappers.query(); - wrapper.eq(productType != null && productType != 0, "product_type", productType) - .eq(productId != null && productId != 0, "product_id", productId) - .like(StrUtil.isNotEmpty(name), "name", name) - .eq(position != null && position != 0, "position", position) - .eq(createUserId != null && createUserId != 0, "create_user_id", createUserId) - .last("order by weight desc,create_time desc"); - Page page = advertMapper.selectPage(query.toPage(), wrapper); - Map userMap = userService.getUserMap(); - List list = page.getRecords().stream().map(advert -> new AdvertVO(advert, userMap.get(advert.getCreateUserId()))).collect(Collectors.toList()); - // 填充非H5类型的产品名称 - List filterH5List = list.stream().filter(vo -> !ProductType.H5.value.equals(vo.getProductType())).collect(Collectors.toList()); - Table productTable = mergeProductService.queryMergeProductInfo(filterH5List); - filterH5List.forEach(vo -> { - MergeProductInfoVO productVO = productTable.get(vo.getProductType(), vo.getProductId()); - if (productVO != null) { - vo.setName(productVO.getProductName()); - vo.setSummary(productVO.getSummary()); - } - }); - return new Pager<>(list, page.getTotal()); - } - - @Transactional(rollbackFor = Exception.class) - public void save(SaveAdvertQuery query, BackendUserVO backendUserVO) { - validateProduct(query); - ProductType productType = ProductType.fromValue(query.getProductType()); - Advert advert = query.toPO(backendUserVO.getUserId()); - try { - advertMapper.insert(advert); - } catch (DuplicateKeyException e) { - throw new BizException(ResponseStatus.ADVERT_DUPLICATE); - } - this.clearCache(AdvertPosition.fromValue(query.getPosition())); - } - - @Transactional(rollbackFor = Exception.class) - public void update(UpdateAdvertQuery query, BackendUserVO backendUserVO) { - validateProduct(query); - ProductType productType = ProductType.fromValue(query.getProductType()); - Advert advert = query.toPO(); - int rows; - try { - rows = advertMapper.updateById(advert); - } catch (DuplicateKeyException e) { - throw new BizException(ResponseStatus.ADVERT_DUPLICATE); - } - if (rows == 0) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - this.clearCache(AdvertPosition.fromValue(query.getPosition())); - } - - @Transactional(rollbackFor = Exception.class) - public void delete(OnlyIdQuery query, BackendUserVO backendUserVO) { - Advert advert = advertMapper.selectById(query.getId()); - if (advert == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - advertMapper.deleteById(query.getId()); - this.clearCache(AdvertPosition.fromValue(advert.getPosition())); - ProductType productType = ProductType.fromValue(advert.getProductType()); - } - - public List listForApp(Integer position) { - return cacheService.get(CacheKey.ADVERT, CacheKey.AdvertKey.APP_ADVERT_LIST + position, () -> { - QueryWrapper wrapper = Wrappers.query(); - wrapper.eq("position", position).last("order by weight desc,create_time desc"); - List list = advertMapper.selectList(wrapper); - return list.stream().map(AdvertAppVO::new).collect(Collectors.toList()); - }); - } - - public void clearCache(AdvertPosition position) { - Map cacheMap = hazelcastInstance.getMap(CacheKey.ADVERT); - cacheMap.remove(CacheKey.AdvertKey.APP_ADVERT_LIST + position.value); - } - - public void clearCache(ProductType productType) { - Map cacheMap = hazelcastInstance.getMap(CacheKey.ADVERT); - Collection positionSet = productTypePositionMap.get(productType.value); - positionSet.forEach(position -> cacheMap.remove(CacheKey.AdvertKey.APP_ADVERT_LIST + position)); - } - - private void validateProduct(SaveAdvertQuery query) { - Integer position = query.getPosition(); - Integer productType = query.getProductType(); - Collection productTypeSet = positionProductTypeMap.get(position); - if (!productTypeSet.contains(productType)) { - throw new BizException(ResponseStatus.PARM_ERROR, "产品类型不符合推荐位置要求"); - } - if (ProductType.H5.value.equals(productType)) { - if (StrUtil.isEmpty(query.getName())) { - throw new BizException(ResponseStatus.PARM_ERROR, "H5链接名称不能为空"); - } - if (StrUtil.hasText(query.getUrl())) { - throw new BizException(ResponseStatus.PARM_ERROR, "H5链接URL不能为空"); - } - } else { - if (query.getProductId() == null) { - throw new BizException(ResponseStatus.PARM_ERROR, "非H5类型,产品ID不能为空"); - } - } - recommendService.validateProduct(query); - } - - public void validateRecommendExist(ProductType productType, Integer productId) { - // TODO 校验关联数据(投顾\观点\观点包\锦囊\三方产品\套餐产品) - QueryWrapper advertWrapper = Wrappers.query(); - advertWrapper.eq("product_type", productType.value) - .eq("product_id", productId); - Long advertCount = advertMapper.selectCount(advertWrapper); - if (advertCount > 0) throw new BizException(ResponseStatus.ADVERT_CAN_NOT_SOLD_OUT); - } - -} diff --git a/src/main/java/com/upchina/common/service/CommentBlackService.java~ b/src/main/java/com/upchina/common/service/CommentBlackService.java~ deleted file mode 100644 index 4b91ef3..0000000 --- a/src/main/java/com/upchina/common/service/CommentBlackService.java~ +++ /dev/null @@ -1,272 +0,0 @@ -package com.upchina.common.service; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.StrUtil; -import com.alibaba.fastjson.JSONObject; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.toolkit.Wrappers; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.google.common.collect.Table; -import com.hazelcast.core.HazelcastInstance; -import com.hazelcast.map.IMap; -import com.upchina.common.constant.CommentBlackStatus; -import com.upchina.common.constant.CommentBlackType; -import com.upchina.common.entity.CommentBlack; -import com.upchina.common.handler.BizException; -import com.upchina.common.mapper.CommentBlackMapper; -import com.upchina.common.mapper.CommentMapper; -import com.upchina.common.query.AddCommentBlackQuery; -import com.upchina.common.query.BaseProductQuery; -import com.upchina.common.query.CommentBlackQuery; -import com.upchina.common.result.Pager; -import com.upchina.common.result.ResponseStatus; -import com.upchina.common.util.HideUtils; -import com.upchina.common.util.LoggerUtil; -import com.upchina.common.vo.BackendUserVO; -import com.upchina.common.vo.CommentBlackVO; -import com.upchina.common.vo.MergeProductInfoVO; -import com.upchina.rbac.entity.Dept; -import com.upchina.rbac.entity.UserDept; -import com.upchina.rbac.service.AuthService; -import com.upchina.rbac.service.DeptService; -import com.upchina.rbac.service.UserService; -import ma.glasnost.orika.MapperFacade; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.CollectionUtils; -import org.springframework.util.StringUtils; - -import javax.annotation.Resource; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.*; -import java.util.stream.Collectors; - -import static com.upchina.common.config.cache.CacheKey.COMMENT_BLACK; -import static com.upchina.common.config.cache.CacheKey.CommentBlackKey.ALL_BLACK_USER; - -@Service -public class CommentBlackService { - - @Value("${rsa.priKey}") - private String ypPriKey; - - @Value("${rsa.pubKey}") - private String ypPubKey; - - @Resource - private MapperFacade mapperFacade; - - @Resource - private CommentBlackMapper commentBlackMapper; - - @Resource - private CommentMapper commentMapper; - - @Resource - private UserService userService; - - @Resource - private MergeProductService mergeProductService; - - @Resource - private HazelcastInstance hazelcastInstance; - - @Resource - private CacheService cacheService; - - @Resource - private AuthService authService; - - @Resource - private DeptService deptService; - - private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - - public Set getAllBlackUser() { - LocalDateTime now = LocalDateTime.now(); - List list = cacheService.get(COMMENT_BLACK, ALL_BLACK_USER, () -> { - QueryWrapper wrapper = Wrappers.query(); - wrapper.in("status", Arrays.asList(CommentBlackStatus.EFFECT.value, CommentBlackStatus.EXPIRED.value)); - List commentBlackList = commentBlackMapper.selectList(wrapper); - LoggerUtil.info("db当前黑名单用户:" + JSONObject.toJSONString(commentBlackList)); - if (CollectionUtils.isEmpty(commentBlackList)) { - return null; - } - return commentBlackList; - }); - if (CollUtil.isEmpty(list)) { - return null; - } - Set set = list.stream() - .filter(black -> now.isAfter(black.getStartTime()) && now.isBefore(black.getEndTime())) - .map(CommentBlack::getPhone).collect(Collectors.toSet()); - LoggerUtil.info("当前黑名单用户:" + JSONObject.toJSONString(set)); - return set; - } - - @Transactional(rollbackFor = Exception.class) - public Integer addCommentBlack(BackendUserVO backendUserVO, AddCommentBlackQuery addCommentBlackQuery) { -// String userPhone = RsaUtil.priKeyDecryption(ypPriKey, addCommentBlackQuery.getUserPhone()); - String userPhone = addCommentBlackQuery.getUserPhone(); - LocalDateTime now = LocalDateTime.now(); - //禁言开始时间-1s - now = now.minusSeconds(1L); - QueryWrapper wrapper = Wrappers.query(); - wrapper.eq("phone", userPhone) - .in("status", Arrays.asList(CommentBlackStatus.EFFECT.value, CommentBlackStatus.EXPIRED.value)) - .lt("start_time", now) - .ge("end_time", now); - long validSize = commentBlackMapper.selectCount(wrapper); - if (validSize > 0) { - throw new BizException(ResponseStatus.REPETITIVE_ERROR); - } - CommentBlack commentBlack = mapperFacade.map(addCommentBlackQuery, CommentBlack.class); - commentBlack.setUserName(addCommentBlackQuery.getUserName()); - commentBlack.setPhone(userPhone); - commentBlack.setStartTime(now); - commentBlack.setStatus(CommentBlackStatus.EFFECT.value); - commentBlack.setOperatorId(backendUserVO.getUserId()); - commentBlack.setUpdateTime(now); - commentBlack.setAdvisorId(backendUserVO.getAdvisorId()); - if (CommentBlackType.DAY.value.equals(commentBlack.getType())) { - commentBlack.setEndTime(now.plusDays(1)); - } else if (CommentBlackType.MONTH.value.equals(commentBlack.getType())) { - commentBlack.setEndTime(now.plusMonths(1)); - } else { - commentBlack.setEndTime(now.plusYears(100)); - } - int count = commentBlackMapper.insert(commentBlack); - if (count < 1) { - throw new BizException(ResponseStatus.DB_SAVE_ERROR); - } - this.clearCache(Collections.singletonList(ALL_BLACK_USER)); - return commentBlack.getId(); - } - - @Transactional(rollbackFor = Exception.class) - public void removeCommentBlack(String phone) { - LocalDateTime now = LocalDateTime.now(); - QueryWrapper wrapper = Wrappers.query(); - wrapper.eq("phone", phone) - .in("status", Arrays.asList(CommentBlackStatus.EFFECT.value, CommentBlackStatus.EXPIRED.value)) - .lt("start_time", now) - .ge("end_time", now); - List commentBlackList = commentBlackMapper.selectList(wrapper); - if (CollectionUtils.isEmpty(commentBlackList)) { - throw new BizException(ResponseStatus.REMOVE_BLACK_USER_ERROR); - } - for (CommentBlack commentBlack : commentBlackList) { - CommentBlack updateObj = new CommentBlack(); - updateObj.setId(commentBlack.getId()); - updateObj.setStatus(CommentBlackStatus.REMOVED.value); - updateObj.setUpdateTime(now); - updateObj.setEndTime(now); - int count = commentBlackMapper.updateById(updateObj); - if (count < 1) { - throw new BizException(ResponseStatus.DB_SAVE_ERROR); - } - } - this.clearCache(Collections.singletonList(ALL_BLACK_USER)); - } - - public Pager queryCommentBlackList(BackendUserVO backendUserVO, CommentBlackQuery commentBlackQuery) { - LocalDateTime startTime = null; - LocalDateTime endTime = null; - LocalDateTime startOpTime = null; - LocalDateTime endOpTime = null; - if (StrUtil.isNotEmpty(commentBlackQuery.getStartTime())) { - startTime = LocalDateTime.parse(commentBlackQuery.getStartTime(), formatter); - } - if (StrUtil.isNotEmpty(commentBlackQuery.getEndTime())) { - endTime = LocalDateTime.parse(commentBlackQuery.getEndTime(), formatter); - } - if (StrUtil.isNotEmpty(commentBlackQuery.getStartOpTime())) { - startOpTime = LocalDateTime.parse(commentBlackQuery.getStartOpTime(), formatter); - } - if (StrUtil.isNotEmpty(commentBlackQuery.getEndOpTime())) { - endOpTime = LocalDateTime.parse(commentBlackQuery.getEndOpTime(), formatter); - } - /*Set advisorIdSet = authService.getAccessibleAdviserSet(null, backendUserVO, UserType.fromValue(commentBlackQuery.getUserType())); - if (advisorIdSet != null && advisorIdSet.isEmpty()) { - return Pager.emptyPager(); - }*/ - QueryWrapper wrapper = Wrappers.query(); - wrapper.like(StrUtil.isNotEmpty(commentBlackQuery.getUserName()), "user_name", commentBlackQuery.getUserName()) - .eq(StrUtil.isNotEmpty(commentBlackQuery.getPhone()), "phone", commentBlackQuery.getPhone()) - .eq(commentBlackQuery.getType() != null, "type", commentBlackQuery.getType()) - //.in(!CollectionUtils.isEmpty(advisorIdSet), "advisor_id", advisorIdSet) - .eq(commentBlackQuery.getProductType() != null, "product_type", commentBlackQuery.getProductType()) - .eq(commentBlackQuery.getProductType() != null && commentBlackQuery.getProductId() != null, "product_id", commentBlackQuery.getProductId()) - .like(StrUtil.isNotBlank(commentBlackQuery.getContent()), "content", commentBlackQuery.getContent()) - .like(StrUtil.isNotEmpty(commentBlackQuery.getReason()), "reason", commentBlackQuery.getReason()) - .eq(commentBlackQuery.getOperatorId() != null, "operator_id", commentBlackQuery.getOperatorId()) - .ge(startTime != null, "start_time", startTime) - .lt(endTime != null, "start_time", endTime) - .ge(startOpTime != null, "end_time", startOpTime) - .lt(endOpTime != null, "end_time", endOpTime); - wrapper.orderByDesc("start_time"); - Page page = commentBlackMapper.selectPage(commentBlackQuery.toPage(), wrapper); - List list = page.getRecords(); - if (CollectionUtils.isEmpty(list)) { - return Pager.emptyPager(); - } - List baseProductQueryList = list.stream().map(commentBlack -> { - if (commentBlack.getProductId() != null && commentBlack.getProductType() != null) { - return new BaseProductQuery(commentBlack.getProductId(), commentBlack.getProductType()); - } - return null; - }).filter(Objects::nonNull).collect(Collectors.toList()); - Table productTable = mergeProductService.queryMergeProductInfo(baseProductQueryList); - Map userMap = userService.getUserMap(); - Map deptMap = deptService.getDeptMap(); - List voList = list.stream().map(commentBlack -> mapperFacade.map(commentBlack, CommentBlackVO.class)).collect(Collectors.toList()); - for (CommentBlackVO commentBlackVO : voList) { - // 查询产品信息 - if (commentBlackVO.getProductId() != null && commentBlackVO.getProductType() != null) { - MergeProductInfoVO mergeProductInfoVO = productTable.get(commentBlackVO.getProductType(), commentBlackVO.getProductId()); - if (mergeProductInfoVO != null) { - commentBlackVO.setProductName(mergeProductInfoVO.getProductName()); - } - } - LocalDateTime now = LocalDateTime.now(); - if (CommentBlackStatus.EFFECT.value.equals(commentBlackVO.getStatus()) && now.isAfter(commentBlackVO.getEndTime())) { - commentBlackVO.setStatus(CommentBlackStatus.EXPIRED.value); - } - UserDept user = userMap.get(commentBlackVO.getOperatorId()); - if (user != null) { - commentBlackVO.setOperatorName(user.getName()); - } - if (StrUtil.hasText(commentBlackVO.getUserOrgNo())) { - Dept dept = deptMap.get(commentBlackVO.getUserOrgNo()); - if (dept != null) { - commentBlackVO.setUserOrgName(dept.getName()); - } - } - commentBlackVO.setPhone(HideUtils.hidePhoneNo(commentBlackVO.getPhone())); - commentBlackVO.setHidePhone(commentBlackVO.getPhone()); - commentBlackVO.setUserName(HideUtils.maskLastName(commentBlackVO.getUserName())); - } - return new Pager<>(voList, page.getTotal()); - } - - private void clearCache(List cacheKeys) { - IMap cacheMap = hazelcastInstance.getMap(COMMENT_BLACK); - for (String key : cacheKeys) { - cacheMap.remove(key); - } - } - - /** - * 校验是否禁言 - */ - public void check(String phone) { - // 判断是否禁言用户 - Set blackUsers = getAllBlackUser(); - if (CollUtil.isNotEmpty(blackUsers) && blackUsers.contains(phone)) { - throw new BizException("禁言用户,禁止发言"); - } - } - -} diff --git a/src/main/java/com/upchina/common/service/SensitiveWordService.java~ b/src/main/java/com/upchina/common/service/SensitiveWordService.java~ deleted file mode 100644 index 97bdb4e..0000000 --- a/src/main/java/com/upchina/common/service/SensitiveWordService.java~ +++ /dev/null @@ -1,130 +0,0 @@ -package com.upchina.common.service; - -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.toolkit.Wrappers; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.upchina.common.entity.SensitiveWord; -import com.upchina.common.handler.BizException; -import com.upchina.common.mapper.SensitiveWordMapper; -import com.upchina.common.query.KeywordPageQuery; -import com.upchina.common.query.OnlyIdQuery; -import com.upchina.common.query.SaveSensitiveQuery; -import com.upchina.common.result.Pager; -import com.upchina.common.result.ResponseStatus; -import com.upchina.common.vo.BackendUserVO; -import com.upchina.common.vo.SensitiveWordVO; -import org.ahocorasick.trie.Emit; -import org.ahocorasick.trie.Trie; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.StringUtils; -import org.springframework.web.multipart.MultipartFile; - -import javax.annotation.Resource; -import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -/** - *

- * 服务类 - *

- * - * @author easonzhu - * @since 2022-08-30 - */ - -@Service -public class SensitiveWordService { - - private static final long trieExpireTime = 300000; - private static Trie trie; - private static long trieBuildTime = 0L; - @Resource - private SensitiveWordMapper sensitiveWordMapper; - - public Pager list(KeywordPageQuery query) { - String keyword = query.getKeyword(); - QueryWrapper wrapper = Wrappers.query(); - wrapper.like(StrUtil.isNotEmpty(keyword), "word", keyword).orderByDesc("create_time"); - Page page = sensitiveWordMapper.selectPage(query.toPage(), wrapper); - List list = page.getRecords().stream().map(SensitiveWordVO::new).collect(Collectors.toList()); - return new Pager<>(list, page.getTotal()); - } - - @Transactional(rollbackFor = Exception.class) - public void save(SaveSensitiveQuery query, BackendUserVO backendUserVO) { - QueryWrapper wrapper = Wrappers.query(); - query.setWords(query.getWords().stream().distinct().collect(Collectors.toList())); - wrapper.in("word", query.getWords()); - sensitiveWordMapper.delete(wrapper); - List list = query.toPO(); - list.forEach(sensitiveWordMapper::insert); - getTrie(false); - } - - @Transactional(rollbackFor = Exception.class) - public void delete(OnlyIdQuery query, BackendUserVO backendUserVO) { - SensitiveWord sensitiveWord = sensitiveWordMapper.selectById(query.getId()); - int rows = sensitiveWordMapper.deleteById(query.getId()); - if (rows == 0) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - getTrie(false); - } - - public String[] upload(MultipartFile file) throws IOException { - String content = new String(file.getBytes()); - String[] lines = content.split("\r\n"); - if (lines.length == 0) { - throw new BizException(ResponseStatus.PARM_ERROR, "数据为空"); - } - int lineNum = 0; - for (String line : lines) { - lineNum++; - if (StrUtil.isEmpty(line)) { - throw new BizException(ResponseStatus.PARM_ERROR, "第" + lineNum + "行为空"); - } - } - return lines; - } - - public void check(List textList) { - if (textList.isEmpty()) { - return; - } - Trie trie = this.getTrie(true); - for (String text : textList) { - Collection emits = trie.parseText(text); - if (!emits.isEmpty()) { - Set collect = emits.stream().map(Emit::getKeyword).collect(Collectors.toSet()); - String emittedSensitiveWords = String.join(",", collect); -// String emittedSensitiveWords = emits.stream().map(Emit::getKeyword).collect(Collectors.joining(",")); - throw new BizException(ResponseStatus.SENSITIVE_WORD_ERROR.code, ResponseStatus.SENSITIVE_WORD_ERROR.message + ":" + emittedSensitiveWords); - } - } - } - - public void check(String... texts) { - this.check(Arrays.stream(texts).filter(StringUtils::isNotEmpty).collect(Collectors.toList())); - } - - private synchronized Trie getTrie(boolean flag) { - if (flag && (trie != null && System.currentTimeMillis() - trieBuildTime < trieExpireTime)) { - return trie; - } - Trie.TrieBuilder trieBuilder = Trie.builder(); - List list = sensitiveWordMapper.selectList(Wrappers.emptyWrapper()); - for (SensitiveWord word : list) { - trieBuilder.addKeyword(word.getWord()); - } - trieBuildTime = System.currentTimeMillis(); - trie = trieBuilder.build(); - return trie; - } - -} diff --git a/src/main/java/com/upchina/common/util/HideUtils.java~ b/src/main/java/com/upchina/common/util/HideUtils.java~ deleted file mode 100644 index 940a52f..0000000 --- a/src/main/java/com/upchina/common/util/HideUtils.java~ +++ /dev/null @@ -1,29 +0,0 @@ -package com.upchina.common.util; - -import cn.hutool.core.util.StrUtil; -import org.apache.commons.lang3.StringUtils; - -public class HideUtils { - - public static String hidePhoneNo(String phoneNo) { - if (StringUtils.isBlank(phoneNo)) { - return phoneNo; - } - if (phoneNo.length() >= 7) { - //前三后四 - return phoneNo.substring(0, 3) + "****" + - phoneNo.substring(phoneNo.length() - 4); - } else { - return phoneNo; - } - } - - public static String maskLastName(String name) { - if (StrUtil.isBlank(name)) { - return null; - } - int length = name.length(); - return name.substring(0, length - 1) + "*"; - } - -} diff --git a/src/main/java/com/upchina/common/util/LoggerUtil.java~ b/src/main/java/com/upchina/common/util/LoggerUtil.java~ deleted file mode 100644 index a8eeae6..0000000 --- a/src/main/java/com/upchina/common/util/LoggerUtil.java~ +++ /dev/null @@ -1,69 +0,0 @@ -package com.upchina.common.util; - -import java.util.Arrays; - -public class LoggerUtil { - - public static class Logger { - public static void info(String message) { - // TODO - System.out.println(message); - } - - public static void info(Object... message) { - // TODO - System.out.println(Arrays.toString(message)); - } - - public static void error(String message) { - // TODO - System.err.println(message); - } - - public static void error(Object... message) { - // TODO - System.err.println(Arrays.toString(message)); - } - - public static void warn(String message) { - // TODO - System.err.println(message); - } - - public static void error(Object... message) { - // TODO - System.err.println(Arrays.toString(message)); - } - } - - public static final Logger video = new Logger(); - - public static final Logger data = new Logger(); - - public static final Logger error = new Logger(); - - public static final Logger websocket = new Logger(); - - public static final Logger auth = new Logger(); - - public static void info(String message) { - // TODO - System.out.println(message); - } - - public static void info(Object... message) { - // TODO - System.out.println(Arrays.toString(message)); - } - - public static void error(String message) { - // TODO - System.err.println(message); - } - - public static void error(Object... message) { - // TODO - System.err.println(Arrays.toString(message)); - } - -} diff --git a/src/main/java/com/upchina/common/util/RsaUtil.java~ b/src/main/java/com/upchina/common/util/RsaUtil.java~ deleted file mode 100644 index 75a1775..0000000 --- a/src/main/java/com/upchina/common/util/RsaUtil.java~ +++ /dev/null @@ -1,143 +0,0 @@ -package com.upchina.common.util; - -import cn.hutool.core.codec.Base64; -import org.apache.commons.lang3.exception.ExceptionUtils; - -import javax.crypto.Cipher; -import java.io.ByteArrayOutputStream; -import java.security.KeyFactory; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.X509EncodedKeySpec; -import java.util.Arrays; - -public class RsaUtil { - - /** - * RSA最大加密大小 - */ - private final static int MAX_ENCRYPT_BLOCK = 117; - - /** - * ** - * RSA最大解密大小 - */ - private final static int MAX_DECRYPT_BLOCK = 128; - - /** - * 公钥加密 - * - * @param pubKey 公钥字符串 - * @param str 需要加密操作的字符串 - * @return 结果再Base64加密后的字符串 - * @throws Exception - */ - public static String pubKeyEncryption(String pubKey, String str) { - try { - // String 转 公钥 - PublicKey rsaPublicKey = getPublicKey(pubKey); - //公钥加密 - X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded()); - KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec); - Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); - cipher.init(Cipher.ENCRYPT_MODE, publicKey); - byte[] inputArray = str.getBytes(); - int inputLength = inputArray.length; - // 分段加密 - int offSet = 0; - byte[] resultBytes = {}; - byte[] cache; - while (inputLength - offSet > 0) { - if (inputLength - offSet > MAX_ENCRYPT_BLOCK) { - cache = cipher.doFinal(inputArray, offSet, MAX_ENCRYPT_BLOCK); - offSet += MAX_ENCRYPT_BLOCK; - } else { - cache = cipher.doFinal(inputArray, offSet, inputLength - offSet); - offSet = inputLength; - } - resultBytes = Arrays.copyOf(resultBytes, resultBytes.length + cache.length); - System.arraycopy(cache, 0, resultBytes, resultBytes.length - cache.length, cache.length); - } - return Base64.encode(resultBytes); - } catch (Exception exception) { - LoggerUtil.info("RsaUtil.pubKeyEncryption异常:" + ExceptionUtils.getStackTrace(exception)); - return null; - } - } - - /** - * 用私钥 解密 - * - * @param priKey 私钥字符串 - * @param encryptionBase64Str RSA加密后又base64编码后的字符串 - * @return 解密结果 - * @throws Exception - */ - public static String priKeyDecryption(String priKey, String encryptionBase64Str) { - try { - // base64 解码 - byte[] base64 = Base64.decode(encryptionBase64Str); - // String 转 私钥 - PrivateKey rsaPrivateKey = getPrivateKey(priKey); - //私钥解密 - PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded()); - KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); - Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); - cipher.init(Cipher.DECRYPT_MODE, privateKey); - // 返回UTF-8编码的解密信息 - int inputLen = base64.length; - ByteArrayOutputStream out = new ByteArrayOutputStream(); - int offSet = 0; - byte[] cache; - int i = 0; - // 对数据分段解密 - while (inputLen - offSet > 0) { - if (inputLen - offSet > MAX_DECRYPT_BLOCK) { - cache = cipher.doFinal(base64, offSet, MAX_DECRYPT_BLOCK); - } else { - cache = cipher.doFinal(base64, offSet, inputLen - offSet); - } - out.write(cache, 0, cache.length); - i++; - offSet = i * MAX_DECRYPT_BLOCK; - } - out.close(); - return out.toString("UTF-8"); - } catch (Exception exception) { - LoggerUtil.info("RsaUtil.priKeyDecryption异常:" + ExceptionUtils.getStackTrace(exception)); - return null; - } - } - - /** - * String转公钥PublicKey - * - * @param key - * @return - * @throws Exception - */ - private static PublicKey getPublicKey(String key) throws Exception { - byte[] keyBytes = Base64.decode(key); - X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); - KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - return keyFactory.generatePublic(keySpec); - } - - /** - * String转私钥PrivateKey - * - * @param key - * @return - * @throws Exception - */ - private static PrivateKey getPrivateKey(String key) throws Exception { - byte[] keyBytes = Base64.decodeBase64(key); - PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); - KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - return keyFactory.generatePrivate(keySpec); - } - -} diff --git a/src/main/java/com/upchina/common/util/WebServerInfo.java~ b/src/main/java/com/upchina/common/util/WebServerInfo.java~ deleted file mode 100644 index 78a59c9..0000000 --- a/src/main/java/com/upchina/common/util/WebServerInfo.java~ +++ /dev/null @@ -1,29 +0,0 @@ -package com.upchina.common.util; - -import org.springframework.boot.web.context.WebServerApplicationContext; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; -import java.net.InetAddress; -import java.net.UnknownHostException; - -@Component -public class WebServerInfo { - - @Resource - private WebServerApplicationContext webServerApplicationContext; - - public String getServerIp() { - // 获取本地的 IP 地址,Spring Boot 默认会绑定到 0.0.0.0(所有网络接口) - try { - InetAddress inetAddress = InetAddress.getLocalHost(); - } catch (UnknownHostException e) { - e.printStackTrace(); - } - return inetAddress.getHostAddress(); - } - - public int getServerPort() { - return webServerApplicationContext.getWebServer().getPort(); - } -} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/service/SerialService.java~ b/src/main/java/com/upchina/course/service/SerialService.java~ deleted file mode 100644 index 2b42e49..0000000 --- a/src/main/java/com/upchina/course/service/SerialService.java~ +++ /dev/null @@ -1,522 +0,0 @@ -package com.upchina.course.service; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.toolkit.Wrappers; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.hazelcast.map.IMap; -import com.upchina.advisor.entity.AdvisorBasic; -import com.upchina.advisor.service.AdvisorInfoService; -import com.upchina.common.config.cache.CacheKey; -import com.upchina.common.constant.IsOrNot; -import com.upchina.common.constant.IsRecommend; -import com.upchina.common.handler.BizException; -import com.upchina.common.query.OnlyIdPageQuery; -import com.upchina.common.query.OnlyIdQuery; -import com.upchina.common.result.Pager; -import com.upchina.common.result.ResponseStatus; -import com.upchina.common.service.AppUserService; -import com.upchina.common.service.CacheService; -import com.upchina.common.service.SensitiveWordService; -import com.upchina.common.state.StateMachine; -import com.upchina.common.vo.AuthResultVO; -import com.upchina.common.vo.BackendUserVO; -import com.upchina.common.vo.FrontUserVO; -import com.upchina.common.vo.InsertIdVO; -import com.upchina.course.constant.*; -import com.upchina.course.entity.CourseContent; -import com.upchina.course.entity.Serial; -import com.upchina.course.entity.SerialContent; -import com.upchina.course.mapper.CourseContentMapper; -import com.upchina.course.mapper.SerialContentMapper; -import com.upchina.course.mapper.SerialMapper; -import com.upchina.course.query.*; -import com.upchina.course.vo.SerialContentVO; -import com.upchina.course.vo.SerialVO; -import com.upchina.course.vo.ShortVideoVO; -import com.upchina.rbac.entity.UserDept; -import com.upchina.rbac.service.AuthService; -import com.upchina.rbac.service.UserService; -import com.upchina.video.constant.VideoStatus; -import com.upchina.video.constant.VideoUserType; -import com.upchina.video.service.app.AppVideoInfoService; -import com.upchina.video.vo.info.VideoDetailAppVO; -import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.annotation.Resource; -import java.time.LocalDateTime; -import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -// 合集Service -@Service -public class SerialService { - - @Resource - private SerialMapper serialMapper; - - @Resource - private SensitiveWordService sensitiveWordService; - - @Resource - private StateMachine serialSM; - - @Resource - private AdvisorInfoService advisorInfoService; - - @Resource - private UserService userService; - - @Resource - private SerialContentMapper serialContentMapper; - - @Resource - private AppVideoInfoService appVideoInfoService; - - @Resource - private CacheService cacheService; - - @Resource - private CourseContentMapper courseContentMapper; - - @Resource - private CourseService courseService; - - @Resource - private AuthService authService; - - @Resource - private ShortVideoService shortVideoService; - - @Resource - private CourseCommonService courseCommonService; - - @Resource - private AppUserService appUserService; - - @Resource - private IMap courseCache; - - /** - * 保存合集 - * - * @param query 保存合集参数 - * @param backendUserVO 后台用户 - * @return 合集ID - */ - @Transactional(rollbackFor = Exception.class) - public InsertIdVO save(SaveSerialQuery query, BackendUserVO backendUserVO) { - sensitiveWordService.check(query.getName(), query.getRemark()); - Integer advisorId = courseCommonService.getAdvisorId(query.getAdvisorId(), backendUserVO); - Serial serial = query.toPO(backendUserVO, advisorId); - serialMapper.insert(serial); - return new InsertIdVO(serial.getId()); - } - - /** - * 更新合集 - * - * @param query 更新合集参数 - * @param backendUserVO 后台用户 - */ - @Transactional(rollbackFor = Exception.class) - public void update(UpdateSerialQuery query, BackendUserVO backendUserVO) { - sensitiveWordService.check(query.getName(), query.getRemark()); - Serial serialInDB = serialMapper.selectById(query.getId()); - if (serialInDB == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - - // 状态机扭转,判断是否能够编辑 - SerialStatus dbStatus = SerialStatus.fromValue(serialInDB.getStatus()); - serialSM.send(dbStatus, SerialStatus.EVENT_UPDATE); - - Serial serial = query.toPO(backendUserVO); - serialMapper.updateById(serial); - clearCache(query.getId()); - } - - /** - * 更新合集状态 - * - * @param query 更新合集状态参数 - * @param backendUserVO 后台用户 - */ - @Transactional(rollbackFor = Exception.class) - public void updateStatus(UpdateSerialStatusQuery query, BackendUserVO backendUserVO) { - Serial serialInDB = serialMapper.selectById(query.getId()); - if (serialInDB == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - - // 状态机扭转 - SerialStatus dbStatus = SerialStatus.fromValue(serialInDB.getStatus()); - SerialStatus targetStatus = serialSM.send(dbStatus, SerialStatus.fromValue(query.getEvent())); - - Serial serial = query.toPO(targetStatus, backendUserVO); - serialMapper.updateById(serial); - clearCache(query.getId()); - } - - /** - * 查询合集列表 - * - * @param query 查询参数 - * @param backendUserVO 后台用户 - * @return 合集列表 - */ - public Pager list(ListSerialQuery query, BackendUserVO backendUserVO) { - String name = query.getName(); - Integer status = query.getStatus(); - Integer type = query.getType(); - Integer userType = query.getUserType(); - Integer contentType = query.getContentType(); - Integer contentId = query.getContentId(); - Integer excludeCourseId = query.getExcludeCourseId(); - - Set authSet = null; - if (backendUserVO != null) { - authSet = authService.getAuthByUserType(VideoUserType.format(userType), backendUserVO, true); - if (authSet != null && authSet.isEmpty()) { - return null; - } - } - - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .in(CollUtil.isNotEmpty(authSet), Serial::getAdvisorId, authSet) - .like(StrUtil.isNotEmpty(name), Serial::getName, name) - .eq(status != null && status != 0, Serial::getStatus, status) - .eq(type != null && type != 0, Serial::getType, type) - .exists(contentType != null && contentId != null, - "select 0 from serial_content where serial_content.serial_id = serial.id and serial_content.type = {0} and serial_content.content_id = {1}", - contentType, contentId) - .notExists("select 0 from course_content where course_content.content_id = serial.id and course_content.type = {0} and course_content.course_id = {1}", - CourseContentType.SERIAL.value, excludeCourseId) - .ne(!VideoUserType.MANAGER_USER.value.equals(userType), Serial::getStatus, SerialStatus.DELETED.value) - .orderByDesc(Serial::getCreateTime); - Page page = serialMapper.selectPage(query.toPage(), wrapper); - Map advisorNameMap = advisorInfoService.getAdvisorMap().values().stream() - .collect(Collectors.toMap(AdvisorBasic::getId, AdvisorBasic::getName)); - Map userNameMap = userService.getUserMap().values().stream() - .collect(Collectors.toMap(UserDept::getUserId, UserDept::getName)); - List list = page.getRecords().stream().map(serial -> new SerialVO( - serial, - advisorNameMap.get(serial.getAdvisorId()), - userNameMap.get(serial.getCreateUserId()), - userNameMap.get(serial.getAuditUserId()), - getContentCount(serial.getId()) - )).collect(Collectors.toList()); - return new Pager<>(list, page.getTotal()); - } - - /** - * 查询合集详情 - * - * @param query 查询参数 - * @param backendUserVO 后台用户 - * @return 合集详情 - */ - public SerialVO get(OnlyIdQuery query, BackendUserVO backendUserVO) { - Integer id = query.getId(); - Serial serial = getEntity(id, backendUserVO); - if (serial == null) { - return null; - } - Map advisorNameMap = advisorInfoService.getAdvisorMap().values().stream() - .collect(Collectors.toMap(AdvisorBasic::getId, AdvisorBasic::getName)); - Map userNameMap = userService.getUserMap().values().stream() - .collect(Collectors.toMap(UserDept::getUserId, UserDept::getName)); - return new SerialVO( - serial, - advisorNameMap.get(serial.getAdvisorId()), - userNameMap.get(serial.getCreateUserId()), - userNameMap.get(serial.getAuditUserId()), - getContentCount(id)); - } - - /** - * 查询合集内容列表 - * - * @param query 查询参数 - * @param backendUserVO 后台用户 - * @return 合集内容列表 - */ - public Pager listContent(OnlyIdPageQuery query, BackendUserVO backendUserVO) { - // 校验合集是否存在以及数据权限 - Serial serial = getEntity(query.getId(), backendUserVO); - if (serial == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - Integer type = serial.getType(); - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .eq(SerialContent::getSerialId, query.getId()) - .eq(SerialContent::getType, type) - .orderByDesc(SerialContent::getIsRecommend, SerialContent::getCreateTime); - Page page = serialContentMapper.selectPage(query.toPage(), wrapper); - List list = page.getRecords().stream().map(content -> { - if (SerialType.SHORT_VIDEO.value.equals(type)) { - ShortVideoVO shortVideo = shortVideoService.get(new OnlyIdQuery(content.getContentId()), null); - return new SerialContentVO(content, shortVideo); - } else if (SerialType.VIDEO.value.equals(type)) { - VideoDetailAppVO video = appVideoInfoService.getVideoDetail(null, content.getContentId(), IsOrNot.NOT.value, null, null); - return new SerialContentVO(content, video); - } - return null; - }).filter(Objects::nonNull).collect(Collectors.toList()); - return new Pager<>(list, page.getTotal()); - } - - /** - * 编辑合集内容 - * - * @param query 编辑合集内容参数 - * @param backendUserVO 后台用户 - */ - @Transactional(rollbackFor = Exception.class) - public void updateContent(UpdateSerialContentQuery query, BackendUserVO backendUserVO) { - // 校验合集是否存在以及数据权限 - Serial serial = getEntity(query.getSerialId(), backendUserVO); - if (serial == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - // 构造查询条件 - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .eq(SerialContent::getSerialId, query.getSerialId()) - .eq(SerialContent::getType, serial.getType()) - .eq(SerialContent::getContentId, query.getContentId()); - UpdateContentEvent event = UpdateContentEvent.fromValue(query.getEvent()); - switch (event) { - case SAVE: - saveContentList(query.getSerialId(), serial.getType(), query.toContentListPO(serial.getType()), event); - break; - case RECOMMEND: - if (query.getIsRecommend() == null || IsRecommend.NO.value.equals(query.getIsRecommend())) { - throw new BizException(ResponseStatus.PARM_ERROR, "权重值错误"); - } - SerialContent recommendContent = new SerialContent(); - recommendContent.setIsRecommend(query.getIsRecommend()); - serialContentMapper.update(recommendContent, wrapper); - break; - case UN_RECOMMEND: - SerialContent unRecommendContent = new SerialContent(); - unRecommendContent.setIsRecommend(IsRecommend.NO.value); - serialContentMapper.update(unRecommendContent, wrapper); - break; - case ADD: - saveContentList(query.getSerialId(), serial.getType(), query.toContentListPO(serial.getType()), event); - break; - case DELETE: - saveContentList(query.getSerialId(), serial.getType(), Collections.singletonList(query.toContentPO(serial.getType())), event); - break; - } - clearCache(query.getSerialId()); - } - - /** - * APP端查询合集详情 - * - * @param query 查询参数 - * @return 合集详情 - */ - public SerialVO getForApp(OnlyIdQuery query, FrontUserVO frontUserVO) { - SerialVO vo = cacheService.get(CacheKey.COURSE, CacheKey.CourseKey.SERIAL_INFO + query.getId(), () -> { - SerialVO serial = get(query, null); - if (serial == null) { - return null; - } - // 如果合集本来就没有权限,不计算父级权限,允许免费观看 - if (!StringUtils.isBlank(serial.getAuthorityId())) { - serial.setAuthorityId(getAuthorityId(query.getId())); - } - return serial; - }); - if (vo == null) { - return null; - } - AuthResultVO authResultVo = appUserService.checkAuth(vo.getAuthorityId(), frontUserVO); - vo.setAuthResultVo(authResultVo); - return vo; - } - - /** - * APP端查询合集内容列表 - * - * @param query 查询参数 - * @return 合集内容列表 - */ - public List listContentForApp(OnlyIdQuery query, FrontUserVO frontUserVO) { - if (frontUserVO != null) { - SerialVO vo = getForApp(query, frontUserVO); - if (vo == null) { - return null; - } - if (!vo.getAuthResultVo().getAuth()) { - throw new BizException(ResponseStatus.NOT_PRODUCT_AUTH); - } - } - return cacheService.get(CacheKey.COURSE, CacheKey.CourseKey.SERIAL_CONTENT + query.getId(), () -> { - OnlyIdPageQuery listQuery = new OnlyIdPageQuery(query.getId()); - listQuery.setCurrent(1); - listQuery.setSize(Integer.MAX_VALUE); - Pager page = listContent(listQuery, null); - // 过滤内容状态 - return page.getList().stream().filter(c -> - SerialType.VIDEO.value.equals(c.getType()) && VideoStatus.PASS.value.equals(c.getVideo().getStatus()) - || SerialType.SHORT_VIDEO.value.equals(c.getType()) && ShortVideoStatus.AUDITED.value.equals(c.getShortVideo().getStatus()) - ).collect(Collectors.toList()); - }); - } - - /** - * 查询合集内容数量 - * - * @param serialId 合集ID - * @return 合集内容数量 - */ - public int getContentCount(Integer serialId) { - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .eq(SerialContent::getSerialId, serialId); - return serialContentMapper.selectCount(wrapper).intValue(); - } - - /** - * 保存内容列表 - * - * @param contentId 内容ID - * @param contentType 内容类型 - * @param serialIds 集合ID列表 - */ - public void saveContentList(Integer contentId, SerialType contentType, List serialIds) { - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .select(SerialContent::getSerialId) - .eq(SerialContent::getContentId, contentId) - .eq(SerialContent::getType, contentType.value); - List existSerialList = serialContentMapper.selectList(wrapper); - Set existSerialIdSet = existSerialList.stream().map(SerialContent::getSerialId).collect(Collectors.toSet()); - LocalDateTime now = LocalDateTime.now(); - if (CollUtil.isNotEmpty(serialIds)) { - // 添加新增的 - List contentList = serialIds.stream().filter(serialId -> !existSerialIdSet.contains(serialId)).map(serialId -> { - SerialContent content = new SerialContent(); - content.setSerialId(serialId); - content.setContentId(contentId); - content.setType(contentType.value); - content.setCreateTime(now); - content.setIsRecommend(IsRecommend.NO.value); - return content; - }).collect(Collectors.toList()); - if (CollUtil.isNotEmpty(contentList)) { - serialContentMapper.insertBatchSomeColumn(contentList); - } - } - // 删除多余的 - existSerialList.stream().filter(content -> !serialIds.contains(content.getSerialId())).forEach(content -> { - LambdaQueryWrapper deleteWrapper = Wrappers.lambdaQuery() - .eq(SerialContent::getSerialId, content.getSerialId()) - .eq(SerialContent::getContentId, contentId) - .eq(SerialContent::getType, contentType.value); - serialContentMapper.delete(deleteWrapper); - }); - if (CollUtil.isNotEmpty(serialIds)) { - serialIds.forEach(this::refreshUpdateTime); - } - } - - /** - * 查询包含此内容且最后更新的合集 - * - * @param contentId 内容ID - * @param serialType 合集类型 - * @return 合集 - */ - public SerialVO getLastUpdateSerial(Integer contentId, SerialType serialType) { - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .select(SerialContent::getSerialId) - .eq(SerialContent::getContentId, contentId) - .eq(SerialContent::getType, serialType.value) - .orderByDesc(SerialContent::getCreateTime) - .last("limit 1"); - SerialContent serialContent = serialContentMapper.selectOne(wrapper); - if (serialContent == null) { - return null; - } - return get(new OnlyIdQuery(serialContent.getSerialId()), null); - } - - /** - * 清除缓存 - * - * @param id 合集ID - */ - private void clearCache(Integer id) { - courseCache.delete(CacheKey.CourseKey.SERIAL_INFO + id); - courseCache.delete(CacheKey.CourseKey.SERIAL_CONTENT + id); - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .select(CourseContent::getCourseId) - .eq(CourseContent::getContentId, id) - .eq(CourseContent::getType, CourseContentType.SERIAL.value); - List list = courseContentMapper.selectList(wrapper); - list.stream().map(CourseContent::getCourseId).forEach(courseId -> courseService.clearCache(courseId, null)); - } - - private Serial getEntity(Integer id, BackendUserVO backendUserVO) { - Serial serial = serialMapper.selectById(id); - if (serial == null) { - return null; - } - // 数据权限检查 - courseCommonService.checkAdvisorId(serial.getAdvisorId(), backendUserVO); - return serial; - } - - private void saveContentList(Integer serialId, Integer contentType, List contentListPO, UpdateContentEvent event) { - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .select(SerialContent::getContentId) - .eq(SerialContent::getSerialId, serialId) - .eq(SerialContent::getType, contentType); - List existContentList = serialContentMapper.selectList(wrapper); - Set existContentIdSet = existContentList.stream().map(SerialContent::getContentId).collect(Collectors.toSet()); - if (UpdateContentEvent.SAVE.equals(event) || UpdateContentEvent.ADD.equals(event)) { - // 添加新增的 - List contentList = contentListPO.stream().filter(content -> !existContentIdSet.contains(content.getContentId())).collect(Collectors.toList()); - if (CollUtil.isNotEmpty(contentList)) { - serialContentMapper.insertBatchSomeColumn(contentList); - } - } - if (UpdateContentEvent.SAVE.equals(event) || UpdateContentEvent.DELETE.equals(event)) { - Stream contentStream = Stream.empty(); - if (UpdateContentEvent.SAVE.equals(event)) { - // 删除多余的 - Set contentIdSet = contentListPO.stream().map(SerialContent::getContentId).collect(Collectors.toSet()); - contentStream = existContentList.stream().filter(content -> !contentIdSet.contains(content.getContentId())); - } else if (UpdateContentEvent.DELETE.equals(event)) { - // 删除传入的 - contentStream = contentListPO.stream(); - } - contentStream.forEach(content -> { - LambdaQueryWrapper deleteWrapper = Wrappers.lambdaQuery() - .eq(SerialContent::getSerialId, serialId) - .eq(SerialContent::getContentId, content.getContentId()) - .eq(SerialContent::getType, contentType); - serialContentMapper.delete(deleteWrapper); - }); - } - refreshUpdateTime(serialId); - } - - private void refreshUpdateTime(Integer serialId) { - Serial serial = new Serial(); - serial.setId(serialId); - serial.setUpdateTime(LocalDateTime.now()); - serialMapper.updateById(serial); - } - - private String getAuthorityId(Integer id) { - String authorityId = serialMapper.getAuthorityId(id, CourseContentType.SERIAL.value); - return authorityId == null ? null : Arrays.stream(authorityId.split(",|,")).distinct().collect(Collectors.joining(",")); - } -} \ No newline at end of file diff --git a/src/main/java/com/upchina/course/service/ShortVideoService.java~ b/src/main/java/com/upchina/course/service/ShortVideoService.java~ deleted file mode 100644 index 2aedf5f..0000000 --- a/src/main/java/com/upchina/course/service/ShortVideoService.java~ +++ /dev/null @@ -1,879 +0,0 @@ -package com.upchina.course.service; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.toolkit.Wrappers; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.hazelcast.collection.ISet; -import com.hazelcast.core.HazelcastInstance; -import com.hazelcast.map.IMap; -import com.upchina.advisor.service.AdvisorInfoService; -import com.upchina.advisor.vo.AdvisorBasicVO; -import com.upchina.common.config.cache.CacheKey; -import com.upchina.common.constant.IsDisplay; -import com.upchina.common.constant.IsLike; -import com.upchina.common.constant.IsOrNot; -import com.upchina.common.constant.ProductType; -import com.upchina.common.entity.VideoTransFlow; -import com.upchina.common.handler.BizException; -import com.upchina.common.mapper.VideoTransFlowMapper; -import com.upchina.common.query.OnlyIdQuery; -import com.upchina.common.result.AppPager; -import com.upchina.common.result.Pager; -import com.upchina.common.result.ResponseStatus; -import com.upchina.common.service.*; -import com.upchina.common.state.StateMachine; -import com.upchina.common.util.LoggerUtil; -import com.upchina.common.vo.*; -import com.upchina.course.constant.*; -import com.upchina.course.entity.*; -import com.upchina.course.mapper.*; -import com.upchina.course.query.*; -import com.upchina.course.vo.*; -import com.upchina.rbac.entity.UserDept; -import com.upchina.rbac.entity.WxUser; -import com.upchina.rbac.mapper.WxUserMapper; -import com.upchina.rbac.service.AuthService; -import com.upchina.rbac.service.UserService; -import com.upchina.video.constant.VideoLimitType; -import com.upchina.video.constant.VideoTransStatus; -import com.upchina.video.constant.VideoUserType; -import com.upchina.video.entity.CloudMediaEntity; -import com.upchina.video.query.info.AppLimitQuery; -import com.upchina.video.service.app.AppVideoInfoService; -import com.upchina.video.service.common.VideoCloudService; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.dao.DuplicateKeyException; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.annotation.Resource; -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.time.LocalDateTime; -import java.util.*; -import java.util.function.Function; -import java.util.stream.Collectors; - -// 短视频Service -@Service -public class ShortVideoService { - - @Resource - private ShortVideoMapper shortVideoMapper; - - @Resource - private UserService userService; - - @Resource - private CacheService cacheService; - - @Resource - private SensitiveWordService sensitiveWordService; - - @Resource - private AuthService authService; - - @Resource - private AdvisorInfoService advisorInfoService; - - @Resource - private StateMachine shortVideoSM; - - @Resource - private ShortVideoCartMapper shortVideoCartMapper; - - @Resource - private ShortVideoFavorMapper shortVideoFavorMapper; - - @Resource - private CommentService commentService; - - @Resource - private SerialService serialService; - - @Resource - private VideoCloudService videoCloudService; - - @Resource - private CourseCommonService courseCommonService; - - @Resource - private ShortVideoWatchMapper shortVideoWatchMapper; - - @Resource - private ShortVideoShareMapper shortVideoShareMapper; - - @Resource - private HazelcastInstance hazelcastInstance; - - @Resource - private AppUserService appUserService; - - @Resource - private AppVideoInfoService appVideoInfoService; - - @Resource - private ShortVideoCartClickMapper shortVideoCartClickMapper; - - @Resource - private WxUserMapper wxUserMapper; - - @Resource - private UrlService urlService; - - @Resource - private ShortVideoSaleMapper shortVideoSaleMapper; - - @Resource - private IMap courseCache; - - @Resource - private VideoTransFlowMapper videoTransFlowMapper; - - @Value("${video.finishReadRatio}") - private Double finishReadRatio; - - @Value("${resizeUrl.shortVideoUrl}") - private String shortVideoUrl; - - /** - * 保存短视频 - * - * @param query 保存短视频参数 - * @param backendUserVO 后台用户 - * @return 短视频ID - */ - @Transactional(rollbackFor = Exception.class) - public InsertIdVO save(SaveShortVideoQuery query, BackendUserVO backendUserVO) { - sensitiveWordService.check(query.getTitle(), query.getViewPoint()); - Integer advisorId = courseCommonService.getAdvisorId(query.getAdvisorId(), backendUserVO); - // 检测短视频回调情况 - boolean hasTrans = checkShortVideoHasTrans(query.getFileId()); - ShortVideo shortVideo = query.toPO(backendUserVO, advisorId, hasTrans); - shortVideoMapper.insert(shortVideo); - Integer id = shortVideo.getId(); - - // 保存购物车 - if (IsOrNot.IS.value.equals(query.getIsCart())) { - List cartList = query.toCartListPO(id); - saveCartList(id, cartList); - } else { - removeCartList(id); - } - - // 保存合集 - if (CollUtil.isNotEmpty(query.getSerialIds())) { - serialService.saveContentList(id, SerialType.SHORT_VIDEO, query.getSerialIds()); - } - - // 检查转码状态,防止先转码成功,数据还没有保存的问题 - List cloudMediaEntities = videoCloudService.describeMediaInfos(Collections.singleton(shortVideo.getFileId())); - if (CollUtil.isNotEmpty(cloudMediaEntities)) { - CloudMediaEntity media = cloudMediaEntities.get(0); - ShortVideo updateVideo = new ShortVideo(); - updateVideo.setId(id); - updateVideo.setFileName(media.getName()); - updateVideo.setDuration(media.getDuration().intValue()); - updateVideo.setSize(media.getSize().intValue()); - updateVideo.setTransStatus(VideoTransStatus.HAS_TRANSCODE.value); - shortVideoMapper.updateById(updateVideo); - } - - - return new InsertIdVO(id); - } - - /* - 检测是否上传视频已回调 true已转码 false未转码 - */ - public boolean checkShortVideoHasTrans(String fileId) { - VideoTransFlow videoTransFlow = videoTransFlowMapper.selectOne(new QueryWrapper() - .eq("file_id", fileId) - .last("limit 1") - ); - return videoTransFlow != null && Objects.equals(videoTransFlow.getErrCode(), 0); - } - - /** - * 更新短视频 - * - * @param query 更新短视频参数 - * @param backendUserVO 后台用户 - */ - @Transactional(rollbackFor = Exception.class) - public void update(UpdateShortVideoQuery query, BackendUserVO backendUserVO) { - sensitiveWordService.check(query.getTitle(), query.getViewPoint()); - - Integer id = query.getId(); - ShortVideo videoInDB = shortVideoMapper.selectById(id); - if (videoInDB == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - - // 状态机扭转,判断是否能够编辑 - ShortVideoStatus dbStatus = ShortVideoStatus.fromValue(videoInDB.getStatus()); - shortVideoSM.send(dbStatus, ShortVideoStatus.EVENT_UPDATE); - - ShortVideo shortVideo = query.toPO(backendUserVO, checkShortVideoHasTrans(query.getFileId())); - shortVideoMapper.updateById(shortVideo); - - // 保存购物车 - if (IsOrNot.IS.value.equals(query.getIsCart())) { - List cartList = query.toCartListPO(id); - saveCartList(id, cartList); - } else { - removeCartList(id); - } - - // 保存合集 - if (CollUtil.isNotEmpty(query.getSerialIds())) { - serialService.saveContentList(id, SerialType.SHORT_VIDEO, query.getSerialIds()); - } - - clearCache(id, videoInDB.getAdvisorId()); - } - - /** - * 更新短视频状态 - * - * @param query 更新短视频状态参数 - * @param backendUserVO 后台用户 - */ - @Transactional(rollbackFor = Exception.class) - public void updateStatus(UpdateShortVideoStatusQuery query, BackendUserVO backendUserVO) { - ShortVideo videoInDB = shortVideoMapper.selectById(query.getId()); - if (videoInDB == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - // 状态机扭转 - ShortVideoStatus dbStatus = ShortVideoStatus.fromValue(videoInDB.getStatus()); - ShortVideoStatus targetStatus = shortVideoSM.send(dbStatus, ShortVideoStatus.fromValue(query.getEvent())); - - ShortVideo shortVideo = query.toPO(targetStatus, backendUserVO); - shortVideoMapper.updateById(shortVideo); - clearCache(query.getId(), videoInDB.getAdvisorId()); - } - - /** - * 查询短视频列表 - * - * @param query 查询参数 - * @param backendUserVO 后台用户 - * @return 短视频列表 - */ - public Pager list(ListShortVideoQuery query, BackendUserVO backendUserVO) { - String title = query.getTitle(); - Integer status = query.getStatus(); - Integer userType = query.getUserType(); - Integer advisorId = query.getAdvisorId(); - Integer excludeSerialId = query.getExcludeSerialId(); - Integer isDisplay = query.getIsDisplay(); - - Set authSet = authService.getAuthByUserType(VideoUserType.format(userType), backendUserVO, true); - if (authSet != null && authSet.isEmpty()) { - return null; - } - - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .in(CollUtil.isNotEmpty(authSet), ShortVideo::getAdvisorId, authSet) - .eq(advisorId != null && advisorId != 0, ShortVideo::getAdvisorId, advisorId) - .like(StrUtil.isNotEmpty(title), ShortVideo::getTitle, title) - .eq(status != null && status != 0, ShortVideo::getStatus, status) - .eq(isDisplay != null && isDisplay != 0, ShortVideo::getIsDisplay, isDisplay) - .notExists(excludeSerialId != null && excludeSerialId != 0, "select 0 from serial_content where serial_content.content_id = short_video.id and serial_content.serial_id = {0} and type = {1}", excludeSerialId, SerialType.SHORT_VIDEO.value) - .ne(!VideoUserType.MANAGER_USER.value.equals(userType), ShortVideo::getStatus, ShortVideoStatus.DELETED.value) - .orderByDesc(!IsOrNot.IS.value.equals(isDisplay), ShortVideo::getCreateTime) - .orderByDesc(IsOrNot.IS.value.equals(isDisplay), ShortVideo::getIsRecommend); - Page page = shortVideoMapper.selectPage(query.toPage(), wrapper); - Map advisorMap = advisorInfoService.getAdvisorVoMap(); - Map userNameMap = userService.getUserMap().values().stream() - .collect(Collectors.toMap(UserDept::getUserId, UserDept::getName)); - List list = page.getRecords().stream().map(video -> new ShortVideoVO( - video, - advisorMap.get(video.getAdvisorId()), - userNameMap.get(video.getCreateUserId()), - userNameMap.get(video.getAuditUserId()), - getFavorCount(video.getId()), - commentService.queryCommentCount(video.getId(), ProductType.SHORT_VIDEO.value, null, true), - shortVideoWatchMapper.selectWatchCount(video.getId()) - )).collect(Collectors.toList()); - return new Pager<>(list, page.getTotal()); - } - - /** - * 查询短视频详情 - * - * @param query 查询参数 - * @param backendUserVO 后台用户 - * @return 短视频详情 - */ - public ShortVideoVO get(OnlyIdQuery query, BackendUserVO backendUserVO) { - Integer id = query.getId(); - ShortVideo video = getEntity(id, backendUserVO); - if (video == null) { - return null; - } - Map advisorMap = advisorInfoService.getAdvisorVoMap(); - Map userNameMap = userService.getUserMap().values().stream() - .collect(Collectors.toMap(UserDept::getUserId, UserDept::getName)); - ShortVideoVO vo = new ShortVideoVO( - video, - advisorMap.get(video.getAdvisorId()), - userNameMap.get(video.getCreateUserId()), - userNameMap.get(video.getAuditUserId()), - getFavorCount(id), - commentService.queryCommentCount(id, ProductType.SHORT_VIDEO.value, null, true), - shortVideoWatchMapper.selectWatchCount(id) - ); - List cartList = shortVideoCartMapper.selectList(Wrappers.lambdaQuery() - .eq(ShortVideoCart::getVideoId, id) - .orderByDesc(ShortVideoCart::getWeight)); - vo.setCartList(cartList.stream().map(ShortVideoCartVO::new).collect(Collectors.toList())); - vo.setSerialList(listSerial(id, backendUserVO)); - return vo; - } - - /** - * 设置首页参数 - * - * @param query 查询参数 - * @param backendUserVO 后台用户 - */ - public void setMainPageParam(SetMainPageQuery query, BackendUserVO backendUserVO) { - // 不使用返回值,仅校验课程是否存在以及数据权限 - ShortVideo videoInDB = getEntity(query.getId(), backendUserVO); - if (videoInDB == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - ShortVideo video = query.toShortVideoPO(); - shortVideoMapper.updateById(video); - this.clearCache(query.getId(), videoInDB.getAdvisorId()); - } - - /** - * 更新购物车商品上下架 - * - * @param query 更新购物车商品上下架参数 - * @param backendUserVO 后台用户 - */ - @Transactional(rollbackFor = Exception.class) - public void updateCartStatus(UpdateCartStatusQuery query, BackendUserVO backendUserVO) { - Integer id = query.getVideoId(); - ShortVideo video = shortVideoMapper.selectById(id); - if (video == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - // 数据权限检查 - courseCommonService.checkAdvisorId(video.getAdvisorId(), backendUserVO); - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .eq(ShortVideoCart::getVideoId, id) - .eq(ShortVideoCart::getProductId, query.getProductId()) - .eq(ShortVideoCart::getProductType, query.getProductType()); - ShortVideoCart cart = new ShortVideoCart(); - cart.setStatus(query.getStatus()); - int rows = shortVideoCartMapper.update(cart, wrapper); - if (rows == 0) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - clearCache(id, video.getAdvisorId()); - } - - /** - * APP端查询短视频详情 - * - * @param query 查询参数 - * @param frontUserVO 前台用户 - * @return 短视频详情 - */ - public ShortVideoVO getForApp(IdAndSaleUserQuery query, FrontUserVO frontUserVO, boolean removeLimitField) { - Integer id = query.getId(); - Integer saleUserId = query.getSaleUserId(); - ShortVideoVO vo = cacheService.get(courseCache, CacheKey.CourseKey.SHORT_VIDEO + id, () -> { - ShortVideoVO video = get(query.toOnlyIdQuery(), null); - if (video == null) { - return null; - } - // 如果视频本来就没有权限,不计算父级权限,允许免费观看 - if (!StringUtils.isBlank(video.getAuthorityId())) { - video.setAuthorityId(getAuthorityId(id)); - } - return video; - }); - if (vo == null) { - return null; - } - vo.setFavorCount(getFavorCount(id)); - vo.setCommentCount(commentService.queryCommentCount(id, ProductType.SHORT_VIDEO.value, frontUserVO, false)); - vo.setWatchCount(shortVideoWatchMapper.selectWatchCount(id)); - if (frontUserVO != null) { - vo.setIsFavor(isFavor(query.getId(), frontUserVO.getUserId())); - } - vo.setAuthResultVo(appUserService.checkAuth(vo.getAuthorityId(), frontUserVO)); - vo.setIsLiving(appVideoInfoService.livingByAdvisorId(vo.getAdvisorId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); - // app端不返回合集列表,只返回最近更新的一个 - vo.setSerialList(null); - vo.setSerial(serialService.getLastUpdateSerial(id, SerialType.SHORT_VIDEO)); - vo.setResizeUrl(urlService.getResizeUrlByApp(shortVideoUrl, CacheKey.URL_KEY.URL_KEY_SHORT_VIDEO_ID, id, saleUserId)); - vo.setUpcomingLive(appVideoInfoService.getNotPlayVideoByAdvisorId(vo.getAdvisorId(), frontUserVO)); - if (removeLimitField) { - vo.setAuthorityId(null); - vo.setInviteCode(null); - } - // 插入营销关系 - if (frontUserVO != null && saleUserId != null) { - LambdaQueryWrapper saleWrapper = Wrappers.lambdaQuery() - .eq(ShortVideoSale::getUserId, frontUserVO.getUserId()) - .eq(ShortVideoSale::getVideoId, id); - ShortVideoSale sale = shortVideoSaleMapper.selectOne(saleWrapper); - if (sale == null) { - sale = new ShortVideoSale(); - sale.setUserId(frontUserVO.getUserId()); - sale.setVideoId(id); - sale.setSaleUserId(saleUserId); - shortVideoSaleMapper.insert(sale); - } else { - sale = new ShortVideoSale(); - sale.setUserId(frontUserVO.getUserId()); - sale.setVideoId(id); - sale.setSaleUserId(saleUserId); - shortVideoSaleMapper.update(sale, saleWrapper); - } - } - return vo; - } - - /** - * APP端点赞短视频 - * - * @param query 点赞短视频参数 - * @param frontUserVO 前台用户 - * @return 点赞数 - */ - @Transactional(rollbackFor = Exception.class) - public CountVO favor(FavorVideoQuery query, FrontUserVO frontUserVO) { - Integer videoId = query.getVideoId(); - Integer option = query.getOption(); - String userId = frontUserVO.getUserId(); - if (IsLike.YES.value.equals(option)) { - try { - shortVideoFavorMapper.insert(query.toPO(userId)); - } catch (DuplicateKeyException e) { - throw new BizException(ResponseStatus.REPETITIVE_ERROR); - } - getFavorSet(videoId).add(userId); - } else if (IsLike.NO.value.equals(option)) { - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .eq(ShortVideoFavor::getUserId, userId) - .eq(ShortVideoFavor::getVideoId, videoId); - shortVideoFavorMapper.delete(wrapper); - getFavorSet(videoId).remove(userId); - } else { - return null; - } - return new CountVO(getFavorCount(videoId)); - } - - /** - * APP端查询短视频列表 - * - * @param query 查询参数 - * @param frontUserVO 前台用户 - * @return 短视频列表 - */ - public AppPager listForApp(ListCourseAppQuery query, FrontUserVO frontUserVO) { - Integer id = query.getId(); - Integer lastId = query.getLastId(); - LocalDateTime lastPublishTime = query.getLastPublishTime(); - Integer lastWeight = query.getLastWeight(); - Integer size = query.getSize(); - NavigableSet sortedSet = cacheService.get(courseCache, CacheKey.CourseKey.MAIN_SHORT_VIDEO_LIST + id, () -> { - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .eq(ShortVideo::getAdvisorId, id) - .eq(ShortVideo::getStatus, CourseStatus.AUDITED.value) - .eq(ShortVideo::getIsDisplay, IsDisplay.YES.value) - .orderByDesc(ShortVideo::getIsRecommend, ShortVideo::getAuditTime); - List list = shortVideoMapper.selectList(wrapper); - NavigableSet set = new TreeSet<>(); - list.stream().map(CourseSortEntity::new).forEach(set::add); - return set; - }); - CourseSortEntity lastEntity = lastId == null || lastWeight == null || lastPublishTime == null ? null : new CourseSortEntity(lastId, lastWeight, lastPublishTime); - if (lastEntity != null) { - sortedSet = sortedSet.tailSet(lastEntity, false); - } - List voList = new ArrayList<>(size); - Iterator iterator = sortedSet.iterator(); - while (iterator.hasNext() && voList.size() < size) { - CourseSortEntity entity = iterator.next(); - ShortVideoVO vo = getForApp(new IdAndSaleUserQuery(entity.getId()), null, true); - if (vo != null) { - voList.add(vo); - } - } - return new AppPager<>(voList, iterator.hasNext()); - } - - public OnlyBoolVO checkLimit(AppLimitQuery query, FrontUserVO frontUserVO) { - Integer id = query.getVideoId(); - String code = query.getCode(); - ShortVideoVO vo = getForApp(new IdAndSaleUserQuery(id), frontUserVO, false); - if (vo == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - if (!VideoLimitType.CODE.value.equals(vo.getLimitType()) || StrUtil.isBlank(vo.getInviteCode())) { - return new OnlyBoolVO(true); - } - return new OnlyBoolVO(vo.getInviteCode().equals(code)); - } - - /** - * 保存短视频观看记录 - * - * @param query 保存短视频观看记录参数 - * @param frontUserVO 前台用户 - */ - public void saveWatch(SaveShortVideoWatchListQuery query, FrontUserVO frontUserVO) { - List cacheList = hazelcastInstance.getList(CacheKey.CourseKey.SHORT_VIDEO_WATCH_LIST); - List voList = query.getList().stream() - .filter(watch -> watch.getVideoId() != null) - .map(watch -> new ShortVideoWatchVO(watch, frontUserVO)) - .collect(Collectors.toList()); - cacheList.addAll(voList); - } - - /** - * 保存短视频分享记录 - * - * @param query 查询对象,包含视频ID - * @param frontUserVO 前台用户 - */ - @Transactional(rollbackFor = Exception.class) - public void saveShare(OnlyIdQuery query, FrontUserVO frontUserVO) { - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .eq(ShortVideoShare::getVideoId, query.getId()) - .eq(ShortVideoShare::getUserId, frontUserVO.getUserId()); - ShortVideoShare share = shortVideoShareMapper.selectOne(wrapper); - if (share == null) { - share = new ShortVideoShare(); - share.setUserId(frontUserVO.getUserId()); - share.setVideoId(query.getId()); - share.setCount(1); - share.setCreateTime(LocalDateTime.now()); - shortVideoShareMapper.insert(share); - } else { - share.setCount(share.getCount() + 1); - share.setUpdateTime(LocalDateTime.now()); - shortVideoShareMapper.update(share, wrapper); - } - } - - /** - * 刷新短视频的转码状态 - * - * @param fileIds 要刷新转码状态的短视频文件ID集合 - */ - public void refreshTranscodeStatus(Set fileIds) { - try { - if (CollUtil.isEmpty(fileIds)) { - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .select(ShortVideo::getFileId) - .eq(ShortVideo::getTransStatus, TransStatus.TRANSCODING.value) - .isNotNull(ShortVideo::getFileId); - List transcodingVideoList = shortVideoMapper.selectList(wrapper); - fileIds = transcodingVideoList.stream().map(ShortVideo::getFileId).collect(Collectors.toSet()); - } - if (CollUtil.isEmpty(fileIds)) { - return; - } - List list = videoCloudService.describeMediaInfos(fileIds); - for (CloudMediaEntity media : list) { - try { - if (Objects.equals(media.getTransStatus(), VideoTransStatus.HAS_TRANSCODE.value)) { - LambdaQueryWrapper updateWrapper = Wrappers.lambdaQuery() - .eq(ShortVideo::getFileId, media.getFileId()); - shortVideoMapper.update(media.toShortVideoPO(), updateWrapper); - } - } catch (Exception ex) { - LoggerUtil.error("更新视频资源失败:" + ExceptionUtils.getStackTrace(ex)); - } - } - } catch (BizException e) { - String targets = fileIds == null ? "" : String.join(",", fileIds); - LoggerUtil.error("查询云点播失败|" + targets + "|" + e.getErrorMsg()); - throw e; - } - } - - /** - * 保存短视频观看记录 - */ - @Transactional(rollbackFor = Exception.class) - public void saveWatchToDB() { - List cacheList = hazelcastInstance.getList(CacheKey.CourseKey.SHORT_VIDEO_WATCH_LIST); - // 合并重复项 - Set videoIdSet = new HashSet<>(); - Map map = new HashMap<>(cacheList.size()); - for (ShortVideoWatchVO vo : cacheList) { - if (vo != null) { - videoIdSet.add(vo.getVideoId()); - ShortVideoWatch watch = vo.toPO(); - ShortVideoWatch existWatch = map.get(vo); - if (existWatch == null) { - map.put(vo, watch); - } else { - existWatch.setCount(existWatch.getCount() + watch.getCount()); - existWatch.setSeconds(existWatch.getSeconds() + watch.getSeconds()); - } - } - } - if (videoIdSet.isEmpty() || map.isEmpty()) { - return; - } - List videoList = shortVideoMapper.selectBatchIds(videoIdSet); - Map videoMap = videoList.stream().collect(Collectors.toMap(ShortVideo::getId, Function.identity())); - // 保存 - map.forEach((k, v) -> { - ShortVideo video = videoMap.get(v.getVideoId()); - if (video == null || video.getDuration() == null) { - return; - } - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .eq(ShortVideoWatch::getUserId, v.getUserId()) - .eq(ShortVideoWatch::getVideoId, v.getVideoId()); - ShortVideoWatch watch = shortVideoWatchMapper.selectOne(wrapper); - if (watch == null) { - v.setCreateTime(LocalDateTime.now()); - shortVideoWatchMapper.insert(v); - } else { - // 不能超过总视频时长的2倍 - v.setSeconds(Math.min(video.getDuration() * 2, watch.getSeconds() + v.getSeconds())); - v.setCount(watch.getCount() + v.getCount()); - v.setUpdateTime(LocalDateTime.now()); - shortVideoWatchMapper.update(v, wrapper); - } - }); - cacheList.clear(); - } - - /** - * 保存购物车点击 - * - * @param query - * @param frontUserVO - */ - public void saveCartClick(SaveShortVideoCartClickQuery query, FrontUserVO frontUserVO) { - if (frontUserVO == null || StrUtil.isBlank(frontUserVO.getUserId())) { - throw new BizException(ResponseStatus.SESSION_USER_LOGOUT); - } - Integer videoId = query.getVideoId(); - Integer productId = query.getProductId(); - Integer productType = query.getProductType(); - String productName = query.getProductName(); - ShortVideoCartClick click = new ShortVideoCartClick(); - click.setUserId(frontUserVO.getUserId()); - click.setVideoId(videoId); - click.setProductType(productType); - click.setProductId(productId); - click.setProductName(productName); - try { - // 忽略重复异常 - shortVideoCartClickMapper.insert(click); - } catch (DuplicateKeyException e) { - } - } - - /** - * 后台统计短视频数据明细 - * - * @param query 查询参数 - * @param backendUserVO 后端用户 - * @return 统计明细列表 - */ - public Pager listCollect(ListShortVideoCollectQuery query, BackendUserVO backendUserVO) { - Integer id = query.getId(); - BigDecimal completeRate = query.getCompleteRate(); - ShortVideo video = getEntity(id, backendUserVO); - if (video == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - Integer finishReadSecond = null; - if (completeRate != null && completeRate.compareTo(BigDecimal.ZERO) > 0 && video.getDuration() != null && video.getDuration() > 0) { - finishReadSecond = completeRate.multiply(BigDecimal.valueOf(video.getDuration())).intValue(); - } - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .eq(ShortVideoWatch::getVideoId, id) - .gt(finishReadSecond != null && finishReadSecond < video.getDuration(), ShortVideoWatch::getSeconds, finishReadSecond) - .ge(finishReadSecond != null && finishReadSecond >= video.getDuration(), ShortVideoWatch::getSeconds, finishReadSecond) - .orderByDesc(ShortVideoWatch::getSeconds); - Page page = shortVideoWatchMapper.selectPage(query.toPage(), wrapper); - Set userIds = page.getRecords().stream().map(ShortVideoWatch::getUserId).filter(StrUtil::isNotBlank).collect(Collectors.toSet()); - Map userSaleIdMap = new HashMap<>(); - Map userNameMap = userService.getUserMap().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getName())); - if (CollUtil.isNotEmpty(userIds)) { - LambdaQueryWrapper saleWrapper = Wrappers.lambdaQuery() - .eq(ShortVideoSale::getVideoId, id) - .in(ShortVideoSale::getUserId, userIds); - shortVideoSaleMapper.selectList(saleWrapper).forEach(sale -> userSaleIdMap.put(sale.getUserId(), sale.getSaleUserId())); - } - List voList = page.getRecords().stream().map(watch -> { - String userId = watch.getUserId(); - WxUser user = wxUserMapper.selectById(userId); - Integer commentCount = commentService.getUserProductCommentCount(userId, ProductType.SHORT_VIDEO, id); - Integer isFavor = isFavor(id, userId); - Integer shareCount = getShareCount(id, userId); - ShortVideoCollectVO vo = new ShortVideoCollectVO(user, video, watch, commentCount, isFavor, shareCount); - Integer saleUserId = userSaleIdMap.get(userId); - vo.setSaleUserId(saleUserId); - if (saleUserId != null) { - vo.setSaleUserName(userNameMap.get(saleUserId)); - } - LambdaQueryWrapper cartClickWrapper = Wrappers.lambdaQuery() - .select(ShortVideoCartClick::getProductName) - .eq(ShortVideoCartClick::getUserId, userId) - .eq(ShortVideoCartClick::getVideoId, id); - List clickList = shortVideoCartClickMapper.selectList(cartClickWrapper); - List productNames = clickList.stream().map(ShortVideoCartClick::getProductName).collect(Collectors.toList()); - vo.setClickCartNames(productNames); - return vo; - }).collect(Collectors.toList()); - return new Pager<>(voList, page.getTotal()); - } - - /** - * 后台统计短视频数据汇总 - * - * @param query 查询参数 - * @param backendUserVO 后端用户 - * @return 统计汇总 - */ - public ShortVideoCollectSummaryVO getCollectSummary(OnlyIdQuery query, BackendUserVO backendUserVO) { - Integer id = query.getId(); - ShortVideo video = getEntity(id, backendUserVO); - if (video == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - // 查询观看次数、观看人数、总播放时长 - ShortVideoCollectSummaryVO summary = shortVideoWatchMapper.selectCollectSummary(id); - // 计算观看平均播放时长 - if (summary.getWatchSeconds() != 0 && summary.getWatchUserCount() != 0) { - summary.setWatchSeconds(summary.getWatchSeconds() / summary.getWatchUserCount()); - } else { - summary.setWatchSeconds(0); - } - // 查询完整观看人数 - if (video.getDuration() == null || video.getDuration() == 0) { - summary.setWatchFullUserCount(0); - } else { - Integer finishReadSecond = (int) (video.getDuration() * finishReadRatio); - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .eq(ShortVideoWatch::getVideoId, id) - .ge(ShortVideoWatch::getSeconds, finishReadSecond); - Integer watchFullUserCount = shortVideoWatchMapper.selectCount(wrapper).intValue(); - summary.setWatchFullUserCount(watchFullUserCount); - } - // 评论数 - Integer commentCount = commentService.getUserProductCommentCount(null, ProductType.SHORT_VIDEO, id); - summary.setCommentCount(commentCount); - // 点赞数 - summary.setFavorCount(getFavorCount(id)); - // 分享数 - summary.setShareCount(getShareCount(id, null)); - // 互动率 = (评论人去重 + 分享数按人去重 + 点赞数) / 总观看人数 - BigDecimal commentRate = BigDecimal.ZERO; - if (summary.getWatchUserCount() != 0) { - // 评论数去重 - Integer distinctCommentCount = commentService.getDistinctUserCount(ProductType.SHORT_VIDEO, id); - // 分享数去重 - QueryWrapper shareWrapper = Wrappers.query() - .select("count(distinct user_id) as count") - .eq("video_id", id); - ShortVideoShare share = shortVideoShareMapper.selectOne(shareWrapper); - Integer distinctShareCount = share == null ? 0 : share.getCount(); - commentRate = BigDecimal.valueOf(distinctCommentCount + distinctShareCount + summary.getFavorCount()) - .divide(BigDecimal.valueOf(summary.getWatchUserCount()), 4, RoundingMode.HALF_UP); - } - summary.setCommentRate(commentRate); - return summary; - } - - private Integer isFavor(Integer videoId, String userId) { - if (userId == null) { - return IsLike.NO.value; - } - ISet favorUserIds = getFavorSet(videoId); - return favorUserIds.contains(userId) ? IsLike.YES.value : IsLike.NO.value; - } - - private ISet getFavorSet(Integer videoId) { - return cacheService.getSet(CacheKey.CourseKey.SHORT_VIDEO_FAVOR_USER_IDS + videoId, () -> { - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .select(ShortVideoFavor::getUserId) - .eq(ShortVideoFavor::getVideoId, videoId); - return shortVideoFavorMapper.selectList(wrapper).stream().map(ShortVideoFavor::getUserId).collect(Collectors.toSet()); - }); - } - - private Integer getFavorCount(Integer videoId) { - return getFavorSet(videoId).size(); - } - - private void clearCache(Integer id, Integer advisorId) { - courseCache.delete(CacheKey.CourseKey.SHORT_VIDEO + id); - courseCache.delete(CacheKey.CourseKey.MAIN_SHORT_VIDEO_LIST + advisorId); - } - - private ShortVideo getEntity(Integer id, BackendUserVO backendUserVO) { - ShortVideo video = shortVideoMapper.selectById(id); - if (video == null) { - return null; - } - // 数据权限检查 - courseCommonService.checkAdvisorId(video.getAdvisorId(), backendUserVO); - return video; - } - - private void saveCartList(Integer id, List cartList) { - removeCartList(id); - if (CollUtil.isNotEmpty(cartList)) { - shortVideoCartMapper.insertBatchSomeColumn(cartList); - } - } - - private void removeCartList(Integer id) { - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .eq(ShortVideoCart::getVideoId, id); - shortVideoCartMapper.delete(wrapper); - } - - private String getAuthorityId(Integer id) { - String authorityId = shortVideoMapper.getAuthorityId(id, SerialType.SHORT_VIDEO.value, CourseContentType.SERIAL.value); - return authorityId == null ? null : Arrays.stream(authorityId.split(",|,")).distinct().collect(Collectors.joining(",")); - } - - private Integer getShareCount(Integer id, String userId) { - QueryWrapper wrapper = Wrappers.query() - .select("ifnull(sum(count), 0) as count") - .eq("video_id", id) - .eq(userId != null, "user_id", userId); - ShortVideoShare share = shortVideoShareMapper.selectOne(wrapper); - return share == null ? 0 : share.getCount(); - } - - private List listSerial(Integer videoId, BackendUserVO userVO) { - ListSerialQuery query = new ListSerialQuery(); - query.setStatus(SerialStatus.AUDITED.value); - query.setContentId(videoId); - query.setContentType(SerialType.SHORT_VIDEO.value); - query.setCurrent(1); - query.setSize(Integer.MAX_VALUE); - query.setUserType(VideoUserType.MANAGER_USER.value); - Pager page = serialService.list(query, userVO); - return page.getList(); - } - -} \ No newline at end of file diff --git a/src/main/java/com/upchina/rbac/service/MenuService.java~ b/src/main/java/com/upchina/rbac/service/MenuService.java~ deleted file mode 100644 index aa114f1..0000000 --- a/src/main/java/com/upchina/rbac/service/MenuService.java~ +++ /dev/null @@ -1,129 +0,0 @@ -package com.upchina.rbac.service; - -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.toolkit.Wrappers; -import cn.hutool.core.util.StrUtil; -import com.upchina.common.handler.BizException; -import com.upchina.common.query.OnlyIdQuery; -import com.upchina.common.result.ResponseStatus; -import com.upchina.common.vo.BackendUserVO; -import com.upchina.rbac.entity.Menu; -import com.upchina.rbac.entity.Permission; -import com.upchina.rbac.mapper.MenuMapper; -import com.upchina.rbac.mapper.PermissionMapper; -import com.upchina.rbac.query.ListMenuQuery; -import com.upchina.rbac.query.SaveMenuQuery; -import com.upchina.rbac.query.UpdateMenuQuery; -import com.upchina.rbac.vo.MenuVO; -import com.upchina.rbac.vo.PermissionVO; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.annotation.Resource; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -@Service -public class MenuService { - - @Resource - private MenuMapper menuMapper; - - @Resource - private PermissionMapper permissionMapper; - - @Transactional(readOnly = true) - public List list(ListMenuQuery query, Integer userId, boolean buildTree) { - String keyword = query.getKeyword(); - Integer roleId = query.getRoleId(); - List searchList; - List searchVoList; - List allVoList; - QueryWrapper wrapper = Wrappers.query(); - wrapper.orderByAsc("sort"); - boolean isAll = false; - if (StringUtils.isNotEmpty(keyword)) { - wrapper.like("name", keyword).or().like("path", keyword); - searchList = menuMapper.selectList(wrapper); - } else if (userId != null) { - searchList = menuMapper.selectListByUserId(userId); - } else if (roleId != null) { - searchList = menuMapper.selectListByRoleId(roleId); - } else { - searchList = menuMapper.selectList(wrapper); - isAll = true; - } - searchVoList = searchList.stream().map(MenuVO::new).collect(Collectors.toList()); - if (!buildTree) { - return searchVoList; - } - if (isAll) { - allVoList = searchVoList; - } else { - QueryWrapper allWrapper = Wrappers.query().orderByAsc("pid"); - List allList = menuMapper.selectList(allWrapper); - allVoList = allList.stream().map(MenuVO::new).collect(Collectors.toList()); - } - - // 填充权限 - List allPermissionList = permissionMapper.selectList(Wrappers.emptyWrapper()); - Map> menuPermissionListMap = allPermissionList.stream().map(PermissionVO::new).collect(Collectors.groupingBy(PermissionVO::getMenuId)); - allVoList.forEach(menuVO -> menuVO.setPermissions(menuPermissionListMap.get(menuVO.getId()))); - - List rootList = Collections.emptyList(); - if (!allVoList.isEmpty()) { - rootList = (List) new MenuVO().buildTree(searchVoList, allVoList); - } - - rootList.sort(Comparator.comparing(MenuVO::getSort)); - if (userId != null) { - convertMenu(rootList); - } - return rootList; - } - - @Transactional - public void save(SaveMenuQuery query, BackendUserVO backendUserVO) { - Menu menu = query.toPO(); - menuMapper.insert(menu); - } - - @Transactional - public void update(UpdateMenuQuery query, BackendUserVO backendUserVO) { - Menu menu = query.toPO(); - int rows = menuMapper.updateById(menu); - if (rows == 0) throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - - @Transactional - public void delete(OnlyIdQuery query, BackendUserVO backendUserVO) { - Integer id = query.getId(); - Menu menu = menuMapper.selectById(id); - if (menu == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - QueryWrapper wrapper = Wrappers.query(); - wrapper.eq("pid", id); - Long count = menuMapper.selectCount(wrapper); - if (count > 0) { - throw new BizException(ResponseStatus.CHILD_EXIST_ERROR); - } - menuMapper.deleteById(query.getId()); - } - - private void convertMenu(List list) { - list.forEach(vo -> { - if (vo.getPid() == null || vo.getPid() <= 0) { - vo.setPath("/" + vo.getPath()); - vo.setComponent(StringUtils.isEmpty(vo.getComponent()) ? "Layout" : vo.getComponent()); - } - if (vo.getChildren() != null && !vo.getChildren().isEmpty()) { - vo.setRedirect("noredirect"); - convertMenu(vo.getChildren()); - } - }); - } -} diff --git a/src/main/java/com/upchina/rbac/service/RoleService.java~ b/src/main/java/com/upchina/rbac/service/RoleService.java~ deleted file mode 100644 index c212373..0000000 --- a/src/main/java/com/upchina/rbac/service/RoleService.java~ +++ /dev/null @@ -1,170 +0,0 @@ -package com.upchina.rbac.service; - -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.toolkit.Wrappers; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.hazelcast.core.HazelcastInstance; -import cn.hutool.core.util.StrUtil; -import com.upchina.common.config.cache.CacheKey; -import com.upchina.common.handler.BizException; -import com.upchina.common.query.OnlyIdQuery; -import com.upchina.common.result.Pager; -import com.upchina.common.result.ResponseStatus; -import com.upchina.common.vo.BackendUserVO; -import com.upchina.rbac.entity.*; -import com.upchina.rbac.mapper.RoleMapper; -import com.upchina.rbac.mapper.RolesMenusMapper; -import com.upchina.rbac.mapper.RolesPermissionsMapper; -import com.upchina.rbac.mapper.UsersRolesMapper; -import com.upchina.rbac.query.*; -import com.upchina.rbac.vo.RoleBasicVO; -import com.upchina.rbac.vo.RoleVO; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.annotation.Resource; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -/** - * @author yetian - */ -@Service -public class RoleService { - - @Resource - private RoleMapper roleMapper; - - @Resource - private UsersRolesMapper usersRolesMapper; - - @Resource - private MenuService menuService; - - @Resource - private RolesMenusMapper rolesMenusMapper; - - @Resource - private RolesPermissionsMapper rolesPermissionsMapper; - - @Resource - private PermissionService permissionService; - - @Resource - private HazelcastInstance hazelcastInstance; - - @Transactional(readOnly = true) - public Pager list(ListRoleQuery query) { - String name = query.getName(); - QueryWrapper wrapper = Wrappers.query(); - wrapper.like(StringUtils.isNotEmpty(name), "name", name); - Page page = roleMapper.selectPage(query.toPage(), wrapper); - List list = page.getRecords().stream().map(role -> { - RoleVO vo = new RoleVO(role); - ListMenuQuery listMenuQuery = new ListMenuQuery(); - listMenuQuery.setRoleId(role.getId()); - vo.setMenuList(menuService.list(listMenuQuery, null, false)); - vo.setPermissionList(permissionService.list(role.getId(), null)); - return vo; - }).collect(Collectors.toList()); - return new Pager<>(list, page.getTotal()); - } - - @Transactional(readOnly = true) - public RoleVO get(Integer id) { - Role role = roleMapper.selectById(id); - if (role == null) { - return null; - } - RoleVO vo = new RoleVO(role); - ListMenuQuery listMenuQuery = new ListMenuQuery(); - listMenuQuery.setRoleId(role.getId()); - vo.setMenuList(menuService.list(listMenuQuery, null, false)); - return vo; - } - - public List listByUserId(ListRoleByUserIdQuery query) { - List list = roleMapper.selectByUserId(query.getUserId()); - return list.stream().map(RoleVO::new).collect(Collectors.toList()); - } - - public Map> getUserRoleList(List userIdList) { - if (userIdList == null || userIdList.isEmpty()) { - return Collections.emptyMap(); - } - String userIds = userIdList.stream().distinct().map(String::valueOf).collect(Collectors.joining(",")); - List list = roleMapper.selectByUserIds(userIds); - return list.stream().collect( - Collectors.groupingBy(UserRoleEntity::getUserId, - Collectors.mapping(RoleBasicVO::new, Collectors.toList()))); - } - - @Transactional(rollbackFor = Exception.class) - public void save(SaveRoleQuery query, BackendUserVO backendUserVO) { - Role role = query.toPO(); - roleMapper.insert(role); - } - - @Transactional(rollbackFor = Exception.class) - public void update(UpdateRoleQuery query, BackendUserVO backendUserVO) { - Role originRole = roleMapper.selectById(query.getId()); - if (originRole.getBuiltIn() == 1) { - throw new BizException(ResponseStatus.BUILT_IN_CAN_NOT_MODIFY); - } - Role role = query.toPO(); - int rows = roleMapper.updateById(role); - if (rows == 0) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - } - - @Transactional(rollbackFor = Exception.class) - public void delete(OnlyIdQuery query, BackendUserVO backendUserVO) { - Role originRole = roleMapper.selectById(query.getId()); - if (originRole.getBuiltIn() == 1) { - throw new BizException(ResponseStatus.BUILT_IN_CAN_NOT_MODIFY); - } - QueryWrapper wrapper = Wrappers.query(); - wrapper.eq("role_id", originRole.getId()); - Long count = usersRolesMapper.selectCount(wrapper); - if (count > 0) { - throw new BizException(ResponseStatus.BE_USED_NOT_MODIFY); - } - int rows = roleMapper.deleteById(query.getId()); - if (rows == 0) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - } - - @Transactional(rollbackFor = Exception.class) - public void saveMenus(SaveRoleMenusQuery query, BackendUserVO backendUserVO) { - QueryWrapper wrapper = Wrappers.query(); - wrapper.eq("role_id", query.getRoleId()); - rolesMenusMapper.delete(wrapper); - - List list = query.toPO(); - for (RolesMenus rm : list) { - rolesMenusMapper.insert(rm); - } - } - - @Transactional - public void savePermissions(SaveRolePermissionsQuery query, BackendUserVO backendUserVO) { - Role originRole = roleMapper.selectById(query.getRoleId()); - if (originRole.getBuiltIn() == 1) { - throw new BizException(ResponseStatus.BUILT_IN_CAN_NOT_MODIFY); - } - QueryWrapper wrapper = Wrappers.query(); - wrapper.eq("role_id", query.getRoleId()); - rolesPermissionsMapper.delete(wrapper); - - List list = query.toPO(); - for (RolesPermissions rp : list) { - rolesPermissionsMapper.insert(rp); - } - Map cacheMap = hazelcastInstance.getMap(CacheKey.RBAC); - cacheMap.remove(CacheKey.RbacKey.ROLE_PERMISSIONS_URL + query.getRoleId()); - } -} diff --git a/src/main/java/com/upchina/rbac/vo/IParentChildVO.java~ b/src/main/java/com/upchina/rbac/vo/IParentChildVO.java~ deleted file mode 100644 index 61685ff..0000000 --- a/src/main/java/com/upchina/rbac/vo/IParentChildVO.java~ +++ /dev/null @@ -1,49 +0,0 @@ -package com.upchina.rbac.vo; - -import com.google.common.collect.Lists; -import cn.hutool.core.util.StrUtil; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; - -public interface IParentChildVO { - - PK getId(); - - PK getPid(); - - List getChildren(); - - void setChildren(List list); - - default void buildParent(IParentChildVO vo, Map allMap, Map rootMap) { - PK pid = (PK) vo.getPid(); - if (pid != null && ((pid instanceof String && StringUtils.isNotEmpty((String) pid) && !"0".equals(pid) && !"-1".equals(pid)) - || (pid instanceof Integer && (Integer) pid > 0) - || (pid instanceof Long && (Long) pid > 0))) { - IParentChildVO parent = allMap.get(vo.getPid()); - if (parent == null) return; - List children = parent.getChildren(); - if (children != null) { - if (children.stream().noneMatch(child -> child.getId().equals(vo.getId()))) { - children.add(vo); - } - } else { - parent.setChildren(Lists.newArrayList(vo)); - } - buildParent(parent, allMap, rootMap); - } else { - rootMap.put((PK) vo.getId(), vo); - } - } - - default List buildTree(List voList, List allList) { - Map allMap = allList.stream().collect(Collectors.toMap(vo -> (PK) vo.getId(), Function.identity())); - Map rootMap = new HashMap<>(); - voList.forEach(vo -> buildParent(vo, allMap, rootMap)); - return Lists.newArrayList(rootMap.values()); - } -} diff --git a/src/main/java/com/upchina/video/service/admin/AdminVideoInfoService.java~ b/src/main/java/com/upchina/video/service/admin/AdminVideoInfoService.java~ deleted file mode 100644 index f31d0e8..0000000 --- a/src/main/java/com/upchina/video/service/admin/AdminVideoInfoService.java~ +++ /dev/null @@ -1,1307 +0,0 @@ -package com.upchina.video.service.admin; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.StrUtil; -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.Wrappers; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.google.common.collect.Sets; -import com.google.common.collect.Table; -import cn.hutool.core.util.StrUtil; -import com.upchina.advisor.service.AdvisorInfoService; -import com.upchina.advisor.vo.AdvisorBasicVO; -import com.upchina.common.config.cache.CacheKey; -import com.upchina.common.constant.IsDisplay; -import com.upchina.common.constant.IsOrNot; -import com.upchina.common.constant.ProductType; -import com.upchina.common.constant.RecommendOption; -import com.upchina.common.handler.BizException; -import com.upchina.common.query.OnlyIdQuery; -import com.upchina.common.result.Pager; -import com.upchina.common.result.ResponseStatus; -import com.upchina.common.service.MergeProductService; -import com.upchina.common.service.TagService; -import com.upchina.common.state.StateMachine; -import com.upchina.common.util.LoggerUtil; -import com.upchina.common.vo.BackendUserVO; -import com.upchina.common.vo.MergeProductInfoVO; -import com.upchina.common.vo.OnlyIdVO; -import com.upchina.common.vo.TagVO; -import com.upchina.course.constant.*; -import com.upchina.course.query.ListCourseQuery; -import com.upchina.course.query.ListSerialQuery; -import com.upchina.course.query.SetMainPageQuery; -import com.upchina.course.service.CourseService; -import com.upchina.course.service.SerialService; -import com.upchina.course.service.ShortVideoService; -import com.upchina.course.vo.CourseVO; -import com.upchina.course.vo.SerialVO; -import com.upchina.rbac.service.AuthService; -import com.upchina.video.constant.*; -import com.upchina.video.entity.*; -import com.upchina.video.helper.VideoHelper; -import com.upchina.video.mapper.*; -import com.upchina.video.query.VideoSwitchQuery; -import com.upchina.video.query.VideoUdateInteractTypeQuery; -import com.upchina.video.query.cart.CartQuery; -import com.upchina.video.query.common.*; -import com.upchina.video.query.info.*; -import com.upchina.video.query.mix.SaveLiveMixQuery; -import com.upchina.video.query.mix.UpdateMixStatusQuery; -import com.upchina.video.query.mix.UpdateShowMainQuery; -import com.upchina.video.query.push.LivePushQuery; -import com.upchina.video.service.common.VideoCacheService; -import com.upchina.video.service.common.VideoCloudService; -import com.upchina.video.service.common.VideoCommonService; -import com.upchina.video.service.common.VideoMessageService; -import com.upchina.video.vo.cart.VideoCartVO; -import com.upchina.video.vo.info.VideoInfoDetailVO; -import com.upchina.video.vo.info.VideoInfoListVO; -import com.upchina.video.vo.message.VideoNotificationVO; -import com.upchina.video.vo.message.VideoPcAdvisorMessageVO; -import com.upchina.video.vo.mix.LiveMixVO; -import com.upchina.video.vo.push.LivePushVO; -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.annotation.Resource; -import java.time.LocalDateTime; -import java.util.*; -import java.util.stream.Collectors; - -// admin信息Service -@Service -public class AdminVideoInfoService { - - @Resource - private VideoLiveMapper videoLiveMapper; - - @Resource - private VideoCloudService videoCloudService; - - @Resource - private VideoCacheService videoCacheService; - - @Resource - private VideoMessageService videoMessageService; - - @Resource - private VideoCommonService videoCommonService; - - @Resource - private AdminVideoColumnService adminVideoColumnService; - - @Resource - private VideoLiveLibraryMapper videoLiveLibraryMapper; - - @Resource - private VideoLiveTagMapper videoLiveTagMapper; - - @Resource - private VideoCartMapper videoCartMapper; - - @Resource - private MergeProductService mergeProductService; - - @Resource - private AdvisorInfoService advisorInfoService; - - @Resource - private StateMachine videoStatusSm; - - @Resource - private TagService tagService; - - @Resource - private VideoLiveUserMapper videoLiveUserMapper; - - @Resource - private AdminVideoQuestionService adminVideoQuestionService; - - @Resource - private AuthService authService; - - @Resource - private AdminVideoCartService adminVideoCartService; - - @Resource - private SerialService serialService; - - @Resource - private CourseService courseService; - - @Resource - private AdminVideoInteractionService adminVideoInteractionService; - - @Resource - private ShortVideoService shortVideoService; - - @Resource - private VideoLivePushMapper videoLivePushMapper; - - @Resource - private AdminVideoPushService adminVideoPushService; - - @Resource - private VideoLiveMixMapper videoLiveMixMapper; - - @Resource - private AdminVideoMixService adminVideoMixService; - - /** - * 控制视频直播(中断、恢复、终止) - * - * @param query 控制视频直播的查询对象 - */ - @Transactional(rollbackFor = Exception.class) - public void controlLive(ControlVideoLiveQuery query) { - Integer id = query.getId(); - Integer option = query.getOption(); - - VideoLive video = validateEntity(id, false); - if (VideoLiveStatus.NOT_STARTED.value.equals(video.getLiveStatus())) { - throw new BizException(ResponseStatus.STATUS_ERROR, "未直播"); - } - if (VideoLiveStatus.HAS_ENDED.value.equals(video.getLiveStatus())) { - throw new BizException(ResponseStatus.STATUS_ERROR, "直播已结束"); - } - - VideoLiveStatus videoLiveStatus = null; - LocalDateTime realEndTime = null; - if (VideoControlType.DROP.value.equals(option)) { - videoLiveStatus = VideoLiveStatus.SUSPENSION; - // 中断 - videoCloudService.forbidLiveStream(id); - // 更新视频直播状态为暂停中 - videoLiveMapper.updateById(new VideoLive(id, videoLiveStatus)); - } else if (VideoControlType.RESUME.value.equals(option)) { - // 恢复 - videoCloudService.resumeLiveStream(id); - } else if (VideoControlType.FORBID.value.equals(option)) { - videoLiveStatus = VideoLiveStatus.HAS_ENDED; - videoCloudService.stopRecordTask(video); - // 终止 - videoCloudService.forbidLiveStream(id); - // 更新视频直播状态为已结束 - VideoLive updateVideo = new VideoLive(id, videoLiveStatus); - // 第一次结束,记录真实结束时间 - if (video.getRealEndTime() == null) { - realEndTime = LocalDateTime.now(); - updateVideo.setRealEndTime(realEndTime); - } - updateVideo.setOnlineTop(adminVideoInteractionService.getOnlineMax(id)); - // 插入直播观看人次 - Integer totalReadCount = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.READ, null, null, false); - updateVideo.setLiveNum(totalReadCount); - videoLiveMapper.updateById(updateVideo); - //结束直播间所有的问卷 - adminVideoQuestionService.stopByVideoId(id); - // 混流相关 - VideoLiveMix mix = videoLiveMixMapper.selectById(id); - if (mix != null && VideoMixStatus.STARTED.value.equals(mix.getStatus())) { - // 忽略混流异常 - try { - // 中断嘉宾推流 - videoCloudService.forbidLiveStream(adminVideoMixService.getStreamName(id, true)); - // 中断混流 - UpdateMixStatusQuery updateMixStatusQuery = new UpdateMixStatusQuery(); - updateMixStatusQuery.setVideoId(id); - updateMixStatusQuery.setStatus(VideoMixStatus.ENDED.value); - this.updateMixStatus(updateMixStatusQuery, null); - } catch (Exception e) { - LoggerUtil.error("控制嘉宾混流异常" + ExceptionUtils.getStackTrace(e)); - } - } - } - videoCacheService.clearVideoCache(video); - // 推送直播状态消息 - if (videoLiveStatus != null) { - videoMessageService.publishLiveStatusNotification(id, videoLiveStatus.value, realEndTime); - // 直播状态推送(pc) - VideoPcAdvisorMessageVO pcAdvisorMessageVO = new VideoPcAdvisorMessageVO(videoLiveStatus.value); - videoMessageService.publishPcAdvisorMessage(id, pcAdvisorMessageVO); - } - } - - /** - * 获取视频直播状态 - * - * @param videoId 视频ID - * @return 视频直播状态 - */ - public Integer getLiveStatus(Integer videoId) { - VideoLive video = videoCacheService.getVideoInfo(videoId); - if (video == null) { - throw new BizException(ResponseStatus.PRODUCT_NOT_EXIST); - } - LocalDateTime startTime = video.getRealStartTime() == null ? video.getStartTime() : video.getRealStartTime(); - LocalDateTime endTime = video.getRealEndTime() == null ? video.getEndTime() : video.getRealEndTime(); - if (startTime == null || endTime == null) { - return VideoLiveStatus.LIVING.value; - } - if (VideoPlayType.RECORD.value.equals(video.getPlayType())) { - return null; - } - return video.getLiveStatus(); - } - - /** - * 保存视频信息 - * - * @param query 保存视频信息的查询对象 - * @param backendUser 后端用户信息 - * @return 仅包含ID的VO对象 - */ - @Transactional(rollbackFor = {Exception.class}) - public OnlyIdVO save(SaveVideoInfoQuery query, BackendUserVO backendUser) { - Integer createUserId = backendUser.getUserId(); - if (createUserId == null) { - throw new BizException(ResponseStatus.ADVISOR_NOT_EXIST_ERROR); - } - videoCommonService.checkSensitiveWords(query.getTitle(), query.getViewPoint()); - if (CollUtil.isNotEmpty(query.getPushList())) { - for (LivePushQuery pushQuery : query.getPushList()) { - if (!AdminVideoPushService.isValidRTMP(pushQuery.getPushUrl())) { - throw new BizException(ResponseStatus.PARM_ERROR, "推送URL格式错误"); - } - } - } - VideoLive video = buildValidVideo(query, null, createUserId, backendUser.getAdvisorId()); - videoLiveMapper.insert(video); - handleRecord(query, video); - if (CollUtil.isNotEmpty(query.getTagIdList())) { - //写入关联标签 - List list = buildVideoTag(query.getTagIdList(), video.getId()); - videoLiveTagMapper.insertBatchSomeColumn(list); - } - if (IsOrNot.IS.value.equals(query.getIsCart())) { - //写入购物车 - List list = buildVideoCart(query.getCartList(), video.getId()); - videoCartMapper.insertBatchSomeColumn(list); - } - if (CollUtil.isNotEmpty(query.getPushList())) { - //写入转推信息 - List list = query.toPushPOList(video.getId()); - for (VideoLivePush push : list) { - adminVideoPushService.createLivePullStreamTask(video, push, backendUser); - } - videoLivePushMapper.insertBatchSomeColumn(list); - } - if (query.getMixQuery() != null) { - // 写入混流 - VideoLiveMix mix = query.getMixQuery().toPO(video.getId()); - videoLiveMixMapper.insert(mix); - } - List serialIds = query.getSerialIds(); - serialService.saveContentList(video.getId(), SerialType.VIDEO, serialIds); - List courseIds = query.getCourseIds(); - courseService.saveContentList(video.getId(), CourseContentType.VIDEO, courseIds); - return new OnlyIdVO(video.getId()); - } - - /** - * 保存视频信息 - * - * @param queryList 参数列表 - * @param backendUser 后台用户 - */ - @Transactional(rollbackFor = {Exception.class}) - public void batchSave(List queryList, BackendUserVO backendUser) { - for (SaveVideoInfoQuery query : queryList) { - OnlyIdVO idVO = save(query, backendUser); - //申请上架 - submit(new SubmitVideoInfoQuery(idVO.getId())); - } - } - - /** - * 更新视频信息 - * - * @param query 更新视频信息的查询对象 - * @param backendUser 后端用户信息 - */ - @Transactional(rollbackFor = {Exception.class}) - public void update(UpdateVideoInfoQuery query, BackendUserVO backendUser) { - Integer id = query.getVideoId(); - Integer loginAdvisorId = backendUser.getAdvisorId(); - VideoLive videoInDb = validateEntity(id, false); - videoCommonService.checkSensitiveWords(query.getTitle(), query.getViewPoint()); - if (CollUtil.isNotEmpty(query.getPushList())) { - for (LivePushQuery pushQuery : query.getPushList()) { - if (!AdminVideoPushService.isValidRTMP(pushQuery.getPushUrl())) { - throw new BizException(ResponseStatus.PARM_ERROR, "推送URL格式错误"); - } - } - } - VideoStatus dbStatus = VideoStatus.fromValue(videoInDb.getStatus()); - VideoStatus targetStatus = videoStatusSm.send(dbStatus, VideoStatus.EVENT_UPDATE, StateMachine.ROLE.ADVISOR); - // 管理员修改/待提交/驳回/下架直接修改 - if (VideoStatus.INIT.equals(dbStatus) || VideoStatus.REJECTED.equals(dbStatus) || VideoStatus.SOLD_OUT.equals(dbStatus) || VideoStatus.PASS.equals(dbStatus)) { - // 上架修改需要添加修改待审核 - VideoLive video = buildValidVideo(query, targetStatus.value, loginAdvisorId, backendUser.getAdvisorId()); - LambdaUpdateWrapper wrapper = Wrappers.lambdaUpdate() - .eq(VideoLive::getId, video.getId()); - if (query.getRiskLevel() == null) { - wrapper.set(VideoLive::getRiskLevel, null); - } - if (CollUtil.isEmpty(query.getAuthIds())) { - wrapper.set(VideoLive::getAuthIds, null); - } - if (StrUtil.isBlank(query.getDetail())) { - wrapper.set(VideoLive::getDetail, null); - } - videoLiveMapper.update(video, wrapper); - - // 清空老数据关联 - videoLiveLibraryMapper.resetVideoId(video.getId(), query.getFileId()); - handleRecord(query, video); - - //删除标签 - LambdaQueryWrapper deleteTagWrapper = Wrappers.lambdaQuery() - .eq(VideoLiveTag::getVideoId, id); - videoLiveTagMapper.delete(deleteTagWrapper); - if (CollUtil.isNotEmpty(query.getTagIdList())) { - //写入关联标签 - List list = buildVideoTag(query.getTagIdList(), video.getId()); - videoLiveTagMapper.insertBatchSomeColumn(list); - } - //删除购物车 - LambdaQueryWrapper deleteCartWrapper = Wrappers.lambdaQuery() - .eq(VideoCart::getVideoId, id); - videoCartMapper.delete(deleteCartWrapper); - if (IsOrNot.IS.value.equals(query.getIsCart())) { - //写入购物车 - List list = buildVideoCart(query.getCartList(), video.getId()); - videoCartMapper.insertBatchSomeColumn(list); - //消息通知 - // 推送前端所有推送产品取消 - VideoNotificationVO notificationVO = new VideoNotificationVO(VideoMessageNotifyType.CANCEL_VIDEO_CART_PUSH.value); - videoMessageService.publishNotifyMessage(id, notificationVO); - // 删除最近推送缓存 - videoCacheService.getVideoCacheMap().remove(CacheKey.VideoLiveKey.VIDEO_LIVE_RECENT_PUSH_CART + id); - } - // 删除转推 - LambdaQueryWrapper pushWrapper = Wrappers.lambdaQuery() - .eq(VideoLivePush::getVideoId, video.getId()); - List pushList = videoLivePushMapper.selectList(pushWrapper); - if (CollUtil.isNotEmpty(pushList)) { - for (VideoLivePush push : pushList) { - // 忽略异常 - try { - adminVideoPushService.deleteLivePullStreamTask(push.getTaskId(), backendUser); - } catch (Exception e) { - LoggerUtil.error("删除直播拉流任务异常:" + ExceptionUtils.getStackTrace(e)); - } - } - videoLivePushMapper.delete(pushWrapper); - } - if (CollUtil.isNotEmpty(query.getPushList())) { - //写入转推信息 - List list = query.toPushPOList(video.getId()); - for (VideoLivePush push : list) { - adminVideoPushService.createLivePullStreamTask(video, push, backendUser); - } - videoLivePushMapper.insertBatchSomeColumn(list); - } - // 删除混流 - try { - // 忽略异常 - adminVideoMixService.cancelCommonMixStream(id); - } catch (Exception e) { - LoggerUtil.error("取消通用混流异常:" + ExceptionUtils.getStackTrace(e)); - } - videoLiveMixMapper.deleteById(id); - // 写入混流 - if (query.getMixQuery() != null) { - // 写入混流 - VideoLiveMix mix = query.getMixQuery().toPO(video.getId()); - videoLiveMixMapper.insert(mix); - } - // 处理合集、课程 - List serialIds = query.getSerialIds(); - serialService.saveContentList(id, SerialType.VIDEO, serialIds); - List courseIds = query.getCourseIds(); - courseService.saveContentList(id, CourseContentType.VIDEO, courseIds); - if (VideoStatus.PASS.equals(dbStatus)) { - videoCacheService.clearVideoCache(video); - } - } else { - throw new BizException("该状态不允许修改:" + dbStatus.name); - } - if (videoInDb.getColumnId() != null && videoInDb.getColumnId() != 0) { - videoCacheService.setVideoColumnId(id, videoInDb.getColumnId()); - } - } - - /** - * 上架视频信息 - * - * @param query 提交视频信息的查询对象 - */ - @Transactional(rollbackFor = Exception.class) - public void submit(SubmitVideoInfoQuery query) { - Integer id = query.getVideoId(); - VideoLive videoInDb = validateEntity(id, false); - // 投顾未上架创建产品,并提示申请上架信息 - VideoStatus dbStatus = VideoStatus.fromValue(videoInDb.getStatus()); - VideoStatus targetStatus = videoStatusSm.send(dbStatus, VideoStatus.EVENT_SUBMIT); - VideoLive updateVideo = query.toPO(null, targetStatus.value); - videoLiveMapper.updateById(updateVideo); - } - - /** - * 撤回视频提交 - * - * @param query 提交视频信息的查询对象 - */ - @Transactional(rollbackFor = Exception.class) - public void recall(RecallVideoUpdateQuery query) { - VideoLive videoInDb = videoLiveMapper.selectById(query.getId()); - VideoLive video = new VideoLive(query.getId()); - if (VideoStatus.TO_AUDIT.value.equals(videoInDb.getStatus())) { - // 申请上架撤回 - video.setStatus(VideoStatus.INIT.value); - } else { - throw new BizException("非申请上架状态视频不能撤回!"); - } - videoLiveMapper.updateById(video); - } - - /** - * 删除视频 - * - * @param query 删除视频的查询对象 - */ - @Transactional(rollbackFor = Exception.class) - public void delete(DeleteVideoQuery query) { - List ids = query.getIds(); - if (query.getId() != null) { - ids = Collections.singletonList(query.getId()); - } - if (CollUtil.isEmpty(ids)) { - throw new BizException(ResponseStatus.PARM_ERROR); - } - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .select(VideoLive::getStatus) - .in(VideoLive::getId, ids); - List list = videoLiveMapper.selectList(wrapper); - if (list.stream().anyMatch(v -> !VideoStatus.INIT.value.equals(v.getStatus()))) { - throw new BizException(ResponseStatus.STATUS_ERROR, "视频专栏状态不正确"); - } - VideoLive entity = new VideoLive(); - entity.setStatus(VideoStatus.DELETED.value); - entity.setUpdateTime(LocalDateTime.now()); - videoLiveMapper.update(entity, wrapper); - } - - /** - * 更新视频状态 - * - * @param query 更新视频状态的查询对象 - * @param backendUser 后端用户信息 - */ - @Transactional(rollbackFor = {Exception.class}) - public void updateStatus(UpdateVideoStatusQuery query, BackendUserVO backendUser) { - Integer id = query.getId(); - Integer userId = backendUser.getUserId(); - VideoLive videoInDb = validateEntity(id, false); - VideoStatus submitStatus = VideoStatus.fromValue(query.getStatus()); - VideoStatus dbStatus = VideoStatus.fromValue(videoInDb.getStatus()); - boolean isRejected = VideoStatus.REJECTED.equals(submitStatus); - boolean isPass = VideoStatus.PASS.equals(submitStatus); - if (isRejected && StringUtils.isEmpty(query.getReason())) { - throw new BizException(ResponseStatus.PARM_ERROR, "驳回原因为空"); - } - // 当前用户不能审核/上架/下架自己的产品 - Integer createUserId = videoInDb.getCreateUserId(); - if (backendUser.getAdvisorId() != null) { - advisorInfoService.validateAdvisor(createUserId, true, backendUser); - } - // 已推荐不能下架 - videoCommonService.validateRecommend(ProductType.VIDEO_SINGLE, id, submitStatus); - VideoStatus targetStatus = videoStatusSm.send(dbStatus, submitStatus); - VideoLive video = query.toPO(null, targetStatus); - boolean isAuditPass = VideoStatus.PASS.value.equals(targetStatus.value); - boolean isSoldOut = VideoStatus.SOLD_OUT.value.equals(targetStatus.value); - boolean isAudit = VideoStatus.TO_AUDIT.equals(dbStatus); - if (isAudit && (isPass || isRejected)) { - video.setAuditUserId(userId); - video.setAuditTime(LocalDateTime.now()); - video.setReason(isRejected ? query.getReason() : StrUtil.EMPTY); - } - LocalDateTime now = LocalDateTime.now(); - if (isSoldOut) { - //下架修改直播状态和推流状态 - video.setLiveStatus(VideoLiveStatus.HAS_ENDED.value); - videoCommonService.endVideo(null, new VideoLive(id, VideoLiveStatus.HAS_ENDED.value, now)); - } - if (VideoLiveStatus.LIVING.value.equals(videoInDb.getLiveStatus())) { - video.setRealEndTime(now); - } - // 已下架 -> 上架 直播的回放过期时间设置为永久有效 - if (VideoPlayType.LIVE.value.equals(videoInDb.getPlayType()) && VideoStatus.SOLD_OUT.equals(dbStatus) && VideoStatus.PASS.equals(submitStatus)) { - video.setReplayExpireDays(0); - } - videoLiveMapper.updateById(video); - if (isPass || VideoStatus.SOLD_OUT.equals(submitStatus)) { - videoMessageService.publishVideoStatusNotification(id, submitStatus.value); - } - // 审核通过,更新专栏视频/课程视频 - if (isAuditPass || isSoldOut) { - adminVideoColumnService.updateVideo(videoInDb.getColumnId(), id, targetStatus.value); - } - videoCacheService.clearVideoCache(videoInDb); - // 修改主题和专栏 - if (isPass) { - Integer oldColumnId = videoCacheService.getVideoColumnId(id); - if (oldColumnId != null) { - videoCacheService.clearVideoColumnVideoCache(oldColumnId, null); - videoCacheService.clearVideoColumnIdCache(id); - } - } - } - - /** - * 投顾主页视频推荐 - * - * @param query 更新视频推荐的查询对象 - */ - @Transactional(rollbackFor = Exception.class) - public void recommendInAdvisor(UpdateVideoRecommendQuery query) { - Integer id = query.getId(); - Integer option = query.getOption(); - VideoLive videoInDB = validateEntity(id, true); - if (RecommendOption.RECOMMEND.value.equals(option)) { - Integer weight = query.getWeight(); - if (weight == null) { - throw new BizException(ResponseStatus.PARM_ERROR, "权重为空"); - } - VideoLive video = new VideoLive(id); - video.setWeight(weight); - videoLiveMapper.updateById(video); - } else if (RecommendOption.UN_RECOMMEND.value.equals(option)) { - videoLiveMapper.resetRecommend(id); - } - videoCacheService.clearVideoCache(videoInDB); - } - - /** - * 获取视频列表 - * - * @param query 查询视频列表的查询对象 - * @param backendUserVO 后端用户信息 - * @return 视频列表分页对象 - */ - public Pager getVideoList(ListVideoInfoQuery query, BackendUserVO backendUserVO) { - Page page = videoLiveMapper.selectExtendPage(query.toPage(), buildQuery(query, backendUserVO)); - List dbList = page.getRecords(); - if (CollUtil.isEmpty(dbList)) { - return Pager.emptyPager(); - } - List ids = dbList.stream().map(VideoLiveExtend::getId).collect(Collectors.toList()); - //视频资源信息 - LambdaQueryWrapper libraryWrapper = Wrappers.lambdaQuery().in(VideoLiveLibrary::getVideoId, ids); - List libraryList = videoLiveLibraryMapper.selectList(libraryWrapper); - Map> libraryMap = libraryList.stream().collect(Collectors.groupingBy(VideoLiveLibrary::getVideoId)); - // 购物车 - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery().in(VideoCart::getVideoId, ids); - List videoCart = videoCartMapper.selectList(wrapper); - Map> cartMap = videoCart.stream().collect(Collectors.groupingBy(VideoCart::getVideoId)); - List selfProducts = cartMap.values().stream() - .flatMap(Collection::stream) - .filter(cart -> !ProductType.CUSTOM_PRODUCT.value.equals(cart.getProductType())) - .collect(Collectors.toList()); - // 产品 - Table infoVOTable = mergeProductService.queryMergeProductInfo(selfProducts); - // 标签 - List tagList = videoLiveTagMapper.selectList(Wrappers.lambdaQuery().in(VideoLiveTag::getVideoId, ids)); - Map> videoTagMap = tagList.stream().collect(Collectors.groupingBy(VideoLiveTag::getVideoId)); - Map tagMap = tagService.getTagMap(); - // 消息 - Map msgCountMap = adminVideoInteractionService.queryVideoMessageCount(ids, VideoMessageContentType.TEXT, null); - // 分享 - Map shareCountMap = adminVideoInteractionService.queryVideoInteractionCount(ids, VideoUserRecordType.SHARE, false); - - List list = dbList.stream().map(video -> { - Integer id = video.getId(); - VideoInfoListVO vo = new VideoInfoListVO(video, advisorInfoService.getAdvisorVoMap().get(video.getAdvisorId())); - //预约人数 - vo.setSubscribeUserCount(videoCacheService.getVideoSubscribeUserCount(id)); - //购物车 - List videoCarts = cartMap.get(id); - if (CollUtil.isNotEmpty(videoCarts)) { - List cartVoList = videoCarts.stream().map(cart -> { - VideoCartVO videoCartVO; - if (cart.getProductType().equals(ProductType.CUSTOM_PRODUCT.value)) { - videoCartVO = new VideoCartVO(cart); - } else { - videoCartVO = new VideoCartVO(cart, infoVOTable.get(cart.getProductType(), cart.getProductId())); - videoCartVO.setCount(videoCacheService.getVideoCartReadCount(cart.getVideoId(), cart.getProductId(), cart.getProductType(), 0)); - } - return videoCartVO; - }).collect(Collectors.toList()); - vo.setCartVOList(cartVoList); - } - // 标签 - List liveTagList = videoTagMap.get(id); - if (CollUtil.isNotEmpty(liveTagList)) { - vo.setTagVOList(liveTagList.stream().map(tag -> tagMap.get(tag.getTagId())).collect(Collectors.toList())); - } - // 资源 - List libraries = libraryMap.get(id); - if (CollUtil.isNotEmpty(libraries)) { - VideoLiveLibrary maxLibrary = libraries.stream().max(Comparator.comparing(VideoLiveLibrary::getId)).orElse(null); - if (maxLibrary != null) { - vo.setLibraryName(maxLibrary.getName()); - vo.setTransStatus(maxLibrary.getTransStatus()); - } - vo.setDuration((long) libraries.stream().mapToInt(VideoLiveLibrary::getDuration).sum()); - List downloadStatusList = libraries.stream().map(VideoLiveLibrary::getDownloadStatus).collect(Collectors.toList()); - if (downloadStatusList.contains(VideoTransStatus.NOT_START.value)) { - // 存在未开始 则返回需要转码 - vo.setDownloadStatus(VideoTransStatus.NOT_START.value); - } else if (downloadStatusList.contains(VideoTransStatus.TRANSCODING.value)) { - // 不存在未开始,存在转码中,则返回转码中 - vo.setDownloadStatus(VideoTransStatus.TRANSCODING.value); - } else { - // 不存在未开始和转码中,那么只剩转码完成 - vo.setDownloadStatus(VideoTransStatus.HAS_TRANSCODE.value); - } - } - //观看数 - vo.setReadCount(videoCacheService.getVideoReadCount(id)); - //点赞数 - vo.setFavorUserCount(videoCacheService.getVideoFavorUserCount(id)); - //互动数 - vo.setJoinUserCount(msgCountMap.getOrDefault(id, 0) + shareCountMap.getOrDefault(id, 0)); - return vo; - }).collect(Collectors.toList()); - return new Pager<>(list, page.getTotal()); - } - - /** - * 获取视频详情 - * - * @param id 视频ID - * @return 视频详情VO对象 - */ - public VideoInfoDetailVO getVideoDetail(Integer id) { - VideoLiveExtend video = videoLiveMapper.selectExtendById(id); - if (video == null) { - return null; - } - VideoInfoDetailVO vo = new VideoInfoDetailVO(video); - // 投顾 - vo.setAdvisorBasic(advisorInfoService.getAdvisorVoMap().get(video.getAdvisorId())); - // 购物车 - LambdaQueryWrapper liveUserWrapper = Wrappers.lambdaQuery() - .eq(VideoLiveUser::getVideoId, id) - .in(VideoLiveUser::getType, VideoUserRecordType.CART.value, VideoUserRecordType.READ.value); - List videoLiveUsers = videoLiveUserMapper.selectList(liveUserWrapper); - vo.setCartVOList(adminVideoCartService.queryCartList(id, videoLiveUsers)); - // 转推 - LambdaQueryWrapper pushWrapper = Wrappers.lambdaQuery() - .eq(VideoLivePush::getVideoId, id); - List pushList = videoLivePushMapper.selectList(pushWrapper); - List pushVOList = pushList.stream().map(LivePushVO::new).collect(Collectors.toList()); -// for (LivePushVO push : pushVOList) { -// if (IsOrNot.IS.value.equals(push.getIsPush()) && StrUtil.isNotEmpty(push.getTaskId())) { -// push.setRunStatus(adminVideoPushService.describeLivePullStreamTaskStatus(push.getTaskId()).value); -// } -// } - vo.setPushList(pushVOList); - // 混流 - vo.setMixInfo(getMixDetail(id, false)); - // 标签 - List tagList = videoLiveTagMapper.selectList(Wrappers.lambdaQuery() - .eq(VideoLiveTag::getVideoId, id)); - if (CollUtil.isNotEmpty(tagList)) { - Map tagMap = tagService.getTagMap(); - List tagVOList = tagList.stream().map(tag -> tagMap.get(tag.getTagId())).collect(Collectors.toList()); - vo.setTagVOList(tagVOList); - } - // 用户数 - long newUserCount = CollUtil.isEmpty(videoLiveUsers) ? 0 : videoLiveUsers.stream().filter(item -> item.getType().equals(VideoUserRecordType.READ.value) && IsOrNot.IS.value.equals(item.getIsNew())).count(); - long oldUserCount = CollUtil.isEmpty(videoLiveUsers) ? 0 : videoLiveUsers.stream().filter(item -> item.getType().equals(VideoUserRecordType.READ.value) && IsOrNot.NOT.value.equals(item.getIsNew())).count(); - vo.setNewUserCount(newUserCount); - vo.setOldUserCount(oldUserCount); - vo.setReadCount(videoCacheService.getVideoReadCount(id)); - List libraries = videoLiveLibraryMapper.selectList(new QueryWrapper() - .eq("video_id", vo.getId()) - .orderByAsc("live_index")); - if (CollUtil.isNotEmpty(libraries)) { - List fileIds = libraries.stream().map(VideoLiveLibrary::getFileId).collect(Collectors.toList()); - vo.setFileId(String.join(",", fileIds)); - List fileNames = libraries.stream().map(VideoLiveLibrary::getFileName).collect(Collectors.toList()); - vo.setLibraryName(String.join(",", fileNames)); - Integer trans = libraries.stream().map(VideoLiveLibrary::getTransStatus).min(Integer::compareTo).orElse(1); - vo.setTransStatus(trans); - } - - //直播关联的课程和合集 - vo.setCourseVOList(getCourseVOList(id)); - vo.setSerialVOList(getSerialVOList(id)); - return vo; - } - - /** - * 根据直播id获取关联的合集 - * - * @param id 直播id - * @return 合集vo列表 - */ - private List getSerialVOList(Integer id) { - ListSerialQuery query = new ListSerialQuery(); - query.setContentId(id); - query.setContentType(SerialType.VIDEO.value); - query.setStatus(SerialStatus.AUDITED.value); - Pager page = serialService.list(query, null); - return page == null ? null : page.getList(); - } - - /** - * 根据直播id获取关联的课程 - * - * @param id 直播id - * @return 课程vo列表 - */ - private List getCourseVOList(Integer id) { - ListCourseQuery query = new ListCourseQuery(); - query.setContentId(id); - query.setContentType(CourseContentType.VIDEO.value); - query.setStatus(CourseStatus.AUDITED.value); - Pager page = courseService.list(query, null); - return page == null ? null : page.getList(); - } - - /** - * 开启消息审核 - * - * @param query 开启消息审核的查询对象 - */ - @Transactional(rollbackFor = Exception.class) - public void openMessAudit(VideoOpenMessageAuditQuery query) { - Integer videoId = query.getVideoId(); - Integer messageAudit = query.getMessageAudit(); - VideoLive videoLive = videoLiveMapper.selectById(videoId); - if (videoLive == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - Integer dbMessageAudit = videoLive.getMessageAudit(); - if (messageAudit.equals(dbMessageAudit)) { - throw new BizException(ResponseStatus.PARM_ERROR); - } - VideoLive update = query.toPO(); - videoLiveMapper.updateById(update); - videoCacheService.clearVideoInfoCache(videoId, null); - } - - /** - * 拉取播放趋势信息 - * - * @param id 视频ID - * @return 趋势信息 - */ - public List pullTrend(Integer id) { - VideoLive videoLive = videoLiveMapper.selectById(id); - PullVideoPlayInfoDataQuery query = new PullVideoPlayInfoDataQuery(); - query.setVideoId(String.valueOf(id)); - query.setStartTime(videoLive.getRealStartTime()); - query.setEndTime(videoLive.getRealEndTime()); - return videoCloudService.pullVideoPlayInfoData(query); - } - - /** - * 刷新视频直播状态 - */ - @Transactional(rollbackFor = {Exception.class}) - public void refreshLiveStatus() { - // 查询所有直播视频 - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .eq(VideoLive::getPlayType, VideoPlayType.LIVE.value) - .in(VideoLive::getStatus, VideoHelper.VALID_STATUS_LIST); - List videoList = videoLiveMapper.selectList(wrapper); - // 查询直播推流信息 - Set streamSet = videoCloudService.describeLiveStreamOnlineList(null); - - videoList.forEach(v -> { - Integer liveStatus; - // 已经暂停,忽略推流 - if (VideoLiveStatus.HAS_ENDED.value.equals(v.getLiveStatus())) { - // 已结束 - liveStatus = VideoLiveStatus.HAS_ENDED.value; - } else { - // 直播中 - liveStatus = streamSet.contains(v.getId()) ? VideoLiveStatus.LIVING.value : VideoLiveStatus.SUSPENSION.value; - } - - if (liveStatus != null) { - VideoLive video = new VideoLive(); - video.setId(v.getId()); - video.setLiveStatus(liveStatus); - videoLiveMapper.updateById(video); - videoCacheService.clearVideoCache(video); - // 直播状态推送 - videoMessageService.publishLiveStatusNotification(video.getId(), video.getLiveStatus()); - // 直播状态推送(pc) - VideoPcAdvisorMessageVO pcAdvisorMessageVO = new VideoPcAdvisorMessageVO(video.getLiveStatus()); - videoMessageService.publishPcAdvisorMessage(v.getId(), pcAdvisorMessageVO); - } - }); - } - - private VideoLive validateEntity(Integer id, boolean checkStatus) { - VideoLive videoInDb = videoLiveMapper.selectById(id); - if (videoInDb == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "视频不存在"); - } - if (checkStatus && !VideoHelper.VALID_STATUS_LIST.contains(videoInDb.getStatus())) { - throw new BizException(ResponseStatus.STATUS_ERROR, "视频未上架"); - } - return videoInDb; - } - - private QueryWrapper buildQuery(ListVideoInfoQuery query, BackendUserVO backendUserVO) { - Integer userType = query.getUserType(); - String title = query.getTitle(); - Integer status = query.getStatus(); - String createUserCmpId = query.getCreateUserCmpId(); - String createUserDeptId = query.getCreateUserDeptId(); - LocalDateTime liveTimeStart = query.getLiveTimeStart(); - LocalDateTime liveTimeEnd = query.getLiveTimeEnd(); - LocalDateTime createTimeStart = query.getCreateTimeStart(); - LocalDateTime createTimeEnd = query.getCreateTimeEnd(); - LocalDateTime auditTimeStart = query.getAuditTimeStart(); - LocalDateTime auditTimeEnd = query.getAuditTimeEnd(); - Integer playType = query.getPlayType(); - Integer liveStatus = query.getLiveStatus(); - Integer isColumn = query.getIsColumn(); - Integer tagId = query.getTagId(); - String advisorName = query.getAdvisorName(); - String deptId = query.getDeptId(); - List statusList = query.getStatusList(); - Integer courseId = query.getCourseId(); - Integer serialId = query.getSerialId(); - Integer advisorId = query.getAdvisorId(); - Integer isDisplay = query.getIsDisplay(); - Integer isGuest = query.getIsGuest(); - if (IsOrNot.IS.value.equals(isGuest) && backendUserVO.getAdvisorId() == null) { - throw new BizException(ResponseStatus.DATA_PERMISSION_ERROR, "非投顾,不能已嘉宾模式查询"); - } - Set accessibleAdvisers = authService.getAccessibleAdviserSet(backendUserVO, query.getUserType()); - List tagVideoIds = null; - if (tagId != null) { - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .eq(VideoLiveTag::getTagId, tagId); - List tagList = videoLiveTagMapper.selectList(wrapper); - tagVideoIds = tagList.stream().map(VideoLiveTag::getVideoId).collect(Collectors.toList()); - } - QueryWrapper wrapper = Wrappers.query(); - String courseSql = "select 0 from course_content cc where cc.course_id = " + courseId + " and cc.type = " + CourseContentType.VIDEO.value + " and vi.id = cc.content_id"; - String serialSql = "select 0 from serial_content sc where sc.serial_id = " + serialId + " and sc.type = " + SerialType.VIDEO.value + " and vi.id = sc.content_id"; - String guestSql = "select 0 from video_live_mix m where m.video_id = vi.id and m.guest_id = {0}"; - - wrapper.like(StringUtils.isNotEmpty(title), "vi.title", title) - .eq(playType != null && playType > 0, "vi.play_type", playType) - .eq(status != null, "vi.status", status) - .in(CollUtil.isNotEmpty(statusList), "vi.live_status", statusList) - .eq(liveStatus != null && liveStatus > 0, "vi.live_status", liveStatus) - .ge(liveTimeStart != null, "vi.start_time", liveTimeStart) - .ge(auditTimeStart != null, "vi.audit_time", auditTimeStart) - .ge(createTimeStart != null, "vi.create_time", createTimeStart) - .isNotNull(IsOrNot.IS.value.equals(isColumn), "vi.column_id") - .isNull(IsOrNot.NOT.value.equals(isColumn), "vi.column_id") - .eq(StringUtils.isNotEmpty(createUserDeptId), "ai.dept_id", createUserDeptId) - .eq(StringUtils.isNotEmpty(createUserCmpId), "ai.com_id", createUserCmpId) - .in(CollUtil.isNotEmpty(tagVideoIds), "vi.id", tagVideoIds) - .like(StrUtil.isNotBlank(advisorName), "ai.name", advisorName) - .eq(StrUtil.isNotBlank(deptId), "ai.dept_id", deptId) - .ne(!VideoUserType.ADVISOR.value.equals(userType) && !VideoUserType.TEACHING_ASSISTANT.value.equals(userType), "vi.status", VideoStatus.INIT.value) - .in(!IsOrNot.IS.value.equals(isGuest) && CollUtil.isNotEmpty(accessibleAdvisers), "vi.advisor_id", accessibleAdvisers) - .notExists(courseId != null, courseSql) - .notExists(serialId != null, serialSql) - .eq(advisorId != null, "vi.advisor_id", advisorId) - .eq(IsDisplay.YES.value.equals(isDisplay), "vi.is_display", IsDisplay.YES.value) - .and(IsDisplay.NO.value.equals(isDisplay), ew -> ew.eq("vi.is_display", IsDisplay.NO.value).or().isNull("vi.is_display")) - .ne(!VideoUserType.MANAGER_USER.value.equals(userType), "vi.status", VideoStatus.DELETED.value) - .exists(IsOrNot.IS.value.equals(isGuest) && backendUserVO.getAdvisorId() != null, guestSql, backendUserVO.getAdvisorId()) - .orderByDesc(IsOrNot.IS.value.equals(isDisplay), "vi.is_recommend", "vi.create_time") - .orderByDesc(!IsOrNot.IS.value.equals(isDisplay), "vi.create_time"); - if (liveTimeEnd != null) { - wrapper.lt("vi.end_time", liveTimeEnd.plusDays(1)); - } - if (auditTimeEnd != null) { - wrapper.lt("vi.audit_time", auditTimeEnd.plusDays(1)); - } - if (createTimeEnd != null) { - wrapper.lt("vi.create_time", createTimeEnd.plusDays(1)); - } - return wrapper; - } - - private List buildVideoCart(List cartList, Integer videoId) { - // TODO: 2024/4/18 校验产品是否存在并且上架 - return cartList.stream().map(cart -> cart.toPO(videoId)).collect(Collectors.toList()); - } - - private List buildVideoTag(List tagIdList, Integer videoId) { - return tagIdList.stream().map(id -> new VideoLiveTag(videoId, id)).collect(Collectors.toList()); - } - - private VideoLive buildValidVideo(T query, Integer status, Integer createUserId, Integer advisorId) { - VideoLive video; - Integer columnId; - if (VideoOperateType.CREATE.value.equals(query.getOptType())) { - SaveVideoInfoQuery createQuery = (SaveVideoInfoQuery) query; - video = createQuery.toPO(createUserId, advisorId); - columnId = createQuery.getColumnId(); - video.setIsSpeak(IsOrNot.IS.value); - video.setWeight(0); - } else { - //更新 - UpdateVideoInfoQuery updateQuery = (UpdateVideoInfoQuery) query; - video = updateQuery.toPO(status); - columnId = updateQuery.getColumnId(); - } - video.setMessageAudit(IsOrNot.IS.value); - // 视频:需要选择专栏 - if (columnId != null) { - VideoLiveColumn columnInDb = adminVideoColumnService.getEntity(columnId); - if (columnInDb == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "视频专栏不存在"); - } - if (!VideoHelper.VALID_STATUS_LIST.contains(columnInDb.getStatus())) { - throw new BizException(ResponseStatus.STATUS_ERROR, "视频专栏未上架"); - } - } - if (VideoPlayType.LIVE.value.equals(video.getPlayType())) { - video.setLibraryId(0); - // 直播:则需要选择是否生产回放、视频展现形式 - if (video.getIsGenerateRecord() == null) { - throw new BizException(ResponseStatus.PARM_ERROR, "请选择是否生产回放视频"); - } - if (video.getPlayStyle() == null) { - throw new BizException(ResponseStatus.PARM_ERROR, "请选择视频展现形式"); - } - } - // 检查直播时间 - validateLiveTime(video.getStartTime(), video.getEndTime(), video.getPlayType()); - return video; - } - - private void validateLiveTime(LocalDateTime startTime, LocalDateTime endTime, Integer playType) { - if (startTime == null || endTime == null) { - if (VideoPlayType.LIVE.value.equals(playType)) { - throw new BizException(ResponseStatus.PARM_ERROR, "直播时间不能为空"); - } - return; - } - if (!startTime.toLocalDate().isEqual(endTime.toLocalDate())) { - throw new BizException(ResponseStatus.PARM_ERROR, "开始时间和结束时间必须为同一天"); - } - if (startTime.isAfter(endTime) || startTime.isEqual(endTime)) { - throw new BizException(ResponseStatus.PARM_ERROR, "结束时间不能早于或等于开始时间"); - } - } - - @Transactional(rollbackFor = Exception.class) - public void updateInteractType(VideoUdateInteractTypeQuery query) { - Integer videoId = query.getVideoId(); - VideoLive dbVideoLive = videoLiveMapper.selectById(videoId); - if (dbVideoLive == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - VideoLive videoLive = query.toUpdatePO(); - videoLiveMapper.updateById(videoLive); - videoCacheService.clearVideoCache(dbVideoLive); - } - - @Transactional(rollbackFor = Exception.class) - public void setMainPageParam(SetMainPageQuery query) { - VideoLive videoLive = query.toVideoLivePO(); - videoLiveMapper.updateById(videoLive); - VideoLive videoInDB = videoLiveMapper.selectById(videoLive.getId()); - videoCacheService.clearVideoCache(videoInDB); - } - - @Transactional(rollbackFor = Exception.class) - public void updateQWParam(VideoSwitchQuery query) { - Integer videoId = query.getVideoId(); - VideoLive videoLive = query.toQwPO(); - videoLiveMapper.updateById(videoLive); - videoCacheService.clearVideoCache(videoLive); - //消息通知 - videoMessageService.publishNotifyMessage(videoId, new VideoNotificationVO(VideoMessageNotifyType.SWITCH_QW.value, query.getIsOpen())); - } - - @Transactional(rollbackFor = Exception.class) - public void showNickname(VideoSwitchQuery query) { - Integer videoId = query.getVideoId(); - VideoLive videoLive = query.toNicknamePO(); - videoLiveMapper.updateById(videoLive); - videoCacheService.clearVideoCache(videoLive); - //消息通知 - videoMessageService.publishNotifyMessage(videoId, new VideoNotificationVO(VideoMessageNotifyType.SHOW_NICKNAME.value, query.getIsOpen())); - } - - @Transactional(rollbackFor = Exception.class) - public void deletePush(OnlyIdQuery query, BackendUserVO backendUserVO) { - VideoLivePush push = videoLivePushMapper.selectById(query.getId()); - if (push == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - VideoLive video = videoLiveMapper.selectById(push.getVideoId()); - if (video == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "直播不存在"); - } - if (VideoLiveStatus.LIVING.value.equals(video.getLiveStatus())) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "直播时无法删除转推任务"); - } - adminVideoPushService.deleteLivePullStreamTask(push.getTaskId(), backendUserVO); - videoLivePushMapper.deleteById(query.getId()); - } - - @Transactional(rollbackFor = Exception.class) - public LivePushVO savePush(LivePushQuery query, BackendUserVO backendUserVO) { - if (!AdminVideoPushService.isValidRTMP(query.getPushUrl())) { - throw new BizException(ResponseStatus.PARM_ERROR, "推送URL格式错误"); - } - if (query.getId() == null) { - // 新增 - if (query.getVideoId() == null) { - throw new BizException(ResponseStatus.PARM_ERROR, "视频ID为空"); - } - VideoLive video = videoLiveMapper.selectById(query.getVideoId()); - if (video == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "直播不存在"); - } - if (VideoLiveStatus.LIVING.value.equals(video.getLiveStatus())) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "直播时无法创建转推任务"); - } - VideoLivePush insertPush = query.toInsertPO(video.getId()); - adminVideoPushService.createLivePullStreamTask(video, insertPush, backendUserVO); - videoLivePushMapper.insert(insertPush); - return new LivePushVO(insertPush); - } else { - // 编辑 - VideoLivePush push = videoLivePushMapper.selectById(query.getId()); - if (push == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - VideoLive video = videoLiveMapper.selectById(push.getVideoId()); - if (video == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "直播不存在"); - } - VideoLivePush updatePush = query.toUpdatePO(push.getTaskId()); - adminVideoPushService.modifyLivePullStreamTask(video, updatePush, backendUserVO); - videoLivePushMapper.updateById(updatePush); - updatePush.setVideoId(push.getVideoId()); - return new LivePushVO(updatePush); - } - } - - public LivePushVO getLastPush(Integer advisorId) { - QueryWrapper wrapper = Wrappers.query() - .exists("select 1 from video_live where video_live.id = video_live_push.video_id and video_live.advisor_id = {0}", advisorId) - .eq("is_push", IsOrNot.IS.value) - .orderByDesc("id") - .last("limit 1"); - VideoLivePush push = videoLivePushMapper.selectOne(wrapper); - if (push == null) { - return null; - } - return new LivePushVO(push); - } - - private void handleRecord(SaveVideoInfoQuery query, VideoLive video) { - if (Objects.equals(VideoPlayType.RECORD.value, query.getPlayType())) { - // 录播 - VideoLiveLibrary videoLiveLibrary = videoLiveLibraryMapper.selectOne(new QueryWrapper() - .eq("file_id", query.getFileId()) - .last("limit 1")); - // 检测短视频回调情况 - boolean hasTrans = shortVideoService.checkShortVideoHasTrans(query.getFileId()); - if (videoLiveLibrary == null) { - // 腾讯云尚未回调本系统 - // 未转码完成 - List list = videoCloudService.describeMediaInfos(Sets.newHashSet(query.getFileId())); - list.forEach(ce -> { - // 新增直播录制视频资源 - VideoLiveLibrary library = new VideoLiveLibrary(); - library.setType(VideoPlayType.RECORD.value); - library.setVideoId(video.getId()); - library.setName(video.getTitle()); - library.setFileId(query.getFileId()); - library.setFileName(ce.getName()); - library.setDuration(ce.getDuration().intValue()); - library.setSize(ce.getSize()); - library.setLiveIndex(1); - library.setTransStatus(hasTrans ? VideoTransStatus.HAS_TRANSCODE.value : VideoTransStatus.TRANSCODING.value); - library.setAdvisorId(video.getCreateUserId()); - library.setCreateUserId(video.getCreateUserId()); - library.setCreateTime(LocalDateTime.now()); - videoLiveLibraryMapper.insert(library); - }); - } else { - // 腾讯云已经回调本系统 - // 转码完成videoLiveLibrary - videoLiveLibrary.setVideoId(video.getId()); - videoLiveLibrary.setType(VideoPlayType.RECORD.value); - videoLiveLibrary.setVideoId(video.getId()); - videoLiveLibrary.setName(video.getTitle()); - videoLiveLibrary.setAdvisorId(video.getAdvisorId()); - videoLiveLibrary.setCreateUserId(video.getCreateUserId()); - videoLiveLibrary.setCreateTime(LocalDateTime.now()); - videoLiveLibraryMapper.updateById(videoLiveLibrary); - } - } - } - - public void refreshTranscodeStatus(Set fileIds) { - try { - if (CollUtil.isEmpty(fileIds)) { - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .select(VideoLiveLibrary::getFileId) - .eq(VideoLiveLibrary::getTransStatus, TransStatus.TRANSCODING.value) - .isNotNull(VideoLiveLibrary::getFileId); - List transcodingVideoList = videoLiveLibraryMapper.selectList(wrapper); - fileIds = transcodingVideoList.stream().map(VideoLiveLibrary::getFileId).collect(Collectors.toSet()); - } - if (CollUtil.isEmpty(fileIds)) { - return; - } - List list = videoCloudService.describeMediaInfos(fileIds); - for (CloudMediaEntity media : list) { - try { - if (Objects.equals(media.getTransStatus(), VideoTransStatus.HAS_TRANSCODE.value)) { - LambdaQueryWrapper updateWrapper = Wrappers.lambdaQuery() - .eq(VideoLiveLibrary::getFileId, media.getFileId()); - videoLiveLibraryMapper.update(media.toVideoLibraryPO(), updateWrapper); - } - } catch (Exception ex) { - LoggerUtil.error("更新视频资源失败:" + ExceptionUtils.getStackTrace(ex)); - } - } - } catch (BizException e) { - String targets = fileIds == null ? "" : String.join(",", fileIds); - LoggerUtil.error("查询云点播失败|" + targets + "|" + e.getErrorMsg()); - throw e; - } - } - - public void saveMix(SaveLiveMixQuery query, BackendUserVO backendUserVO) { - VideoLive video = videoLiveMapper.selectById(query.getVideoId()); - if (video == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - VideoLiveMix mix = videoLiveMixMapper.selectById(query.getVideoId()); - if (mix != null) { - throw new BizException(ResponseStatus.PARM_ERROR, "混流信息已存在"); - } - mix = query.toPO(); - videoLiveMixMapper.insert(mix); - } - - public LiveMixVO getMixDetail(Integer id, boolean queryStreamStatus) { - // 混流 - VideoLiveMix mix = videoLiveMixMapper.selectById(id); - if (mix == null) { - return null; - } - AdvisorBasicVO guest = null; - if (mix.getGuestId() != null) { - guest = advisorInfoService.getAdvisorVoMap().get(mix.getGuestId()); - } - LiveMixVO vo = new LiveMixVO(mix, guest); - if (queryStreamStatus) { - vo.setStreamStatus(adminVideoMixService.describeLiveStreamState(id, true)); - } - return vo; - } - - @Transactional - public void updateShowMain(UpdateShowMainQuery query) { - Integer videoId = query.getVideoId(); - VideoLiveMix mix = query.toPO(); - int rows = videoLiveMixMapper.updateById(mix); - if (rows == 0) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - mix = videoLiveMixMapper.selectById(videoId); - if (mix == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - // 调整主画面显示需要取消并重建混流 - if (VideoMixStatus.STARTED.value.equals(mix.getStatus())) { - - try { - // 忽略异常 - adminVideoMixService.cancelCommonMixStream(videoId); - } catch (Exception e) { - LoggerUtil.error("取消通用混流异常:" + ExceptionUtils.getStackTrace(e)); - } - adminVideoMixService.createCommonMixStream(mix); - } - } - - @Transactional - public void updateMixStatus(UpdateMixStatusQuery query, BackendUserVO backendUserVO) { - Integer videoId = query.getVideoId(); - Integer status = query.getStatus(); - VideoLiveMix mix = videoLiveMixMapper.selectById(videoId); - if (mix == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - if (VideoMixStatus.REMOVED.value.equals(status)) { - try { - adminVideoMixService.cancelCommonMixStream(videoId); - } catch (Exception e) { - LoggerUtil.error("取消通用混流异常,混流可能未创建"); - } - videoLiveMixMapper.deleteById(videoId); - } - if (VideoMixStatus.STARTED.value.equals(status) && !VideoMixStatus.NOT_START.value.equals(mix.getStatus()) && !VideoMixStatus.ENDED.value.equals(mix.getStatus())) { - throw new BizException(ResponseStatus.STATUS_ERROR, "禁止开始,前置状态为:" + mix.getStatus()); - } - if (VideoMixStatus.ENDED.value.equals(status) && !VideoMixStatus.STARTED.value.equals(mix.getStatus())) { - throw new BizException(ResponseStatus.STATUS_ERROR, "禁止结束,前置状态为:" + mix.getStatus()); - } - if (VideoMixStatus.STARTED.value.equals(status)) { - String advisorStreamStatus = adminVideoMixService.describeLiveStreamState(videoId, false); - if (!"active".equals(advisorStreamStatus)) { - throw new BizException(ResponseStatus.STATUS_ERROR, "投顾推流状态为:" + advisorStreamStatus); - } - String guestStreamStatus = adminVideoMixService.describeLiveStreamState(videoId, true); - if (!"active".equals(guestStreamStatus)) { - throw new BizException(ResponseStatus.STATUS_ERROR, "嘉宾推流状态为:" + guestStreamStatus); - } - adminVideoMixService.createCommonMixStream(mix); - } else if (VideoMixStatus.ENDED.value.equals(status)) { - try { - // 忽略异常 - adminVideoMixService.cancelCommonMixStream(videoId); - } catch (Exception e) { - LoggerUtil.error("取消通用混流异常:" + ExceptionUtils.getStackTrace(e)); - } - } - VideoLiveMix updateMix = query.toPO(); - videoLiveMixMapper.updateById(updateMix); - } - - public String getGuestPushUrl(Integer id, BackendUserVO backendUserVO) { - VideoLive video = videoLiveMapper.selectById(id); - if (video == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - VideoLiveMix mix = videoLiveMixMapper.selectById(id); - if (backendUserVO.getAdvisorId() == null || !backendUserVO.getAdvisorId().equals(mix.getGuestId())) { - throw new BizException(ResponseStatus.DATA_PERMISSION_ERROR, "非投顾或者嘉宾不匹配"); - } - String streamName = adminVideoMixService.getStreamName(id, true); - return videoCloudService.getPushUrl(streamName); - } - -} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/service/admin/AdminVideoLibraryService.java~ b/src/main/java/com/upchina/video/service/admin/AdminVideoLibraryService.java~ deleted file mode 100644 index 6c7fb5b..0000000 --- a/src/main/java/com/upchina/video/service/admin/AdminVideoLibraryService.java~ +++ /dev/null @@ -1,114 +0,0 @@ -package com.upchina.video.service.admin; - -import cn.hutool.core.collection.CollUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.toolkit.Wrappers; -import cn.hutool.core.util.StrUtil; -import com.upchina.common.handler.BizException; -import com.upchina.common.result.ResponseStatus; -import com.upchina.video.constant.VideoTransStatus; -import com.upchina.video.entity.VideoLiveLibrary; -import com.upchina.video.mapper.VideoLiveLibraryMapper; -import com.upchina.video.service.common.VideoCloudService; -import com.upchina.video.vo.cloud.TaskDetailVO; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.annotation.Resource; -import java.util.*; -import java.util.stream.Collectors; - -// admin资源Service -@Service -public class AdminVideoLibraryService { - - @Resource - private VideoLiveLibraryMapper videoLibraryMapper; - - @Resource - private VideoCloudService videoCloudService; - - /** - * 根据视频ID集合查询视频资源映射 - * - * @param videoIds 视频ID集合 - * @return 视频资源映射 - */ - public Map selectLibraryMap(Collection videoIds) { - if (CollUtil.isEmpty(videoIds)) { - return Collections.emptyMap(); - } - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery().in(VideoLiveLibrary::getVideoId, videoIds); - List libraryList = videoLibraryMapper.selectList(wrapper); - return libraryList.stream() - .collect(Collectors.groupingBy( - VideoLiveLibrary::getVideoId, - Collectors.summingInt(VideoLiveLibrary::getDuration) - )); - } - - /** - * 处理视频转码 - * - * @param videoId 视频ID - */ - @Transactional(rollbackFor = Exception.class) - public List processVideo(Integer videoId) { - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .eq(VideoLiveLibrary::getVideoId, videoId); - List libraryList = videoLibraryMapper.selectList(wrapper); - if (CollUtil.isEmpty(libraryList)) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "该视频直播没有需要下载转码的视频"); - } - // 查该视频直播所有未转码下载链接的视屏 - List libraries = libraryList.stream().filter(l -> VideoTransStatus.NOT_START.value.equals(l.getDownloadStatus())).collect(Collectors.toList()); - libraries.forEach(library -> { - String taskId = videoCloudService.ProcessMediaByProcedure(library.getFileId()); - if (StringUtils.isNotEmpty(taskId)) { - LambdaQueryWrapper w = Wrappers.lambdaQuery() - .eq(VideoLiveLibrary::getVideoId, videoId) - .eq(VideoLiveLibrary::getFileId, library.getFileId()); - videoLibraryMapper.updateTask(taskId, w); - } - }); - return libraryList.stream().map(l -> { - Integer downloadStatus = l.getDownloadStatus(); - if (VideoTransStatus.HAS_TRANSCODE.value.equals(downloadStatus)) { - return new TaskDetailVO(l.getFileId(), 100L); - } else { - return new TaskDetailVO(l.getFileId(), 0L); - } - }).sorted(Comparator.comparing(TaskDetailVO::getFileId)).collect(Collectors.toList()); - } - - /** - * 下载转码视频 - * - * @param videoId 视频ID - * @return 视频地址 - */ - public List download(Integer videoId) { - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .eq(VideoLiveLibrary::getVideoId, videoId); - List libraries = videoLibraryMapper.selectList(wrapper); - if (CollUtil.isEmpty(libraries)) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "该直播暂无录播"); - } - String[] fileIds = libraries.stream().map(VideoLiveLibrary::getFileId).toArray(String[]::new); - return videoCloudService.buildDownloadUrl(fileIds); - } - - /** - * 查询转码视频进度 - * - * @param videoId 视频ID - * @return 任务详情 - */ - public List searchTasksDetail(Integer videoId) { - // 查所有视频记录 - List libraryList = videoLibraryMapper.selectList(Wrappers.lambdaQuery() - .eq(VideoLiveLibrary::getVideoId, videoId)); - return videoCloudService.searchTasksDetail(libraryList); - } - -} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/service/admin/AdminVideoStatisticService.java~ b/src/main/java/com/upchina/video/service/admin/AdminVideoStatisticService.java~ deleted file mode 100644 index ab256fc..0000000 --- a/src/main/java/com/upchina/video/service/admin/AdminVideoStatisticService.java~ +++ /dev/null @@ -1,1163 +0,0 @@ -package com.upchina.video.service.admin; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.toolkit.Wrappers; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.upchina.advisor.entity.AdvisorBasic; -import com.upchina.advisor.service.AdvisorInfoService; -import com.upchina.app.service.CouponService; -import com.upchina.app.service.OrderQueryService; -import com.upchina.app.vo.OrderStatCollect; -import com.upchina.common.config.cache.CacheKey; -import com.upchina.common.constant.IsOrNot; -import com.upchina.common.constant.ProductType; -import com.upchina.common.constant.UserType; -import com.upchina.common.handler.BizException; -import com.upchina.common.result.Pager; -import com.upchina.common.result.ResponseStatus; -import com.upchina.common.service.CacheService; -import com.upchina.common.vo.BackendUserVO; -import com.upchina.crm.service.ProductService; -import com.upchina.rbac.entity.Dept; -import com.upchina.rbac.entity.UserDept; -import com.upchina.rbac.service.AuthService; -import com.upchina.rbac.service.DeptService; -import com.upchina.rbac.service.UserService; -import com.upchina.video.constant.*; -import com.upchina.video.entity.*; -import com.upchina.video.helper.VideoHelper; -import com.upchina.video.mapper.VideoLiveMapper; -import com.upchina.video.mapper.VideoUserFlowMapper; -import com.upchina.video.query.statistic.*; -import com.upchina.video.schedule.CollectTask; -import com.upchina.video.service.common.VideoCacheService; -import com.upchina.video.service.common.VideoCloudService; -import com.upchina.video.vo.statistic.*; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -import javax.annotation.Resource; -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.time.Duration; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.*; -import java.util.function.BiFunction; -import java.util.function.Function; -import java.util.stream.Collectors; - -// admin统计Service -@Service -public class AdminVideoStatisticService { - - @Resource - private VideoLiveMapper videoLiveMapper; - - @Resource - private AdvisorInfoService advisorInfoService; - - @Resource - private DeptService deptService; - - @Resource - private UserService userService; - - @Resource - private ProductService productService; - - @Resource - private VideoCacheService videoCacheService; - - @Resource - private VideoUserFlowMapper videoUserFlowMapper; - - @Resource - private AuthService authService; - - @Resource - private CacheService cacheService; - - @Resource - private OrderQueryService orderQueryService; - - @Resource - private CouponService couponService; - - @Resource - private AdminVideoCustomerService adminVideoCustomerService; - - @Resource - private AdminVideoInteractionService adminVideoInteractionService; - - @Resource - private VideoCloudService videoCloudService; - - @Value("${video.finishReadRatio}") - private Double finishReadRatio; - - - /** - * 单场分析 - * - * @param id 视频ID - * @param userType 用户类型 - * @param backendUserVO 后台用户信息 - * @return 视频统计信息 - */ - public VideoStatisticVO statistic(Integer id, Integer userType, BackendUserVO backendUserVO) { - VideoLive video = videoLiveMapper.selectById(id); - VideoLiveLibrary library = videoCacheService.getVideoLibrary(id, null); - OrderStatCollect orderCollect = orderQueryService.queryOrderCollect(id, ProductType.VIDEO_SINGLE); - - VideoStatisticVO vo = new VideoStatisticVO(); - vo.setVideoSaleAmount(orderCollect.getPayAmount()); - vo.setVideoSaleCount(orderCollect.getPayCount()); - vo.setVideoOrderAmount(orderCollect.getOrderAmount()); - vo.setVideoOrderCount(orderCollect.getCount()); - - Integer saleUserId = UserType.NOT_ADVISOR.value.equals(userType) ? backendUserVO.getUserId() : null; - Set userIds = saleUserId == null ? Collections.emptySet() : adminVideoCustomerService.getSaleCustomerIdSet(id, saleUserId); - if (saleUserId != null && CollUtil.isEmpty(userIds)) { - return vo; - } - - // 点击产品数 - Integer productClickCount = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.CART, saleUserId, null, false); - vo.setProductClickCount(productClickCount); - - // 直播观看人次 - int readNumDB = video.getLiveNum() == null ? 0 : video.getLiveNum(); - int preNum = video.getPreNum() == null ? 0 : video.getPreNum(); - if (video.getRealStartTime() == null) { - vo.setReadCount(0); - } else { - if (video.getRealEndTime() == null) { - Integer readCount = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.READ, null, null, true); - vo.setReadCount(readCount - preNum); - } else { - vo.setReadCount(readNumDB - preNum); - } - } - // 完播率 - if (UserType.NOT_ADVISOR.value.equals(userType) && CollUtil.isEmpty(userIds)) { - vo.setCompleteRate(BigDecimal.ZERO); - } else { - Map readMap = adminVideoInteractionService.calcuVideoReadMap(id, userIds, null, null); - int duration = library == null ? 0 : library.getDuration(); - if (CollUtil.isNotEmpty(readMap) && duration > 0) { - duration = BigDecimal.valueOf(duration).multiply(BigDecimal.valueOf(finishReadRatio)).intValue(); - int finalDuration = duration; - long finishReadCount = readMap.values().stream() - .filter(t -> BigDecimal.valueOf(t).multiply(BigDecimal.valueOf(60)).compareTo(BigDecimal.valueOf(finalDuration)) >= 0) - .count(); - long totalReadCount = readMap.size(); - BigDecimal completeRate = totalReadCount > 0 ? BigDecimal.valueOf(finishReadCount).divide(BigDecimal.valueOf(totalReadCount), 6, RoundingMode.HALF_UP) : BigDecimal.ZERO; - vo.setCompleteRate(completeRate); - } else { - vo.setCompleteRate(BigDecimal.ZERO); - } - } - // 转粉率 - Integer newFollowCount = adminVideoInteractionService.queryNewFollowCount(video); - BigDecimal likeRate = vo.getReadCount() > 0 ? BigDecimal.valueOf(newFollowCount).divide(BigDecimal.valueOf(vo.getReadCount()), 6, RoundingMode.HALF_UP) : BigDecimal.ZERO; - vo.setLikeRate(likeRate); - // 签约转化率 邀约人数 领券人数 - Integer inviteCount = userIds.size(); - Integer couponNum = couponService.queryCouponCount(id); - vo.setInvitePeopleCount(inviteCount); - vo.setHasGotCouponPeopleNum(couponNum); - if (CollUtil.isNotEmpty(userIds) && orderCollect.getPayCount() != null) { - vo.setSubTransRate(BigDecimal.valueOf(orderCollect.getPayCount()).divide(BigDecimal.valueOf(userIds.size()), 6, RoundingMode.HALF_UP)); - } else { - vo.setSubTransRate(BigDecimal.ZERO); - } - // 评论数 - if (UserType.NOT_ADVISOR.value.equals(userType) && CollUtil.isEmpty(userIds)) { - vo.setMsgCount(0); - } else { - Integer msgCount = adminVideoInteractionService.queryMessageCount(id, VideoMessageContentType.TEXT, userIds); - vo.setMsgCount(msgCount); - } - // 分享数 - if (UserType.NOT_ADVISOR.value.equals(userType) && CollUtil.isEmpty(userIds)) { - vo.setShareCount(0); - } else { - Integer shareCount = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.SHARE, null, userIds, false); - vo.setShareCount(shareCount); - } - // 点赞数 - if (UserType.NOT_ADVISOR.value.equals(userType) && CollUtil.isEmpty(userIds)) { - vo.setFavorCount(0); - vo.setFavorPeopleCount(0); - } else { - // 点赞人数 - Integer favorPeopleCount = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.FAVOR, saleUserId, userIds, false); - vo.setFavorPeopleCount(favorPeopleCount); - // 点赞数 - Integer favorCount = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.FAVOR, saleUserId, userIds, true); - vo.setFavorCount(favorCount); - } - // 互动率 - if (UserType.NOT_ADVISOR.value.equals(userType) && CollUtil.isEmpty(userIds)) { - vo.setMsgRate(BigDecimal.ZERO); - } else { - Integer msgCount = adminVideoInteractionService.queryMessageCount(id, VideoMessageContentType.TEXT, userIds); - Integer shareCount = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.SHARE, null, userIds, false); - BigDecimal msgRate = vo.getReadCount() > 0 ? BigDecimal.valueOf(msgCount + shareCount + vo.getFavorPeopleCount()).divide(BigDecimal.valueOf(vo.getReadCount()), 6, RoundingMode.HALF_UP) : BigDecimal.ZERO; - vo.setMsgRate(msgRate); - } - // 预约人数 - Integer subscribeCount = adminVideoInteractionService.queryInteractionCount(id, VideoUserRecordType.SUBSCRIBE, null, null, true); - vo.setSubscribeCount(subscribeCount); - return vo; - } - - /** - * 统计视频直播的运营数据 - * - * @param query 视频操作统计查询条件 - * @param backendUserVO 后台用户信息 - * @return 视频操作统计信息 - */ - public VideoOperationStatisticVO operationStatistic(VideoOperationStatisticQuery query, BackendUserVO backendUserVO) { - Integer searchType = query.getSearchType(); - Integer advisorId = query.getAdvisorId(); - LocalDateTime startTime = query.getStartTime(); - LocalDateTime endTime = query.getEndTime(); - Integer userType = query.getUserType(); - - Set authSet = authService.getAuthByUserType(VideoUserType.format(userType), backendUserVO, true); - if (authSet != null && authSet.isEmpty()) { - return null; - } - - //直播数 直播时长 - List videoLiveList = getVideoLives(authSet, advisorId, startTime, endTime); - if (CollUtil.isEmpty(videoLiveList)) { - return null; - } - Set videoIds = videoLiveList.stream().map(VideoLive::getId).collect(Collectors.toSet()); - - // 观看人次 - Map watchCountMap = adminVideoInteractionService.queryVideoInteractionCount(videoIds, VideoUserRecordType.READ, true); - // 点击产品数 - Map cartCountMap = adminVideoInteractionService.queryVideoInteractionCount(videoIds, VideoUserRecordType.CART, false); - - // 观看时长、观看人数 - AdminVideoInteractionService.WatchResultVO watchResult = adminVideoInteractionService.calWatchUserCountAndTime(videoIds); - Map watchTimeMap = watchResult.watchTimeMap; - Map watchUserMap = watchResult.watchUserMap; - - // 人均观看时长 - Map avgWatchTimeMap = adminVideoInteractionService.queryAvgWatchTime(videoIds); - // 完播人数 - Map finishUserMap = adminVideoInteractionService.queryFinishUserCount(videoIds); - // 总完播率 - int totalWatchUser = watchUserMap.values().stream().mapToInt(Integer::intValue).sum(); - int totalFinishUser = finishUserMap.values().stream().mapToInt(Integer::intValue).sum(); - BigDecimal totalFinishRate = totalWatchUser == 0 || totalFinishUser == 0 ? BigDecimal.ZERO : - BigDecimal.valueOf(totalFinishUser).divide(BigDecimal.valueOf(totalWatchUser), 4, RoundingMode.HALF_UP); - - //参与互动人数 - Map interactionMap = adminVideoInteractionService.queryAllInteractionUserCount(videoIds); - - //处理时间 - videoLiveList.forEach(item -> item.setStartTime(item.getRealStartTime().toLocalDate().atStartOfDay())); - Map> videoMap = videoLiveList.stream().collect(Collectors.groupingBy(v -> v.getStartTime().toLocalDate(), TreeMap::new, Collectors.toList())); - - Map videoCountMap = new TreeMap<>(); - Map videoHourMap = new TreeMap<>(); - Map readUserCountMap = new TreeMap<>(); - Map readCountMap = new TreeMap<>(); - Map readHoursMap = new TreeMap<>(); - Map avgReadHoursMap = new TreeMap<>(); - Map joinUserCountMap = new TreeMap<>(); - Map browseProCountMap = new TreeMap<>(); - Map finishReadRateMap = new TreeMap<>(); - - //数据处理到每一天 - videoMap.forEach((time, liveList) -> { - List ids = liveList.stream().map(VideoLive::getId).collect(Collectors.toList()); - //直播数 - videoCountMap.put(time, liveList.size()); - //直播时长 - videoHourMap.put(time, getVideoTime(liveList)); - //观看人数 - int watchUserCount = ids.stream().mapToInt(id -> watchUserMap.getOrDefault(id, 0)).sum(); - readUserCountMap.put(time, watchUserCount); - //观看人次 - readCountMap.put(time, ids.stream().mapToInt(id -> watchCountMap.getOrDefault(id, 0)).sum()); - //观看时长 - readHoursMap.put(time, ids.stream().mapToInt(id -> watchTimeMap.getOrDefault(id, 0)).sum()); - //人均观看时长 - avgReadHoursMap.put(time, ids.stream().mapToInt(id -> avgWatchTimeMap.getOrDefault(id, 0)).sum()); - // 完播用户数 - int finishWatchUserCount = ids.stream().mapToInt(id -> finishUserMap.getOrDefault(id, 0)).sum(); - // 完播率 - BigDecimal finishRate = finishWatchUserCount == 0 || watchUserCount == 0 ? BigDecimal.ZERO : - BigDecimal.valueOf(finishWatchUserCount).divide(BigDecimal.valueOf(watchUserCount), 4, RoundingMode.HALF_UP); - finishReadRateMap.put(time, finishRate); - //参与互动人数 (点赞、分享、普通消息) - joinUserCountMap.put(time, ids.stream().mapToInt(id -> interactionMap.getOrDefault(id, 0)).sum()); - //点击产品数 - browseProCountMap.put(time, ids.stream().mapToInt(id -> cartCountMap.getOrDefault(id, 0)).sum()); - }); - VideoOperationStatisticVO vo = new VideoOperationStatisticVO(); - if (VideoSearchTimeUnitType.WEEK.value.equals(searchType) || VideoSearchTimeUnitType.MONTH.value.equals(searchType)) { - vo = new VideoOperationStatisticVO(videoCountMap, videoHourMap, readUserCountMap, readCountMap, readHoursMap, avgReadHoursMap, finishReadRateMap, joinUserCountMap, browseProCountMap); - } else if (VideoSearchTimeUnitType.YEAR.value.equals(searchType)) { - vo = new VideoOperationStatisticVO(getMapByInteger(videoCountMap), getMapByInteger(videoHourMap), getMapByInteger(readUserCountMap), getMapByInteger(readCountMap), - getMapByInteger(readHoursMap), getMapByInteger(avgReadHoursMap), getMapByDecimal(finishReadRateMap), getMapByInteger(joinUserCountMap), - getMapByInteger(browseProCountMap)); - } - - OrderQueryService.CycleFormat format = searchType.equals(VideoSearchTimeUnitType.YEAR.value) ? OrderQueryService.CycleFormat.MONTH : OrderQueryService.CycleFormat.DAY; - - Map cycleOrderCollectMap = orderQueryService.queryCycleOrderCollect(ProductType.VIDEO_SINGLE, videoIds, format); - Map orderButNotPayCountMap = new TreeMap<>(); - Map orderCountMap = new TreeMap<>(); - Map orderAmountMap = new TreeMap<>(); - if (CollUtil.isNotEmpty(cycleOrderCollectMap)) { - cycleOrderCollectMap.forEach((key, value) -> { - orderButNotPayCountMap.put(key, value.getUnPayCount()); - orderCountMap.put(key, value.getPayCount()); - orderAmountMap.put(key, value.getPayAmount()); - }); - } - vo.setOrderButNotPayCountMap(orderButNotPayCountMap); - vo.setOrderCountMap(orderCountMap); - vo.setOrderAmountMap(orderAmountMap); - vo.setTotalFinishRate(totalFinishRate); - return vo; - } - - /** - * 统计视频直播营销漏斗数据 - * - * @param query 视频漏斗统计查询条件 - * @param backendUserVO 后台用户信息 - * @return 视频漏斗统计信息 - */ - public VideoFunnelStatisticVO operationFunnelStatistic(VideoFunnelStatisticQuery query, BackendUserVO backendUserVO) { - Integer userType = query.getUserType(); - Integer type = query.getType(); - Integer videoId = query.getVideoId(); - Integer advisorId = query.getAdvisorId(); - LocalDateTime startTime = query.getStartTime(); - LocalDateTime endTime = query.getEndTime(); - Set authSet = authService.getAuthByUserType(VideoUserType.format(userType), backendUserVO, true); - - if (authSet != null && authSet.isEmpty()) { - return null; - } - - VideoFunnelStatisticVO videoFunnelStatisticVO = new VideoFunnelStatisticVO(); - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .eq(VideoDataType.ADVISOR.value.equals(type), VideoLive::getAdvisorId, advisorId) - .eq(VideoDataType.VIDEO.value.equals(type), VideoLive::getId, videoId) - .in(CollUtil.isNotEmpty(authSet) && videoId == null, VideoLive::getAdvisorId, authSet) - .eq(VideoLive::getStatus, VideoStatus.PASS.value) - .eq(VideoLive::getIsCart, IsOrNot.IS.value) - .between(startTime != null && endTime != null, VideoLive::getRealStartTime, startTime, endTime); - List videoLiveList = videoLiveMapper.selectList(wrapper); - if (CollUtil.isEmpty(videoLiveList)) { - return new VideoFunnelStatisticVO(); - } - - Set videoIds = videoLiveList.stream().map(VideoLive::getId).collect(Collectors.toSet()); - - // 观看人数 - Integer totalReadUserCount = adminVideoInteractionService.queryWatchUserCount(videoIds); - videoFunnelStatisticVO.setTotalReadUserCount(totalReadUserCount); - - // 点击产品数 - Integer totalReadCartUserCount = adminVideoInteractionService.queryInteractionCount(videoIds, VideoUserRecordType.CART, null, null, true); - videoFunnelStatisticVO.setTotalReadCartUserCount(totalReadCartUserCount); - - // 订单相关 - OrderStatCollect orderCollect = orderQueryService.queryOrderCollect(videoIds, ProductType.VIDEO_SINGLE); - videoFunnelStatisticVO.setOrderUserCount(orderCollect.getUserCount()); - videoFunnelStatisticVO.setOrderCount(orderCollect.getCount()); - videoFunnelStatisticVO.setOrderAmount(orderCollect.getOrderAmount()); - videoFunnelStatisticVO.setPaidUserCount(orderCollect.getPayUserCount()); - videoFunnelStatisticVO.setPaidOrderCount(orderCollect.getPayCount()); - videoFunnelStatisticVO.setPaidAmount(orderCollect.getPayAmount()); - return videoFunnelStatisticVO; - } - - /** - * 获取视频客户直播榜单列表 - * - * @param query 视频客户观看排名查询条件 - * @param backendUserVO 后台用户信息 - * @return 视频客户观看排名列表 - */ - public Pager customerReadRankList(CustomerReadRankQuery query, BackendUserVO backendUserVO) { - LocalDateTime startTime = query.getStartTime(); - LocalDateTime endTime = query.getEndTime(); - Integer rankType = query.getRankType(); - Integer userType = query.getUserType(); - - Set authSet = authService.getAuthByUserType(VideoUserType.format(userType), backendUserVO, true); - if (authSet != null && authSet.isEmpty()) { - return Pager.emptyPager(); - } - - List videoLiveList = getVideoLives(authSet, null, startTime, endTime); - Set videoIds = videoLiveList.stream().map(VideoLive::getId).collect(Collectors.toSet()); - Map> advisorVideoMap = videoLiveList.stream().collect(Collectors.groupingBy(VideoLive::getAdvisorId)); - Map> advisorVideoIdMap = videoLiveList.stream().collect(Collectors.groupingBy(VideoLive::getAdvisorId, Collectors.mapping(VideoLive::getId, Collectors.toList()))); - if (CollUtil.isEmpty(videoIds)) { - return Pager.emptyPager(); - } - String videoIdsStr = StrUtil.join(",", videoIds); - Page page; - if (VideoRankType.READ.value.equals(rankType)) { - page = videoLiveMapper.selectAdvisorRankListOrderByWatchUser(query.toPage(), videoIdsStr); - } else if (VideoRankType.READ_TIME.value.equals(rankType)) { - page = videoLiveMapper.selectAdvisorRankListOrderByWatchTime(query.toPage(), videoIdsStr); - } else if (VideoRankType.ORDER_NUM.value.equals(rankType)) { - page = videoLiveMapper.selectAdvisorRankListOrderByOrderCount(query.toPage(), videoIdsStr, OrderQueryService.PAID_STATUS_STR); - } else if (VideoRankType.ORDER_AMOUNT.value.equals(rankType)) { - page = videoLiveMapper.selectAdvisorRankListOrderByOrderAmount(query.toPage(), videoIdsStr, OrderQueryService.PAID_STATUS_STR); - } else { - return Pager.emptyPager(); - } - Set advisorIds = page.getRecords().stream().map(VideoCustomerReadRankListVO::getAdvisorId).collect(Collectors.toSet()); - if (CollUtil.isEmpty(advisorIds)) { - return Pager.emptyPager(); - } - // 投顾 - Map advisorMap = advisorInfoService.getAdvisorMap(); - Map advisorNameMap = advisorMap.values().stream().collect(Collectors.toMap(AdvisorBasic::getId, AdvisorBasic::getName)); - // 部门 - Map deptMap = deptService.getDeptMap(); - Map advisorDeptNameMap = advisorMap.values().stream() - .filter(advisor -> deptMap.containsKey(advisor.getDeptId())) - .collect(Collectors.toMap(AdvisorBasic::getId, advisor -> deptMap.get(advisor.getDeptId()).getName())); - // 观看 - AdminVideoInteractionService.WatchResultVO watchResult = adminVideoInteractionService.calWatchUserCountAndTime(videoIds); - Map watchTimeMap = watchResult.watchTimeMap; - Map watchUserMap = watchResult.watchUserMap; - Map advisorWatchTimeMap = advisorVideoIdMap.entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().stream().mapToInt(id -> watchTimeMap.getOrDefault(id, 0)).sum())); - Map advisorWatchUserMap = advisorVideoIdMap.entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().stream().mapToInt(id -> watchUserMap.getOrDefault(id, 0)).sum())); - // 关注 - Map followMap = adminVideoInteractionService.calAdvisorFollow(advisorIds, startTime, endTime); - // 消息 - Map msgCountMap = adminVideoInteractionService.queryVideoMessageCount(videoIds, VideoMessageContentType.TEXT, null); - // 分享 - Map shareCountMap = adminVideoInteractionService.queryVideoInteractionCount(videoIds, VideoUserRecordType.SHARE, false); - // 点赞 - Map favorNumMap = adminVideoInteractionService.queryVideoInteractionCount(videoIds, VideoUserRecordType.FAVOR, false); - // 订单 - Map videoOrderCollectMap = orderQueryService.queryVideoOrderCollect(ProductType.VIDEO_SINGLE, videoIds); - page.getRecords().forEach(vo -> { - Integer advisorId = vo.getAdvisorId(); - vo.setAdvisorName(advisorNameMap.get(advisorId)); - vo.setDeptName(advisorDeptNameMap.get(advisorId)); - List liveList = advisorVideoMap.get(advisorId); - if (CollUtil.isNotEmpty(liveList)) { - List ids = liveList.stream().map(VideoLive::getId).collect(Collectors.toList()); - vo.setVideoCount(liveList.size()); - long columnCount = liveList.stream().filter(live -> live.getColumnId() != null).count(); - vo.setColumnCount((int) columnCount); - vo.setVideoTime(getVideoTime(liveList)); - vo.setTotalReadCount(advisorWatchUserMap.getOrDefault(advisorId, 0)); - vo.setTotalReadTime(advisorWatchTimeMap.getOrDefault(advisorId, 0)); - vo.setAvgReadTime(vo.getTotalReadCount() == 0 ? BigDecimal.ZERO : BigDecimal.valueOf(vo.getTotalReadTime()).divide(BigDecimal.valueOf(vo.getTotalReadCount()), 2, RoundingMode.HALF_UP)); - vo.setAvgReadCount(BigDecimal.valueOf(vo.getTotalReadCount()).divide(BigDecimal.valueOf(vo.getVideoCount()), 2, RoundingMode.HALF_UP)); - vo.setIncFollowCount(followMap.getOrDefault(advisorId, 0)); - vo.setMsgCount(ids.stream().mapToInt(id -> msgCountMap.getOrDefault(id, 0)).sum()); - vo.setFavorCount(ids.stream().mapToInt(id -> favorNumMap.getOrDefault(id, 0)).sum()); - vo.setShareCount(ids.stream().mapToInt(id -> shareCountMap.getOrDefault(id, 0)).sum()); - vo.setOrderCount(ids.stream().map(videoOrderCollectMap::get).filter(Objects::nonNull).mapToInt(OrderStatCollect::getCount).sum()); - vo.setOrderAmount(ids.stream().map(videoOrderCollectMap::get).filter(Objects::nonNull).map(OrderStatCollect::getPayAmount).reduce(BigDecimal.ZERO, BigDecimal::add)); - } else { - vo.setVideoCount(0); - vo.setColumnCount(0); - vo.setVideoTime(0); - vo.setTotalReadCount(0); - vo.setTotalReadTime(0); - vo.setAvgReadTime(BigDecimal.ZERO); - vo.setAvgReadCount(BigDecimal.ZERO); - vo.setIncFollowCount(0); - vo.setMsgCount(0); - vo.setFavorCount(0); - vo.setShareCount(0); - vo.setOrderCount(0); - vo.setOrderAmount(BigDecimal.ZERO); - } - }); - return new Pager<>(page); - } - - /** - * 获取投顾直播榜单数据 - * - * @param query 查询条件 - * @param backendUserVO 后台用户信息 - * @return 视频客户观看排名列表 - */ - public Pager customerReadRankListAdvisor(CustomerReadRankQuery query, BackendUserVO backendUserVO) { - LocalDateTime startTime = query.getStartTime(); - LocalDateTime endTime = query.getEndTime(); - Integer rankType = query.getRankType(); - Integer advisorId = backendUserVO.getAdvisorId(); - if (advisorId == null) { - throw new BizException(ResponseStatus.NOT_ADVISOR_ERROR); - } - - List videoLiveList = getVideoLives(null, advisorId, startTime, endTime); - Map videoMap = videoLiveList.stream().collect(Collectors.toMap(VideoLive::getId, Function.identity())); - Set videoIds = videoMap.keySet(); - if (CollUtil.isEmpty(videoIds)) { - return Pager.emptyPager(); - } - String videoIdsStr = StrUtil.join(",", videoIds); - Page page; - if (VideoRankType.READ.value.equals(rankType)) { - page = videoLiveMapper.selectVideoRankListOrderByWatchUser(query.toPage(), videoIdsStr); - } else if (VideoRankType.READ_TIME.value.equals(rankType)) { - page = videoLiveMapper.selectVideoRankListOrderByWatchTime(query.toPage(), videoIdsStr); - } else if (VideoRankType.ORDER_NUM.value.equals(rankType)) { - page = videoLiveMapper.selectVideoRankListOrderByOrderCount(query.toPage(), videoIdsStr, OrderQueryService.PAID_STATUS_STR); - } else if (VideoRankType.ORDER_AMOUNT.value.equals(rankType)) { - page = videoLiveMapper.selectVideoRankListOrderByOrderAmount(query.toPage(), videoIdsStr, OrderQueryService.PAID_STATUS_STR); - } else { - return Pager.emptyPager(); - } - // 观看 - AdminVideoInteractionService.WatchResultVO watchResult = adminVideoInteractionService.calWatchUserCountAndTime(videoIds); - Map watchTimeMap = watchResult.watchTimeMap; - Map watchUserMap = watchResult.watchUserMap; - // 观看人次 - Map readNumMap = adminVideoInteractionService.queryVideoInteractionCount(videoIds, VideoUserRecordType.READ, false); - // 关注 - Map followMap = adminVideoInteractionService.calVideoFollow(advisorId, videoIds, startTime, endTime); - // 消息 - Map msgCountMap = adminVideoInteractionService.queryVideoMessageCount(videoIds, VideoMessageContentType.TEXT, null); - // 分享 - Map shareCountMap = adminVideoInteractionService.queryVideoInteractionCount(videoIds, VideoUserRecordType.SHARE, false); - // 点赞 - Map favorNumMap = adminVideoInteractionService.queryVideoInteractionCount(videoIds, VideoUserRecordType.FAVOR, false); - // 订单 - Map videoOrderCollectMap = orderQueryService.queryVideoOrderCollect(ProductType.VIDEO_SINGLE, videoIds); - page.getRecords().forEach(vo -> { - Integer id = vo.getId(); - VideoLive video = videoMap.get(id); - if (video == null) { - return; - } - vo.setTitle(video.getTitle()); - vo.setVideoTime(getVideoTime(Collections.singletonList(video))); - vo.setTotalReadCount(watchUserMap.getOrDefault(id, 0)); - vo.setTotalReadTime(watchTimeMap.getOrDefault(id, 0)); - vo.setReadCount(readNumMap.getOrDefault(id, 0)); - vo.setMaxOnline(adminVideoInteractionService.getOnlineMax(id)); - vo.setAvgReadTime(vo.getTotalReadCount() == 0 ? BigDecimal.ZERO : BigDecimal.valueOf(vo.getTotalReadTime()).divide(BigDecimal.valueOf(vo.getTotalReadCount()), 2, RoundingMode.HALF_UP)); - vo.setIncFollowCount(followMap.getOrDefault(id, 0)); - vo.setMsgCount(msgCountMap.getOrDefault(id, 0)); - vo.setFavorCount(favorNumMap.getOrDefault(id, 0)); - vo.setShareCount(shareCountMap.getOrDefault(id, 0)); - OrderStatCollect collect = videoOrderCollectMap.get(id); - vo.setOrderCount(collect == null ? 0 : collect.getCount()); - vo.setOrderAmount(collect == null ? BigDecimal.ZERO : collect.getPayAmount()); - }); - return new Pager<>(page); - } - - /** - * 获取视频行为数据统计详情 - * - * @param query 视频统计详情查询条件 - * @param backendUserVO 后台用户信息 - * @return 视频统计用户详情分页信息 - */ - public Pager statisticAppUserDetailById(VideoStatisticDetailQuery query, BackendUserVO backendUserVO) { - Integer videoId = query.getVideoId(); - Integer type = query.getType(); - String nickName = query.getNickName(); - String userId = query.getUserId(); - Integer isSpeak = query.getIsSpeak(); - Integer hasGotCoupon = query.getHasGotCoupon(); - Integer isOrder = query.getIsOrder(); - Integer hasBoughtPro = query.getHasBoughtPro(); - Integer isAnswer = query.getIsAnswer(); - - QueryWrapper wrapper = Wrappers.query() - .eq("u.video_id", videoId) - .eq("u.type", VideoUserRecordType.READ.value) - .eq(VideoUserType.SALE_USER.value.equals(query.getUserType()), "s.sale_user_id", backendUserVO.getUserId()) - .like(StrUtil.isNotEmpty(nickName), "u.user_name", nickName) - .like(StrUtil.isNotEmpty(userId), "u.user_id", userId); - -// Map> userCouponMap = Collections.emptyMap(); - - if (VideoCustomerType.COMPLETE_WATCH.value.equals(type)) { - wrapper.exists("SELECT 1 FROM video_user_watch_collect w WHERE w.video_id = u.video_id AND w.user_id = u.user_id and w.finish_read_rate >= {0}", finishReadRatio); - } - if (VideoCustomerType.INTERACT.value.equals(type)) { - wrapper.and(w -> w.exists("SELECT 1 FROM video_live_message m WHERE m.video_id = u.video_id AND m.user_id = u.user_id AND m.type = {0}", VideoMessageContentType.TEXT.value) - .or().exists("SELECT 1 FROM video_live_user i where i.video_id = u.video_id AND i.user_id = u.user_id and i.type in (" + VideoUserRecordType.FAVOR.value + "," + VideoUserRecordType.SHARE.value + ")")); - } - if (VideoCustomerType.CLICK_PRODUCT.value.equals(type)) { - wrapper.exists("SELECT 1 FROM video_live_user c WHERE c.video_id = u.video_id AND c.user_id = u.user_id AND c.type = {0}", VideoUserRecordType.CART.value); - } - if (VideoCustomerType.ORDER_NOT_PAID.value.equals(type)) { - wrapper.exists("SELECT 1 FROM app_order o WHERE o.video_id = u.video_id AND o.user_name = u.user_id AND o.status IN (" + OrderQueryService.UNPAID_STATUS_STR + ")"); - } -// if (VideoCustomerType.COUPON_NOT_USED.value.equals(type) || IsOrNot.IS.value.equals(hasGotCoupon)) { -// userCouponMap = couponService.queryVideoCoupon(videoId); -// if (userCouponMap.isEmpty()) { -// return Pager.emptyPager(); -// } -// if (VideoCustomerType.COUPON_NOT_USED.value.equals(type)) { -// // 领券未使用 -// List couponNotUsedUser = userCouponMap.entrySet().stream().filter(entry -> entry.getValue().stream().noneMatch(coupon -> coupon.getStatus() == 2)).map(Map.Entry::getKey).collect(Collectors.toList()); -// } else { -// // 领券 -// wrapper.in("u.user_name", userCouponMap.keySet()); -// } -// // 当前优惠券系统没有和订单系统打通,所以所有优惠券都是领券未使用 -// wrapper.in("u.user_id", userCouponMap.keySet()); -// } - if (VideoCustomerType.SUBSCRIBE_PRODUCT.value.equals(type) || IsOrNot.IS.value.equals(hasBoughtPro)) { - wrapper.exists("SELECT 1 FROM app_order o WHERE o.video_id = u.video_id AND o.user_name = u.user_id AND o.status IN (" + OrderQueryService.PAID_STATUS_STR + ")"); - } - if (VideoCustomerType.COMPLETE_SURVEY.value.equals(type) || IsOrNot.IS.value.equals(isAnswer)) { - wrapper.exists("SELECT 1 FROM video_question_answer a JOIN video_question_main q WHERE a.question_id = q.id AND a.user_id = u.user_id AND q.video_id = u.video_id"); - } - if (IsOrNot.IS.value.equals(isSpeak)) { - wrapper.exists("SELECT 1 FROM video_live_message m WHERE m.video_id = u.video_id AND m.user_id = u.user_id AND m.type = {1}", VideoMessageContentType.TEXT.value); - } - if (IsOrNot.IS.value.equals(isOrder)) { - wrapper.exists("SELECT 1 FROM app_order o WHERE o.video_id = u.video_id AND o.user_name = u.user_id"); - } - Page page = adminVideoInteractionService.selectVideoUserDetail(query.toPage(), wrapper); - List records = page.getRecords(); - List onlineList = videoCacheService.getOnlineList(videoId); - Set onlineUserIdSet = onlineList.stream().map(OnlineUser::getUserId).collect(Collectors.toSet()); - Map userNameMap = userService.getUserMap().values().stream().collect(Collectors.toMap(UserDept::getUserId, UserDept::getName)); - Map readMinuteMap = adminVideoInteractionService.calcuVideoReadMap(videoId, null, null, null); - Map messageCountMap = adminVideoInteractionService.calUserMessageCount(videoId, null, VideoMessageContentType.TEXT); - Map favorCountMap = adminVideoInteractionService.queryUserInteractionCount(videoId, null, VideoUserRecordType.FAVOR); - Map shareCountMap = adminVideoInteractionService.queryUserInteractionCount(videoId, null, VideoUserRecordType.SHARE); - Map> cartNameMap = adminVideoInteractionService.calUserCartName(videoId); - Map> orderNameMap = orderQueryService.calUserOrderName(videoId, null); - Map> paidOrderNameMap = orderQueryService.calUserOrderName(videoId, IsOrNot.IS.value); - Map> answerNameMap = adminVideoInteractionService.calUserAnswerName(videoId); - // 填充其他字段 - for (VideoStatisticUserDetailVO vo : records) { - vo.setIsOnline(onlineUserIdSet.contains(vo.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); - vo.setSaleUserName(userNameMap.get(vo.getSaleUserId())); - Integer minutes = readMinuteMap.getOrDefault(vo.getUserId(), 0); - vo.setReadHours(BigDecimal.valueOf(minutes).multiply(BigDecimal.valueOf(60)).intValue()); - vo.setMessCount(messageCountMap.getOrDefault(vo.getUserId(), 0)); - vo.setFavorCount(favorCountMap.getOrDefault(vo.getUserId(), 0)); - vo.setIsShare(shareCountMap.containsKey(vo.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); -// vo.setHasGotCoupon(userCouponMap.containsKey(vo.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); -// vo.setCouponName(userCouponMap.getOrDefault(vo.getUserId(), Collections.emptyList()).stream().map(UserCoupon::getCouponName).collect(Collectors.joining(","))); - vo.setHasSeenCart(cartNameMap.containsKey(vo.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); - if (cartNameMap.containsKey(vo.getUserId())) { - vo.setCartName(cartNameMap.get(vo.getUserId()).stream().filter(Objects::nonNull).collect(Collectors.joining(","))); - } - vo.setIsOrder(orderNameMap.containsKey(vo.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); - if (orderNameMap.containsKey(vo.getUserId())) { - vo.setOrderProName(orderNameMap.get(vo.getUserId()).stream().filter(Objects::nonNull).collect(Collectors.joining(","))); - } - vo.setHasBoughtPro(paidOrderNameMap.containsKey(vo.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); - if (paidOrderNameMap.containsKey(vo.getUserId())) { - vo.setHasBoughtProName(paidOrderNameMap.get(vo.getUserId()).stream().filter(Objects::nonNull).collect(Collectors.joining(","))); - } - vo.setIsAnswer(answerNameMap.containsKey(vo.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); - if (answerNameMap.containsKey(vo.getUserId())) { - vo.setQuestionName(answerNameMap.get(vo.getUserId()).stream().filter(Objects::nonNull).collect(Collectors.joining(","))); - } - } - return new Pager<>(records, page.getTotal()); - } - - /** - * 获取营销人员数据统计详情 - * - * @param query 视频统计详情查询条件 - * @return 视频统计员工用户详情分页信息 - */ - public Pager statisticStaffUserDetailById(VideoStatisticStaffDetailQuery query) { - Integer videoId = query.getVideoId(); - Integer type = query.getType(); - String userName = query.getUserName(); - String staffNo = query.getStaffNo(); - String deptId = query.getDeptId(); - - QueryWrapper wrapper = Wrappers.query() - .eq(StrUtil.isNotEmpty(userName), "u.name", userName) - .eq(StrUtil.isNotEmpty(staffNo), "u.staff_no", staffNo) - .eq(StrUtil.isNotEmpty(deptId), "u.dept_id", deptId); - if (VideoStatisticEventType.INVITE_WATCH.value.equals(type)) { - wrapper.orderByDesc("sr.count"); - } else if (VideoStatisticEventType.SUBSCRIBE_COUNT.value.equals(type)) { - wrapper.orderByDesc("op.amount"); - } else if (VideoStatisticEventType.SIGN_CONVERSION_RATE.value.equals(type)) { - wrapper.orderByDesc("op.count/sr.count"); - } - Page page = adminVideoInteractionService.statisticSaleUserByVideo(query.toPage(), videoId, wrapper); - - // 查询用户和营销人员关系 - Map userSaleMap = adminVideoCustomerService.getCustomerSaleMap(videoId); - // 部门 - Map deptMap = deptService.getDeptMap(); - Map deptNameMap = deptMap.values().stream().collect(Collectors.toMap(Dept::getId, Dept::getName)); - page.getRecords().forEach(vo -> { - if (StrUtil.isNotEmpty(vo.getDeptId())) { - vo.setDeptName(deptNameMap.get(vo.getDeptId())); - } - }); - -// // 查询优惠券 -// Map> userCouponMap = couponService.queryVideoCoupon(videoId); - // 统计优惠券领取情况 - Map saleUserMap = page.getRecords().stream().collect(Collectors.toMap(VideoStatisticStaffDetailVO::getSaleUserId, Function.identity())); -// userCouponMap.forEach((userId, couponList) -> { -// Integer saleUserId = userSaleMap.get(userId); -// VideoStatisticStaffDetailVO vo = saleUserMap.get(saleUserId); -// if (vo != null && CollUtil.isNotEmpty(couponList)) { -// couponList.forEach(coupon -> { -// vo.setGetCouponCount(vo.getGetCouponCount() + 1); -// if (coupon.getStatus() != 2) { -// vo.setGetCouponNotUseCount(vo.getGetCouponNotUseCount() + 1); -// } -// }); -// } -// }); - - return new Pager<>(page); - } - - /** - * 获取视频直播的实时趋势数据 - * - * @param videoId 视频ID - * @return 视频直播趋势数据列表 - */ - public List videoLiveNowTrend(Integer videoId) { - // 先尝试从汇总表读取 - List timeList = adminVideoInteractionService.queryTimeCollect(videoId); - if (CollUtil.isNotEmpty(timeList)) { - return timeList.stream().map(collect -> { - VideoLiveTrendVO trend = new VideoLiveTrendVO(); - if (collect.getSecondTime() != null) { - trend.setTime(CollectTask.formatter.format(collect.getSecondTime())); - } - trend.setOnlineNum(collect.getOnlineCount()); - trend.setAttendNum(collect.getAttendCount()); - trend.setLeaveNum(collect.getLeaveCount()); - trend.setSaleNum(collect.getSaleCount()); - trend.setIsRecommendPro(collect.getIsRecommend()); - trend.setHasSendCoupon(collect.getHasSendCoupon()); - return trend; - }).collect(Collectors.toList()); - } - // 获取不到就查明细表 - return videoLiveNowTrendReverse(videoId); - } - - /** - * 获取视频直播的实时趋势数据 - * 只取明细表 - * - * @param videoId 视频ID - * @return 视频直播趋势数据列表 - */ - public List videoLiveNowTrendReverse(Integer videoId) { - // 从明细表读取 - VideoLive videoLive = videoLiveMapper.selectById(videoId); - LocalDateTime realStartTime = videoLive.getRealStartTime(); - LocalDateTime realEndTime = videoLive.getRealEndTime() == null ? LocalDateTime.now() : videoLive.getRealEndTime(); - if (realStartTime == null) { - return Collections.emptyList(); - } - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); - List data = videoUserFlowMapper.selectLine(videoId); - if (CollUtil.isEmpty(data)) { - return Collections.emptyList(); - } - Map trendMap = data.stream().collect(Collectors.toMap(t -> t.getCreateTime().format(formatter), Function.identity())); - // 推送产品 - List messages = adminVideoInteractionService.queryOnShelfMessage(videoId); - Set isRecommend = messages.stream().map(message -> message.getCreateTime().format(formatter)).collect(Collectors.toSet()); - - // 查每分钟销量 - Map cycleCollectMap = orderQueryService.queryCycleOrderCollect(ProductType.VIDEO_SINGLE, Collections.singleton(videoId), OrderQueryService.CycleFormat.MINUTE); - Map saleMap = cycleCollectMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getPayCount())); - -// // 每分钟是否发优惠券 -// LiveBaseReq req = new LiveBaseReq(); -// req.setLiveCategoryId(ProductType.VIDEO_SINGLE.value); -// req.setLiveProductId(videoId); -// List liveCouponStatByMin = productService.getLiveCouponStatByMin(req); -// Map couponMap = liveCouponStatByMin.stream().collect(Collectors.toMap(CouponNumByMin::getMinTime, CouponNumByMin::getSendCouponNum)); - - List vos = new ArrayList<>(data.size()); - int preOnline = 0; - while (realStartTime.isBefore(realEndTime)) { - VideoLiveTrendVO vo = new VideoLiveTrendVO(); - // yyyy-MM-dd HH:mm - String format = realStartTime.format(formatter); - vo.setTime(format); - VideoLiveTrend trend = trendMap.get(format); - if (trend != null) { - vo.setOnlineNum(trend.getOnline() == null ? 0 : trend.getOnline()); - vo.setLeaveNum(trend.getLeaveNum() == null ? 0 : trend.getLeaveNum()); - // pre + jin - leave = online - int attendNum = vo.getOnlineNum() + vo.getLeaveNum() - preOnline; - vo.setAttendNum(attendNum < 0 ? 0 : attendNum); - } - - vo.setIsRecommendPro(isRecommend.contains(format) ? IsOrNot.IS.value : IsOrNot.NOT.value); - // 填充销量 - Integer saleNum = saleMap.get(format); - vo.setSaleNum(saleNum == null ? 0 : saleNum); - // 优惠券数量 - Integer couponNum = couponMap.get(format); - couponNum = couponNum == null ? 0 : couponNum; - vo.setHasSendCoupon(couponNum > 0 ? IsOrNot.IS.value : IsOrNot.NOT.value); - vos.add(vo); - - preOnline = vo.getOnlineNum(); - realStartTime = realStartTime.plusMinutes(1); - - } - return vos; - } - - /** - * 获取视频数据概况(数据大屏) - * - * @param videoId 视频ID - * @return 视频直播数据概览 - */ - public VideoLiveOverviewVO videoLiveDataOverview(Integer videoId) { - VideoLive video = videoLiveMapper.selectById(videoId); - LocalDateTime realStartTime = video.getRealStartTime(); - LocalDateTime realEndTime = video.getRealEndTime(); - LocalDateTime now = LocalDateTime.now(); - Integer liveStatus = video.getLiveStatus(); - - VideoLiveOverviewVO vo = new VideoLiveOverviewVO(); - vo.setLiveStatus(video.getLiveStatus()); - vo.setTitle(video.getTitle()); - vo.setStartTime(video.getRealStartTime() == null ? video.getStartTime() : video.getRealStartTime()); - // 直播时长 - if (realStartTime != null) { - Duration duration = Duration.between(realStartTime, video.getRealEndTime() == null ? now : video.getRealEndTime()); - vo.setHours(VideoHelper.buildTimeStr(duration)); - } - // 填充实时在线人数 - // 直播在线人数峰值 - vo.setOnlineMostNum(adminVideoInteractionService.getOnlineMax(videoId)); - vo.setOnlineNum(!VideoLiveStatus.HAS_ENDED.value.equals(liveStatus) ? videoCacheService.getOnlineCount(videoId) : 0); - // 直播观看 - if (realStartTime == null && Objects.equals(video.getPlayType(), VideoPlayType.LIVE.value)) { - vo.setReadNum(0); - vo.setReadPeopleNum(0); - vo.setReadDuration(BigDecimal.ZERO); - vo.setReadDurationAvg(BigDecimal.ZERO); - } else { - // 直播观看人次 - Integer liveReadCount = adminVideoInteractionService.queryInteractionCount(videoId, VideoUserRecordType.READ, null, null, false); - vo.setReadNum(liveReadCount - (video.getPreNum() == null ? 0 : video.getPreNum())); - // 直播观看人数、总时长、人均时长 - AdminVideoInteractionService.UserAndTime userAndTime = adminVideoInteractionService.queryUserAndTime(videoId, true); - vo.setReadPeopleNum(userAndTime.user); - vo.setReadDuration(BigDecimal.valueOf(userAndTime.sum).divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP)); - vo.setReadDurationAvg(BigDecimal.valueOf(userAndTime.avg).divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP)); - } - // 回放观看 - if (realEndTime == null) { - vo.setReReadNum(0); - vo.setReReadPeopleNum(0); - vo.setReReadDuration(BigDecimal.ZERO); - vo.setReReadDurationAvg(BigDecimal.ZERO); - } else { - // 回放观看人次 - Integer vodReadCount = adminVideoInteractionService.queryInteractionCount(videoId, VideoUserRecordType.READ, null, null, false); - vo.setReReadNum(vodReadCount - (video.getLiveNum() == null ? 0 : video.getLiveNum())); - // 回放观看人数、总时长、人均时长 - AdminVideoInteractionService.UserAndTime userAndTime = adminVideoInteractionService.queryUserAndTime(videoId, false); - vo.setReReadPeopleNum(userAndTime.user); - vo.setReReadDuration(BigDecimal.valueOf(userAndTime.sum).divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP)); - vo.setReReadDurationAvg(BigDecimal.valueOf(userAndTime.avg).divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP)); - } - // 互动 - // 评论数 - Integer msgCount = adminVideoInteractionService.queryMessageCount(videoId, VideoMessageContentType.TEXT, null); - vo.setMessCount(msgCount); - // 点赞人数 - Integer favorPeopleCount = adminVideoInteractionService.queryInteractionCount(videoId, VideoUserRecordType.FAVOR, null, null, true); - vo.setFavorPeopleCount(favorPeopleCount); - // 点赞数 - Integer totalFavorCount = adminVideoInteractionService.queryInteractionCount(videoId, VideoUserRecordType.FAVOR, null, null, false); - vo.setFavorCount(totalFavorCount); - // 分享数 - Integer shareCount = adminVideoInteractionService.queryInteractionCount(videoId, VideoUserRecordType.SHARE, null, null, false); - vo.setShareCount(shareCount); - // 互动率 - Integer msgUserCount = adminVideoInteractionService.queryMessageUserCount(videoId, VideoMessageContentType.TEXT); - Integer shareUserCount = adminVideoInteractionService.queryInteractionCount(videoId, VideoUserRecordType.SHARE, null, null, false); - BigDecimal msgRate = BigDecimal.ZERO; - if (vo.getReadNum() > 0) { - msgRate = BigDecimal.valueOf(msgUserCount + shareUserCount + favorPeopleCount).divide(BigDecimal.valueOf(vo.getReadNum()), 6, RoundingMode.HALF_UP); - } - vo.setMsgRate(msgRate); - // 新增粉丝数 - Integer newFollowCount = adminVideoInteractionService.queryNewFollowCount(video); - vo.setNewFollowCount(newFollowCount); - // 点击产品数 - Integer clickCartCount = adminVideoInteractionService.queryInteractionCount(videoId, VideoUserRecordType.CART, null, null, false); - vo.setBrowseProCount(clickCartCount); - // 提交订单未付款数 - // 成交订单数 - // 成交金额 - OrderStatCollect orderCollect = orderQueryService.queryOrderCollect(videoId, ProductType.VIDEO_SINGLE); - vo.setOrderButNotPayCount(orderCollect.getUnPayCount()); - vo.setSubCount(orderCollect.getPayCount()); - vo.setSubAmount(orderCollect.getPayAmount()); - return vo; - } - - /** - * 统计视频直播用户的新老占比(直播数据大屏) - * - * @param videoId 视频ID - * @return 视频直播用户年龄分布信息 - */ - public VideoLiveUserAgeVO videoLiveUserAge(Integer videoId) { - Integer newNum = adminVideoInteractionService.queryNewOrOldReadCount(videoId, IsOrNot.IS); - Integer oldNum = adminVideoInteractionService.queryNewOrOldReadCount(videoId, IsOrNot.NOT); - int total = newNum + oldNum; - if (total == 0) { - return new VideoLiveUserAgeVO(0, 0, BigDecimal.ZERO, BigDecimal.ZERO); - } - BigDecimal newProportion = BigDecimal.valueOf(newNum).divide(BigDecimal.valueOf(total), 4, RoundingMode.HALF_UP); - BigDecimal oldProportion = BigDecimal.valueOf(oldNum).divide(BigDecimal.valueOf(total), 4, RoundingMode.HALF_UP); - return new VideoLiveUserAgeVO(newNum, oldNum, newProportion, oldProportion); - } - - /** - * 获取视频直播用户的渠道分布(直播数据大屏) - * - * @param videoId 视频ID - * @return 视频直播用户渠道分布信息列表 - */ - public List videoLiveUserChannel(Integer videoId) { - List customers = adminVideoInteractionService.queryChannelCustomers(videoId); - if (CollUtil.isEmpty(customers)) { - return Collections.emptyList(); - } - int total = customers.stream().mapToInt(VideoLiveCustomer::getSaleUserId).sum(); - return customers.stream().map(customer -> new VideoLiveUserChannelVO( - VideoCustomerChannel.fromValue(customer.getChannel()), - total == 0 ? BigDecimal.ZERO : - BigDecimal.valueOf(customer.getSaleUserId()).divide(BigDecimal.valueOf(total), 4, RoundingMode.HALF_UP)) - ).collect(Collectors.toList()); - } - - /** - * 获取视频直播产品销售数据(直播数据大屏) - * - * @param videoId 视频ID - * @return 视频直播产品销售数据列表 - */ - public List videoLiveProductSale(Integer videoId) { - return orderQueryService.queryVideoLiveProductSale(videoId); - } - - /** - * 获取视频直播用户的省份分布比例(直播数据大屏) - * - * @param videoId 视频ID - * @return 视频直播用户省份分布信息列表 - */ - public List userProvinceProportion(Integer videoId) { - VideoLive video = videoLiveMapper.selectById(videoId); - if (video == null) { - return Collections.emptyList(); - } - LocalDateTime startTime = video.getRealStartTime(); - if (startTime == null) { - return Collections.emptyList(); - } - LocalDateTime endTime = video.getRealEndTime() == null ? LocalDateTime.now() : video.getRealEndTime(); - Map provinceMap; - try { - provinceMap = videoCloudService.describeProIspPlaySumInfoList(startTime, endTime); - } catch (Exception e) { - return Collections.emptyList(); - } - if (CollUtil.isEmpty(provinceMap)) { - return Collections.emptyList(); - } - int totalNumInt = provinceMap.values().stream().mapToInt(Long::intValue).sum(); - if (totalNumInt == 0) { - return Collections.emptyList(); - } - // 腾讯云返回的是所有直播的总数,按比例换算成某一个直播间的 - BigDecimal maxOnline = BigDecimal.valueOf(adminVideoInteractionService.getOnlineMax(videoId)); - BigDecimal totalNum = BigDecimal.valueOf(totalNumInt); - BigDecimal radio = maxOnline.divide(totalNum, 10, RoundingMode.HALF_UP); - - Map newProvinceMap = provinceMap.entrySet().stream().filter(entry -> entry.getValue() != null && entry.getValue() > 0) - .collect(Collectors.toMap(Map.Entry::getKey, entry -> - BigDecimal.valueOf(entry.getValue()).multiply(radio).intValue())); - totalNumInt = newProvinceMap.values().stream().mapToInt(Integer::intValue).sum(); - if (totalNumInt == 0) { - return Collections.emptyList(); - } - BigDecimal newTotalNum = BigDecimal.valueOf(totalNumInt); - - return newProvinceMap.entrySet().stream().filter(entry -> entry.getValue() != null && entry.getValue() > 0) - .map(entry -> new VideoUserProvinceVO( - entry.getKey(), - entry.getValue(), - BigDecimal.valueOf(entry.getValue()).divide(newTotalNum, 4, RoundingMode.HALF_UP)) - ).collect(Collectors.toList()); - } - - /** - * 获取视频直播产品成交金额曲线(直播数据大屏) - * - * @param videoId 视频ID - * @return 视频直播产品销售数据时间线列表 - */ - public List productSaleLine(Integer videoId) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); - Map cycleCollectMap = orderQueryService.queryCycleOrderCollect(ProductType.VIDEO_SINGLE, Collections.singleton(videoId), OrderQueryService.CycleFormat.MINUTE); - return cycleCollectMap.entrySet().stream() - .map(entry -> new VideoProductSaleLineVO(LocalDateTime.parse(entry.getKey(), formatter), entry.getValue().getPayAmount())) - .collect(Collectors.toList()); - } - - /** - * 查询用户在线状态 - * - * @param query 用户在线查询条件 - * @return 用户在线信息 - */ - public UserOnlineVO queryUserOnline(UserOnlineQuery query) { - Integer videoId = query.getVideoId(); - List onlineList = videoCacheService.getOnlineList(videoId); - String userId = query.getUserId(); - Integer isOnline; - if (onlineList != null && !onlineList.isEmpty()) { - OnlineUser entry = onlineList.stream().filter(o -> Objects.equals(o.getUserId(), userId)).findAny().orElse(null); - isOnline = entry != null && entry.getIsOnline() != null ? entry.getIsOnline() : IsOrNot.NOT.value; - } else { - isOnline = IsOrNot.NOT.value; - } - return new UserOnlineVO(userId, videoId, isOnline); - } - - /** - * 获取数据大屏整合数据 - * - * @param videoId 视频ID - * @return 视频数据概况对象 - */ - public VideoScreenVO getScreenUnion(Integer videoId) { - return cacheService.get(CacheKey.SCREEN, CacheKey.ScreenKey.SCREEN_VIDEO_INFO + videoId, () -> { - List videoLiveTrendVOS = videoLiveNowTrend(videoId); - VideoLiveOverviewVO videoLiveOverviewVO = videoLiveDataOverview(videoId); - VideoLiveUserAgeVO videoLiveUserAgeVO = videoLiveUserAge(videoId); - List videoLiveUserChannelVOS = videoLiveUserChannel(videoId); - List videoLiveProductSaleVOS = videoLiveProductSale(videoId); - List videoUserProvinceVOS = userProvinceProportion(videoId); - List videoProductSaleLineVOS = productSaleLine(videoId); - List clientTypeCountVOS = queryClientTypeCount(videoId); - return new VideoScreenVO(videoLiveTrendVOS, videoLiveOverviewVO, videoLiveUserAgeVO, videoLiveUserChannelVOS, videoLiveProductSaleVOS, videoUserProvinceVOS, videoProductSaleLineVOS, clientTypeCountVOS); - }); - } - - /** - * 获取看完直播的个数 - * - * @param videoTimeMap 视频时长 - * @param userReadTimeMap 用户观看时长 - */ - public int getFinishedVideoCount(Map videoTimeMap, Map userReadTimeMap) { - return (int) videoTimeMap.entrySet().stream() - .filter(entry -> entry.getValue() > 0) - .filter(entry -> userReadTimeMap.getOrDefault(entry.getKey(), 0) / (entry.getValue() / 60.0) >= finishReadRatio) - .count(); - } - - /** - * 终端类型统计 - * - * @param videoId 视频ID - * @return 终端类型统计列表 - */ - public List queryClientTypeCount(Integer videoId) { - List list = adminVideoInteractionService.queryClientTypeCount(videoId); - List voList = new ArrayList<>(); - int otherCount = 0; - // 客户类型 1 PC 2 app 3 web 4 H5 0 其他 - for (VideoLiveUser record : list) { - Integer clientType = record.getClientType(); - if (clientType != null && clientType >= 0 && clientType <= 4) { - voList.add(new ClientTypeCountVO(record.getClientType(), record.getNum())); - } else { - otherCount += record.getNum(); - } - } - if (otherCount > 0) { - voList.add(new ClientTypeCountVO(0, otherCount)); - } - return voList; - } - - private List getVideoLives(Collection advisorIds, Integer advisorId, LocalDateTime startTime, LocalDateTime endTime) { - LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery() - .in(CollUtil.isNotEmpty(advisorIds), VideoLive::getAdvisorId, advisorIds) - .eq(advisorId != null, VideoLive::getAdvisorId, advisorId) - .isNotNull(VideoLive::getRealStartTime) - .between(startTime != null && endTime != null, VideoLive::getRealStartTime, startTime, endTime) - .eq(VideoLive::getPlayType, VideoPlayType.LIVE.value); - return videoLiveMapper.selectList(queryWrapper); - } - - private Integer getVideoTime(List liveList) { - return liveList.stream() - .mapToInt(videoLive -> { - LocalDateTime start = videoLive.getRealStartTime(); - LocalDateTime end = videoLive.getRealEndTime(); - return (start == null || end == null) ? 0 : (int) Duration.between(start, end).getSeconds(); - }) - .sum(); - } - - private Map getMapByDecimal(Map avgReadHoursMap) { - return getMapByUnit(avgReadHoursMap, BigDecimal::add); - } - - private Map getMapByInteger(Map videoCountMap) { - return getMapByUnit(videoCountMap, Integer::sum); - } - - private Map getMapByUnit(Map countMap, BiFunction fn) { - Map map = new TreeMap<>(); - countMap.forEach((key, value) -> { - LocalDate month = key.withDayOfMonth(1); - map.merge(month, value, fn); - }); - return map; - } - -} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/service/app/AppVideoMessageService.java~ b/src/main/java/com/upchina/video/service/app/AppVideoMessageService.java~ deleted file mode 100644 index 410a3a0..0000000 --- a/src/main/java/com/upchina/video/service/app/AppVideoMessageService.java~ +++ /dev/null @@ -1,328 +0,0 @@ -package com.upchina.video.service.app; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.core.util.StrUtil; -import com.upchina.advisor.service.AdvisorInfoService; -import com.upchina.advisor.vo.AdvisorBasicVO; -import com.upchina.common.config.cache.CacheKey; -import com.upchina.common.constant.IsOrNot; -import com.upchina.common.constant.ProductType; -import com.upchina.common.handler.BizException; -import com.upchina.common.query.SaveCommentQuery; -import com.upchina.common.result.AppPager; -import com.upchina.common.result.ResponseStatus; -import com.upchina.common.service.CacheService; -import com.upchina.common.service.CommentService; -import com.upchina.common.util.LoggerUtil; -import com.upchina.common.util.TextUtil; -import com.upchina.common.vo.FrontUserVO; -import com.upchina.rbac.service.UserService; -import com.upchina.video.constant.VideoMessageContentType; -import com.upchina.video.constant.VideoPlayType; -import com.upchina.video.entity.VideoLive; -import com.upchina.video.entity.VideoLiveMessage; -import com.upchina.video.entity.VideoSortEntity; -import com.upchina.video.helper.VideoHelper; -import com.upchina.video.mapper.VideoLiveMessageMapper; -import com.upchina.video.query.common.UpdateVideoOptionQuery; -import com.upchina.video.query.message.ListVideoAppQuery; -import com.upchina.video.query.message.SendLiveMessageQuery; -import com.upchina.video.service.common.VideoCacheService; -import com.upchina.video.service.common.VideoCommonService; -import com.upchina.video.service.common.VideoMessageService; -import com.upchina.video.vo.common.VideoProductInfoVO; -import com.upchina.video.vo.message.VideoMessageAppVO; -import com.upchina.video.vo.message.VideoMessageBasicVO; -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.annotation.PostConstruct; -import javax.annotation.Resource; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; - -// app消息Service -@Service -public class AppVideoMessageService { - - @Resource - private VideoCommonService videoCommonService; - - @Resource - private VideoCacheService videoCacheService; - - @Resource - private VideoMessageService videoMessageService; - - @Resource - private CacheService cacheService; - - @Resource - private AdvisorInfoService advisorInfoService; - - @Resource - private CommentService commentService; - - @Resource - private VideoLiveMessageMapper videoLiveMessageMapper; - - @Resource - private UserService userService; - - private final long userMessageInterval = 1000; - - private final ConcurrentHashMap> tempMessageVOMap = new ConcurrentHashMap<>(); - - /** - * 从缓存中获取消息列表 - * - * @param query 查询条件 - * @param frontUser 前端用户信息 - * @return 消息分页列表 - */ - public AppPager getMessageListByCache(ListVideoAppQuery query, FrontUserVO frontUser) { - if (query.getLastId() == null) { - return cacheService.get(CacheKey.VIDEO_LIVE_MESSAGE, CacheKey.VideoLiveMessageKey.MESSAGE_TOP_20 + query.getId(), () -> getMessageList(query, frontUser)); - } else { - return getMessageList(query, frontUser); - } - } - - /** - * 从缓存中获取投顾消息列表 - * - * @param query 查询条件 - * @return 消息分页列表 - */ - public AppPager getMessageAdvisorListByCache(ListVideoAppQuery query) { - if (query.getLastId() == null) { - return cacheService.get(CacheKey.VIDEO_LIVE_MESSAGE, CacheKey.VideoLiveMessageKey.MESSAGE_ADVISOR_TOP_20 + query.getId(), () -> getAdvisorMessageList(query)); - } else { - return getAdvisorMessageList(query); - } - } - - /** - * 获取消息列表 - * - * @param query 查询条件 - * @param frontUser 前端用户信息 - * @return 消息分页列表 - */ - public AppPager getMessageList(ListVideoAppQuery query, FrontUserVO frontUser) { - if (query.getId() == null) { - return AppPager.emptyPager(); - } - SortedSet sortedSet; - if (frontUser != null) { - sortedSet = videoCacheService.getVideoMessageList(query.getId(), query.getStatus()); - } else { - sortedSet = videoCacheService.getVideoMessageAdvisorList(query.getId()); - } - Integer lastId = query.getLastId(); - Integer size = query.getSize(); - if (lastId != null) { - VideoSortEntity lastEntity = sortedSet.stream().filter(v -> v.getId().equals(lastId)).findFirst().orElse(null); - if (lastEntity == null) { - //特殊情况,当lastId对应的消息被删除时 - List entityList = sortedSet.stream().filter(v -> v.getId() >= lastId).collect(Collectors.toList()); - if (CollUtil.isEmpty(entityList)) { - return AppPager.emptyPager(); - } - lastEntity = entityList.get(entityList.size() - 1); - } - sortedSet = ((NavigableSet) sortedSet).tailSet(lastEntity, false); - } - Map advisorMap = advisorInfoService.getAdvisorVoMap(); - List voList = new ArrayList<>(size); - Iterator it = sortedSet.iterator(); - String userId = frontUser == null ? null : frontUser.getUserId(); - while (it.hasNext()) { - VideoMessageAppVO vo = getMessageDetail(it.next().getId()); - vo.setAdvisorBasic(advisorMap.get(vo.getAdvisorId())); - if (vo.getCreateUserId() != null) { - vo.setCreateUserVO(userService.get(vo.getCreateUserId(), false)); - } - if (frontUser != null) { - vo.setIsCurrentUser(Objects.equals(userId, vo.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); - if (VideoHelper.isPhone(vo.getUserId())) { - vo.setUserId(videoCommonService.encryptPhone(vo.getUserId())); - } - } - voList.add(vo); - if (--size == 0) { - break; - } - } - return new AppPager<>(voList, it.hasNext()); - } - - /** - * 获取消息详情 - * - * @param messageId 消息ID - * @return 消息详情 - */ - public VideoMessageAppVO getMessageDetail(Integer messageId) { - VideoLiveMessage message = videoCacheService.getVideoMessageInfo(messageId); - VideoMessageAppVO vo = new VideoMessageAppVO(message); - if (StrUtil.isNotBlank(message.getUserId())) { - vo.setIsForbid(videoCommonService.checkAppForbidden(message.getUserId()) ? IsOrNot.IS.value : IsOrNot.NOT.value); - } - if (message.getReplyId() != null) { - VideoLiveMessage replyMessage = videoCacheService.getVideoMessageInfo(message.getReplyId()); - vo.setReplyBasic(VideoMessageBasicVO.toVo(replyMessage, true)); - } - // 推荐产品 - if (StringUtils.isNotEmpty(message.getRecommendProduct())) { - List prdList = videoCommonService.getMergeProductList(vo.getVideoId(), new String[]{message.getRecommendProduct()}); - vo.setProductBasic(prdList.isEmpty() ? null : prdList.get(0)); - } - // 头像清晰度改写 - vo.setImgUrl(VideoMessageService.resizeImgUrl(vo.getImgUrl())); - return vo; - } - - /** - * APP发送消息 - * - * @param query 发送消息查询对象 - * @param frontUser 前端用户信息 - * @return 发送的消息 - */ - @Transactional(rollbackFor = Exception.class) - public VideoMessageAppVO sendMessage(SendLiveMessageQuery query, FrontUserVO frontUser) { - return saveUserTextMessage(query, frontUser); - } - - /** - * 直播间关注投顾消息 - * - * @param query 更新视频选项查询对象 - * @param frontUser 前端用户信息 - */ - @Transactional(rollbackFor = Exception.class) - public void sendFollowMessage(UpdateVideoOptionQuery query, FrontUserVO frontUser) { - videoMessageService.publishFollowMessage(query.getId(), frontUser); - } - - /** - * 获取投顾消息列表 - * - * @param query 查询条件 - * @return 消息分页列表 - */ - public AppPager getAdvisorMessageList(ListVideoAppQuery query) { - return getMessageList(query, null); - } - - /** - * 保存APP用户文本消息 - * - * @param query 发送消息查询对象 - * @param frontUser 前端用户信息 - */ - private VideoMessageAppVO saveUserTextMessage(SendLiveMessageQuery query, FrontUserVO frontUser) { - String groupId = query.getGroupId(); - if (!StrUtil.isNumeric(groupId)) { - throw new BizException(ResponseStatus.PARM_ERROR); - } - String userId = frontUser.getUserId(); - String imgUrl = frontUser.getImgUrl(); - String userName = frontUser.getUserName(); - String content = query.getText(); - Integer videoId = Integer.valueOf(groupId); - try { - videoCommonService.checkSensitiveWords(content); - } catch (BizException e) { - throw new BizException(ResponseStatus.SENSITIVE_WORD_ERROR); - } - try { - VideoLive video = videoCacheService.getVideoInfo(videoId); - if (video == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR); - } - if (!VideoHelper.VALID_STATUS_LIST.contains(video.getStatus())) { - throw new BizException(ResponseStatus.STATUS_ERROR, "视频直播未上架"); - } - boolean isLive = VideoPlayType.LIVE.value.equals(video.getPlayType()); - VideoLiveMessage message = query.toVo(videoId, userId, userName, video.getMessageAudit(), imgUrl); - if (!isLive) { - // 录播走评论接口 - SaveCommentQuery commentQuery = new SaveCommentQuery(); - commentQuery.setProductId(videoId); - commentQuery.setProductType(ProductType.VIDEO_SINGLE.value); - commentQuery.setCommentContent(query.getText()); - commentQuery.setSource(query.getSource()); - commentService.saveComment(commentQuery, frontUser); - } else { - // 直播走消息接口 - if (videoCommonService.checkAppForbidden(userId)) { - throw new BizException(ResponseStatus.COMMENT_BLACK_USER_ERROR, "您已被禁言"); - } - message.setContent(TextUtil.cleanUnsafeHtml(message.getContent())); - } - Integer messageCount = videoCacheService.getMessageCount(videoId, VideoMessageContentType.TEXT.value.equals(query.getType()) ? 1 : 0); - videoLiveMessageMapper.insert(message); - VideoMessageAppVO vo = new VideoMessageAppVO(message); - if (StrUtil.isNotBlank(message.getUserId())) { - if (videoCommonService.checkAppForbidden(message.getUserId())) { - vo.setIsForbid(IsOrNot.IS.value); - } else { - vo.setIsForbid(IsOrNot.NOT.value); - } - } - // 获取互动数 - vo.setMessageCount(messageCount); - // 改写头像清晰度 - vo.setImgUrl(VideoMessageService.resizeImgUrl(vo.getImgUrl())); - this.publishVideoMessage(vo, videoId); - videoCacheService.clearVideoMessageCache(message.getVideoId(), null, message.getType(), message, null); - return vo; - } catch (BizException ex) { - videoMessageService.publishVideoMessage(Integer.valueOf(groupId), ex); - throw ex; - } catch (Exception ex) { - BizException bizEx = new BizException(ResponseStatus.SYS_BUSY, ex); - videoMessageService.publishVideoMessage(Integer.valueOf(groupId), bizEx); - throw ex; - } - } - - public synchronized void publishVideoMessage(VideoMessageAppVO vo, Integer videoId) { - if (videoId == null) { - return; - } - List list = tempMessageVOMap.get(videoId); - if (vo != null) { - if (list == null) { - list = new ArrayList<>(); - tempMessageVOMap.put(videoId, list); - } - list.add(vo); - } else { - if (CollUtil.isNotEmpty(list)) { - videoMessageService.publishVideoMessage(videoId, list); - } - tempMessageVOMap.remove(videoId); - } - } - - @PostConstruct - public void initPushUserMessageThread() { - new Thread(() -> { - while (true) { - try { - tempMessageVOMap.keySet().forEach(videoId -> publishVideoMessage(null, videoId)); - Thread.sleep(userMessageInterval); - } catch (InterruptedException e) { - LoggerUtil.error("定时推送用户消息异常:" + ExceptionUtils.getStackTrace(e)); - } - } - }).start(); - } - -} \ No newline at end of file diff --git a/src/main/java/com/upchina/video/service/common/VideoCommonService.java~ b/src/main/java/com/upchina/video/service/common/VideoCommonService.java~ deleted file mode 100644 index d0c687d..0000000 --- a/src/main/java/com/upchina/video/service/common/VideoCommonService.java~ +++ /dev/null @@ -1,584 +0,0 @@ -package com.upchina.video.service.common; - -import cn.hutool.core.collection.CollUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.toolkit.Wrappers; -import com.google.common.collect.Table; -import cn.hutool.core.util.StrUtil; -import com.upchina.common.config.cache.CacheKey; -import com.upchina.common.constant.IsOrNot; -import com.upchina.common.constant.ProductType; -import com.upchina.common.handler.BizException; -import com.upchina.common.result.ResponseStatus; -import com.upchina.common.service.*; -import com.upchina.common.util.Debounce; -import com.upchina.common.util.LoggerUtil; -import com.upchina.common.util.RsaUtil; -import com.upchina.video.constant.*; -import com.upchina.video.entity.*; -import com.upchina.video.helper.AbstractVideoSortComparator; -import com.upchina.video.helper.VideoHelper; -import com.upchina.video.mapper.*; -import com.upchina.video.query.common.PullVideoPlayInfoDataQuery; -import com.upchina.video.service.admin.AdminVideoInteractionService; -import com.upchina.video.service.admin.AdminVideoQuestionService; -import com.upchina.video.service.app.AppVideoInfoService; -import com.upchina.video.service.app.AppVideoInteractionService; -import com.upchina.video.vo.cloud.VideoPlayInfoAdminVO; -import com.upchina.video.vo.common.VideoProductInfoVO; -import com.upchina.video.vo.info.VideoInfoAppVO; -import com.upchina.video.vo.message.VideoPcAdvisorMessageVO; -import com.upchina.video.vo.statistic.TXOnlineVO; -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -import javax.annotation.Resource; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - *

- * 公共函数 服务类 - *

- * - * @author fangliangbao - * @since 2022-09-21 - */ -@Service -public class VideoCommonService { - - @Value("${rsa.pubKey}") - private String ypPubKey; - - @Resource - private SensitiveWordService sensitiveWordService; - - @Resource - private VideoCloudService videoCloudService; - - @Resource - private RecommendService recommendService; - - @Resource - private MergeProductService mergeProductService; - - @Resource - private VideoCacheService videoCacheService; - - @Resource - private VideoLiveMapper videoLiveMapper; - - @Resource - private VideoMessageService videoMessageService; - - @Resource - private AdminVideoQuestionService adminVideoQuestionService; - - @Resource - private CommentBlackService commentBlackService; - - @Resource - private AppVideoInfoService appVideoInfoService; - - @Resource - private VideoCartMapper videoCartMapper; - - @Resource - private VideoBehaviorNotifyMapper videoBehaviorNotifyMapper; - - @Resource - private VideoUserFlowMapper videoUserFlowMapper; - - @Resource - private VideoLiveUserMapper videoLiveUserMapper; - - @Resource - private VideoLiveTagMapper videoLiveTagMapper; - - @Resource - private AppVideoInteractionService appVideoInteractionService; - - @Resource - private AdminVideoInteractionService adminVideoInteractionService; - - @Resource - private CacheService cacheService; - - // 防抖延时(ms) - private final long pushDelay = 10 * 1000; - - private final Map debounceMap = new HashMap<>(); - - /** - * 生成播放信息,包含直播相关地址 - * - * @param videoId 视频直播ID - * @param isApp 是否APP查询 - * @return 地址信息 - */ - public VideoPlayInfoAdminVO getPlayInfo(Integer videoId, boolean isApp) { - VideoLive video = videoCacheService.getVideoInfo(videoId); - if (video == null) { - throw new BizException(ResponseStatus.PRODUCT_NOT_EXIST); - } - VideoPlayInfoAdminVO vo = new VideoPlayInfoAdminVO(); - if (VideoPlayType.LIVE.value.equals(video.getPlayType())) { - // 直播(未结束) - if (!isApp && !VideoLiveStatus.HAS_ENDED.value.equals(video.getLiveStatus())) { - vo.setPushUrl(videoCloudService.getPushUrl(videoId)); - } - vo.setPlayUrl(videoCloudService.getLivePlayUrl(videoId)); - vo.setFlvUrl(videoCloudService.getLivePlayUrl(videoId, "flv")); - } else if (VideoPlayType.RECORD.value.equals(video.getPlayType())) { - // 录播 - if (video.getLibraryId() == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "未选择视频资源"); - } - VideoLiveLibrary library = videoCacheService.getVideoLibraryInfo(video.getLibraryId()); - if (library == null) { - throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "视频资源不存在"); - } - vo.setPlayUrl(videoCloudService.getPlayUrl(library.getFileId())); - vo.setPlayUrl(videoCloudService.getPlayUrl(library.getFileId())); - } - return vo; - } - - /** - * 手机号加密,非手机号直接返回 - * - * @param phone 手机号 - * @return 加密后的手机号 - */ - public String encryptPhone(String phone) { - if (VideoHelper.isPhone(phone)) { - return RsaUtil.pubKeyEncryption(ypPubKey, phone); - } - return phone; - } - - /** - * 敏感词检测 - * - * @param contents 检测内容集合 - */ - public void checkSensitiveWords(String... contents) { - List words = Stream.of(contents).filter(StringUtils::isNotEmpty).collect(Collectors.toList()); - if (words.isEmpty()) { - return; - } - sensitiveWordService.check(words); - } - - /** - * 校验推荐产品是否存在 - * - * @param type 产品类型 - * @param id 产品ID - * @param status 产品状态 - */ - public void validateRecommend(ProductType type, Integer id, VideoStatus status) { - if (VideoStatus.SOLD_OUT.equals(status)) { - recommendService.validateRecommendExist(type, id); - } - } - - /** - * 结束暂停中或直播中的直播 - * 下架设置回放过期时间的直播 - */ - public void stopLivingVideo() { - // 结束前一天直播 - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); - wrapper.select(VideoLive::getId, VideoLive::getEndTime) - .ne(VideoLive::getLiveStatus, VideoLiveStatus.HAS_ENDED.value) - .lt(VideoLive::getEndTime, LocalDate.now().atStartOfDay()); - List videoList = videoLiveMapper.selectList(wrapper); - LocalDateTime now = LocalDateTime.now(); - if (!videoList.isEmpty()) { - Map cacheMap = videoCacheService.getVideoCacheMap(); - videoList.forEach(v -> { - LocalDateTime realEndTime = LocalDateTime.of(v.getEndTime().toLocalDate(), LocalTime.MAX); - VideoLive entity = new VideoLive(v.getId(), VideoLiveStatus.HAS_ENDED.value, realEndTime); - entity.setStatus(VideoStatus.SOLD_OUT.value); - entity.setOnlineTop(adminVideoInteractionService.getOnlineMax(v.getId())); - // 插入直播观看人次 - Integer totalReadCount = adminVideoInteractionService.queryInteractionCount(v.getId(), VideoUserRecordType.READ, null, null, false); - entity.setLiveNum(totalReadCount); - videoLiveMapper.updateById(entity); - endVideo(cacheMap, v); - adminVideoQuestionService.stopByVideoId(v.getId()); - }); - } - // 回放过期 - wrapper = Wrappers.lambdaQuery() - .eq(VideoLive::getPlayType, VideoPlayType.LIVE.value) - .eq(VideoLive::getStatus, VideoStatus.PASS.value) - .eq(VideoLive::getLiveStatus, VideoLiveStatus.HAS_ENDED.value) - .isNotNull(VideoLive::getReplayExpireDays) - .gt(VideoLive::getReplayExpireDays, 0); - List expireVideoList = videoLiveMapper.selectList(wrapper); - for (VideoLive video : expireVideoList) { - // 下架设置回放过期时间的直播 - Integer expireDays = video.getReplayExpireDays(); - if (expireDays != null && expireDays != 0) { - LocalDateTime replayExpireTime = video.getStartTime().toLocalDate().plusDays(expireDays + 1).atStartOfDay(); - if (replayExpireTime.isBefore(now)) { - VideoLive soldOutVideo = new VideoLive(video.getId(), VideoStatus.SOLD_OUT); - videoLiveMapper.updateById(soldOutVideo); - videoCacheService.clearVideoCache(video); - } - } - } - videoCacheService.clearVideoCache(null); - } - - /** - * 结束直播 - * - * @param cacheMap 缓存 - * @param video 直播信息 - */ - public void endVideo(Map cacheMap, VideoLive video) { - // 清除直播状态缓存 - videoCacheService.clearVideoInfoCache(video.getId(), cacheMap); - // 已结束,中断投顾推流 - videoCloudService.dropLiveStream(video.getId()); - // 直播结束通知 - videoMessageService.publishLiveStatusNotification(video.getId(), VideoLiveStatus.HAS_ENDED.value); - // 直播状态推送(pc) - VideoPcAdvisorMessageVO pcAdvisorMessageVO = new VideoPcAdvisorMessageVO(VideoLiveStatus.HAS_ENDED.value); - videoMessageService.publishPcAdvisorMessage(video.getId(), pcAdvisorMessageVO); - } - - /** - * 更新录播直播状态 - */ - public void updateLiveStatus() { - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .select(VideoLive::getId, VideoLive::getStartTime, VideoLive::getEndTime) - .ne(VideoLive::getLiveStatus, VideoLiveStatus.HAS_ENDED.value) - .eq(VideoLive::getPlayType, VideoPlayType.RECORD.value) - .isNotNull(VideoLive::getStartTime) - .isNotNull(VideoLive::getEndTime); - LocalDateTime now = LocalDateTime.now(); - List notStart = new ArrayList<>(); - List started = new ArrayList<>(); - List hasEnded = new ArrayList<>(); - - videoLiveMapper.selectList(wrapper).forEach(v -> { - LocalDateTime startTime = v.getStartTime(); - LocalDateTime endTime = v.getEndTime(); - VideoLiveStatus videoLiveStatus = null; - if (now.isBefore(startTime)) { - notStart.add(v.getId()); - } else if (now.isAfter(startTime) && endTime.isAfter(now)) { - started.add(v.getId()); - videoLiveStatus = VideoLiveStatus.LIVING; - } else { - hasEnded.add(v.getId()); - videoLiveStatus = VideoLiveStatus.HAS_ENDED; - } - if (videoLiveStatus != null) { - videoMessageService.publishLiveStatusNotification(v.getId(), videoLiveStatus.value); - // 直播状态推送(pc) - VideoPcAdvisorMessageVO pcAdvisorMessageVO = new VideoPcAdvisorMessageVO(videoLiveStatus.value); - videoMessageService.publishPcAdvisorMessage(v.getId(), pcAdvisorMessageVO); - } - }); - - updateLiveStatusByIds(notStart, VideoLiveStatus.NOT_STARTED.value); - updateLiveStatusByIds(started, VideoLiveStatus.LIVING.value); - updateLiveStatusByIds(hasEnded, VideoLiveStatus.HAS_ENDED.value); - - Map cacheMap = videoCacheService.getVideoCacheMap(); - Stream.of(notStart, started, hasEnded).flatMap(List::stream) - .forEach(v -> videoCacheService.clearVideoInfoCache(v, cacheMap)); - videoCacheService.clearVideoCache(null); - } - - /** - * 刷新视频直播及课程观看数及用户(定时任务执行) - */ - public void saveCountAndUser() { - try { - LoggerUtil.video.info(">>>刷新视频直播播放量及观看用户任务开始"); - long start = System.currentTimeMillis(); - // 记录观看、购物车点击、分享用户 - videoCacheService.loadVideoRecordUserToDb(); - // 点赞 - appVideoInteractionService.saveFavor(); - LoggerUtil.video.info(">>>刷新视频直播播放量及观看用户耗时:" + (System.currentTimeMillis() - start)); - } catch (Exception e) { - LoggerUtil.error("刷新视频直播播放量及观看用户异常:" + ExceptionUtils.getStackTrace(e)); - } - } - - /** - * 用户消息被回复推送消息提醒 - */ - public void pushReplyVideoMessage(Integer videoId, Integer replyId, String replyText) { - } - - /** - * 直播互动消息禁言 - * - * @param phone 客户手机号 - */ - public boolean checkAppForbidden(String phone) { - Set blackUser = commentBlackService.getAllBlackUser(); - if (blackUser == null || StrUtil.isEmpty(phone)) { - return false; - } - return blackUser.contains(phone); - } - - /** - * 直播开播未观看提醒 - * - * @param video 直播信息 - */ - public void pushBeforeLiveMessage(VideoLive video) { - try { - Integer videoId = video.getId(); - String videoName = video.getTitle(); - List onlineList = videoCacheService.getOnlineList(videoId); - Set onlineUserIds = onlineList.stream().map(OnlineUser::getUserId).collect(Collectors.toSet()); - - // 查询预约的用户 - LambdaQueryWrapper subWrapper = Wrappers.lambdaQuery() - .select(VideoLiveUser::getUserId, VideoLiveUser::getUserName) - .eq(VideoLiveUser::getVideoId, videoId) - .eq(VideoLiveUser::getType, VideoUserRecordType.SUBSCRIBE.value) - .and(w -> w.isNull(VideoLiveUser::getHasNotified).or().eq(VideoLiveUser::getHasNotified, IsOrNot.NOT.value)); - List allSubUserList = videoLiveUserMapper.selectList(subWrapper); - - // 预约后未进入直播间用户 - List notOnlineUser = allSubUserList.stream() - .filter(user -> !onlineUserIds.contains(user.getUserId())).collect(Collectors.toList()); - - // 在线已退出用户,退出时间在直播已开始之后 - LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery() - .select(VideoUserFlow::getUserId) - .eq(VideoUserFlow::getVideoId, videoId); - List dbReadRecords = videoUserFlowMapper.selectList(queryWrapper); - List dbUserIds = dbReadRecords.stream() - .map(VideoUserFlow::getUserId).distinct().collect(Collectors.toList()); - - //预约后未进入直播间用户 - List notifyUserList = notOnlineUser.stream() - .filter(user -> !dbUserIds.contains(user.getUserId())).collect(Collectors.toList()); - List notifyUserIds = notifyUserList.stream().map(VideoLiveUser::getUserId).collect(Collectors.toList()); - - LoggerUtil.video.info("直播开播未及时观看提醒:直播【" + videoName + "】预约用户【" + notifyUserIds + "】"); - if (notifyUserIds.isEmpty()) { - return; - } - - // 开播前5分钟直播记录所有待通知用户 - String content = String.format("预约的直播【%s】已开播5分钟,尚未进入直播间", videoName); - List notifyList = notifyUserList.stream().map(user -> { - VideoBehaviorNotify notify = new VideoBehaviorNotify(); - notify.setUserId(user.getUserId()); - notify.setUserName(user.getUserName()); - notify.setPhone(user.getUserId()); - notify.setType(VideoNotifyType.SUBSCRIBE_UN_ENTER.value); - notify.setVideoId(videoId); - notify.setDescription(content); - notify.setNotifyTime(LocalDateTime.now()); - notify.setCreateTime(LocalDateTime.now()); - return notify; - }).collect(Collectors.toList()); - // 写入行为提醒 - videoBehaviorNotifyMapper.insertBatchSomeColumn(notifyList); - // 更新用户已提醒 - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .eq(VideoLiveUser::getType, VideoUserRecordType.SUBSCRIBE.value) - .eq(VideoLiveUser::getVideoId, videoId) - .in(VideoLiveUser::getUserId, notifyUserIds) - .ne(VideoLiveUser::getHasNotified, IsOrNot.IS.value); - videoLiveUserMapper.update(new VideoLiveUser(videoId, IsOrNot.IS.value, LocalDateTime.now()), wrapper); - } catch (Exception e) { - LoggerUtil.error("直播开播未观看提醒:异常-" + ExceptionUtils.getStackTrace(e)); - } - } - - /** - * 获取已排序的视频直播集合 - * - * @param videoIds 视频直播ID集合 - * @return 观看用户 - */ - public SortedSet getSortedVideos(Collection videoIds) { - SortedSet sortedSet = new TreeSet<>(AbstractVideoSortComparator.VIDEO_COMP_PLAN_LIST); - - videoIds.forEach(videoId -> { - VideoLive video = videoCacheService.getVideoInfo(videoId); - if (video == null) return; - - LocalDateTime startTime = Optional.ofNullable(video.getRealStartTime()).orElse(video.getStartTime()); - VideoLiveLibrary library = videoCacheService.getVideoLibrary(video.getId(), video.getLibraryId()); - boolean isRecord = IsOrNot.IS.value.equals(video.getIsGenerateRecord()); - - VideoSortEntity entity = new VideoSortEntity(); - entity.setId(video.getId()); - entity.setName(video.getTitle()); - entity.setTime(startTime); - entity.setCount(videoCacheService.getVideoReadCount(videoId)); - entity.setPlayType(video.getPlayType()); - entity.setLiveStatus(video.getLiveStatus()); - entity.setLibCount(isRecord && library != null ? 1 : 0); - entity.setCreateTime(video.getCreateTime()); - entity.setAuditTime(video.getAuditTime()); - entity.setNewLiveStatus(appVideoInfoService.getNewStatus(entity.getLiveStatus())); - - sortedSet.add(entity); - }); - - return sortedSet; - } - - /** - * 获取视频直播关联产品信息 - * - * @param videoId 视频直播ID - * @param typeAndIds 关联产品类型和ID - * @return 关联产品信息 - */ - public List getMergeProductList(Integer videoId, String[] typeAndIds) { - try { - List list = Arrays.stream(typeAndIds) - .map(v -> { - String[] typeAndId = v.split(":"); - VideoLiveProduct vp = new VideoLiveProduct(); - vp.setType(VideoRelativeProduct.RECOMMEND.value); - vp.setProductType(Integer.parseInt(typeAndId[0])); - vp.setProductId(Integer.parseInt(typeAndId[1])); - return vp; - }).collect(Collectors.toList()); - - if (list.size() == 1) { - VideoLiveProduct product = list.get(0); - if (ProductType.CUSTOM_PRODUCT.value.equals(product.getProductType())) { - VideoCart cart = videoCartMapper.selectOne(Wrappers.lambdaQuery() - .eq(VideoCart::getVideoId, videoId) - .eq(VideoCart::getProductId, product.getProductId()) - .eq(VideoCart::getProductType, product.getProductType())); - return Collections.singletonList(new VideoProductInfoVO(cart.getProductId(), cart.getProductType(), cart.getProductName(), cart.getProductDesc(), cart.getUrl())); - } - } - - Integer videoType = ProductType.VIDEO_SINGLE.value; - List pList = list.stream() - .filter(v -> !(videoType.equals(v.getProductType()) && Objects.equals(videoId, v.getProductId()))) - .collect(Collectors.toList()); - - VideoLive video = videoCacheService.getVideoInfo(videoId); - if (video == null) { - return Collections.emptyList(); - } - - Table table = mergeProductService.queryMergeProductInfo(pList, true); - - return list.stream().map(v -> { - VideoProductInfoVO prd; - if (videoType.equals(v.getProductType()) && Objects.equals(videoId, v.getProductId())) { - prd = new VideoProductInfoVO(v, video.getTitle(), video.getViewPoint(), video.getAuthorityId()); - } else { - prd = getProductInfo(table, v); - } - return prd; - }).collect(Collectors.toList()); - } catch (Exception e) { - LoggerUtil.error("视频直播查询关联产品错误:" + ExceptionUtils.getStackTrace(e)); - return new ArrayList<>(0); - } - } - - /** - * 获取腾讯云实时在线人数 - * - * @param videoId 视频ID - * @return TXOnlineVO对象,包含实时在线人数和直播状态 - */ - public TXOnlineVO txonline(Integer videoId) { - VideoLive videoInfo = videoCacheService.getVideoInfo(videoId); - Integer txonline = cacheService.get(CacheKey.VIDEO_TX_ONLINE, CacheKey.TXKey.VIDEO_ONLINE_TX + videoId, () -> { - LocalDateTime now = LocalDateTime.now().minusMinutes(1); - VideoLive videoLive = videoLiveMapper.selectById(videoId); - PullVideoPlayInfoDataQuery query = new PullVideoPlayInfoDataQuery(); - query.setVideoId(String.valueOf(videoId)); - query.setStartTime(videoLive.getRealStartTime()); - query.setEndTime(videoLive.getRealEndTime() == null ? now : videoLive.getRealEndTime()); - List trends = videoCloudService.pullVideoPlayInfoData(query); - return CollUtil.isEmpty(trends) ? 0 : trends.get(trends.size() - 1).getOnline(); - }); - return new TXOnlineVO(txonline, videoInfo == null ? null : videoInfo.getLiveStatus()); - } - - /** - * 检查标签是否被使用 - * - * @param id 标签ID - * @return 是否被使用 - */ - public boolean checkUseTag(Integer id) { - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .eq(VideoLiveTag::getTagId, id); - return videoLiveTagMapper.exists(wrapper); - } - - private void updateLiveStatusByIds(List ids, Integer status) { - if (!ids.isEmpty()) { - QueryWrapper wrapper = Wrappers.query(); - wrapper.in("id", ids); - videoLiveMapper.update(new VideoLive(status), wrapper); - } - } - - private VideoProductInfoVO getProductInfo(Table table, VideoLiveProduct product) { - try { - Integer productType = product.getProductType(); - Object detail = table.get(productType, product.getProductId()); - if (detail == null) { - return null; - } - if (ProductType.VIDEO_SINGLE.value.equals(productType)) { - VideoInfoAppVO vo = (VideoInfoAppVO) detail; - return new VideoProductInfoVO(product, vo.getTitle(), vo.getViewPoint(), null); - } - return null; - } catch (Exception e) { - LoggerUtil.error("视频直播查询推广产品错误:" + ExceptionUtils.getStackTrace(e)); - return null; - } - } - - public synchronized void publishPcMessageWithDebounce(Integer videoId) { - Debounce debounce = debounceMap.get(videoId); - if (debounce == null) { - debounce = new Debounce(); - debounceMap.put(videoId, debounce); - } - // 防抖执行 - debounce.debounce(() -> this.publishPcMessage(videoId), pushDelay); - } - - private void publishPcMessage(Integer videoId) { - //点赞数 - Integer favorCount = videoCacheService.getVideoFavorUserCount(videoId); - //观看 - Integer readCount = videoCacheService.getVideoReadCount(videoId); - //在线数 - int onlineCount = videoCacheService.getOnlineCount(videoId); - VideoPcAdvisorMessageVO messageVO = new VideoPcAdvisorMessageVO(favorCount, readCount, onlineCount); - videoMessageService.publishPcAdvisorMessage(videoId, messageVO); - } - -} diff --git a/src/main/java/com/upchina/video/vo/cart/CouponVO.java~ b/src/main/java/com/upchina/video/vo/cart/CouponVO.java~ deleted file mode 100644 index 9f40d5d..0000000 --- a/src/main/java/com/upchina/video/vo/cart/CouponVO.java~ +++ /dev/null @@ -1,249 +0,0 @@ -package com.upchina.video.vo.cart; - -import cn.hutool.core.util.StrUtil; -import com.upchina.dyqh.QuerySendCouponReq; -import io.swagger.annotations.ApiModelProperty; - -import java.io.Serializable; - -public class CouponVO implements Serializable { - - private static final long serialVersionUID = 1L; - - @ApiModelProperty("领券关联id") - public int sendCouponId = 0; - - @ApiModelProperty("优惠券批次名称") - public String name = ""; - - @ApiModelProperty("优惠券类型 1-体验券;2-折扣券 3-满减券") - public int couponType = 0; - - @ApiModelProperty("满减券-优惠金额 (单位:元)") - public double discount = 0D; - - @ApiModelProperty("折扣券-折扣率") - public double discountPercent = 0D; - - @ApiModelProperty("体验券,体验数") - public int discountNum = 0; - - @ApiModelProperty("体验券,体验时长,1-天;2-月") - public int discountNumType = 0; - - @ApiModelProperty("适用产品范围类型,逗号分割,0:全场通用1:指定产品可用") - public int scopeType = 0; - - @ApiModelProperty("优惠券有效期起始日") - public String validStart; - - @ApiModelProperty("优惠券有效期截止日") - public String validEnd; - - @ApiModelProperty("订单使用优惠券最低限额(单位:元)0表示不限制 使用优惠券前的订单金额大于等于此金额才能使用优惠券") - public double basicConsume = 0D; - - @ApiModelProperty("订单最低使用金额限制(单位:元)0表示不限制 使用优惠券后订单金额不能低于此金额") - public double basicUsedAmt = 0D; - - @ApiModelProperty("折扣券,最多优惠 (单位:元),0表示没有限制") - public double discountLimit = 0D; - - @ApiModelProperty("领取要求: 0 无要求, 1 关注主播, 2 评论互动") - private Integer receiveRequirement; - - @ApiModelProperty("视频直播id") - private Integer liveId; - - @ApiModelProperty("视频直播id") - private Integer validDays; - - @ApiModelProperty(value = "发放数量", example = "100") - private Integer sendTotalNumber; - - @ApiModelProperty(value = "已领取数量", example = "10") - private Integer sendGottenNumber; - - @ApiModelProperty(value = "已使用数量", example = "1") - private Integer sendUsedNumber; - - public CouponVO() { - } - - public int getSendCouponId() { - return sendCouponId; - } - - public void setSendCouponId(int sendCouponId) { - this.sendCouponId = sendCouponId; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getCouponType() { - return couponType; - } - - public void setCouponType(int couponType) { - this.couponType = couponType; - } - - public double getDiscount() { - return discount; - } - - public void setDiscount(double discount) { - this.discount = discount; - } - - public double getDiscountPercent() { - return discountPercent; - } - - public void setDiscountPercent(double discountPercent) { - this.discountPercent = discountPercent; - } - - public int getDiscountNum() { - return discountNum; - } - - public void setDiscountNum(int discountNum) { - this.discountNum = discountNum; - } - - public int getDiscountNumType() { - return discountNumType; - } - - public void setDiscountNumType(int discountNumType) { - this.discountNumType = discountNumType; - } - - public int getScopeType() { - return scopeType; - } - - public void setScopeType(int scopeType) { - this.scopeType = scopeType; - } - - public String getValidStart() { - return validStart; - } - - public void setValidStart(String validStart) { - this.validStart = validStart; - } - - public String getValidEnd() { - return validEnd; - } - - public void setValidEnd(String validEnd) { - this.validEnd = validEnd; - } - - public Integer getReceiveRequirement() { - return receiveRequirement; - } - - public void setReceiveRequirement(Integer receiveRequirement) { - this.receiveRequirement = receiveRequirement; - } - - public double getBasicConsume() { - return basicConsume; - } - - public void setBasicConsume(double basicConsume) { - this.basicConsume = basicConsume; - } - - public double getBasicUsedAmt() { - return basicUsedAmt; - } - - public void setBasicUsedAmt(double basicUsedAmt) { - this.basicUsedAmt = basicUsedAmt; - } - - public double getDiscountLimit() { - return discountLimit; - } - - public void setDiscountLimit(double discountLimit) { - this.discountLimit = discountLimit; - } - - public Integer getLiveId() { - return liveId; - } - - public void setLiveId(Integer liveId) { - this.liveId = liveId; - } - - public Integer getValidDays() { - return validDays; - } - - public void setValidDays(Integer validDays) { - this.validDays = validDays; - } - - public Integer getSendTotalNumber() { - return sendTotalNumber; - } - - public void setSendTotalNumber(Integer sendTotalNumber) { - this.sendTotalNumber = sendTotalNumber; - } - - public Integer getSendGottenNumber() { - return sendGottenNumber; - } - - public void setSendGottenNumber(Integer sendGottenNumber) { - this.sendGottenNumber = sendGottenNumber; - } - - public Integer getSendUsedNumber() { - return sendUsedNumber; - } - - public void setSendUsedNumber(Integer sendUsedNumber) { - this.sendUsedNumber = sendUsedNumber; - } - - @Override - public String toString() { - return "CouponVO{" + - "sendCouponId=" + sendCouponId + - ", name='" + name + '\'' + - ", couponType=" + couponType + - ", discount=" + discount + - ", discountPercent=" + discountPercent + - ", discountNum=" + discountNum + - ", discountNumType=" + discountNumType + - ", scopeType=" + scopeType + - ", validStart='" + validStart + '\'' + - ", validEnd='" + validEnd + '\'' + - ", basicConsume=" + basicConsume + - ", basicUsedAmt=" + basicUsedAmt + - ", discountLimit=" + discountLimit + - ", receiveRequirement=" + receiveRequirement + - ", liveId=" + liveId + - ", validDays=" + validDays + - ", sendTotalNumber=" + sendTotalNumber + - ", sendGottenNumber=" + sendGottenNumber + - ", sendUsedNumber=" + sendUsedNumber + - '}'; - } -} diff --git a/src/main/java/com/upchina/video/vo/message/VideoMessageBasicVO.java~ b/src/main/java/com/upchina/video/vo/message/VideoMessageBasicVO.java~ deleted file mode 100644 index adb04e0..0000000 --- a/src/main/java/com/upchina/video/vo/message/VideoMessageBasicVO.java~ +++ /dev/null @@ -1,126 +0,0 @@ -package com.upchina.video.vo.message; - -import cn.hutool.core.util.StrUtil; -import com.upchina.video.entity.VideoLiveMessage; -import com.upchina.video.helper.VideoHelper; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; - -import java.io.Serializable; -import java.time.LocalDateTime; - -/** - *

- * 互动消息基本信息 - *

- * - * @author fangliangbao - * @since 2022-11-01 - */ -@ApiModel("互动消息基本信息") -public class VideoMessageBasicVO implements Serializable { - - private static final long serialVersionUID = 1L; - - @ApiModelProperty("ID") - private Integer id; - - @ApiModelProperty("用户ID") - private String userId; - - @ApiModelProperty("用户名称") - private String userName; - - @ApiModelProperty("消息内容") - private String content; - - @ApiModelProperty("回复时间") - private LocalDateTime replyTime; - - @ApiModelProperty("是否公开 1公开 2不公开") - private Integer isOpen; - - public static VideoMessageBasicVO toVo(VideoLiveMessage message, boolean needMask) { - if (message == null) { - return null; - } - VideoMessageBasicVO vo = new VideoMessageBasicVO(); - vo.setId(message.getId()); - if (needMask) { - vo.setUserId(VideoHelper.maskPhone(message.getUserId())); - if (StringUtils.isNotEmpty(message.getUserName())) { -// vo.setUserName(VideoHelper.maskUserName(message.getUserName())); - vo.setUserName(message.getUserName()); - } else { - vo.setUserName(VideoHelper.maskPhone(message.getUserId())); - } - } else { - vo.setUserId(message.getUserId()); - vo.setUserName(message.getUserName()); - } - vo.setContent(message.getContent()); - vo.setReplyTime(message.getCreateTime()); - vo.setIsOpen(message.getIsOpen()); - return vo; - } - - public Integer getId() { - return id; - } - - public void setId(Integer id) { - this.id = id; - } - - public String getUserId() { - return userId; - } - - public void setUserId(String userId) { - this.userId = userId; - } - - public String getUserName() { - return userName; - } - - public void setUserName(String userName) { - this.userName = userName; - } - - public String getContent() { - return content; - } - - public void setContent(String content) { - this.content = content; - } - - public LocalDateTime getReplyTime() { - return replyTime; - } - - public void setReplyTime(LocalDateTime replyTime) { - this.replyTime = replyTime; - } - - public Integer getIsOpen() { - return isOpen; - } - - public void setIsOpen(Integer isOpen) { - this.isOpen = isOpen; - } - - @Override - public String toString() { - return "VideoMessageBasicVO{" + - "id=" + id + - ", userId='" + userId + '\'' + - ", userName='" + userName + '\'' + - ", content='" + content + '\'' + - ", replyTime=" + replyTime + - ", isOpen=" + isOpen + - '}'; - } -}