fix: Cronjob backup supports multiple selections (#8691)

Refs #8669 #8694
This commit is contained in:
ssongliu 2025-05-16 14:30:14 +08:00 committed by GitHub
parent f9ccd10cc9
commit c7c3572ecd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 89 additions and 34 deletions

View file

@ -27,12 +27,17 @@ func (u *CronjobService) handleApp(cronjob model.Cronjob, startTime time.Time, t
if cronjob.AppID == "all" { if cronjob.AppID == "all" {
apps, _ = appInstallRepo.ListBy(context.Background()) apps, _ = appInstallRepo.ListBy(context.Background())
} else { } else {
itemID, _ := strconv.Atoi(cronjob.AppID) appIds := strings.Split(cronjob.AppID, ",")
app, err := appInstallRepo.GetFirst(repo.WithByID(uint(itemID))) 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 { if err != nil {
return err return err
} }
apps = append(apps, app) apps = appItems
} }
if len(apps) == 0 { if len(apps) == 0 {
return errors.New("no such app in database!") 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) u.removeExpiredBackup(cronjob, accountMap, record)
return nil return nil
}, nil, int(cronjob.RetryTimes), time.Duration(cronjob.Timeout)*time.Second) }, nil, int(cronjob.RetryTimes), time.Duration(cronjob.Timeout)*time.Second)
return nil
} }
return nil return nil
} }
@ -327,7 +331,9 @@ func loadDbsForJob(cronjob model.Cronjob) []DatabaseHelper {
} }
return dbs return dbs
} }
itemID, _ := strconv.Atoi(cronjob.DBName) dbNames := strings.Split(cronjob.DBName, ",")
for _, name := range dbNames {
itemID, _ := strconv.Atoi(name)
if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" { if cronjob.DBType == "mysql" || cronjob.DBType == "mariadb" {
mysqlItem, _ := mysqlRepo.Get(repo.WithByID(uint(itemID))) mysqlItem, _ := mysqlRepo.Get(repo.WithByID(uint(itemID)))
dbs = append(dbs, DatabaseHelper{ dbs = append(dbs, DatabaseHelper{
@ -345,6 +351,7 @@ func loadDbsForJob(cronjob model.Cronjob) []DatabaseHelper {
Name: pgItem.Name, Name: pgItem.Name,
}) })
} }
}
return dbs return dbs
} }
@ -354,11 +361,13 @@ func loadWebsForJob(cronjob model.Cronjob) []model.Website {
weblist, _ = websiteRepo.List() weblist, _ = websiteRepo.List()
return weblist return weblist
} }
itemID, _ := strconv.Atoi(cronjob.Website) websites := strings.Split(cronjob.Website, ",")
webItem, _ := websiteRepo.GetFirst(repo.WithByID(uint(itemID))) var idItems []uint
if webItem.ID != 0 { for i := 0; i < len(websites); i++ {
weblist = append(weblist, webItem) itemID, _ := strconv.Atoi(websites[i])
idItems = append(idItems, uint(itemID))
} }
weblist, _ = websiteRepo.GetBy(repo.WithByIDs(idItems))
return weblist return weblist
} }

View file

@ -30,6 +30,10 @@ export namespace Cronjob {
files: Array<Item>; files: Array<Item>;
sourceDir: string; sourceDir: string;
websiteList: Array<string>;
appIdList: Array<string>;
dbNameList: Array<string>;
sourceAccounts: Array<string>; sourceAccounts: Array<string>;
downloadAccount: string; downloadAccount: string;
sourceAccountIDs: string; sourceAccountIDs: string;

View file

@ -217,9 +217,17 @@
<LayoutCol v-if="isWebsite()"> <LayoutCol v-if="isWebsite()">
<el-form-item <el-form-item
:label="form.type === 'website' ? $t('cronjob.website') : $t('menu.website')" :label="form.type === 'website' ? $t('cronjob.website') : $t('menu.website')"
prop="website" prop="websiteList"
>
<el-select
v-model="form.websiteList"
multiple
@change="
form.websiteList = form.websiteList.includes('all')
? ['all']
: form.websiteList
"
> >
<el-select v-model="form.website">
<el-option <el-option
:disabled="websiteOptions.length === 0" :disabled="websiteOptions.length === 0"
:label="$t('commons.table.all')" :label="$t('commons.table.all')"
@ -243,8 +251,17 @@
</el-form-item> </el-form-item>
</LayoutCol> </LayoutCol>
<LayoutCol v-if="form.type === 'app'"> <LayoutCol v-if="form.type === 'app'">
<el-form-item :label="$t('cronjob.app')" prop="appID"> <el-form-item :label="$t('cronjob.app')" prop="appIdList">
<el-select clearable v-model="form.appID"> <el-select
clearable
v-model="form.appIdList"
multiple
@change="
form.appIdList = form.appIdList.includes('all')
? ['all']
: form.appIdList
"
>
<el-option <el-option
:disabled="appOptions.length === 0" :disabled="appOptions.length === 0"
:label="$t('commons.table.all')" :label="$t('commons.table.all')"
@ -271,8 +288,17 @@
</el-form-item> </el-form-item>
</LayoutCol> </LayoutCol>
<LayoutCol v-if="form.type === 'database'"> <LayoutCol v-if="form.type === 'database'">
<el-form-item :label="$t('cronjob.database')" prop="dbName"> <el-form-item :label="$t('cronjob.database')" prop="dbNameList">
<el-select clearable v-model="form.dbName"> <el-select
clearable
v-model="form.dbNameList"
multiple
@change="
form.dbNameList = form.dbNameList.includes('all')
? ['all']
: form.dbNameList
"
>
<el-option <el-option
:disabled="dbInfo.dbs.length === 0" :disabled="dbInfo.dbs.length === 0"
:label="$t('commons.table.all')" :label="$t('commons.table.all')"
@ -716,6 +742,10 @@ const form = reactive<Cronjob.CronjobInfo>({
downloadAccountID: 0, downloadAccountID: 0,
sourceAccountItems: [], sourceAccountItems: [],
websiteList: [],
appIdList: [],
dbNameList: [],
retainCopies: 7, retainCopies: 7,
retryTimes: 0, retryTimes: 0,
timeout: 300, timeout: 300,
@ -770,10 +800,13 @@ const search = async () => {
form.scriptID = res.data.scriptID; form.scriptID = res.data.scriptID;
form.appID = res.data.appID; form.appID = res.data.appID;
form.appIdList = res.data.appID.split(',') || [];
form.website = res.data.website; form.website = res.data.website;
form.websiteList = res.data.website.split(',') || [];
form.exclusionRules = res.data.exclusionRules; form.exclusionRules = res.data.exclusionRules;
form.dbType = res.data.dbType; form.dbType = res.data.dbType;
form.dbName = res.data.dbName; form.dbName = res.data.dbName;
form.dbNameList = res.data.dbName.split(',') || [];
form.url = res.data.url; form.url = res.data.url;
form.isDir = res.data.isDir; form.isDir = res.data.isDir;
@ -986,9 +1019,9 @@ const rules = reactive({
script: [{ validator: verifyScript, trigger: 'blur', required: true }], script: [{ validator: verifyScript, trigger: 'blur', required: true }],
scriptID: [Rules.requiredSelect], scriptID: [Rules.requiredSelect],
containerName: [Rules.requiredSelect], containerName: [Rules.requiredSelect],
appID: [Rules.requiredSelect], websiteList: [Rules.requiredSelect],
website: [Rules.requiredSelect], appIdList: [Rules.requiredSelect],
dbName: [Rules.requiredSelect], dbNameList: [Rules.requiredSelect],
url: [Rules.requiredInput], url: [Rules.requiredInput],
files: [{ validator: verifyFiles, trigger: 'blur', required: true }], files: [{ validator: verifyFiles, trigger: 'blur', required: true }],
sourceDir: [Rules.requiredInput], sourceDir: [Rules.requiredInput],
@ -1241,6 +1274,15 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
form.containerName = ''; form.containerName = '';
} }
form.timeout = transferTimeToSecond(form.timeoutItem + form.timeoutUint); 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.alertCount = form.hasAlert && isProductPro.value ? form.alertCount : 0;
form.alertTitle = form.alertTitle =