From e3131e15dc25513cc1557bd7a60debaed107ebf8 Mon Sep 17 00:00:00 2001 From: engigu Date: Wed, 24 Dec 2025 09:57:12 +0800 Subject: [PATCH] feat: add package reisntall --- docker-compose.ghcr.yml | 4 +- internal/controllers/dependency_controller.go | 61 +++++++++++++++++++ internal/router/router.go | 2 + web/src/api/index.ts | 2 + web/src/views/dependencies/Dependencies.vue | 40 +++++++++++- 5 files changed, 104 insertions(+), 5 deletions(-) diff --git a/docker-compose.ghcr.yml b/docker-compose.ghcr.yml index 30986ad..0f9a8aa 100644 --- a/docker-compose.ghcr.yml +++ b/docker-compose.ghcr.yml @@ -1,8 +1,8 @@ -version: '3.8' + services: baihu: - image: ghcr.io/engigu/baihu:main + image: ghcr.io/engigu/baihu:latest container_name: baihu ports: - "8052:8052" diff --git a/internal/controllers/dependency_controller.go b/internal/controllers/dependency_controller.go index 88ad3d3..64b6ab4 100644 --- a/internal/controllers/dependency_controller.go +++ b/internal/controllers/dependency_controller.go @@ -2,6 +2,7 @@ package controllers import ( "strconv" + "strings" "baihu/internal/models" "baihu/internal/services" @@ -147,6 +148,66 @@ func (c *DependencyController) Uninstall(ctx *gin.Context) { utils.SuccessMsg(ctx, "卸载成功") } +// Reinstall 重新安装依赖 +func (c *DependencyController) Reinstall(ctx *gin.Context) { + id, err := strconv.Atoi(ctx.Param("id")) + if err != nil { + utils.BadRequest(ctx, "无效的 ID") + return + } + + // 获取依赖信息 + deps, _ := c.service.List("") + var dep *models.Dependency + for _, d := range deps { + if d.ID == id { + dep = &d + break + } + } + + if dep == nil { + utils.NotFound(ctx, "依赖不存在") + return + } + + if err := c.service.Install(dep); err != nil { + utils.ServerError(ctx, err.Error()) + return + } + + utils.SuccessMsg(ctx, "重新安装成功") +} + +// ReinstallAll 重新安装所有依赖 +func (c *DependencyController) ReinstallAll(ctx *gin.Context) { + depType := ctx.Query("type") + if depType == "" { + utils.BadRequest(ctx, "缺少 type 参数") + return + } + + deps, err := c.service.List(depType) + if err != nil { + utils.ServerError(ctx, "获取依赖列表失败") + return + } + + var failed []string + for _, d := range deps { + if err := c.service.Install(&d); err != nil { + failed = append(failed, d.Name) + } + } + + if len(failed) > 0 { + utils.ServerError(ctx, "部分包安装失败: "+strings.Join(failed, ", ")) + return + } + + utils.SuccessMsg(ctx, "全部重新安装成功") +} + // GetInstalled 获取已安装的包 func (c *DependencyController) GetInstalled(ctx *gin.Context) { depType := ctx.Query("type") diff --git a/internal/router/router.go b/internal/router/router.go index 22bbe7e..fa47d35 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -193,6 +193,8 @@ func Setup(c *Controllers) *gin.Engine { deps.DELETE("/:id", c.Dependency.Delete) deps.POST("/install", c.Dependency.Install) deps.POST("/uninstall/:id", c.Dependency.Uninstall) + deps.POST("/reinstall/:id", c.Dependency.Reinstall) + deps.POST("/reinstall-all", c.Dependency.ReinstallAll) deps.GET("/installed", c.Dependency.GetInstalled) } } diff --git a/web/src/api/index.ts b/web/src/api/index.ts index 0de378d..132507b 100644 --- a/web/src/api/index.ts +++ b/web/src/api/index.ts @@ -203,6 +203,8 @@ export const api = { install: (data: { name: string; version?: string; type: string; remark?: string }) => request('/deps/install', { method: 'POST', body: JSON.stringify(data) }), uninstall: (id: number) => request(`/deps/uninstall/${id}`, { method: 'POST' }), + reinstall: (id: number) => request(`/deps/reinstall/${id}`, { method: 'POST' }), + reinstallAll: (type: string) => request(`/deps/reinstall-all?type=${type}`, { method: 'POST' }), getInstalled: (type: string) => request(`/deps/installed?type=${type}`) } } diff --git a/web/src/views/dependencies/Dependencies.vue b/web/src/views/dependencies/Dependencies.vue index 66cb2a5..96d9684 100644 --- a/web/src/views/dependencies/Dependencies.vue +++ b/web/src/views/dependencies/Dependencies.vue @@ -7,7 +7,7 @@ import { Badge } from '@/components/ui/badge' import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog' import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from '@/components/ui/alert-dialog' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' -import { Trash2, Package, Search, RefreshCw, Loader2, Download, FileText } from 'lucide-vue-next' +import { Trash2, Package, Search, RefreshCw, Loader2, Download, FileText, RotateCw } from 'lucide-vue-next' import { api, type Dependency } from '@/api' import { toast } from 'vue-sonner' @@ -15,6 +15,8 @@ const activeTab = ref('py') const deps = ref([]) const loading = ref(false) const installing = ref(false) +const reinstalling = ref(null) +const reinstallingAll = ref(false) // 安装对话框 const showInstallDialog = ref(false) @@ -107,6 +109,32 @@ function showLog(dep: Dependency) { showLogDialog.value = true } +async function reinstallPackage(dep: Dependency) { + reinstalling.value = dep.id + try { + await api.deps.reinstall(dep.id) + toast.success(`${dep.name} 重新安装成功`) + await loadDeps() + } catch (e: unknown) { + toast.error((e as Error).message || '重新安装失败') + } finally { + reinstalling.value = null + } +} + +async function reinstallAll() { + reinstallingAll.value = true + try { + await api.deps.reinstallAll(activeTab.value) + toast.success('全部重新安装成功') + await loadDeps() + } catch (e: unknown) { + toast.error((e as Error).message || '重新安装失败') + } finally { + reinstallingAll.value = false + } +} + function getTypeLabel(type: string) { return type === 'py' ? 'Python' : 'Node.js' } @@ -144,6 +172,9 @@ onMounted(loadDeps) + @@ -155,7 +186,7 @@ onMounted(loadDeps) 包名 版本 - 操作 + 操作 @@ -177,10 +208,13 @@ onMounted(loadDeps) {{ dep.name }} {{ dep.version || '-' }} - + +