diff --git a/internal/controllers/dependency_controller.go b/internal/controllers/dependency_controller.go index 9c5a495..dea104f 100644 --- a/internal/controllers/dependency_controller.go +++ b/internal/controllers/dependency_controller.go @@ -31,9 +31,6 @@ func (c *DependencyController) List(ctx *gin.Context) { return } vos := vo.ToDependencyVOListFromModels(deps) - for i := range vos { - vos[i].Log = "" // 列表不返回日志 - } utils.Success(ctx, vos) } @@ -115,14 +112,14 @@ func (c *DependencyController) Install(ctx *gin.Context) { Remark: req.Remark, } - if err := c.service.Install(dep); err != nil { + err := c.service.Install(dep) + // 无论成功失败,都同步记录日志 + c.service.Create(dep) + + if err != nil { utils.ServerError(ctx, err.Error()) return } - - // 安装成功后保存到数据库 - c.service.Create(dep) - utils.SuccessMsg(ctx, "安装成功") } @@ -194,9 +191,9 @@ func (c *DependencyController) Uninstall(ctx *gin.Context) { // 获取依赖信息 deps, _ := c.service.List("", "") var dep *models.Dependency - for _, d := range deps { - if d.ID == id { - dep = &d + for i := range deps { + if deps[i].ID == id { + dep = &deps[i] break } } @@ -228,9 +225,9 @@ func (c *DependencyController) Reinstall(ctx *gin.Context) { // 获取依赖信息 deps, _ := c.service.List("", "") var dep *models.Dependency - for _, d := range deps { - if d.ID == id { - dep = &d + for i := range deps { + if deps[i].ID == id { + dep = &deps[i] break } } @@ -240,11 +237,14 @@ func (c *DependencyController) Reinstall(ctx *gin.Context) { return } - if err := c.service.Install(dep); err != nil { + err := c.service.Install(dep) + // 无论成功失败,都同步记录日志 + c.service.Create(dep) + + if err != nil { utils.ServerError(ctx, err.Error()) return } - utils.SuccessMsg(ctx, "重新安装成功") } @@ -264,10 +264,14 @@ func (c *DependencyController) ReinstallAll(ctx *gin.Context) { } var failed []string - for _, d := range deps { - if err := c.service.Install(&d); err != nil { + for i := range deps { + d := &deps[i] + err := c.service.Install(d) + if err != nil { failed = append(failed, d.Name) } + // 无论成功失败,都同步记录日志到数据库 + c.service.Create(d) } if len(failed) > 0 { diff --git a/internal/services/dependency_service.go b/internal/services/dependency_service.go index 6820437..5309a9b 100644 --- a/internal/services/dependency_service.go +++ b/internal/services/dependency_service.go @@ -31,12 +31,16 @@ func (s *DependencyService) List(language, langVersion string) ([]models.Depende // Create 创建依赖记录 func (s *DependencyService) Create(dep *models.Dependency) error { - // 检查是否已存在(名称、语言、版本 必须完全匹配) + // 检查是否已存在(名称、版本、语言及版本必须完全匹配) var existing models.Dependency - err := database.DB.Where("name = ? AND language = ? AND lang_version = ?", dep.Name, dep.Language, dep.LangVersion).First(&existing).Error + err := database.DB.Where("name = ? AND version = ? AND language = ? AND lang_version = ?", dep.Name, dep.Version, dep.Language, dep.LangVersion).First(&existing).Error if err == nil { - return errors.New("依赖已存在") + // 如果已存在,更新 ID 并执行更新 + dep.ID = existing.ID + return database.DB.Model(&existing).Updates(dep).Error } + + // 不存在则新建 if dep.ID == "" { dep.ID = utils.GenerateID() } diff --git a/web/src/components/XTerminal.vue b/web/src/components/XTerminal.vue index 19fe5ff..c735d35 100644 --- a/web/src/components/XTerminal.vue +++ b/web/src/components/XTerminal.vue @@ -190,7 +190,7 @@ function connectWebSocket() { } terminal?.write(event.data) - // 检测安装结果标识 + // 检测结果标识(保持简单的单次消息检测,不使用持久缓冲区,避免重复触发通知) if (typeof event.data === 'string') { if (event.data.includes('__INSTALL_SUCCESS__')) { emit('success') diff --git a/web/src/views/dependencies/Dependencies.vue b/web/src/views/dependencies/Dependencies.vue index fba98fe..fde5065 100644 --- a/web/src/views/dependencies/Dependencies.vue +++ b/web/src/views/dependencies/Dependencies.vue @@ -7,10 +7,9 @@ import { Label } from '@/components/ui/label' import { Badge } from '@/components/ui/badge' import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogDescription } from '@/components/ui/dialog' import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from '@/components/ui/alert-dialog' -import { Trash2, Package, Search, RefreshCw, Loader2, Download, FileText, RotateCw, ChevronLeft, Terminal as TerminalIcon, X } from 'lucide-vue-next' +import { Trash2, Package, Search, RefreshCw, Loader2, Download, FileText, RotateCw, ChevronLeft } from 'lucide-vue-next' import { api, type Dependency } from '@/api' import TextOverflow from '@/components/TextOverflow.vue' -import XTerminal from '@/components/XTerminal.vue' import { toast } from 'vue-sonner' const route = useRoute() @@ -35,18 +34,10 @@ const newPkgRemark = ref('') const showDeleteDialog = ref(false) const depToDelete = ref(null) -// 日志对话框 const showLogDialog = ref(false) const logContent = ref('') const logPkgName = ref('') -// 终端状态 -const showTerminalDialog = ref(false) -const terminalCommand = ref('') -const terminalTitle = ref('依赖安装') -const isInstallSuccess = ref(false) -const pendingInstall = ref<{ name: string; version?: string; language: string; lang_version?: string; remark?: string } | null>(null) - // 搜索 const searchQuery = ref('') @@ -110,41 +101,19 @@ async function installPackage() { } installing.value = true - isInstallSuccess.value = false // 重置状态 try { - const { command } = await api.deps.getInstallCmd(pkgData) - terminalCommand.value = command - terminalTitle.value = `安装: ${pkgData.name}` - pendingInstall.value = pkgData + await api.deps.install(pkgData) + toast.success('指令已发送,详情请查看日志') + showInstallDialog.value = false + } catch (e: any) { + toast.error('安装过程出错: ' + e.message) showInstallDialog.value = false - showTerminalDialog.value = true - } catch (e: unknown) { - toast.error((e as Error).message || '获取安装命令失败') } finally { installing.value = false + await loadDeps() } } -async function handleTerminalClose() { - if (pendingInstall.value && isInstallSuccess.value) { - try { - // 终端关闭后,仅在成功时尝试在数据库中记录 - await api.deps.create(pendingInstall.value) - toast.success('依赖记录已更新') - } catch (e: any) { - if (e.message !== '依赖已存在') { - toast.error('记录依赖失败: ' + e.message) - } - } - } else if (pendingInstall.value && !isInstallSuccess.value) { - toast.error('安装未成功,记录未保存') - } - - pendingInstall.value = null - isInstallSuccess.value = false - loadDeps() -} - function confirmDelete(dep: Dependency) { depToDelete.value = dep showDeleteDialog.value = true @@ -173,20 +142,13 @@ function showLog(dep: Dependency) { async function reinstallPackage(dep: Dependency) { reinstalling.value = dep.id try { - const { command } = await api.deps.getInstallCmd({ - name: dep.name, - version: dep.version, - language: dep.language, - lang_version: dep.lang_version - }) - terminalCommand.value = command - terminalTitle.value = `重装: ${dep.name}` - pendingInstall.value = null // 重新安装不需要再次记录 - showTerminalDialog.value = true - } catch (e: unknown) { - toast.error((e as Error).message || '获取命令失败') + await api.deps.reinstall(dep.id) + toast.success(`重装指令已发送`) + } catch (e: any) { + toast.error('重装错误: ' + e.message) } finally { reinstalling.value = null + await loadDeps() } } @@ -195,16 +157,13 @@ async function reinstallAll() { try { const lang = language.value || activeTab.value const ver = langVersion.value - const { command } = await api.deps.getReinstallAllCmd(lang, ver) - - terminalCommand.value = command - terminalTitle.value = `全部重装: ${getTypeLabel(lang)}` - pendingInstall.value = null // 全部重装不需要记录新条目 - showTerminalDialog.value = true - } catch (e: unknown) { - toast.error((e as Error).message || '获取命令失败') + await api.deps.reinstallAll(lang, ver) + toast.success('全部重装指令执行完毕') + } catch (e: any) { + toast.error('全部重装错误: ' + e.message) } finally { reinstallingAll.value = false + await loadDeps() } } @@ -297,7 +256,7 @@ onMounted(async () => { 包名 版本 - 操作 + 操作 @@ -319,15 +278,19 @@ onMounted(async () => { - - - - @@ -401,35 +364,6 @@ onMounted(async () => { - - - - - - {{ terminalTitle }} - 正在执行依赖安装指令 - -
-
-
- - 正在执行: {{ terminalCommand }} -
- -
-
- -
-
-
-