fix(web): show five portrait work cards per desktop row
douyin-release-gate / verify (push) Failing after 12m45s

This commit is contained in:
2026-10-06 13:43:55 +08:00
parent 950b23da32
commit 7c6fb54164
3 changed files with 83 additions and 3 deletions
+3 -3
View File
@@ -35,10 +35,10 @@ export function WorkCover({ workID, title }: { workID: string; title?: string })
};
}, [workID]);
if (src) {
return <img src={src} alt={title || '作品封面'} style={{ width: '100%', aspectRatio: '16 / 9', objectFit: 'cover' }} />;
return <img src={src} alt={title || '作品封面'} style={{ width: '100%', aspectRatio: '9 / 16', objectFit: 'cover' }} />;
}
return (
<Flex align="center" justify="center" style={{ aspectRatio: '16 / 9', background: '#f5f5f5' }}>
<Flex align="center" justify="center" style={{ aspectRatio: '9 / 16', background: '#f5f5f5' }}>
<Typography.Text type="secondary" style={{ fontSize: 12 }}>{missing ? '封面未缓存' : '封面加载中'}</Typography.Text>
</Flex>
);
@@ -267,7 +267,7 @@ export default function WorksGallery({ sourceId, sourceType, emptyHint, extraFil
{works.length ? (
<Row gutter={[16, 16]}>
{works.map((work) => (
<Col key={work.id} xs={24} sm={12} lg={8} xl={6}>
<Col key={work.id} xs={24} sm={12} lg={8} xl={{ flex: '20%' }}>
<Card
hoverable
style={{ height: '100%' }}
@@ -191,6 +191,74 @@ test('详情作品总数使用完整采集历史,而非仅依赖最近指标
assert.equal(byType(card(tree, '账号数据'), 'Statistic')[4].props.value, '100');
});
for (const [name, props] of [
['我的账号详情', { sourceId: 'owned-1', sourceType: 'owned' }],
['监控账号详情', { sourceId: 'monitor-1', sourceType: 'competitor' }],
['竞品分析', { sourceType: 'competitor', extraFilters: { min_likes: 100 } }],
]) {
test(`${name}作品列表桌面五列,窄屏保持一至三列`, async () => {
const works = Array.from({ length: 6 }, (_, i) => ({ id: `work-${i}`, title: `作品${i}` }));
const page = harness('src/components/creator/WorksGallery.tsx', {
workPages: { 1: { data: works, total: 30, hasNext: true } },
collectionStatus: { work_count: 30, aweme_count: 30, works: { status: 'succeeded' } },
});
const tree = await page.mount(props);
const columns = byType(card(tree, '作品列表'), 'Col');
assert.equal(columns.length, 6);
columns.forEach(({ props: column }, i) => {
assert.equal(column.xs, 24);
assert.equal(column.sm, 12);
assert.equal(column.lg, 8);
assert.deepEqual(column.xl, { flex: '20%' });
assert.equal(column.children.props.cover.props.workID, works[i].id);
assert.equal(typeof column.children.props.onClick, 'function');
});
assert.equal(byType(tree, 'Pagination')[0].props.pageSize, 25);
assert.equal(page.calls.lists[0].pageSize, 25);
assert.equal(page.calls.lists[0].filters.source_id, props.sourceId);
assert.equal(page.calls.lists[0].filters.source_type, props.sourceType);
assert.equal(page.calls.lists[0].filters.min_likes, props.extraFilters?.min_likes);
page.unmount();
});
}
test('作品封面加载占位与成功图片均为9:16,图片裁切显示并释放缓存地址', async (t) => {
const blob = new Blob(['cover'], { type: 'image/jpeg' });
const createURL = t.mock.method(URL, 'createObjectURL', () => 'blob:portrait-cover');
const revokeURL = t.mock.method(URL, 'revokeObjectURL', () => {});
const requests = [];
const cover = harness('src/components/creator/WorksGallery.tsx', {
services: { fetchCreatorBinary: async (url) => { requests.push(url); return blob; } },
}, 'WorkCover');
let tree = cover.render({ workID: 'work/1', title: '作品标题' });
assert.equal(tree.props.style.aspectRatio, '9 / 16');
assert.match(text(tree), /封面加载中/);
await flush();
tree = cover.render();
assert.equal(tree.type, 'img');
assert.equal(tree.props.style.aspectRatio, '9 / 16');
assert.equal(tree.props.style.width, '100%');
assert.equal(tree.props.style.objectFit, 'cover');
assert.equal(tree.props.src, 'blob:portrait-cover');
assert.equal(tree.props.alt, '作品标题');
assert.deepEqual(requests, ['/creator/works/work%2F1/cover']);
assert.equal(createURL.mock.calls[0].arguments[0], blob);
cover.unmount();
assert.deepEqual(revokeURL.mock.calls[0].arguments, ['blob:portrait-cover']);
});
test('缺失封面也保持9:16,不使用远程图片代替', async () => {
const cover = harness('src/components/creator/WorksGallery.tsx', {
services: { fetchCreatorBinary: async () => { throw new Error('封面不存在'); } },
}, 'WorkCover');
const tree = await cover.mount({ workID: 'missing-work' });
assert.equal(tree.type, 'Flex');
assert.equal(tree.props.style.aspectRatio, '9 / 16');
assert.match(text(tree), /封面未缓存/);
assert.equal(byType(tree, 'img').length, 0);
cover.unmount();
});
test('自有账号作品展示独立采集进度,历史作品可翻页且筛选不改变进度分母', async () => {
const api = {
collectionStatus: { work_count: 28, aweme_count: 100, works: { status: 'succeeded' } },
+12
View File
@@ -48,6 +48,18 @@ function sourceText() {
return source.getFullText();
}
for (const [name, pagePath] of [
['我的账号详情', 'accounts/$id'],
['监控账号详情', 'accounts/monitoring/$id'],
['竞品分析', 'creator/competitors'],
]) {
test(`${name}使用共用作品列表,列数与封面比例保持一致`, () => {
const page = readFileSync(`${__dirname}/../src/pages/${pagePath}/index.tsx`, 'utf8');
assert.match(page, /import WorksGallery from '@\/components\/creator\/WorksGallery'/);
assert.match(page, /<WorksGallery\b/);
});
}
const competitorsPageText = readFileSync(`${__dirname}/../src/pages/creator/competitors/index.tsx`, 'utf8');
test('竞品分析页复用 WorksGallery,不再自建作品卡片/详情抽屉', () => {