Files
1Panel/frontend/src/views/setting/tabs/backup.vue
2022-12-02 18:54:15 +08:00

344 lines
13 KiB
Vue

<template>
<el-card style="margin-top: 20px">
<template #header>
<div class="card-header">
<span>{{ $t('setting.backup') }}</span>
</div>
</template>
<el-button type="primary" icon="Plus" @click="onCreate">
{{ $t('commons.button.create') }}
</el-button>
<el-row :gutter="20" class="row-box">
<el-col v-for="item in data" :key="item.id" :span="8" style="margin-top: 20px">
<el-card class="el-card">
<template #header>
<div class="card-header">
<svg-icon style="font-size: 7px" :iconName="loadIconName(item.type)"></svg-icon>
<span style="font-size: 16px; font-weight: 500">&nbsp;{{ loadBackupName(item.type) }}</span>
<div style="float: right">
<el-button @click="onEdit(item)">{{ $t('commons.button.edit') }}</el-button>
<el-button v-if="item.type !== 'LOCAL'" @click="onBatchDelete(item)">
{{ $t('commons.button.delete') }}
</el-button>
</div>
</div>
</template>
<el-form label-position="left" label-width="130px">
<el-form-item v-if="item.type === 'LOCAL'" :label="$t('setting.currentPath')">
{{ item.varsJson['dir'] }}
</el-form-item>
<el-form-item v-if="item.type === 'S3'" label="Region">
{{ item.varsJson['region'] }}
</el-form-item>
<el-form-item v-if="hasBucket(item.type)" label="Endpoint">
{{ item.varsJson['endpoint'] }}
</el-form-item>
<el-form-item v-if="hasBucket(item.type)" label="Bucket">
{{ item.bucket }}
</el-form-item>
<el-form-item v-if="item.type === 'SFTP'" :label="$t('setting.address')">
{{ item.varsJson['address'] }}
</el-form-item>
<el-form-item v-if="item.type === 'SFTP'" :label="$t('setting.port')">
{{ item.varsJson['port'] }}
</el-form-item>
<el-form-item v-if="item.type === 'SFTP'" :label="$t('setting.username')">
{{ item.varsJson['username'] }}
</el-form-item>
<el-form-item :label="$t('commons.table.createdAt')">
{{ dateFromat(0, 0, item.createdAt) }}
</el-form-item>
</el-form>
</el-card>
</el-col>
</el-row>
<el-dialog
@close="search"
v-model="backupVisiable"
:destroy-on-close="true"
:title="$t('setting.backupAccount')"
width="30%"
>
<div v-loading="loading">
<el-form ref="formRef" label-position="left" :model="form" label-width="160px">
<el-form-item :label="$t('commons.table.type')" prop="type" :rules="Rules.requiredSelect">
<el-select style="width: 100%" v-model="form.type" :disabled="operation === 'edit'">
<el-option
v-for="item in typeOptions"
:key="item.label"
:value="item.value"
:label="item.label"
/>
</el-select>
</el-form-item>
<el-form-item
v-if="form.type === 'LOCAL'"
:label="$t('setting.currentPath')"
prop="varsJson['dir']"
:rules="Rules.requiredInput"
>
<el-input v-model="form.varsJson['dir']">
<template #append>
<FileList @choose="loadDir" :dir="true"></FileList>
</template>
</el-input>
</el-form-item>
<el-form-item
v-if="hasBucket(form.type) && operation !== 'edit'"
label="Access Key ID"
prop="varsJson.accessKey"
:rules="Rules.requiredInput"
>
<el-input v-model="form.varsJson['accessKey']" />
</el-form-item>
<el-form-item
v-if="hasBucket(form.type)"
label="Access Key Secret"
prop="credential"
:rules="Rules.requiredInput"
>
<el-input show-password v-model="form.credential" />
</el-form-item>
<el-form-item
v-if="form.type === 'S3'"
label="Region"
prop="varsJson.region"
:rules="Rules.requiredInput"
>
<el-input v-model="form.varsJson['region']" />
</el-form-item>
<el-form-item
v-if="hasBucket(form.type)"
label="Endpoint"
prop="varsJson.endpoint"
:rules="Rules.requiredInput"
>
<el-input v-model="form.varsJson['endpoint']" />
</el-form-item>
<el-form-item
v-if="form.type !== '' && hasBucket(form.type)"
label="Bucket"
prop="bucket"
:rules="Rules.requiredSelect"
>
<el-select style="width: 80%" v-model="form.bucket">
<el-option v-for="item in buckets" :key="item" :value="item" />
</el-select>
<el-button style="width: 20%" plain @click="getBuckets">
{{ $t('setting.loadBucket') }}
</el-button>
</el-form-item>
<div v-if="form.type === 'SFTP'">
<el-form-item
:label="$t('setting.address')"
prop="varsJson.address"
:rules="Rules.requiredInput"
>
<el-input v-model="form.varsJson['address']" />
</el-form-item>
<el-form-item :label="$t('setting.port')" prop="varsJson.port" :rules="[Rules.number]">
<el-input-number :min="0" :max="65535" v-model.number="form.varsJson['port']" />
</el-form-item>
<el-form-item
:label="$t('setting.username')"
prop="varsJson.username"
:rules="[Rules.requiredInput]"
>
<el-input v-model="form.varsJson['username']" />
</el-form-item>
<el-form-item :label="$t('setting.password')" prop="credential" :rules="[Rules.requiredInput]">
<el-input type="password" show-password v-model="form.credential" />
</el-form-item>
<el-form-item :label="$t('setting.path')" prop="bucket">
<el-input v-model="form.bucket" />
</el-form-item>
</div>
</el-form>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="backupVisiable = false">{{ $t('commons.button.cancel') }}</el-button>
<el-button type="primary" @click="onSubmit(formRef)">
{{ $t('commons.button.confirm') }}
</el-button>
</span>
</template>
</el-dialog>
</el-card>
</template>
<script setup lang="ts">
import { dateFromat } from '@/utils/util';
import { onMounted, reactive, ref } from 'vue';
import { loadBackupName } from '@/views/setting/helper';
import { getBackupList, addBackup, editBackup, listBucket, deleteBackup } from '@/api/modules/backup';
import { Backup } from '@/api/interface/backup';
import i18n from '@/lang';
import { Rules } from '@/global/form-rules';
import { ElForm, ElMessage } from 'element-plus';
import { useDeleteData } from '@/hooks/use-delete-data';
import FileList from '@/components/file-list/index.vue';
const data = ref();
const selects = ref<any>([]);
const backupVisiable = ref<boolean>(false);
const operation = ref<string>('create');
const loading = ref(false);
const form = reactive({
id: 0,
type: 'LOCAL',
bucket: '',
credential: '',
vars: '',
varsJson: {},
});
type FormInstance = InstanceType<typeof ElForm>;
const formRef = ref<FormInstance>();
const typeOptions = ref();
const buckets = ref();
const search = async () => {
const res = await getBackupList();
data.value = res.data;
for (const bac of data.value) {
bac.varsJson = JSON.parse(bac.vars);
}
};
const onCreate = () => {
loadOption();
if (!typeOptions.value || typeOptions.value.length === 0) {
ElMessage.info(i18n.global.t('setting.noTypeForCreate'));
return;
}
operation.value = 'create';
form.id = 0;
form.type = typeOptions.value[0].value;
form.bucket = '';
form.credential = '';
form.vars = '';
form.varsJson = {};
backupVisiable.value = true;
};
const onBatchDelete = async (row: Backup.BackupInfo | null) => {
let ids: Array<number> = [];
if (row === null) {
selects.value.forEach((item: Backup.BackupInfo) => {
ids.push(item.id);
});
} else {
ids.push(row.id);
}
await useDeleteData(deleteBackup, { ids: ids }, 'commons.msg.delete');
search();
restForm();
};
const onEdit = (row: Backup.BackupInfo) => {
typeOptions.value = [
{ label: i18n.global.t('setting.serverDisk'), value: 'LOCAL' },
{ label: i18n.global.t('setting.OSS'), value: 'OSS' },
{ label: i18n.global.t('setting.S3'), value: 'S3' },
{ label: 'SFTP', value: 'SFTP' },
{ label: 'MinIO', value: 'MINIO' },
];
restForm();
form.id = row.id;
form.type = row.type;
form.bucket = row.bucket;
form.varsJson = JSON.parse(row.vars);
operation.value = 'edit';
backupVisiable.value = true;
};
const onSubmit = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(async (valid) => {
if (!valid) return;
form.vars = JSON.stringify(form.varsJson);
if (form.id !== 0 && operation.value === 'edit') {
await editBackup(form);
} else if (form.id === 0 && operation.value === 'create') {
await addBackup(form);
} else {
ElMessage.success(i18n.global.t('commons.msg.notSupportOperation'));
return;
}
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
restForm();
search();
backupVisiable.value = false;
});
};
function hasBucket(val: string) {
return val === 'OSS' || val === 'S3' || val === 'MINIO';
}
function restForm() {
if (formRef.value) {
formRef.value.resetFields();
}
}
const getBuckets = async () => {
loading.value = true;
listBucket({
type: form.type,
vars: JSON.stringify(form.varsJson),
credential: form.credential,
})
.then((res) => {
loading.value = true;
buckets.value = res.data;
})
.finally(() => {
buckets.value = [];
loading.value = false;
});
};
const loadDir = async (path: string) => {
form.varsJson['dir'] = path;
};
const loadOption = () => {
let options = [
{ label: i18n.global.t('setting.serverDisk'), value: 'LOCAL' },
{ label: i18n.global.t('setting.OSS'), value: 'OSS' },
{ label: i18n.global.t('setting.S3'), value: 'S3' },
{ label: 'SFTP', value: 'SFTP' },
{ label: 'MinIO', value: 'MINIO' },
];
for (const item of data.value) {
for (let i = 0; i < options.length; i++) {
if (item.type === options[i].value) {
options.splice(i, 1);
}
}
}
typeOptions.value = options;
};
const loadIconName = (type: string) => {
switch (type) {
case 'OSS':
return 'p-oss';
break;
case 'S3':
return 'p-aws';
break;
case 'SFTP':
return 'p-SFTP';
break;
case 'MINIO':
return 'p-minio';
break;
case 'LOCAL':
return 'p-file-folder';
break;
}
};
onMounted(() => {
search();
});
</script>