From 76ee18133ec61d7fce2ae2dc6c370f04a37ba9c3 Mon Sep 17 00:00:00 2001 From: Suzumiya Date: Wed, 7 Oct 2026 12:34:24 +0800 Subject: [PATCH] =?UTF-8?q?feat(agc):=20=E5=85=B1=E5=88=9B=E5=8D=A1?= =?UTF-8?q?=E7=89=87=E8=A1=A5=E6=98=BE=E7=A4=BA=E4=BD=9C=E5=93=81=E8=87=AA?= =?UTF-8?q?=E8=BA=AB=E6=B8=B8=E7=8E=A9=E6=AC=A1=E6=95=B0=EF=BC=88=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E7=AB=AF=E6=97=A0=E6=A0=91=EF=BC=8C=E4=B8=8D=E5=86=99?= =?UTF-8?q?=E5=90=88=E8=AE=A1=E5=8F=A3=E5=BE=84=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../features/platform-fork/forkPageStyles.ts | 6 ++ .../platform-fork/platformForkCatalog.ts | 16 +++++ .../src/view/co-creation/index.tsx | 27 +++++-- .../tests/coCreation.test.tsx | 71 ++++++++++++++++++- 4 files changed, 115 insertions(+), 5 deletions(-) diff --git a/apps/ai-game-creator-shell/src/features/platform-fork/forkPageStyles.ts b/apps/ai-game-creator-shell/src/features/platform-fork/forkPageStyles.ts index 16e4ff8b9..d84e5d00b 100644 --- a/apps/ai-game-creator-shell/src/features/platform-fork/forkPageStyles.ts +++ b/apps/ai-game-creator-shell/src/features/platform-fork/forkPageStyles.ts @@ -81,6 +81,12 @@ export const FORK_STICKY_FOOTER = /** 卡片里的「标签 → 数值」两列表:标签列定宽 + 数值列等宽数字,避免换行跳动。 */ export const FORK_META_GRID = 'grid grid-cols-[52px_minmax(0,1fr)] items-baseline gap-x-2 gap-y-1 text-[11px] leading-4'; +/** + * 同上一套,但行距收到 2px:给「四行信息」(作者 / 类型 / 游玩 / 创建时间)的列表卡片用, + * 让多出来的一行不至于把卡片撑高。字号与颜色与 `FORK_META_GRID` 完全一致。 + */ +export const FORK_META_GRID_COMPACT = + 'grid grid-cols-[52px_minmax(0,1fr)] items-baseline gap-x-2 gap-y-0.5 text-[11px] leading-4'; export const FORK_META_LABEL = 'whitespace-nowrap text-(--platform-text-soft)'; export const FORK_META_VALUE = 'min-w-0 truncate whitespace-nowrap tabular-nums text-(--platform-neutral-text)'; diff --git a/apps/ai-game-creator-shell/src/features/platform-fork/platformForkCatalog.ts b/apps/ai-game-creator-shell/src/features/platform-fork/platformForkCatalog.ts index f1294902d..9709cff71 100644 --- a/apps/ai-game-creator-shell/src/features/platform-fork/platformForkCatalog.ts +++ b/apps/ai-game-creator-shell/src/features/platform-fork/platformForkCatalog.ts @@ -62,6 +62,22 @@ function formatLocalDate(date: Date): string | null { return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`; } +/** + * 卡片上的游玩次数文案:只格式化**该作品自身**的 `playCount`(公开目录投影保证下发)。 + * + * 为什么是自身值:客户端拿不到血缘树(要树得逐作品拉 `/lineage`,列表页不能这么打接口), + * 因此**刻意与网页侧不同**——网页侧能按子树合计,客户端只能给自身值。文案只写「N 次」, + * 不出现「含衍生」这类会被读成合计的措辞。 + * + * 缺失/非法(旧响应或字段被裁)返回 `null`,由调用方整行不渲染,不留恒为「—」的死行。 + */ +export function formatCatalogPlayCount(value: unknown): string | null { + if (typeof value !== 'number' || !Number.isFinite(value)) { + return null; + } + return `${Math.max(0, Math.floor(value)).toLocaleString('zh-CN')} 次`; +} + /** 支持共创 = 授权不是「禁止共创」;字段缺省按 `forbidden` 处理(与契约一致)。 */ export function isForkableGame(game: GameDistributionGame): boolean { return (game.forkAuthorization ?? 'forbidden') !== 'forbidden'; diff --git a/apps/ai-game-creator-shell/src/view/co-creation/index.tsx b/apps/ai-game-creator-shell/src/view/co-creation/index.tsx index 3efe9a344..32a140e3b 100644 --- a/apps/ai-game-creator-shell/src/view/co-creation/index.tsx +++ b/apps/ai-game-creator-shell/src/view/co-creation/index.tsx @@ -20,7 +20,7 @@ import { FORK_BODY_TEXT, FORK_BUTTON_SECONDARY, FORK_CARD, - FORK_META_GRID, + FORK_META_GRID_COMPACT, FORK_META_LABEL, FORK_META_VALUE, FORK_PAGE_COLUMN, @@ -34,6 +34,7 @@ import { FORK_CATALOG_MAX_PAGES, type ForkCatalogResult, formatCatalogCreatedAt, + formatCatalogPlayCount, loadForkableGames, } from '../../features/platform-fork/platformForkCatalog'; import { usePlatformForkCovers } from '../../features/platform-fork/usePlatformForkCovers'; @@ -202,6 +203,7 @@ export default function CoCreationView({ onOpenConfirm }: CoCreationViewProps) { {games.map((game) => { const coverUrl = coverUrls[game.id]; const createdAt = formatCatalogCreatedAt(game.createdAt); + const selfPlayCountLabel = formatCatalogPlayCount(game.playCount); return (
)} - + {game.title || '(无标题)'} - + 作者 {game.author?.name || '—'} @@ -240,6 +242,23 @@ export default function CoCreationView({ onOpenConfirm }: CoCreationViewProps) { {game.category || '—'} + {/* + 游玩次数:**只显示该作品自身的计数**(`game.playCount`),不叠加任何子代。 + 客户端拿不到血缘树(要树得逐作品拉 `/lineage`,列表页不能这么打接口), + 所以这里与网页端**刻意不同**——网页侧能按子树合计,客户端只能给自身值。 + 因此文案固定写「游玩 N 次」,**不写「含衍生」之类会被读成合计的措辞**: + 这不是漏了聚合,是客户端没有聚合所需的数据(别当成 bug 修)。 + 字段由公开目录投影保证下发(api-server `public_game_payload` → `"playCount"`); + 万一缺失/非法就整行不渲染,不留恒为「—」的死行。 + */} + {selfPlayCountLabel ? ( + <> + 游玩 + + {selfPlayCountLabel} + + + ) : null} {/* 公开目录没有 `updatedAt`,只有 `createdAt`:标签就写「创建时间」, 取不到时整行不渲染(不留恒为「—」的死行)。 @@ -252,7 +271,7 @@ export default function CoCreationView({ onOpenConfirm }: CoCreationViewProps) { ) : null}