feat(content): 新增内容类型与首页分类 feed

This commit is contained in:
Zhou Weidong committed 2026-10-21 15:40:19 +08:00
1 parent d9cdbc8e15
commit 1052b97306
19 files changed
+557 -4

No files matched your search

@@ -5,12 +5,15 @@ package com.fruitshorts.app.controller;
import com.fruitshorts.app.service.AppCatalogService;
import com.fruitshorts.app.vo.AppCategoryVO;
import com.fruitshorts.app.vo.AppFeedVO;
import com.fruitshorts.app.vo.AppDramaCardVO;
import com.fruitshorts.common.pojo.CursorResult;
import com.fruitshorts.common.pojo.Result;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@@ -38,6 +41,15 @@ public class AppCatalogController {
return Result.ok(appCatalogService.discoverFeed());
}
@Operation(summary = "推荐流:支持内容类型多选与游标翻页")
@GetMapping("/feed")
public Result<CursorResult<AppDramaCardVO>> feed(
@RequestParam(required = false) String types,
@RequestParam(required = false) Long cursor,
@RequestParam(required = false) Integer size) {
return Result.ok(appCatalogService.feed(types, cursor, size));
}
@Operation(summary = "分类列表")
@GetMapping("/categories")
public Result<List<AppCategoryVO>> categories() {
@@ -9,6 +9,7 @@ import com.fruitshorts.app.vo.AppDramaDetailVO;
import com.fruitshorts.app.vo.AppEpisodeVO;
import com.fruitshorts.app.vo.AppFeedVO;
import com.fruitshorts.app.vo.AppSectionVO;
import com.fruitshorts.common.pojo.CursorResult;
import com.fruitshorts.content.dal.entity.ContentBanner;
import com.fruitshorts.content.dal.entity.Drama;
import com.fruitshorts.content.dal.entity.DramaEpisode;
@@ -27,6 +28,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Arrays;
/**
* C 端目录聚合:把内容域的只读视图组装成客户端一次请求就能渲染的结构。
@@ -39,6 +41,8 @@ public class AppCatalogService {
private static final int HOME_SECTION_SIZE = 6;
private static final int DISCOVER_SECTION_SIZE = 10;
private static final int MAX_CATEGORY_SECTIONS = 4;
private static final int DEFAULT_FEED_SIZE = 20;
private static final int MAX_FEED_SIZE = 50;
private final DramaService dramaService;
private final EpisodeService episodeService;
@@ -70,6 +74,24 @@ public class AppCatalogService {
.toList();
}
public CursorResult<AppDramaCardVO> feed(String types, Long cursor, Integer size) {
int pageSize = size == null ? DEFAULT_FEED_SIZE : Math.max(1, Math.min(size, MAX_FEED_SIZE));
List<String> dramaTypes = types == null
? List.of()
: Arrays.stream(types.split(","))
.map(String::trim)
.filter(type -> !type.isEmpty())
.toList();
List<Drama> rows = dramaService.listPublishedFeed(dramaTypes, cursor, pageSize + 1);
if (rows.isEmpty()) {
return CursorResult.empty();
}
boolean hasMore = rows.size() > pageSize;
List<Drama> pageRows = hasMore ? rows.subList(0, pageSize) : rows;
Long nextCursor = hasMore ? pageRows.get(pageRows.size() - 1).getId() : null;
return new CursorResult<>(cards(pageRows, categoryNameMap()), nextCursor, hasMore);
}
/**
* 供收藏、观看记录等列表复用卡片结构:字段与首页卡片完全一致,
* 客户端可以用同一套渲染逻辑,不用为每个列表各写一份。
@@ -169,6 +191,7 @@ public class AppCatalogService {
card.setFavoriteCount(drama.getFavoriteCount());
card.setCommentCount(commentCounts.getOrDefault(drama.getId(), 0L));
card.setLanguage(drama.getLanguage());
card.setDramaType(drama.getDramaType());
card.setPreview(preview == null ? null : toEpisode(preview));
return card;
}
@@ -27,6 +27,8 @@ public class AppDramaCardVO {
/** 语种,供客户端按语言筛选(如 zh-CN / id)。 */
@Schema(description = "短剧语种,如 zh-CN / id")
private String language;
/** 内容类型:ANIME=漫剧,LIVE=真人剧 */
private String dramaType;
/**
* 首个可播免费集。首页竖屏播放需要在列表阶段就能起播,
* 带上这一集可以省掉「点开→请求详情→再请求播放地址」的往返。