From 2a26a3943fd3591361e4da87bdc0c8ef9d3822dc Mon Sep 17 00:00:00 2001 From: xiongxiao Date: Thu, 19 Mar 2026 04:12:22 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0=E7=BC=96=E8=BE=91=E5=8A=9F=E8=83=BD=EF=BC=8C?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=A0=87=E9=A2=98=E3=80=81=E6=A0=87=E7=AD=BE?= =?UTF-8?q?=E3=80=81=E6=91=98=E8=A6=81=E3=80=81=E6=8F=8F=E8=BF=B0=E5=92=8C?= =?UTF-8?q?=E9=93=BE=E6=8E=A5=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/FileDescriptionDialog.tsx | 179 +++++++++++++++++++ src/modules/project-api.ts | 164 ++++++++++++++++- src/pages/code-graph/components/NodeInfo.tsx | 40 ++++- src/pages/code-graph/store/index.ts | 5 + 4 files changed, 385 insertions(+), 3 deletions(-) create mode 100644 src/components/FileDescriptionDialog.tsx diff --git a/src/components/FileDescriptionDialog.tsx b/src/components/FileDescriptionDialog.tsx new file mode 100644 index 0000000..3eef32d --- /dev/null +++ b/src/components/FileDescriptionDialog.tsx @@ -0,0 +1,179 @@ +import { useState, useEffect } from 'react'; +import { queryApi as projectApi } from '@/modules/project-api'; +import { toast } from 'sonner'; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogFooter, +} from '@/components/ui/dialog'; +import { Button } from '@/components/ui/button'; +import { Textarea } from '@/components/ui/textarea'; +import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; + +const API_URL = '/root/v1/dev-cnb'; + +export type FileDescriptionData = { + filepath: string; + title?: string; + tags?: string[]; + summary?: string; + description?: string; + link?: string; +}; + +interface FileDescriptionDialogProps { + open: boolean; + onOpenChange: (open: boolean) => void; + data: FileDescriptionData; + onSuccess?: () => void; +} + +export function FileDescriptionDialog({ + open, + onOpenChange, + data, + onSuccess, +}: FileDescriptionDialogProps) { + const [loading, setLoading] = useState(false); + const [formData, setFormData] = useState({ + filepath: data.filepath, + title: '', + tags: [], + summary: '', + description: '', + link: '', + }); + + // 当打开对话框或数据变化时,同步数据 + useEffect(() => { + if (open && data.filepath) { + setFormData({ + filepath: data.filepath, + title: data.title || '', + tags: data.tags || [], + summary: data.summary || '', + description: data.description || '', + link: data.link || '', + }); + } + }, [open, data]); + + const handleSave = async () => { + setLoading(true); + try { + // 过滤掉空值 + const updateData: Partial = { + filepath: formData.filepath, + }; + if (formData.title) updateData.title = formData.title; + if (formData.tags && formData.tags.length > 0) updateData.tags = formData.tags; + if (formData.summary) updateData.summary = formData.summary; + if (formData.description) updateData.description = formData.description; + if (formData.link) updateData.link = formData.link; + + const res = await projectApi['project-file']['update'](updateData, { url: API_URL }); + if (res.code === 200) { + toast.success('保存成功'); + onOpenChange(false); + onSuccess?.(); + } else { + toast.error(res.message ?? '保存失败'); + } + } catch { + toast.error('保存失败'); + } finally { + setLoading(false); + } + }; + + const handleTagsChange = (value: string) => { + // 标签以逗号分隔 + const tags = value.split(',').map((t) => t.trim()).filter(Boolean); + setFormData((prev) => ({ ...prev, tags })); + }; + + return ( + + + + 编辑文件描述 + +
+ {/* 文件路径(只读) */} +
+ + +
+ + {/* 标题 */} +
+ + setFormData((prev) => ({ ...prev, title: e.target.value }))} + placeholder="输入文件标题" + /> +
+ + {/* 标签 */} +
+ + handleTagsChange(e.target.value)} + placeholder="输入标签,用逗号分隔" + /> + 多个标签用逗号分隔 +
+ + {/* 摘要 */} +
+ + setFormData((prev) => ({ ...prev, summary: e.target.value }))} + placeholder="简短描述文件内容" + /> +
+ + {/* 链接 */} +
+ + setFormData((prev) => ({ ...prev, link: e.target.value }))} + placeholder="关联的外部链接(如文档、Issue 等)" + /> +
+ + {/* 描述 */} +
+ +