mirror of https://github.com/1Panel-dev/1Panel
feat: 完成快照同步功能
parent
71349d2a63
commit
205d406761
|
@ -210,3 +210,30 @@ func (b *BaseApi) ListBackup(c *gin.Context) {
|
|||
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
||||
// @Tags Backup Account
|
||||
// @Summary List files from backup accounts
|
||||
// @Description 获取备份账号内文件列表
|
||||
// @Accept json
|
||||
// @Param request body dto.BackupSearchFile true "request"
|
||||
// @Success 200 {anrry} string
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /backups/search/files [post]
|
||||
func (b *BaseApi) LoadFilesFromBackup(c *gin.Context) {
|
||||
var req dto.BackupSearchFile
|
||||
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
|
||||
}
|
||||
data, err := backupService.ListFiles(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
|
|
@ -40,13 +40,13 @@ func (b *BaseApi) CreateMysql(c *gin.Context) {
|
|||
// @Summary Update mysql database description
|
||||
// @Description 更新 mysql 数据库库描述信息
|
||||
// @Accept json
|
||||
// @Param request body dto.MysqlDescription true "request"
|
||||
// @Param request body dto.UpdateDescription true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /databases/description/update [post]
|
||||
// @x-panel-log {"bodyKeys":["id","description"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"database_mysqls","output_colume":"name","output_value":"name"}],"formatZH":"mysql 数据库 [name] 描述信息修改 [description]","formatEN":"The description of the mysql database [name] is modified => [description]"}
|
||||
func (b *BaseApi) UpdateMysqlDescription(c *gin.Context) {
|
||||
var req dto.MysqlDescription
|
||||
var req dto.UpdateDescription
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
)
|
||||
|
||||
// @Tags System Setting
|
||||
// @Summary Create system backup
|
||||
// @Summary Create system snapshot
|
||||
// @Description 创建系统快照
|
||||
// @Accept json
|
||||
// @Param request body dto.SnapshotCreate true "request"
|
||||
|
@ -34,6 +34,58 @@ func (b *BaseApi) CreateSnapshot(c *gin.Context) {
|
|||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags System Setting
|
||||
// @Summary Import system snapshot
|
||||
// @Description 导入已有快照
|
||||
// @Accept json
|
||||
// @Param request body dto.SnapshotImport true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /settings/snapshot/import [post]
|
||||
// @x-panel-log {"bodyKeys":["from", "names"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"从 [from] 同步系统快照 [names]","formatEN":"Sync system snapshots [names] from [from]"}
|
||||
func (b *BaseApi) ImportSnapshot(c *gin.Context) {
|
||||
var req dto.SnapshotImport
|
||||
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 := snapshotService.SnapshotImport(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags System Setting
|
||||
// @Summary Update snapshot description
|
||||
// @Description 更新快照描述信息
|
||||
// @Accept json
|
||||
// @Param request body dto.UpdateDescription true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /settings/snapshot/description/update [post]
|
||||
// @x-panel-log {"bodyKeys":["id","description"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"snapshots","output_colume":"name","output_value":"name"}],"formatZH":"快照 [name] 描述信息修改 [description]","formatEN":"The description of the snapshot [name] is modified => [description]"}
|
||||
func (b *BaseApi) UpdateSnapDescription(c *gin.Context) {
|
||||
var req dto.UpdateDescription
|
||||
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 := snapshotService.UpdateDescription(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags System Setting
|
||||
// @Summary Page system snapshot
|
||||
// @Description 获取系统快照列表分页
|
||||
|
|
|
@ -26,6 +26,10 @@ type BackupSearch struct {
|
|||
DetailName string `json:"detailName"`
|
||||
}
|
||||
|
||||
type BackupSearchFile struct {
|
||||
Type string `json:"type" validate:"required"`
|
||||
}
|
||||
|
||||
type RecordSearch struct {
|
||||
PageInfo
|
||||
Type string `json:"type" validate:"required"`
|
||||
|
|
|
@ -10,6 +10,11 @@ type PageInfo struct {
|
|||
PageSize int `json:"pageSize" validate:"required,number"`
|
||||
}
|
||||
|
||||
type UpdateDescription struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type OperationWithName struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
}
|
||||
|
|
|
@ -2,11 +2,6 @@ package dto
|
|||
|
||||
import "time"
|
||||
|
||||
type MysqlDescription struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type MysqlDBInfo struct {
|
||||
ID uint `json:"id"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
|
|
|
@ -57,6 +57,11 @@ type SnapshotRecover struct {
|
|||
ReDownload bool `json:"reDownload"`
|
||||
ID uint `json:"id" validate:"required"`
|
||||
}
|
||||
type SnapshotImport struct {
|
||||
From string `json:"from"`
|
||||
Names []string `json:"names"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
type SnapshotInfo struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
|
|
|
@ -29,6 +29,8 @@ type IBackupService interface {
|
|||
BatchDelete(ids []uint) error
|
||||
BatchDeleteRecord(ids []uint) error
|
||||
NewClient(backup *model.BackupAccount) (cloud_storage.CloudStorageClient, error)
|
||||
|
||||
ListFiles(req dto.BackupSearchFile) ([]interface{}, error)
|
||||
}
|
||||
|
||||
func NewIBackupService() IBackupService {
|
||||
|
@ -226,6 +228,18 @@ func (u *BackupService) Update(req dto.BackupOperate) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (u *BackupService) ListFiles(req dto.BackupSearchFile) ([]interface{}, error) {
|
||||
backup, err := backupRepo.Get(backupRepo.WithByType(req.Type))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := u.NewClient(&backup)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return client.ListObjects("system_snapshot/")
|
||||
}
|
||||
|
||||
func (u *BackupService) NewClient(backup *model.BackupAccount) (cloud_storage.CloudStorageClient, error) {
|
||||
varMap := make(map[string]interface{})
|
||||
if err := json.Unmarshal([]byte(backup.Vars), &varMap); err != nil {
|
||||
|
|
|
@ -37,7 +37,7 @@ type IMysqlService interface {
|
|||
ChangePassword(info dto.ChangeDBInfo) error
|
||||
UpdateVariables(updatas []dto.MysqlVariablesUpdate) error
|
||||
UpdateConfByFile(info dto.MysqlConfUpdateByFile) error
|
||||
UpdateDescription(req dto.MysqlDescription) error
|
||||
UpdateDescription(req dto.UpdateDescription) error
|
||||
|
||||
RecoverByUpload(req dto.UploadRecover) error
|
||||
Backup(db dto.BackupDB) error
|
||||
|
@ -201,7 +201,7 @@ func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*mode
|
|||
return &mysql, nil
|
||||
}
|
||||
|
||||
func (u *MysqlService) UpdateDescription(req dto.MysqlDescription) error {
|
||||
func (u *MysqlService) UpdateDescription(req dto.UpdateDescription) error {
|
||||
return mysqlRepo.Update(req.ID, map[string]interface{}{"description": req.Description})
|
||||
}
|
||||
|
||||
|
|
|
@ -29,8 +29,10 @@ type ISnapshotService interface {
|
|||
SnapshotCreate(req dto.SnapshotCreate) error
|
||||
SnapshotRecover(req dto.SnapshotRecover) error
|
||||
SnapshotRollback(req dto.SnapshotRecover) error
|
||||
SnapshotImport(req dto.SnapshotImport) error
|
||||
Delete(req dto.BatchDeleteReq) error
|
||||
|
||||
UpdateDescription(req dto.UpdateDescription) error
|
||||
readFromJson(path string) (SnapshotJson, error)
|
||||
}
|
||||
|
||||
|
@ -51,11 +53,48 @@ func (u *SnapshotService) SearchWithPage(req dto.SearchWithPage) (int64, interfa
|
|||
return total, dtoSnap, err
|
||||
}
|
||||
|
||||
func (u *SnapshotService) SnapshotImport(req dto.SnapshotImport) error {
|
||||
if len(req.Names) == 0 {
|
||||
return fmt.Errorf("incorrect snapshot request body: %v", req.Names)
|
||||
}
|
||||
for _, snap := range req.Names {
|
||||
nameItems := strings.Split(snap, "_")
|
||||
if !strings.HasPrefix(snap, "1panel_v") || !strings.HasSuffix(snap, ".tar.gz") || len(nameItems) != 3 {
|
||||
return fmt.Errorf("incorrect snapshot name format of %s", snap)
|
||||
}
|
||||
formatTime, err := time.Parse("20060102150405", strings.ReplaceAll(nameItems[2], ".tar.gz", ""))
|
||||
if err != nil {
|
||||
return fmt.Errorf("incorrect snapshot name format of %s", snap)
|
||||
}
|
||||
itemSnap := model.Snapshot{
|
||||
Name: snap,
|
||||
From: req.From,
|
||||
Version: nameItems[1],
|
||||
Description: req.Description,
|
||||
Status: constant.StatusSuccess,
|
||||
BaseModel: model.BaseModel{
|
||||
CreatedAt: formatTime,
|
||||
UpdatedAt: formatTime,
|
||||
},
|
||||
}
|
||||
if err := snapshotRepo.Create(&itemSnap); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *SnapshotService) UpdateDescription(req dto.UpdateDescription) error {
|
||||
return snapshotRepo.Update(req.ID, map[string]interface{}{"description": req.Description})
|
||||
}
|
||||
|
||||
type SnapshotJson struct {
|
||||
OldBaseDir string `json:"oldBaseDir"`
|
||||
OldDockerDataDir string `json:"oldDockerDataDir"`
|
||||
OldBackupDataDir string `json:"oldDackupDataDir"`
|
||||
OldPanelDataDir string `json:"oldPanelDataDir"`
|
||||
|
||||
BaseDir string `json:"baseDir"`
|
||||
DockerDataDir string `json:"dockerDataDir"`
|
||||
BackupDataDir string `json:"backupDataDir"`
|
||||
PanelDataDir string `json:"panelDataDir"`
|
||||
|
@ -78,15 +117,15 @@ func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate) error {
|
|||
}
|
||||
|
||||
timeNow := time.Now().Format("20060102150405")
|
||||
rootDir := fmt.Sprintf("%s/system/1panel_snapshot_%s", localDir, timeNow)
|
||||
versionItem, _ := settingRepo.Get(settingRepo.WithByKey("SystemVersion"))
|
||||
rootDir := fmt.Sprintf("%s/system/1panel_%s_%s", localDir, versionItem.Value, timeNow)
|
||||
backupPanelDir := fmt.Sprintf("%s/1panel", rootDir)
|
||||
_ = os.MkdirAll(backupPanelDir, os.ModePerm)
|
||||
backupDockerDir := fmt.Sprintf("%s/docker", rootDir)
|
||||
_ = os.MkdirAll(backupDockerDir, os.ModePerm)
|
||||
|
||||
versionItem, _ := settingRepo.Get(settingRepo.WithByKey("SystemVersion"))
|
||||
snap := model.Snapshot{
|
||||
Name: "1panel_snapshot_" + timeNow,
|
||||
Name: fmt.Sprintf("1panel_%s_%s", versionItem.Value, timeNow),
|
||||
Description: req.Description,
|
||||
From: req.From,
|
||||
Version: versionItem.Value,
|
||||
|
@ -139,13 +178,19 @@ func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate) error {
|
|||
return
|
||||
}
|
||||
|
||||
snapJson := SnapshotJson{DockerDataDir: dockerDataDir, BackupDataDir: localDir, PanelDataDir: global.CONF.BaseDir + "/1panel", LiveRestoreEnabled: liveRestoreStatus}
|
||||
snapJson := SnapshotJson{
|
||||
BaseDir: global.CONF.BaseDir,
|
||||
DockerDataDir: dockerDataDir,
|
||||
BackupDataDir: localDir,
|
||||
PanelDataDir: global.CONF.BaseDir + "/1panel",
|
||||
LiveRestoreEnabled: liveRestoreStatus,
|
||||
}
|
||||
if err := u.saveJson(snapJson, rootDir); err != nil {
|
||||
updateSnapshotStatus(snap.ID, constant.StatusFailed, fmt.Sprintf("save snapshot json failed, err: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
if err := fileOp.Compress([]string{rootDir}, fmt.Sprintf("%s/system", localDir), fmt.Sprintf("1panel_snapshot_%s.tar.gz", timeNow), files.TarGz); err != nil {
|
||||
if err := fileOp.Compress([]string{rootDir}, fmt.Sprintf("%s/system", localDir), fmt.Sprintf("1panel_%s_%s.tar.gz", versionItem.Value, timeNow), files.TarGz); err != nil {
|
||||
updateSnapshotStatus(snap.ID, constant.StatusFailed, err.Error())
|
||||
return
|
||||
}
|
||||
|
@ -154,14 +199,14 @@ func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate) error {
|
|||
|
||||
global.LOG.Infof("start to upload snapshot to %s, please wait", backup.Type)
|
||||
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusUploading})
|
||||
localPath := fmt.Sprintf("%s/system/1panel_snapshot_%s.tar.gz", localDir, timeNow)
|
||||
if ok, err := backupAccont.Upload(localPath, fmt.Sprintf("system_snapshot/1panel_snapshot_%s.tar.gz", timeNow)); err != nil || !ok {
|
||||
localPath := fmt.Sprintf("%s/system/1panel_%s_%s.tar.gz", localDir, versionItem.Value, timeNow)
|
||||
if ok, err := backupAccont.Upload(localPath, fmt.Sprintf("system_snapshot/1panel_%s_%s.tar.gz", versionItem.Value, timeNow)); err != nil || !ok {
|
||||
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
|
||||
global.LOG.Errorf("upload snapshot to %s failed, err: %v", backup.Type, err)
|
||||
return
|
||||
}
|
||||
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusSuccess})
|
||||
_ = os.RemoveAll(fmt.Sprintf("%s/system/1panel_snapshot_%s.tar.gz", localDir, timeNow))
|
||||
_ = os.RemoveAll(fmt.Sprintf("%s/system/1panel_%s_%s.tar.gz", localDir, versionItem.Value, timeNow))
|
||||
|
||||
global.LOG.Infof("upload snapshot to %s success", backup.Type)
|
||||
}()
|
||||
|
@ -230,8 +275,6 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
|
|||
isReTry = false
|
||||
}
|
||||
rootDir := fmt.Sprintf("%s/%s", baseDir, snap.Name)
|
||||
u.OriginalPath = fmt.Sprintf("%s/original_%s", global.CONF.BaseDir, snap.Name)
|
||||
_ = os.MkdirAll(u.OriginalPath, os.ModePerm)
|
||||
|
||||
snapJson, err := u.readFromJson(fmt.Sprintf("%s/snapshot.json", rootDir))
|
||||
if err != nil {
|
||||
|
@ -241,7 +284,10 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
|
|||
if snap.InterruptStep == "Readjson" {
|
||||
isReTry = false
|
||||
}
|
||||
u.OriginalPath = fmt.Sprintf("%s/original_%s", snapJson.BaseDir, snap.Name)
|
||||
_ = os.MkdirAll(u.OriginalPath, os.ModePerm)
|
||||
|
||||
snapJson.OldBaseDir = global.CONF.BaseDir
|
||||
snapJson.OldPanelDataDir = global.CONF.BaseDir + "/1panel"
|
||||
snapJson.OldBackupDataDir = localDir
|
||||
recoverPanelDir := fmt.Sprintf("%s/%s/1panel", baseDir, snap.Name)
|
||||
|
@ -340,10 +386,6 @@ func (u *SnapshotService) SnapshotRollback(req dto.SnapshotRecover) error {
|
|||
fileOp := files.NewFileOp()
|
||||
|
||||
rootDir := fmt.Sprintf("%s/system/%s/%s", localDir, snap.Name, snap.Name)
|
||||
u.OriginalPath = fmt.Sprintf("%s/original_%s", global.CONF.BaseDir, snap.Name)
|
||||
if _, err := os.Stat(u.OriginalPath); err != nil && os.IsNotExist(err) {
|
||||
return fmt.Errorf("load original dir failed, err: %s", err)
|
||||
}
|
||||
|
||||
_ = settingRepo.Update("SystemStatus", "Rollbacking")
|
||||
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"rollback_status": constant.StatusWaiting})
|
||||
|
@ -353,6 +395,10 @@ func (u *SnapshotService) SnapshotRollback(req dto.SnapshotRecover) error {
|
|||
updateRollbackStatus(snap.ID, constant.StatusFailed, fmt.Sprintf("decompress file failed, err: %v", err))
|
||||
return
|
||||
}
|
||||
u.OriginalPath = fmt.Sprintf("%s/original_%s", snapJson.OldBaseDir, snap.Name)
|
||||
if _, err := os.Stat(u.OriginalPath); err != nil && os.IsNotExist(err) {
|
||||
return
|
||||
}
|
||||
|
||||
_, _ = cmd.Exec("systemctl stop docker")
|
||||
if err := u.handleDockerDatas(fileOp, "rollback", u.OriginalPath, snapJson.OldDockerDataDir); err != nil {
|
||||
|
|
|
@ -58,7 +58,7 @@ func (u *UpgradeService) SearchUpgrade() (*dto.UpgradeInfo, error) {
|
|||
}
|
||||
if len(releaseInfo.NewVersion) != 0 {
|
||||
isNew, err := compareVersion(currentVersion.Value, releaseInfo.NewVersion)
|
||||
if !isNew && err != nil {
|
||||
if !isNew || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &releaseInfo, nil
|
||||
|
|
|
@ -17,6 +17,7 @@ func (s *BackupRouter) InitBackupRouter(Router *gin.RouterGroup) {
|
|||
baseApi := v1.ApiGroupApp.BaseApi
|
||||
{
|
||||
baRouter.GET("/search", baseApi.ListBackup)
|
||||
baRouter.POST("/search/files", baseApi.LoadFilesFromBackup)
|
||||
baRouter.POST("/buckets", baseApi.ListBuckets)
|
||||
baRouter.POST("", baseApi.CreateBackup)
|
||||
baRouter.POST("/del", baseApi.DeleteBackup)
|
||||
|
|
|
@ -27,9 +27,11 @@ func (s *SettingRouter) InitSettingRouter(Router *gin.RouterGroup) {
|
|||
settingRouter.POST("/mfa/bind", baseApi.MFABind)
|
||||
settingRouter.POST("/snapshot", baseApi.CreateSnapshot)
|
||||
settingRouter.POST("/snapshot/search", baseApi.SearchSnapshot)
|
||||
settingRouter.POST("/snapshot/import", baseApi.ImportSnapshot)
|
||||
settingRouter.POST("/snapshot/del", baseApi.DeleteSnapshot)
|
||||
settingRouter.POST("/snapshot/recover", baseApi.RecoverSnapshot)
|
||||
settingRouter.POST("/snapshot/rollback", baseApi.RollbackSnapshot)
|
||||
settingRouter.POST("/snapshot/description/update", baseApi.UpdateSnapDescription)
|
||||
settingRouter.POST("/upgrade", baseApi.Upgrade)
|
||||
settingRouter.GET("/upgrade", baseApi.GetUpgradeInfo)
|
||||
settingRouter.GET("/basedir", baseApi.LoadBaseDir)
|
||||
|
|
|
@ -15,7 +15,7 @@ func init() {
|
|||
}
|
||||
|
||||
var userinfoCmd = &cobra.Command{
|
||||
Use: "userinfo",
|
||||
Use: "user-info",
|
||||
Short: "获取用户信息",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
fullPath := "/opt/1panel/db/1Panel.db"
|
|
@ -1169,6 +1169,42 @@ var doc = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/backups/search/files": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取备份账号内文件列表",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Backup Account"
|
||||
],
|
||||
"summary": "List files from backup accounts",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.BackupSearchFile"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "anrry"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/backups/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
|
@ -3907,7 +3943,7 @@ var doc = `{
|
|||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.MysqlDescription"
|
||||
"$ref": "#/definitions/dto.UpdateDescription"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -6285,7 +6321,7 @@ var doc = `{
|
|||
"tags": [
|
||||
"System Setting"
|
||||
],
|
||||
"summary": "Create system backup",
|
||||
"summary": "Create system snapshot",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
|
@ -6365,6 +6401,101 @@ var doc = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/settings/snapshot/description/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "更新快照描述信息",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"System Setting"
|
||||
],
|
||||
"summary": "Update snapshot description",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UpdateDescription"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [
|
||||
{
|
||||
"db": "snapshots",
|
||||
"input_colume": "id",
|
||||
"input_value": "id",
|
||||
"isList": false,
|
||||
"output_colume": "name",
|
||||
"output_value": "name"
|
||||
}
|
||||
],
|
||||
"bodyKeys": [
|
||||
"id",
|
||||
"description"
|
||||
],
|
||||
"formatEN": "The description of the snapshot [name] is modified =\u003e [description]",
|
||||
"formatZH": "快照 [name] 描述信息修改 [description]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/snapshot/import": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "导入已有快照",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"System Setting"
|
||||
],
|
||||
"summary": "Import system snapshot",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SnapshotImport"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"from",
|
||||
"names"
|
||||
],
|
||||
"formatEN": "Sync system snapshots [names] from [from]",
|
||||
"formatZH": "从 [from] 同步系统快照 [names]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/snapshot/recover": {
|
||||
"post": {
|
||||
"security": [
|
||||
|
@ -8474,6 +8605,17 @@ var doc = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"dto.BackupSearchFile": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.BatchDelete": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
@ -9751,20 +9893,6 @@ var doc = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"dto.MysqlDescription": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.MysqlStatus": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -10451,6 +10579,23 @@ var doc = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"dto.SnapshotImport": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"from": {
|
||||
"type": "string"
|
||||
},
|
||||
"names": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SnapshotRecover": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
@ -10468,6 +10613,20 @@ var doc = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"dto.UpdateDescription": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.Upgrade": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
@ -1155,6 +1155,42 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/backups/search/files": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取备份账号内文件列表",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Backup Account"
|
||||
],
|
||||
"summary": "List files from backup accounts",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.BackupSearchFile"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "anrry"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/backups/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
|
@ -3893,7 +3929,7 @@
|
|||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.MysqlDescription"
|
||||
"$ref": "#/definitions/dto.UpdateDescription"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -6271,7 +6307,7 @@
|
|||
"tags": [
|
||||
"System Setting"
|
||||
],
|
||||
"summary": "Create system backup",
|
||||
"summary": "Create system snapshot",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
|
@ -6351,6 +6387,101 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/settings/snapshot/description/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "更新快照描述信息",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"System Setting"
|
||||
],
|
||||
"summary": "Update snapshot description",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UpdateDescription"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [
|
||||
{
|
||||
"db": "snapshots",
|
||||
"input_colume": "id",
|
||||
"input_value": "id",
|
||||
"isList": false,
|
||||
"output_colume": "name",
|
||||
"output_value": "name"
|
||||
}
|
||||
],
|
||||
"bodyKeys": [
|
||||
"id",
|
||||
"description"
|
||||
],
|
||||
"formatEN": "The description of the snapshot [name] is modified =\u003e [description]",
|
||||
"formatZH": "快照 [name] 描述信息修改 [description]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/snapshot/import": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "导入已有快照",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"System Setting"
|
||||
],
|
||||
"summary": "Import system snapshot",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SnapshotImport"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"from",
|
||||
"names"
|
||||
],
|
||||
"formatEN": "Sync system snapshots [names] from [from]",
|
||||
"formatZH": "从 [from] 同步系统快照 [names]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/settings/snapshot/recover": {
|
||||
"post": {
|
||||
"security": [
|
||||
|
@ -8460,6 +8591,17 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"dto.BackupSearchFile": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.BatchDelete": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
@ -9737,20 +9879,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"dto.MysqlDescription": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.MysqlStatus": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -10437,6 +10565,23 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"dto.SnapshotImport": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"from": {
|
||||
"type": "string"
|
||||
},
|
||||
"names": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.SnapshotRecover": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
@ -10454,6 +10599,20 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"dto.UpdateDescription": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.Upgrade": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
@ -28,6 +28,13 @@ definitions:
|
|||
- type
|
||||
- vars
|
||||
type: object
|
||||
dto.BackupSearchFile:
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
- type
|
||||
type: object
|
||||
dto.BatchDelete:
|
||||
properties:
|
||||
names:
|
||||
|
@ -890,15 +897,6 @@ definitions:
|
|||
required:
|
||||
- id
|
||||
type: object
|
||||
dto.MysqlDescription:
|
||||
properties:
|
||||
description:
|
||||
type: string
|
||||
id:
|
||||
type: integer
|
||||
required:
|
||||
- id
|
||||
type: object
|
||||
dto.MysqlStatus:
|
||||
properties:
|
||||
Aborted_clients:
|
||||
|
@ -1354,6 +1352,17 @@ definitions:
|
|||
required:
|
||||
- from
|
||||
type: object
|
||||
dto.SnapshotImport:
|
||||
properties:
|
||||
description:
|
||||
type: string
|
||||
from:
|
||||
type: string
|
||||
names:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
dto.SnapshotRecover:
|
||||
properties:
|
||||
id:
|
||||
|
@ -1365,6 +1374,15 @@ definitions:
|
|||
required:
|
||||
- id
|
||||
type: object
|
||||
dto.UpdateDescription:
|
||||
properties:
|
||||
description:
|
||||
type: string
|
||||
id:
|
||||
type: integer
|
||||
required:
|
||||
- id
|
||||
type: object
|
||||
dto.Upgrade:
|
||||
properties:
|
||||
version:
|
||||
|
@ -3358,6 +3376,28 @@ paths:
|
|||
summary: List buckets
|
||||
tags:
|
||||
- Backup Account
|
||||
/backups/search/files:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 获取备份账号内文件列表
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.BackupSearchFile'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
type: anrry
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: List files from backup accounts
|
||||
tags:
|
||||
- Backup Account
|
||||
/backups/update:
|
||||
post:
|
||||
consumes:
|
||||
|
@ -5100,7 +5140,7 @@ paths:
|
|||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.MysqlDescription'
|
||||
$ref: '#/definitions/dto.UpdateDescription'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
|
@ -6621,7 +6661,7 @@ paths:
|
|||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Create system backup
|
||||
summary: Create system snapshot
|
||||
tags:
|
||||
- System Setting
|
||||
x-panel-log:
|
||||
|
@ -6665,6 +6705,68 @@ paths:
|
|||
formatEN: Delete system backup [name]
|
||||
formatZH: 删除系统快照 [name]
|
||||
paramKeys: []
|
||||
/settings/snapshot/description/update:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 更新快照描述信息
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.UpdateDescription'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Update snapshot description
|
||||
tags:
|
||||
- System Setting
|
||||
x-panel-log:
|
||||
BeforeFuntions:
|
||||
- db: snapshots
|
||||
input_colume: id
|
||||
input_value: id
|
||||
isList: false
|
||||
output_colume: name
|
||||
output_value: name
|
||||
bodyKeys:
|
||||
- id
|
||||
- description
|
||||
formatEN: The description of the snapshot [name] is modified => [description]
|
||||
formatZH: 快照 [name] 描述信息修改 [description]
|
||||
paramKeys: []
|
||||
/settings/snapshot/import:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 导入已有快照
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.SnapshotImport'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Import system snapshot
|
||||
tags:
|
||||
- System Setting
|
||||
x-panel-log:
|
||||
BeforeFuntions: []
|
||||
bodyKeys:
|
||||
- from
|
||||
- names
|
||||
formatEN: Sync system snapshots [names] from [from]
|
||||
formatZH: 从 [from] 同步系统快照 [names]
|
||||
paramKeys: []
|
||||
/settings/snapshot/recover:
|
||||
post:
|
||||
consumes:
|
||||
|
|
|
@ -5,10 +5,6 @@ export namespace Database {
|
|||
mysqlName: string;
|
||||
dbName: string;
|
||||
}
|
||||
export interface DescriptionUpdate {
|
||||
id: number;
|
||||
description: string;
|
||||
}
|
||||
export interface Backup {
|
||||
mysqlName: string;
|
||||
dbName: string;
|
||||
|
|
|
@ -28,6 +28,10 @@ export interface CommonModel {
|
|||
CreatedAt?: string;
|
||||
UpdatedAt?: string;
|
||||
}
|
||||
export interface DescriptionUpdate {
|
||||
id: number;
|
||||
description: string;
|
||||
}
|
||||
|
||||
// * 文件上传模块
|
||||
export namespace Upload {
|
||||
|
|
|
@ -53,6 +53,11 @@ export namespace Setting {
|
|||
from: string;
|
||||
description: string;
|
||||
}
|
||||
export interface SnapshotImport {
|
||||
from: string;
|
||||
names: Array<string>;
|
||||
description: string;
|
||||
}
|
||||
export interface SnapshotRecover {
|
||||
id: number;
|
||||
isNew: boolean;
|
||||
|
|
|
@ -6,6 +6,10 @@ export const getBackupList = () => {
|
|||
return http.get<Array<Backup.BackupInfo>>(`/backups/search`);
|
||||
};
|
||||
|
||||
export const getFilesFromBackup = (type: string) => {
|
||||
return http.post<Array<any>>(`/backups/search/files`, { type: type });
|
||||
};
|
||||
|
||||
export const addBackup = (params: Backup.BackupOperate) => {
|
||||
return http.post<Backup.BackupOperate>(`/backups`, params);
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import http from '@/api';
|
||||
import { SearchWithPage, ReqPage, ResPage } from '../interface';
|
||||
import { SearchWithPage, ReqPage, ResPage, DescriptionUpdate } from '../interface';
|
||||
import { Database } from '../interface/database';
|
||||
|
||||
export const searchMysqlDBs = (params: SearchWithPage) => {
|
||||
|
@ -25,7 +25,7 @@ export const updateMysqlAccess = (params: Database.ChangeInfo) => {
|
|||
export const updateMysqlPassword = (params: Database.ChangeInfo) => {
|
||||
return http.post(`/databases/change/password`, params);
|
||||
};
|
||||
export const updateMysqlDescription = (params: Database.DescriptionUpdate) => {
|
||||
export const updateMysqlDescription = (params: DescriptionUpdate) => {
|
||||
return http.post(`/databases/description/update`, params);
|
||||
};
|
||||
export const updateMysqlVariables = (params: Array<Database.VariablesUpdate>) => {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import http from '@/api';
|
||||
import { ResPage, SearchWithPage } from '../interface';
|
||||
import { ResPage, SearchWithPage, DescriptionUpdate } from '../interface';
|
||||
import { Setting } from '../interface/setting';
|
||||
|
||||
export const getSettingInfo = () => {
|
||||
|
@ -53,6 +53,12 @@ export const loadBaseDir = () => {
|
|||
export const snapshotCreate = (param: Setting.SnapshotCreate) => {
|
||||
return http.post(`/settings/snapshot`, param);
|
||||
};
|
||||
export const snapshotImport = (param: Setting.SnapshotImport) => {
|
||||
return http.post(`/settings/snapshot/import`, param);
|
||||
};
|
||||
export const updateSnapshotDescription = (param: DescriptionUpdate) => {
|
||||
return http.post(`/settings/snapshot/description/update`, param);
|
||||
};
|
||||
export const snapshotDelete = (param: { ids: number[] }) => {
|
||||
return http.post(`/settings/snapshot/del`, param);
|
||||
};
|
||||
|
|
|
@ -770,6 +770,7 @@ export default {
|
|||
thirdPartySupport: 'Only third-party accounts are supported',
|
||||
recoverDetail: 'Recover detail',
|
||||
createSnapshot: 'Create snapshot',
|
||||
importSnapshot: 'Sync snapshot',
|
||||
recover: 'Recover',
|
||||
noRecoverRecord: 'No recovery record has been recorded',
|
||||
lastRecoverAt: 'Last recovery time',
|
||||
|
|
|
@ -768,6 +768,7 @@ export default {
|
|||
thirdPartySupport: '仅支持第三方账号',
|
||||
recoverDetail: '恢复详情',
|
||||
createSnapshot: '创建快照',
|
||||
importSnapshot: '同步快照',
|
||||
recover: '恢复',
|
||||
noRecoverRecord: '暂无恢复记录',
|
||||
lastRecoverAt: '上次恢复时间',
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
<template>
|
||||
<div v-loading="loading">
|
||||
<el-drawer v-model="drawerVisiable" size="50%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="$t('setting.importSnapshot')" :back="handleClose" />
|
||||
</template>
|
||||
<el-form ref="formRef" label-position="top" :model="form" :rules="rules">
|
||||
<el-row type="flex" justify="center">
|
||||
<el-col :span="22">
|
||||
<el-form-item :label="$t('setting.backupAccount')" prop="from">
|
||||
<el-select style="width: 100%" v-model="form.from" @change="loadFiles" clearable>
|
||||
<el-option
|
||||
v-for="item in backupOptions"
|
||||
:key="item.label"
|
||||
:value="item.value"
|
||||
:label="item.label"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('commons.table.name')" prop="names">
|
||||
<el-select style="width: 100%" v-model="form.names" multiple clearable>
|
||||
<el-option v-for="item in fileNames" :key="item" :value="item" :label="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('commons.table.description')" prop="description">
|
||||
<el-input type="textarea" clearable v-model="form.description" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button :disabled="loading" @click="drawerVisiable = false">
|
||||
{{ $t('commons.button.cancel') }}
|
||||
</el-button>
|
||||
<el-button :disabled="loading" type="primary" @click="submitImport(formRef)">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref } from 'vue';
|
||||
import { ElMessage, FormInstance } from 'element-plus';
|
||||
import i18n from '@/lang';
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { snapshotImport } from '@/api/modules/setting';
|
||||
import { getBackupList, getFilesFromBackup } from '@/api/modules/backup';
|
||||
import { loadBackupName } from '../../helper';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
|
||||
const drawerVisiable = ref(false);
|
||||
const loading = ref();
|
||||
|
||||
const formRef = ref();
|
||||
const backupOptions = ref();
|
||||
const fileNames = ref();
|
||||
|
||||
const form = reactive({
|
||||
from: '',
|
||||
names: [],
|
||||
description: '',
|
||||
});
|
||||
|
||||
const rules = reactive({
|
||||
from: [Rules.requiredSelect],
|
||||
name: [Rules.requiredSelect],
|
||||
});
|
||||
|
||||
const acceptParams = (): void => {
|
||||
form.from = '';
|
||||
form.names = [] as Array<string>;
|
||||
loadBackups();
|
||||
drawerVisiable.value = true;
|
||||
};
|
||||
const emit = defineEmits(['search']);
|
||||
|
||||
const handleClose = () => {
|
||||
drawerVisiable.value = false;
|
||||
};
|
||||
|
||||
const submitImport = async (formEl: FormInstance | undefined) => {
|
||||
loading.value = true;
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
await snapshotImport(form)
|
||||
.then(() => {
|
||||
emit('search');
|
||||
loading.value = false;
|
||||
drawerVisiable.value = false;
|
||||
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const loadBackups = async () => {
|
||||
const res = await getBackupList();
|
||||
backupOptions.value = [];
|
||||
for (const item of res.data) {
|
||||
if (item.type !== 'LOCAL' && item.id !== 0) {
|
||||
backupOptions.value.push({ label: loadBackupName(item.type), value: item.type });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const loadFiles = async () => {
|
||||
const res = await getFilesFromBackup(form.from);
|
||||
fileNames.value = res.data || [];
|
||||
for (let i = 0; i < fileNames.value.length; i++) {
|
||||
fileNames.value[i] = fileNames.value[i].replaceAll('system_snapshot/', '');
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
|
@ -7,6 +7,9 @@
|
|||
<el-button type="primary" @click="onCreate()">
|
||||
{{ $t('setting.createSnapshot') }}
|
||||
</el-button>
|
||||
<el-button @click="onImport()">
|
||||
{{ $t('setting.importSnapshot') }}
|
||||
</el-button>
|
||||
<el-button type="primary" plain :disabled="selects.length === 0" @click="batchDelete(null)">
|
||||
{{ $t('commons.button.delete') }}
|
||||
</el-button>
|
||||
|
@ -43,14 +46,9 @@
|
|||
prop="name"
|
||||
fix
|
||||
/>
|
||||
<el-table-column
|
||||
:label="$t('commons.table.description')"
|
||||
min-width="150"
|
||||
show-overflow-tooltip
|
||||
prop="description"
|
||||
/>
|
||||
<el-table-column :label="$t('setting.backupAccount')" min-width="150" prop="from" />
|
||||
<el-table-column :label="$t('setting.backup')" min-width="80" prop="status">
|
||||
<el-table-column prop="version" :label="$t('app.version')" />
|
||||
<el-table-column :label="$t('setting.backupAccount')" min-width="80" prop="from" />
|
||||
<el-table-column :label="$t('commons.table.status')" min-width="80" prop="status">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.status === 'Success'" type="success">
|
||||
{{ $t('commons.table.statusSuccess') }}
|
||||
|
@ -72,6 +70,13 @@
|
|||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('commons.table.description')" prop="description">
|
||||
<template #default="{ row }">
|
||||
<fu-read-write-switch :data="row.description" v-model="row.edit" @change="onChange(row)">
|
||||
<el-input v-model="row.description" @blur="row.edit = false" />
|
||||
</fu-read-write-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="createdAt"
|
||||
:label="$t('commons.table.date')"
|
||||
|
@ -89,6 +94,7 @@
|
|||
</template>
|
||||
</LayoutContent>
|
||||
<RecoverStatus ref="recoverStatusRef" @search="search()"></RecoverStatus>
|
||||
<SnapshotImport ref="importRef" @search="search()" />
|
||||
<el-drawer v-model="drawerVisiable" size="50%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="$t('setting.createSnapshot')" :back="handleClose" />
|
||||
|
@ -139,7 +145,7 @@
|
|||
<script setup lang="ts">
|
||||
import ComplexTable from '@/components/complex-table/index.vue';
|
||||
import TableSetting from '@/components/table-setting/index.vue';
|
||||
import { snapshotCreate, searchSnapshotPage, snapshotDelete } from '@/api/modules/setting';
|
||||
import { snapshotCreate, searchSnapshotPage, snapshotDelete, updateSnapshotDescription } from '@/api/modules/setting';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { dateFormat } from '@/utils/util';
|
||||
import { useDeleteData } from '@/hooks/use-delete-data';
|
||||
|
@ -150,6 +156,7 @@ import { ElMessage } from 'element-plus';
|
|||
import { Setting } from '@/api/interface/setting';
|
||||
import LayoutContent from '@/layout/layout-content.vue';
|
||||
import RecoverStatus from '@/views/setting/snapshot/status/index.vue';
|
||||
import SnapshotImport from '@/views/setting/snapshot/import/index.vue';
|
||||
import { getBackupList } from '@/api/modules/backup';
|
||||
import { loadBackupName } from '../helper';
|
||||
|
||||
|
@ -164,6 +171,7 @@ const paginationConfig = reactive({
|
|||
const searchName = ref();
|
||||
|
||||
const recoverStatusRef = ref();
|
||||
const importRef = ref();
|
||||
const isRecordShow = ref();
|
||||
const backupOptions = ref();
|
||||
type FormInstance = InstanceType<typeof ElForm>;
|
||||
|
@ -184,10 +192,21 @@ const onCreate = async () => {
|
|||
drawerVisiable.value = true;
|
||||
};
|
||||
|
||||
const onImport = () => {
|
||||
importRef.value.acceptParams();
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
drawerVisiable.value = false;
|
||||
};
|
||||
|
||||
const onChange = async (info: any) => {
|
||||
if (!info.edit) {
|
||||
await updateSnapshotDescription({ id: info.id, description: info.description });
|
||||
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
||||
}
|
||||
};
|
||||
|
||||
const submitAddSnapshot = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
|
|
Loading…
Reference in New Issue