temp
This commit is contained in:
parent
fdc4a4aeb9
commit
f1b0cba4bd
@ -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<String, List<Object>> queryVideoCoupon(Integer videoId) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询用户优惠券
|
|
||||||
*
|
|
||||||
* @param userId 用户ID
|
|
||||||
* @return 优惠券Map key: 视频ID value: 优惠券列表
|
|
||||||
*/
|
|
||||||
public Map<Integer, List<Object>> queryUserCoupon(String userId) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int queryCouponCount(Integer videoId) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<UserCoupon> queryCoupon(Integer videoId, String userId) {
|
|
||||||
List<UserCoupon> 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<LiveCouponRsp> 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -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<Object> arguments = new ArrayList<>();
|
|
||||||
String destination = "";
|
|
||||||
for (Object arg : args) {
|
|
||||||
if (arg instanceof SimpMessageHeaderAccessor) {
|
|
||||||
SimpMessageHeaderAccessor accessor = (SimpMessageHeaderAccessor) arg;
|
|
||||||
destination = accessor.getDestination();
|
|
||||||
Map<String, Object> 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<Object> 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<String, Object> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -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());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* WebSocket处理ERROR指令错误
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @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<byte[]> 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());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* WebSocket连结token鉴权
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @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<String, Object> 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<String, Object> 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<String, OnlineUser> 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<String, OnlineUser> 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) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -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<Integer, Integer> positionProductTypeMap = HashMultimap.create();
|
|
||||||
// 产品类型和推荐位置关系
|
|
||||||
private static final Multimap<Integer, Integer> productTypePositionMap = HashMultimap.create();
|
|
||||||
|
|
||||||
private static void putRelation(Integer advertPosition, Collection<Integer> 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<AdvertVO> list(ListAdvertQuery query) {
|
|
||||||
Integer productType = query.getProductType();
|
|
||||||
Integer productId = query.getProductId();
|
|
||||||
String name = query.getName();
|
|
||||||
Integer position = query.getPosition();
|
|
||||||
Integer createUserId = query.getCreateUserId();
|
|
||||||
QueryWrapper<Advert> 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<Advert> page = advertMapper.selectPage(query.toPage(), wrapper);
|
|
||||||
Map<Integer, UserDept> userMap = userService.getUserMap();
|
|
||||||
List<AdvertVO> list = page.getRecords().stream().map(advert -> new AdvertVO(advert, userMap.get(advert.getCreateUserId()))).collect(Collectors.toList());
|
|
||||||
// 填充非H5类型的产品名称
|
|
||||||
List<AdvertVO> filterH5List = list.stream().filter(vo -> !ProductType.H5.value.equals(vo.getProductType())).collect(Collectors.toList());
|
|
||||||
Table<Integer, Integer, MergeProductInfoVO> 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<AdvertAppVO> listForApp(Integer position) {
|
|
||||||
return cacheService.get(CacheKey.ADVERT, CacheKey.AdvertKey.APP_ADVERT_LIST + position, () -> {
|
|
||||||
QueryWrapper<Advert> wrapper = Wrappers.query();
|
|
||||||
wrapper.eq("position", position).last("order by weight desc,create_time desc");
|
|
||||||
List<Advert> list = advertMapper.selectList(wrapper);
|
|
||||||
return list.stream().map(AdvertAppVO::new).collect(Collectors.toList());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearCache(AdvertPosition position) {
|
|
||||||
Map<String, Object> cacheMap = hazelcastInstance.getMap(CacheKey.ADVERT);
|
|
||||||
cacheMap.remove(CacheKey.AdvertKey.APP_ADVERT_LIST + position.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearCache(ProductType productType) {
|
|
||||||
Map<String, Object> cacheMap = hazelcastInstance.getMap(CacheKey.ADVERT);
|
|
||||||
Collection<Integer> 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<Integer> 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<Advert> 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -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<String> getAllBlackUser() {
|
|
||||||
LocalDateTime now = LocalDateTime.now();
|
|
||||||
List<CommentBlack> list = cacheService.get(COMMENT_BLACK, ALL_BLACK_USER, () -> {
|
|
||||||
QueryWrapper<CommentBlack> wrapper = Wrappers.query();
|
|
||||||
wrapper.in("status", Arrays.asList(CommentBlackStatus.EFFECT.value, CommentBlackStatus.EXPIRED.value));
|
|
||||||
List<CommentBlack> 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<String> 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<CommentBlack> 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<CommentBlack> 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<CommentBlack> 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<CommentBlackVO> 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<Integer> advisorIdSet = authService.getAccessibleAdviserSet(null, backendUserVO, UserType.fromValue(commentBlackQuery.getUserType()));
|
|
||||||
if (advisorIdSet != null && advisorIdSet.isEmpty()) {
|
|
||||||
return Pager.emptyPager();
|
|
||||||
}*/
|
|
||||||
QueryWrapper<CommentBlack> 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<CommentBlack> page = commentBlackMapper.selectPage(commentBlackQuery.toPage(), wrapper);
|
|
||||||
List<CommentBlack> list = page.getRecords();
|
|
||||||
if (CollectionUtils.isEmpty(list)) {
|
|
||||||
return Pager.emptyPager();
|
|
||||||
}
|
|
||||||
List<BaseProductQuery> 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<Integer, Integer, MergeProductInfoVO> productTable = mergeProductService.queryMergeProductInfo(baseProductQueryList);
|
|
||||||
Map<Integer, UserDept> userMap = userService.getUserMap();
|
|
||||||
Map<String, Dept> deptMap = deptService.getDeptMap();
|
|
||||||
List<CommentBlackVO> 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<String> cacheKeys) {
|
|
||||||
IMap<String, Object> cacheMap = hazelcastInstance.getMap(COMMENT_BLACK);
|
|
||||||
for (String key : cacheKeys) {
|
|
||||||
cacheMap.remove(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 校验是否禁言
|
|
||||||
*/
|
|
||||||
public void check(String phone) {
|
|
||||||
// 判断是否禁言用户
|
|
||||||
Set<String> blackUsers = getAllBlackUser();
|
|
||||||
if (CollUtil.isNotEmpty(blackUsers) && blackUsers.contains(phone)) {
|
|
||||||
throw new BizException("禁言用户,禁止发言");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* 服务类
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @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<SensitiveWordVO> list(KeywordPageQuery query) {
|
|
||||||
String keyword = query.getKeyword();
|
|
||||||
QueryWrapper<SensitiveWord> wrapper = Wrappers.query();
|
|
||||||
wrapper.like(StrUtil.isNotEmpty(keyword), "word", keyword).orderByDesc("create_time");
|
|
||||||
Page<SensitiveWord> page = sensitiveWordMapper.selectPage(query.toPage(), wrapper);
|
|
||||||
List<SensitiveWordVO> 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<SensitiveWord> wrapper = Wrappers.query();
|
|
||||||
query.setWords(query.getWords().stream().distinct().collect(Collectors.toList()));
|
|
||||||
wrapper.in("word", query.getWords());
|
|
||||||
sensitiveWordMapper.delete(wrapper);
|
|
||||||
List<SensitiveWord> 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<String> textList) {
|
|
||||||
if (textList.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Trie trie = this.getTrie(true);
|
|
||||||
for (String text : textList) {
|
|
||||||
Collection<Emit> emits = trie.parseText(text);
|
|
||||||
if (!emits.isEmpty()) {
|
|
||||||
Set<String> 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<SensitiveWord> list = sensitiveWordMapper.selectList(Wrappers.emptyWrapper());
|
|
||||||
for (SensitiveWord word : list) {
|
|
||||||
trieBuilder.addKeyword(word.getWord());
|
|
||||||
}
|
|
||||||
trieBuildTime = System.currentTimeMillis();
|
|
||||||
trie = trieBuilder.build();
|
|
||||||
return trie;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -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) + "*";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -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));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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<SerialStatus> 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<String, Object> 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<SerialVO> 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<Integer> authSet = null;
|
|
||||||
if (backendUserVO != null) {
|
|
||||||
authSet = authService.getAuthByUserType(VideoUserType.format(userType), backendUserVO, true);
|
|
||||||
if (authSet != null && authSet.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LambdaQueryWrapper<Serial> wrapper = Wrappers.<Serial>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<Serial> page = serialMapper.selectPage(query.toPage(), wrapper);
|
|
||||||
Map<Integer, String> advisorNameMap = advisorInfoService.getAdvisorMap().values().stream()
|
|
||||||
.collect(Collectors.toMap(AdvisorBasic::getId, AdvisorBasic::getName));
|
|
||||||
Map<Integer, String> userNameMap = userService.getUserMap().values().stream()
|
|
||||||
.collect(Collectors.toMap(UserDept::getUserId, UserDept::getName));
|
|
||||||
List<SerialVO> 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<Integer, String> advisorNameMap = advisorInfoService.getAdvisorMap().values().stream()
|
|
||||||
.collect(Collectors.toMap(AdvisorBasic::getId, AdvisorBasic::getName));
|
|
||||||
Map<Integer, String> 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<SerialContentVO> 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<SerialContent> wrapper = Wrappers.<SerialContent>lambdaQuery()
|
|
||||||
.eq(SerialContent::getSerialId, query.getId())
|
|
||||||
.eq(SerialContent::getType, type)
|
|
||||||
.orderByDesc(SerialContent::getIsRecommend, SerialContent::getCreateTime);
|
|
||||||
Page<SerialContent> page = serialContentMapper.selectPage(query.toPage(), wrapper);
|
|
||||||
List<SerialContentVO> 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<SerialContent> wrapper = Wrappers.<SerialContent>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<SerialContentVO> 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<SerialContentVO> 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<SerialContent> wrapper = Wrappers.<SerialContent>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<Integer> serialIds) {
|
|
||||||
LambdaQueryWrapper<SerialContent> wrapper = Wrappers.<SerialContent>lambdaQuery()
|
|
||||||
.select(SerialContent::getSerialId)
|
|
||||||
.eq(SerialContent::getContentId, contentId)
|
|
||||||
.eq(SerialContent::getType, contentType.value);
|
|
||||||
List<SerialContent> existSerialList = serialContentMapper.selectList(wrapper);
|
|
||||||
Set<Integer> existSerialIdSet = existSerialList.stream().map(SerialContent::getSerialId).collect(Collectors.toSet());
|
|
||||||
LocalDateTime now = LocalDateTime.now();
|
|
||||||
if (CollUtil.isNotEmpty(serialIds)) {
|
|
||||||
// 添加新增的
|
|
||||||
List<SerialContent> 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<SerialContent> deleteWrapper = Wrappers.<SerialContent>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<SerialContent> wrapper = Wrappers.<SerialContent>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<CourseContent> wrapper = Wrappers.<CourseContent>lambdaQuery()
|
|
||||||
.select(CourseContent::getCourseId)
|
|
||||||
.eq(CourseContent::getContentId, id)
|
|
||||||
.eq(CourseContent::getType, CourseContentType.SERIAL.value);
|
|
||||||
List<CourseContent> 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<SerialContent> contentListPO, UpdateContentEvent event) {
|
|
||||||
LambdaQueryWrapper<SerialContent> wrapper = Wrappers.<SerialContent>lambdaQuery()
|
|
||||||
.select(SerialContent::getContentId)
|
|
||||||
.eq(SerialContent::getSerialId, serialId)
|
|
||||||
.eq(SerialContent::getType, contentType);
|
|
||||||
List<SerialContent> existContentList = serialContentMapper.selectList(wrapper);
|
|
||||||
Set<Integer> existContentIdSet = existContentList.stream().map(SerialContent::getContentId).collect(Collectors.toSet());
|
|
||||||
if (UpdateContentEvent.SAVE.equals(event) || UpdateContentEvent.ADD.equals(event)) {
|
|
||||||
// 添加新增的
|
|
||||||
List<SerialContent> 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<SerialContent> contentStream = Stream.empty();
|
|
||||||
if (UpdateContentEvent.SAVE.equals(event)) {
|
|
||||||
// 删除多余的
|
|
||||||
Set<Integer> 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<SerialContent> deleteWrapper = Wrappers.<SerialContent>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(","));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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<ShortVideoStatus> 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<String, Object> 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<ShortVideoCart> cartList = query.toCartListPO(id);
|
|
||||||
saveCartList(id, cartList);
|
|
||||||
} else {
|
|
||||||
removeCartList(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存合集
|
|
||||||
if (CollUtil.isNotEmpty(query.getSerialIds())) {
|
|
||||||
serialService.saveContentList(id, SerialType.SHORT_VIDEO, query.getSerialIds());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查转码状态,防止先转码成功,数据还没有保存的问题
|
|
||||||
List<CloudMediaEntity> 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<VideoTransFlow>()
|
|
||||||
.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<ShortVideoCart> 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<ShortVideoVO> 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<Integer> authSet = authService.getAuthByUserType(VideoUserType.format(userType), backendUserVO, true);
|
|
||||||
if (authSet != null && authSet.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
LambdaQueryWrapper<ShortVideo> wrapper = Wrappers.<ShortVideo>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<ShortVideo> page = shortVideoMapper.selectPage(query.toPage(), wrapper);
|
|
||||||
Map<Integer, AdvisorBasicVO> advisorMap = advisorInfoService.getAdvisorVoMap();
|
|
||||||
Map<Integer, String> userNameMap = userService.getUserMap().values().stream()
|
|
||||||
.collect(Collectors.toMap(UserDept::getUserId, UserDept::getName));
|
|
||||||
List<ShortVideoVO> 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<Integer, AdvisorBasicVO> advisorMap = advisorInfoService.getAdvisorVoMap();
|
|
||||||
Map<Integer, String> 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<ShortVideoCart> cartList = shortVideoCartMapper.selectList(Wrappers.<ShortVideoCart>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<ShortVideoCart> wrapper = Wrappers.<ShortVideoCart>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<ShortVideoSale> saleWrapper = Wrappers.<ShortVideoSale>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<ShortVideoFavor> wrapper = Wrappers.<ShortVideoFavor>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<ShortVideoVO> 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<CourseSortEntity> sortedSet = cacheService.get(courseCache, CacheKey.CourseKey.MAIN_SHORT_VIDEO_LIST + id, () -> {
|
|
||||||
LambdaQueryWrapper<ShortVideo> wrapper = Wrappers.<ShortVideo>lambdaQuery()
|
|
||||||
.eq(ShortVideo::getAdvisorId, id)
|
|
||||||
.eq(ShortVideo::getStatus, CourseStatus.AUDITED.value)
|
|
||||||
.eq(ShortVideo::getIsDisplay, IsDisplay.YES.value)
|
|
||||||
.orderByDesc(ShortVideo::getIsRecommend, ShortVideo::getAuditTime);
|
|
||||||
List<ShortVideo> list = shortVideoMapper.selectList(wrapper);
|
|
||||||
NavigableSet<CourseSortEntity> 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<ShortVideoVO> voList = new ArrayList<>(size);
|
|
||||||
Iterator<CourseSortEntity> 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<ShortVideoWatchVO> cacheList = hazelcastInstance.getList(CacheKey.CourseKey.SHORT_VIDEO_WATCH_LIST);
|
|
||||||
List<ShortVideoWatchVO> 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<ShortVideoShare> wrapper = Wrappers.<ShortVideoShare>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<String> fileIds) {
|
|
||||||
try {
|
|
||||||
if (CollUtil.isEmpty(fileIds)) {
|
|
||||||
LambdaQueryWrapper<ShortVideo> wrapper = Wrappers.<ShortVideo>lambdaQuery()
|
|
||||||
.select(ShortVideo::getFileId)
|
|
||||||
.eq(ShortVideo::getTransStatus, TransStatus.TRANSCODING.value)
|
|
||||||
.isNotNull(ShortVideo::getFileId);
|
|
||||||
List<ShortVideo> transcodingVideoList = shortVideoMapper.selectList(wrapper);
|
|
||||||
fileIds = transcodingVideoList.stream().map(ShortVideo::getFileId).collect(Collectors.toSet());
|
|
||||||
}
|
|
||||||
if (CollUtil.isEmpty(fileIds)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<CloudMediaEntity> list = videoCloudService.describeMediaInfos(fileIds);
|
|
||||||
for (CloudMediaEntity media : list) {
|
|
||||||
try {
|
|
||||||
if (Objects.equals(media.getTransStatus(), VideoTransStatus.HAS_TRANSCODE.value)) {
|
|
||||||
LambdaQueryWrapper<ShortVideo> updateWrapper = Wrappers.<ShortVideo>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<ShortVideoWatchVO> cacheList = hazelcastInstance.getList(CacheKey.CourseKey.SHORT_VIDEO_WATCH_LIST);
|
|
||||||
// 合并重复项
|
|
||||||
Set<Integer> videoIdSet = new HashSet<>();
|
|
||||||
Map<ShortVideoWatchVO, ShortVideoWatch> 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<ShortVideo> videoList = shortVideoMapper.selectBatchIds(videoIdSet);
|
|
||||||
Map<Integer, ShortVideo> 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<ShortVideoWatch> wrapper = Wrappers.<ShortVideoWatch>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<ShortVideoCollectVO> 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<ShortVideoWatch> wrapper = Wrappers.<ShortVideoWatch>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<ShortVideoWatch> page = shortVideoWatchMapper.selectPage(query.toPage(), wrapper);
|
|
||||||
Set<String> userIds = page.getRecords().stream().map(ShortVideoWatch::getUserId).filter(StrUtil::isNotBlank).collect(Collectors.toSet());
|
|
||||||
Map<String, Integer> userSaleIdMap = new HashMap<>();
|
|
||||||
Map<Integer, String> userNameMap = userService.getUserMap().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getName()));
|
|
||||||
if (CollUtil.isNotEmpty(userIds)) {
|
|
||||||
LambdaQueryWrapper<ShortVideoSale> saleWrapper = Wrappers.<ShortVideoSale>lambdaQuery()
|
|
||||||
.eq(ShortVideoSale::getVideoId, id)
|
|
||||||
.in(ShortVideoSale::getUserId, userIds);
|
|
||||||
shortVideoSaleMapper.selectList(saleWrapper).forEach(sale -> userSaleIdMap.put(sale.getUserId(), sale.getSaleUserId()));
|
|
||||||
}
|
|
||||||
List<ShortVideoCollectVO> 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<ShortVideoCartClick> cartClickWrapper = Wrappers.<ShortVideoCartClick>lambdaQuery()
|
|
||||||
.select(ShortVideoCartClick::getProductName)
|
|
||||||
.eq(ShortVideoCartClick::getUserId, userId)
|
|
||||||
.eq(ShortVideoCartClick::getVideoId, id);
|
|
||||||
List<ShortVideoCartClick> clickList = shortVideoCartClickMapper.selectList(cartClickWrapper);
|
|
||||||
List<String> 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<ShortVideoWatch> wrapper = Wrappers.<ShortVideoWatch>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<ShortVideoShare> shareWrapper = Wrappers.<ShortVideoShare>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<String> favorUserIds = getFavorSet(videoId);
|
|
||||||
return favorUserIds.contains(userId) ? IsLike.YES.value : IsLike.NO.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ISet<String> getFavorSet(Integer videoId) {
|
|
||||||
return cacheService.getSet(CacheKey.CourseKey.SHORT_VIDEO_FAVOR_USER_IDS + videoId, () -> {
|
|
||||||
LambdaQueryWrapper<ShortVideoFavor> wrapper = Wrappers.<ShortVideoFavor>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<ShortVideoCart> cartList) {
|
|
||||||
removeCartList(id);
|
|
||||||
if (CollUtil.isNotEmpty(cartList)) {
|
|
||||||
shortVideoCartMapper.insertBatchSomeColumn(cartList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void removeCartList(Integer id) {
|
|
||||||
LambdaQueryWrapper<ShortVideoCart> wrapper = Wrappers.<ShortVideoCart>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<ShortVideoShare> wrapper = Wrappers.<ShortVideoShare>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<SerialVO> 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<SerialVO> page = serialService.list(query, userVO);
|
|
||||||
return page.getList();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -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<MenuVO> list(ListMenuQuery query, Integer userId, boolean buildTree) {
|
|
||||||
String keyword = query.getKeyword();
|
|
||||||
Integer roleId = query.getRoleId();
|
|
||||||
List<Menu> searchList;
|
|
||||||
List<MenuVO> searchVoList;
|
|
||||||
List<MenuVO> allVoList;
|
|
||||||
QueryWrapper<Menu> 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<Menu> allList = menuMapper.selectList(allWrapper);
|
|
||||||
allVoList = allList.stream().map(MenuVO::new).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 填充权限
|
|
||||||
List<Permission> allPermissionList = permissionMapper.selectList(Wrappers.emptyWrapper());
|
|
||||||
Map<Integer, List<PermissionVO>> menuPermissionListMap = allPermissionList.stream().map(PermissionVO::new).collect(Collectors.groupingBy(PermissionVO::getMenuId));
|
|
||||||
allVoList.forEach(menuVO -> menuVO.setPermissions(menuPermissionListMap.get(menuVO.getId())));
|
|
||||||
|
|
||||||
List<MenuVO> rootList = Collections.emptyList();
|
|
||||||
if (!allVoList.isEmpty()) {
|
|
||||||
rootList = (List<MenuVO>) 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<Menu> 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<MenuVO> 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());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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<RoleVO> list(ListRoleQuery query) {
|
|
||||||
String name = query.getName();
|
|
||||||
QueryWrapper<Role> wrapper = Wrappers.query();
|
|
||||||
wrapper.like(StringUtils.isNotEmpty(name), "name", name);
|
|
||||||
Page<Role> page = roleMapper.selectPage(query.toPage(), wrapper);
|
|
||||||
List<RoleVO> 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<RoleVO> listByUserId(ListRoleByUserIdQuery query) {
|
|
||||||
List<Role> list = roleMapper.selectByUserId(query.getUserId());
|
|
||||||
return list.stream().map(RoleVO::new).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<Integer, List<RoleBasicVO>> getUserRoleList(List<Integer> userIdList) {
|
|
||||||
if (userIdList == null || userIdList.isEmpty()) {
|
|
||||||
return Collections.emptyMap();
|
|
||||||
}
|
|
||||||
String userIds = userIdList.stream().distinct().map(String::valueOf).collect(Collectors.joining(","));
|
|
||||||
List<UserRoleEntity> 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<UsersRoles> 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<RolesMenus> wrapper = Wrappers.query();
|
|
||||||
wrapper.eq("role_id", query.getRoleId());
|
|
||||||
rolesMenusMapper.delete(wrapper);
|
|
||||||
|
|
||||||
List<RolesMenus> 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<RolesPermissions> wrapper = Wrappers.query();
|
|
||||||
wrapper.eq("role_id", query.getRoleId());
|
|
||||||
rolesPermissionsMapper.delete(wrapper);
|
|
||||||
|
|
||||||
List<RolesPermissions> list = query.toPO();
|
|
||||||
for (RolesPermissions rp : list) {
|
|
||||||
rolesPermissionsMapper.insert(rp);
|
|
||||||
}
|
|
||||||
Map<String, Object> cacheMap = hazelcastInstance.getMap(CacheKey.RBAC);
|
|
||||||
cacheMap.remove(CacheKey.RbacKey.ROLE_PERMISSIONS_URL + query.getRoleId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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<T extends IParentChildVO, PK> {
|
|
||||||
|
|
||||||
PK getId();
|
|
||||||
|
|
||||||
PK getPid();
|
|
||||||
|
|
||||||
List<T> getChildren();
|
|
||||||
|
|
||||||
void setChildren(List<T> list);
|
|
||||||
|
|
||||||
default void buildParent(IParentChildVO vo, Map<PK, IParentChildVO> allMap, Map<PK, IParentChildVO> 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<IParentChildVO> 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<? extends IParentChildVO> buildTree(List<? extends IParentChildVO> voList, List<? extends IParentChildVO> allList) {
|
|
||||||
Map<PK, IParentChildVO> allMap = allList.stream().collect(Collectors.toMap(vo -> (PK) vo.getId(), Function.identity()));
|
|
||||||
Map<PK, IParentChildVO> rootMap = new HashMap<>();
|
|
||||||
voList.forEach(vo -> buildParent(vo, allMap, rootMap));
|
|
||||||
return Lists.newArrayList(rootMap.values());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -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<Integer, Integer> selectLibraryMap(Collection<Integer> videoIds) {
|
|
||||||
if (CollUtil.isEmpty(videoIds)) {
|
|
||||||
return Collections.emptyMap();
|
|
||||||
}
|
|
||||||
LambdaQueryWrapper<VideoLiveLibrary> wrapper = Wrappers.<VideoLiveLibrary>lambdaQuery().in(VideoLiveLibrary::getVideoId, videoIds);
|
|
||||||
List<VideoLiveLibrary> 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<TaskDetailVO> processVideo(Integer videoId) {
|
|
||||||
LambdaQueryWrapper<VideoLiveLibrary> wrapper = Wrappers.<VideoLiveLibrary>lambdaQuery()
|
|
||||||
.eq(VideoLiveLibrary::getVideoId, videoId);
|
|
||||||
List<VideoLiveLibrary> libraryList = videoLibraryMapper.selectList(wrapper);
|
|
||||||
if (CollUtil.isEmpty(libraryList)) {
|
|
||||||
throw new BizException(ResponseStatus.ID_NOT_EXIST_ERROR, "该视频直播没有需要下载转码的视频");
|
|
||||||
}
|
|
||||||
// 查该视频直播所有未转码下载链接的视屏
|
|
||||||
List<VideoLiveLibrary> 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<VideoLiveLibrary> w = Wrappers.<VideoLiveLibrary>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<String> download(Integer videoId) {
|
|
||||||
LambdaQueryWrapper<VideoLiveLibrary> wrapper = Wrappers.<VideoLiveLibrary>lambdaQuery()
|
|
||||||
.eq(VideoLiveLibrary::getVideoId, videoId);
|
|
||||||
List<VideoLiveLibrary> 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<TaskDetailVO> searchTasksDetail(Integer videoId) {
|
|
||||||
// 查所有视频记录
|
|
||||||
List<VideoLiveLibrary> libraryList = videoLibraryMapper.selectList(Wrappers.<VideoLiveLibrary>lambdaQuery()
|
|
||||||
.eq(VideoLiveLibrary::getVideoId, videoId));
|
|
||||||
return videoCloudService.searchTasksDetail(libraryList);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -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<Integer, List<VideoMessageAppVO>> tempMessageVOMap = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从缓存中获取消息列表
|
|
||||||
*
|
|
||||||
* @param query 查询条件
|
|
||||||
* @param frontUser 前端用户信息
|
|
||||||
* @return 消息分页列表
|
|
||||||
*/
|
|
||||||
public AppPager<VideoMessageAppVO> 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<VideoMessageAppVO> 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<VideoMessageAppVO> getMessageList(ListVideoAppQuery query, FrontUserVO frontUser) {
|
|
||||||
if (query.getId() == null) {
|
|
||||||
return AppPager.emptyPager();
|
|
||||||
}
|
|
||||||
SortedSet<VideoSortEntity> 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<VideoSortEntity> 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<VideoSortEntity>) sortedSet).tailSet(lastEntity, false);
|
|
||||||
}
|
|
||||||
Map<Integer, AdvisorBasicVO> advisorMap = advisorInfoService.getAdvisorVoMap();
|
|
||||||
List<VideoMessageAppVO> voList = new ArrayList<>(size);
|
|
||||||
Iterator<VideoSortEntity> 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<VideoProductInfoVO> 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<VideoMessageAppVO> 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<VideoMessageAppVO> 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* 公共函数 服务类
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @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<Integer, Debounce> 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<String> 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<VideoLive> wrapper = Wrappers.lambdaQuery();
|
|
||||||
wrapper.select(VideoLive::getId, VideoLive::getEndTime)
|
|
||||||
.ne(VideoLive::getLiveStatus, VideoLiveStatus.HAS_ENDED.value)
|
|
||||||
.lt(VideoLive::getEndTime, LocalDate.now().atStartOfDay());
|
|
||||||
List<VideoLive> videoList = videoLiveMapper.selectList(wrapper);
|
|
||||||
LocalDateTime now = LocalDateTime.now();
|
|
||||||
if (!videoList.isEmpty()) {
|
|
||||||
Map<String, Object> 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.<VideoLive>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<VideoLive> 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<String, Object> 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<VideoLive> wrapper = Wrappers.<VideoLive>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<Integer> notStart = new ArrayList<>();
|
|
||||||
List<Integer> started = new ArrayList<>();
|
|
||||||
List<Integer> 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<String, Object> 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<String> 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<OnlineUser> onlineList = videoCacheService.getOnlineList(videoId);
|
|
||||||
Set<String> onlineUserIds = onlineList.stream().map(OnlineUser::getUserId).collect(Collectors.toSet());
|
|
||||||
|
|
||||||
// 查询预约的用户
|
|
||||||
LambdaQueryWrapper<VideoLiveUser> subWrapper = Wrappers.<VideoLiveUser>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<VideoLiveUser> allSubUserList = videoLiveUserMapper.selectList(subWrapper);
|
|
||||||
|
|
||||||
// 预约后未进入直播间用户
|
|
||||||
List<VideoLiveUser> notOnlineUser = allSubUserList.stream()
|
|
||||||
.filter(user -> !onlineUserIds.contains(user.getUserId())).collect(Collectors.toList());
|
|
||||||
|
|
||||||
// 在线已退出用户,退出时间在直播已开始之后
|
|
||||||
LambdaQueryWrapper<VideoUserFlow> queryWrapper = Wrappers.<VideoUserFlow>lambdaQuery()
|
|
||||||
.select(VideoUserFlow::getUserId)
|
|
||||||
.eq(VideoUserFlow::getVideoId, videoId);
|
|
||||||
List<VideoUserFlow> dbReadRecords = videoUserFlowMapper.selectList(queryWrapper);
|
|
||||||
List<String> dbUserIds = dbReadRecords.stream()
|
|
||||||
.map(VideoUserFlow::getUserId).distinct().collect(Collectors.toList());
|
|
||||||
|
|
||||||
//预约后未进入直播间用户
|
|
||||||
List<VideoLiveUser> notifyUserList = notOnlineUser.stream()
|
|
||||||
.filter(user -> !dbUserIds.contains(user.getUserId())).collect(Collectors.toList());
|
|
||||||
List<String> 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<VideoBehaviorNotify> 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<VideoLiveUser> wrapper = Wrappers.<VideoLiveUser>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<VideoSortEntity> getSortedVideos(Collection<Integer> videoIds) {
|
|
||||||
SortedSet<VideoSortEntity> 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<VideoProductInfoVO> getMergeProductList(Integer videoId, String[] typeAndIds) {
|
|
||||||
try {
|
|
||||||
List<VideoLiveProduct> 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.<VideoCart>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<VideoLiveProduct> 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<Integer, Integer, Object> 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<VideoLiveTrend> 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<VideoLiveTag> wrapper = Wrappers.<VideoLiveTag>lambdaQuery()
|
|
||||||
.eq(VideoLiveTag::getTagId, id);
|
|
||||||
return videoLiveTagMapper.exists(wrapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateLiveStatusByIds(List<Integer> ids, Integer status) {
|
|
||||||
if (!ids.isEmpty()) {
|
|
||||||
QueryWrapper<VideoLive> wrapper = Wrappers.query();
|
|
||||||
wrapper.in("id", ids);
|
|
||||||
videoLiveMapper.update(new VideoLive(status), wrapper);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private VideoProductInfoVO getProductInfo(Table<Integer, Integer, Object> 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -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 +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* 互动消息基本信息
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @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 +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user