feat(interaction): 新增分集计数统计接口
This commit is contained in:
1 parent
15b540cdd6
commit
2fe24b9db7
10 files changed
+299
-2
No files matched your search
+10
@@ -3,7 +3,9 @@
|
||||
package com.fruitshorts.app.controller;
|
||||
|
||||
import com.fruitshorts.app.service.AppCatalogService;
|
||||
import com.fruitshorts.app.service.AppEpisodeStatsService;
|
||||
import com.fruitshorts.app.vo.AppDramaDetailVO;
|
||||
import com.fruitshorts.app.vo.AppEpisodeStatsVO;
|
||||
import com.fruitshorts.common.pojo.Result;
|
||||
import com.fruitshorts.content.dal.entity.DramaEpisode;
|
||||
import com.fruitshorts.content.service.EpisodeService;
|
||||
@@ -34,6 +36,7 @@ public class AppDramaController {
|
||||
private final PlaybackService playbackService;
|
||||
private final EpisodeService episodeService;
|
||||
private final CommentService commentService;
|
||||
private final AppEpisodeStatsService appEpisodeStatsService;
|
||||
|
||||
/** 详情:包含剧集列表,客户端进详情页一次请求即可渲染 */
|
||||
@Operation(summary = "短剧详情(含剧集列表,进详情页一次请求即可渲染)")
|
||||
@@ -59,4 +62,11 @@ public class AppDramaController {
|
||||
vo.setCommentCount(commentService.countByEpisodes(List.of(id)).getOrDefault(id, 0L));
|
||||
return Result.ok(vo);
|
||||
}
|
||||
|
||||
/** 轻量计数快照:只读互动状态,不签发播放地址、不写票据缓存。 */
|
||||
@Operation(summary = "播放页轻量计数与当前用户互动状态")
|
||||
@GetMapping("/episodes/{id}/stats")
|
||||
public Result<AppEpisodeStatsVO> stats(@PathVariable Long id) {
|
||||
return Result.ok(appEpisodeStatsService.get(id, SecurityUtils.getUserIdOrNull()));
|
||||
}
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
// Author: fruit.com.cn
|
||||
|
||||
package com.fruitshorts.app.service;
|
||||
|
||||
import com.fruitshorts.app.vo.AppEpisodeStatsVO;
|
||||
import com.fruitshorts.common.exception.ErrorCode;
|
||||
import com.fruitshorts.common.exception.ServiceException;
|
||||
import com.fruitshorts.content.dal.entity.Drama;
|
||||
import com.fruitshorts.content.dal.entity.DramaEpisode;
|
||||
import com.fruitshorts.content.service.DramaService;
|
||||
import com.fruitshorts.content.service.EpisodeService;
|
||||
import com.fruitshorts.interaction.service.CommentService;
|
||||
import com.fruitshorts.interaction.service.LikeService;
|
||||
import com.fruitshorts.playback.service.FavoriteService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/** 播放页只读计数快照;固定维度批量查询,不签发播放地址或票据。 */
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AppEpisodeStatsService {
|
||||
|
||||
private final EpisodeService episodeService;
|
||||
private final DramaService dramaService;
|
||||
private final CommentService commentService;
|
||||
private final LikeService likeService;
|
||||
private final FavoriteService favoriteService;
|
||||
|
||||
public AppEpisodeStatsVO get(Long episodeId, Long userId) {
|
||||
Map<Long, AppEpisodeStatsVO> stats = batch(List.of(episodeId), userId);
|
||||
AppEpisodeStatsVO result = stats.get(episodeId);
|
||||
if (result == null) {
|
||||
throw new ServiceException(ErrorCode.DATA_NOT_FOUND, "剧集不存在或未上线");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** 每类数据只查一次,供后续多集统计复用。 */
|
||||
public Map<Long, AppEpisodeStatsVO> batch(Collection<Long> episodeIds, Long userId) {
|
||||
if (episodeIds == null || episodeIds.isEmpty()) {
|
||||
return Map.of();
|
||||
}
|
||||
List<DramaEpisode> episodes = episodeService.listPublishedByIds(episodeIds);
|
||||
if (episodes.isEmpty()) {
|
||||
return Map.of();
|
||||
}
|
||||
List<Long> normalizedIds = episodes.stream().map(DramaEpisode::getId).toList();
|
||||
List<Long> dramaIds = episodes.stream().map(DramaEpisode::getDramaId).distinct().toList();
|
||||
Map<Long, Long> commentCounts = commentService.countByEpisodes(normalizedIds);
|
||||
Map<Long, Drama> dramas = new HashMap<>();
|
||||
for (Drama drama : dramaService.listPublishedByIds(dramaIds)) {
|
||||
dramas.put(drama.getId(), drama);
|
||||
}
|
||||
Set<Long> likedIds = likeService.likedTargetIds(
|
||||
userId, LikeService.TYPE_EPISODE, normalizedIds);
|
||||
Set<Long> favoriteDramaIds = favoriteService.favoriteDramaIds(userId, dramaIds);
|
||||
|
||||
Map<Long, AppEpisodeStatsVO> result = new HashMap<>();
|
||||
for (DramaEpisode episode : episodes) {
|
||||
Drama drama = dramas.get(episode.getDramaId());
|
||||
if (drama == null) {
|
||||
continue;
|
||||
}
|
||||
AppEpisodeStatsVO vo = new AppEpisodeStatsVO();
|
||||
vo.setEpisodeId(episode.getId());
|
||||
vo.setDramaId(episode.getDramaId());
|
||||
vo.setLikeCount(episode.getLikeCount() == null ? 0L : episode.getLikeCount());
|
||||
vo.setCommentCount(commentCounts.getOrDefault(episode.getId(), 0L));
|
||||
vo.setFavoriteCount(drama.getFavoriteCount() == null ? 0L : drama.getFavoriteCount());
|
||||
vo.setLiked(likedIds.contains(episode.getId()));
|
||||
vo.setFavorited(favoriteDramaIds.contains(episode.getDramaId()));
|
||||
result.put(episode.getId(), vo);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// Author: fruit.com.cn
|
||||
|
||||
package com.fruitshorts.app.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/** 播放页轻量计数快照,不触发票据签发。 */
|
||||
@Data
|
||||
public class AppEpisodeStatsVO {
|
||||
|
||||
private Long episodeId;
|
||||
private Long dramaId;
|
||||
private Long likeCount;
|
||||
private Long commentCount;
|
||||
private Long favoriteCount;
|
||||
private Boolean liked;
|
||||
private Boolean favorited;
|
||||
}
|
||||
Reference in new issue
Block a user