mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-03-13 17:24:44 +08:00
fix: 统一文件上传、删除接口
This commit is contained in:
parent
c11c3be0de
commit
e66ce1a9f2
@ -1,8 +1,6 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
@ -44,50 +42,6 @@ func (b *BaseApi) UpdateMysql(c *gin.Context) {
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
func (b *BaseApi) UploadMysqlFiles(c *gin.Context) {
|
||||
form, err := c.MultipartForm()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
files := form.File["file"]
|
||||
|
||||
mysqlName, ok := c.Params.Get("mysqlName")
|
||||
if !ok {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error mysqlName in path"))
|
||||
return
|
||||
}
|
||||
if err := mysqlService.UpFile(mysqlName, files); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
func (b *BaseApi) MysqlUpList(c *gin.Context) {
|
||||
var req dto.SearchDBWithPage
|
||||
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
|
||||
}
|
||||
|
||||
total, list, err := mysqlService.SearchUpListWithPage(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, dto.PageResult{
|
||||
Items: list,
|
||||
Total: total,
|
||||
})
|
||||
}
|
||||
|
||||
func (b *BaseApi) UpdateMysqlVariables(c *gin.Context) {
|
||||
var req []dto.MysqlVariablesUpdate
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
|
@ -128,24 +128,6 @@ func (b *BaseApi) RedisBackupList(c *gin.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
func (b *BaseApi) RedisBackupDelete(c *gin.Context) {
|
||||
var req dto.RedisBackupDelete
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, name := range req.Names {
|
||||
fullPath := fmt.Sprintf("%s/%s", req.FileDir, name)
|
||||
if err := os.Remove(fullPath); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
func (b *BaseApi) UpdateRedisConfByFile(c *gin.Context) {
|
||||
var req dto.RedisConfUpdateByFile
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
|
@ -1,10 +1,13 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
@ -71,6 +74,20 @@ func (b *BaseApi) DeleteFile(c *gin.Context) {
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
func (b *BaseApi) BatchDeleteFile(c *gin.Context) {
|
||||
var req dto.FileBatchDelete
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
err := fileService.BatchDelete(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
func (b *BaseApi) ChangeFileMode(c *gin.Context) {
|
||||
var req dto.FileCreate
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
@ -148,6 +165,19 @@ func (b *BaseApi) UploadFiles(c *gin.Context) {
|
||||
}
|
||||
files := form.File["file"]
|
||||
paths := form.Value["path"]
|
||||
if len(paths) == 0 || !strings.Contains(paths[0], "/") {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error paths in request"))
|
||||
return
|
||||
}
|
||||
dir := paths[0][:strings.LastIndex(paths[0], "/")]
|
||||
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, fmt.Errorf("mkdir %s failed, err: %v", dir, err))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
success := 0
|
||||
for _, file := range files {
|
||||
err := c.SaveUploadedFile(file, path.Join(paths[0], file.Filename))
|
||||
|
@ -190,7 +190,3 @@ type RedisBackupRecover struct {
|
||||
FileName string `json:"fileName"`
|
||||
FileDir string `json:"fileDir"`
|
||||
}
|
||||
type RedisBackupDelete struct {
|
||||
FileDir string `json:"fileDir"`
|
||||
Names []string `json:"names"`
|
||||
}
|
||||
|
@ -34,6 +34,11 @@ type FileDelete struct {
|
||||
IsDir bool
|
||||
}
|
||||
|
||||
type FileBatchDelete struct {
|
||||
IsDir bool
|
||||
Paths []string
|
||||
}
|
||||
|
||||
type FileCompress struct {
|
||||
Files []string
|
||||
Dst string
|
||||
|
@ -6,9 +6,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@ -38,9 +36,7 @@ type IMysqlService interface {
|
||||
UpdateVariables(updatas []dto.MysqlVariablesUpdate) error
|
||||
UpdateConfByFile(info dto.MysqlConfUpdateByFile) error
|
||||
|
||||
UpFile(mysqlName string, files []*multipart.FileHeader) error
|
||||
RecoverByUpload(req dto.UploadRecover) error
|
||||
SearchUpListWithPage(req dto.SearchDBWithPage) (int64, interface{}, error)
|
||||
Backup(db dto.BackupDB) error
|
||||
Recover(db dto.RecoverDB) error
|
||||
|
||||
@ -67,74 +63,6 @@ func (u *MysqlService) SearchWithPage(search dto.PageInfo) (int64, interface{},
|
||||
return total, dtoMysqls, err
|
||||
}
|
||||
|
||||
func (u *MysqlService) SearchUpListWithPage(req dto.SearchDBWithPage) (int64, interface{}, error) {
|
||||
var (
|
||||
list []dto.DatabaseFileRecords
|
||||
backDatas []dto.DatabaseFileRecords
|
||||
)
|
||||
localDir, err := loadLocalDir()
|
||||
if err != nil {
|
||||
return 0, list, nil
|
||||
}
|
||||
uploadDir := fmt.Sprintf("%s/database/mysql/%s/upload", localDir, req.MysqlName)
|
||||
if _, err := os.Stat(uploadDir); err != nil {
|
||||
return 0, list, nil
|
||||
}
|
||||
_ = filepath.Walk(uploadDir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if !info.IsDir() {
|
||||
list = append(list, dto.DatabaseFileRecords{
|
||||
CreatedAt: info.ModTime().Format("2006-01-02 15:04:05"),
|
||||
Size: int(info.Size()),
|
||||
FileDir: uploadDir,
|
||||
FileName: info.Name(),
|
||||
})
|
||||
}
|
||||
return nil
|
||||
})
|
||||
total, start, end := len(list), (req.Page-1)*req.PageSize, req.Page*req.PageSize
|
||||
if start > total {
|
||||
backDatas = make([]dto.DatabaseFileRecords, 0)
|
||||
} else {
|
||||
if end >= total {
|
||||
end = total
|
||||
}
|
||||
backDatas = list[start:end]
|
||||
}
|
||||
return int64(total), backDatas, nil
|
||||
}
|
||||
|
||||
func (u *MysqlService) UpFile(mysqlName string, files []*multipart.FileHeader) error {
|
||||
localDir, err := loadLocalDir()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dstDir := fmt.Sprintf("%s/database/mysql/%s/upload", localDir, mysqlName)
|
||||
if _, err := os.Stat(dstDir); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(dstDir, os.ModePerm); err != nil {
|
||||
if err != nil {
|
||||
return fmt.Errorf("mkdir %s failed, err: %v", dstDir, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, file := range files {
|
||||
src, err := file.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer src.Close()
|
||||
out, err := os.Create(dstDir + "/" + file.Filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
_, _ = io.Copy(out, src)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *MysqlService) RecoverByUpload(req dto.UploadRecover) error {
|
||||
app, err := appInstallRepo.LoadBaseInfoByKey("mysql")
|
||||
if err != nil {
|
||||
|
@ -2,17 +2,18 @@ package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"github.com/pkg/errors"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type FileService struct {
|
||||
@ -20,6 +21,9 @@ type FileService struct {
|
||||
|
||||
func (f FileService) GetFileList(op dto.FileOption) (dto.FileInfo, error) {
|
||||
var fileInfo dto.FileInfo
|
||||
if _, err := os.Stat(op.Path); err != nil && os.IsNotExist(err) {
|
||||
return fileInfo, nil
|
||||
}
|
||||
info, err := files.NewFileInfo(op.FileOption)
|
||||
if err != nil {
|
||||
return fileInfo, err
|
||||
@ -77,6 +81,24 @@ func (f FileService) Delete(op dto.FileDelete) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (f FileService) BatchDelete(op dto.FileBatchDelete) error {
|
||||
fo := files.NewFileOp()
|
||||
if op.IsDir {
|
||||
for _, file := range op.Paths {
|
||||
if err := fo.DeleteDir(file); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, file := range op.Paths {
|
||||
if err := fo.DeleteFile(file); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f FileService) ChangeMode(op dto.FileCreate) error {
|
||||
fo := files.NewFileOp()
|
||||
return fo.Chmod(op.Path, fs.FileMode(op.Mode))
|
||||
|
@ -24,8 +24,6 @@ func (s *DatabaseRouter) InitDatabaseRouter(Router *gin.RouterGroup) {
|
||||
withRecordRouter.POST("", baseApi.CreateMysql)
|
||||
withRecordRouter.PUT("/:id", baseApi.UpdateMysql)
|
||||
withRecordRouter.POST("/backup", baseApi.BackupMysql)
|
||||
cmdRouter.POST("/uplist", baseApi.MysqlUpList)
|
||||
cmdRouter.POST("/uplist/upload/:mysqlName", baseApi.UploadMysqlFiles)
|
||||
withRecordRouter.POST("/recover/byupload", baseApi.RecoverMysqlByUpload)
|
||||
withRecordRouter.POST("/recover", baseApi.RecoverMysql)
|
||||
withRecordRouter.POST("/del", baseApi.DeleteMysql)
|
||||
@ -44,7 +42,6 @@ func (s *DatabaseRouter) InitDatabaseRouter(Router *gin.RouterGroup) {
|
||||
cmdRouter.POST("/redis/backup", baseApi.RedisBackup)
|
||||
cmdRouter.POST("/redis/recover", baseApi.RedisRecover)
|
||||
cmdRouter.POST("/redis/backup/records", baseApi.RedisBackupList)
|
||||
cmdRouter.POST("/redis/backup/del", baseApi.RedisBackupDelete)
|
||||
cmdRouter.POST("/redis/conf/update", baseApi.UpdateRedisConf)
|
||||
cmdRouter.POST("/redis/conf/update/byfile", baseApi.UpdateRedisConfByFile)
|
||||
cmdRouter.POST("/redis/conf/update/persistence", baseApi.UpdateRedisPersistenceConf)
|
||||
|
@ -19,6 +19,7 @@ func (f *FileRouter) InitFileRouter(Router *gin.RouterGroup) {
|
||||
fileRouter.POST("/tree", baseApi.GetFileTree)
|
||||
fileRouter.POST("", baseApi.CreateFile)
|
||||
fileRouter.POST("/del", baseApi.DeleteFile)
|
||||
fileRouter.POST("/batch/del", baseApi.BatchDeleteFile)
|
||||
fileRouter.POST("/mode", baseApi.ChangeFileMode)
|
||||
fileRouter.POST("/compress", baseApi.CompressFile)
|
||||
fileRouter.POST("/decompress", baseApi.DeCompressFile)
|
||||
|
@ -169,10 +169,6 @@ export namespace Database {
|
||||
createdAt: string;
|
||||
size: string;
|
||||
}
|
||||
export interface FileRecordDelete {
|
||||
fileDir: string;
|
||||
names: Array<string>;
|
||||
}
|
||||
export interface RedisRecover {
|
||||
fileName: string;
|
||||
fileDir: string;
|
||||
|
@ -51,6 +51,11 @@ export namespace File {
|
||||
isDir: boolean;
|
||||
}
|
||||
|
||||
export interface FileBatchDelete {
|
||||
isDir: boolean;
|
||||
paths: Array<string>;
|
||||
}
|
||||
|
||||
export interface FileCompress {
|
||||
files: string[];
|
||||
type: string;
|
||||
|
@ -1,18 +1,11 @@
|
||||
import http from '@/api';
|
||||
import { ReqPage, ResPage } from '../interface';
|
||||
import { Database } from '../interface/database';
|
||||
import { File } from '@/api/interface/file';
|
||||
|
||||
export const searchMysqlDBs = (params: ReqPage) => {
|
||||
return http.post<ResPage<Database.MysqlDBInfo>>(`/databases/search`, params);
|
||||
};
|
||||
|
||||
export const searchUpList = (params: ReqPage) => {
|
||||
return http.post<ResPage<Database.FileRecord>>(`/databases/uplist`, params);
|
||||
};
|
||||
export const uploadFile = (mysqlName: string, params: FormData) => {
|
||||
return http.upload<File.File>(`/databases/uplist/upload/${mysqlName}`, params);
|
||||
};
|
||||
export const backup = (params: Database.Backup) => {
|
||||
return http.post(`/databases/backup`, params);
|
||||
};
|
||||
@ -80,6 +73,3 @@ export const recoverRedis = (param: Database.RedisRecover) => {
|
||||
export const redisBackupRedisRecords = (param: ReqPage) => {
|
||||
return http.post<ResPage<Database.FileRecord>>(`/databases/redis/backup/records`, param);
|
||||
};
|
||||
export const deleteDatabaseFile = (param: Database.FileRecordDelete) => {
|
||||
return http.post(`/databases/redis/backup/del`, param);
|
||||
};
|
||||
|
@ -18,6 +18,10 @@ export const DeleteFile = (form: File.FileDelete) => {
|
||||
return http.post<File.File>('files/del', form);
|
||||
};
|
||||
|
||||
export const BatchDeleteFile = (form: File.FileBatchDelete) => {
|
||||
return http.post('files/batch/del', form);
|
||||
};
|
||||
|
||||
export const ChangeFileMode = (form: File.FileCreate) => {
|
||||
return http.post<File.File>('files/mode', form);
|
||||
};
|
||||
|
@ -40,14 +40,17 @@
|
||||
</el-button>
|
||||
</template>
|
||||
<el-table-column type="selection" fix />
|
||||
<el-table-column :label="$t('commons.table.name')" show-overflow-tooltip prop="fileName" />
|
||||
<el-table-column :label="$t('file.dir')" show-overflow-tooltip prop="fileDir" />
|
||||
<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')" prop="createdAt" />
|
||||
<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"
|
||||
@ -63,14 +66,16 @@
|
||||
<script lang="ts" setup>
|
||||
import ComplexTable from '@/components/complex-table/index.vue';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { computeSize } from '@/utils/util';
|
||||
import { computeSize, dateFromat } from '@/utils/util';
|
||||
import { useDeleteData } from '@/hooks/use-delete-data';
|
||||
import { deleteDatabaseFile, recoverByUpload, searchUpList, uploadFile } from '@/api/modules/database';
|
||||
import { recoverByUpload } from '@/api/modules/database';
|
||||
import i18n from '@/lang';
|
||||
import { ElMessage, UploadFile, UploadFiles, UploadInstance, UploadProps } from 'element-plus';
|
||||
import { Database } from '@/api/interface/database';
|
||||
import { File } from '@/api/interface/file';
|
||||
import { BatchDeleteFile, GetFilesList, UploadFileData } from '@/api/modules/files';
|
||||
|
||||
const selects = ref<any>([]);
|
||||
const baseDir = '/opt/1Panel/data/uploads/database/';
|
||||
|
||||
const data = ref();
|
||||
const paginationConfig = reactive({
|
||||
@ -97,19 +102,20 @@ const search = async () => {
|
||||
let params = {
|
||||
page: paginationConfig.currentPage,
|
||||
pageSize: paginationConfig.pageSize,
|
||||
mysqlName: mysqlName.value,
|
||||
path: baseDir,
|
||||
expand: true,
|
||||
};
|
||||
const res = await searchUpList(params);
|
||||
const res = await GetFilesList(params);
|
||||
data.value = res.data.items || [];
|
||||
paginationConfig.total = res.data.total;
|
||||
paginationConfig.total = res.data.itemTotal;
|
||||
};
|
||||
|
||||
const onRecover = async (row: Database.FileRecord) => {
|
||||
const onRecover = async (row: File.File) => {
|
||||
let params = {
|
||||
mysqlName: mysqlName.value,
|
||||
dbName: dbName.value,
|
||||
fileDir: row.fileDir,
|
||||
fileName: row.fileName,
|
||||
fileDir: baseDir,
|
||||
fileName: row.name,
|
||||
};
|
||||
await recoverByUpload(params);
|
||||
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
||||
@ -150,39 +156,37 @@ const onSubmit = () => {
|
||||
if (uploaderFiles.value[0]!.raw != undefined) {
|
||||
formData.append('file', uploaderFiles.value[0]!.raw);
|
||||
}
|
||||
uploadFile(mysqlName.value, formData).then(() => {
|
||||
formData.append('path', baseDir);
|
||||
UploadFileData(formData, {}).then(() => {
|
||||
ElMessage.success(i18n.global.t('file.uploadSuccess'));
|
||||
handleClose();
|
||||
search();
|
||||
});
|
||||
};
|
||||
|
||||
const onBatchDelete = async (row: Database.FileRecord | null) => {
|
||||
let names: Array<string> = [];
|
||||
let fileDir: string = '';
|
||||
const onBatchDelete = async (row: File.File | null) => {
|
||||
let files: Array<string> = [];
|
||||
if (row) {
|
||||
fileDir = row.fileDir;
|
||||
names.push(row.fileName);
|
||||
files.push(baseDir + row.name);
|
||||
} else {
|
||||
selects.value.forEach((item: Database.FileRecord) => {
|
||||
fileDir = item.fileDir;
|
||||
names.push(item.fileName);
|
||||
selects.value.forEach((item: File.File) => {
|
||||
files.push(baseDir + item.name);
|
||||
});
|
||||
}
|
||||
await useDeleteData(deleteDatabaseFile, { fileDir: fileDir, names: names }, 'commons.msg.delete', true);
|
||||
await useDeleteData(BatchDeleteFile, { paths: files, isDir: false }, 'commons.msg.delete', true);
|
||||
search();
|
||||
};
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
label: i18n.global.t('commons.button.recover'),
|
||||
click: (row: Database.FileRecord) => {
|
||||
click: (row: File.File) => {
|
||||
onRecover(row);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('commons.button.delete'),
|
||||
click: (row: Database.FileRecord) => {
|
||||
click: (row: File.File) => {
|
||||
onBatchDelete(row);
|
||||
},
|
||||
},
|
||||
|
@ -124,7 +124,6 @@ import ConfirmDialog from '@/components/confirm-dialog/index.vue';
|
||||
import { Database } from '@/api/interface/database';
|
||||
import {
|
||||
backupRedis,
|
||||
deleteDatabaseFile,
|
||||
recoverRedis,
|
||||
redisBackupRedisRecords,
|
||||
RedisPersistenceConf,
|
||||
@ -136,6 +135,7 @@ import { ElMessage, FormInstance } from 'element-plus';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { useDeleteData } from '@/hooks/use-delete-data';
|
||||
import { computeSize } from '@/utils/util';
|
||||
import { BatchDeleteFile } from '@/api/modules/files';
|
||||
|
||||
interface saveStruct {
|
||||
second: number;
|
||||
@ -207,18 +207,15 @@ const onRecover = async () => {
|
||||
};
|
||||
|
||||
const onBatchDelete = async (row: Database.FileRecord | null) => {
|
||||
let names: Array<string> = [];
|
||||
let fileDir: string = '';
|
||||
let files: Array<string> = [];
|
||||
if (row) {
|
||||
fileDir = row.fileDir;
|
||||
names.push(row.fileName);
|
||||
files.push(row.fileDir + '/' + row.fileName);
|
||||
} else {
|
||||
selects.value.forEach((item: Database.FileRecord) => {
|
||||
fileDir = item.fileDir;
|
||||
names.push(item.fileName);
|
||||
files.push(item.fileDir + '/' + item.fileName);
|
||||
});
|
||||
}
|
||||
await useDeleteData(deleteDatabaseFile, { fileDir: fileDir, names: names }, 'commons.msg.delete', true);
|
||||
await useDeleteData(BatchDeleteFile, { isDir: false, paths: files }, 'commons.msg.delete', true);
|
||||
loadBackupRecords();
|
||||
};
|
||||
const buttons = [
|
||||
|
@ -63,7 +63,7 @@
|
||||
<script lang="ts" setup>
|
||||
import LayoutContent from '@/layout/layout-content.vue';
|
||||
import BackupRecords from '@/views/website/website/backup/index.vue';
|
||||
import UploadDialog from '@/views/database/mysql/upload/index.vue';
|
||||
import UploadDialog from '@/views/website/website/upload/index.vue';
|
||||
import ComplexTable from '@/components/complex-table/index.vue';
|
||||
import { onMounted, reactive, ref } from '@vue/runtime-core';
|
||||
import CreateWebSite from './create/index.vue';
|
||||
|
198
frontend/src/views/website/website/upload/index.vue
Normal file
198
frontend/src/views/website/website/upload/index.vue
Normal file
@ -0,0 +1,198 @@
|
||||
<template>
|
||||
<div>
|
||||
<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') }}
|
||||
</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) }}
|
||||
</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-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
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';
|
||||
|
||||
const selects = ref<any>([]);
|
||||
const baseDir = '/opt/1Panel/data/uploads/website/';
|
||||
|
||||
const data = ref();
|
||||
const paginationConfig = reactive({
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
const upVisiable = ref(false);
|
||||
const mysqlName = ref();
|
||||
const dbName = ref();
|
||||
interface DialogProps {
|
||||
mysqlName: string;
|
||||
dbName: string;
|
||||
}
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
mysqlName.value = params.mysqlName;
|
||||
dbName.value = params.dbName;
|
||||
upVisiable.value = true;
|
||||
search();
|
||||
};
|
||||
|
||||
const search = async () => {
|
||||
let params = {
|
||||
page: paginationConfig.currentPage,
|
||||
pageSize: paginationConfig.pageSize,
|
||||
path: baseDir,
|
||||
expand: true,
|
||||
};
|
||||
const res = await GetFilesList(params);
|
||||
data.value = res.data.items || [];
|
||||
paginationConfig.total = res.data.itemTotal;
|
||||
};
|
||||
|
||||
const onRecover = async (row: File.File) => {
|
||||
let params = {
|
||||
mysqlName: mysqlName.value,
|
||||
dbName: dbName.value,
|
||||
fileDir: baseDir,
|
||||
fileName: row.name,
|
||||
};
|
||||
await recoverByUpload(params);
|
||||
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
||||
};
|
||||
|
||||
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')
|
||||
) {
|
||||
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;
|
||||
};
|
||||
|
||||
const fileOnChange = (_uploadFile: UploadFile, uploadFiles: UploadFiles) => {
|
||||
uploaderFiles.value = uploadFiles;
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
uploadRef.value!.clearFiles();
|
||||
};
|
||||
|
||||
const onSubmit = () => {
|
||||
const formData = new FormData();
|
||||
if (uploaderFiles.value.length !== 1) {
|
||||
return;
|
||||
}
|
||||
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();
|
||||
});
|
||||
};
|
||||
|
||||
const onBatchDelete = async (row: File.File | null) => {
|
||||
let files: Array<string> = [];
|
||||
if (row) {
|
||||
files.push(baseDir + row.name);
|
||||
} else {
|
||||
selects.value.forEach((item: File.File) => {
|
||||
files.push(baseDir + item.name);
|
||||
});
|
||||
}
|
||||
await useDeleteData(BatchDeleteFile, { isDir: false, paths: files }, 'commons.msg.delete', true);
|
||||
search();
|
||||
};
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
label: i18n.global.t('commons.button.recover'),
|
||||
click: (row: File.File) => {
|
||||
onRecover(row);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('commons.button.delete'),
|
||||
click: (row: File.File) => {
|
||||
onBatchDelete(row);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
Loading…
x
Reference in New Issue
Block a user