refactor: 收口排行配置模型
This commit is contained in:
@@ -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)}
|
||||
/>
|
||||
))}
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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 (
|
||||
|
||||
Reference in New Issue
Block a user