feat(core): 列表数据在途显示骨架屏(加载态),不再先显示空状态

渐进渲染后,列表在接口返回前会短暂显示「0 SKU / 显示 0」的空状态,易被误读为「没数据」。
新增 SkeletonGrid/SkeletonRows(components/loading),区分「加载中(请求在途且无数据)」与
「加载完确实为空」:

- 全局态页(商品库/视频项目/工作台最近项目):App 传 loading={!dataLoaded},未加载完显示骨架。
- 自取页(资产库/商品详情AI素材/图片生成任务/账单流水):各自 loading 标志,首次拉取时显示骨架/加载行。
- 团队成员有 owner 兜底行(非空)不改。

闸:9 页全绿、功能正常;实测 /products 加载期显示骨架→数据到后渲染真实卡片。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
zyc
2026-06-17 21:37:07 +08:00
co-authored by Claude Opus 4.8
parent 6e73fb53dd
commit 7c6d4477da
9 changed files with 228 additions and 78 deletions
+27
View File
@@ -0,0 +1,27 @@
/* 列表加载骨架屏:数据在途时显示「加载中」的形,而非空状态。冷灰底上做轻微 shimmer。 */
@keyframes sk-shimmer {
0% { background-position: -480px 0; }
100% { background-position: 480px 0; }
}
.skeleton-block {
background: var(--background-base, #f1f1f1);
background-image: linear-gradient(90deg, rgba(0,0,0,0.03) 0%, rgba(0,0,0,0.07) 40%, rgba(0,0,0,0.03) 80%);
background-size: 480px 100%;
background-repeat: no-repeat;
animation: sk-shimmer 1.2s ease-in-out infinite;
border-radius: 8px;
}
.skeleton-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 16px;
}
.skeleton-grid .skeleton-card { aspect-ratio: 1 / 1; }
.skeleton-rows { display: flex; flex-direction: column; gap: 10px; }
.skeleton-rows .skeleton-line { height: 56px; }
.skeleton-loading-tag {
font-family: var(--font-mono, monospace);
font-size: 12px;
color: var(--black-alpha-56, #8a8a8a);
padding: 4px 0 12px;
}
+28
View File
@@ -0,0 +1,28 @@
import "./loading.css";
// 列表数据在途时的骨架屏(grid 卡片 / 行),替代「为空」状态,让用户看到「加载中」而非「没数据」。
export function SkeletonGrid({ count = 8 }: { count?: number }) {
return (
<div>
<div className="skeleton-loading-tag">// 加载中…</div>
<div className="skeleton-grid">
{Array.from({ length: count }).map((_, i) => (
<div className="skeleton-block skeleton-card" key={i} />
))}
</div>
</div>
);
}
export function SkeletonRows({ count = 6 }: { count?: number }) {
return (
<div>
<div className="skeleton-loading-tag">// 加载中…</div>
<div className="skeleton-rows">
{Array.from({ length: count }).map((_, i) => (
<div className="skeleton-block skeleton-line" key={i} />
))}
</div>
</div>
);
}