mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-10-27 01:05:57 +08:00
feat: 快照支持本地目录及多选备份账号 (#3693)
This commit is contained in:
parent
e35998a4be
commit
61078a24fd
6 changed files with 67 additions and 13 deletions
|
|
@ -99,9 +99,10 @@ 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"`
|
||||||
Description string `json:"description" validate:"max=256"`
|
DefaultDownload string `json:"defaultDownload" validate:"required"`
|
||||||
|
Description string `json:"description" validate:"max=256"`
|
||||||
}
|
}
|
||||||
type SnapshotRecover struct {
|
type SnapshotRecover struct {
|
||||||
IsNew bool `json:"isNew"`
|
IsNew bool `json:"isNew"`
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,13 @@ package model
|
||||||
|
|
||||||
type Snapshot struct {
|
type Snapshot struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
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"`
|
||||||
Status string `json:"status" gorm:"type:varchar(64)"`
|
DefaultDownload string `json:"defaultDownload" gorm:"type:varchar(64)"`
|
||||||
Message string `json:"message" gorm:"type:varchar(256)"`
|
Status string `json:"status" gorm:"type:varchar(64)"`
|
||||||
Version string `json:"version" gorm:"type:varchar(256)"`
|
Message string `json:"message" gorm:"type:varchar(256)"`
|
||||||
|
Version string `json:"version" gorm:"type:varchar(256)"`
|
||||||
|
|
||||||
InterruptStep string `json:"interruptStep" gorm:"type:varchar(64)"`
|
InterruptStep string `json:"interruptStep" gorm:"type:varchar(64)"`
|
||||||
RecoverStatus string `json:"recoverStatus" gorm:"type:varchar(64)"`
|
RecoverStatus string `json:"recoverStatus" gorm:"type:varchar(64)"`
|
||||||
|
|
|
||||||
|
|
@ -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…
Add table
Reference in a new issue