perf(core): 全站资产改服务端懒加载,撤掉 bootstrap 全量 allAssets
不再在启动时一次性拉全部资产(数据多时随之变慢/串多页),各页按需服务端分页/过滤: - 生图(ImageWorkbench 模特库按 category=person、AssetFactory 按 ai 生成图)页面内懒加载。 - 商品库/项目向导封面图改用后端内嵌 cover_preview_url / images[].preview_url,不再反查全局 assets。 - 商品详情 AI 素材按 ?product 懒加载(上传/生成/采用三视图后刷新)。 - 工作台资产总数走轻量 /assets/summary/。 - App bootstrap 删除 api.allAssets() 与全局 assets state;loadData 仅留必要全局数据。 - 后端 ?product 过滤并集补上 ProductImage 关联资产,等价前端原 belongsToProduct。 - pipeline 用项目详情已内嵌的 *_url 显示,调用处传空 assets(不再依赖全局全量)。 闸验证:9 页功能正常、无分页瀑布、无接口报错;首屏不再含资产全量拉取。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+10
-16
@@ -102,7 +102,6 @@ export function App() {
|
||||
const [team, setTeam] = useState<Team | null>(null);
|
||||
const [products, setProducts] = useState<Product[]>([]);
|
||||
const [projects, setProjects] = useState<Project[]>([]);
|
||||
const [assets, setAssets] = useState<Asset[]>([]);
|
||||
const [teamMembers, setTeamMembers] = useState<TeamMember[]>([]);
|
||||
const [modelConfigs, setModelConfigs] = useState<ModelConfig[]>([]);
|
||||
const [aiTasks, setAiTasks] = useState<AITask[]>([]);
|
||||
@@ -139,11 +138,11 @@ export function App() {
|
||||
);
|
||||
|
||||
const loadData = useCallback(async () => {
|
||||
const [productData, projectData, assetData, billingData, ledgerData, trendData, memberData, modelData, taskData, notificationData] =
|
||||
// 资产不再全局取全:各页按需服务端分页懒加载(library/生图/商品详情/dashboard 自取)。
|
||||
const [productData, projectData, billingData, ledgerData, trendData, memberData, modelData, taskData, notificationData] =
|
||||
await Promise.all([
|
||||
api.products(),
|
||||
api.projects(),
|
||||
api.allAssets(),
|
||||
api.billingSummary().catch(() => null),
|
||||
api.ledgers(1, 10).catch(() => ({ count: 0, page: 1, page_size: 10, results: [] as Ledger[] })),
|
||||
api.billingTrend().catch(() => null),
|
||||
@@ -154,7 +153,6 @@ export function App() {
|
||||
]);
|
||||
setProducts(productData.results);
|
||||
setProjects(projectData.results);
|
||||
setAssets(assetData);
|
||||
setTeamMembers(memberData);
|
||||
setModelConfigs(modelData?.results || []);
|
||||
setAiTasks(taskData?.results || []);
|
||||
@@ -564,13 +562,12 @@ export function App() {
|
||||
function renderPage() {
|
||||
switch (page) {
|
||||
case "dashboard":
|
||||
return <Dashboard products={products} projects={projects} assets={assets} billing={billing} userName={currentUser.username} navigate={navigate} />;
|
||||
return <Dashboard products={products} projects={projects} billing={billing} userName={currentUser.username} navigate={navigate} />;
|
||||
case "products":
|
||||
return (
|
||||
<ProductsPage
|
||||
products={products}
|
||||
projects={projects}
|
||||
assets={assets}
|
||||
navigate={navigate}
|
||||
openProduct={(productId, tab) => navigate("productDetail", { productId, hash: tab === "videos" ? "videos" : undefined })}
|
||||
onCreate={(payload) => action(() => api.createProduct(payload), "")}
|
||||
@@ -585,7 +582,6 @@ export function App() {
|
||||
<ProductsPage
|
||||
products={products}
|
||||
projects={projects}
|
||||
assets={assets}
|
||||
navigate={navigate}
|
||||
openProduct={(productId, tab) => navigate("productDetail", { productId, hash: tab === "videos" ? "videos" : undefined })}
|
||||
onCreate={(payload) => action(() => api.createProduct(payload), "")}
|
||||
@@ -595,12 +591,11 @@ export function App() {
|
||||
/>
|
||||
);
|
||||
case "productDetail":
|
||||
if (!activeProduct) return <ProductsPage products={products} assets={assets} navigate={navigate} openProduct={(productId, tab) => navigate("productDetail", { productId, hash: tab === "videos" ? "videos" : undefined })} onCreate={(payload) => action(() => api.createProduct(payload), "")} onDelete={(productId) => action(() => api.deleteProduct(productId), "商品已删除")} />;
|
||||
if (!activeProduct) return <ProductsPage products={products} navigate={navigate} openProduct={(productId, tab) => navigate("productDetail", { productId, hash: tab === "videos" ? "videos" : undefined })} onCreate={(payload) => action(() => api.createProduct(payload), "")} onDelete={(productId) => action(() => api.deleteProduct(productId), "商品已删除")} />;
|
||||
return (
|
||||
<ProductDetailPage
|
||||
product={activeProduct}
|
||||
projects={projects.filter((project) => project.product === activeProduct.id)}
|
||||
assets={assets}
|
||||
initialTab={route.hash === "videos" ? "videos" : "assets"}
|
||||
navigate={navigate}
|
||||
onUpdate={(payload) => action(() => api.updateProduct(activeProduct.id, payload), "商品已更新")}
|
||||
@@ -626,7 +621,6 @@ export function App() {
|
||||
<ProjectWizardPage
|
||||
products={products}
|
||||
projects={projects}
|
||||
assets={assets}
|
||||
preselectProductId={activeProductId}
|
||||
onBack={() => navigate("projects")}
|
||||
onCreate={async (payload) => {
|
||||
@@ -699,13 +693,13 @@ export function App() {
|
||||
/>
|
||||
);
|
||||
case "assetFactory":
|
||||
return <AssetFactoryPage navigate={navigate} aiTasks={aiTasks} assets={assets} />;
|
||||
return <AssetFactoryPage navigate={navigate} aiTasks={aiTasks} />;
|
||||
case "imageOptimize":
|
||||
return <ImageWorkbenchPage mode="image" products={products} assets={assets} modelConfigs={modelConfigs} initialProductId={activeProductId} onBack={() => navigate("assetFactory")} navigate={navigate} onGenerate={generateImages} onResume={resumeImages} />;
|
||||
return <ImageWorkbenchPage mode="image" products={products} modelConfigs={modelConfigs} initialProductId={activeProductId} onBack={() => navigate("assetFactory")} navigate={navigate} onGenerate={generateImages} onResume={resumeImages} />;
|
||||
case "modelPhoto":
|
||||
return <ImageWorkbenchPage mode="model" products={products} assets={assets} modelConfigs={modelConfigs} initialProductId={activeProductId} onBack={() => navigate("assetFactory")} navigate={navigate} onGenerate={generateImages} onResume={resumeImages} />;
|
||||
return <ImageWorkbenchPage mode="model" products={products} modelConfigs={modelConfigs} initialProductId={activeProductId} onBack={() => navigate("assetFactory")} navigate={navigate} onGenerate={generateImages} onResume={resumeImages} />;
|
||||
case "platformCover":
|
||||
return <ImageWorkbenchPage mode="cover" products={products} assets={assets} modelConfigs={modelConfigs} initialProductId={activeProductId} onBack={() => navigate("assetFactory")} navigate={navigate} onGenerate={generateImages} onResume={resumeImages} />;
|
||||
return <ImageWorkbenchPage mode="cover" products={products} modelConfigs={modelConfigs} initialProductId={activeProductId} onBack={() => navigate("assetFactory")} navigate={navigate} onGenerate={generateImages} onResume={resumeImages} />;
|
||||
case "modelPhotoDemoA":
|
||||
return <ModelPhotoDemoPage variant="A" products={products} onBack={() => navigate("modelPhoto")} navigate={navigate} />;
|
||||
case "modelPhotoDemoB":
|
||||
@@ -715,7 +709,7 @@ export function App() {
|
||||
case "settingsNotify":
|
||||
return <SettingsPage user={currentUser} team={currentTeam} initialSection="notify" preferences={preferences} sessions={sessions} onSavePreferences={savePreferences} onRevokeSession={revokeSession} onRevokeOthers={revokeOtherSessions} onSaveProfile={saveProfile} onChangePassword={changeOwnPassword} onUploadAvatar={uploadOwnAvatar} onResetAvatar={resetOwnAvatar} onNotify={(text) => setNotice({ type: "success", text })} onLogout={logout} />;
|
||||
default:
|
||||
return <Dashboard products={products} projects={projects} assets={assets} billing={billing} navigate={navigate} />;
|
||||
return <Dashboard products={products} projects={projects} billing={billing} navigate={navigate} />;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -740,7 +734,7 @@ export function App() {
|
||||
team={currentTeam}
|
||||
products={products}
|
||||
projects={projects}
|
||||
assets={assets}
|
||||
assets={[]}
|
||||
billing={billing}
|
||||
notice={notice}
|
||||
unreadCount={unreadCount}
|
||||
|
||||
Reference in New Issue
Block a user