This commit is contained in:
2026-05-14 13:40:50 +08:00
parent 5a55180b78
commit 2dc9d752e4
24 changed files with 1873 additions and 98 deletions

View File

@@ -257,3 +257,70 @@ test('creation hub published work spans full mobile row', () => {
expect(html).toContain('col-span-2 sm:col-span-1');
expect(html).not.toContain('grid-cols-1 gap-3 md:grid-cols-2');
});
test('creation hub draft cards use cover background and hide updated time', () => {
const html = renderToStaticMarkup(
<CustomWorldCreationHub
mode="works-only"
items={[]}
puzzleItems={[
{
workId: 'puzzle:old-draft',
profileId: 'puzzle-profile-old',
ownerUserId: 'user-1',
authorDisplayName: '测试作者',
workTitle: '旧草稿',
workDescription: '先前修改的拼图草稿。',
levelName: '旧草稿',
summary: '先前修改的拼图草稿。',
themeTags: [],
coverImageSrc: '/covers/old-draft.webp',
publicationStatus: 'draft',
updatedAt: '2026-05-07T00:00:00.000Z',
publishedAt: null,
publishReady: false,
},
{
workId: 'puzzle:new-draft',
profileId: 'puzzle-profile-new',
ownerUserId: 'user-1',
authorDisplayName: '测试作者',
workTitle: '新草稿',
workDescription: '最近修改的拼图草稿。',
levelName: '新草稿',
summary: '最近修改的拼图草稿。',
themeTags: [],
coverImageSrc: '/covers/new-draft.webp',
publicationStatus: 'draft',
updatedAt: '1778457601.234567Z',
publishedAt: null,
publishReady: false,
},
]}
loading={false}
error={null}
onRetry={() => {}}
onCreateType={noopCreateType}
onOpenDraft={() => {}}
onEnterPublished={() => {}}
entryConfig={testEntryConfig}
creationTypes={testCreationTypes}
onOpenPuzzleDetail={() => {}}
/>,
);
const newerIndex = html.indexOf('新草稿');
const olderIndex = html.indexOf('旧草稿');
expect(newerIndex).toBeGreaterThanOrEqual(0);
expect(olderIndex).toBeGreaterThanOrEqual(0);
expect(newerIndex).toBeLessThan(olderIndex);
expect(html).toContain(
'class="absolute inset-0 h-full w-full object-cover" src="/covers/new-draft.webp"',
);
expect(html).toContain('src="/covers/new-draft.webp"');
expect(html).not.toContain('1778457601.234567Z');
expect(html).not.toContain('2026-05-07');
expect(html).not.toContain('更新于');
expect(html).not.toContain('最后修改');
});

View File

@@ -1,7 +1,10 @@
import { expect, test, vi } from 'vitest';
import type { BabyObjectMatchDraft } from '../../../packages/shared/src/contracts/edutainmentBabyObject';
import { buildCreationWorkShelfItems } from './creationWorkShelf';
import {
buildCreationWorkShelfItems,
getCreationWorkShelfItemTime,
} from './creationWorkShelf';
test('buildCreationWorkShelfItems maps visual novel items with VN public code', () => {
const items = buildCreationWorkShelfItems({
@@ -141,3 +144,54 @@ test('buildCreationWorkShelfItems maps baby object match local drafts', () => {
expect(items[1]?.status).toBe('draft');
expect(items[1]?.publicWorkCode).toBeNull();
});
test('buildCreationWorkShelfItems sorts works by latest updatedAt across timestamp formats', () => {
const items = buildCreationWorkShelfItems({
rpgItems: [],
bigFishItems: [],
puzzleItems: [
{
workId: 'puzzle:older',
profileId: 'puzzle-profile-older',
ownerUserId: 'user-1',
authorDisplayName: '测试作者',
levelName: '旧草稿',
summary: '较早修改。',
themeTags: [],
coverImageSrc: null,
publicationStatus: 'draft',
updatedAt: '2026-05-07T00:00:00.000Z',
publishedAt: null,
publishReady: false,
},
{
workId: 'puzzle:newer',
profileId: 'puzzle-profile-newer',
ownerUserId: 'user-1',
authorDisplayName: '测试作者',
levelName: '新草稿',
summary: '较晚修改。',
themeTags: [],
coverImageSrc: null,
publicationStatus: 'draft',
updatedAt: '1778457601.234567Z',
publishedAt: null,
publishReady: false,
},
],
});
expect(items.map((item) => item.id)).toEqual([
'puzzle:newer',
'puzzle:older',
]);
});
test('getCreationWorkShelfItemTime parses backend seconds.microsZ values', () => {
expect(getCreationWorkShelfItemTime('1778457601.234567Z')).toBe(
1778457601234.567,
);
expect(getCreationWorkShelfItemTime('2026-05-07T00:00:00.000Z')).toBe(
new Date('2026-05-07T00:00:00.000Z').getTime(),
);
});

View File

@@ -240,7 +240,8 @@ export function buildCreationWorkShelfItems(params: {
})
.sort(
(left, right) =>
getShelfItemTime(right.updatedAt) - getShelfItemTime(left.updatedAt),
getCreationWorkShelfItemTime(right.updatedAt) -
getCreationWorkShelfItemTime(left.updatedAt),
);
}
@@ -731,7 +732,25 @@ function buildStatusBadge(
};
}
function getShelfItemTime(value: string) {
const timestamp = new Date(value).getTime();
export function getCreationWorkShelfItemTime(value: string) {
const normalized = value.trim();
const numericTimestamp = normalized.match(/^(-?\d+(?:\.\d+)?)(?:Z)?$/u);
if (numericTimestamp?.[1]) {
const rawTimestamp = Number(numericTimestamp[1]);
if (Number.isFinite(rawTimestamp)) {
const absoluteTimestamp = Math.abs(rawTimestamp);
if (absoluteTimestamp >= 1_000_000_000_000_000) {
return rawTimestamp / 1000;
}
if (absoluteTimestamp >= 1_000_000_000_000) {
return rawTimestamp;
}
if (absoluteTimestamp >= 1_000_000_000) {
return rawTimestamp * 1000;
}
}
}
const timestamp = new Date(normalized).getTime();
return Number.isNaN(timestamp) ? 0 : timestamp;
}