feat(admin): upgrade admin console UI widgets, add plan & status management, and redesign system status dashboard

This commit is contained in:
Blizzard
2026-07-18 22:18:12 +08:00
parent 197531ea33
commit 0d2929931f
16 changed files with 1979 additions and 503 deletions
+35 -2
View File
@@ -739,8 +739,11 @@ export async function listTenants(): Promise<TenantRow[]> {
return ((await res.json()) as { tenants?: TenantRow[] }).tenants ?? [];
}
export async function createTenant(name: string, slug: string, ownerEmail?: string): Promise<void> {
const res = guard(await fetch(`${ADMIN}/tenants`, { method: "POST", headers: authHeaders(true), body: JSON.stringify({ name, slug, owner_email: ownerEmail ?? "" }) }));
export async function createTenant(name: string, slug: string, ownerEmail?: string, plan?: string): Promise<void> {
const res = guard(await fetch(`${ADMIN}/tenants`, {
method: "POST", headers: authHeaders(true),
body: JSON.stringify({ name, slug, owner_email: ownerEmail ?? "", plan: plan ?? "free" }),
}));
const d = (await res.json().catch(() => ({}))) as { error?: string; warn?: string };
if (!res.ok) throw new Error(d.error ?? `create tenant failed: ${res.status}`);
if (d.warn) throw new Error(d.warn); // 租户已建但指定 owner 失败 → 当提示
@@ -783,3 +786,33 @@ export async function setSharedBilling(tenantId: string, on: boolean): Promise<v
throw new Error(d.error ?? `set shared billing failed: ${res.status}`);
}
}
// —— KB 存储迁移(管理员一次性运维操作:owner/kb 作用域 → space_id/kb 作用域)——
export interface MigrateKbResult {
total: number; // 扫描文档总数
enqueued: number; // 成功入队重灌的文档数
skipped: number; // 已是新作用域跳过数
}
export async function migrateKbStorage(): Promise<MigrateKbResult> {
const res = guard(await fetch(`${ADMIN}/migrate-kb-storage`, { method: "POST", headers: authHeaders(true) }));
const d = (await res.json().catch(() => ({}))) as Partial<MigrateKbResult> & { error?: string };
if (!res.ok) throw new Error(d.error ?? `migrate kb failed: ${res.status}`);
return { total: d.total ?? 0, enqueued: d.enqueued ?? 0, skipped: d.skipped ?? 0 };
}
export async function setTenantPlan(tenantId: string, plan: string): Promise<void> {
const res = guard(await fetch(`${ADMIN}/tenants/${tenantId}/plan`, { method: "PUT", headers: authHeaders(true), body: JSON.stringify({ plan }) }));
if (!res.ok) {
const d = (await res.json().catch(() => ({}))) as { error?: string };
throw new Error(d.error ?? `set tenant plan failed: ${res.status}`);
}
}
export async function setTenantStatus(tenantId: string, status: string): Promise<void> {
const res = guard(await fetch(`${ADMIN}/tenants/${tenantId}/status`, { method: "PUT", headers: authHeaders(true), body: JSON.stringify({ status }) }));
if (!res.ok) {
const d = (await res.json().catch(() => ({}))) as { error?: string };
throw new Error(d.error ?? `set tenant status failed: ${res.status}`);
}
}