From 59ab3c040444d86833c8f4398f886130051b853f Mon Sep 17 00:00:00 2001 From: zyc <1439655764@qq.com> Date: Wed, 17 Jun 2026 18:10:05 +0800 Subject: [PATCH] =?UTF-8?q?perf(core):=20=E8=B5=84=E4=BA=A7=E5=BA=93?= =?UTF-8?q?=E6=94=B9=E6=9C=8D=E5=8A=A1=E7=AB=AF=E6=87=92=E5=8A=A0=E8=BD=BD?= =?UTF-8?q?=E5=88=86=E9=A1=B5(tab/=E7=AD=9B=E9=80=89/=E8=AE=A1=E6=95=B0?= =?UTF-8?q?=E8=B5=B0=E5=90=8E=E7=AB=AF,=E4=B8=8D=E5=86=8D=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E5=8F=96=E5=85=A8=E9=87=8F=E5=88=87=E7=89=87)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - api.ts 加 assetsPage(分页+tab/category/source/type/product/q/metadata 过滤)、 assetSummary(tab 计数)、assetFacets(某 tab 真实存在的来源/类型/metadata 取值)。 - LibraryPage 不再吃全局 assets 全量数组:列表按页拉、tab 徽标走 summary、 筛选下拉走 facets(「只列真有的」体验保留)、搜索去抖、上传/删除后刷新。 - App.tsx 不再向 LibraryPage 透传 assets。 Co-Authored-By: Claude Opus 4.8 --- core/frontend/src/App.tsx | 2 +- core/frontend/src/api.ts | 24 ++++++++ core/frontend/src/routes/library.tsx | 91 +++++++++++++++++++--------- 3 files changed, 86 insertions(+), 31 deletions(-) diff --git a/core/frontend/src/App.tsx b/core/frontend/src/App.tsx index f978a04..8b7f4f3 100644 --- a/core/frontend/src/App.tsx +++ b/core/frontend/src/App.tsx @@ -660,7 +660,7 @@ export function App() { ); case "library": - return action(() => api.uploadAsset(formData), "资产已上传")} onDelete={(id) => action(() => api.deleteAsset(id), "资产已删除")} />; + return action(() => api.uploadAsset(formData), "资产已上传")} onDelete={(id) => action(() => api.deleteAsset(id), "资产已删除")} />; case "account": return ( >("/api/assets/"); }, + // 服务端分页+过滤的资产列表(各页按需懒加载,不再前端取全量再切片)。 + assetsPage(params: { + tab?: string; category?: string; source?: string; asset_type?: string; + product?: string; q?: string; ordering?: string; page?: number; pageSize?: number; + meta?: Record; + } = {}) { + const qs = new URLSearchParams(); + const { meta, pageSize, ...rest } = params; + for (const [k, v] of Object.entries(rest)) if (v !== undefined && v !== "" && v !== null) qs.set(k, String(v)); + if (pageSize) qs.set("page_size", String(pageSize)); + if (meta) for (const [k, v] of Object.entries(meta)) if (v) qs.set(`m_${k}`, v); + return request>(`/api/assets/?${qs.toString()}`); + }, + // 资产库各 tab 计数(tab 徽标用,不必取全量) + assetSummary() { + return request>("/api/assets/summary/"); + }, + // 某 tab 下真实存在的筛选项(来源/类型/指定 metadata 键取值),供下拉「只列真有的」 + assetFacets(tab?: string, metaKeys: string[] = []) { + const qs = new URLSearchParams(); + if (tab) qs.set("tab", tab); + if (metaKeys.length) qs.set("meta_keys", metaKeys.join(",")); + return request<{ sources: string[]; kinds: string[]; metadata: Record }>(`/api/assets/facets/?${qs.toString()}`); + }, // 经后端同源代理取资产原始文件(TOS 未配 CORS,浏览器抽帧/解码必须同源) async fetchAssetBlob(id: string): Promise { const token = getToken(); diff --git a/core/frontend/src/routes/library.tsx b/core/frontend/src/routes/library.tsx index 4a697ed..a7da2f0 100644 --- a/core/frontend/src/routes/library.tsx +++ b/core/frontend/src/routes/library.tsx @@ -1,5 +1,6 @@ import { useEffect, useState } from "react"; import type { FormEvent } from "react"; +import { api } from "../api"; import type { Asset } from "../types"; import { ConfirmModal, Drawer, MediaLightbox } from "../components/overlays"; import { Pager } from "../components/pager"; @@ -53,7 +54,7 @@ function assetTab(asset: Asset): LibTab { } } -export function LibraryPage({ assets, onUpload, onDelete }: { assets: Asset[]; onUpload: (formData: FormData) => Promise | void; onDelete?: (id: string) => Promise | void }) { +export function LibraryPage({ onUpload, onDelete }: { onUpload: (formData: FormData) => Promise | void; onDelete?: (id: string) => Promise | void }) { const [tab, setTab] = useState("people"); const [query, setQuery] = useState(""); const [drawer, setDrawer] = useState(false); @@ -75,12 +76,62 @@ export function LibraryPage({ assets, onUpload, onDelete }: { assets: Asset[]; o return () => document.body.classList.remove("edit-mode"); }, [editMode]); - // 分页:每页 10 个,切 tab / 改筛选 / 改排序回到第 1 页(数据多时全量渲染卡顿,视频卡每张挂一个