From c7c3572ecdadb56855de3cd20e4bdcbf93a7fbaa Mon Sep 17 00:00:00 2001 From: ssongliu <73214554+ssongliu@users.noreply.github.com> Date: Fri, 16 May 2025 14:30:14 +0800 Subject: [PATCH] fix: Cronjob backup supports multiple selections (#8691) Refs #8669 #8694 --- agent/app/service/cronjob_backup.go | 59 ++++++++++-------- frontend/src/api/interface/cronjob.ts | 4 ++ .../views/cronjob/cronjob/operate/index.vue | 60 ++++++++++++++++--- 3 files changed, 89 insertions(+), 34 deletions(-) diff --git a/agent/app/service/cronjob_backup.go b/agent/app/service/cronjob_backup.go index f627a5394..bbabddd71 100644 --- a/agent/app/service/cronjob_backup.go +++ b/agent/app/service/cronjob_backup.go @@ -27,12 +27,17 @@ func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time, t if cronjob.AppID == "all" { apps, _ = appInstallRepo.ListBy(context.Background()) } else { - itemID, _ := strconv.Atoi(cronjob.AppID) - app, err := appInstallRepo.GetFirst(repo.WithByID(uint(itemID))) + appIds := strings.Split(cronjob.AppID, ",") + var idItems []uint + for i := 0; i < len(appIds); i++ { + itemID, _ := strconv.Atoi(appIds[i]) + idItems = append(idItems, uint(itemID)) + } + appItems, err := appInstallRepo.ListBy(context.Background(), repo.WithByIDs(idItems)) if err != nil { return err } - apps = append(apps, app) + apps = appItems } if len(apps) == 0 { return errors.New("no such app in database!") @@ -108,7 +113,6 @@ func (u *CronjobService) handleWebsite(cronjob model.Cronjob, startTime time.Tim u.removeExpiredBackup(cronjob, accountMap, record) return nil }, nil, int(cronjob.RetryTimes), time.Duration(cronjob.Timeout)*time.Second) - return nil } return nil } @@ -327,23 +331,26 @@ func loadDbsForJob(cronjob model.Cronjob) []DatabaseHelper { } return dbs } - itemID, _ := strconv.Atoi(cronjob.DBName) - if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" { - mysqlItem, _ := mysqlRepo.Get(repo.WithByID(uint(itemID))) - dbs = append(dbs, DatabaseHelper{ - ID: mysqlItem.ID, - DBType: cronjob.DBType, - Database: mysqlItem.MysqlName, - Name: mysqlItem.Name, - }) - } else { - pgItem, _ := postgresqlRepo.Get(repo.WithByID(uint(itemID))) - dbs = append(dbs, DatabaseHelper{ - ID: pgItem.ID, - DBType: cronjob.DBType, - Database: pgItem.PostgresqlName, - Name: pgItem.Name, - }) + dbNames := strings.Split(cronjob.DBName, ",") + for _, name := range dbNames { + itemID, _ := strconv.Atoi(name) + if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" { + mysqlItem, _ := mysqlRepo.Get(repo.WithByID(uint(itemID))) + dbs = append(dbs, DatabaseHelper{ + ID: mysqlItem.ID, + DBType: cronjob.DBType, + Database: mysqlItem.MysqlName, + Name: mysqlItem.Name, + }) + } else { + pgItem, _ := postgresqlRepo.Get(repo.WithByID(uint(itemID))) + dbs = append(dbs, DatabaseHelper{ + ID: pgItem.ID, + DBType: cronjob.DBType, + Database: pgItem.PostgresqlName, + Name: pgItem.Name, + }) + } } return dbs } @@ -354,11 +361,13 @@ func loadWebsForJob(cronjob model.Cronjob) []model.Website { weblist, _ = websiteRepo.List() return weblist } - itemID, _ := strconv.Atoi(cronjob.Website) - webItem, _ := websiteRepo.GetFirst(repo.WithByID(uint(itemID))) - if webItem.ID != 0 { - weblist = append(weblist, webItem) + websites := strings.Split(cronjob.Website, ",") + var idItems []uint + for i := 0; i < len(websites); i++ { + itemID, _ := strconv.Atoi(websites[i]) + idItems = append(idItems, uint(itemID)) } + weblist, _ = websiteRepo.GetBy(repo.WithByIDs(idItems)) return weblist } diff --git a/frontend/src/api/interface/cronjob.ts b/frontend/src/api/interface/cronjob.ts index d98f857fb..42de724ea 100644 --- a/frontend/src/api/interface/cronjob.ts +++ b/frontend/src/api/interface/cronjob.ts @@ -30,6 +30,10 @@ export namespace Cronjob { files: Array; sourceDir: string; + websiteList: Array; + appIdList: Array; + dbNameList: Array; + sourceAccounts: Array; downloadAccount: string; sourceAccountIDs: string; diff --git a/frontend/src/views/cronjob/cronjob/operate/index.vue b/frontend/src/views/cronjob/cronjob/operate/index.vue index 81edab9fc..f6fb60fc0 100644 --- a/frontend/src/views/cronjob/cronjob/operate/index.vue +++ b/frontend/src/views/cronjob/cronjob/operate/index.vue @@ -217,9 +217,17 @@ - + - - + + - - + + ({ downloadAccountID: 0, sourceAccountItems: [], + websiteList: [], + appIdList: [], + dbNameList: [], + retainCopies: 7, retryTimes: 0, timeout: 300, @@ -770,10 +800,13 @@ const search = async () => { form.scriptID = res.data.scriptID; form.appID = res.data.appID; + form.appIdList = res.data.appID.split(',') || []; form.website = res.data.website; + form.websiteList = res.data.website.split(',') || []; form.exclusionRules = res.data.exclusionRules; form.dbType = res.data.dbType; form.dbName = res.data.dbName; + form.dbNameList = res.data.dbName.split(',') || []; form.url = res.data.url; form.isDir = res.data.isDir; @@ -986,9 +1019,9 @@ const rules = reactive({ script: [{ validator: verifyScript, trigger: 'blur', required: true }], scriptID: [Rules.requiredSelect], containerName: [Rules.requiredSelect], - appID: [Rules.requiredSelect], - website: [Rules.requiredSelect], - dbName: [Rules.requiredSelect], + websiteList: [Rules.requiredSelect], + appIdList: [Rules.requiredSelect], + dbNameList: [Rules.requiredSelect], url: [Rules.requiredInput], files: [{ validator: verifyFiles, trigger: 'blur', required: true }], sourceDir: [Rules.requiredInput], @@ -1241,6 +1274,15 @@ const onSubmit = async (formEl: FormInstance | undefined) => { form.containerName = ''; } form.timeout = transferTimeToSecond(form.timeoutItem + form.timeoutUint); + if (form.appIdList) { + form.appID = form.appIdList.join(','); + } + if (form.websiteList) { + form.website = form.websiteList.join(','); + } + if (form.dbNameList) { + form.dbName = form.dbNameList.join(','); + } form.alertCount = form.hasAlert && isProductPro.value ? form.alertCount : 0; form.alertTitle =