mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-09-22 16:00:51 +00:00
feat: 拆分备份账号代码 (#3454)
This commit is contained in:
@@ -1239,6 +1239,28 @@ const message = {
|
||||
'Please click on the "Acquire" button, then login to OneDrive and copy the content after "code" in the redirected link. Paste it into this input box. For specific instructions, please refer to the official documentation.',
|
||||
loadCode: 'Acquire',
|
||||
COS: 'Tencent COS',
|
||||
ap_beijing_1: 'Beijing Zone 1',
|
||||
ap_beijing: 'Beijing',
|
||||
ap_nanjing: 'Nanjing',
|
||||
ap_shanghai: 'Shanghai',
|
||||
ap_guangzhou: 'Guangzhou',
|
||||
ap_chengdu: 'Chengdu',
|
||||
ap_chongqing: 'Chongqing',
|
||||
ap_shenzhen_fsi: 'Shenzhen Financial',
|
||||
ap_shanghai_fsi: 'Shanghai Financial',
|
||||
ap_beijing_fsi: 'Beijing Financial',
|
||||
ap_hongkong: 'Hong Kong, China',
|
||||
ap_singapore: 'Singapore',
|
||||
ap_mumbai: 'Mumbai',
|
||||
ap_jakarta: 'Jakarta',
|
||||
ap_seoul: 'Seoul',
|
||||
ap_bangkok: 'Bangkok',
|
||||
ap_tokyo: 'Tokyo',
|
||||
na_siliconvalley: 'Silicon Valley (US West)',
|
||||
na_ashburn: 'Ashburn (US East)',
|
||||
na_toronto: 'Toronto',
|
||||
sa_saopaulo: 'Sao Paulo',
|
||||
eu_frankfurt: 'Frankfurt',
|
||||
KODO: 'Qiniu Kodo',
|
||||
scType: ' Storage type',
|
||||
typeStandard: 'Standard',
|
||||
@@ -1253,7 +1275,6 @@ const message = {
|
||||
scDeep_Archive: 'Durable cold storage is suitable for business scenarios with extremely low access frequency.',
|
||||
archiveHelper:
|
||||
'Archival storage files cannot be downloaded directly and must first be restored through the corresponding cloud service provider`s website. Please use with caution!',
|
||||
domainHelper: 'The accelerated domain name must contain http:// or https://',
|
||||
backupAlert:
|
||||
"In theory, as long as the cloud provider is compatible with the S3 protocol, existing Amazon S3 cloud storage can be used for backup. For specific configurations, please refer to the <a target=“_blank” href='https://1panel.cn/docs/user_manual/settings/#3'>official documentation.</a> ",
|
||||
domain: 'Accelerate domain',
|
||||
|
||||
@@ -1165,6 +1165,28 @@ const message = {
|
||||
'請點擊獲取按鈕,然後登錄 OneDrive 復製跳轉鏈接中 code 後面的內容,粘貼到該輸入框中,具體操作可參考官方文檔。',
|
||||
loadCode: '獲取',
|
||||
COS: '騰訊雲 COS',
|
||||
ap_beijing_1: '北京一區',
|
||||
ap_beijing: '北京',
|
||||
ap_nanjing: '南京',
|
||||
ap_shanghai: '上海',
|
||||
ap_guangzhou: '廣州',
|
||||
ap_chengdu: '成都',
|
||||
ap_chongqing: '重慶',
|
||||
ap_shenzhen_fsi: '深圳金融',
|
||||
ap_shanghai_fsi: '上海金融',
|
||||
ap_beijing_fsi: '北京金融',
|
||||
ap_hongkong: '中國香港',
|
||||
ap_singapore: '新加坡',
|
||||
ap_mumbai: '孟買',
|
||||
ap_jakarta: '雅加達',
|
||||
ap_seoul: '首爾',
|
||||
ap_bangkok: '曼谷',
|
||||
ap_tokyo: '東京',
|
||||
na_siliconvalley: '硅谷(美西)',
|
||||
na_ashburn: '弗吉尼亞(美東)',
|
||||
na_toronto: '多倫多',
|
||||
sa_saopaulo: '聖保羅',
|
||||
eu_frankfurt: '法蘭克福',
|
||||
KODO: '七牛雲 Kodo',
|
||||
scType: '存儲類型',
|
||||
typeStandard: '標準存儲',
|
||||
@@ -1176,7 +1198,6 @@ const message = {
|
||||
scArchive: '歸檔存儲,適用於極低訪問頻率(例如半年訪問1次)的業務場景。',
|
||||
scDeep_Archive: '深度歸檔存儲,適用於極低訪問頻率(例如1年訪問1~2次)的業務場景。',
|
||||
archiveHelper: '歸檔存儲的文件無法直接下載,需要先在對應的雲服務商網站進行恢復操作,請謹慎使用!',
|
||||
domainHelper: '加速域名必須包含 http:// 或者 https://',
|
||||
backupAlert:
|
||||
"理論上只要雲廠商兼容 S3 協議,就可以用現有的亞馬遜 S3 雲存儲來備份,具體配置參考 <a target=「_blank」 href='https://1panel.cn/docs/user_manual/settings/#3'>官方文檔</a> ",
|
||||
domain: '加速域名',
|
||||
|
||||
@@ -1166,6 +1166,28 @@ const message = {
|
||||
'请点击获取按钮,然后登录 OneDrive 复制跳转链接中 code 后面的内容,粘贴到该输入框中,具体操作可参考官方文档。',
|
||||
loadCode: '获取',
|
||||
COS: '腾讯云 COS',
|
||||
ap_beijing_1: '北京一区',
|
||||
ap_beijing: '北京',
|
||||
ap_nanjing: '南京',
|
||||
ap_shanghai: '上海',
|
||||
ap_guangzhou: '广州',
|
||||
ap_chengdu: '成都',
|
||||
ap_chongqing: '重庆',
|
||||
ap_shenzhen_fsi: '深圳金融',
|
||||
ap_shanghai_fsi: '上海金融',
|
||||
ap_beijing_fsi: '北京金融',
|
||||
ap_hongkong: '中国香港',
|
||||
ap_singapore: '新加坡',
|
||||
ap_mumbai: '孟买',
|
||||
ap_jakarta: '雅加达',
|
||||
ap_seoul: '首尔',
|
||||
ap_bangkok: '曼谷',
|
||||
ap_tokyo: '东京',
|
||||
na_siliconvalley: '硅谷(美西)',
|
||||
na_ashburn: '弗吉尼亚(美东)',
|
||||
na_toronto: '多伦多',
|
||||
sa_saopaulo: '圣保罗',
|
||||
eu_frankfurt: '法兰克福',
|
||||
KODO: '七牛云 Kodo',
|
||||
scType: '存储类型',
|
||||
typeStandard: '标准存储',
|
||||
@@ -1177,7 +1199,6 @@ const message = {
|
||||
scArchive: '归档存储,适用于极低访问频率(例如半年访问1次)的业务场景。',
|
||||
scDeep_Archive: '深度归档存储,适用于极低访问频率(例如1年访问1~2次)的业务场景。',
|
||||
archiveHelper: '归档存储的文件无法直接下载,需要先在对应的云服务商网站进行恢复操作,请谨慎使用!',
|
||||
domainHelper: '加速域名必须包含 http:// 或者 https://',
|
||||
backupAlert:
|
||||
"理论上只要云厂商兼容 S3 协议,就可以用现有的亚马逊 S3 云存储来备份,具体配置参考 <a target=“_blank” href='https://1panel.cn/docs/user_manual/settings/#3'>官方文档</a> ",
|
||||
domain: '加速域名',
|
||||
|
||||
@@ -370,6 +370,19 @@ export function transTimeUnit(val: string): any {
|
||||
return val + i18n.global.t('commons.units.second');
|
||||
}
|
||||
|
||||
export function splitHttp(url: string) {
|
||||
if (url.indexOf('https://') != -1) {
|
||||
return { proto: 'https', url: url.replaceAll('https://', '') };
|
||||
}
|
||||
if (url.indexOf('http://') != -1) {
|
||||
return { proto: 'http', url: url.replaceAll('http://', '') };
|
||||
}
|
||||
return { proto: '', url: url };
|
||||
}
|
||||
export function spliceHttp(proto: string, url: string) {
|
||||
return proto + '://' + url.replaceAll('https://', '').replaceAll('http://', '');
|
||||
}
|
||||
|
||||
export function getAge(d1: string): string {
|
||||
const dateBegin = new Date(d1);
|
||||
const dateEnd = new Date();
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-drawer v-model="drawerVisible" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="title + $t('setting.backupAccount')" :back="handleClose" />
|
||||
</template>
|
||||
<el-form @submit.prevent ref="formRef" v-loading="loading" label-position="top" :model="cosData.rowData">
|
||||
<el-row type="flex" justify="center">
|
||||
<el-col :span="22">
|
||||
<el-form-item :label="$t('commons.table.type')" prop="type" :rules="Rules.requiredSelect">
|
||||
<el-tag>{{ $t('setting.' + cosData.rowData!.type) }}</el-tag>
|
||||
</el-form-item>
|
||||
<el-form-item label="Access Key ID" prop="accessKey" :rules="Rules.requiredInput">
|
||||
<el-input v-model.trim="cosData.rowData!.accessKey" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Secret Key" prop="credential" :rules="Rules.requiredInput">
|
||||
<el-input show-password clearable v-model.trim="cosData.rowData!.credential" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Region" prop="varsJson.region" :rules="Rules.requiredInput">
|
||||
<el-checkbox v-model="regionInput" :label="$t('container.input')" />
|
||||
<el-select
|
||||
v-if="!regionInput"
|
||||
v-model="cosData.rowData!.varsJson['region']"
|
||||
filterable
|
||||
clearable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in cities"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
>
|
||||
<span style="float: left">{{ item.label }}</span>
|
||||
<span class="option-help">
|
||||
{{ item.value }}
|
||||
</span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-input v-else v-model.trim="cosData.rowData!.varsJson['region']" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Endpoint" prop="varsJson.endpointItem" :rules="Rules.requiredInput">
|
||||
<el-input v-model.trim="cosData.rowData!.varsJson['endpointItem']">
|
||||
<template #prepend>
|
||||
<el-select v-model.trim="endpointProto" style="width: 100px">
|
||||
<el-option label="http" value="http" />
|
||||
<el-option label="https" value="https" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="Bucket" prop="bucket">
|
||||
<el-select
|
||||
@change="errBuckets = false"
|
||||
style="width: 80%"
|
||||
v-model="cosData.rowData!.bucket"
|
||||
>
|
||||
<el-option v-for="item in buckets" :key="item" :value="item" />
|
||||
</el-select>
|
||||
<el-button style="width: 20%" plain @click="getBuckets(formRef)">
|
||||
{{ $t('setting.loadBucket') }}
|
||||
</el-button>
|
||||
<span v-if="errBuckets" class="input-error">{{ $t('commons.rule.requiredSelect') }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('setting.scType')"
|
||||
prop="varsJson.scType"
|
||||
:rules="[Rules.requiredSelect]"
|
||||
>
|
||||
<el-select v-model="cosData.rowData!.varsJson['scType']">
|
||||
<el-option value="Standard" :label="$t('setting.scStandard')" />
|
||||
<el-option value="Standard_IA" :label="$t('setting.scStandard_IA')" />
|
||||
<el-option value="Archive" :label="$t('setting.scArchive')" />
|
||||
<el-option value="Deep_Archive" :label="$t('setting.scDeep_Archive')" />
|
||||
</el-select>
|
||||
<el-alert
|
||||
v-if="cosData.rowData!.varsJson['scType'] === 'Archive' || cosData.rowData!.varsJson['scType'] === 'Deep_Archive'"
|
||||
style="margin-top: 10px"
|
||||
:closable="false"
|
||||
type="warning"
|
||||
:title="$t('setting.archiveHelper')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('setting.backupDir')" prop="backupPath">
|
||||
<el-input clearable v-model.trim="cosData.rowData!.backupPath" placeholder="/1panel" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button :disabled="loading" @click="handleClose">
|
||||
{{ $t('commons.button.cancel') }}
|
||||
</el-button>
|
||||
<el-button :disabled="loading" type="primary" @click="onSubmit(formRef)">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import i18n from '@/lang';
|
||||
import { ElForm } from 'element-plus';
|
||||
import { Backup } from '@/api/interface/backup';
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { addBackup, editBackup, listBucket } from '@/api/modules/setting';
|
||||
import { deepCopy, spliceHttp, splitHttp } from '@/utils/util';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
|
||||
const loading = ref(false);
|
||||
type FormInstance = InstanceType<typeof ElForm>;
|
||||
const formRef = ref<FormInstance>();
|
||||
const buckets = ref();
|
||||
const regionInput = ref();
|
||||
const errBuckets = ref();
|
||||
|
||||
const endpointProto = ref('http');
|
||||
const emit = defineEmits(['search']);
|
||||
|
||||
const cities = [
|
||||
{ value: 'ap-beijing-1', label: i18n.global.t('setting.ap_beijing_1') },
|
||||
{ value: 'ap-beijing', label: i18n.global.t('setting.ap_beijing') },
|
||||
{ value: 'ap-nanjing', label: i18n.global.t('setting.ap_nanjing') },
|
||||
{ value: 'ap-shanghai', label: i18n.global.t('setting.ap_shanghai') },
|
||||
{ value: 'ap-guangzhou', label: i18n.global.t('setting.ap_guangzhou') },
|
||||
{ value: 'ap-chengdu', label: i18n.global.t('setting.ap_chengdu') },
|
||||
{ value: 'ap-chongqing', label: i18n.global.t('setting.ap_chongqing') },
|
||||
{ value: 'ap-shenzhen_fsi', label: i18n.global.t('setting.ap_shenzhen_fsi') },
|
||||
{ value: 'ap-shanghai_fsi', label: i18n.global.t('setting.ap_shanghai_fsi') },
|
||||
{ value: 'ap-beijing_fsi', label: i18n.global.t('setting.ap_beijing_fsi') },
|
||||
{ value: 'ap-hongkong', label: i18n.global.t('setting.ap_hongkong') },
|
||||
{ value: 'ap-singapore', label: i18n.global.t('setting.ap_singapore') },
|
||||
{ value: 'ap-mumbai', label: i18n.global.t('setting.ap_mumbai') },
|
||||
{ value: 'ap-jakarta', label: i18n.global.t('setting.ap_jakarta') },
|
||||
{ value: 'ap-seoul', label: i18n.global.t('setting.ap_seoul') },
|
||||
{ value: 'ap-bangkok', label: i18n.global.t('setting.ap_bangkok') },
|
||||
{ value: 'ap-tokyo', label: i18n.global.t('setting.ap_tokyo') },
|
||||
{ value: 'na-siliconvalley', label: i18n.global.t('setting.na_siliconvalley') },
|
||||
{ value: 'na-ashburn', label: i18n.global.t('setting.na_ashburn') },
|
||||
{ value: 'na-toronto', label: i18n.global.t('setting.na_toronto') },
|
||||
{ value: 'sa-saopaulo', label: i18n.global.t('setting.sa_saopaulo') },
|
||||
{ value: 'eu-frankfurt', label: i18n.global.t('setting.eu_frankfurt') },
|
||||
];
|
||||
|
||||
interface DialogProps {
|
||||
title: string;
|
||||
rowData?: Backup.BackupInfo;
|
||||
}
|
||||
const title = ref<string>('');
|
||||
const drawerVisible = ref(false);
|
||||
const cosData = ref<DialogProps>({
|
||||
title: '',
|
||||
});
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
buckets.value = [];
|
||||
cosData.value = params;
|
||||
if (params.title === 'create' || (params.title === 'edit' && !cosData.value.rowData.varsJson['scType'])) {
|
||||
cosData.value.rowData.varsJson['scType'] = 'Standard';
|
||||
}
|
||||
if (cosData.value.title === 'edit') {
|
||||
let httpItem = splitHttp(cosData.value.rowData!.varsJson['endpoint']);
|
||||
cosData.value.rowData!.varsJson['endpointItem'] = httpItem.url;
|
||||
endpointProto.value = httpItem.proto;
|
||||
}
|
||||
title.value = i18n.global.t('commons.button.' + cosData.value.title);
|
||||
drawerVisible.value = true;
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
};
|
||||
|
||||
const getBuckets = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
loading.value = true;
|
||||
let item = deepCopy(cosData.value.rowData!.varsJson);
|
||||
item['endpoint'] = spliceHttp(endpointProto.value, cosData.value.rowData!.varsJson['endpointItem']);
|
||||
listBucket({
|
||||
type: cosData.value.rowData!.type,
|
||||
vars: JSON.stringify(item),
|
||||
accessKey: cosData.value.rowData!.accessKey,
|
||||
credential: cosData.value.rowData!.credential,
|
||||
})
|
||||
.then((res) => {
|
||||
loading.value = false;
|
||||
buckets.value = res.data;
|
||||
})
|
||||
.catch(() => {
|
||||
buckets.value = [];
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!cosData.value.rowData.bucket) {
|
||||
errBuckets.value = true;
|
||||
return;
|
||||
}
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
if (!cosData.value.rowData) return;
|
||||
cosData.value.rowData!.varsJson['endpoint'] = spliceHttp(
|
||||
endpointProto.value,
|
||||
cosData.value.rowData!.varsJson['endpointItem'],
|
||||
);
|
||||
cosData.value.rowData.vars = JSON.stringify(cosData.value.rowData!.varsJson);
|
||||
loading.value = true;
|
||||
if (cosData.value.title === 'create') {
|
||||
await addBackup(cosData.value.rowData)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
await editBackup(cosData.value.rowData)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.option-help {
|
||||
float: right;
|
||||
font-size: 12px;
|
||||
word-break: break-all;
|
||||
color: #8f959e;
|
||||
}
|
||||
</style>
|
||||
@@ -2,7 +2,7 @@
|
||||
<div>
|
||||
<LayoutContent :title="$t('commons.button.backup')">
|
||||
<template #main>
|
||||
<el-form label-position="left" label-width="130px" :v-key="reflash">
|
||||
<el-form label-width="130px" :v-key="refresh">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<div>
|
||||
@@ -414,8 +414,15 @@
|
||||
</template>
|
||||
</LayoutContent>
|
||||
|
||||
<s3Dialog ref="s3Ref" @search="search" />
|
||||
<ossDialog ref="ossRef" @search="search" />
|
||||
<cosDialog ref="cosRef" @search="search" />
|
||||
<oneDriveDialog ref="oneDriveRef" @search="search" />
|
||||
<kodoDialog ref="kodoRef" @search="search" />
|
||||
<minioDialog ref="minioRef" @search="search" />
|
||||
<sftpDialog ref="sftpRef" @search="search" />
|
||||
<webDavDialog ref="webDavRef" @search="search" />
|
||||
<OpDialog ref="opRef" @search="search" />
|
||||
<DialogOperate ref="dialogRef" @search="search" />
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
@@ -423,14 +430,31 @@ import { dateFormat } from '@/utils/util';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import OpDialog from '@/components/del-dialog/index.vue';
|
||||
import { getBackupList, deleteBackup } from '@/api/modules/setting';
|
||||
import DialogOperate from '@/views/setting/backup-account/operate/index.vue';
|
||||
import s3Dialog from '@/views/setting/backup-account/s3/index.vue';
|
||||
import ossDialog from '@/views/setting/backup-account/oss/index.vue';
|
||||
import cosDialog from '@/views/setting/backup-account/cos/index.vue';
|
||||
import oneDriveDialog from '@/views/setting/backup-account/onedrive/index.vue';
|
||||
import kodoDialog from '@/views/setting/backup-account/kodo/index.vue';
|
||||
import minioDialog from '@/views/setting/backup-account/minio/index.vue';
|
||||
import sftpDialog from '@/views/setting/backup-account/sftp/index.vue';
|
||||
import webDavDialog from '@/views/setting/backup-account/webdav/index.vue';
|
||||
import { Backup } from '@/api/interface/backup';
|
||||
import { ElForm } from 'element-plus';
|
||||
import i18n from '@/lang';
|
||||
|
||||
const data = ref();
|
||||
const opRef = ref();
|
||||
const reflash = ref(false);
|
||||
const refresh = ref(false);
|
||||
|
||||
const s3Ref = ref();
|
||||
const ossRef = ref();
|
||||
const cosRef = ref();
|
||||
const oneDriveRef = ref();
|
||||
const kodoRef = ref();
|
||||
const minioRef = ref();
|
||||
const sftpRef = ref();
|
||||
const webDavRef = ref();
|
||||
|
||||
const localData = ref<Backup.BackupInfo>({
|
||||
id: 0,
|
||||
type: 'LOCAL',
|
||||
@@ -453,7 +477,6 @@ const ossData = ref<Backup.BackupInfo>({
|
||||
backupPath: '',
|
||||
vars: '',
|
||||
varsJson: {
|
||||
region: '',
|
||||
endpoint: '',
|
||||
scType: 'Standard',
|
||||
},
|
||||
@@ -540,6 +563,7 @@ const cosData = ref<Backup.BackupInfo>({
|
||||
varsJson: {
|
||||
region: '',
|
||||
scType: 'Standard',
|
||||
endpoint: '',
|
||||
},
|
||||
createdAt: new Date(),
|
||||
});
|
||||
@@ -609,7 +633,6 @@ const onDelete = async (row: Backup.BackupInfo) => {
|
||||
});
|
||||
};
|
||||
|
||||
const dialogRef = ref();
|
||||
const onOpenDialog = async (
|
||||
title: string,
|
||||
accountType: string,
|
||||
@@ -623,7 +646,32 @@ const onOpenDialog = async (
|
||||
title,
|
||||
rowData: { ...rowData },
|
||||
};
|
||||
dialogRef.value!.acceptParams(params);
|
||||
switch (accountType) {
|
||||
case 'S3':
|
||||
s3Ref.value.acceptParams(params);
|
||||
return;
|
||||
case 'OSS':
|
||||
ossRef.value.acceptParams(params);
|
||||
return;
|
||||
case 'COS':
|
||||
cosRef.value.acceptParams(params);
|
||||
return;
|
||||
case 'OneDrive':
|
||||
oneDriveRef.value.acceptParams(params);
|
||||
return;
|
||||
case 'KODO':
|
||||
kodoRef.value.acceptParams(params);
|
||||
return;
|
||||
case 'MINIO':
|
||||
minioRef.value.acceptParams(params);
|
||||
return;
|
||||
case 'SFTP':
|
||||
sftpRef.value.acceptParams(params);
|
||||
return;
|
||||
case 'WebDAV':
|
||||
webDavRef.value.acceptParams(params);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-drawer v-model="drawerVisible" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="title + $t('setting.backupAccount')" :back="handleClose" />
|
||||
</template>
|
||||
<el-form @submit.prevent ref="formRef" v-loading="loading" label-position="top" :model="kodoData.rowData">
|
||||
<el-row type="flex" justify="center">
|
||||
<el-col :span="22">
|
||||
<el-form-item :label="$t('commons.table.type')" prop="type" :rules="Rules.requiredSelect">
|
||||
<el-tag>{{ $t('setting.' + kodoData.rowData!.type) }}</el-tag>
|
||||
</el-form-item>
|
||||
<el-form-item label="Access Key ID" prop="accessKey" :rules="Rules.requiredInput">
|
||||
<el-input v-model.trim="kodoData.rowData!.accessKey" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Secret Key" prop="credential" :rules="Rules.requiredInput">
|
||||
<el-input show-password clearable v-model.trim="kodoData.rowData!.credential" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('setting.domain')"
|
||||
prop="varsJson.domainItem"
|
||||
:rules="Rules.requiredInput"
|
||||
>
|
||||
<el-input v-model="kodoData.rowData!.varsJson['domainItem']">
|
||||
<template #prepend>
|
||||
<el-select v-model.trim="domainProto" style="width: 100px">
|
||||
<el-option label="http" value="http" />
|
||||
<el-option label="https" value="https" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="Bucket" prop="bucket">
|
||||
<el-select
|
||||
@change="errBuckets = false"
|
||||
style="width: 80%"
|
||||
v-model="kodoData.rowData!.bucket"
|
||||
>
|
||||
<el-option v-for="item in buckets" :key="item" :value="item" />
|
||||
</el-select>
|
||||
<el-button style="width: 20%" plain @click="getBuckets(formRef)">
|
||||
{{ $t('setting.loadBucket') }}
|
||||
</el-button>
|
||||
<span v-if="errBuckets" class="input-error">{{ $t('commons.rule.requiredSelect') }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('setting.backupDir')" prop="backupPath">
|
||||
<el-input clearable v-model.trim="kodoData.rowData!.backupPath" placeholder="/1panel" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button :disabled="loading" @click="handleClose">
|
||||
{{ $t('commons.button.cancel') }}
|
||||
</el-button>
|
||||
<el-button :disabled="loading" type="primary" @click="onSubmit(formRef)">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import i18n from '@/lang';
|
||||
import { ElForm } from 'element-plus';
|
||||
import { Backup } from '@/api/interface/backup';
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { addBackup, editBackup, listBucket } from '@/api/modules/setting';
|
||||
import { deepCopy, spliceHttp, splitHttp } from '@/utils/util';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
|
||||
const loading = ref(false);
|
||||
type FormInstance = InstanceType<typeof ElForm>;
|
||||
const formRef = ref<FormInstance>();
|
||||
const buckets = ref();
|
||||
const errBuckets = ref();
|
||||
|
||||
const domainProto = ref('http');
|
||||
const emit = defineEmits(['search']);
|
||||
|
||||
interface DialogProps {
|
||||
title: string;
|
||||
rowData?: Backup.BackupInfo;
|
||||
}
|
||||
const title = ref<string>('');
|
||||
const drawerVisible = ref(false);
|
||||
const kodoData = ref<DialogProps>({
|
||||
title: '',
|
||||
});
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
buckets.value = [];
|
||||
kodoData.value = params;
|
||||
if (kodoData.value.title === 'edit') {
|
||||
let httpItem = splitHttp(kodoData.value.rowData!.varsJson['domain']);
|
||||
kodoData.value.rowData!.varsJson['domainItem'] = httpItem.url;
|
||||
domainProto.value = httpItem.proto;
|
||||
}
|
||||
title.value = i18n.global.t('commons.button.' + kodoData.value.title);
|
||||
drawerVisible.value = true;
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
};
|
||||
|
||||
const getBuckets = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
loading.value = true;
|
||||
let item = deepCopy(kodoData.value.rowData!.varsJson);
|
||||
item['domain'] = spliceHttp(domainProto.value, kodoData.value.rowData!.varsJson['domainItem']);
|
||||
listBucket({
|
||||
type: kodoData.value.rowData!.type,
|
||||
vars: JSON.stringify(item),
|
||||
accessKey: kodoData.value.rowData!.accessKey,
|
||||
credential: kodoData.value.rowData!.credential,
|
||||
})
|
||||
.then((res) => {
|
||||
loading.value = false;
|
||||
buckets.value = res.data;
|
||||
})
|
||||
.catch(() => {
|
||||
buckets.value = [];
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!kodoData.value.rowData.bucket) {
|
||||
errBuckets.value = true;
|
||||
return;
|
||||
}
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
if (!kodoData.value.rowData) return;
|
||||
kodoData.value.rowData!.varsJson['domain'] = spliceHttp(
|
||||
domainProto.value,
|
||||
kodoData.value.rowData!.varsJson['domainItem'],
|
||||
);
|
||||
kodoData.value.rowData.vars = JSON.stringify(kodoData.value.rowData!.varsJson);
|
||||
loading.value = true;
|
||||
if (kodoData.value.title === 'create') {
|
||||
await addBackup(kodoData.value.rowData)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
await editBackup(kodoData.value.rowData)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,178 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-drawer v-model="drawerVisible" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="title + $t('setting.backupAccount')" :back="handleClose" />
|
||||
</template>
|
||||
<el-form @submit.prevent ref="formRef" v-loading="loading" label-position="top" :model="minioData.rowData">
|
||||
<el-row type="flex" justify="center">
|
||||
<el-col :span="22">
|
||||
<el-form-item :label="$t('commons.table.type')" prop="type" :rules="Rules.requiredSelect">
|
||||
<el-tag>{{ $t('setting.' + minioData.rowData!.type) }}</el-tag>
|
||||
</el-form-item>
|
||||
<el-form-item label="Access Key ID" prop="accessKey" :rules="Rules.requiredInput">
|
||||
<el-input v-model.trim="minioData.rowData!.accessKey" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Secret Key" prop="credential" :rules="Rules.requiredInput">
|
||||
<el-input show-password clearable v-model.trim="minioData.rowData!.credential" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Endpoint" prop="varsJson.endpointItem" :rules="Rules.requiredInput">
|
||||
<el-input v-model="minioData.rowData!.varsJson['endpointItem']">
|
||||
<template #prepend>
|
||||
<el-select v-model.trim="endpointProto" style="width: 100px">
|
||||
<el-option label="http" value="http" />
|
||||
<el-option label="https" value="https" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="Bucket" prop="bucket">
|
||||
<el-select
|
||||
style="width: 80%"
|
||||
@change="errBuckets = false"
|
||||
v-model="minioData.rowData!.bucket"
|
||||
>
|
||||
<el-option v-for="item in buckets" :key="item" :value="item" />
|
||||
</el-select>
|
||||
<el-button style="width: 20%" plain @click="getBuckets(formRef)">
|
||||
{{ $t('setting.loadBucket') }}
|
||||
</el-button>
|
||||
<span v-if="errBuckets" class="input-error">{{ $t('commons.rule.requiredSelect') }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('setting.backupDir')" prop="backupPath">
|
||||
<el-input clearable v-model.trim="minioData.rowData!.backupPath" placeholder="/1panel" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button :disabled="loading" @click="handleClose">
|
||||
{{ $t('commons.button.cancel') }}
|
||||
</el-button>
|
||||
<el-button :disabled="loading" type="primary" @click="onSubmit(formRef)">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import i18n from '@/lang';
|
||||
import { ElForm } from 'element-plus';
|
||||
import { Backup } from '@/api/interface/backup';
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { addBackup, editBackup, listBucket } from '@/api/modules/setting';
|
||||
import { deepCopy, splitHttp, spliceHttp } from '@/utils/util';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
|
||||
const loading = ref(false);
|
||||
type FormInstance = InstanceType<typeof ElForm>;
|
||||
const formRef = ref<FormInstance>();
|
||||
const buckets = ref();
|
||||
const errBuckets = ref();
|
||||
|
||||
const endpointProto = ref('http');
|
||||
const emit = defineEmits(['search']);
|
||||
|
||||
interface DialogProps {
|
||||
title: string;
|
||||
rowData?: Backup.BackupInfo;
|
||||
}
|
||||
const title = ref<string>('');
|
||||
const drawerVisible = ref(false);
|
||||
const minioData = ref<DialogProps>({
|
||||
title: '',
|
||||
});
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
buckets.value = [];
|
||||
minioData.value = params;
|
||||
if (minioData.value.title === 'edit') {
|
||||
let httpItem = splitHttp(minioData.value.rowData!.varsJson['endpoint']);
|
||||
minioData.value.rowData!.varsJson['endpointItem'] = httpItem.url;
|
||||
endpointProto.value = httpItem.proto;
|
||||
}
|
||||
title.value = i18n.global.t('commons.button.' + minioData.value.title);
|
||||
drawerVisible.value = true;
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
};
|
||||
|
||||
const getBuckets = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
loading.value = true;
|
||||
let item = deepCopy(minioData.value.rowData!.varsJson);
|
||||
item['endpoint'] = spliceHttp(endpointProto.value, minioData.value.rowData!.varsJson['endpointItem']);
|
||||
item['endpointItem'] = undefined;
|
||||
listBucket({
|
||||
type: minioData.value.rowData!.type,
|
||||
vars: JSON.stringify(item),
|
||||
accessKey: minioData.value.rowData!.accessKey,
|
||||
credential: minioData.value.rowData!.credential,
|
||||
})
|
||||
.then((res) => {
|
||||
loading.value = false;
|
||||
buckets.value = res.data;
|
||||
})
|
||||
.catch(() => {
|
||||
buckets.value = [];
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!minioData.value.rowData.bucket) {
|
||||
errBuckets.value = true;
|
||||
return;
|
||||
}
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
if (!minioData.value.rowData) return;
|
||||
minioData.value.rowData!.varsJson['endpoint'] = spliceHttp(
|
||||
endpointProto.value,
|
||||
minioData.value.rowData!.varsJson['endpointItem'],
|
||||
);
|
||||
minioData.value.rowData!.varsJson['endpointItem'] = undefined;
|
||||
minioData.value.rowData.vars = JSON.stringify(minioData.value.rowData!.varsJson);
|
||||
loading.value = true;
|
||||
if (minioData.value.title === 'create') {
|
||||
await addBackup(minioData.value.rowData)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
await editBackup(minioData.value.rowData)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,175 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-drawer v-model="drawerVisible" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="title + $t('setting.backupAccount')" :back="handleClose" />
|
||||
</template>
|
||||
<el-form
|
||||
@submit.prevent
|
||||
ref="formRef"
|
||||
v-loading="loading"
|
||||
label-position="top"
|
||||
:model="onedriveData.rowData"
|
||||
>
|
||||
<el-row type="flex" justify="center">
|
||||
<el-col :span="22">
|
||||
<el-form-item :label="$t('commons.table.type')" prop="type" :rules="Rules.requiredSelect">
|
||||
<el-tag>{{ $t('setting.' + onedriveData.rowData!.type) }}</el-tag>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-checkbox
|
||||
disabled
|
||||
v-model="onedriveData.rowData!.varsJson['isCN']"
|
||||
:label="$t('setting.isCN')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('setting.code')" prop="varsJson.code" :rules="rules.driveCode">
|
||||
<div style="width: 100%">
|
||||
<el-input
|
||||
style="width: calc(100% - 80px)"
|
||||
:autosize="{ minRows: 3, maxRows: 15 }"
|
||||
type="textarea"
|
||||
clearable
|
||||
v-model.trim="onedriveData.rowData!.varsJson['code']"
|
||||
/>
|
||||
<el-button class="append-button" @click="jumpAzure">
|
||||
{{ $t('setting.loadCode') }}
|
||||
</el-button>
|
||||
</div>
|
||||
<span class="input-help">
|
||||
{{ $t('setting.codeHelper') }}
|
||||
<el-link
|
||||
style="font-size: 12px; margin-left: 5px"
|
||||
icon="Position"
|
||||
@click="toDoc()"
|
||||
type="primary"
|
||||
>
|
||||
{{ $t('firewall.quickJump') }}
|
||||
</el-link>
|
||||
</span>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('setting.backupDir')" prop="backupPath">
|
||||
<el-input clearable v-model.trim="onedriveData.rowData!.backupPath" placeholder="/1panel" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button :disabled="loading" @click="handleClose">
|
||||
{{ $t('commons.button.cancel') }}
|
||||
</el-button>
|
||||
<el-button :disabled="loading" type="primary" @click="onSubmit(formRef)">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import i18n from '@/lang';
|
||||
import { ElForm } from 'element-plus';
|
||||
import { Backup } from '@/api/interface/backup';
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { addBackup, editBackup, getOneDriveInfo } from '@/api/modules/setting';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
|
||||
const loading = ref(false);
|
||||
type FormInstance = InstanceType<typeof ElForm>;
|
||||
const formRef = ref<FormInstance>();
|
||||
|
||||
const rules = reactive({
|
||||
driveCode: [{ validator: checkDriveCode, required: true, trigger: 'blur' }],
|
||||
});
|
||||
function checkDriveCode(rule: any, value: any, callback: any) {
|
||||
const reg = /^[A-Za-z0-9_.-]+$/;
|
||||
if (!reg.test(value)) {
|
||||
return callback(new Error(i18n.global.t('setting.codeWarning')));
|
||||
}
|
||||
callback();
|
||||
}
|
||||
|
||||
const emit = defineEmits(['search']);
|
||||
|
||||
interface DialogProps {
|
||||
title: string;
|
||||
rowData?: Backup.BackupInfo;
|
||||
}
|
||||
const title = ref<string>('');
|
||||
const drawerVisible = ref(false);
|
||||
const onedriveData = ref<DialogProps>({
|
||||
title: '',
|
||||
});
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
onedriveData.value = params;
|
||||
title.value = i18n.global.t('commons.button.' + onedriveData.value.title);
|
||||
drawerVisible.value = true;
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
};
|
||||
const jumpAzure = async () => {
|
||||
const res = await getOneDriveInfo();
|
||||
let commonUrl = `response_type=code&client_id=${res.data}&redirect_uri=http://localhost/login/authorized&scope=offline_access+Files.ReadWrite.All+User.Read`;
|
||||
if (!onedriveData.value.rowData!.varsJson['isCN']) {
|
||||
window.open('https://login.microsoftonline.com/common/oauth2/v2.0/authorize?' + commonUrl, '_blank');
|
||||
} else {
|
||||
window.open('https://login.chinacloudapi.cn/common/oauth2/v2.0/authorize?' + commonUrl, '_blank');
|
||||
}
|
||||
};
|
||||
|
||||
const toDoc = () => {
|
||||
window.open('https://1panel.cn/docs/user_manual/settings/', '_blank', 'noopener,noreferrer');
|
||||
};
|
||||
|
||||
const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
if (!onedriveData.value.rowData) return;
|
||||
onedriveData.value.rowData.vars = JSON.stringify(onedriveData.value.rowData!.varsJson);
|
||||
loading.value = true;
|
||||
if (onedriveData.value.title === 'create') {
|
||||
await addBackup(onedriveData.value.rowData)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
await editBackup(onedriveData.value.rowData)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.append-button {
|
||||
width: 80px;
|
||||
background-color: var(--el-fill-color-light);
|
||||
color: var(--el-color-info);
|
||||
}
|
||||
</style>
|
||||
@@ -1,460 +0,0 @@
|
||||
<template>
|
||||
<div v-loading="loading">
|
||||
<el-drawer v-model="drawerVisible" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="title + $t('setting.backupAccount')" :back="handleClose" />
|
||||
</template>
|
||||
<el-form
|
||||
@submit.prevent
|
||||
ref="formRef"
|
||||
v-loading="loading"
|
||||
label-position="top"
|
||||
:model="dialogData.rowData"
|
||||
label-width="120px"
|
||||
>
|
||||
<el-row type="flex" justify="center">
|
||||
<el-col :span="22">
|
||||
<el-form-item :label="$t('commons.table.type')" prop="type" :rules="Rules.requiredSelect">
|
||||
<el-tag>{{ $t('setting.' + dialogData.rowData!.type) }}</el-tag>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="dialogData.rowData!.type === 'LOCAL'"
|
||||
:label="$t('setting.currentPath')"
|
||||
prop="varsJson['dir']"
|
||||
:rules="Rules.requiredInput"
|
||||
>
|
||||
<el-input v-model="dialogData.rowData!.varsJson['dir']">
|
||||
<template #prepend>
|
||||
<FileList @choose="loadDir" :dir="true"></FileList>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="hasBucket(dialogData.rowData!.type)"
|
||||
label="Access Key ID"
|
||||
prop="accessKey"
|
||||
:rules="Rules.requiredInput"
|
||||
>
|
||||
<el-input v-model.trim="dialogData.rowData!.accessKey" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="hasBucket(dialogData.rowData!.type)"
|
||||
label="Secret Key"
|
||||
prop="credential"
|
||||
:rules="Rules.requiredInput"
|
||||
>
|
||||
<el-input show-password clearable v-model.trim="dialogData.rowData!.credential" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="dialogData.rowData!.type === 'OneDrive'">
|
||||
<el-checkbox
|
||||
disabled
|
||||
v-model="dialogData.rowData!.varsJson['isCN']"
|
||||
:label="$t('setting.isCN')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="dialogData.rowData!.type === 'OneDrive'"
|
||||
:label="$t('setting.code')"
|
||||
prop="varsJson.code"
|
||||
:rules="rules.driveCode"
|
||||
>
|
||||
<div style="width: 100%">
|
||||
<el-input
|
||||
style="width: calc(100% - 80px)"
|
||||
:autosize="{ minRows: 3, maxRows: 15 }"
|
||||
type="textarea"
|
||||
clearable
|
||||
v-model.trim="dialogData.rowData!.varsJson['code']"
|
||||
/>
|
||||
<el-button class="append-button" @click="jumpAzure">
|
||||
{{ $t('setting.loadCode') }}
|
||||
</el-button>
|
||||
</div>
|
||||
<span class="input-help">
|
||||
{{ $t('setting.codeHelper') }}
|
||||
<el-link
|
||||
style="font-size: 12px; margin-left: 5px"
|
||||
icon="Position"
|
||||
@click="toDoc()"
|
||||
type="primary"
|
||||
>
|
||||
{{ $t('firewall.quickJump') }}
|
||||
</el-link>
|
||||
</span>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="dialogData.rowData!.type === 'S3' || dialogData.rowData!.type === 'COS'"
|
||||
label="Region"
|
||||
prop="varsJson.region"
|
||||
:rules="Rules.requiredInput"
|
||||
>
|
||||
<el-input v-model.trim="dialogData.rowData!.varsJson['region']" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="hasEndpoint(dialogData.rowData!.type)"
|
||||
label="Endpoint"
|
||||
prop="varsJson.endpoint"
|
||||
:rules="Rules.requiredInput"
|
||||
>
|
||||
<el-input v-model.trim="dialogData.rowData!.varsJson['endpoint']" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="dialogData.rowData!.type === 'KODO'"
|
||||
:label="$t('setting.domain')"
|
||||
prop="varsJson.domain"
|
||||
:rules="Rules.requiredInput"
|
||||
>
|
||||
<el-input v-model.trim="dialogData.rowData!.varsJson['domain']" />
|
||||
<span class="input-help">{{ $t('setting.domainHelper') }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="dialogData.rowData!.type === 'MINIO'"
|
||||
label="Endpoint"
|
||||
prop="varsJson.endpointItem"
|
||||
:rules="Rules.requiredInput"
|
||||
>
|
||||
<el-input v-model="dialogData.rowData!.varsJson['endpointItem']">
|
||||
<template #prepend>
|
||||
<el-select v-model.trim="endpoints" style="width: 80px">
|
||||
<el-option label="http" value="http" />
|
||||
<el-option label="https" value="https" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="dialogData.rowData!.type !== '' && hasBucket(dialogData.rowData!.type)"
|
||||
label="Bucket"
|
||||
prop="bucket"
|
||||
>
|
||||
<el-select
|
||||
style="width: 80%"
|
||||
@change="errBuckets = false"
|
||||
v-model="dialogData.rowData!.bucket"
|
||||
>
|
||||
<el-option v-for="item in buckets" :key="item" :value="item" />
|
||||
</el-select>
|
||||
<el-button style="width: 20%" plain @click="getBuckets(formRef)">
|
||||
{{ $t('setting.loadBucket') }}
|
||||
</el-button>
|
||||
<span v-if="errBuckets" class="input-error">{{ $t('commons.rule.requiredSelect') }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="dialogData.rowData!.type === 'COS'"
|
||||
:label="$t('setting.scType')"
|
||||
prop="varsJson.scType"
|
||||
:rules="[Rules.requiredSelect]"
|
||||
>
|
||||
<el-select v-model="dialogData.rowData!.varsJson['scType']">
|
||||
<el-option value="Standard" :label="$t('setting.scStandard')" />
|
||||
<el-option value="Standard_IA" :label="$t('setting.scStandard_IA')" />
|
||||
<el-option value="Archive" :label="$t('setting.scArchive')" />
|
||||
<el-option value="Deep_Archive" :label="$t('setting.scDeep_Archive')" />
|
||||
</el-select>
|
||||
<el-alert
|
||||
v-if="dialogData.rowData!.varsJson['scType'] === 'Archive' || dialogData.rowData!.varsJson['scType'] === 'Deep_Archive'"
|
||||
style="margin-top: 10px"
|
||||
:closable="false"
|
||||
type="warning"
|
||||
:title="$t('setting.archiveHelper')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="dialogData.rowData!.type === 'OSS'"
|
||||
:label="$t('setting.scType')"
|
||||
prop="varsJson.scType"
|
||||
:rules="[Rules.requiredSelect]"
|
||||
>
|
||||
<el-select v-model="dialogData.rowData!.varsJson['scType']">
|
||||
<el-option value="Standard" :label="$t('setting.scStandard')" />
|
||||
<el-option value="IA" :label="$t('setting.scStandard_IA')" />
|
||||
<el-option value="Archive" :label="$t('setting.scArchive')" />
|
||||
<el-option value="ColdArchive" :label="$t('setting.scDeep_Archive')" />
|
||||
</el-select>
|
||||
<el-alert
|
||||
v-if="dialogData.rowData!.varsJson['scType'] === 'Archive' || dialogData.rowData!.varsJson['scType'] === 'ColdArchive'"
|
||||
style="margin-top: 10px"
|
||||
:closable="false"
|
||||
type="warning"
|
||||
:title="$t('setting.archiveHelper')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="dialogData.rowData!.type === 'S3'"
|
||||
:label="$t('setting.scType')"
|
||||
prop="varsJson.scType"
|
||||
:rules="[Rules.requiredSelect]"
|
||||
>
|
||||
<el-select v-model="dialogData.rowData!.varsJson['scType']">
|
||||
<el-option value="STANDARD" :label="$t('setting.scStandard')" />
|
||||
<el-option value="STANDARD_IA" :label="$t('setting.scStandard_IA')" />
|
||||
<el-option value="GLACIER" :label="$t('setting.scArchive')" />
|
||||
<el-option value="DEEP_ARCHIVE" :label="$t('setting.scDeep_Archive')" />
|
||||
</el-select>
|
||||
<el-alert
|
||||
v-if="dialogData.rowData!.varsJson['scType'] === 'Archive' || dialogData.rowData!.varsJson['scType'] === 'ColdArchive'"
|
||||
style="margin-top: 10px"
|
||||
:closable="false"
|
||||
type="warning"
|
||||
:title="$t('setting.archiveHelper')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<div v-if="isSftpOrWebDAV(dialogData.rowData!.type)">
|
||||
<el-form-item
|
||||
v-if="dialogData.rowData!.type === 'SFTP'"
|
||||
:label="$t('setting.address')"
|
||||
prop="varsJson.address"
|
||||
:rules="Rules.host"
|
||||
>
|
||||
<el-input v-model.trim="dialogData.rowData!.varsJson['address']" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="dialogData.rowData!.type === 'WebDAV'"
|
||||
:label="$t('setting.address')"
|
||||
prop="varsJson.address"
|
||||
:rules="Rules.requiredInput"
|
||||
>
|
||||
<el-input v-model.trim="dialogData.rowData!.varsJson['address']" />
|
||||
<span class="input-help">http://172.16.10.111</span>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('commons.table.port')" prop="varsJson.port" :rules="[Rules.port]">
|
||||
<el-input-number
|
||||
:min="0"
|
||||
:max="65535"
|
||||
v-model.number="dialogData.rowData!.varsJson['port']"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('commons.login.username')"
|
||||
prop="accessKey"
|
||||
:rules="[Rules.requiredInput]"
|
||||
>
|
||||
<el-input v-model.trim="dialogData.rowData!.accessKey" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('commons.login.password')"
|
||||
prop="credential"
|
||||
:rules="[Rules.requiredInput]"
|
||||
>
|
||||
<el-input
|
||||
type="password"
|
||||
clearable
|
||||
show-password
|
||||
v-model.trim="dialogData.rowData!.credential"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('setting.path')" prop="bucket" :rules="[Rules.requiredInput]">
|
||||
<el-input v-model.trim="dialogData.rowData!.bucket" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item
|
||||
v-if="dialogData.rowData!.type !== 'LOCAL' && !isSftpOrWebDAV(dialogData.rowData!.type)"
|
||||
:label="$t('setting.backupDir')"
|
||||
prop="backupPath"
|
||||
>
|
||||
<el-input clearable v-model.trim="dialogData.rowData!.backupPath" placeholder="/1panel" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button :disabled="loading" @click="handleClose">
|
||||
{{ $t('commons.button.cancel') }}
|
||||
</el-button>
|
||||
<el-button :disabled="loading" type="primary" @click="onSubmit(formRef)">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import FileList from '@/components/file-list/index.vue';
|
||||
import i18n from '@/lang';
|
||||
import { ElForm } from 'element-plus';
|
||||
import { Backup } from '@/api/interface/backup';
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { addBackup, editBackup, getOneDriveInfo, listBucket } from '@/api/modules/setting';
|
||||
import { deepCopy } from '@/utils/util';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
|
||||
const loading = ref(false);
|
||||
type FormInstance = InstanceType<typeof ElForm>;
|
||||
const formRef = ref<FormInstance>();
|
||||
const buckets = ref();
|
||||
const errBuckets = ref();
|
||||
|
||||
const endpoints = ref('http');
|
||||
const rules = reactive({
|
||||
driveCode: [{ validator: checkDriveCode, required: true, trigger: 'blur' }],
|
||||
});
|
||||
function checkDriveCode(rule: any, value: any, callback: any) {
|
||||
const reg = /^[A-Za-z0-9_.-]+$/;
|
||||
if (!reg.test(value)) {
|
||||
return callback(new Error(i18n.global.t('setting.codeWarning')));
|
||||
}
|
||||
callback();
|
||||
}
|
||||
|
||||
const emit = defineEmits<{ (e: 'search'): void }>();
|
||||
|
||||
interface DialogProps {
|
||||
title: string;
|
||||
rowData?: Backup.BackupInfo;
|
||||
getTableList?: () => Promise<any>;
|
||||
}
|
||||
const title = ref<string>('');
|
||||
const drawerVisible = ref(false);
|
||||
const dialogData = ref<DialogProps>({
|
||||
title: '',
|
||||
});
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
buckets.value = [];
|
||||
dialogData.value = params;
|
||||
if (dialogData.value.title === 'edit' && dialogData.value.rowData!.type === 'MINIO') {
|
||||
if (dialogData.value.rowData!.varsJson['endpoint'].indexOf('://') !== 0) {
|
||||
endpoints.value = dialogData.value.rowData!.varsJson['endpoint'].split('://')[0];
|
||||
dialogData.value.rowData!.varsJson['endpointItem'] =
|
||||
dialogData.value.rowData!.varsJson['endpoint'].split('://')[1];
|
||||
}
|
||||
}
|
||||
if (dialogData.value.title === 'create' && dialogData.value.rowData!.type === 'SFTP') {
|
||||
dialogData.value.rowData.varsJson['port'] = 22;
|
||||
}
|
||||
if (dialogData.value.rowData!.type === 'COS' || dialogData.value.rowData!.type === 'OSS') {
|
||||
if (params.title === 'create' || (params.title === 'edit' && !dialogData.value.rowData.varsJson['scType'])) {
|
||||
dialogData.value.rowData.varsJson['scType'] = 'Standard';
|
||||
}
|
||||
}
|
||||
if (dialogData.value.rowData!.type === 'S3') {
|
||||
if (params.title === 'create' || (params.title === 'edit' && !dialogData.value.rowData.varsJson['scType'])) {
|
||||
dialogData.value.rowData.varsJson['scType'] = 'STANDARD';
|
||||
}
|
||||
}
|
||||
title.value = i18n.global.t('commons.button.' + dialogData.value.title);
|
||||
drawerVisible.value = true;
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
};
|
||||
const jumpAzure = async () => {
|
||||
const res = await getOneDriveInfo();
|
||||
let commonUrl = `response_type=code&client_id=${res.data}&redirect_uri=http://localhost/login/authorized&scope=offline_access+Files.ReadWrite.All+User.Read`;
|
||||
if (!dialogData.value.rowData!.varsJson['isCN']) {
|
||||
window.open('https://login.microsoftonline.com/common/oauth2/v2.0/authorize?' + commonUrl, '_blank');
|
||||
} else {
|
||||
window.open('https://login.chinacloudapi.cn/common/oauth2/v2.0/authorize?' + commonUrl, '_blank');
|
||||
}
|
||||
};
|
||||
|
||||
const loadDir = async (path: string) => {
|
||||
dialogData.value.rowData!.varsJson['dir'] = path;
|
||||
};
|
||||
function hasBucket(val: string) {
|
||||
return val === 'OSS' || val === 'S3' || val === 'MINIO' || val === 'COS' || val === 'KODO';
|
||||
}
|
||||
|
||||
function hasEndpoint(val: string) {
|
||||
return val === 'OSS' || val === 'S3';
|
||||
}
|
||||
|
||||
function isSftpOrWebDAV(val: string) {
|
||||
return val === 'SFTP' || val === 'WebDAV';
|
||||
}
|
||||
|
||||
const toDoc = () => {
|
||||
window.open('https://1panel.cn/docs/user_manual/settings/', '_blank', 'noopener,noreferrer');
|
||||
};
|
||||
|
||||
const getBuckets = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
loading.value = true;
|
||||
let item = deepCopy(dialogData.value.rowData!.varsJson);
|
||||
if (dialogData.value.rowData!.type === 'MINIO') {
|
||||
dialogData.value.rowData!.varsJson['endpointItem'] = dialogData.value
|
||||
.rowData!.varsJson['endpointItem'].replace('https://', '')
|
||||
.replace('http://', '');
|
||||
item['endpoint'] = endpoints.value + '://' + dialogData.value.rowData!.varsJson['endpointItem'];
|
||||
item['endpointItem'] = undefined;
|
||||
}
|
||||
listBucket({
|
||||
type: dialogData.value.rowData!.type,
|
||||
vars: JSON.stringify(item),
|
||||
accessKey: dialogData.value.rowData!.accessKey,
|
||||
credential: dialogData.value.rowData!.credential,
|
||||
})
|
||||
.then((res) => {
|
||||
loading.value = false;
|
||||
buckets.value = res.data;
|
||||
})
|
||||
.catch(() => {
|
||||
buckets.value = [];
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (hasBucket(dialogData.value.rowData.type) && !dialogData.value.rowData.bucket) {
|
||||
errBuckets.value = true;
|
||||
return;
|
||||
}
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
if (!dialogData.value.rowData) return;
|
||||
if (dialogData.value.rowData!.type === 'MINIO') {
|
||||
dialogData.value.rowData!.varsJson['endpointItem'].replace('https://', '').replace('http://', '');
|
||||
dialogData.value.rowData!.varsJson['endpoint'] =
|
||||
endpoints.value + '://' + dialogData.value.rowData!.varsJson['endpointItem'];
|
||||
dialogData.value.rowData!.varsJson['endpointItem'] = undefined;
|
||||
}
|
||||
dialogData.value.rowData.vars = JSON.stringify(dialogData.value.rowData!.varsJson);
|
||||
loading.value = true;
|
||||
if (dialogData.value.title === 'create') {
|
||||
await addBackup(dialogData.value.rowData)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
await editBackup(dialogData.value.rowData)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.append-button {
|
||||
width: 80px;
|
||||
background-color: var(--el-fill-color-light);
|
||||
color: var(--el-color-info);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,198 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-drawer v-model="drawerVisible" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="title + $t('setting.backupAccount')" :back="handleClose" />
|
||||
</template>
|
||||
<el-form @submit.prevent ref="formRef" v-loading="loading" label-position="top" :model="ossData.rowData">
|
||||
<el-row type="flex" justify="center">
|
||||
<el-col :span="22">
|
||||
<el-form-item :label="$t('commons.table.type')" prop="type" :rules="Rules.requiredSelect">
|
||||
<el-tag>{{ $t('setting.' + ossData.rowData!.type) }}</el-tag>
|
||||
</el-form-item>
|
||||
<el-form-item label="Access Key ID" prop="accessKey" :rules="Rules.requiredInput">
|
||||
<el-input v-model.trim="ossData.rowData!.accessKey" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Secret Key" prop="credential" :rules="Rules.requiredInput">
|
||||
<el-input show-password clearable v-model.trim="ossData.rowData!.credential" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Endpoint" prop="varsJson.endpointItem" :rules="Rules.requiredInput">
|
||||
<el-input v-model="ossData.rowData!.varsJson['endpointItem']">
|
||||
<template #prepend>
|
||||
<el-select v-model.trim="endpointProto" style="width: 100px">
|
||||
<el-option label="http" value="http" />
|
||||
<el-option label="https" value="https" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="Bucket" prop="bucket">
|
||||
<el-select
|
||||
@change="errBuckets = false"
|
||||
style="width: 80%"
|
||||
v-model="ossData.rowData!.bucket"
|
||||
>
|
||||
<el-option v-for="item in buckets" :key="item" :value="item" />
|
||||
</el-select>
|
||||
<el-button style="width: 20%" plain @click="getBuckets(formRef)">
|
||||
{{ $t('setting.loadBucket') }}
|
||||
</el-button>
|
||||
<span v-if="errBuckets" class="input-error">{{ $t('commons.rule.requiredSelect') }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('setting.scType')"
|
||||
prop="varsJson.scType"
|
||||
:rules="[Rules.requiredSelect]"
|
||||
>
|
||||
<el-select v-model="ossData.rowData!.varsJson['scType']">
|
||||
<el-option value="Standard" :label="$t('setting.scStandard')" />
|
||||
<el-option value="IA" :label="$t('setting.scStandard_IA')" />
|
||||
<el-option value="Archive" :label="$t('setting.scArchive')" />
|
||||
<el-option value="ColdArchive" :label="$t('setting.scDeep_Archive')" />
|
||||
</el-select>
|
||||
<el-alert
|
||||
v-if="ossData.rowData!.varsJson['scType'] === 'Archive' || ossData.rowData!.varsJson['scType'] === 'ColdArchive'"
|
||||
style="margin-top: 10px"
|
||||
:closable="false"
|
||||
type="warning"
|
||||
:title="$t('setting.archiveHelper')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('setting.backupDir')" prop="backupPath">
|
||||
<el-input clearable v-model.trim="ossData.rowData!.backupPath" placeholder="/1panel" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button :disabled="loading" @click="handleClose">
|
||||
{{ $t('commons.button.cancel') }}
|
||||
</el-button>
|
||||
<el-button :disabled="loading" type="primary" @click="onSubmit(formRef)">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import i18n from '@/lang';
|
||||
import { ElForm } from 'element-plus';
|
||||
import { Backup } from '@/api/interface/backup';
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { addBackup, editBackup, listBucket } from '@/api/modules/setting';
|
||||
import { deepCopy, spliceHttp, splitHttp } from '@/utils/util';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
|
||||
const loading = ref(false);
|
||||
type FormInstance = InstanceType<typeof ElForm>;
|
||||
const formRef = ref<FormInstance>();
|
||||
const buckets = ref();
|
||||
const errBuckets = ref();
|
||||
|
||||
const endpointProto = ref('http');
|
||||
const emit = defineEmits(['search']);
|
||||
|
||||
interface DialogProps {
|
||||
title: string;
|
||||
rowData?: Backup.BackupInfo;
|
||||
}
|
||||
const title = ref<string>('');
|
||||
const drawerVisible = ref(false);
|
||||
const ossData = ref<DialogProps>({
|
||||
title: '',
|
||||
});
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
buckets.value = [];
|
||||
ossData.value = params;
|
||||
if (params.title === 'create' || (params.title === 'edit' && !ossData.value.rowData.varsJson['scType'])) {
|
||||
ossData.value.rowData.varsJson['scType'] = 'Standard';
|
||||
}
|
||||
if (ossData.value.title === 'edit') {
|
||||
let httpItem = splitHttp(ossData.value.rowData!.varsJson['endpoint']);
|
||||
ossData.value.rowData!.varsJson['endpointItem'] = httpItem.url;
|
||||
endpointProto.value = httpItem.proto;
|
||||
}
|
||||
title.value = i18n.global.t('commons.button.' + ossData.value.title);
|
||||
drawerVisible.value = true;
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
};
|
||||
|
||||
const getBuckets = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
loading.value = true;
|
||||
let item = deepCopy(ossData.value.rowData!.varsJson);
|
||||
item['endpoint'] = spliceHttp(endpointProto.value, ossData.value.rowData!.varsJson['endpointItem']);
|
||||
listBucket({
|
||||
type: ossData.value.rowData!.type,
|
||||
vars: JSON.stringify(item),
|
||||
accessKey: ossData.value.rowData!.accessKey,
|
||||
credential: ossData.value.rowData!.credential,
|
||||
})
|
||||
.then((res) => {
|
||||
loading.value = false;
|
||||
buckets.value = res.data;
|
||||
})
|
||||
.catch(() => {
|
||||
buckets.value = [];
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!ossData.value.rowData.bucket) {
|
||||
errBuckets.value = true;
|
||||
return;
|
||||
}
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
if (!ossData.value.rowData) return;
|
||||
ossData.value.rowData!.varsJson['endpoint'] = spliceHttp(
|
||||
endpointProto.value,
|
||||
ossData.value.rowData!.varsJson['endpointItem'],
|
||||
);
|
||||
ossData.value.rowData.vars = JSON.stringify(ossData.value.rowData!.varsJson);
|
||||
loading.value = true;
|
||||
if (ossData.value.title === 'create') {
|
||||
await addBackup(ossData.value.rowData)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
await editBackup(ossData.value.rowData)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,197 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-drawer v-model="drawerVisible" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="title + $t('setting.backupAccount')" :back="handleClose" />
|
||||
</template>
|
||||
<el-form @submit.prevent ref="formRef" v-loading="loading" label-position="top" :model="s3Data.rowData">
|
||||
<el-row type="flex" justify="center">
|
||||
<el-col :span="22">
|
||||
<el-form-item :label="$t('commons.table.type')" prop="type" :rules="Rules.requiredSelect">
|
||||
<el-tag>{{ $t('setting.' + s3Data.rowData!.type) }}</el-tag>
|
||||
</el-form-item>
|
||||
<el-form-item label="Access Key ID" prop="accessKey" :rules="Rules.requiredInput">
|
||||
<el-input v-model.trim="s3Data.rowData!.accessKey" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Secret Key" prop="credential" :rules="Rules.requiredInput">
|
||||
<el-input show-password clearable v-model.trim="s3Data.rowData!.credential" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Region" prop="varsJson.region" :rules="Rules.requiredInput">
|
||||
<el-input pro v-model.trim="s3Data.rowData!.varsJson['region']" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Endpoint" prop="varsJson.endpointItem" :rules="Rules.requiredInput">
|
||||
<el-input v-model="s3Data.rowData!.varsJson['endpointItem']">
|
||||
<template #prepend>
|
||||
<el-select v-model.trim="endpointProto" style="width: 100px">
|
||||
<el-option label="http" value="http" />
|
||||
<el-option label="https" value="https" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="Bucket" prop="bucket">
|
||||
<el-select @change="errBuckets = false" style="width: 80%" v-model="s3Data.rowData!.bucket">
|
||||
<el-option v-for="item in buckets" :key="item" :value="item" />
|
||||
</el-select>
|
||||
<el-button style="width: 20%" plain @click="getBuckets(formRef)">
|
||||
{{ $t('setting.loadBucket') }}
|
||||
</el-button>
|
||||
<span v-if="errBuckets" class="input-error">{{ $t('commons.rule.requiredSelect') }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('setting.scType')"
|
||||
prop="varsJson.scType"
|
||||
:rules="[Rules.requiredSelect]"
|
||||
>
|
||||
<el-select v-model="s3Data.rowData!.varsJson['scType']">
|
||||
<el-option value="STANDARD" :label="$t('setting.scStandard')" />
|
||||
<el-option value="STANDARD_IA" :label="$t('setting.scStandard_IA')" />
|
||||
<el-option value="GLACIER" :label="$t('setting.scArchive')" />
|
||||
<el-option value="DEEP_ARCHIVE" :label="$t('setting.scDeep_Archive')" />
|
||||
</el-select>
|
||||
<el-alert
|
||||
v-if="s3Data.rowData!.varsJson['scType'] === 'Archive' || s3Data.rowData!.varsJson['scType'] === 'ColdArchive'"
|
||||
style="margin-top: 10px"
|
||||
:closable="false"
|
||||
type="warning"
|
||||
:title="$t('setting.archiveHelper')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('setting.backupDir')" prop="backupPath">
|
||||
<el-input clearable v-model.trim="s3Data.rowData!.backupPath" placeholder="/1panel" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button :disabled="loading" @click="handleClose">
|
||||
{{ $t('commons.button.cancel') }}
|
||||
</el-button>
|
||||
<el-button :disabled="loading" type="primary" @click="onSubmit(formRef)">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import i18n from '@/lang';
|
||||
import { ElForm } from 'element-plus';
|
||||
import { Backup } from '@/api/interface/backup';
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { addBackup, editBackup, listBucket } from '@/api/modules/setting';
|
||||
import { deepCopy, spliceHttp, splitHttp } from '@/utils/util';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
|
||||
const loading = ref(false);
|
||||
type FormInstance = InstanceType<typeof ElForm>;
|
||||
const formRef = ref<FormInstance>();
|
||||
const buckets = ref();
|
||||
const errBuckets = ref();
|
||||
|
||||
const endpointProto = ref('http');
|
||||
const emit = defineEmits(['search']);
|
||||
|
||||
interface DialogProps {
|
||||
title: string;
|
||||
rowData?: Backup.BackupInfo;
|
||||
}
|
||||
const title = ref<string>('');
|
||||
const drawerVisible = ref(false);
|
||||
const s3Data = ref<DialogProps>({
|
||||
title: '',
|
||||
});
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
buckets.value = [];
|
||||
s3Data.value = params;
|
||||
if (params.title === 'create' || (params.title === 'edit' && !s3Data.value.rowData.varsJson['scType'])) {
|
||||
s3Data.value.rowData.varsJson['scType'] = 'STANDARD';
|
||||
}
|
||||
if (s3Data.value.title === 'edit') {
|
||||
let httpItem = splitHttp(s3Data.value.rowData!.varsJson['endpoint']);
|
||||
s3Data.value.rowData!.varsJson['endpointItem'] = httpItem.url;
|
||||
endpointProto.value = httpItem.proto;
|
||||
}
|
||||
title.value = i18n.global.t('commons.button.' + s3Data.value.title);
|
||||
drawerVisible.value = true;
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
};
|
||||
|
||||
const getBuckets = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
loading.value = true;
|
||||
let item = deepCopy(s3Data.value.rowData!.varsJson);
|
||||
item['endpoint'] = spliceHttp(endpointProto.value, s3Data.value.rowData!.varsJson['endpointItem']);
|
||||
listBucket({
|
||||
type: s3Data.value.rowData!.type,
|
||||
vars: JSON.stringify(item),
|
||||
accessKey: s3Data.value.rowData!.accessKey,
|
||||
credential: s3Data.value.rowData!.credential,
|
||||
})
|
||||
.then((res) => {
|
||||
loading.value = false;
|
||||
buckets.value = res.data;
|
||||
})
|
||||
.catch(() => {
|
||||
buckets.value = [];
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!s3Data.value.rowData.bucket) {
|
||||
errBuckets.value = true;
|
||||
return;
|
||||
}
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
if (!s3Data.value.rowData) return;
|
||||
s3Data.value.rowData!.varsJson['endpoint'] = spliceHttp(
|
||||
endpointProto.value,
|
||||
s3Data.value.rowData!.varsJson['endpointItem'],
|
||||
);
|
||||
s3Data.value.rowData.vars = JSON.stringify(s3Data.value.rowData!.varsJson);
|
||||
loading.value = true;
|
||||
if (s3Data.value.title === 'create') {
|
||||
await addBackup(s3Data.value.rowData)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
await editBackup(s3Data.value.rowData)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-drawer v-model="drawerVisible" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="title + $t('setting.backupAccount')" :back="handleClose" />
|
||||
</template>
|
||||
<el-form @submit.prevent ref="formRef" v-loading="loading" label-position="top" :model="sftpData.rowData">
|
||||
<el-row type="flex" justify="center">
|
||||
<el-col :span="22">
|
||||
<el-form-item :label="$t('commons.table.type')" prop="type" :rules="Rules.requiredSelect">
|
||||
<el-tag>{{ $t('setting.' + sftpData.rowData!.type) }}</el-tag>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('setting.address')" prop="varsJson.address" :rules="Rules.host">
|
||||
<el-input v-model.trim="sftpData.rowData!.varsJson['address']" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('commons.table.port')" prop="varsJson.port" :rules="[Rules.port]">
|
||||
<el-input-number
|
||||
:min="0"
|
||||
:max="65535"
|
||||
v-model.number="sftpData.rowData!.varsJson['port']"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('commons.login.username')"
|
||||
prop="accessKey"
|
||||
:rules="[Rules.requiredInput]"
|
||||
>
|
||||
<el-input v-model.trim="sftpData.rowData!.accessKey" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('commons.login.password')"
|
||||
prop="credential"
|
||||
:rules="[Rules.requiredInput]"
|
||||
>
|
||||
<el-input
|
||||
type="password"
|
||||
clearable
|
||||
show-password
|
||||
v-model.trim="sftpData.rowData!.credential"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('setting.path')" prop="bucket" :rules="[Rules.requiredInput]">
|
||||
<el-input v-model.trim="sftpData.rowData!.bucket" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button :disabled="loading" @click="handleClose">
|
||||
{{ $t('commons.button.cancel') }}
|
||||
</el-button>
|
||||
<el-button :disabled="loading" type="primary" @click="onSubmit(formRef)">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import i18n from '@/lang';
|
||||
import { ElForm } from 'element-plus';
|
||||
import { Backup } from '@/api/interface/backup';
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { addBackup, editBackup } from '@/api/modules/setting';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
|
||||
const loading = ref(false);
|
||||
type FormInstance = InstanceType<typeof ElForm>;
|
||||
const formRef = ref<FormInstance>();
|
||||
|
||||
const emit = defineEmits(['search']);
|
||||
|
||||
interface DialogProps {
|
||||
title: string;
|
||||
rowData?: Backup.BackupInfo;
|
||||
getTableList?: () => Promise<any>;
|
||||
}
|
||||
const title = ref<string>('');
|
||||
const drawerVisible = ref(false);
|
||||
const sftpData = ref<DialogProps>({
|
||||
title: '',
|
||||
});
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
sftpData.value = params;
|
||||
if (sftpData.value.title === 'create') {
|
||||
sftpData.value.rowData.varsJson['port'] = 22;
|
||||
}
|
||||
title.value = i18n.global.t('commons.button.' + sftpData.value.title);
|
||||
drawerVisible.value = true;
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
};
|
||||
|
||||
const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
if (!sftpData.value.rowData) return;
|
||||
sftpData.value.rowData.vars = JSON.stringify(sftpData.value.rowData!.varsJson);
|
||||
loading.value = true;
|
||||
if (sftpData.value.title === 'create') {
|
||||
await addBackup(sftpData.value.rowData)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
await editBackup(sftpData.value.rowData)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,156 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-drawer v-model="drawerVisible" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="title + $t('setting.backupAccount')" :back="handleClose" />
|
||||
</template>
|
||||
<el-form @submit.prevent ref="formRef" v-loading="loading" label-position="top" :model="webdavData.rowData">
|
||||
<el-row type="flex" justify="center">
|
||||
<el-col :span="22">
|
||||
<el-form-item :label="$t('commons.table.type')" prop="type" :rules="Rules.requiredSelect">
|
||||
<el-tag>{{ $t('setting.' + webdavData.rowData!.type) }}</el-tag>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('setting.address')"
|
||||
prop="varsJson.address"
|
||||
:rules="Rules.requiredInput"
|
||||
>
|
||||
<el-input v-model="webdavData.rowData!.varsJson['addressItem']">
|
||||
<template #prepend>
|
||||
<el-select v-model.trim="addressProto" style="width: 100px">
|
||||
<el-option label="http" value="http" />
|
||||
<el-option label="https" value="https" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('commons.table.port')" prop="varsJson.port" :rules="[Rules.port]">
|
||||
<el-input-number
|
||||
:min="0"
|
||||
:max="65535"
|
||||
v-model.number="webdavData.rowData!.varsJson['port']"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('commons.login.username')"
|
||||
prop="accessKey"
|
||||
:rules="[Rules.requiredInput]"
|
||||
>
|
||||
<el-input v-model.trim="webdavData.rowData!.accessKey" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('commons.login.password')"
|
||||
prop="credential"
|
||||
:rules="[Rules.requiredInput]"
|
||||
>
|
||||
<el-input
|
||||
type="password"
|
||||
clearable
|
||||
show-password
|
||||
v-model.trim="webdavData.rowData!.credential"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('setting.path')" prop="bucket" :rules="[Rules.requiredInput]">
|
||||
<el-input v-model.trim="webdavData.rowData!.bucket" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button :disabled="loading" @click="handleClose">
|
||||
{{ $t('commons.button.cancel') }}
|
||||
</el-button>
|
||||
<el-button :disabled="loading" type="primary" @click="onSubmit(formRef)">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import i18n from '@/lang';
|
||||
import { ElForm } from 'element-plus';
|
||||
import { Backup } from '@/api/interface/backup';
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { addBackup, editBackup } from '@/api/modules/setting';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { spliceHttp, splitHttp } from '@/utils/util';
|
||||
|
||||
const loading = ref(false);
|
||||
type FormInstance = InstanceType<typeof ElForm>;
|
||||
const formRef = ref<FormInstance>();
|
||||
|
||||
const addressProto = ref('http');
|
||||
const emit = defineEmits(['search']);
|
||||
|
||||
interface DialogProps {
|
||||
title: string;
|
||||
rowData?: Backup.BackupInfo;
|
||||
}
|
||||
const title = ref<string>('');
|
||||
const drawerVisible = ref(false);
|
||||
const webdavData = ref<DialogProps>({
|
||||
title: '',
|
||||
});
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
webdavData.value = params;
|
||||
if (webdavData.value.title === 'edit') {
|
||||
let httpItem = splitHttp(webdavData.value.rowData!.varsJson['address']);
|
||||
webdavData.value.rowData!.varsJson['addressItem'] = httpItem.url;
|
||||
addressProto.value = httpItem.proto;
|
||||
}
|
||||
title.value = i18n.global.t('commons.button.' + webdavData.value.title);
|
||||
drawerVisible.value = true;
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
};
|
||||
|
||||
const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
if (!webdavData.value.rowData) return;
|
||||
webdavData.value.rowData!.varsJson['address'] = spliceHttp(
|
||||
addressProto.value,
|
||||
webdavData.value.rowData!.varsJson['addressItem'],
|
||||
);
|
||||
webdavData.value.rowData.vars = JSON.stringify(webdavData.value.rowData!.varsJson);
|
||||
loading.value = true;
|
||||
if (webdavData.value.title === 'create') {
|
||||
await addBackup(webdavData.value.rowData)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
await editBackup(webdavData.value.rowData)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user