2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 13:47:15 +08:00

feat: 优化备份与恢复体验

This commit is contained in:
耗子
2025-03-27 03:20:40 +08:00
parent 69b430d7cb
commit 1c7c6074a1
3 changed files with 102 additions and 29 deletions

View File

@@ -1,9 +1,13 @@
<script setup lang="ts">
import website from '@/api/panel/website'
defineOptions({
name: 'backup-index'
})
import app from '@/api/panel/app'
import backup from '@/api/panel/backup'
import dashboard from '@/api/panel/dashboard'
import ListView from '@/views/backup/ListView.vue'
import { NButton, NInput } from 'naive-ui'
@@ -14,6 +18,27 @@ const createModel = ref({
path: ''
})
const { data: installedDbAndPhp } = useRequest(dashboard.installedDbAndPhp, {
initialData: {
db: [
{
label: '',
value: ''
}
]
}
})
const mySQLInstalled = computed(() => {
return installedDbAndPhp.value.db.find((item: any) => item.value === 'mysql')
})
const postgreSQLInstalled = computed(() => {
return installedDbAndPhp.value.db.find((item: any) => item.value === 'postgresql')
})
const websites = ref<any>([])
const handleCreate = () => {
useRequest(
backup.create(currentTab.value, createModel.value.target, createModel.value.path)
@@ -23,26 +48,57 @@ const handleCreate = () => {
window.$message.success('创建成功')
})
}
watch(currentTab, () => {
if (currentTab.value === 'website') {
createModel.value.target = websites.value[0]?.value
} else {
createModel.value.target = ''
}
})
onMounted(() => {
useRequest(app.isInstalled('nginx')).onSuccess(({ data }) => {
if (data.installed) {
useRequest(website.list(1, 10000)).onSuccess(({ data }: { data: any }) => {
for (const item of data.items) {
websites.value.push({
label: item.name,
value: item.name
})
}
createModel.value.target = websites.value[0]?.value
})
}
})
})
</script>
<template>
<common-page show-footer>
<template #action>
<n-button type="primary" @click="createModal = true">
<n-button v-if="currentTab == 'website'" type="primary" @click="createModal = true">
<TheIcon :size="18" icon="material-symbols:add" />
创建备份
备份网站
</n-button>
<n-button v-if="currentTab == 'mysql'" type="primary" @click="createModal = true">
<TheIcon :size="18" icon="material-symbols:add" />
备份 MySQL
</n-button>
<n-button v-if="currentTab == 'postgres'" type="primary" @click="createModal = true">
<TheIcon :size="18" icon="material-symbols:add" />
备份 PostgreSQL
</n-button>
</template>
<n-flex vertical>
<n-alert type="info">该页面预计下版本移除</n-alert>
<n-tabs v-model:value="currentTab" type="line" animated>
<n-tab-pane name="website" tab="网站">
<list-view v-model:type="currentTab" />
</n-tab-pane>
<n-tab-pane name="mysql" tab="MySQL">
<n-tab-pane v-if="mySQLInstalled" name="mysql" tab="MySQL">
<list-view v-model:type="currentTab" />
</n-tab-pane>
<n-tab-pane name="postgres" tab="PostgreSQL">
<n-tab-pane v-if="postgreSQLInstalled" name="postgres" tab="PostgreSQL">
<list-view v-model:type="currentTab" />
</n-tab-pane>
</n-tabs>
@@ -59,15 +115,18 @@ const handleCreate = () => {
@close="createModal = false"
>
<n-form :model="createModel">
<n-form-item path="name" label="名称">
<n-form-item v-if="currentTab == 'website'" path="name" label="网站">
<n-select v-model:value="createModel.target" :options="websites" placeholder="选择网站" />
</n-form-item>
<n-form-item v-if="currentTab != 'website'" path="name" label="数据库名">
<n-input
v-model:value="createModel.target"
type="text"
@keydown.enter.prevent
placeholder="输入网站/数据库名称"
placeholder="输入数据库名称"
/>
</n-form-item>
<n-form-item path="path" label="目录">
<n-form-item path="path" label="保存目录">
<n-input
v-model:value="createModel.path"
type="text"

View File

@@ -1,8 +1,11 @@
<script setup lang="ts">
import backup from '@/api/panel/backup'
import { renderIcon } from '@/utils'
import { MessageReactive, NButton, NDataTable, NInput, NPopconfirm } from 'naive-ui'
import type { MessageReactive } from 'naive-ui'
import { NButton, NDataTable, NInput, NPopconfirm } from 'naive-ui'
import app from '@/api/panel/app'
import website from '@/api/panel/website'
import { formatDateTime } from '@/utils'
const type = defineModel<string>('type', { type: String, required: true })
@@ -15,6 +18,8 @@ const restoreModel = ref({
target: ''
})
const websites = ref<any>([])
const columns: any = [
{
title: '文件名',
@@ -125,6 +130,21 @@ const handleDelete = async (file: string) => {
}
onMounted(() => {
useRequest(app.isInstalled('nginx')).onSuccess(({ data }) => {
if (data.installed) {
useRequest(website.list(1, 10000)).onSuccess(({ data }: { data: any }) => {
for (const item of data.items) {
websites.value.push({
label: item.name,
value: item.name
})
}
if (type.value === 'website') {
restoreModel.value.target = websites.value[0]?.value
}
})
}
})
refresh()
window.$bus.on('backup:refresh', () => {
refresh()
@@ -168,7 +188,10 @@ onUnmounted(() => {
@close="restoreModal = false"
>
<n-form :model="restoreModel">
<n-form-item path="name" label="恢复目标">
<n-form-item v-if="type == 'website'" path="name" label="网站">
<n-select v-model:value="restoreModel.target" :options="websites" placeholder="选择网站" />
</n-form-item>
<n-form-item v-if="type != 'website'" path="name" label="数据库">
<n-input v-model:value="restoreModel.target" type="text" @keydown.enter.prevent />
</n-form-item>
</n-form>

View File

@@ -25,12 +25,6 @@ const websites = ref<any>([])
const { data: installedDbAndPhp } = useRequest(dashboard.installedDbAndPhp, {
initialData: {
php: [
{
label: '不使用',
value: 0
}
],
db: [
{
label: '',
@@ -48,17 +42,6 @@ const postgreSQLInstalled = computed(() => {
return installedDbAndPhp.value.db.find((item: any) => item.value === 'postgresql')
})
const getWebsiteList = async (page: number, limit: number) => {
const data = await website.list(page, limit)
for (const item of data.items) {
websites.value.push({
label: item.name,
value: item.name
})
}
createModel.value.target = websites.value[0]?.value
}
const handleSubmit = async () => {
loading.value = true
useRequest(cron.create(createModel.value))
@@ -83,7 +66,15 @@ watch(createModel, (value) => {
onMounted(() => {
useRequest(app.isInstalled('nginx')).onSuccess(({ data }) => {
if (data.installed) {
getWebsiteList(1, 10000)
useRequest(website.list(1, 10000)).onSuccess(({ data }: { data: any }) => {
for (const item of data.items) {
websites.value.push({
label: item.name,
value: item.name
})
}
createModel.value.target = websites.value[0]?.value
})
}
})
})
@@ -134,7 +125,7 @@ onMounted(() => {
</div>
<n-form-item v-if="createModel.type === 'backup'" label="备份类型">
<n-radio-group v-model:value="createModel.backup_type">
<n-radio value="website">网站目录</n-radio>
<n-radio value="website">网站</n-radio>
<n-radio value="mysql" :disabled="!mySQLInstalled"> MySQL 数据库</n-radio>
<n-radio value="postgres" :disabled="!postgreSQLInstalled"> PostgreSQL 数据库 </n-radio>
</n-radio-group>