diff --git a/frontend-web/src/components/workspace/admin/admin-memory-page.tsx b/frontend-web/src/components/workspace/admin/admin-memory-page.tsx index eae8f24b..bd48cde9 100644 --- a/frontend-web/src/components/workspace/admin/admin-memory-page.tsx +++ b/frontend-web/src/components/workspace/admin/admin-memory-page.tsx @@ -19,8 +19,12 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Textarea } from "@/components/ui/textarea"; import { useAdminAddMemoryEntry, + useAdminAddV1Fact, useAdminDeleteMemoryEntry, + useAdminDeleteV1Fact, useAdminReplaceMemoryEntry, + useAdminUpdateV1Fact, + useAdminUpdateV1Section, useUserMemory, } from "@/core/admin/hooks"; import { useAllUsers } from "@/core/auth/hooks"; @@ -31,6 +35,288 @@ function getEntries(data: Record): string[] { return raw.filter((e): e is string => typeof e === "string" && e.trim().length > 0); } +// ── V1 只读视图 ──────────────────────────────────────────────────────────── + +const CTX_LABELS: Record = { + workContext: "工作背景", + personalContext: "个人信息", + topOfMind: "当前重点", +}; +const HISTORY_LABELS: Record = { + recentMonths: "近期", + earlierContext: "早期背景", + longTermBackground: "长期背景", +}; +const CATEGORY_COLORS: Record = { + preference: "bg-blue-100 text-blue-700", + knowledge: "bg-green-100 text-green-700", + context: "bg-yellow-100 text-yellow-700", + behavior: "bg-purple-100 text-purple-700", + goal: "bg-orange-100 text-orange-700", + correction: "bg-red-100 text-red-700", +}; + +const V1_CATEGORIES = ["preference", "knowledge", "context", "behavior", "goal", "correction"]; + +function extractSummary(val: unknown): string { + if (typeof val === "string") return val; + if (val && typeof val === "object" && "summary" in val) + return String((val as Record).summary ?? ""); + return ""; +} + +// 单个摘要字段的行内编辑 +function V1SectionField({ + label, + value, + onSave, +}: { + label: string; + value: string; + onSave: (v: string) => Promise; +}) { + const [editing, setEditing] = useState(false); + const [draft, setDraft] = useState(value); + const [saving, setSaving] = useState(false); + + async function handleSave() { + if (draft.trim() === value.trim()) { setEditing(false); return; } + setSaving(true); + try { await onSave(draft.trim()); setEditing(false); } + catch (err) { toast.error(err instanceof Error ? err.message : "保存失败"); } + finally { setSaving(false); } + } + + return ( +
+
+ {label} + {!editing && ( + + )} +
+ {editing ? ( +
+