feat: server-side attachment thumbnails (480px webp at upload) + session caches - detail grids no longer download full originals

This commit is contained in:
root
2026-10-16 23:10:44 +08:00
parent 76cee988c0
commit 07f7cd51b2
19 changed files with 426 additions and 359 deletions
+15 -1
View File
@@ -57,6 +57,20 @@ ok((tl.body?.data?.groups?.length ?? 0) >= 1, 'timeline 有分组');
const st = await api(A, 'POST', '/api/stats_overview', {}, T);
ok(st.body?.ok === true, 'stats_overview 可用');
// 附件缩略图:上传带 thumb → 列表标记 → thumb/原图分离读取
const tl0 = await api(A, 'POST', '/api/type_list', {}, T);
const fpUp = await api(A, 'POST', '/api/footprint_upsert', { item: { type_id: (tl0.body?.data?.items || [])[0]?.id, title: '附件缩略图测试', status: 'finished' } }, T);
const fpId = fpUp.body?.data?.id;
ok(!!fpId, '创建附件测试足迹', fpUp.body);
const attAdd = await api(A, 'POST', '/api/attachment_add', { owner_id: fpId, file_name: 'photo.jpg', mime: 'image/jpeg', size: 8, data_b64: Buffer.from('ORIGDATA').toString('base64'), thumb_b64: Buffer.from('THUMBWEBPDATA').toString('base64') }, T);
ok(attAdd.body?.ok === true && !!attAdd.body?.data?.item?.thumb_rel_path, 'attachment_add 存储缩略图', attAdd.body);
const attList = await api(A, 'POST', '/api/attachment_list', { owner_id: fpId }, T);
ok(!!attList.body?.data?.items?.[0]?.thumb_rel_path, 'attachment_list 返回缩略图标记');
const attThumb = await api(A, 'POST', '/api/attachment_thumb', { id: attAdd.body?.data?.item?.id }, T);
ok(attThumb.body?.data?.data_b64 === Buffer.from('THUMBWEBPDATA').toString('base64'), 'attachment_thumb 返回缩略图内容', attThumb.body);
const attRead2 = await api(A, 'POST', '/api/attachment_read', { id: attAdd.body?.data?.item?.id }, T);
ok(attRead2.body?.data?.data_b64 === Buffer.from('ORIGDATA').toString('base64'), 'attachment_read 原图不受影响', attRead2.body);
// 邀请码:增
const c1 = await api(A, 'POST', '/admin/invites/create', { code: 'xiong-friend-2025', remark: '给学弟的码' }, T);
ok(c1.status === 200 && c1.body?.data?.code === 'XIONG-FRIEND-2025', '新建自定义码(大小写归一化)', c1.body);
@@ -97,7 +111,7 @@ const login2 = await api(B, 'POST', '/auth/login', { username: 'demo', password:
ok(login2.status === 200, '重启后 demo 可登录');
const T2 = login2.body.data.token;
const fp2 = await api(B, 'POST', '/api/footprint_list', { query: { page: 1, page_size: 50 } }, T2);
ok(fp2.body?.data?.total === 16, '重启后仍是 16 条(无重复播种)', fp2.body?.data?.total);
ok(fp2.body?.data?.total === 17, '重启后仍是 17 条(无重复播种)', fp2.body?.data?.total);
const list2 = (await api(B, 'GET', '/admin/invites', undefined, T2)).body.data.invites;
ok(list2.some((i) => i.code === 'XIONG-FRIEND-2025'), '邀请码跨重启持久化');