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:
@@ -133,7 +133,7 @@ REST_FRAMEWORK = {
|
|||||||
"DEFAULT_PERMISSION_CLASSES": [
|
"DEFAULT_PERMISSION_CLASSES": [
|
||||||
"rest_framework.permissions.IsAuthenticated",
|
"rest_framework.permissions.IsAuthenticated",
|
||||||
],
|
],
|
||||||
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
|
"DEFAULT_PAGINATION_CLASS": "apps.common.pagination.DefaultPagination",
|
||||||
"DEFAULT_FILTER_BACKENDS": [
|
"DEFAULT_FILTER_BACKENDS": [
|
||||||
"rest_framework.filters.SearchFilter",
|
"rest_framework.filters.SearchFilter",
|
||||||
"rest_framework.filters.OrderingFilter",
|
"rest_framework.filters.OrderingFilter",
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
from rest_framework.pagination import PageNumberPagination
|
||||||
|
|
||||||
|
|
||||||
|
class DefaultPagination(PageNumberPagination):
|
||||||
|
"""全局默认分页:默认 20 条/页,允许前端用 ?page_size= 覆盖(上限 200)。
|
||||||
|
各列表端点据此可按需懒加载/取大页,不再因默认类忽略 page_size 而被迫并行翻页。"""
|
||||||
|
|
||||||
|
page_size_query_param = "page_size"
|
||||||
|
max_page_size = 200
|
||||||
+10
-35
@@ -102,14 +102,8 @@ export function App() {
|
|||||||
const [team, setTeam] = useState<Team | null>(null);
|
const [team, setTeam] = useState<Team | null>(null);
|
||||||
const [products, setProducts] = useState<Product[]>([]);
|
const [products, setProducts] = useState<Product[]>([]);
|
||||||
const [projects, setProjects] = useState<Project[]>([]);
|
const [projects, setProjects] = useState<Project[]>([]);
|
||||||
const [teamMembers, setTeamMembers] = useState<TeamMember[]>([]);
|
|
||||||
const [modelConfigs, setModelConfigs] = useState<ModelConfig[]>([]);
|
const [modelConfigs, setModelConfigs] = useState<ModelConfig[]>([]);
|
||||||
const [aiTasks, setAiTasks] = useState<AITask[]>([]);
|
|
||||||
const [billing, setBilling] = useState<BillingSummary | null>(null);
|
const [billing, setBilling] = useState<BillingSummary | null>(null);
|
||||||
const [ledgers, setLedgers] = useState<Ledger[]>([]);
|
|
||||||
const [billingTrend, setBillingTrend] = useState<BillingTrend | null>(null);
|
|
||||||
const [notifications, setNotifications] = useState<Notification[]>([]);
|
|
||||||
const [notificationTotal, setNotificationTotal] = useState(0); // 后端真实总数(团队动态「共 N」用,与已加载的近期 100 条区分)
|
|
||||||
const [unreadCount, setUnreadCount] = useState(0);
|
const [unreadCount, setUnreadCount] = useState(0);
|
||||||
const [projectDetail, setProjectDetail] = useState<Project | null>(null);
|
const [projectDetail, setProjectDetail] = useState<Project | null>(null);
|
||||||
const [exportResult, setExportResult] = useState<ExportPoll | null>(null);
|
const [exportResult, setExportResult] = useState<ExportPoll | null>(null);
|
||||||
@@ -138,32 +132,22 @@ export function App() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const loadData = useCallback(async () => {
|
const loadData = useCallback(async () => {
|
||||||
// 资产不再全局取全:各页按需服务端分页懒加载(library/生图/商品详情/dashboard 自取)。
|
// bootstrap 只拉「每页 shell 都要」的全局数据:商品/项目(侧栏+导航+active 解析)、余额(顶栏)、
|
||||||
const [productData, projectData, billingData, ledgerData, trendData, memberData, modelData, taskData, notificationData] =
|
// 模型配置(多生成页+pipeline 共用)、未读数(侧栏徽标,page_size=1 轻量)。
|
||||||
|
// 资产/流水/趋势/成员/任务/通知列表均改各页按需懒加载,不再全局取全。
|
||||||
|
const [productData, projectData, billingData, modelData, badgeData] =
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
api.products(),
|
api.products(),
|
||||||
api.projects(),
|
api.projects(),
|
||||||
api.billingSummary().catch(() => null),
|
api.billingSummary().catch(() => null),
|
||||||
api.ledgers(1, 10).catch(() => ({ count: 0, page: 1, page_size: 10, results: [] as Ledger[] })),
|
|
||||||
api.billingTrend().catch(() => null),
|
|
||||||
api.teamMembers().catch(() => []),
|
|
||||||
api.modelConfigs().catch(() => null),
|
api.modelConfigs().catch(() => null),
|
||||||
api.aiTasks().catch(() => null),
|
api.notificationsBadge().catch(() => null)
|
||||||
api.allNotifications().catch(() => null)
|
|
||||||
]);
|
]);
|
||||||
setProducts(productData.results);
|
setProducts(productData.results);
|
||||||
setProjects(projectData.results);
|
setProjects(projectData.results);
|
||||||
setTeamMembers(memberData);
|
|
||||||
setModelConfigs(modelData?.results || []);
|
setModelConfigs(modelData?.results || []);
|
||||||
setAiTasks(taskData?.results || []);
|
|
||||||
if (billingData) setBilling(billingData);
|
if (billingData) setBilling(billingData);
|
||||||
setLedgers(ledgerData.results);
|
if (badgeData) setUnreadCount(badgeData.unread_count);
|
||||||
setBillingTrend(trendData);
|
|
||||||
if (notificationData) {
|
|
||||||
setNotifications(notificationData.results);
|
|
||||||
setNotificationTotal(notificationData.count);
|
|
||||||
setUnreadCount(notificationData.unread_count);
|
|
||||||
}
|
|
||||||
setActiveProjectId((current) => current || projectData.results[0]?.id || "");
|
setActiveProjectId((current) => current || projectData.results[0]?.id || "");
|
||||||
setActiveProductId((current) => current || productData.results[0]?.id || "");
|
setActiveProductId((current) => current || productData.results[0]?.id || "");
|
||||||
}, []);
|
}, []);
|
||||||
@@ -210,13 +194,10 @@ export function App() {
|
|||||||
setSessions(await api.loginSessions().catch(() => []));
|
setSessions(await api.loginSessions().catch(() => []));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 只刷新侧边栏未读徽标(通知列表由消息中心/团队页各自拉);标记已读后调用
|
||||||
const reloadNotifications = useCallback(async () => {
|
const reloadNotifications = useCallback(async () => {
|
||||||
const data = await api.allNotifications().catch(() => null);
|
const data = await api.notificationsBadge().catch(() => null);
|
||||||
if (data) {
|
if (data) setUnreadCount(data.unread_count);
|
||||||
setNotifications(data.results);
|
|
||||||
setNotificationTotal(data.count);
|
|
||||||
setUnreadCount(data.unread_count);
|
|
||||||
}
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Boot: validate token, hydrate identity + data.
|
// Boot: validate token, hydrate identity + data.
|
||||||
@@ -659,10 +640,7 @@ export function App() {
|
|||||||
return (
|
return (
|
||||||
<AccountPage
|
<AccountPage
|
||||||
billing={billing}
|
billing={billing}
|
||||||
ledgers={ledgers}
|
|
||||||
trend={billingTrend}
|
|
||||||
projects={projects}
|
projects={projects}
|
||||||
teamMembers={teamMembers}
|
|
||||||
onRecharge={(amount, bonus) => action(() => api.recharge({ amount, bonus }), "充值成功")}
|
onRecharge={(amount, bonus) => action(() => api.recharge({ amount, bonus }), "充值成功")}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -671,10 +649,7 @@ export function App() {
|
|||||||
<TeamPage
|
<TeamPage
|
||||||
team={currentTeam}
|
team={currentTeam}
|
||||||
user={currentUser}
|
user={currentUser}
|
||||||
members={teamMembers}
|
|
||||||
billing={billing}
|
billing={billing}
|
||||||
notifications={notifications}
|
|
||||||
notificationTotal={notificationTotal}
|
|
||||||
navigate={navigate}
|
navigate={navigate}
|
||||||
onCreateMember={(payload) => action(() => api.createTeamMember(payload), "成员账户已创建")}
|
onCreateMember={(payload) => action(() => api.createTeamMember(payload), "成员账户已创建")}
|
||||||
onUpdateMember={(id, payload) => action(() => api.updateTeamMember(id, payload), "成员已更新")}
|
onUpdateMember={(id, payload) => action(() => api.updateTeamMember(id, payload), "成员已更新")}
|
||||||
@@ -693,7 +668,7 @@ export function App() {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case "assetFactory":
|
case "assetFactory":
|
||||||
return <AssetFactoryPage navigate={navigate} aiTasks={aiTasks} />;
|
return <AssetFactoryPage navigate={navigate} />;
|
||||||
case "imageOptimize":
|
case "imageOptimize":
|
||||||
return <ImageWorkbenchPage mode="image" products={products} 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":
|
case "modelPhoto":
|
||||||
|
|||||||
@@ -472,6 +472,10 @@ export const api = {
|
|||||||
async allNotifications(): Promise<NotificationList> {
|
async allNotifications(): Promise<NotificationList> {
|
||||||
return request<NotificationList>(`/api/ops/notifications/?page_size=100`);
|
return request<NotificationList>(`/api/ops/notifications/?page_size=100`);
|
||||||
},
|
},
|
||||||
|
// 侧边栏未读徽标:只要 unread_count,取 1 条即可(不为徽标拉 100 条)
|
||||||
|
notificationsBadge() {
|
||||||
|
return request<NotificationList>(`/api/ops/notifications/?page_size=1`);
|
||||||
|
},
|
||||||
markAllNotificationsRead() {
|
markAllNotificationsRead() {
|
||||||
return request<{ updated: number; unread_count: number }>("/api/ops/notifications/mark-all-read/", {
|
return request<{ updated: number; unread_count: number }>("/api/ops/notifications/mark-all-read/", {
|
||||||
method: "POST"
|
method: "POST"
|
||||||
|
|||||||
@@ -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" }
|
{ 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;
|
billing: BillingSummary | null;
|
||||||
ledgers: Ledger[];
|
|
||||||
trend: BillingTrend | null;
|
|
||||||
projects: Project[];
|
projects: Project[];
|
||||||
teamMembers: TeamMember[];
|
|
||||||
onRecharge: (amount: number, bonus: number) => void | Promise<unknown>;
|
onRecharge: (amount: number, bonus: number) => void | Promise<unknown>;
|
||||||
}) {
|
}) {
|
||||||
const [tab, setTab] = useState<Tab>("overview");
|
const [tab, setTab] = useState<Tab>("overview");
|
||||||
const [recharge, setRecharge] = useState(500);
|
const [recharge, setRecharge] = useState(500);
|
||||||
const [customAmt, setCustomAmt] = useState("");
|
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 条
|
// 账单流水分页:服务端分页(总数随流水增长,不再写死 100),每页 10 条
|
||||||
const BILLS_PER_PAGE = 10;
|
const BILLS_PER_PAGE = 10;
|
||||||
const [billPage, setBillPage] = useState(1);
|
const [billPage, setBillPage] = useState(1);
|
||||||
const [ledgerRows, setLedgerRows] = useState<Ledger[]>(ledgers);
|
const [ledgerRows, setLedgerRows] = useState<Ledger[]>([]);
|
||||||
const [ledgerCount, setLedgerCount] = useState<number>(ledgers.length);
|
const [ledgerCount, setLedgerCount] = useState<number>(0);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let alive = true;
|
let alive = true;
|
||||||
api.ledgers(billPage, BILLS_PER_PAGE).then((data) => {
|
api.ledgers(billPage, BILLS_PER_PAGE).then((data) => {
|
||||||
@@ -70,7 +79,7 @@ export function AccountPage({ billing, ledgers, trend, projects, teamMembers, on
|
|||||||
setLedgerCount(data.count);
|
setLedgerCount(data.count);
|
||||||
}).catch(() => {});
|
}).catch(() => {});
|
||||||
return () => { alive = false; };
|
return () => { alive = false; };
|
||||||
}, [billPage]);
|
}, [billPage, reloadFlag]);
|
||||||
const billTotalPages = Math.max(1, Math.ceil(ledgerCount / BILLS_PER_PAGE));
|
const billTotalPages = Math.max(1, Math.ceil(ledgerCount / BILLS_PER_PAGE));
|
||||||
const safeBillPage = Math.min(billPage, billTotalPages);
|
const safeBillPage = Math.min(billPage, billTotalPages);
|
||||||
|
|
||||||
@@ -82,6 +91,8 @@ export function AccountPage({ billing, ledgers, trend, projects, teamMembers, on
|
|||||||
if (effectiveAmount <= 0) return;
|
if (effectiveAmount <= 0) return;
|
||||||
await onRecharge(effectiveAmount, effectiveBonus);
|
await onRecharge(effectiveAmount, effectiveBonus);
|
||||||
setCustomAmt("");
|
setCustomAmt("");
|
||||||
|
setBillPage(1);
|
||||||
|
setReloadFlag((n) => n + 1); // 充值后刷新流水/趋势(余额由全局 action→loadData 刷新)
|
||||||
}
|
}
|
||||||
|
|
||||||
const balance = Number(billing?.account.balance || 0);
|
const balance = Number(billing?.account.balance || 0);
|
||||||
|
|||||||
@@ -81,12 +81,13 @@ async function downloadImage(url: string, filename: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AssetFactoryPage({ navigate, aiTasks }: { navigate: (page: Page) => void; aiTasks: AITask[] }) {
|
export function AssetFactoryPage({ navigate }: { navigate: (page: Page) => void }) {
|
||||||
// 任务 → 生成结果图:按 asset.origin_task 关联取缩略图。服务端懒加载最近的 AI 生成图(不再吃全局 assets 全量),
|
// 任务历史 + 任务→结果图:都在本页懒加载(不再吃全局 bootstrap 的 aiTasks/assets 全量)。
|
||||||
// 覆盖近 200 张生成图的任务卡缩略图;更早的任务卡留占位。
|
const [aiTasks, setAiTasks] = useState<AITask[]>([]);
|
||||||
const [assets, setAssets] = useState<Asset[]>([]);
|
const [assets, setAssets] = useState<Asset[]>([]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let alive = true;
|
let alive = true;
|
||||||
|
api.aiTasks().then((res) => { if (alive) setAiTasks(res.results || []); }).catch(() => {});
|
||||||
api.assetsPage({ asset_type: "image", source: "ai_generated", pageSize: 200 })
|
api.assetsPage({ asset_type: "image", source: "ai_generated", pageSize: 200 })
|
||||||
.then((res) => { if (alive) setAssets(res.results); })
|
.then((res) => { if (alive) setAssets(res.results); })
|
||||||
.catch(() => { if (alive) setAssets([]); });
|
.catch(() => { if (alive) setAssets([]); });
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { CircleDollarSign, KeyRound, UserPlus } from "lucide-react";
|
import { CircleDollarSign, KeyRound, UserPlus } from "lucide-react";
|
||||||
|
import { api } from "../api";
|
||||||
import type { BillingSummary, Notification, Team, TeamMember, User } from "../types";
|
import type { BillingSummary, Notification, Team, TeamMember, User } from "../types";
|
||||||
import type { Page } from "./route-config";
|
import type { Page } from "./route-config";
|
||||||
import { money } from "./stage-config";
|
import { money } from "./stage-config";
|
||||||
@@ -27,13 +28,10 @@ const PERM_ROWS: Array<{ cap: string; cells: [string, string, string]; last?: bo
|
|||||||
{ cap: "创建项目 / 用 AI 流程", cells: ["✓", "✓", "✓"], last: true }
|
{ cap: "创建项目 / 用 AI 流程", cells: ["✓", "✓", "✓"], last: true }
|
||||||
];
|
];
|
||||||
|
|
||||||
export function TeamPage({ team, user, members, billing, notifications = [], notificationTotal, navigate, onCreateMember, onUpdateMember, onRemoveMember, onResetPassword, onRecharge }: {
|
export function TeamPage({ team, user, billing, navigate, onCreateMember: onCreateMemberRaw, onUpdateMember: onUpdateMemberRaw, onRemoveMember: onRemoveMemberRaw, onResetPassword, onRecharge: onRechargeRaw }: {
|
||||||
team: Team;
|
team: Team;
|
||||||
user: User;
|
user: User;
|
||||||
members: TeamMember[];
|
|
||||||
billing: BillingSummary | null;
|
billing: BillingSummary | null;
|
||||||
notifications?: Notification[];
|
|
||||||
notificationTotal?: number; // 后端真实总数(只加载了近期 100 条,「共 N」用这个而非数组长度)
|
|
||||||
navigate: (page: Page) => void;
|
navigate: (page: Page) => void;
|
||||||
onCreateMember: (payload: { username: string; password: string; name?: string; role?: string; monthly_credit_limit?: number }) => void | Promise<unknown>;
|
onCreateMember: (payload: { username: string; password: string; name?: string; role?: string; monthly_credit_limit?: number }) => void | Promise<unknown>;
|
||||||
onUpdateMember: (id: string, payload: { role?: string; monthly_credit_limit?: number }) => void | Promise<unknown>;
|
onUpdateMember: (id: string, payload: { role?: string; monthly_credit_limit?: number }) => void | Promise<unknown>;
|
||||||
@@ -44,6 +42,24 @@ export function TeamPage({ team, user, members, billing, notifications = [], not
|
|||||||
const [modal, setModal] = useState<"" | "invite" | "limit" | "recharge">("");
|
const [modal, setModal] = useState<"" | "invite" | "limit" | "recharge">("");
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
|
|
||||||
|
// 团队成员 + 团队动态本页懒加载(不再走全局 bootstrap);成员/充值操作后 bump 刷新
|
||||||
|
const [reloadFlag, setReloadFlag] = useState(0);
|
||||||
|
const [members, setMembers] = useState<TeamMember[]>([]);
|
||||||
|
const [notifications, setNotifications] = useState<Notification[]>([]);
|
||||||
|
const [notificationTotal, setNotificationTotal] = useState(0);
|
||||||
|
useEffect(() => {
|
||||||
|
let alive = true;
|
||||||
|
api.teamMembers().then((m) => { if (alive) setMembers(m); }).catch(() => {});
|
||||||
|
api.allNotifications().then((n) => { if (alive) { setNotifications(n.results); setNotificationTotal(n.count); } }).catch(() => {});
|
||||||
|
return () => { alive = false; };
|
||||||
|
}, [reloadFlag]);
|
||||||
|
const reloadTeam = () => setReloadFlag((n) => n + 1);
|
||||||
|
// 包一层:操作完成后刷新本页成员列表(余额由全局 action→loadData 刷新);透传返回值(调用处据此判成功)
|
||||||
|
const onCreateMember = async (p: Parameters<typeof onCreateMemberRaw>[0]) => { const r = await onCreateMemberRaw(p); reloadTeam(); return r; };
|
||||||
|
const onUpdateMember = async (id: string, p: Parameters<typeof onUpdateMemberRaw>[1]) => { const r = await onUpdateMemberRaw(id, p); reloadTeam(); return r; };
|
||||||
|
const onRemoveMember = async (id: string) => { const r = await onRemoveMemberRaw(id); reloadTeam(); return r; };
|
||||||
|
const onRecharge = async (amount: number, bonus: number) => { const r = await onRechargeRaw(amount, bonus); reloadTeam(); return r; };
|
||||||
|
|
||||||
// 创建账户表单
|
// 创建账户表单
|
||||||
const [cuUser, setCuUser] = useState("");
|
const [cuUser, setCuUser] = useState("");
|
||||||
const [cuPass, setCuPass] = useState("");
|
const [cuPass, setCuPass] = useState("");
|
||||||
|
|||||||
@@ -50,16 +50,17 @@ const baselinePath = path.resolve(here, "perf-baseline.json");
|
|||||||
// 注:App.tsx 启动会并行拉 ~10 个全局接口(products/projects/assets/billing/...)。
|
// 注:App.tsx 启动会并行拉 ~10 个全局接口(products/projects/assets/billing/...)。
|
||||||
// 这些是「全局首屏」开销,记在 dashboard 头上。其余页若在已加载全局态后还重复拉同样数据 = 架构问题。
|
// 这些是「全局首屏」开销,记在 dashboard 头上。其余页若在已加载全局态后还重复拉同样数据 = 架构问题。
|
||||||
// 阈值是「当前现状 + 少量余量」起步;优化推进后人工调低,逼着请求数下降。
|
// 阈值是「当前现状 + 少量余量」起步;优化推进后人工调低,逼着请求数下降。
|
||||||
|
// 资产+非资产全局态改按页懒加载后的新基线(shell 全局 ~6 个 + 各页自取少量)+ 小余量,作回归护栏。
|
||||||
const REQUEST_BUDGET = {
|
const REQUEST_BUDGET = {
|
||||||
dashboard: 14,
|
dashboard: 7,
|
||||||
products: 6,
|
products: 6,
|
||||||
projects: 6,
|
projects: 6,
|
||||||
library: 8,
|
library: 9,
|
||||||
account: 8,
|
account: 9,
|
||||||
team: 4,
|
team: 7,
|
||||||
messages: 4,
|
messages: 6,
|
||||||
productDetail: 8,
|
productDetail: 7,
|
||||||
pipeline: 10,
|
pipeline: 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
async function login() {
|
async function login() {
|
||||||
|
|||||||
Reference in New Issue
Block a user