2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 07:57:21 +08:00

feat: 备份优化

This commit is contained in:
2026-01-22 03:13:06 +08:00
parent 7aeb56f6b7
commit 0440f33cfb
5 changed files with 74 additions and 28 deletions

View File

@@ -77,12 +77,22 @@ func (r *backupRepo) List(typ biz.BackupType) ([]*types.BackupFile, error) {
// target 目标名称
// account 备份账号ID
func (r *backupRepo) Create(ctx context.Context, typ biz.BackupType, target string, account uint) error {
// 取备份账号0 为本地备份
backupAccount := new(biz.BackupAccount)
if err := r.db.First(backupAccount, account).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New(r.t.Get("backup account not found"))
if account != 0 {
if err := r.db.First(backupAccount, account).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New(r.t.Get("backup account not found"))
}
return err
}
} else {
backupAccount = &biz.BackupAccount{
Type: biz.BackupAccountTypeLocal,
Info: types.BackupAccountInfo{
Path: r.GetDefaultPath(typ),
},
}
return err
}
client, err := r.getStorage(*backupAccount)

View File

@@ -66,26 +66,26 @@ func (r *cronRepo) Create(ctx context.Context, req *request.CronCreate) error {
script = fmt.Sprintf(`#!/bin/bash
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
acepanel backup website -n '%s' -p '%s'
acepanel backup clear -t website -f '%s' -s '%d' -p '%s'
`, req.Target, req.BackupPath, req.Target, req.Save, req.BackupPath)
acepanel backup website -n '%s' -a '%d'
acepanel backup clear -t website -f '%s' -s '%d' -a '%d'
`, req.Target, req.BackupAccount, req.Target, req.Save, req.BackupAccount)
}
if req.BackupType == "mysql" || req.BackupType == "postgres" {
script = fmt.Sprintf(`#!/bin/bash
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
acepanel backup database -t '%s' -n '%s' -p '%s'
acepanel backup clear -t '%s' -f '%s' -s '%d' -p '%s'
`, req.BackupType, req.Target, req.BackupPath, req.BackupType, req.Target, req.Save, req.BackupPath)
acepanel backup database -t '%s' -n '%s' -a '%d'
acepanel backup clear -t '%s' -f '%s' -s '%d' -a '%d'
`, req.BackupType, req.Target, req.BackupAccount, req.BackupType, req.Target, req.Save, req.BackupAccount)
}
}
if req.Type == "cutoff" {
script = fmt.Sprintf(`#!/bin/bash
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
acepanel cutoff website -n '%s' -p '%s'
acepanel cutoff clear -t website -n '%s' -s '%d' -p '%s'
`, req.Target, req.BackupPath, req.Target, req.Save, req.BackupPath)
acepanel cutoff website -n '%s'
acepanel cutoff clear -t website -n '%s' -s '%d'
`, req.Target, req.Target, req.Save)
}
if req.Type == "shell" {
script = req.Script

View File

@@ -1,14 +1,14 @@
package request
type CronCreate struct {
Name string `form:"name" json:"name" validate:"required|notExists:crons,name"`
Type string `form:"type" json:"type" validate:"required"`
Time string `form:"time" json:"time" validate:"required|cron"`
Script string `form:"script" json:"script"`
BackupType string `form:"backup_type" json:"backup_type" validate:"requiredIf:Type,backup"`
BackupPath string `form:"backup_path" json:"backup_path"`
Target string `form:"target" json:"target" validate:"requiredIf:Type,backup,cutoff"`
Save int `form:"save" json:"save" validate:"required"`
Name string `form:"name" json:"name" validate:"required|notExists:crons,name"`
Type string `form:"type" json:"type" validate:"required"`
Time string `form:"time" json:"time" validate:"required|cron"`
Script string `form:"script" json:"script"`
BackupType string `form:"backup_type" json:"backup_type" validate:"requiredIf:Type,backup"`
BackupAccount uint `form:"backup_account" json:"backup_account"`
Target string `form:"target" json:"target" validate:"requiredIf:Type,backup,cutoff"`
Save int `form:"save" json:"save" validate:"required"`
}
type CronUpdate struct {

View File

@@ -652,7 +652,6 @@ func (s *CliService) BackupPanel(ctx context.Context, cmd *cli.Command) error {
}
func (s *CliService) BackupClear(ctx context.Context, cmd *cli.Command) error {
path := s.backupRepo.GetDefaultPath(biz.BackupType(cmd.String("type")))
fmt.Println(s.hr)
fmt.Println(s.t.Get("★ Start cleaning [%s]", time.Now().Format(time.DateTime)))
@@ -661,11 +660,12 @@ func (s *CliService) BackupClear(ctx context.Context, cmd *cli.Command) error {
fmt.Println(s.t.Get("|-Cleaning target: %s", cmd.String("file")))
fmt.Println(s.t.Get("|-Keep count: %d", cmd.Int("save")))
if cmd.String("account") != "" {
if cmd.Uint("account") != 0 {
if err := s.backupRepo.ClearAccountExpired(cmd.Uint("account"), biz.BackupType(cmd.String("type")), cmd.String("file"), cmd.Int("save")); err != nil {
return errors.New(s.t.Get("Cleaning failed: %v", err))
}
} else {
path := s.backupRepo.GetDefaultPath(biz.BackupType(cmd.String("type")))
if err := s.backupRepo.ClearExpired(path, cmd.String("file"), cmd.Int("save")); err != nil {
return errors.New(s.t.Get("Cleaning failed: %v", err))
}

View File

@@ -1,5 +1,6 @@
<script setup lang="ts">
import app from '@/api/panel/app'
import backupAccount from '@/api/panel/backupAccount'
import cron from '@/api/panel/cron'
import home from '@/api/panel/home'
import website from '@/api/panel/website'
@@ -17,12 +18,13 @@ const createModel = ref({
target: '',
save: 1,
backup_type: 'website',
backup_path: '',
backup_account: 0,
script: $gettext('# Enter your script content here'),
time: '* * * * *'
})
const websites = ref<any>([])
const accounts = ref<any[]>([])
const { data: installedEnvironment } = useRequest(home.installedEnvironment, {
initialData: {
@@ -64,6 +66,30 @@ watch(createModel, (value) => {
}
})
const generateTaskName = () => {
const type = createModel.value.type
const target = createModel.value.target
if (type === 'backup') {
const backupTypeMap: Record<string, string> = {
website: $gettext('Backup Website'),
mysql: $gettext('Backup MySQL'),
postgres: $gettext('Backup PostgreSQL')
}
const prefix = backupTypeMap[createModel.value.backup_type] || $gettext('Backup')
createModel.value.name = target ? `${prefix} - ${target}` : prefix
} else if (type === 'cutoff') {
createModel.value.name = target ? `${$gettext('Log Rotation')} - ${target}` : $gettext('Log Rotation')
}
}
watch(
() => [createModel.value.type, createModel.value.backup_type, createModel.value.target],
() => {
generateTaskName()
}
)
onMounted(() => {
useRequest(app.isInstalled('nginx')).onSuccess(({ data }) => {
if (data) {
@@ -78,6 +104,15 @@ onMounted(() => {
})
}
})
useRequest(backupAccount.list(1, 10000)).onSuccess(({ data }: { data: any }) => {
for (const item of data.items) {
accounts.value.push({
label: item.name,
value: item.id
})
}
createModel.value.backup_account = accounts.value[0]?.value || 0
})
})
</script>
@@ -143,10 +178,11 @@ onMounted(() => {
>
<n-input v-model:value="createModel.target" :placeholder="$gettext('Database Name')" />
</n-form-item>
<n-form-item v-if="createModel.type === 'backup'" :label="$gettext('Save Directory')">
<n-input
v-model:value="createModel.backup_path"
:placeholder="$gettext('Save Directory')"
<n-form-item v-if="createModel.type === 'backup'" :label="$gettext('Backup Account')">
<n-select
v-model:value="createModel.backup_account"
:options="accounts"
:placeholder="$gettext('Select backup account')"
/>
</n-form-item>
<n-form-item v-if="createModel.type !== 'shell'" :label="$gettext('Retention Count')">