feat: 快照支持本地目录及多选备份账号 (#3693)

pull/3696/head
ssongliu 10 months ago committed by GitHub
parent e35998a4be
commit 61078a24fd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -101,6 +101,7 @@ type SnapshotStatus struct {
type SnapshotCreate struct { type SnapshotCreate struct {
ID uint `json:"id"` ID uint `json:"id"`
From string `json:"from" validate:"required"` From string `json:"from" validate:"required"`
DefaultDownload string `json:"defaultDownload" validate:"required"`
Description string `json:"description" validate:"max=256"` Description string `json:"description" validate:"max=256"`
} }
type SnapshotRecover struct { type SnapshotRecover struct {

@ -5,6 +5,7 @@ type Snapshot struct {
Name string `json:"name" gorm:"type:varchar(64);not null;unique"` Name string `json:"name" gorm:"type:varchar(64);not null;unique"`
Description string `json:"description" gorm:"type:varchar(256)"` Description string `json:"description" gorm:"type:varchar(256)"`
From string `json:"from"` From string `json:"from"`
DefaultDownload string `json:"defaultDownload" gorm:"type:varchar(64)"`
Status string `json:"status" gorm:"type:varchar(64)"` Status string `json:"status" gorm:"type:varchar(64)"`
Message string `json:"message" gorm:"type:varchar(256)"` Message string `json:"message" gorm:"type:varchar(256)"`
Version string `json:"version" gorm:"type:varchar(256)"` Version string `json:"version" gorm:"type:varchar(256)"`

@ -69,6 +69,7 @@ func Init() {
migrations.UpdateOneDriveToken, migrations.UpdateOneDriveToken,
migrations.UpdateCronjobSpec, migrations.UpdateCronjobSpec,
migrations.UpdateBackupRecordPath, migrations.UpdateBackupRecordPath,
migrations.UpdateSnapshotRecords,
}) })
if err := m.Migrate(); err != nil { if err := m.Migrate(); err != nil {
global.LOG.Error(err) global.LOG.Error(err)

@ -415,3 +415,20 @@ var UpdateBackupRecordPath = &gormigrate.Migration{
return nil return nil
}, },
} }
var UpdateSnapshotRecords = &gormigrate.Migration{
ID: "20240124-update-snapshot-records",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.Snapshot{}); err != nil {
return err
}
var snaps []model.Snapshot
_ = tx.Find(&snaps).Error
for _, snap := range snaps {
_ = tx.Model(&model.Snapshot{}).
Where("id = ?", snap.ID).
Updates(map[string]interface{}{"default_download": snap.From}).Error
}
return nil
},
}

@ -90,6 +90,7 @@ export namespace Setting {
export interface SnapshotCreate { export interface SnapshotCreate {
id: number; id: number;
from: string; from: string;
defaultDownload: string;
description: string; description: string;
} }
export interface SnapshotImport { export interface SnapshotImport {

@ -111,9 +111,9 @@
<el-col :span="22"> <el-col :span="22">
<el-form-item <el-form-item
:label="$t('cronjob.target') + ' ( ' + $t('setting.thirdPartySupport') + ' )'" :label="$t('cronjob.target') + ' ( ' + $t('setting.thirdPartySupport') + ' )'"
prop="from" prop="fromAccounts"
> >
<el-select v-model="snapInfo.from" clearable> <el-select multiple @change="changeAccount" v-model="snapInfo.fromAccounts" clearable>
<el-option <el-option
v-for="item in backupOptions" v-for="item in backupOptions"
:key="item.label" :key="item.label"
@ -122,6 +122,16 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="$t('cronjob.default_download_path')" prop="default_download">
<el-select v-model="snapInfo.default_download" clearable>
<el-option
v-for="item in accountOptions"
:key="item.label"
:value="item.value"
:label="item.label"
/>
</el-select>
</el-form-item>
<el-form-item :label="$t('commons.table.description')" prop="description"> <el-form-item :label="$t('commons.table.description')" prop="description">
<el-input type="textarea" clearable v-model="snapInfo.description" /> <el-input type="textarea" clearable v-model="snapInfo.description" />
</el-form-item> </el-form-item>
@ -180,15 +190,20 @@ const recoverStatusRef = ref();
const importRef = ref(); const importRef = ref();
const isRecordShow = ref(); const isRecordShow = ref();
const backupOptions = ref(); const backupOptions = ref();
const accountOptions = ref();
type FormInstance = InstanceType<typeof ElForm>; type FormInstance = InstanceType<typeof ElForm>;
const snapRef = ref<FormInstance>(); const snapRef = ref<FormInstance>();
const rules = reactive({ const rules = reactive({
from: [Rules.requiredSelect], fromAccounts: [Rules.requiredSelect],
default_download: [Rules.requiredSelect],
}); });
let snapInfo = reactive<Setting.SnapshotCreate>({ let snapInfo = reactive<Setting.SnapshotCreate>({
id: 0, id: 0,
from: '', from: '',
default_download: '',
fromAccounts: [],
description: '', description: '',
}); });
@ -217,6 +232,7 @@ const submitAddSnapshot = (formEl: FormInstance | undefined) => {
formEl.validate(async (valid) => { formEl.validate(async (valid) => {
if (!valid) return; if (!valid) return;
loading.value = true; loading.value = true;
snapInfo.from = snapInfo.fromAccounts.join(',');
await snapshotCreate(snapInfo) await snapshotCreate(snapInfo)
.then(() => { .then(() => {
loading.value = false; loading.value = false;
@ -238,10 +254,27 @@ const loadBackups = async () => {
const res = await getBackupList(); const res = await getBackupList();
backupOptions.value = []; backupOptions.value = [];
for (const item of res.data) { for (const item of res.data) {
if (item.type !== 'LOCAL' && item.id !== 0) { if (item.id !== 0) {
backupOptions.value.push({ label: i18n.global.t('setting.' + item.type), value: item.type }); backupOptions.value.push({ label: i18n.global.t('setting.' + item.type), value: item.type });
} }
} }
changeAccount();
};
const changeAccount = async () => {
accountOptions.value = [];
for (const item of backupOptions.value) {
let exit = false;
for (const ac of snapInfo.fromAccounts) {
if (item.value == ac) {
exit = true;
break;
}
}
if (exit) {
accountOptions.value.push(item);
}
}
}; };
const batchDelete = async (row: Setting.SnapshotInfo | null) => { const batchDelete = async (row: Setting.SnapshotInfo | null) => {

Loading…
Cancel
Save