feat(frontend/admin): M10 后台管理面板(/admin hash 路由 + 15 大模块 + RBAC(owner/admin/viewer) + 审计 + Miuix);Docs/api-client.md v0.3 契约补全;tsc+vite build 通过

This commit is contained in:
Aska committed 2026-09-06 07:55:04 +08:00
1 parent 4c48e94659
commit f43eb17030
26 files changed
+2253 -4

No files matched your search

+71
View File
@@ -0,0 +1,71 @@
/**
* Hash-based admin routing. The M9 SPA uses a state store (useModeStore) instead
* of react-router, so the admin subsystem stays consistent: it is entered via
* `#/admin` and each module is a hash segment (`#/admin/personas`, ...). Keeps
* the build dependency-free and works behind the single-binary gateway serving
* `base: "./"`.
*/
export type AdminSectionId =
| "dashboard"
| "personas"
| "sessions"
| "memories"
| "plugins"
| "channels"
| "iot"
| "rag"
| "llm"
| "automations"
| "agents"
| "backthink"
| "observability"
| "system"
| "users";
export interface AdminRoute {
admin: boolean;
section: AdminSectionId;
}
const VALID_SECTIONS: ReadonlySet<string> = new Set([
"dashboard",
"personas",
"sessions",
"memories",
"plugins",
"channels",
"iot",
"rag",
"llm",
"automations",
"agents",
"backthink",
"observability",
"system",
"users",
]);
/** Parse a `window.location.hash` into an admin route descriptor. */
export function parseAdminHash(hash: string): AdminRoute {
const raw = hash.replace(/^#/, "").replace(/^\/+/, "").split("/");
if (raw[0] !== "admin") return { admin: false, section: "dashboard" };
const section = raw[1];
return {
admin: true,
section: VALID_SECTIONS.has(section) ? (section as AdminSectionId) : "dashboard",
};
}
/** The hash that selects the admin root (dashboard). */
export const ADMIN_ROOT_HASH = "#/admin";
/** Build a hash for a given admin section. */
export function adminSectionHash(section: AdminSectionId): string {
return section === "dashboard" ? ADMIN_ROOT_HASH : `#/admin/${section}`;
}
/** Navigate to an admin section by setting the location hash. */
export function navigateAdmin(section: AdminSectionId): void {
window.location.hash = adminSectionHash(section);
}