refactor: 收口推荐流展示模型

This commit is contained in:
2026-06-03 17:48:47 +08:00
parent a178942033
commit d67abecc9e
7 changed files with 287 additions and 110 deletions
@@ -3,8 +3,10 @@ import { expect, test } from 'vitest';
import type { CustomWorldGalleryCard } from '../../../packages/shared/src/contracts/runtime';
import {
buildPlatformRankingEntries,
buildPlatformRecommendFeedEntries,
buildPublicCategoryGroups,
buildPublicGalleryCardKey,
dedupePlatformPublicGalleryEntries,
filterPlatformWorkSearchResults,
filterTodayPublishedEntries,
getPlatformCategoryKindFilter,
@@ -13,6 +15,8 @@ import {
getPlatformRankingMetricValue,
matchesPlatformCategoryKindFilter,
parsePlatformEntryTimestamp,
selectAdjacentPlatformRecommendEntry,
selectPlatformRecommendFeedWindow,
sortPlatformCategoryEntries,
} from './rpgEntryPublicGalleryViewModel';
import type {
@@ -146,6 +150,100 @@ test('public gallery ViewModel dedupes merged public entries by latest source',
});
});
test('public gallery ViewModel builds recommend feed from general public entries', () => {
const featuredPuzzle = buildPuzzleEntry({
profileId: 'shared',
worldName: '精选旧拼图',
});
const latestPuzzle = buildPuzzleEntry({
profileId: 'shared',
worldName: '最新拼图',
});
const edutainmentPuzzle = buildPuzzleEntry({
profileId: 'edutainment',
themeTags: ['寓教于乐'],
});
const jumpHopEntry = buildJumpHopEntry({ profileId: 'jump-hop' });
expect(
buildPlatformRecommendFeedEntries(
[featuredPuzzle, edutainmentPuzzle],
[latestPuzzle, jumpHopEntry],
),
).toEqual([latestPuzzle, jumpHopEntry]);
expect(
dedupePlatformPublicGalleryEntries([featuredPuzzle, latestPuzzle]),
).toEqual([latestPuzzle]);
});
test('public gallery ViewModel selects recommend feed window with wraparound neighbors', () => {
const firstEntry = buildPuzzleEntry({ profileId: 'first' });
const secondEntry = buildJumpHopEntry({ profileId: 'second' });
const thirdEntry = buildWoodenFishEntry({ profileId: 'third' });
const entries = [firstEntry, secondEntry, thirdEntry];
expect(selectPlatformRecommendFeedWindow([], 'missing')).toEqual({
activeEntry: null,
activeEntryKey: null,
activeIndex: -1,
nextEntry: null,
previousEntry: null,
});
expect(selectPlatformRecommendFeedWindow([firstEntry], null)).toEqual({
activeEntry: firstEntry,
activeEntryKey: buildPublicGalleryCardKey(firstEntry),
activeIndex: 0,
nextEntry: null,
previousEntry: null,
});
expect(
selectPlatformRecommendFeedWindow(
entries,
buildPublicGalleryCardKey(secondEntry),
),
).toEqual({
activeEntry: secondEntry,
activeEntryKey: buildPublicGalleryCardKey(secondEntry),
activeIndex: 1,
nextEntry: thirdEntry,
previousEntry: firstEntry,
});
expect(selectPlatformRecommendFeedWindow(entries, 'missing')).toEqual({
activeEntry: firstEntry,
activeEntryKey: buildPublicGalleryCardKey(firstEntry),
activeIndex: 0,
nextEntry: secondEntry,
previousEntry: thirdEntry,
});
expect(selectPlatformRecommendFeedWindow(entries, null)).toEqual({
activeEntry: firstEntry,
activeEntryKey: buildPublicGalleryCardKey(firstEntry),
activeIndex: 0,
nextEntry: secondEntry,
previousEntry: thirdEntry,
});
});
test('public gallery ViewModel selects adjacent recommend entry without self-loop', () => {
const onlyEntry = buildPuzzleEntry({ profileId: 'only' });
const nextEntry = buildJumpHopEntry({ profileId: 'next' });
expect(
selectAdjacentPlatformRecommendEntry([onlyEntry], 1, 'missing'),
).toBeNull();
expect(
selectAdjacentPlatformRecommendEntry(
[onlyEntry, nextEntry],
1,
buildPublicGalleryCardKey(onlyEntry),
),
).toBe(nextEntry);
expect(
selectAdjacentPlatformRecommendEntry([onlyEntry, nextEntry], -1, 'missing'),
).toBe(nextEntry);
});
test('public gallery ViewModel searches compact work codes and ranks name prefix first', () => {
const nameMatch = buildPuzzleEntry({
profileId: 'name-match',