package com.tzy.controller.living; import com.beust.jcommander.internal.Lists; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.tzy.annotation.ApiLimitRule; import com.tzy.common.config.CommonConfig; import com.tzy.common.config.handle.ApiVersion; import com.tzy.common.constant.Constants; import com.tzy.common.core.controller.BaseController; import com.tzy.common.dto.InDto; import com.tzy.common.dto.OutDTO; import com.tzy.common.dto.UserInfo; import com.tzy.common.utils.UserType; import com.tzy.common.utils.UserUtils; import com.tzy.common.utils.bean.JSONTools; import com.tzy.common.utils.http.forest.CommonForestClient; import com.tzy.dto.*; import com.tzy.framework.util.RedisUtils; import com.tzy.liveConfig.service.LiveLikeDBUpdateService; import com.tzy.liveConfig.service.LiveLikePushService; import com.tzy.sportcard.api.dto.LiveMerchantDTO; import com.tzy.sportcard.api.dto.group.LiveListDTO; import com.tzy.sportcard.api.service.GroupApiService; import com.tzy.sportcard.group.domain.CardGroupLivesConfig; import com.tzy.sportcard.group.domain.CardGroupLivesLike; import com.tzy.sportcard.group.mapper.CardGroupLivesConfigMapper; import com.tzy.sportcard.group.mapper.CardGroupLivesLikeMapper; import com.tzy.sportcard.group.service.ICardGroupLivesConfigService; import com.tzy.sportcard.group.service.impl.GroupActService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.util.CollectionUtils; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import org.teasoft.bee.osql.SuidRich; import javax.annotation.Resource; import java.util.*; import java.util.stream.Collectors; /** * 直播-api */ @Api("直播-api") @Slf4j @RestController @RequestMapping("/api/living") public class LivingApiController extends BaseController { @Resource private SuidRich suidRich; @Resource private CardGroupLivesConfigMapper cardGroupLivesConfigMapper; @Resource private CardGroupLivesLikeMapper cardGroupLivesLikeMapper; @Resource private GroupApiService groupApiService; @Resource private LiveLikePushService liveLikePushService; @Resource private LiveLikeDBUpdateService liveLikeDBUpdateService; @Resource private ICardGroupLivesConfigService livesConfigService; @Resource private CommonForestClient commonForestClient; @Value("${liveWebSocketUrl:https://im-dev.hobbystocks.cn/chat/handler}") private String liveWebSocketUrl; @Resource private RedisUtils redisUtils; @Resource private GroupActService groupActService; @PostMapping(value = "/details") public OutDTO details(@RequestBody InDto inDto) { Integer roomid = inDto.getIntegerParam("id"); if (null == roomid) return OutDTO.error(10040, "参数[id]不能为空!"); LivingRoomDTO cond = new LivingRoomDTO(); cond.setId(roomid); LivingRoomDTO livingRoomDto = suidRich.selectOne(cond); if (livingRoomDto == null) { return OutDTO.error500("直播间不存在!"); } return OutDTO.ok().put("livingRoomInfo", livingRoomDto); } @ApiOperation("获取直播间") @PostMapping("/{version}/list/{type}/{refId}") public OutDTO findMerchantLiving(@PathVariable("refId") Integer refId, @PathVariable("type") String type) { UserInfo user = UserUtils.getSimpleUserInfo(); Integer userId = user == null ? null : user.getId(); List liveList = livesConfigService.findAllLiving(type, refId, userId); if (CollectionUtils.isEmpty(liveList)) { return OutDTO.ok().put("livingList", liveList); } boolean isShipping = user != null && UserType.USER_ROLE_SHIPPING.equals(user.getRoleCode()); // 判断当前登陆的用户是否是商家角色 Integer merchantId = isShipping && user.getMerchantId() != null ? user.getMerchantId() : null; liveList.parallelStream().filter(living -> Constants.ORDER_TYPE_GROUP.equals(living.getCategory())) .forEach(living -> { boolean confirmStatus = isShipping && Objects.equals(living.getMerchantId(), merchantId); living.setConfirmStatus(confirmStatus); groupApiService.setGroupData(userId, living); }); return OutDTO.ok().put("livingList", liveList); } @ApiOperation("获取已结束直播") @PostMapping("/{version}/end/list") public OutDTO findEndLive(@RequestBody EndLiveParam endLiveParam) { PageInfo liveList = livesConfigService.findEndLives(endLiveParam); return OutDTO.ok().put("livingList", liveList); } @ApiOperation("获取直播间用户信息") @PostMapping("/{version}/user/{code}") @ApiLimitRule(seconds = 1, limitCount = 30, msg = "网络失败,请重试!") public OutDTO findLivingRoomUser(@PathVariable("code") String code) { List rooms = getRooms(code); if (CollectionUtils.isEmpty(rooms)) { return OutDTO.ok().put("users", new ArrayList<>()); } Integer merchantId = rooms.get(0).getMerchantId(); String url = String.format(CommonConfig.baseconfig.getImBaseUrl() + CommonConfig.baseconfig.getImUserUrl(), code); String result = commonForestClient.sendGet(url); ImUserResp resp = JSONTools.jsonStr2obj(result, ImUserResp.class); if (resp == null || resp.getCode() != 200 || CollectionUtils.isEmpty(resp.getData())) { log.warn("查询直播间用户异常:{}", result); return OutDTO.ok().put("users", new ArrayList<>()); } UserInfo user = UserUtils.getSimpleUserInfo(); boolean isOwnerMerchant = user != null && Objects.equals(merchantId, user.getMerchantId()); log.debug("查询直播间用户结果:{}", result); List users = livesConfigService.findLivingRoomUser(merchantId, resp.getData(), isOwnerMerchant, 1, 200); return OutDTO.ok().put("users", users); } private List getRooms(String code) { LivingRoomDTO cond = new LivingRoomDTO(); cond.setCode(code); cond.setDelFlg(0); cond.setStatus(1); return suidRich.select(cond); } private LivingRoomDTO checkRoomUser(ImParam param) { if (StringUtils.isEmpty(param.getCode())) { return null; } if (CollectionUtils.isEmpty(param.getUserIds())) { return null; } List rooms = getRooms(param.getCode()); if (CollectionUtils.isEmpty(rooms)) { return null; } return rooms.get(0); } @ApiOperation("直播间用户变动") @PostMapping("/{version}/user/change") public OutDTO livingUserChange(@RequestBody ImParam param) { LivingRoomDTO livingRoom = checkRoomUser(param); if (livingRoom == null) { return OutDTO.error(405, "直播间信息不存在"); } log.debug("直播间用户变动:{}", param); List users = livesConfigService.getImUsers(livingRoom.getMerchantId(), param.getUserIds(), 3); livesConfigService.setCachedLiveRoomUser(param.getCode(), param.getUserIds()); if (CollectionUtils.isEmpty(users)) { return OutDTO.ok(); } // if (!redisUtils.setIfAbsent(Constants.LIVING_USER_CHANGE_RECORD + param.getCode(), "1", 2, TimeUnit.SECONDS)) { // return OutDTO.ok(); // } //List imgList = new ArrayList<>(3); // StringJoiner stringJoiner = new StringJoiner(","); // for(ImUserDTO user:users){ // stringJoiner.add(user.getId().toString()); // imgList.add(user.getAvatar()); // } // String currentUserIds = stringJoiner.toString(); // String key=Constants.LIVING_ROOM_USER_KEY+param.getCode(); // Object existUserId = redisUtils.get(key); // if (currentUserIds.equals(existUserId)) { // return OutDTO.ok(); // } List imgList = users.stream().map(ImUserDTO::getAvatar).collect(Collectors.toList()); Message message = buildImReq(param.getCode(), imgList, param.getUserIds()); //commonForestClient.sendPost(liveWebSocketUrl, Constants.JSON_HEADS, message); //redisUtils.set(key,currentUserIds,60); return OutDTO.ok().put("message",message); } private Message buildImReq(String code, List imgList, List userIdList) { Map body = new HashMap<>(2); body.put("imgList", imgList); body.put("totalNum", userIdList.size()); return Message.builder().code("chat") .messageType("chat_to_room") .messageParam( Message.MessageParam.builder() .receiver(code) .payload( Message.MessageParam.Payload.builder() .contentType("CHANGES_NUM_PEOPLE") .sender("app") .content("user") .extra(JSONTools.obj2json(body)) .build() ).build()).build(); } @ApiOperation("获取直播间用户信息v2,分页") @PostMapping("/{version}/user") @ApiLimitRule(seconds = 1, limitCount = 30, msg = "网络失败,请重试!") public OutDTO findLivingRoomUserV2(@Validated @RequestBody LivingUserParam param) { String code = param.getCode(); if (StringUtils.isEmpty(code)) { return OutDTO.error500("参数缺失"); } List rooms = getRooms(code); if (CollectionUtils.isEmpty(rooms)) { return OutDTO.ok().put("users", new ArrayList<>()).put("totalNum", 0); } Integer merchantId = rooms.get(0).getMerchantId(); // String url = String.format(CommonConfig.baseconfig.getImBaseUrl() + CommonConfig.baseconfig.getImUserUrl(), code); // String result = commonForestClient.sendGet(url); String result = livesConfigService.getCachedLiveRoomUser(param.getCode()); if (result == null) { log.warn("查询直播间用户异常:{}", result); return OutDTO.ok().put("users", new ArrayList<>()).put("totalNum", 0); } List userIds = JSONTools.jsonStr2obj(result, List.class); UserInfo user = UserUtils.getSimpleUserInfo(); boolean isOwnerMerchant = user != null && Objects.equals(merchantId, user.getMerchantId()); log.debug("查询直播间用户结果:{}", result); List users = livesConfigService.findLivingRoomUser(merchantId, userIds, isOwnerMerchant, param.getPageNo(), param.getPageSize()); return OutDTO.ok().put("users", users).put("totalNum", userIds.size()); } @ApiOperation("获取商城直播画面") @PostMapping("/{version}/screen") public OutDTO getlivingScreen() { // 查询直播中的商城直播 List shopLivings = livesConfigService.getShopLivings(); if(CollectionUtils.isEmpty(shopLivings)){ return OutDTO.ok().put("livingScreens", null); } List livingScreens = Lists.newArrayList(); shopLivings.forEach(living ->{ String key = "simple_living_" + living.getCode(); if(redisUtils.hasKey(key)){ LivingScreenDTO livingScreenDTO = new LivingScreenDTO(); Map playbackData = redisUtils.hmget(key); livingScreenDTO.setCaptureTime(playbackData.get("capture_time").toString()); livingScreenDTO.setCaptureUrl(playbackData.get("capture_url").toString()); livingScreenDTO.setCode(living.getCode()); livingScreens.add(livingScreenDTO); } }); return OutDTO.ok().put("livingScreens", livingScreens); } @ApiOperation("获取直播间点赞") @PostMapping("/{version}/like/{code}") @ApiLimitRule(seconds = 1, limitCount = 30, msg = "网络失败,请重试!") public OutDTO getLivingRoomLike(@PathVariable("code") String code) { if (!redisUtils.hHasKey(Constants.LIVING_ROOM_LIKE_KEY, code)) { List livingRoomDto = cardGroupLivesConfigMapper.selectLivingRoomByCode(code); // 写缓存 int liveLikeNum = 0; if(livingRoomDto != null && !livingRoomDto.isEmpty()){ liveLikeNum = livingRoomDto.get(0).getLiveLikeNum(); } redisUtils.hset(Constants.LIVING_ROOM_LIKE_KEY, code, liveLikeNum, 24 * 60 * 60); } return OutDTO.ok().put("count", redisUtils.hget(Constants.LIVING_ROOM_LIKE_KEY, code)); } @ApiOperation("点赞直播间") @PostMapping("/{version}/like") @ApiLimitRule(seconds = 1, limitCount = 30, msg = "网络失败,请重试!") public OutDTO likeLivingRoom(@Validated @RequestBody UserLikeParam param) { //1000465 HS-APP【直播间竞价】并发场景下当前端传的num参数大于50时,则接口最大有效值为50(防止被恶意修改参数) int likeNum = param.getNum() >= 50 ? 50 : param.getNum(); //region LIVING_ROOM_LIKE_KEY logic int finalLikeNum = likeNum; if (redisUtils.hHasKey(Constants.LIVING_ROOM_LIKE_KEY, param.getCode())) { finalLikeNum = (int)redisUtils.hget(Constants.LIVING_ROOM_LIKE_KEY, param.getCode()) +finalLikeNum; } else{ List livingRoomDtoList = cardGroupLivesConfigMapper.selectLivingRoomByCode(param.getCode()); if(livingRoomDtoList != null && !livingRoomDtoList.isEmpty()){ finalLikeNum = (livingRoomDtoList.get(0).getLiveLikeNum()==null?0:livingRoomDtoList.get(0).getLiveLikeNum()) + likeNum; } } // 写LIVING_ROOM_LIKE_KEY缓存 redisUtils.hset(Constants.LIVING_ROOM_LIKE_KEY, param.getCode(), finalLikeNum, 24 * 60 * 60); //endregion //region LIVING_ROOM_LIKE_USER_KEY logic UserInfo user = UserUtils.getSimpleUserInfo(true); // 写LIVING_ROOM_LIKE_USER_KEY缓存 int finalUserLikeNum = likeNum; if (redisUtils.hHasKey(Constants.LIVING_ROOM_LIKE_USER_KEY, user.getId()+param.getCode())) { finalUserLikeNum = (int)redisUtils.hget(Constants.LIVING_ROOM_LIKE_USER_KEY, user.getId()+param.getCode()) +finalUserLikeNum; } else{ CardGroupLivesLike livesLike = cardGroupLivesLikeMapper.selectCardGroupLivesLikeById(user.getId(),param.getCode()); if (livesLike != null) { finalUserLikeNum = livesLike.getLike_num()==null?0:livesLike.getLike_num() + likeNum; } } // 写LIVING_ROOM_LIKE_USER_KEY缓存 redisUtils.hset(Constants.LIVING_ROOM_LIKE_USER_KEY, user.getId()+param.getCode(), finalUserLikeNum, 24 * 60 * 60); //endregion // 定时推给db更新 liveLikeDBUpdateService.handleRequest(param.getCode(),user.getId()); // 定时推给im更新 liveLikePushService.handleRequest(param.getCode()); return OutDTO.ok().put("count", finalLikeNum); } @ApiOperation("首页直播商家排序") @PostMapping("/{version}/sorts") public OutDTO getLiveMerchantList(@RequestBody CardGroupLivesConfig cardGroupLivesConfig) { if(cardGroupLivesConfig == null){ cardGroupLivesConfig = new CardGroupLivesConfig(); } UserInfo userInfo = UserUtils.getSimpleUserInfo(false); if(userInfo != null){ cardGroupLivesConfig.setAppUserId(userInfo.getId()); } // 查询直播中的商家直播信息 List liveMerchantList = livesConfigService.getLiveMerchantList(cardGroupLivesConfig); return OutDTO.ok().put("liveMerchantList", liveMerchantList); } @ApiVersion(1.0) @ApiOperation("根据paniniListId查询直播中的商品/拍品") @PostMapping("/{version}/panini/{paniniListId}") public OutDTO getLiveByPaniniListId(@PathVariable Long paniniListId) { // 根据paniniListId查询直播中的商品 List paniniLives = livesConfigService.getLiveByPaniniListId(paniniListId); return OutDTO.ok().put("paniniLives", paniniLives); } @PostMapping("/{version}/main/place/list") @ApiVersion(1.0) @ApiOperation(value = "查询双11主会场直播列表") public OutDTO getMainPlaceLiveConfigs(@RequestBody InDto inDto){ PageHelper.startPage(inDto.getPageNo(),inDto.getPageSize()); List livesConfigList = livesConfigService.getLivesByStartTime(); return OutDTO.ok().put("livesConfigList",livesConfigList); } }