代码修改
This commit is contained in:
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>
|
||||
|
||||
Reference in new issue
Block a user