feat: 支持下载备份

This commit is contained in:
耗子
2026-07-24 19:06:22 +08:00
parent 0fc912e6a2
commit 2ad637e1d7
3 changed files with 40 additions and 1 deletions
+2
View File
@@ -20,6 +20,8 @@ func BackupRoutes(i do.Injector) (Endpoints, error) {
{Method: http.MethodPost, Path: "/api/backup/{type}", Handler: backup.Create, Summary: "创建备份", Tags: []string{"备份"},
Request: request.BackupCreate{}},
{Method: http.MethodPost, Path: "/api/backup/{type}/upload", Handler: backup.Upload, Summary: "上传备份", Tags: []string{"备份"}},
{Method: http.MethodGet, Path: "/api/backup/{type}/download", Handler: backup.Download, Summary: "下载备份", Tags: []string{"备份"},
Request: request.BackupFile{}},
{Method: http.MethodDelete, Path: "/api/backup/{type}/delete", Handler: backup.Delete, Summary: "删除备份", Tags: []string{"备份"},
Request: request.BackupFile{}},
{Method: http.MethodPost, Path: "/api/backup/{type}/restore", Handler: backup.Restore, Summary: "恢复备份", Tags: []string{"备份"},
+23
View File
@@ -152,6 +152,29 @@ func (s *BackupService) Delete(w http.ResponseWriter, r *http.Request) {
Success(w, nil)
}
func (s *BackupService) Download(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.BackupFile](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
return
}
file := filepath.Join(s.backupRepo.GetDefaultPath(biz.BackupType(req.Type)), req.File)
info, err := os.Stat(file)
if err != nil {
Error(w, http.StatusNotFound, "%v", err)
return
}
if info.IsDir() {
Error(w, http.StatusForbidden, s.t.Get("can't download a directory"))
return
}
render := chix.NewRender(w, r)
defer render.Release()
render.Download(file, info.Name())
}
func (s *BackupService) Restore(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.BackupRestore](r)
if err != nil {
+15 -1
View File
@@ -65,10 +65,24 @@ const columns: any = [
{
title: $gettext('Actions'),
key: 'actions',
width: 260,
width: 320,
hideInExcel: true,
render(row: any) {
return h(NFlex, { size: 'small', align: 'center' }, () => [
h(
NButton,
{
size: 'small',
type: 'primary',
secondary: true,
onClick: () => {
window.open(
`/api/backup/${type.value}/download?file=${encodeURIComponent(row.name)}`,
)
},
},
{ default: () => $gettext('Download') },
),
h(
NButton,
{