feat(app): 全部短剧改为请求体分页
This commit is contained in:
1 parent
ebc5f890fd
commit
2367a5d12b
15 files changed
+322
-61
No files matched your search
+46
-3
@@ -4,6 +4,7 @@ package com.fruitshorts.app.controller;
|
|||||||
|
|
||||||
import com.fruitshorts.app.service.AppCatalogService;
|
import com.fruitshorts.app.service.AppCatalogService;
|
||||||
import com.fruitshorts.app.vo.AppCategoryVO;
|
import com.fruitshorts.app.vo.AppCategoryVO;
|
||||||
|
import com.fruitshorts.app.vo.AppDramaPageReqVO;
|
||||||
import com.fruitshorts.app.vo.AppFeedVO;
|
import com.fruitshorts.app.vo.AppFeedVO;
|
||||||
import com.fruitshorts.app.vo.AppDramaCardVO;
|
import com.fruitshorts.app.vo.AppDramaCardVO;
|
||||||
import com.fruitshorts.app.vo.AppPlaylistDetailVO;
|
import com.fruitshorts.app.vo.AppPlaylistDetailVO;
|
||||||
@@ -16,6 +17,8 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@@ -30,6 +33,9 @@ import java.util.List;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class AppCatalogController {
|
public class AppCatalogController {
|
||||||
|
|
||||||
|
private static final int DRAMA_PAGE_INDEX = 1;
|
||||||
|
private static final int DRAMA_PAGE_SIZE = 20;
|
||||||
|
|
||||||
private final AppCatalogService appCatalogService;
|
private final AppCatalogService appCatalogService;
|
||||||
|
|
||||||
@Operation(summary = "首页聚合:轮播 + 分区,一次请求渲染整页")
|
@Operation(summary = "首页聚合:轮播 + 分区,一次请求渲染整页")
|
||||||
@@ -69,9 +75,46 @@ public class AppCatalogController {
|
|||||||
return Result.ok(appCatalogService.categoryDramas(id, pageIndex, pageSize));
|
return Result.ok(appCatalogService.categoryDramas(id, pageIndex, pageSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "剧单详情:剧单基本信息 + 该剧单下已上线短剧卡片")
|
@Operation(summary = "已启用类型")
|
||||||
|
@GetMapping("/drama-categories")
|
||||||
|
public Result<List<AppCategoryVO>> dramaCategories() {
|
||||||
|
return Result.ok(appCatalogService.dramaCategories());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "已启用标签")
|
||||||
|
@GetMapping("/tags")
|
||||||
|
public Result<List<AppCategoryVO>> tags() {
|
||||||
|
return Result.ok(appCatalogService.tags());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全部短剧分页。类型、分类、标签放在请求体,避免长 id 进入查询串。
|
||||||
|
* 同一组多选为或,不同组同时传入为且。
|
||||||
|
*/
|
||||||
|
@Operation(summary = "全部短剧:类型、分类、标签多选,分页")
|
||||||
|
@PostMapping("/dramas/page")
|
||||||
|
public Result<PageResult<AppDramaCardVO>> dramas(@RequestBody(required = false) AppDramaPageReqVO req) {
|
||||||
|
AppDramaPageReqVO body = req == null ? new AppDramaPageReqVO() : req;
|
||||||
|
int pageIndex = body.getPageIndex() == null ? DRAMA_PAGE_INDEX : body.getPageIndex();
|
||||||
|
int pageSize = body.getPageSize() == null ? DRAMA_PAGE_SIZE : body.getPageSize();
|
||||||
|
return Result.ok(appCatalogService.libraryDramas(
|
||||||
|
body.getCategoryIds(), body.getClassificationIds(), body.getTagIds(), pageIndex, pageSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "剧单列表:已启用剧单及其已上线短剧卡片,分页")
|
||||||
|
@GetMapping("/playlists")
|
||||||
|
public Result<PageResult<AppPlaylistDetailVO>> playlists(
|
||||||
|
@RequestParam(defaultValue = "1") int pageIndex,
|
||||||
|
@RequestParam(defaultValue = "10") int pageSize) {
|
||||||
|
return Result.ok(appCatalogService.playlists(pageIndex, pageSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "剧单详情:剧单基本信息 + 该页已上线短剧卡片")
|
||||||
@GetMapping("/playlists/{id}")
|
@GetMapping("/playlists/{id}")
|
||||||
public Result<AppPlaylistDetailVO> playlistDetail(@PathVariable Long id) {
|
public Result<AppPlaylistDetailVO> playlistDetail(
|
||||||
return Result.ok(appCatalogService.playlistDetail(id));
|
@PathVariable Long id,
|
||||||
|
@RequestParam(defaultValue = "1") int pageIndex,
|
||||||
|
@RequestParam(defaultValue = "20") int pageSize) {
|
||||||
|
return Result.ok(appCatalogService.playlistDetail(id, pageIndex, pageSize));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+170
-35
@@ -13,10 +13,13 @@ import com.fruitshorts.app.vo.AppSectionVO;
|
|||||||
import com.fruitshorts.common.pojo.CursorResult;
|
import com.fruitshorts.common.pojo.CursorResult;
|
||||||
import com.fruitshorts.common.pojo.PageResult;
|
import com.fruitshorts.common.pojo.PageResult;
|
||||||
import com.fruitshorts.content.dal.entity.ContentBanner;
|
import com.fruitshorts.content.dal.entity.ContentBanner;
|
||||||
|
import com.fruitshorts.content.dal.entity.ContentTag;
|
||||||
import com.fruitshorts.content.dal.entity.Drama;
|
import com.fruitshorts.content.dal.entity.Drama;
|
||||||
import com.fruitshorts.content.dal.entity.DramaEpisode;
|
import com.fruitshorts.content.dal.entity.DramaEpisode;
|
||||||
import com.fruitshorts.content.enums.BannerPosition;
|
import com.fruitshorts.content.enums.BannerPosition;
|
||||||
import com.fruitshorts.content.service.BannerService;
|
import com.fruitshorts.content.service.BannerService;
|
||||||
|
import com.fruitshorts.content.service.ContentLocaleTexts;
|
||||||
|
import com.fruitshorts.content.service.ContentTagService;
|
||||||
import com.fruitshorts.content.service.DramaCategoryService;
|
import com.fruitshorts.content.service.DramaCategoryService;
|
||||||
import com.fruitshorts.content.service.DramaClassificationService;
|
import com.fruitshorts.content.service.DramaClassificationService;
|
||||||
import com.fruitshorts.content.service.DramaPlaylistCategoryService;
|
import com.fruitshorts.content.service.DramaPlaylistCategoryService;
|
||||||
@@ -31,6 +34,7 @@ import org.springframework.stereotype.Service;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -48,11 +52,17 @@ public class AppCatalogService {
|
|||||||
private static final int MAX_CATEGORY_SECTIONS = 4;
|
private static final int MAX_CATEGORY_SECTIONS = 4;
|
||||||
private static final int DEFAULT_FEED_SIZE = 20;
|
private static final int DEFAULT_FEED_SIZE = 20;
|
||||||
private static final int MAX_FEED_SIZE = 50;
|
private static final int MAX_FEED_SIZE = 50;
|
||||||
|
private static final int DEFAULT_PLAYLIST_PAGE_SIZE = 10;
|
||||||
|
private static final int MAX_PLAYLIST_PAGE_SIZE = 20;
|
||||||
|
private static final int DEFAULT_PLAYLIST_DRAMA_PAGE_SIZE = 20;
|
||||||
|
private static final int MAX_PLAYLIST_DRAMA_PAGE_SIZE = 50;
|
||||||
|
private static final int PLAYLIST_DRAMA_PREVIEW_SIZE = 10;
|
||||||
|
|
||||||
private final DramaService dramaService;
|
private final DramaService dramaService;
|
||||||
private final EpisodeService episodeService;
|
private final EpisodeService episodeService;
|
||||||
private final BannerService bannerService;
|
private final BannerService bannerService;
|
||||||
private final DramaCategoryService dramaCategoryService;
|
private final DramaCategoryService dramaCategoryService;
|
||||||
|
private final ContentTagService contentTagService;
|
||||||
private final DramaClassificationService dramaClassificationService;
|
private final DramaClassificationService dramaClassificationService;
|
||||||
private final DramaPlaylistCategoryService dramaPlaylistCategoryService;
|
private final DramaPlaylistCategoryService dramaPlaylistCategoryService;
|
||||||
private final PlaybackSigner playbackSigner;
|
private final PlaybackSigner playbackSigner;
|
||||||
@@ -60,28 +70,65 @@ public class AppCatalogService {
|
|||||||
private final ThumbnailUrlResolver thumbnailUrlResolver;
|
private final ThumbnailUrlResolver thumbnailUrlResolver;
|
||||||
|
|
||||||
public AppFeedVO homeFeed() {
|
public AppFeedVO homeFeed() {
|
||||||
Map<Long, String> categoryNames = categoryNameMap();
|
Map<Long, Map<String, String>> categoryLocales = categoryLocaleMap();
|
||||||
List<AppSectionVO> sections = new ArrayList<>();
|
List<AppSectionVO> sections = new ArrayList<>();
|
||||||
addIfNotEmpty(sections, "hot", "热门推荐",
|
addIfNotEmpty(sections, "hot", "热门推荐",
|
||||||
dramaService.listPublishedHot(HOME_SECTION_SIZE), categoryNames);
|
dramaService.listPublishedHot(HOME_SECTION_SIZE), categoryLocales);
|
||||||
addIfNotEmpty(sections, "new", "新剧上线",
|
addIfNotEmpty(sections, "new", "新剧上线",
|
||||||
dramaService.listPublishedLatest(HOME_SECTION_SIZE), categoryNames);
|
dramaService.listPublishedLatest(HOME_SECTION_SIZE), categoryLocales);
|
||||||
sections.addAll(categorySections(HOME_SECTION_SIZE, categoryNames));
|
sections.addAll(categorySections(HOME_SECTION_SIZE, categoryLocales));
|
||||||
return new AppFeedVO(banners(BannerPosition.HOME_TOP.name()), sections);
|
return new AppFeedVO(banners(BannerPosition.HOME_TOP.name()), sections);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AppFeedVO discoverFeed() {
|
public AppFeedVO discoverFeed() {
|
||||||
return new AppFeedVO(banners(BannerPosition.DISCOVER.name()),
|
return new AppFeedVO(banners(BannerPosition.DISCOVER.name()),
|
||||||
categorySections(DISCOVER_SECTION_SIZE, categoryNameMap()));
|
categorySections(DISCOVER_SECTION_SIZE, categoryLocaleMap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 分类频道:运营自定义的精选/新剧/榜单等(drama_classification)。 */
|
/** 分类频道:运营自定义的精选/新剧/榜单等(drama_classification)。 */
|
||||||
public List<AppCategoryVO> categories() {
|
public List<AppCategoryVO> categories() {
|
||||||
return dramaClassificationService.listEnabled().stream()
|
return dramaClassificationService.listEnabled().stream()
|
||||||
.map(c -> new AppCategoryVO(c.getId(), c.getName()))
|
.map(c -> {
|
||||||
|
Map<String, String> locales = ContentLocaleTexts.read(
|
||||||
|
c.getNameLocales(), c.getName(), c.getNameEn(), c.getNameId());
|
||||||
|
AppCategoryVO vo = new AppCategoryVO(c.getId(), ContentLocaleTexts.value(locales, ContentLocaleTexts.ZH));
|
||||||
|
vo.setLocales(locales);
|
||||||
|
return vo;
|
||||||
|
})
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 已启用类型,名称只放 locales。 */
|
||||||
|
public List<AppCategoryVO> dramaCategories() {
|
||||||
|
return dramaCategoryService.list().stream()
|
||||||
|
.filter(item -> item.getStatus() != null && item.getStatus() == 1)
|
||||||
|
.map(item -> option(item.getId(), item.getName(), item.getLocales()))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 已启用标签,名称只放 locales。 */
|
||||||
|
public List<AppCategoryVO> tags() {
|
||||||
|
return contentTagService.listEnabled().stream()
|
||||||
|
.map(item -> option(item.getId(), item.getName(), item.getLocales()))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 全部短剧分页。同一行多选是或,不同类型之间是且。 */
|
||||||
|
public PageResult<AppDramaCardVO> libraryDramas(List<Long> categoryIds, List<Long> classificationIds,
|
||||||
|
List<Long> tagIds, int pageIndex, int pageSize) {
|
||||||
|
PageResult<Drama> page = dramaService.pagePublishedLibrary(
|
||||||
|
categoryIds, classificationIds, tagIds, pageIndex, pageSize);
|
||||||
|
return new PageResult<>(page.getTotal(), toCards(page.getList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private AppCategoryVO option(Long id, String name, Map<String, String> locales) {
|
||||||
|
AppCategoryVO vo = new AppCategoryVO(id, name);
|
||||||
|
if (locales != null && !locales.isEmpty()) {
|
||||||
|
vo.setLocales(locales);
|
||||||
|
}
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
/** 分类频道:按分类分页查已上线短剧卡片(通过分类关联表过滤)。 */
|
/** 分类频道:按分类分页查已上线短剧卡片(通过分类关联表过滤)。 */
|
||||||
public PageResult<AppDramaCardVO> categoryDramas(Long classificationId,
|
public PageResult<AppDramaCardVO> categoryDramas(Long classificationId,
|
||||||
int pageIndex, int pageSize) {
|
int pageIndex, int pageSize) {
|
||||||
@@ -108,7 +155,7 @@ public class AppCatalogService {
|
|||||||
}
|
}
|
||||||
int toIndex = Math.min(fromIndex + safeSize, ordered.size());
|
int toIndex = Math.min(fromIndex + safeSize, ordered.size());
|
||||||
List<Drama> pageRows = ordered.subList(fromIndex, toIndex);
|
List<Drama> pageRows = ordered.subList(fromIndex, toIndex);
|
||||||
return new PageResult<>(total, cards(pageRows, categoryNameMap()));
|
return new PageResult<>(total, cards(pageRows, categoryLocaleMap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public CursorResult<AppDramaCardVO> feed(
|
public CursorResult<AppDramaCardVO> feed(
|
||||||
@@ -128,7 +175,7 @@ public class AppCatalogService {
|
|||||||
boolean hasMore = rows.size() > pageSize;
|
boolean hasMore = rows.size() > pageSize;
|
||||||
List<Drama> pageRows = hasMore ? rows.subList(0, pageSize) : rows;
|
List<Drama> pageRows = hasMore ? rows.subList(0, pageSize) : rows;
|
||||||
Long nextCursor = hasMore ? pageRows.get(pageRows.size() - 1).getId() : null;
|
Long nextCursor = hasMore ? pageRows.get(pageRows.size() - 1).getId() : null;
|
||||||
return new CursorResult<>(cards(pageRows, categoryNameMap()), nextCursor, hasMore);
|
return new CursorResult<>(cards(pageRows, categoryLocaleMap()), nextCursor, hasMore);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -139,7 +186,7 @@ public class AppCatalogService {
|
|||||||
if (dramas == null || dramas.isEmpty()) {
|
if (dramas == null || dramas.isEmpty()) {
|
||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
return cards(dramas, categoryNameMap());
|
return cards(dramas, categoryLocaleMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
public AppDramaDetailVO dramaDetail(Long dramaId) {
|
public AppDramaDetailVO dramaDetail(Long dramaId) {
|
||||||
@@ -149,15 +196,18 @@ public class AppCatalogService {
|
|||||||
episodes.stream().map(DramaEpisode::getId).sorted().toList());
|
episodes.stream().map(DramaEpisode::getId).sorted().toList());
|
||||||
Map<Long, String> thumbnailUrls = thumbnailUrlResolver.resolveAll(
|
Map<Long, String> thumbnailUrls = thumbnailUrlResolver.resolveAll(
|
||||||
episodes.stream().map(DramaEpisode::getId).sorted().toList());
|
episodes.stream().map(DramaEpisode::getId).sorted().toList());
|
||||||
String categoryName = categoryNameMap().getOrDefault(drama.getCategoryId(), "");
|
List<Map<String, String>> types = dramaCategoryService.localesForDrama(drama, categoryLocaleMap());
|
||||||
|
|
||||||
AppDramaDetailVO detail = new AppDramaDetailVO();
|
AppDramaDetailVO detail = new AppDramaDetailVO();
|
||||||
detail.setId(drama.getId());
|
detail.setId(drama.getId());
|
||||||
detail.setTitle(drama.getTitle());
|
Map<String, String> titles = ContentLocaleTexts.read(drama.getTitleLocales(), drama.getTitle(), null, null);
|
||||||
detail.setSynopsis(drama.getSynopsis());
|
Map<String, String> synopses = ContentLocaleTexts.read(
|
||||||
|
drama.getSynopsisLocales(), drama.getSynopsis(), null, null);
|
||||||
|
detail.setTitleLocales(titles);
|
||||||
|
detail.setSynopsisLocales(synopses);
|
||||||
detail.setCover(drama.getCoverUrl());
|
detail.setCover(drama.getCoverUrl());
|
||||||
detail.setGenre(drama.getGenre());
|
detail.setTypes(types);
|
||||||
detail.setCategory(categoryName);
|
fillDetailTag(detail, drama);
|
||||||
detail.setTotalEpisodes(drama.getTotalEpisodes());
|
detail.setTotalEpisodes(drama.getTotalEpisodes());
|
||||||
detail.setFreeEpisodes(drama.getFreeEpisodes());
|
detail.setFreeEpisodes(drama.getFreeEpisodes());
|
||||||
detail.setUnlockCoin(drama.getUnlockCoin());
|
detail.setUnlockCoin(drama.getUnlockCoin());
|
||||||
@@ -172,8 +222,27 @@ public class AppCatalogService {
|
|||||||
return detail;
|
return detail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** C 端剧单详情:剧单基本信息 + 该剧单下所有已上线短剧卡片。 */
|
/** C 端剧单列表:按页返回已启用剧单,每条只含该页剧单的已上线短剧。 */
|
||||||
public AppPlaylistDetailVO playlistDetail(Long playlistId) {
|
public PageResult<AppPlaylistDetailVO> playlists(int pageIndex, int pageSize) {
|
||||||
|
var all = dramaPlaylistCategoryService.listEnabled();
|
||||||
|
int safeIndex = Math.max(1, pageIndex);
|
||||||
|
int safeSize = pageSize <= 0
|
||||||
|
? DEFAULT_PLAYLIST_PAGE_SIZE
|
||||||
|
: Math.min(pageSize, MAX_PLAYLIST_PAGE_SIZE);
|
||||||
|
int fromIndex = (safeIndex - 1) * safeSize;
|
||||||
|
if (fromIndex >= all.size()) {
|
||||||
|
return new PageResult<>(all.size(), List.of());
|
||||||
|
}
|
||||||
|
int toIndex = Math.min(fromIndex + safeSize, all.size());
|
||||||
|
List<AppPlaylistDetailVO> page = new ArrayList<>();
|
||||||
|
for (var category : all.subList(fromIndex, toIndex)) {
|
||||||
|
page.add(playlistDetail(category.getId(), 1, PLAYLIST_DRAMA_PREVIEW_SIZE));
|
||||||
|
}
|
||||||
|
return new PageResult<>(all.size(), page);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** C 端剧单详情:剧单基本信息 + 该页已上线短剧卡片。 */
|
||||||
|
public AppPlaylistDetailVO playlistDetail(Long playlistId, int pageIndex, int pageSize) {
|
||||||
var category = dramaPlaylistCategoryService.getEnabledById(playlistId);
|
var category = dramaPlaylistCategoryService.getEnabledById(playlistId);
|
||||||
List<Long> allIds = dramaPlaylistCategoryService.listDramaIdsByCategory(playlistId);
|
List<Long> allIds = dramaPlaylistCategoryService.listDramaIdsByCategory(playlistId);
|
||||||
List<Drama> published = dramaService.listPublishedByIds(allIds);
|
List<Drama> published = dramaService.listPublishedByIds(allIds);
|
||||||
@@ -190,12 +259,27 @@ public class AppCatalogService {
|
|||||||
})
|
})
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
|
int safeIndex = Math.max(1, pageIndex);
|
||||||
|
int safeSize = pageSize <= 0
|
||||||
|
? DEFAULT_PLAYLIST_DRAMA_PAGE_SIZE
|
||||||
|
: Math.min(pageSize, MAX_PLAYLIST_DRAMA_PAGE_SIZE);
|
||||||
|
int from = (safeIndex - 1) * safeSize;
|
||||||
|
List<Drama> pageRows = from >= ordered.size()
|
||||||
|
? List.of()
|
||||||
|
: ordered.subList(from, Math.min(from + safeSize, ordered.size()));
|
||||||
|
Map<String, String> locales = ContentLocaleTexts.read(
|
||||||
|
category.getNameLocales(), category.getName(), category.getNameEn(), category.getNameId());
|
||||||
|
Map<String, String> descriptions = ContentLocaleTexts.read(
|
||||||
|
category.getDescriptionLocales(), category.getDescription(),
|
||||||
|
category.getDescriptionEn(), category.getDescriptionId());
|
||||||
AppPlaylistDetailVO vo = new AppPlaylistDetailVO();
|
AppPlaylistDetailVO vo = new AppPlaylistDetailVO();
|
||||||
vo.setId(category.getId());
|
vo.setId(category.getId());
|
||||||
vo.setName(category.getName());
|
vo.setLocales(locales);
|
||||||
vo.setDescription(category.getDescription());
|
vo.setDescriptionLocales(descriptions);
|
||||||
vo.setDramaCount(ordered.size());
|
vo.setDramaCount(ordered.size());
|
||||||
vo.setList(cards(ordered, categoryNameMap()));
|
vo.setPageIndex(safeIndex);
|
||||||
|
vo.setPageSize(safeSize);
|
||||||
|
vo.setList(cards(pageRows, categoryLocaleMap()));
|
||||||
return vo;
|
return vo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,7 +287,7 @@ public class AppCatalogService {
|
|||||||
return bannerService.listActive(position).stream().map(this::toBanner).toList();
|
return bannerService.listActive(position).stream().map(this::toBanner).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<AppSectionVO> categorySections(int size, Map<Long, String> categoryNames) {
|
private List<AppSectionVO> categorySections(int size, Map<Long, Map<String, String>> categoryLocales) {
|
||||||
List<AppSectionVO> sections = new ArrayList<>();
|
List<AppSectionVO> sections = new ArrayList<>();
|
||||||
for (DramaCategoryRespVO category : dramaCategoryService.listBasic()) {
|
for (DramaCategoryRespVO category : dramaCategoryService.listBasic()) {
|
||||||
if (sections.size() >= MAX_CATEGORY_SECTIONS) {
|
if (sections.size() >= MAX_CATEGORY_SECTIONS) {
|
||||||
@@ -213,17 +297,17 @@ public class AppCatalogService {
|
|||||||
if (!dramas.isEmpty()) {
|
if (!dramas.isEmpty()) {
|
||||||
sections.add(new AppSectionVO(
|
sections.add(new AppSectionVO(
|
||||||
"category-" + category.getId(),
|
"category-" + category.getId(),
|
||||||
category.getName(),
|
category.getLocales(),
|
||||||
cards(dramas, categoryNames)));
|
cards(dramas, categoryLocales)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sections;
|
return sections;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addIfNotEmpty(List<AppSectionVO> sections, String code, String title,
|
private void addIfNotEmpty(List<AppSectionVO> sections, String code, String title,
|
||||||
List<Drama> dramas, Map<Long, String> categoryNames) {
|
List<Drama> dramas, Map<Long, Map<String, String>> categoryLocales) {
|
||||||
if (!dramas.isEmpty()) {
|
if (!dramas.isEmpty()) {
|
||||||
sections.add(new AppSectionVO(code, title, cards(dramas, categoryNames)));
|
sections.add(new AppSectionVO(code, title, cards(dramas, categoryLocales)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,30 +321,36 @@ public class AppCatalogService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** 整屏卡片共用一次剧集查询,取每部剧的首个可播免费集作为预览。 */
|
/** 整屏卡片共用一次剧集查询,取每部剧的首个可播免费集作为预览。 */
|
||||||
private List<AppDramaCardVO> cards(List<Drama> dramas, Map<Long, String> categoryNames) {
|
private List<AppDramaCardVO> cards(List<Drama> dramas, Map<Long, Map<String, String>> categoryLocales) {
|
||||||
List<Long> ids = dramas.stream().map(Drama::getId).toList();
|
List<Long> ids = dramas.stream().map(Drama::getId).toList();
|
||||||
Map<Long, DramaEpisode> previews = episodeService.firstPlayableByDramas(ids);
|
Map<Long, DramaEpisode> previews = episodeService.firstPlayableByDramas(ids);
|
||||||
Map<Long, Long> commentCounts = commentService.countByEpisodes(
|
Map<Long, Long> commentCounts = commentService.countByEpisodes(
|
||||||
previews.values().stream().map(DramaEpisode::getId).sorted().toList());
|
previews.values().stream().map(DramaEpisode::getId).sorted().toList());
|
||||||
Map<Long, String> thumbnailUrls = thumbnailUrlResolver.resolveAll(
|
Map<Long, String> thumbnailUrls = thumbnailUrlResolver.resolveAll(
|
||||||
previews.values().stream().map(DramaEpisode::getId).sorted().toList());
|
previews.values().stream().map(DramaEpisode::getId).sorted().toList());
|
||||||
|
Map<Long, ContentTag> tags = loadTags(dramas);
|
||||||
return dramas.stream()
|
return dramas.stream()
|
||||||
.map(drama -> toCard(
|
.map(drama -> toCard(
|
||||||
drama, categoryNames, previews.get(drama.getId()), commentCounts,
|
drama, categoryLocales, tags, previews.get(drama.getId()), commentCounts,
|
||||||
thumbnailUrls))
|
thumbnailUrls))
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private AppDramaCardVO toCard(Drama drama, Map<Long, String> categoryNames,
|
private AppDramaCardVO toCard(Drama drama, Map<Long, Map<String, String>> categoryLocales,
|
||||||
|
Map<Long, ContentTag> tags,
|
||||||
DramaEpisode preview, Map<Long, Long> commentCounts,
|
DramaEpisode preview, Map<Long, Long> commentCounts,
|
||||||
Map<Long, String> thumbnailUrls) {
|
Map<Long, String> thumbnailUrls) {
|
||||||
|
List<Map<String, String>> types = dramaCategoryService.localesForDrama(drama, categoryLocales);
|
||||||
AppDramaCardVO card = new AppDramaCardVO();
|
AppDramaCardVO card = new AppDramaCardVO();
|
||||||
card.setId(drama.getId());
|
card.setId(drama.getId());
|
||||||
card.setTitle(drama.getTitle());
|
Map<String, String> titles = ContentLocaleTexts.read(drama.getTitleLocales(), drama.getTitle(), null, null);
|
||||||
|
Map<String, String> synopses = ContentLocaleTexts.read(
|
||||||
|
drama.getSynopsisLocales(), drama.getSynopsis(), null, null);
|
||||||
|
card.setTitleLocales(titles);
|
||||||
card.setCover(drama.getCoverUrl());
|
card.setCover(drama.getCoverUrl());
|
||||||
card.setSynopsis(shortSynopsis(drama.getSynopsis()));
|
card.setSynopsisLocales(shortLocales(synopses));
|
||||||
card.setGenre(drama.getGenre());
|
card.setTypes(types);
|
||||||
card.setCategory(categoryNames.getOrDefault(drama.getCategoryId(), ""));
|
fillTag(card, drama, tags);
|
||||||
card.setTotalEpisodes(drama.getTotalEpisodes());
|
card.setTotalEpisodes(drama.getTotalEpisodes());
|
||||||
card.setIsHot(drama.getIsHot() != null && drama.getIsHot() == 1);
|
card.setIsHot(drama.getIsHot() != null && drama.getIsHot() == 1);
|
||||||
card.setViewCount(drama.getViewCount());
|
card.setViewCount(drama.getViewCount());
|
||||||
@@ -307,13 +397,58 @@ public class AppCatalogService {
|
|||||||
return episode.getVideoUrl() == null ? "" : episode.getVideoUrl();
|
return episode.getVideoUrl() == null ? "" : episode.getVideoUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<Long, String> categoryNameMap() {
|
private Map<Long, ContentTag> loadTags(List<Drama> dramas) {
|
||||||
Map<Long, String> names = new HashMap<>();
|
List<Long> ids = dramas.stream()
|
||||||
dramaCategoryService.listBasic().forEach(category -> names.put(category.getId(), category.getName()));
|
.map(Drama::getTagId)
|
||||||
return names;
|
.filter(id -> id != null && id > 0L)
|
||||||
|
.distinct()
|
||||||
|
.toList();
|
||||||
|
Map<Long, ContentTag> tags = contentTagService.findByIds(ids);
|
||||||
|
return tags == null ? Map.of() : tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillTag(AppDramaCardVO card, Drama drama, Map<Long, ContentTag> tags) {
|
||||||
|
ContentTag tag = tagOf(drama, tags);
|
||||||
|
Map<String, String> locales = tagLocales(tag);
|
||||||
|
card.setTagLocales(locales);
|
||||||
|
card.setTagColor(tag == null ? "" : tag.getBgColor());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillDetailTag(AppDramaDetailVO detail, Drama drama) {
|
||||||
|
ContentTag tag = tagOf(drama, loadTags(List.of(drama)));
|
||||||
|
Map<String, String> locales = tagLocales(tag);
|
||||||
|
detail.setTagLocales(locales);
|
||||||
|
detail.setTagColor(tag == null ? "" : tag.getBgColor());
|
||||||
|
}
|
||||||
|
|
||||||
|
private ContentTag tagOf(Drama drama, Map<Long, ContentTag> tags) {
|
||||||
|
if (drama.getTagId() == null || drama.getTagId() <= 0L) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return tags.get(drama.getTagId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, String> tagLocales(ContentTag tag) {
|
||||||
|
if (tag == null) {
|
||||||
|
return Map.of();
|
||||||
|
}
|
||||||
|
return ContentLocaleTexts.read(tag.getNameLocales(), tag.getName(), tag.getNameEn(), tag.getNameId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<Long, Map<String, String>> categoryLocaleMap() {
|
||||||
|
return dramaCategoryService.localeMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 卡片只带一句简介,避免列表响应体过大 */
|
/** 卡片只带一句简介,避免列表响应体过大 */
|
||||||
|
private Map<String, String> shortLocales(Map<String, String> locales) {
|
||||||
|
Map<String, String> result = new LinkedHashMap<>();
|
||||||
|
if (locales == null) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
locales.forEach((code, text) -> result.put(code, shortSynopsis(text)));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private String shortSynopsis(String synopsis) {
|
private String shortSynopsis(String synopsis) {
|
||||||
if (synopsis == null) {
|
if (synopsis == null) {
|
||||||
return "";
|
return "";
|
||||||
|
|||||||
@@ -2,13 +2,19 @@
|
|||||||
|
|
||||||
package com.fruitshorts.app.vo;
|
package com.fruitshorts.app.vo;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/** 首页分类。名称只放在 locales。 */
|
||||||
@Data
|
@Data
|
||||||
@AllArgsConstructor
|
|
||||||
public class AppCategoryVO {
|
public class AppCategoryVO {
|
||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
private String name;
|
private Map<String, String> locales;
|
||||||
|
|
||||||
|
public AppCategoryVO(Long id, String name) {
|
||||||
|
this.id = id;
|
||||||
|
this.locales = name == null || name.isBlank() ? Map.of() : Map.of("zh", name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -5,20 +5,26 @@ package com.fruitshorts.app.vo;
|
|||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/** 列表卡片,用于首页/发现页/分类分区 */
|
/** 列表卡片,用于首页/发现页/分类分区 */
|
||||||
@Data
|
@Data
|
||||||
public class AppDramaCardVO {
|
public class AppDramaCardVO {
|
||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
private String title;
|
private Map<String, String> titleLocales;
|
||||||
private String cover;
|
private String cover;
|
||||||
private String synopsis;
|
private Map<String, String> synopsisLocales;
|
||||||
private String genre;
|
/** 短剧选中的全部类型,每项是一份语言表。 */
|
||||||
private String category;
|
private List<Map<String, String>> types;
|
||||||
|
/** 标签语言表,key 为 zh / en / id。 */
|
||||||
|
private Map<String, String> tagLocales;
|
||||||
|
/** 标签角标背景色,#RRGGBB。 */
|
||||||
|
private String tagColor;
|
||||||
private Integer totalEpisodes;
|
private Integer totalEpisodes;
|
||||||
private Boolean isHot;
|
private Boolean isHot;
|
||||||
private Long viewCount;
|
private Long viewCount;
|
||||||
/** 短剧累计点赞数:drama.like_count */
|
|
||||||
private Long likeCount;
|
private Long likeCount;
|
||||||
/** 短剧累计收藏数:drama.favorite_count */
|
/** 短剧累计收藏数:drama.favorite_count */
|
||||||
private Long favoriteCount;
|
private Long favoriteCount;
|
||||||
|
|||||||
@@ -5,16 +5,18 @@ package com.fruitshorts.app.vo;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class AppDramaDetailVO {
|
public class AppDramaDetailVO {
|
||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
private String title;
|
private Map<String, String> titleLocales;
|
||||||
private String synopsis;
|
private Map<String, String> synopsisLocales;
|
||||||
private String cover;
|
private String cover;
|
||||||
private String genre;
|
private List<Map<String, String>> types;
|
||||||
private String category;
|
private Map<String, String> tagLocales;
|
||||||
|
private String tagColor;
|
||||||
private Integer totalEpisodes;
|
private Integer totalEpisodes;
|
||||||
private Integer freeEpisodes;
|
private Integer freeEpisodes;
|
||||||
private Integer unlockCoin;
|
private Integer unlockCoin;
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// Author: fruit.com.cn
|
||||||
|
|
||||||
|
package com.fruitshorts.app.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/** 全部短剧分页筛选。多选 id 放在请求体里,避免查询串过长。 */
|
||||||
|
@Data
|
||||||
|
public class AppDramaPageReqVO {
|
||||||
|
|
||||||
|
private Integer pageIndex;
|
||||||
|
private Integer pageSize;
|
||||||
|
/** 类型 id,多选为或。 */
|
||||||
|
private List<Long> categoryIds;
|
||||||
|
/** 分类 id,多选为或。 */
|
||||||
|
private List<Long> classificationIds;
|
||||||
|
/** 标签 id,多选为或。 */
|
||||||
|
private List<Long> tagIds;
|
||||||
|
}
|
||||||
@@ -5,15 +5,20 @@ package com.fruitshorts.app.vo;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/** C 端剧单详情:基本信息 + 该剧单下已上线的短剧卡片。 */
|
/** C 端剧单详情:基本信息 + 该剧单下已上线的短剧卡片。 */
|
||||||
@Data
|
@Data
|
||||||
public class AppPlaylistDetailVO {
|
public class AppPlaylistDetailVO {
|
||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
private String name;
|
private Map<String, String> locales;
|
||||||
private String description;
|
private Map<String, String> descriptionLocales;
|
||||||
/** 该剧单下已上线短剧的实际条数(被下架/下线的不计入) */
|
/** 该剧单下已上线短剧的实际条数(被下架/下线的不计入) */
|
||||||
private Integer dramaCount;
|
private Integer dramaCount;
|
||||||
|
/** 当前短剧页码,从 1 开始 */
|
||||||
|
private Integer pageIndex;
|
||||||
|
/** 当前短剧页大小 */
|
||||||
|
private Integer pageSize;
|
||||||
private List<AppDramaCardVO> list;
|
private List<AppDramaCardVO> list;
|
||||||
}
|
}
|
||||||
@@ -2,18 +2,28 @@
|
|||||||
|
|
||||||
package com.fruitshorts.app.vo;
|
package com.fruitshorts.app.vo;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import com.fruitshorts.content.service.ContentLocaleTexts;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/** 首页/发现页的一个横滑分区 */
|
/** 首页/发现页的一个横滑分区 */
|
||||||
@Data
|
@Data
|
||||||
@AllArgsConstructor
|
|
||||||
public class AppSectionVO {
|
public class AppSectionVO {
|
||||||
|
|
||||||
/** 分区标识:hot / new / category-{id},客户端可据此做埋点与样式 */
|
/** 分区标识:hot / new / category-{id},客户端可据此做埋点与样式 */
|
||||||
private String code;
|
private String code;
|
||||||
private String title;
|
private Map<String, String> titleLocales;
|
||||||
private List<AppDramaCardVO> dramas;
|
private List<AppDramaCardVO> dramas;
|
||||||
|
|
||||||
|
public AppSectionVO(String code, String title, List<AppDramaCardVO> dramas) {
|
||||||
|
this(code, Map.of(ContentLocaleTexts.ZH, title == null ? "" : title), dramas);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppSectionVO(String code, Map<String, String> titleLocales, List<AppDramaCardVO> dramas) {
|
||||||
|
this.code = code;
|
||||||
|
this.titleLocales = titleLocales;
|
||||||
|
this.dramas = dramas;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+27
-5
@@ -17,15 +17,18 @@ import com.fruitshorts.playback.service.PlaybackService;
|
|||||||
import com.fruitshorts.interaction.service.CommentService;
|
import com.fruitshorts.interaction.service.CommentService;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.nullValue;
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
import static org.mockito.BDDMockito.given;
|
import static org.mockito.BDDMockito.given;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
@@ -58,7 +61,7 @@ class AppCatalogControllerContractTest {
|
|||||||
banner.setLinkValue("12");
|
banner.setLinkValue("12");
|
||||||
AppDramaCardVO card = new AppDramaCardVO();
|
AppDramaCardVO card = new AppDramaCardVO();
|
||||||
card.setId(12L);
|
card.setId(12L);
|
||||||
card.setTitle("命运的相遇");
|
card.setTitleLocales(Map.of("zh", "命运的相遇"));
|
||||||
card.setViewCount(12400L);
|
card.setViewCount(12400L);
|
||||||
card.setLikeCount(3200L);
|
card.setLikeCount(3200L);
|
||||||
card.setFavoriteCount(1800L);
|
card.setFavoriteCount(1800L);
|
||||||
@@ -94,7 +97,7 @@ class AppCatalogControllerContractTest {
|
|||||||
void should_return_typed_cursor_feed() throws Exception {
|
void should_return_typed_cursor_feed() throws Exception {
|
||||||
AppDramaCardVO card = new AppDramaCardVO();
|
AppDramaCardVO card = new AppDramaCardVO();
|
||||||
card.setId(12L);
|
card.setId(12L);
|
||||||
card.setTitle("漫剧卡片");
|
card.setTitleLocales(Map.of("zh", "漫剧卡片"));
|
||||||
card.setDramaType("ANIME");
|
card.setDramaType("ANIME");
|
||||||
given(catalogService.feed("ANIME", 7L, null, 20))
|
given(catalogService.feed("ANIME", 7L, null, 20))
|
||||||
.willReturn(new CursorResult<>(List.of(card), 12L, true));
|
.willReturn(new CursorResult<>(List.of(card), 12L, true));
|
||||||
@@ -122,14 +125,14 @@ class AppCatalogControllerContractTest {
|
|||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("$.code").value(0))
|
.andExpect(jsonPath("$.code").value(0))
|
||||||
.andExpect(jsonPath("$.data[0].id").value(3))
|
.andExpect(jsonPath("$.data[0].id").value(3))
|
||||||
.andExpect(jsonPath("$.data[0].name").value("都市"));
|
.andExpect(jsonPath("$.data[0].locales.zh").value("都市"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void should_bind_path_variable_when_drama_detail_is_requested() throws Exception {
|
void should_bind_path_variable_when_drama_detail_is_requested() throws Exception {
|
||||||
AppDramaDetailVO detail = new AppDramaDetailVO();
|
AppDramaDetailVO detail = new AppDramaDetailVO();
|
||||||
detail.setId(42L);
|
detail.setId(42L);
|
||||||
detail.setTitle("命运的相遇");
|
detail.setTitleLocales(Map.of("zh", "命运的相遇"));
|
||||||
detail.setViewCount(12400L);
|
detail.setViewCount(12400L);
|
||||||
detail.setLikeCount(3200L);
|
detail.setLikeCount(3200L);
|
||||||
detail.setFavoriteCount(1800L);
|
detail.setFavoriteCount(1800L);
|
||||||
@@ -142,7 +145,7 @@ class AppCatalogControllerContractTest {
|
|||||||
.andExpect(jsonPath("$.code").value(0))
|
.andExpect(jsonPath("$.code").value(0))
|
||||||
.andExpect(jsonPath("$.data.id").value("42"))
|
.andExpect(jsonPath("$.data.id").value("42"))
|
||||||
.andExpect(jsonPath("$.data.id").isString())
|
.andExpect(jsonPath("$.data.id").isString())
|
||||||
.andExpect(jsonPath("$.data.title").value("命运的相遇"))
|
.andExpect(jsonPath("$.data.titleLocales.zh").value("命运的相遇"))
|
||||||
.andExpect(jsonPath("$.data.viewCount").value("12400"))
|
.andExpect(jsonPath("$.data.viewCount").value("12400"))
|
||||||
.andExpect(jsonPath("$.data.likeCount").value("3200"))
|
.andExpect(jsonPath("$.data.likeCount").value("3200"))
|
||||||
.andExpect(jsonPath("$.data.favoriteCount").value("1800"))
|
.andExpect(jsonPath("$.data.favoriteCount").value("1800"))
|
||||||
@@ -161,4 +164,23 @@ class AppCatalogControllerContractTest {
|
|||||||
.andExpect(jsonPath("$.code").value(ErrorCode.DATA_NOT_FOUND.getCode()))
|
.andExpect(jsonPath("$.code").value(ErrorCode.DATA_NOT_FOUND.getCode()))
|
||||||
.andExpect(jsonPath("$.data").value(nullValue()));
|
.andExpect(jsonPath("$.data").value(nullValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void should_bind_filter_ids_from_body_when_drama_page_is_posted() throws Exception {
|
||||||
|
AppDramaCardVO card = new AppDramaCardVO();
|
||||||
|
card.setId(9L);
|
||||||
|
card.setTitleLocales(Map.of("zh", "重生"));
|
||||||
|
given(catalogService.libraryDramas(List.of(2L), List.of(3L), List.of(4L), 1, 20))
|
||||||
|
.willReturn(new com.fruitshorts.common.pojo.PageResult<>(1L, List.of(card)));
|
||||||
|
|
||||||
|
catalogMvc.perform(post("/app/dramas/page")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content("{\"pageIndex\":1,\"pageSize\":20,"
|
||||||
|
+ "\"categoryIds\":[\"2\"],\"classificationIds\":[\"3\"],\"tagIds\":[\"4\"]}"))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.code").value(0))
|
||||||
|
.andExpect(jsonPath("$.data.total").value("1"))
|
||||||
|
.andExpect(jsonPath("$.data.list[0].titleLocales.zh").value("重生"));
|
||||||
|
verify(catalogService).libraryDramas(List.of(2L), List.of(3L), List.of(4L), 1, 20);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+2
-1
@@ -7,6 +7,7 @@ import com.fruitshorts.common.pojo.CursorResult;
|
|||||||
import com.fruitshorts.content.dal.entity.Drama;
|
import com.fruitshorts.content.dal.entity.Drama;
|
||||||
import com.fruitshorts.content.dal.entity.DramaEpisode;
|
import com.fruitshorts.content.dal.entity.DramaEpisode;
|
||||||
import com.fruitshorts.content.service.BannerService;
|
import com.fruitshorts.content.service.BannerService;
|
||||||
|
import com.fruitshorts.content.service.ContentTagService;
|
||||||
import com.fruitshorts.content.service.DramaCategoryService;
|
import com.fruitshorts.content.service.DramaCategoryService;
|
||||||
import com.fruitshorts.content.service.DramaClassificationService;
|
import com.fruitshorts.content.service.DramaClassificationService;
|
||||||
import com.fruitshorts.content.service.DramaPlaylistCategoryService;
|
import com.fruitshorts.content.service.DramaPlaylistCategoryService;
|
||||||
@@ -54,7 +55,7 @@ class AppCatalogServiceTest {
|
|||||||
given(thumbnailUrlResolver.resolveAll(any())).willReturn(Map.of());
|
given(thumbnailUrlResolver.resolveAll(any())).willReturn(Map.of());
|
||||||
commentService = mock(CommentService.class);
|
commentService = mock(CommentService.class);
|
||||||
catalogService = new AppCatalogService(dramaService, episodeService, bannerService,
|
catalogService = new AppCatalogService(dramaService, episodeService, bannerService,
|
||||||
dramaCategoryService, dramaClassificationService, dramaPlaylistCategoryService,
|
dramaCategoryService, mock(ContentTagService.class), dramaClassificationService, dramaPlaylistCategoryService,
|
||||||
playbackSigner, commentService, thumbnailUrlResolver);
|
playbackSigner, commentService, thumbnailUrlResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
@@ -43,6 +43,8 @@ class DramaServiceFavoriteCountTest {
|
|||||||
mock(DramaEpisodeMapper.class),
|
mock(DramaEpisodeMapper.class),
|
||||||
mock(DramaReviewRecordMapper.class),
|
mock(DramaReviewRecordMapper.class),
|
||||||
mock(DramaCategoryService.class),
|
mock(DramaCategoryService.class),
|
||||||
|
mock(com.fruitshorts.content.dal.mapper.ContentTagMapper.class),
|
||||||
|
mock(com.fruitshorts.content.service.ContentTagService.class),
|
||||||
mock(EpisodePriceSync.class));
|
mock(EpisodePriceSync.class));
|
||||||
given(dramaMapper.update(isNull(), any())).willReturn(1);
|
given(dramaMapper.update(isNull(), any())).willReturn(1);
|
||||||
ArgumentCaptor<Wrapper<Drama>> captor = ArgumentCaptor.forClass(Wrapper.class);
|
ArgumentCaptor<Wrapper<Drama>> captor = ArgumentCaptor.forClass(Wrapper.class);
|
||||||
|
|||||||
+2
@@ -47,6 +47,8 @@ class DramaServiceFeedTest {
|
|||||||
mock(DramaEpisodeMapper.class),
|
mock(DramaEpisodeMapper.class),
|
||||||
mock(DramaReviewRecordMapper.class),
|
mock(DramaReviewRecordMapper.class),
|
||||||
mock(DramaCategoryService.class),
|
mock(DramaCategoryService.class),
|
||||||
|
mock(com.fruitshorts.content.dal.mapper.ContentTagMapper.class),
|
||||||
|
mock(com.fruitshorts.content.service.ContentTagService.class),
|
||||||
mock(EpisodePriceSync.class));
|
mock(EpisodePriceSync.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ class DramaServiceK88Test {
|
|||||||
mock(DramaEpisodeMapper.class),
|
mock(DramaEpisodeMapper.class),
|
||||||
mock(DramaReviewRecordMapper.class),
|
mock(DramaReviewRecordMapper.class),
|
||||||
mock(DramaCategoryService.class),
|
mock(DramaCategoryService.class),
|
||||||
|
mock(com.fruitshorts.content.dal.mapper.ContentTagMapper.class),
|
||||||
|
mock(com.fruitshorts.content.service.ContentTagService.class),
|
||||||
mock(EpisodePriceSync.class));
|
mock(EpisodePriceSync.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
@@ -56,6 +56,8 @@ class DramaServiceMultiTagTest {
|
|||||||
mock(DramaEpisodeMapper.class),
|
mock(DramaEpisodeMapper.class),
|
||||||
mock(DramaReviewRecordMapper.class),
|
mock(DramaReviewRecordMapper.class),
|
||||||
categoryService,
|
categoryService,
|
||||||
|
mock(com.fruitshorts.content.dal.mapper.ContentTagMapper.class),
|
||||||
|
mock(com.fruitshorts.content.service.ContentTagService.class),
|
||||||
mock(EpisodePriceSync.class));
|
mock(EpisodePriceSync.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
@@ -38,6 +38,8 @@ public class SecurityConfig {
|
|||||||
"/app/discover/**",
|
"/app/discover/**",
|
||||||
"/app/feed",
|
"/app/feed",
|
||||||
"/app/categories/**",
|
"/app/categories/**",
|
||||||
|
"/app/drama-categories",
|
||||||
|
"/app/tags",
|
||||||
"/app/playlists/**",
|
"/app/playlists/**",
|
||||||
"/app/banners/**",
|
"/app/banners/**",
|
||||||
"/app/dramas/**",
|
"/app/dramas/**",
|
||||||
|
|||||||
Reference in new issue
Block a user