From bcea616c70fb0581fdffcbca2e27c7f49f8e14a0 Mon Sep 17 00:00:00 2001 From: aries_ckt <916701291@qq.com> Date: Fri, 13 Feb 2026 16:33:49 +0800 Subject: [PATCH] feat:dbgpt skill --- .../chat/content/ManusLeftPanel.tsx | 8 +- web/pages/index.tsx | 105 +++++++++++++----- 2 files changed, 81 insertions(+), 32 deletions(-) diff --git a/web/new-components/chat/content/ManusLeftPanel.tsx b/web/new-components/chat/content/ManusLeftPanel.tsx index cdd17b3cc..ca3b9eb7b 100644 --- a/web/new-components/chat/content/ManusLeftPanel.tsx +++ b/web/new-components/chat/content/ManusLeftPanel.tsx @@ -77,6 +77,7 @@ export interface ManusLeftPanelProps { stepThoughts?: Record; artifacts?: ArtifactItem[]; onArtifactClick?: (artifact: ArtifactItem) => void; + onArtifactDownload?: (artifact: ArtifactItem) => void; onViewAllFiles?: () => void; isCollapsed?: boolean; onExpand?: () => void; @@ -250,7 +251,8 @@ const getArtifactIconBg = (type: string): string => { const ArtifactCard: React.FC<{ artifact: ArtifactItem; onClick?: () => void; -}> = memo(({ artifact, onClick }) => { + onDownload?: () => void; +}> = memo(({ artifact, onClick, onDownload }) => { return (
{ e.stopPropagation(); - onClick?.(); + onDownload?.(); }} /> @@ -543,6 +545,7 @@ const ManusLeftPanel: React.FC = ({ stepThoughts, artifacts, onArtifactClick, + onArtifactDownload, onViewAllFiles, isCollapsed, onExpand, @@ -681,6 +684,7 @@ const ManusLeftPanel: React.FC = ({ key={artifact.id} artifact={artifact} onClick={() => onArtifactClick?.(artifact)} + onDownload={() => onArtifactDownload?.(artifact)} /> ))} diff --git a/web/pages/index.tsx b/web/pages/index.tsx index 3325f0e66..6cd80e933 100644 --- a/web/pages/index.tsx +++ b/web/pages/index.tsx @@ -950,12 +950,55 @@ const Playground: NextPage = () => { return refs; }; - const _downloadArtifact = (artifact: Artifact) => { - let content: string; - let filename: string; - let mimeType: string; + const downloadArtifact = async (artifact: Artifact) => { + const triggerBlobDownload = (blob: Blob, filename: string) => { + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = filename; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + }; switch (artifact.type) { + case 'image': { + const imgUrl = + typeof artifact.content === 'string' + ? artifact.content + : artifact.content?.url || artifact.content?.src || String(artifact.content); + const resolvedUrl = imgUrl.startsWith('/images/') ? `${process.env.API_BASE_URL || ''}${imgUrl}` : imgUrl; + try { + const resp = await fetch(resolvedUrl); + const blob = await resp.blob(); + const filename = artifact.name || imgUrl.split('/').pop() || 'image.png'; + triggerBlobDownload(blob, filename); + } catch { + const a = document.createElement('a'); + a.href = resolvedUrl; + a.download = artifact.name || 'image.png'; + a.target = '_blank'; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + } + break; + } + case 'html': { + const htmlContent = + typeof artifact.content === 'string' + ? artifact.content + : artifact.content?.content || artifact.content?.html || String(artifact.content); + const blob = new Blob([htmlContent], { type: 'text/html' }); + triggerBlobDownload(blob, artifact.name || 'report.html'); + break; + } + case 'code': { + const blob = new Blob([String(artifact.content)], { type: 'text/plain' }); + triggerBlobDownload(blob, artifact.name || 'code.py'); + break; + } case 'table': { const rows = artifact.content?.rows || []; const columns = artifact.content?.columns?.map((c: any) => c.dataIndex || c.key || c) || []; @@ -963,37 +1006,38 @@ const Playground: NextPage = () => { columns.join(','), ...rows.map((row: any) => columns.map((col: string) => JSON.stringify(row[col] ?? '')).join(',')), ].join('\n'); - content = csvContent; - filename = `table-${Date.now()}.csv`; - mimeType = 'text/csv'; + const blob = new Blob([csvContent], { type: 'text/csv' }); + triggerBlobDownload(blob, artifact.name?.replace(/\.\w+$/, '.csv') || 'table.csv'); break; } - case 'code': - content = String(artifact.content); - filename = `code-${Date.now()}.py`; - mimeType = 'text/plain'; - break; case 'markdown': - case 'summary': - content = String(artifact.content); - filename = `${artifact.type}-${Date.now()}.md`; - mimeType = 'text/markdown'; + case 'summary': { + const blob = new Blob([String(artifact.content)], { type: 'text/markdown' }); + triggerBlobDownload(blob, artifact.name || `${artifact.type}.md`); break; - default: - content = JSON.stringify(artifact.content, null, 2); - filename = `artifact-${Date.now()}.json`; - mimeType = 'application/json'; + } + case 'file': { + const filePath = artifact.content?.file_path || artifact.content?.path; + if (filePath && filePath.includes('/images/')) { + const imgName = filePath.split('/').pop(); + const resolvedUrl = `${process.env.API_BASE_URL || ''}/images/${imgName}`; + try { + const resp = await fetch(resolvedUrl); + const blob = await resp.blob(); + triggerBlobDownload(blob, artifact.name || imgName || 'file'); + } catch { + message.warning('文件暂不可下载'); + } + } else { + message.warning('文件暂不可下载'); + } + break; + } + default: { + const blob = new Blob([JSON.stringify(artifact.content, null, 2)], { type: 'application/json' }); + triggerBlobDownload(blob, artifact.name || 'artifact.json'); + } } - - const blob = new Blob([content], { type: mimeType }); - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = filename; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - URL.revokeObjectURL(url); }; const _copyToClipboard = (text: string) => { @@ -1871,6 +1915,7 @@ const Playground: NextPage = () => { } } }} + onArtifactDownload={artifact => downloadArtifact(artifact as Artifact)} onViewAllFiles={() => { if (round.viewMsg?.id) setActiveViewMsgId(round.viewMsg.id); setRightPanelCollapsed(false);