feat(desktop): 工业化升级 D —— 内容可信(Markdown 渲染 + 健康五灯全真)

- components/Markdown.tsx:零依赖、行级 Markdown 渲染(# 标题 / **粗** *斜* `码` /
  - 与 1. 列表 / > 引用 / --- 分隔 / 段落),流式安全(每 token 重渲染容忍残缺)。
  报告正文与运行输出从裸 <pre> 换成真排版,瞬间像份报告。
- 健康聚合:mcp-go 加 rag.Status() + health 工具(milvus/neo4j/embedding 就绪);
  gateway GET /api/v1/health 聚合 gateway/nats/db/redis(本地) + milvus/neo4j(经 mcp-go);
  health.ts 轮询 /health,TopBar 五盏灯(Gateway/DB/NATS/Milvus/Neo4j)从"灰=未知"变真实绿/红。

验证:浏览器(Preview)跑报告——正文以标题/有序列表/引用/分隔线/二级标题排版呈现;
五盏灯全绿(/health 返回 db/gateway/milvus/nats/neo4j/redis 全 true)。tsc + vite build + 后端 build 通过。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Blizzard
2026-06-12 17:34:54 +08:00
parent 4d9d1ac615
commit d5ae2f71d4
9 changed files with 186 additions and 17 deletions
+24 -8
View File
@@ -3,22 +3,38 @@ import { GATEWAY } from "./api";
export interface Health {
gateway: boolean;
persisted: boolean; // Postgres 是否在线(billing.persisted
persisted: boolean; // Postgres(兼容旧字段名
db: boolean;
redis: boolean;
nats: boolean;
milvus: boolean;
neo4j: boolean;
}
// useHealth 轮询 Gateway 健康(billing 端点同时回报持久化是否就绪)。
// NATS/Milvus/Neo4j 暂未由网关透出,UI 以"未知"呈现(规划:加 /health 聚合)。
const DOWN: Health = { gateway: false, persisted: false, db: false, redis: false, nats: false, milvus: false, neo4j: false };
// useHealth 轮询 Gateway /health 聚合端点,回报全部依赖子系统的实时状态。
// gateway/nats/db/redis 由网关本地判定,milvus/neo4j 经 mcp-go health 工具取。
export function useHealth(intervalMs = 4000): Health {
const [h, setH] = useState<Health>({ gateway: false, persisted: false });
const [h, setH] = useState<Health>(DOWN);
useEffect(() => {
let alive = true;
const ping = async () => {
try {
const res = await fetch(`${GATEWAY}/api/v1/billing`);
const data = (await res.json()) as { persisted?: boolean };
if (alive) setH({ gateway: res.ok, persisted: Boolean(data.persisted) });
const res = await fetch(`${GATEWAY}/api/v1/health`);
const d = (await res.json()) as Partial<Health>;
if (alive)
setH({
gateway: res.ok && Boolean(d.gateway),
db: Boolean(d.db),
persisted: Boolean(d.db),
redis: Boolean(d.redis),
nats: Boolean(d.nats),
milvus: Boolean(d.milvus),
neo4j: Boolean(d.neo4j),
});
} catch {
if (alive) setH({ gateway: false, persisted: false });
if (alive) setH(DOWN);
}
};
ping();