perf(core): 非资产全局态也改按页懒加载,bootstrap 从 ~10 接口瘦到 ~6

启动只保留「每页 shell 都要」的全局数据:商品/项目(侧栏+导航)、余额(顶栏)、
模型配置(多生成页+pipeline 共用)、未读数(侧栏徽标,page_size=1 轻量)。其余移到各页按需:
- 账户页:流水(本就服务端分页)+ 趋势 + 团队成员 本页自取,充值后刷新。
- 团队页:成员 + 团队动态 本页自取,增删成员/充值后刷新。
- 生图工厂:任务历史 + 任务缩略图本页自取。
- 通知:bootstrap 只取 page_size=1 拿未读数(notificationsBadge),列表由消息中心/团队页各自拉。
- 全局默认分页改 DefaultPagination(支持 ?page_size 覆盖,默认 20 上限 200):
  根治 projects/products 等列表端点忽略 page_size、数据过 20 即被迫翻页(同 assets 旧病)。

闸:9 页功能正常、无瀑布、API 检查全过;首屏接口数 5~8(原 8~13)。perf 预算下调到新基线。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
zyc
2026-06-17 18:58:53 +08:00
co-authored by Claude Opus 4.8
parent d959543d43
commit f1bc5933ef
8 changed files with 74 additions and 57 deletions
+18 -7
View File
@@ -45,23 +45,32 @@ const STAGES: Array<{ k: string; color: string; bucket: keyof BillingTrend["by_s
{ k: "脚本 LLM", color: "var(--black-alpha-32)", bucket: "script" }
];
export function AccountPage({ billing, ledgers, trend, projects, teamMembers, onRecharge }: {
export function AccountPage({ billing, projects, onRecharge }: {
billing: BillingSummary | null;
ledgers: Ledger[];
trend: BillingTrend | null;
projects: Project[];
teamMembers: TeamMember[];
onRecharge: (amount: number, bonus: number) => void | Promise<unknown>;
}) {
const [tab, setTab] = useState<Tab>("overview");
const [recharge, setRecharge] = useState(500);
const [customAmt, setCustomAmt] = useState("");
// 账户页数据本页自取(不再走全局 bootstrap):充值后 bump 刷新流水/趋势
const [reloadFlag, setReloadFlag] = useState(0);
// 趋势(day,首屏)+ 团队成员(成员/限额 tab)本页懒加载
const [trend, setTrend] = useState<BillingTrend | null>(null);
const [teamMembers, setTeamMembers] = useState<TeamMember[]>([]);
useEffect(() => {
let alive = true;
api.billingTrend().then((d) => { if (alive) setTrend(d); }).catch(() => {});
api.teamMembers().then((m) => { if (alive) setTeamMembers(m); }).catch(() => {});
return () => { alive = false; };
}, [reloadFlag]);
// 账单流水分页:服务端分页(总数随流水增长,不再写死 100),每页 10 条
const BILLS_PER_PAGE = 10;
const [billPage, setBillPage] = useState(1);
const [ledgerRows, setLedgerRows] = useState<Ledger[]>(ledgers);
const [ledgerCount, setLedgerCount] = useState<number>(ledgers.length);
const [ledgerRows, setLedgerRows] = useState<Ledger[]>([]);
const [ledgerCount, setLedgerCount] = useState<number>(0);
useEffect(() => {
let alive = true;
api.ledgers(billPage, BILLS_PER_PAGE).then((data) => {
@@ -70,7 +79,7 @@ export function AccountPage({ billing, ledgers, trend, projects, teamMembers, on
setLedgerCount(data.count);
}).catch(() => {});
return () => { alive = false; };
}, [billPage]);
}, [billPage, reloadFlag]);
const billTotalPages = Math.max(1, Math.ceil(ledgerCount / BILLS_PER_PAGE));
const safeBillPage = Math.min(billPage, billTotalPages);
@@ -82,6 +91,8 @@ export function AccountPage({ billing, ledgers, trend, projects, teamMembers, on
if (effectiveAmount <= 0) return;
await onRecharge(effectiveAmount, effectiveBonus);
setCustomAmt("");
setBillPage(1);
setReloadFlag((n) => n + 1); // 充值后刷新流水/趋势(余额由全局 action→loadData 刷新)
}
const balance = Number(billing?.account.balance || 0);