refactor: 收口排行配置模型

This commit is contained in:
2026-06-03 18:37:34 +08:00
parent 5fecceef4f
commit 685560ec07
6 changed files with 144 additions and 48 deletions

View File

@@ -160,20 +160,24 @@ import {
buildPublicCategoryGroups,
buildPublicGalleryCardKey,
dedupePlatformPublicGalleryEntries,
DEFAULT_PLATFORM_RANKING_TAB,
filterPlatformWorkSearchResults,
filterTodayPublishedEntries,
getAllPlatformPublicEntries,
getPlatformCategoryPrimaryMetric,
getPlatformPublicEntries,
getPlatformRankingMetricValue,
getPlatformRankingMetric,
getPlatformRankingTabConfig,
getPlatformSearchableWorkIds,
getPlatformWorldLikeCount,
getPlatformWorldPlayCount,
getPlatformWorldRemixCount,
isExactPublicWorkCodeSearch,
matchesPlatformCategoryKindFilter,
PLATFORM_RANKING_TABS,
type PlatformCategoryKindFilter,
type PlatformCategorySortMode,
type PlatformRankingMetric,
type PlatformRankingTab,
selectPlatformRecommendFeedWindow,
sortPlatformCategoryEntries,
@@ -405,37 +409,6 @@ const CHILD_MOTION_DEMO_DEFAULT_CARD = {
summary: '站位、招手和左右手活动。',
};
const PLATFORM_RANKING_TABS: Array<{
id: PlatformRankingTab;
label: string;
metricLabel: string;
emptyText: string;
}> = [
{
id: 'hot',
label: '热门榜',
metricLabel: '游玩',
emptyText: '公开广场暂时还没有热门作品。',
},
{
id: 'remix',
label: '改造榜',
metricLabel: '改造',
emptyText: '公开广场暂时还没有改造作品。',
},
{
id: 'new',
label: '新品榜',
metricLabel: '近7日',
emptyText: '近 7 日暂时还没有新品。',
},
{
id: 'like',
label: '点赞榜',
metricLabel: '点赞',
emptyText: '公开广场暂时还没有点赞作品。',
},
];
function ResolvedAssetBackdrop({
src,
fallbackSrc,
@@ -1362,14 +1335,12 @@ function DesktopTrendingItem({
function PlatformRankingItem({
entry,
rank,
metricLabel,
metricValue,
metric,
onClick,
}: {
entry: PlatformPublicGalleryCard;
rank: number;
metricLabel: string;
metricValue: number;
metric: PlatformRankingMetric;
onClick: () => void;
}) {
const coverImage = resolvePlatformWorldCoverImage(entry);
@@ -1405,9 +1376,9 @@ function PlatformRankingItem({
</div>
<div className="mt-1 flex min-w-0 flex-wrap items-center gap-x-1.5 gap-y-1 text-xs font-semibold text-[var(--platform-text-soft)]">
<span className="text-[var(--platform-warm-text)]">
{formatPlatformCompactCount(metricValue)}
{formatPlatformCompactCount(metric.value)}
</span>
<span>{metricLabel}</span>
<span>{metric.label}</span>
<span>·</span>
<span>{describePlatformPublicWorkKind(entry)}</span>
</div>
@@ -3567,8 +3538,9 @@ export function RpgEntryHomeView({
const [publicAuthorSummariesByKey, setPublicAuthorSummariesByKey] = useState<
Record<string, PublicUserSummary | null>
>({});
const [activeRankingTab, setActiveRankingTab] =
useState<PlatformRankingTab>('hot');
const [activeRankingTab, setActiveRankingTab] = useState<PlatformRankingTab>(
DEFAULT_PLATFORM_RANKING_TAB,
);
const [visitedTabs, setVisitedTabs] = useState<Set<PlatformHomeTab>>(
() => new Set([activeTab]),
);
@@ -4794,9 +4766,7 @@ export function RpgEntryHomeView({
activeTab,
mobileFeedCarouselEnabled,
]);
const activeRankingConfig = PLATFORM_RANKING_TABS.find(
(tab) => tab.id === activeRankingTab,
) as (typeof PLATFORM_RANKING_TABS)[number];
const activeRankingConfig = getPlatformRankingTabConfig(activeRankingTab);
const rankingEntries = useMemo(
() =>
buildPlatformRankingEntries(publicEntries, activeRankingTab).slice(0, 30),
@@ -5037,11 +5007,7 @@ export function RpgEntryHomeView({
key={`${buildPublicGalleryCardKey(entry)}:ranking:${activeRankingTab}`}
entry={entry}
rank={index + 1}
metricLabel={activeRankingConfig.metricLabel}
metricValue={getPlatformRankingMetricValue(
entry,
activeRankingTab,
)}
metric={getPlatformRankingMetric(entry, activeRankingTab)}
onClick={() => onOpenGalleryDetail(entry)}
/>
))}

View File

@@ -7,14 +7,18 @@ import {
buildPublicCategoryGroups,
buildPublicGalleryCardKey,
dedupePlatformPublicGalleryEntries,
DEFAULT_PLATFORM_RANKING_TAB,
filterPlatformWorkSearchResults,
filterTodayPublishedEntries,
getPlatformCategoryKindFilter,
getPlatformCategoryPrimaryMetric,
getPlatformPublicEntries,
getPlatformRankingMetric,
getPlatformRankingMetricValue,
getPlatformRankingTabConfig,
matchesPlatformCategoryKindFilter,
parsePlatformEntryTimestamp,
PLATFORM_RANKING_TABS,
selectAdjacentPlatformRecommendEntry,
selectPlatformRecommendFeedWindow,
sortPlatformCategoryEntries,
@@ -335,11 +339,32 @@ test('public gallery ViewModel ranks entries by selected metric', () => {
});
const entries = [recentWinner, remixWinner, likeWinner, playWinner];
expect(DEFAULT_PLATFORM_RANKING_TAB).toBe('hot');
expect(PLATFORM_RANKING_TABS.map((tab) => tab.label)).toEqual([
'热门榜',
'改造榜',
'新品榜',
'点赞榜',
]);
expect(getPlatformRankingTabConfig('new')).toEqual({
id: 'new',
label: '新品榜',
metricLabel: '近7日',
emptyText: '近 7 日暂时还没有新品。',
});
expect(buildPlatformRankingEntries(entries, 'hot')[0]).toBe(playWinner);
expect(buildPlatformRankingEntries(entries, 'remix')[0]).toBe(remixWinner);
expect(buildPlatformRankingEntries(entries, 'new')[0]).toBe(recentWinner);
expect(buildPlatformRankingEntries(entries, 'like')[0]).toBe(likeWinner);
expect(getPlatformRankingMetricValue(likeWinner, 'like')).toBe(40);
expect(getPlatformRankingMetric(recentWinner, 'new')).toEqual({
label: '近7日',
value: 30,
});
expect(getPlatformRankingMetric(playWinner, 'hot')).toEqual({
label: '游玩',
value: 100,
});
});
test('public gallery ViewModel sorts category entries and exposes primary metric', () => {

View File

@@ -15,6 +15,16 @@ import {
} from './rpgEntryWorldPresentation';
export type PlatformRankingTab = 'hot' | 'remix' | 'new' | 'like';
export type PlatformRankingTabConfig = {
emptyText: string;
id: PlatformRankingTab;
label: string;
metricLabel: string;
};
export type PlatformRankingMetric = {
label: string;
value: number;
};
export type PlatformCategoryKindFilter =
| 'all'
| 'puzzle'
@@ -33,6 +43,40 @@ export type PlatformPublicCategoryGroup = {
entries: PlatformPublicGalleryCard[];
};
export const DEFAULT_PLATFORM_RANKING_TAB: PlatformRankingTab = 'hot';
export const PLATFORM_RANKING_TABS: PlatformRankingTabConfig[] = [
{
id: 'hot',
label: '热门榜',
metricLabel: '游玩',
emptyText: '公开广场暂时还没有热门作品。',
},
{
id: 'remix',
label: '改造榜',
metricLabel: '改造',
emptyText: '公开广场暂时还没有改造作品。',
},
{
id: 'new',
label: '新品榜',
metricLabel: '近7日',
emptyText: '近 7 日暂时还没有新品。',
},
{
id: 'like',
label: '点赞榜',
metricLabel: '点赞',
emptyText: '公开广场暂时还没有点赞作品。',
},
];
const DEFAULT_PLATFORM_RANKING_CONFIG =
PLATFORM_RANKING_TABS.find(
(config) => config.id === DEFAULT_PLATFORM_RANKING_TAB,
) ?? PLATFORM_RANKING_TABS[0]!;
export type PlatformRecommendFeedWindow = {
activeEntry: PlatformPublicGalleryCard | null;
activeEntryKey: string | null;
@@ -372,6 +416,15 @@ export function buildPlatformRankingEntries(
return sortEntriesByMetric(entries, getPlatformWorldRecentPlayCount);
}
export function getPlatformRankingTabConfig(
tab: PlatformRankingTab,
): PlatformRankingTabConfig {
return (
PLATFORM_RANKING_TABS.find((config) => config.id === tab) ??
DEFAULT_PLATFORM_RANKING_CONFIG
);
}
export function getPlatformRankingMetricValue(
entry: PlatformPublicGalleryCard,
tab: PlatformRankingTab,
@@ -391,6 +444,16 @@ export function getPlatformRankingMetricValue(
return getPlatformWorldPlayCount(entry);
}
export function getPlatformRankingMetric(
entry: PlatformPublicGalleryCard,
tab: PlatformRankingTab,
): PlatformRankingMetric {
return {
label: getPlatformRankingTabConfig(tab).metricLabel,
value: getPlatformRankingMetricValue(entry, tab),
};
}
function getPlatformCategoryCompositeScore(entry: PlatformPublicGalleryCard) {
// 分类频道只使用公开读模型已经返回的指标做前端排序,不在 UI 层伪造评分数据。
return (