feat(memory): P1 长期记忆升级 —— 异步攒批 Consolidate + 软删 + importance/last_seen #1

Merged
Blizzard merged 181 commits from feat/wails3 into main 2026-07-17 01:12:32 +00:00
2 changed files with 25 additions and 1 deletions
Showing only changes of commit b388915fff - Show all commits
+9
View File
@@ -447,6 +447,7 @@ export interface TenantRow {
plan: string; plan: string;
status: string; status: string;
credit_balance_micro: number; credit_balance_micro: number;
shared_billing: boolean;
members: number; members: number;
} }
export interface Member { export interface Member {
@@ -500,3 +501,11 @@ export async function removeMember(tenantId: string, uid: string): Promise<void>
throw new Error(d.error ?? `remove member failed: ${res.status}`); throw new Error(d.error ?? `remove member failed: ${res.status}`);
} }
} }
export async function setSharedBilling(tenantId: string, on: boolean): Promise<void> {
const res = guard(await fetch(`${ADMIN}/tenants/${tenantId}/shared-billing`, { method: "PUT", headers: authHeaders(true), body: JSON.stringify({ shared_billing: on }) }));
if (!res.ok) {
const d = (await res.json().catch(() => ({}))) as { error?: string };
throw new Error(d.error ?? `set shared billing failed: ${res.status}`);
}
}
+16 -1
View File
@@ -1,5 +1,5 @@
import { useEffect, useMemo, useState } from "react"; import { useEffect, useMemo, useState } from "react";
import { listTenants, createTenant, listMembers, addMember, setMemberRole, removeMember, type TenantRow, type Member } from "../api"; import { listTenants, createTenant, listMembers, addMember, setMemberRole, removeMember, setSharedBilling, type TenantRow, type Member } from "../api";
// 管理端「租户 & 用户」= 多成员租户管理(平台运维口径):租户目录 + 每租户成员增改删。 // 管理端「租户 & 用户」= 多成员租户管理(平台运维口径):租户目录 + 每租户成员增改删。
// 全真数据:GET/POST /admin/tenants、/admin/tenants/:id/members。 // 全真数据:GET/POST /admin/tenants、/admin/tenants/:id/members。
@@ -110,6 +110,14 @@ export function TenantsPage() {
setMErr((e as Error).message); setMErr((e as Error).message);
} }
}; };
const onToggleShared = async (on: boolean) => {
try {
await setSharedBilling(selId, on);
await loadTenants();
} catch (e) {
setMErr((e as Error).message);
}
};
if (loading) return <div className="text-sm text-gray-400"></div>; if (loading) return <div className="text-sm text-gray-400"></div>;
@@ -172,6 +180,13 @@ export function TenantsPage() {
<span className="tabular-nums text-xs text-gray-500">{credits(selected.credit_balance_micro)} </span> <span className="tabular-nums text-xs text-gray-500">{credits(selected.credit_balance_micro)} </span>
</div> </div>
{/* 共享计费开关 */}
<label className="mb-3 flex cursor-pointer items-center gap-2 rounded-lg border border-gray-100 bg-gray-50/50 px-3 py-2 text-xs text-gray-600">
<input type="checkbox" checked={selected.shared_billing} onChange={(e) => void onToggleShared(e.target.checked)} className="h-4 w-4 accent-violet-600" />
<span className="font-medium text-gray-700"></span>
<span className="text-gray-400">owner </span>
</label>
{/* 加成员 */} {/* 加成员 */}
<div className="mb-4 flex flex-wrap items-center gap-2 rounded-lg border border-violet-100 bg-violet-50/30 p-3"> <div className="mb-4 flex flex-wrap items-center gap-2 rounded-lg border border-violet-100 bg-violet-50/30 p-3">
<input className="flex-1 rounded border bg-white px-2 py-1.5 text-xs focus:border-violet-500 focus:outline-none" placeholder="按邮箱加入已注册用户" value={mEmail} onChange={(e) => setMEmail(e.target.value)} /> <input className="flex-1 rounded border bg-white px-2 py-1.5 text-xs focus:border-violet-500 focus:outline-none" placeholder="按邮箱加入已注册用户" value={mEmail} onChange={(e) => setMEmail(e.target.value)} />