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:
1 parent
4c48e94659
commit
f43eb17030
26 files changed
+2253
-4
No files matched your search
@@ -0,0 +1,99 @@
|
||||
import { useState } from "react";
|
||||
import { useAuditStore } from "../audit";
|
||||
import { Notice, PageHeader } from "../components";
|
||||
import { Button, Surface, Tag } from "../../components/primitives";
|
||||
|
||||
interface DocRow {
|
||||
id: string;
|
||||
name: string;
|
||||
chunks: number;
|
||||
embedded: boolean;
|
||||
}
|
||||
|
||||
const docs: DocRow[] = [
|
||||
{ id: "1", name: "owner_identity.md", chunks: 1, embedded: false },
|
||||
{ id: "2", name: "开发时间线.md", chunks: 6, embedded: false },
|
||||
{ id: "3", name: "design/10-后台管理面板.md", chunks: 2, embedded: false },
|
||||
];
|
||||
|
||||
export function RagModule(): React.ReactNode {
|
||||
const log = useAuditStore((s) => s.log);
|
||||
const [query, setQuery] = useState("");
|
||||
const [hits, setHits] = useState<string[]>([]);
|
||||
|
||||
return (
|
||||
<div className="space-y-5">
|
||||
<PageHeader
|
||||
title="知识库 RAG"
|
||||
subtitle="文档列表(分块/嵌入状态) + 索引 + 检索测试"
|
||||
actions={
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={() => {
|
||||
log("rag.upload", "ok");
|
||||
alert("上传文档(占位):后端 M10+ 提供分块/嵌入。");
|
||||
}}
|
||||
>
|
||||
上传文档
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
|
||||
<Surface className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<h3 className="text-sm font-semibold">文档列表</h3>
|
||||
<span className="text-xs text-[var(--mu-text-lo)]">{docs.length} 篇</span>
|
||||
</div>
|
||||
{docs.map((d) => (
|
||||
<div key={d.id} className="flex items-center gap-2 rounded-[var(--mu-radius)] bg-[var(--mu-surface-2)] px-3 py-2 text-sm">
|
||||
<span className="font-medium">{d.name}</span>
|
||||
<span className="text-xs text-[var(--mu-text-lo)]">{d.chunks} 分块</span>
|
||||
<span className="ml-auto">
|
||||
<Tag tone={d.embedded ? "ok" : "warn"}>{d.embedded ? "已嵌入" : "待嵌入"}</Tag>
|
||||
</span>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => {
|
||||
log("rag.delete", "ok");
|
||||
alert(`删除 ${d.name}(占位)`);
|
||||
}}
|
||||
>
|
||||
删除
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
</Surface>
|
||||
|
||||
<Surface className="space-y-3">
|
||||
<h3 className="text-sm font-semibold">检索测试</h3>
|
||||
<div className="flex gap-2">
|
||||
<input
|
||||
value={query}
|
||||
onChange={(e) => setQuery(e.target.value)}
|
||||
placeholder="输入查询…"
|
||||
className="min-w-0 flex-1 rounded-[var(--mu-radius)] bg-[var(--mu-surface-2)] px-3 py-2 text-sm outline-none focus:ring-1 focus:ring-[var(--mu-accent)]"
|
||||
/>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={() => {
|
||||
log("rag.search", "ok");
|
||||
setHits(query ? [`片段 1(命中 "${query}")`, `片段 2(命中 "${query}")`] : []);
|
||||
}}
|
||||
>
|
||||
检索
|
||||
</Button>
|
||||
</div>
|
||||
{hits.length > 0 ? (
|
||||
<div className="space-y-1.5">
|
||||
{hits.map((h) => (
|
||||
<div key={h} className="rounded-[var(--mu-radius-sm)] bg-[var(--mu-surface-2)] px-3 py-2 text-xs text-[var(--mu-text-mid)]">{h}</div>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
</Surface>
|
||||
|
||||
<Notice>分块/嵌入状态、向量索引与语义检索为后端 M10+ 提供;配置了 pgvector 增强后必须真实走语义路径(非空壳)。</Notice>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user