代码修改

This commit is contained in:
fengxiangdebaozi committed 2026-06-05 18:58:28 +08:00
1 parent 9bbd04d6cf
commit b0fdeab995
15 files changed
+467 -90

No files matched your search

@@ -4,6 +4,11 @@ import remarkGfm from "remark-gfm";
import { Download, FileText, Loader2, X } from "lucide-react";
import { apiFetch } from "@/core/api/fetch-client";
import {
downloadMermaidSvgFile,
isMermaidFile,
renderMermaidToSvg,
} from "@/core/utils/mermaid";
import { buildArtifactDownloadUrl } from "@/roundtable-planning/api/multi-agent";
interface ArtifactPreviewModalProps {
@@ -61,6 +66,11 @@ function isMarkdown(mimeType: string | null, name: string): boolean {
return /\.(md|markdown)$/i.test(name);
}
function isMermaid(mimeType: string | null, name: string): boolean {
if (mimeType === "text/vnd.mermaid") return true;
return isMermaidFile(name);
}
export const ArtifactPreviewModal: React.FC<ArtifactPreviewModalProps> = ({
threadId,
path,
@@ -71,6 +81,7 @@ export const ArtifactPreviewModal: React.FC<ArtifactPreviewModalProps> = ({
const [content, setContent] = useState<string | null>(null);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
const [mermaidSvg, setMermaidSvg] = useState<string | null>(null);
// Esc closes the modal. Attached once per mount.
useEffect(() => {
@@ -116,11 +127,38 @@ export const ArtifactPreviewModal: React.FC<ArtifactPreviewModalProps> = ({
const handleDownload = useCallback(() => {
if (typeof window === "undefined") return;
if (isMermaid(mimeType, name) && content) {
void downloadMermaidSvgFile(content, name).catch((err) => {
setError((err as Error).message);
});
return;
}
const url = buildArtifactDownloadUrl(threadId, path, { download: true });
window.open(url, "_blank", "noopener,noreferrer");
}, [threadId, path]);
}, [content, mimeType, name, path, threadId]);
const renderAsMarkdown = isMarkdown(mimeType, name);
const renderAsMermaid = isMermaid(mimeType, name);
useEffect(() => {
if (!renderAsMermaid || !content) {
setMermaidSvg(null);
return;
}
let cancelled = false;
void renderMermaidToSvg(content)
.then((svg) => {
if (!cancelled) setMermaidSvg(svg);
})
.catch((err) => {
if (!cancelled) setError((err as Error).message);
});
return () => {
cancelled = true;
};
}, [content, renderAsMermaid]);
return (
<div
@@ -170,7 +208,19 @@ export const ArtifactPreviewModal: React.FC<ArtifactPreviewModalProps> = ({
<div className="text-rose-600 text-xs py-6 text-center">
加载失败:{error}
</div>
) : content === null ? null : renderAsMarkdown ? (
) : content === null ? null : renderAsMermaid ? (
mermaidSvg ? (
<div
className="rounded-2xl border border-slate-200 bg-white p-4 shadow-sm"
dangerouslySetInnerHTML={{ __html: mermaidSvg }}
/>
) : (
<div className="flex items-center justify-center gap-2 py-12 text-slate-400">
<Loader2 className="w-4 h-4 animate-spin text-primary" />
<span className="text-xs">正在生成图表预览</span>
</div>
)
) : renderAsMarkdown ? (
<ReactMarkdown remarkPlugins={[remarkGfm]} components={MARKDOWN_COMPONENTS}>
{content}
</ReactMarkdown>