feat(interaction): 新增分集计数统计接口

This commit is contained in:
Zhou Weidong committed 2026-10-26 21:31:17 +08:00
1 parent 15b540cdd6
commit 2fe24b9db7
10 files changed
+299 -2

No files matched your search

@@ -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()));
}
}
@@ -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;
}