feat(core): notification inbox infinite scroll + command palette fix (+ pending WIP)
消息中心:全量渲染 → 真·后端分页滚动加载 - backend(ops/views): NotificationPagination(10/页,page_size 可覆盖)+ 响应回 type_counts(按收件人绝对计数,不受分页/搜索影响) - frontend(messages): 自管分页,滚到底加载下一批;tab/搜索走服务端并重置到第1页; 代号作废在途旧请求防切换卡空白;乐观标已读;「已加载 X / Y」分母用当前筛选总数 - api/App/types: listNotifications 支持 page/page_size/search;allNotifications 携带 type_counts 命令面板(侧边栏搜索):修复点开后 UI 错位 - app-shell: 遮罩 className 漏了基类 shell-command-bg(只有 .show)致无定位塌到左下; 补回基类 + header 类名对齐 .shell-command-h - messages-page.css: 工作台收进视口高度,收件箱在面板内滚动 本次提交一并带入此前若干未提交 WIP(account/ai-tools/library/pipeline/products/settings + accounts/ai/assets/billing/projects 后端),按用户要求整体推 dev。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -231,14 +231,26 @@ export const api = {
|
||||
assets() {
|
||||
return request<Paginated<Asset>>("/api/assets/");
|
||||
},
|
||||
// 跟随 DRF 分页 next 取全部资产 —— 商品图/AI 素材/资产库都靠 asset.id 在这份列表里查 preview_url,
|
||||
// 只取第 1 页(20 条)会让第 20 条之后的资产解析不到图、渲染成空占位。
|
||||
async allAssets(): Promise<Asset[]> {
|
||||
const out: Asset[] = [];
|
||||
let path = "/api/assets/";
|
||||
for (let guard = 0; guard < 50 && path; guard += 1) {
|
||||
const page: Paginated<Asset> = await request<Paginated<Asset>>(path);
|
||||
out.push(...page.results);
|
||||
path = page.next ? new URL(page.next).pathname + new URL(page.next).search : "";
|
||||
}
|
||||
return out;
|
||||
},
|
||||
uploadAsset(formData: FormData) {
|
||||
return request<Asset>("/api/assets/upload/", { method: "POST", body: formData });
|
||||
},
|
||||
billingSummary() {
|
||||
return request<BillingSummary>("/api/billing/summary/");
|
||||
},
|
||||
ledgers() {
|
||||
return request<Ledger[]>("/api/billing/ledgers/");
|
||||
ledgers(page = 1, pageSize = 10) {
|
||||
return request<{ count: number; page: number; page_size: number; results: Ledger[] }>(`/api/billing/ledgers/?page=${page}&page_size=${pageSize}`);
|
||||
},
|
||||
billingTrend(range?: "day" | "week" | "month") {
|
||||
return request<BillingTrend>(`/api/billing/trend/${range ? `?range=${range}` : ""}`);
|
||||
@@ -255,13 +267,32 @@ export const api = {
|
||||
recharge(payload: { amount: number | string; bonus?: number | string; channel?: string }) {
|
||||
return request<RechargeResult>("/api/billing/recharge/", { method: "POST", body: JSON.stringify(payload) });
|
||||
},
|
||||
listNotifications(params?: { type?: string; unread?: boolean }) {
|
||||
// 收件箱按页拉取 —— 滚动加载逐页向后端要(tab/搜索 走服务端,计数随响应回来)
|
||||
listNotifications(params?: { type?: string; unread?: boolean; search?: string; page?: number; pageSize?: number }) {
|
||||
const query = new URLSearchParams();
|
||||
if (params?.type && params.type !== "all") query.set("type", params.type);
|
||||
if (params?.unread) query.set("unread", "1");
|
||||
if (params?.search) query.set("search", params.search);
|
||||
if (params?.page) query.set("page", String(params.page));
|
||||
if (params?.pageSize) query.set("page_size", String(params.pageSize));
|
||||
const qs = query.toString();
|
||||
return request<NotificationList>(`/api/ops/notifications/${qs ? `?${qs}` : ""}`);
|
||||
},
|
||||
// 跟着 next 把所有消息取全(给侧边栏徽标 + 团队动态用,不参与收件箱滚动渲染),与 allAssets 同套路
|
||||
async allNotifications(): Promise<NotificationList> {
|
||||
const out: Notification[] = [];
|
||||
let path = "/api/ops/notifications/?page_size=100";
|
||||
let unreadCount = 0;
|
||||
let typeCounts: NotificationList["type_counts"];
|
||||
for (let guard = 0; guard < 100 && path; guard += 1) {
|
||||
const page = await request<NotificationList>(path);
|
||||
out.push(...page.results);
|
||||
unreadCount = page.unread_count;
|
||||
typeCounts = page.type_counts ?? typeCounts;
|
||||
path = page.next ? new URL(page.next).pathname + new URL(page.next).search : "";
|
||||
}
|
||||
return { count: out.length, next: null, previous: null, results: out, unread_count: unreadCount, type_counts: typeCounts };
|
||||
},
|
||||
markAllNotificationsRead() {
|
||||
return request<{ updated: number; unread_count: number }>("/api/ops/notifications/mark-all-read/", {
|
||||
method: "POST"
|
||||
|
||||
Reference in New Issue
Block a user