mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-18 22:22:59 +08:00
feat: 完成网站上传与恢复功能
This commit is contained in:
parent
e66ce1a9f2
commit
0d95cee924
@ -63,6 +63,24 @@ func (b *BaseApi) BackupWebsite(c *gin.Context) {
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
func (b *BaseApi) RecoverWebsiteByUpload(c *gin.Context) {
|
||||
var req dto.WebSiteRecoverByFile
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if err := global.VALID.Struct(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := websiteService.RecoverByUpload(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
func (b *BaseApi) RecoverWebsite(c *gin.Context) {
|
||||
var req dto.WebSiteRecover
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
|
@ -57,6 +57,13 @@ type WebSiteRecover struct {
|
||||
BackupName string `json:"backupName" validate:"required"`
|
||||
}
|
||||
|
||||
type WebSiteRecoverByFile struct {
|
||||
WebsiteName string `json:"websiteName" validate:"required"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
FileDir string `json:"fileDir" validate:"required"`
|
||||
FileName string `json:"fileName" validate:"required"`
|
||||
}
|
||||
|
||||
type WebSiteDTO struct {
|
||||
model.WebSite
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ func (u *BackupService) BatchDeleteRecord(ids []uint) error {
|
||||
}
|
||||
for _, record := range records {
|
||||
if record.Source == "LOCAL" {
|
||||
if err := os.Remove(record.FileDir + record.FileName); err != nil {
|
||||
if err := os.Remove(record.FileDir + "/" + record.FileName); err != nil {
|
||||
global.LOG.Errorf("remove file %s failed, err: %v", record.FileDir+record.FileName, err)
|
||||
}
|
||||
} else {
|
||||
|
@ -34,6 +34,7 @@ type IWebsiteService interface {
|
||||
GetWebsiteOptions() ([]string, error)
|
||||
Backup(domain string) error
|
||||
Recover(req dto.WebSiteRecover) error
|
||||
RecoverByUpload(req dto.WebSiteRecoverByFile) error
|
||||
UpdateWebsite(req dto.WebSiteUpdate) error
|
||||
DeleteWebSite(req dto.WebSiteDel) error
|
||||
}
|
||||
@ -149,15 +150,40 @@ func (w WebsiteService) Backup(domain string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w WebsiteService) RecoverByUpload(req dto.WebSiteRecoverByFile) error {
|
||||
if err := handleUnTar(fmt.Sprintf("%s/%s", req.FileDir, req.FileName), req.FileDir); err != nil {
|
||||
return err
|
||||
}
|
||||
tmpDir := fmt.Sprintf("%s/%s", req.FileDir, strings.ReplaceAll(req.FileName, ".tar.gz", ""))
|
||||
webJson, err := os.ReadFile(fmt.Sprintf("%s/website.json", tmpDir))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var websiteInfo WebSiteInfo
|
||||
if err := json.Unmarshal(webJson, &websiteInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
if websiteInfo.WebsiteName != req.WebsiteName || websiteInfo.WebsiteType != req.Type {
|
||||
return errors.New("上传文件与选中网站不匹配,无法恢复")
|
||||
}
|
||||
|
||||
website, err := websiteRepo.GetFirst(websiteRepo.WithByDomain(req.WebsiteName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := handleWebsiteRecover(&website, tmpDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w WebsiteService) Recover(req dto.WebSiteRecover) error {
|
||||
website, err := websiteRepo.GetFirst(websiteRepo.WithByDomain(req.WebsiteName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
app, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !strings.Contains(req.BackupName, "/") {
|
||||
return errors.New("error path of request")
|
||||
}
|
||||
@ -167,71 +193,9 @@ func (w WebsiteService) Recover(req dto.WebSiteRecover) error {
|
||||
return err
|
||||
}
|
||||
fileDir = fileDir + "/" + fileName
|
||||
resource, err := appInstallResourceRepo.GetFirst(appInstallResourceRepo.WithAppInstallId(website.AppInstallID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nginxInfo, err := appInstallRepo.LoadBaseInfoByKey("nginx")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mysqlInfo, err := appInstallRepo.LoadBaseInfoByKey("mysql")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
db, err := mysqlRepo.Get(commonRepo.WithByID(resource.ResourceId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
src, err := os.OpenFile(fmt.Sprintf("%s/%s.conf", fileDir, website.PrimaryDomain), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0775)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer src.Close()
|
||||
var out *os.File
|
||||
nginxConfDir := fmt.Sprintf("%s/nginx/%s/conf/conf.d/%s.conf", constant.AppInstallDir, nginxInfo.Name, website.PrimaryDomain)
|
||||
if _, err := os.Stat(nginxConfDir); err != nil {
|
||||
out, err = os.Create(fmt.Sprintf("%s/%s.conf", nginxConfDir, website.PrimaryDomain))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out, err = os.OpenFile(nginxConfDir, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
defer out.Close()
|
||||
_, _ = io.Copy(out, src)
|
||||
if website.Type == "deployment" {
|
||||
cmd := exec.Command("docker", "exec", "-i", mysqlInfo.ContainerName, "mysql", "-uroot", "-p"+mysqlInfo.Password, db.Name)
|
||||
sql, err := os.OpenFile(fmt.Sprintf("%s/%s.sql", fileDir, website.PrimaryDomain), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd.Stdin = sql
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return errors.New(string(stdout))
|
||||
}
|
||||
|
||||
appDir := fmt.Sprintf("%s/%s", constant.AppInstallDir, app.App.Key)
|
||||
if err := handleUnTar(fmt.Sprintf("%s/%s.web.tar.gz", fileDir, website.PrimaryDomain), appDir); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := compose.Restart(fmt.Sprintf("%s/%s/docker-compose.yml", appDir, app.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
appDir := fmt.Sprintf("%s/nginx/%s/www", constant.AppInstallDir, nginxInfo.Name)
|
||||
if err := handleUnTar(fmt.Sprintf("%s/%s.web.tar.gz", fileDir, website.PrimaryDomain), appDir); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
cmd := exec.Command("docker", "exec", "-i", nginxInfo.ContainerName, "nginx", "-s", "reload")
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return errors.New(string(stdout))
|
||||
if err := handleWebsiteRecover(&website, fileDir); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -534,26 +498,6 @@ func handleWebsiteBackup(backupType, baseDir, backupDir, domain, backupName stri
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
app, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resource, err := appInstallResourceRepo.GetFirst(appInstallResourceRepo.WithAppInstallId(website.AppInstallID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mysqlInfo, err := appInstallRepo.LoadBaseInfoByKey(resource.Key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nginxInfo, err := appInstallRepo.LoadBaseInfoByKey("nginx")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
db, err := mysqlRepo.Get(commonRepo.WithByID(resource.ResourceId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmpDir := fmt.Sprintf("%s/%s/%s", baseDir, backupDir, backupName)
|
||||
if _, err := os.Stat(tmpDir); err != nil && os.IsNotExist(err) {
|
||||
@ -563,21 +507,28 @@ func handleWebsiteBackup(backupType, baseDir, backupDir, domain, backupName stri
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := saveNginxConf(nginxInfo.Name, website.PrimaryDomain, tmpDir); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := saveWebsiteJson(&website, tmpDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if website.Type == "deployment" {
|
||||
dbFile := fmt.Sprintf("%s/%s.sql", tmpDir, website.PrimaryDomain)
|
||||
outfile, _ := os.OpenFile(dbFile, os.O_RDWR|os.O_CREATE, 0755)
|
||||
cmd := exec.Command("docker", "exec", mysqlInfo.ContainerName, "mysqldump", "-uroot", "-p"+mysqlInfo.Password, db.Name)
|
||||
cmd.Stdout = outfile
|
||||
_ = cmd.Run()
|
||||
_ = cmd.Wait()
|
||||
nginxInfo, err := appInstallRepo.LoadBaseInfoByKey("nginx")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nginxConfFile := fmt.Sprintf("%s/nginx/%s/conf/conf.d/%s.conf", constant.AppInstallDir, nginxInfo.Name, website.PrimaryDomain)
|
||||
if err := copyConf(nginxConfFile, fmt.Sprintf("%s/%s.conf", tmpDir, website.PrimaryDomain)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if website.Type == "deployment" {
|
||||
if err := mysqlOpration(&website, "backup", tmpDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
app, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
websiteDir := fmt.Sprintf("%s/%s/%s", constant.AppInstallDir, app.App.Key, app.Name)
|
||||
if err := handleTar(websiteDir, tmpDir, fmt.Sprintf("%s.web.tar.gz", website.PrimaryDomain), ""); err != nil {
|
||||
return err
|
||||
@ -612,6 +563,85 @@ func handleWebsiteBackup(backupType, baseDir, backupDir, domain, backupName stri
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleWebsiteRecover(website *model.WebSite, fileDir string) error {
|
||||
nginxInfo, err := appInstallRepo.LoadBaseInfoByKey("nginx")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nginxConfFile := fmt.Sprintf("%s/nginx/%s/conf/conf.d/%s.conf", constant.AppInstallDir, nginxInfo.Name, website.PrimaryDomain)
|
||||
if err := copyConf(fmt.Sprintf("%s/%s.conf", fileDir, website.PrimaryDomain), nginxConfFile); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if website.Type == "deployment" {
|
||||
if err := mysqlOpration(website, "recover", fileDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
app, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
appDir := fmt.Sprintf("%s/%s", constant.AppInstallDir, app.App.Key)
|
||||
if err := handleUnTar(fmt.Sprintf("%s/%s.web.tar.gz", fileDir, website.PrimaryDomain), appDir); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := compose.Restart(fmt.Sprintf("%s/%s/docker-compose.yml", appDir, app.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
appDir := fmt.Sprintf("%s/nginx/%s/www", constant.AppInstallDir, nginxInfo.Name)
|
||||
if err := handleUnTar(fmt.Sprintf("%s/%s.web.tar.gz", fileDir, website.PrimaryDomain), appDir); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
cmd := exec.Command("docker", "exec", "-i", nginxInfo.ContainerName, "nginx", "-s", "reload")
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return errors.New(string(stdout))
|
||||
}
|
||||
_ = os.RemoveAll(fileDir)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func mysqlOpration(website *model.WebSite, operation, filePath string) error {
|
||||
mysqlInfo, err := appInstallRepo.LoadBaseInfoByKey("mysql")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resource, err := appInstallResourceRepo.GetFirst(appInstallResourceRepo.WithAppInstallId(website.AppInstallID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
db, err := mysqlRepo.Get(commonRepo.WithByID(resource.ResourceId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if operation == "backup" {
|
||||
dbFile := fmt.Sprintf("%s/%s.sql", filePath, website.PrimaryDomain)
|
||||
outfile, _ := os.OpenFile(dbFile, os.O_RDWR|os.O_CREATE, 0755)
|
||||
defer outfile.Close()
|
||||
cmd := exec.Command("docker", "exec", mysqlInfo.ContainerName, "mysqldump", "-uroot", "-p"+mysqlInfo.Password, db.Name)
|
||||
cmd.Stdout = outfile
|
||||
_ = cmd.Run()
|
||||
_ = cmd.Wait()
|
||||
return nil
|
||||
}
|
||||
cmd := exec.Command("docker", "exec", "-i", mysqlInfo.ContainerName, "mysql", "-uroot", "-p"+mysqlInfo.Password, db.Name)
|
||||
sqlfile, err := os.Open(fmt.Sprintf("%s/%s.sql", filePath, website.PrimaryDomain))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer sqlfile.Close()
|
||||
cmd.Stdin = sqlfile
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return errors.New(string(stdout))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func saveWebsiteJson(website *model.WebSite, tmpDir string) error {
|
||||
var WebSiteInfo WebSiteInfo
|
||||
WebSiteInfo.WebsiteType = website.Type
|
||||
@ -629,19 +659,20 @@ func saveWebsiteJson(website *model.WebSite, tmpDir string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func saveNginxConf(nginxName, websiteDomain, tmpDir string) error {
|
||||
nginxConfFile := fmt.Sprintf("%s/nginx/%s/conf/conf.d/%s.conf", constant.AppInstallDir, nginxName, websiteDomain)
|
||||
src, err := os.OpenFile(nginxConfFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0775)
|
||||
func copyConf(srcPath, dstPath string) error {
|
||||
if _, err := os.Stat(srcPath); err != nil {
|
||||
return err
|
||||
}
|
||||
src, err := os.OpenFile(srcPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0775)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer src.Close()
|
||||
out, err := os.Create(fmt.Sprintf("%s/%s.conf", tmpDir, websiteDomain))
|
||||
out, err := os.Create(dstPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
_, _ = io.Copy(out, src)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ var AddTableBackupAccount = &gormigrate.Migration{
|
||||
}
|
||||
item := &model.BackupAccount{
|
||||
Type: "LOCAL",
|
||||
Vars: "{\"dir\":\"/opt/1Panel/backup\"}",
|
||||
Vars: "{\"dir\":\"/opt/1Panel/data/backup\"}",
|
||||
}
|
||||
if err := tx.Create(item).Error; err != nil {
|
||||
return err
|
||||
|
@ -19,6 +19,7 @@ func (a *WebsiteRouter) InitWebsiteRouter(Router *gin.RouterGroup) {
|
||||
groupRouter.GET("/options", baseApi.GetWebsiteOptions)
|
||||
groupRouter.POST("/backup/:domain", baseApi.BackupWebsite)
|
||||
groupRouter.POST("/recover", baseApi.RecoverWebsite)
|
||||
groupRouter.POST("/recover/byupload", baseApi.RecoverWebsiteByUpload)
|
||||
groupRouter.POST("/update", baseApi.UpdateWebSite)
|
||||
groupRouter.GET("/:id", baseApi.GetWebSite)
|
||||
groupRouter.GET("/:id/nginx", baseApi.GetWebSiteNginx)
|
||||
|
@ -43,6 +43,12 @@ export namespace WebSite {
|
||||
type: string;
|
||||
backupName: string;
|
||||
}
|
||||
export interface WebsiteRecoverByUpload {
|
||||
websiteName: string;
|
||||
type: string;
|
||||
fileDir: string;
|
||||
fileName: string;
|
||||
}
|
||||
|
||||
export interface WebSiteDel {
|
||||
id: number;
|
||||
|
@ -17,6 +17,9 @@ export const BackupWebsite = (id: number) => {
|
||||
export const RecoverWebsite = (req: WebSite.WebSiteRecover) => {
|
||||
return http.post(`/websites/recover`, req);
|
||||
};
|
||||
export const RecoverWebsiteByUpload = (req: WebSite.WebsiteRecoverByUpload) => {
|
||||
return http.post(`/websites/recover/byupload`, req);
|
||||
};
|
||||
|
||||
export const UpdateWebsite = (req: WebSite.WebSiteUpdateReq) => {
|
||||
return http.post<any>(`/websites/update`, req);
|
||||
|
@ -695,6 +695,9 @@ export default {
|
||||
author: 'author',
|
||||
source: 'source',
|
||||
sync: 'sync',
|
||||
supportUpType: '.tar.gz files are supported only',
|
||||
zipFormat:
|
||||
'.tar.gz compressed package structure: test.tar.gz compressed package must contain the website.json file',
|
||||
appName: 'App Name',
|
||||
status: 'status',
|
||||
container: 'Container',
|
||||
|
@ -739,6 +739,8 @@ export default {
|
||||
type: '类型',
|
||||
static: '静态网站',
|
||||
deployment: '反向代理',
|
||||
supportUpType: '仅支持 tar.gz 文件',
|
||||
zipFormat: 'tar.gz 压缩包结构:test.tar.gz 压缩包内,必需包含 website.json 文件',
|
||||
proxy: '反向代理',
|
||||
alias: '代号',
|
||||
remark: '备注',
|
||||
|
@ -6,7 +6,13 @@
|
||||
<span>{{ $t('database.backup') }} - {{ websiteName }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<ComplexTable :pagination-config="paginationConfig" v-model:selects="selects" @search="search" :data="data">
|
||||
<ComplexTable
|
||||
v-loading="loading"
|
||||
:pagination-config="paginationConfig"
|
||||
v-model:selects="selects"
|
||||
@search="search"
|
||||
:data="data"
|
||||
>
|
||||
<template #toolbar>
|
||||
<el-button type="primary" @click="onBackup()">
|
||||
{{ $t('database.backup') }}
|
||||
@ -43,6 +49,7 @@ import { Backup } from '@/api/interface/backup';
|
||||
import { BackupWebsite, RecoverWebsite } from '@/api/modules/website';
|
||||
|
||||
const selects = ref<any>([]);
|
||||
const loading = ref(false);
|
||||
|
||||
const data = ref();
|
||||
const paginationConfig = reactive({
|
||||
@ -88,14 +95,28 @@ const onRecover = async (row: Backup.RecordInfo) => {
|
||||
type: websiteType.value,
|
||||
backupName: row.fileDir + '/' + row.fileName,
|
||||
};
|
||||
await RecoverWebsite(params);
|
||||
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
||||
loading.value = true;
|
||||
await RecoverWebsite(params)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const onBackup = async () => {
|
||||
await BackupWebsite(websiteName.value);
|
||||
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
||||
search();
|
||||
loading.value = true;
|
||||
await BackupWebsite(websiteName.value)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
||||
search();
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const onDownload = async (row: Backup.RecordInfo) => {
|
||||
|
@ -138,8 +138,8 @@ const buttons = [
|
||||
label: i18n.global.t('database.loadBackup'),
|
||||
click: (row: WebSite.WebSite) => {
|
||||
let params = {
|
||||
mysqlName: 'test',
|
||||
dbName: row.primaryDomain,
|
||||
websiteName: row.primaryDomain,
|
||||
websiteType: row.type,
|
||||
};
|
||||
uploadRef.value!.acceptParams(params);
|
||||
},
|
||||
|
@ -1,64 +1,66 @@
|
||||
<template>
|
||||
<div>
|
||||
<div :v-loading="loading">
|
||||
<el-dialog v-model="upVisiable" :destroy-on-close="true" :close-on-click-modal="false" width="70%">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>{{ $t('commons.button.import') }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
:on-change="fileOnChange"
|
||||
:before-upload="beforeAvatarUpload"
|
||||
class="upload-demo"
|
||||
:auto-upload="false"
|
||||
>
|
||||
<template #trigger>
|
||||
<el-button type="primary" plain>{{ $t('database.selectFile') }}</el-button>
|
||||
</template>
|
||||
<el-button style="margin-left: 10px" icon="Upload" @click="onSubmit">
|
||||
{{ $t('commons.button.upload') }}
|
||||
</el-button>
|
||||
</el-upload>
|
||||
<div style="margin-left: 10px">
|
||||
<span class="input-help">{{ $t('database.supportUpType') }}</span>
|
||||
<span class="input-help">
|
||||
{{ $t('database.zipFormat') }}
|
||||
</span>
|
||||
</div>
|
||||
<el-divider />
|
||||
<ComplexTable :pagination-config="paginationConfig" v-model:selects="selects" :data="data">
|
||||
<template #toolbar>
|
||||
<el-button
|
||||
style="margin-left: 10px"
|
||||
type="danger"
|
||||
plain
|
||||
:disabled="selects.length === 0"
|
||||
@click="onBatchDelete(null)"
|
||||
>
|
||||
{{ $t('commons.button.delete') }}
|
||||
<div v-loading="loading">
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
:on-change="fileOnChange"
|
||||
:before-upload="beforeAvatarUpload"
|
||||
class="upload-demo"
|
||||
:auto-upload="false"
|
||||
>
|
||||
<template #trigger>
|
||||
<el-button type="primary" plain>{{ $t('database.selectFile') }}</el-button>
|
||||
</template>
|
||||
<el-button style="margin-left: 10px" icon="Upload" @click="onSubmit">
|
||||
{{ $t('commons.button.upload') }}
|
||||
</el-button>
|
||||
</template>
|
||||
<el-table-column type="selection" fix />
|
||||
<el-table-column :label="$t('commons.table.name')" show-overflow-tooltip prop="name" />
|
||||
<el-table-column :label="$t('file.size')" prop="size">
|
||||
<template #default="{ row }">
|
||||
{{ computeSize(row.size) }}
|
||||
</el-upload>
|
||||
<div style="margin-left: 10px">
|
||||
<span class="input-help">{{ $t('website.supportUpType') }}</span>
|
||||
<span class="input-help">
|
||||
{{ $t('website.zipFormat') }}
|
||||
</span>
|
||||
</div>
|
||||
<el-divider />
|
||||
<ComplexTable :pagination-config="paginationConfig" v-model:selects="selects" :data="data">
|
||||
<template #toolbar>
|
||||
<el-button
|
||||
style="margin-left: 10px"
|
||||
type="danger"
|
||||
plain
|
||||
:disabled="selects.length === 0"
|
||||
@click="onBatchDelete(null)"
|
||||
>
|
||||
{{ $t('commons.button.delete') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('commons.table.createdAt')" min-width="80" fix>
|
||||
<template #default="{ row }">
|
||||
{{ dateFromat(0, 0, row.modTime) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<fu-table-operations
|
||||
width="300px"
|
||||
:buttons="buttons"
|
||||
:ellipsis="10"
|
||||
:label="$t('commons.table.operate')"
|
||||
fix
|
||||
/>
|
||||
</ComplexTable>
|
||||
<el-table-column type="selection" fix />
|
||||
<el-table-column :label="$t('commons.table.name')" show-overflow-tooltip prop="name" />
|
||||
<el-table-column :label="$t('file.size')" prop="size">
|
||||
<template #default="{ row }">
|
||||
{{ computeSize(row.size) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('commons.table.createdAt')" min-width="80" fix>
|
||||
<template #default="{ row }">
|
||||
{{ dateFromat(0, 0, row.modTime) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<fu-table-operations
|
||||
width="300px"
|
||||
:buttons="buttons"
|
||||
:ellipsis="10"
|
||||
:label="$t('commons.table.operate')"
|
||||
fix
|
||||
/>
|
||||
</ComplexTable>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
@ -68,14 +70,15 @@ import ComplexTable from '@/components/complex-table/index.vue';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { computeSize, dateFromat } from '@/utils/util';
|
||||
import { useDeleteData } from '@/hooks/use-delete-data';
|
||||
import { recoverByUpload } from '@/api/modules/database';
|
||||
import i18n from '@/lang';
|
||||
import { ElMessage, UploadFile, UploadFiles, UploadInstance, UploadProps } from 'element-plus';
|
||||
import { File } from '@/api/interface/file';
|
||||
import { BatchDeleteFile, GetFilesList, UploadFileData } from '@/api/modules/files';
|
||||
import { RecoverWebsiteByUpload } from '@/api/modules/website';
|
||||
|
||||
const selects = ref<any>([]);
|
||||
const baseDir = '/opt/1Panel/data/uploads/website/';
|
||||
const baseDir = ref();
|
||||
const loading = ref(false);
|
||||
|
||||
const data = ref();
|
||||
const paginationConfig = reactive({
|
||||
@ -85,16 +88,18 @@ const paginationConfig = reactive({
|
||||
});
|
||||
|
||||
const upVisiable = ref(false);
|
||||
const mysqlName = ref();
|
||||
const dbName = ref();
|
||||
const websiteName = ref();
|
||||
const websiteType = ref();
|
||||
|
||||
interface DialogProps {
|
||||
mysqlName: string;
|
||||
dbName: string;
|
||||
websiteName: string;
|
||||
websiteType: string;
|
||||
}
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
mysqlName.value = params.mysqlName;
|
||||
dbName.value = params.dbName;
|
||||
websiteName.value = params.websiteName;
|
||||
websiteType.value = params.websiteType;
|
||||
upVisiable.value = true;
|
||||
baseDir.value = '/opt/1Panel/data/uploads/website/' + websiteName.value;
|
||||
search();
|
||||
};
|
||||
|
||||
@ -102,7 +107,7 @@ const search = async () => {
|
||||
let params = {
|
||||
page: paginationConfig.currentPage,
|
||||
pageSize: paginationConfig.pageSize,
|
||||
path: baseDir,
|
||||
path: baseDir.value,
|
||||
expand: true,
|
||||
};
|
||||
const res = await GetFilesList(params);
|
||||
@ -112,30 +117,29 @@ const search = async () => {
|
||||
|
||||
const onRecover = async (row: File.File) => {
|
||||
let params = {
|
||||
mysqlName: mysqlName.value,
|
||||
dbName: dbName.value,
|
||||
fileDir: baseDir,
|
||||
websiteName: websiteName.value,
|
||||
type: websiteType.value,
|
||||
fileDir: baseDir.value,
|
||||
fileName: row.name,
|
||||
};
|
||||
await recoverByUpload(params);
|
||||
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
||||
loading.value = true;
|
||||
await RecoverWebsiteByUpload(params)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const uploaderFiles = ref<UploadFiles>([]);
|
||||
const uploadRef = ref<UploadInstance>();
|
||||
|
||||
const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
|
||||
if (
|
||||
rawFile.name.endsWith('.sql') ||
|
||||
rawFile.name.endsWith('.gz') ||
|
||||
rawFile.name.endsWith('.zip') ||
|
||||
rawFile.name.endsWith('.tgz')
|
||||
) {
|
||||
if (rawFile.name.endsWith('.tar.gz')) {
|
||||
ElMessage.error(i18n.global.t('database.unSupportType'));
|
||||
return false;
|
||||
} else if (rawFile.size / 1024 / 1024 > 10) {
|
||||
ElMessage.error(i18n.global.t('database.unSupportSize'));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
@ -156,21 +160,27 @@ const onSubmit = () => {
|
||||
if (uploaderFiles.value[0]!.raw != undefined) {
|
||||
formData.append('file', uploaderFiles.value[0]!.raw);
|
||||
}
|
||||
formData.append('path', baseDir);
|
||||
UploadFileData(formData, {}).then(() => {
|
||||
ElMessage.success(i18n.global.t('file.uploadSuccess'));
|
||||
handleClose();
|
||||
search();
|
||||
});
|
||||
formData.append('path', baseDir.value + '/');
|
||||
loading.value = true;
|
||||
UploadFileData(formData, {})
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
ElMessage.success(i18n.global.t('file.uploadSuccess'));
|
||||
handleClose();
|
||||
search();
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const onBatchDelete = async (row: File.File | null) => {
|
||||
let files: Array<string> = [];
|
||||
if (row) {
|
||||
files.push(baseDir + row.name);
|
||||
files.push(baseDir.value + '/' + row.name);
|
||||
} else {
|
||||
selects.value.forEach((item: File.File) => {
|
||||
files.push(baseDir + item.name);
|
||||
files.push(baseDir.value + '/' + item.name);
|
||||
});
|
||||
}
|
||||
await useDeleteData(BatchDeleteFile, { isDir: false, paths: files }, 'commons.msg.delete', true);
|
||||
|
Loading…
Reference in New Issue
Block a user