mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-09-12 17:46:20 +08:00
feat: 完成数据库前端页面
This commit is contained in:
parent
b2653c2aef
commit
2c529e8fa3
22 changed files with 790 additions and 52 deletions
63
backend/app/api/v1/databse_mysql.go
Normal file
63
backend/app/api/v1/databse_mysql.go
Normal file
|
@ -0,0 +1,63 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"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"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func (b *BaseApi) CreateMysql(c *gin.Context) {
|
||||
var req dto.MysqlDBCreate
|
||||
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 := mysqlService.Create(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
func (b *BaseApi) SearchMysql(c *gin.Context) {
|
||||
var req dto.SearchWithPage
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
|
||||
total, list, err := mysqlService.SearchWithPage(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) DeleteMysql(c *gin.Context) {
|
||||
var req dto.BatchDeleteReq
|
||||
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 := mysqlService.Delete(req.Ids); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
|
@ -9,18 +9,26 @@ type ApiGroup struct {
|
|||
var ApiGroupApp = new(ApiGroup)
|
||||
|
||||
var (
|
||||
authService = service.ServiceGroupApp.AuthService
|
||||
hostService = service.ServiceGroupApp.HostService
|
||||
backupService = service.ServiceGroupApp.BackupService
|
||||
groupService = service.ServiceGroupApp.GroupService
|
||||
authService = service.ServiceGroupApp.AuthService
|
||||
|
||||
appService = service.ServiceGroupApp.AppService
|
||||
|
||||
containerService = service.ServiceGroupApp.ContainerService
|
||||
composeTemplateService = service.ServiceGroupApp.ComposeTemplateService
|
||||
imageRepoService = service.ServiceGroupApp.ImageRepoService
|
||||
imageService = service.ServiceGroupApp.ImageService
|
||||
commandService = service.ServiceGroupApp.CommandService
|
||||
operationService = service.ServiceGroupApp.OperationService
|
||||
fileService = service.ServiceGroupApp.FileService
|
||||
cronjobService = service.ServiceGroupApp.CronjobService
|
||||
settingService = service.ServiceGroupApp.SettingService
|
||||
appService = service.ServiceGroupApp.AppService
|
||||
|
||||
mysqlService = service.ServiceGroupApp.MysqlService
|
||||
|
||||
cronjobService = service.ServiceGroupApp.CronjobService
|
||||
|
||||
hostService = service.ServiceGroupApp.HostService
|
||||
groupService = service.ServiceGroupApp.GroupService
|
||||
commandService = service.ServiceGroupApp.CommandService
|
||||
fileService = service.ServiceGroupApp.FileService
|
||||
|
||||
settingService = service.ServiceGroupApp.SettingService
|
||||
backupService = service.ServiceGroupApp.BackupService
|
||||
|
||||
operationService = service.ServiceGroupApp.OperationService
|
||||
)
|
||||
|
|
24
backend/app/dto/database.go
Normal file
24
backend/app/dto/database.go
Normal file
|
@ -0,0 +1,24 @@
|
|||
package dto
|
||||
|
||||
import "time"
|
||||
|
||||
type MysqlDBInfo struct {
|
||||
ID uint `json:"id"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
Name string `json:"name"`
|
||||
Format string `json:"format"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Permission string `json:"permission"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type MysqlDBCreate struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Format string `json:"format" validate:"required,oneof=utf8mb4 utf-8 gbk big5"`
|
||||
Username string `json:"username" validate:"required"`
|
||||
Password string `json:"password" validate:"required"`
|
||||
Permission string `json:"permission" validate:"required,oneof=local all ip"`
|
||||
PermissionIPs string `json:"permissionIPs"`
|
||||
Description string `json:"description"`
|
||||
}
|
12
backend/app/model/database_mysql.go
Normal file
12
backend/app/model/database_mysql.go
Normal file
|
@ -0,0 +1,12 @@
|
|||
package model
|
||||
|
||||
type DatabaseMysql struct {
|
||||
BaseModel
|
||||
Name string `json:"name" gorm:"type:varchar(256);not null"`
|
||||
Format string `json:"format" gorm:"type:varchar(64);not null"`
|
||||
Username string `json:"username" gorm:"type:varchar(256);not null"`
|
||||
Password string `json:"password" gorm:"type:varchar(256);not null"`
|
||||
Permission string `json:"permission" gorm:"type:varchar(256);not null"`
|
||||
PermissionIPs string `json:"permissionIPs" gorm:"type:varchar(256)"`
|
||||
Description string `json:"description" gorm:"type:varchar(256);"`
|
||||
}
|
52
backend/app/repo/databse_mysql.go
Normal file
52
backend/app/repo/databse_mysql.go
Normal file
|
@ -0,0 +1,52 @@
|
|||
package repo
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
)
|
||||
|
||||
type MysqlRepo struct{}
|
||||
|
||||
type IMysqlRepo interface {
|
||||
Page(limit, offset int, opts ...DBOption) (int64, []model.DatabaseMysql, error)
|
||||
Create(mysql *model.DatabaseMysql) error
|
||||
Delete(opts ...DBOption) error
|
||||
}
|
||||
|
||||
func NewIMysqlRepo() IMysqlRepo {
|
||||
return &MysqlRepo{}
|
||||
}
|
||||
|
||||
func (u *MysqlRepo) Get(opts ...DBOption) (model.DatabaseMysql, error) {
|
||||
var mysql model.DatabaseMysql
|
||||
db := global.DB
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
err := db.First(&mysql).Error
|
||||
return mysql, err
|
||||
}
|
||||
|
||||
func (u *MysqlRepo) Page(page, size int, opts ...DBOption) (int64, []model.DatabaseMysql, error) {
|
||||
var users []model.DatabaseMysql
|
||||
db := global.DB.Model(&model.DatabaseMysql{})
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
count := int64(0)
|
||||
db = db.Count(&count)
|
||||
err := db.Limit(size).Offset(size * (page - 1)).Find(&users).Error
|
||||
return count, users, err
|
||||
}
|
||||
|
||||
func (u *MysqlRepo) Create(mysql *model.DatabaseMysql) error {
|
||||
return global.DB.Create(mysql).Error
|
||||
}
|
||||
|
||||
func (u *MysqlRepo) Delete(opts ...DBOption) error {
|
||||
db := global.DB
|
||||
for _, opt := range opts {
|
||||
db = opt(db)
|
||||
}
|
||||
return db.Delete(&model.DatabaseMysql{}).Error
|
||||
}
|
|
@ -1,16 +1,8 @@
|
|||
package repo
|
||||
|
||||
type RepoGroup struct {
|
||||
HostRepo
|
||||
BackupRepo
|
||||
GroupRepo
|
||||
ImageRepoRepo
|
||||
ComposeTemplateRepo
|
||||
CommandRepo
|
||||
OperationRepo
|
||||
CommonRepo
|
||||
CronjobRepo
|
||||
SettingRepo
|
||||
|
||||
AppRepo
|
||||
AppTagRepo
|
||||
TagRepo
|
||||
|
@ -19,6 +11,22 @@ type RepoGroup struct {
|
|||
AppInstallResourceRpo
|
||||
DatabaseRepo
|
||||
AppInstallBackupRepo
|
||||
|
||||
ImageRepoRepo
|
||||
ComposeTemplateRepo
|
||||
|
||||
MysqlRepo
|
||||
|
||||
CronjobRepo
|
||||
|
||||
HostRepo
|
||||
CommandRepo
|
||||
GroupRepo
|
||||
|
||||
SettingRepo
|
||||
BackupRepo
|
||||
|
||||
OperationRepo
|
||||
}
|
||||
|
||||
var RepoGroupApp = new(RepoGroup)
|
||||
|
|
58
backend/app/service/database_mysql.go
Normal file
58
backend/app/service/database_mysql.go
Normal file
|
@ -0,0 +1,58 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type MysqlService struct{}
|
||||
|
||||
type IMysqlService interface {
|
||||
SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error)
|
||||
Create(mysqlDto dto.MysqlDBCreate) error
|
||||
Delete(ids []uint) error
|
||||
}
|
||||
|
||||
func NewIMysqlService() IMysqlService {
|
||||
return &MysqlService{}
|
||||
}
|
||||
|
||||
func (u *MysqlService) SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error) {
|
||||
total, mysqls, err := mysqlRepo.Page(search.Page, search.PageSize, commonRepo.WithLikeName(search.Info))
|
||||
var dtoMysqls []dto.MysqlDBInfo
|
||||
for _, mysql := range mysqls {
|
||||
var item dto.MysqlDBInfo
|
||||
if err := copier.Copy(&item, &mysql); err != nil {
|
||||
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
dtoMysqls = append(dtoMysqls, item)
|
||||
}
|
||||
return total, dtoMysqls, err
|
||||
}
|
||||
|
||||
func (u *MysqlService) Create(mysqlDto dto.MysqlDBCreate) error {
|
||||
mysql, _ := mysqlRepo.Get(commonRepo.WithByName(mysqlDto.Name))
|
||||
if mysql.ID != 0 {
|
||||
return constant.ErrRecordExist
|
||||
}
|
||||
if err := copier.Copy(&mysql, &mysqlDto); err != nil {
|
||||
return errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
if err := mysqlRepo.Create(&mysql); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *MysqlService) Delete(ids []uint) error {
|
||||
if len(ids) == 1 {
|
||||
mysql, _ := mysqlRepo.Get(commonRepo.WithByID(ids[0]))
|
||||
if mysql.ID == 0 {
|
||||
return constant.ErrRecordNotFound
|
||||
}
|
||||
return mysqlRepo.Delete(commonRepo.WithByID(ids[0]))
|
||||
}
|
||||
return mysqlRepo.Delete(commonRepo.WithIdsIn(ids))
|
||||
}
|
|
@ -4,34 +4,35 @@ import "github.com/1Panel-dev/1Panel/backend/app/repo"
|
|||
|
||||
type ServiceGroup struct {
|
||||
AuthService
|
||||
HostService
|
||||
BackupService
|
||||
GroupService
|
||||
ImageService
|
||||
ComposeTemplateService
|
||||
ImageRepoService
|
||||
ContainerService
|
||||
CommandService
|
||||
OperationService
|
||||
FileService
|
||||
CronjobService
|
||||
SettingService
|
||||
|
||||
AppService
|
||||
|
||||
ContainerService
|
||||
ImageService
|
||||
ImageRepoService
|
||||
ComposeTemplateService
|
||||
|
||||
MysqlService
|
||||
|
||||
CronjobService
|
||||
|
||||
HostService
|
||||
GroupService
|
||||
CommandService
|
||||
FileService
|
||||
|
||||
SettingService
|
||||
BackupService
|
||||
|
||||
OperationService
|
||||
}
|
||||
|
||||
var ServiceGroupApp = new(ServiceGroup)
|
||||
|
||||
var (
|
||||
hostRepo = repo.RepoGroupApp.HostRepo
|
||||
backupRepo = repo.RepoGroupApp.BackupRepo
|
||||
groupRepo = repo.RepoGroupApp.GroupRepo
|
||||
commandRepo = repo.RepoGroupApp.CommandRepo
|
||||
operationRepo = repo.RepoGroupApp.OperationRepo
|
||||
commonRepo = repo.RepoGroupApp.CommonRepo
|
||||
imageRepoRepo = repo.RepoGroupApp.ImageRepoRepo
|
||||
composeRepo = repo.RepoGroupApp.ComposeTemplateRepo
|
||||
cronjobRepo = repo.RepoGroupApp.CronjobRepo
|
||||
settingRepo = repo.RepoGroupApp.SettingRepo
|
||||
commonRepo = repo.RepoGroupApp.CommonRepo
|
||||
|
||||
appInstallBackupRepo = repo.RepoGroupApp.AppInstallBackupRepo
|
||||
appRepo = repo.RepoGroupApp.AppRepo
|
||||
appTagRepo = repo.RepoGroupApp.AppTagRepo
|
||||
appDetailRepo = repo.RepoGroupApp.AppDetailRepo
|
||||
|
@ -39,5 +40,20 @@ var (
|
|||
appInstallRepo = repo.RepoGroupApp.AppInstallRepo
|
||||
appInstallResourceRepo = repo.RepoGroupApp.AppInstallResourceRpo
|
||||
dataBaseRepo = repo.RepoGroupApp.DatabaseRepo
|
||||
appInstallBackupRepo = repo.RepoGroupApp.AppInstallBackupRepo
|
||||
|
||||
mysqlRepo = repo.RepoGroupApp.MysqlRepo
|
||||
|
||||
imageRepoRepo = repo.RepoGroupApp.ImageRepoRepo
|
||||
composeRepo = repo.RepoGroupApp.ComposeTemplateRepo
|
||||
|
||||
cronjobRepo = repo.RepoGroupApp.CronjobRepo
|
||||
|
||||
hostRepo = repo.RepoGroupApp.HostRepo
|
||||
groupRepo = repo.RepoGroupApp.GroupRepo
|
||||
commandRepo = repo.RepoGroupApp.CommandRepo
|
||||
|
||||
settingRepo = repo.RepoGroupApp.SettingRepo
|
||||
backupRepo = repo.RepoGroupApp.BackupRepo
|
||||
|
||||
operationRepo = repo.RepoGroupApp.OperationRepo
|
||||
)
|
||||
|
|
|
@ -17,6 +17,7 @@ func Init() {
|
|||
migrations.AddTableCronjob,
|
||||
migrations.AddTableApp,
|
||||
migrations.AddTableImageRepo,
|
||||
migrations.AddTableDatabaseMysql,
|
||||
})
|
||||
if err := m.Migrate(); err != nil {
|
||||
global.LOG.Error(err)
|
||||
|
|
|
@ -170,3 +170,10 @@ var AddTableImageRepo = &gormigrate.Migration{
|
|||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var AddTableDatabaseMysql = &gormigrate.Migration{
|
||||
ID: "20201020-add-table-database_mysql",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
return tx.AutoMigrate(&model.DatabaseMysql{})
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
|
||||
v1 "github.com/1Panel-dev/1Panel/backend/app/api/v1"
|
||||
"github.com/1Panel-dev/1Panel/backend/docs"
|
||||
"github.com/1Panel-dev/1Panel/backend/i18n"
|
||||
|
@ -11,8 +14,6 @@ import (
|
|||
"github.com/gin-gonic/gin"
|
||||
swaggerfiles "github.com/swaggo/files"
|
||||
ginSwagger "github.com/swaggo/gin-swagger"
|
||||
"html/template"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func setWebStatic(rootRouter *gin.Engine) {
|
||||
|
@ -78,6 +79,7 @@ func Routers() *gin.Engine {
|
|||
systemRouter.InitCronjobRouter(PrivateGroup)
|
||||
systemRouter.InitSettingRouter(PrivateGroup)
|
||||
systemRouter.InitAppRouter(PrivateGroup)
|
||||
systemRouter.InitDatabaseRouter(PrivateGroup)
|
||||
}
|
||||
|
||||
return Router
|
||||
|
|
|
@ -14,6 +14,7 @@ type RouterGroup struct {
|
|||
CronjobRouter
|
||||
SettingRouter
|
||||
AppRouter
|
||||
DatabaseRouter
|
||||
}
|
||||
|
||||
var RouterGroupApp = new(RouterGroup)
|
||||
|
|
28
backend/router/ro_database.go
Normal file
28
backend/router/ro_database.go
Normal file
|
@ -0,0 +1,28 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
v1 "github.com/1Panel-dev/1Panel/backend/app/api/v1"
|
||||
"github.com/1Panel-dev/1Panel/backend/middleware"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type DatabaseRouter struct{}
|
||||
|
||||
func (s *DatabaseRouter) InitDatabaseRouter(Router *gin.RouterGroup) {
|
||||
cmdRouter := Router.Group("databases").
|
||||
Use(middleware.JwtAuth()).
|
||||
Use(middleware.SessionAuth()).
|
||||
Use(middleware.PasswordExpired())
|
||||
withRecordRouter := Router.Group("databases").
|
||||
Use(middleware.JwtAuth()).
|
||||
Use(middleware.SessionAuth()).
|
||||
Use(middleware.PasswordExpired()).
|
||||
Use(middleware.OperationRecord())
|
||||
baseApi := v1.ApiGroupApp.BaseApi
|
||||
{
|
||||
withRecordRouter.POST("", baseApi.CreateMysql)
|
||||
withRecordRouter.POST("/del", baseApi.DeleteMysql)
|
||||
cmdRouter.POST("/search", baseApi.SearchMysql)
|
||||
}
|
||||
}
|
22
frontend/src/api/interface/database.ts
Normal file
22
frontend/src/api/interface/database.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
export namespace Database {
|
||||
export interface MysqlDBInfo {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
name: string;
|
||||
format: string;
|
||||
username: string;
|
||||
password: string;
|
||||
permission: string;
|
||||
permissionIPs: string;
|
||||
description: string;
|
||||
}
|
||||
export interface MysqlDBCreate {
|
||||
name: string;
|
||||
format: string;
|
||||
username: string;
|
||||
password: string;
|
||||
permission: string;
|
||||
permissionIPs: string;
|
||||
description: string;
|
||||
}
|
||||
}
|
15
frontend/src/api/modules/database.ts
Normal file
15
frontend/src/api/modules/database.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import http from '@/api';
|
||||
import { ResPage, ReqPage } from '../interface';
|
||||
import { Database } from '../interface/database';
|
||||
|
||||
export const searchMysqlDBs = (params: ReqPage) => {
|
||||
return http.post<ResPage<Database.MysqlDBInfo>>(`databases/search`, params);
|
||||
};
|
||||
|
||||
export const addMysqlDB = (params: Database.MysqlDBCreate) => {
|
||||
return http.post(`/databases`, params);
|
||||
};
|
||||
|
||||
export const deleteMysqlDB = (params: { ids: number[] }) => {
|
||||
return http.post(`/databases/del`, params);
|
||||
};
|
|
@ -150,6 +150,16 @@ export default {
|
|||
header: {
|
||||
logout: '退出登录',
|
||||
},
|
||||
database: {
|
||||
permission: '权限',
|
||||
permissionLocal: '本地服务器',
|
||||
permissionForIP: '指定 IP',
|
||||
permissionAll: '所有人(不安全)',
|
||||
rootPassword: 'root 密码',
|
||||
backupList: '备份列表',
|
||||
loadBackup: '导入备份',
|
||||
setting: '数据库设置',
|
||||
},
|
||||
container: {
|
||||
operatorHelper: '将对选中容器进行 {0} 操作,是否继续?',
|
||||
start: '启动',
|
||||
|
|
|
@ -2,19 +2,31 @@ import { Layout } from '@/routers/constant';
|
|||
|
||||
const databaseRouter = {
|
||||
sort: 4,
|
||||
path: '/database',
|
||||
path: '/databases',
|
||||
component: Layout,
|
||||
redirect: '/database',
|
||||
redirect: '/databases',
|
||||
meta: {
|
||||
icon: 'p-database',
|
||||
title: 'menu.database',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '/database',
|
||||
name: 'Database',
|
||||
component: () => import('@/views/database/index.vue'),
|
||||
meta: {},
|
||||
path: '',
|
||||
name: 'Mysql',
|
||||
component: () => import('@/views/database/mysql/index.vue'),
|
||||
hidden: true,
|
||||
meta: {
|
||||
activeMenu: '/databases',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/redis',
|
||||
name: 'Redis',
|
||||
component: () => import('@/views/database/redis/index.vue'),
|
||||
hidden: true,
|
||||
meta: {
|
||||
activeMenu: '/databases',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
@ -1,7 +1,70 @@
|
|||
<template>
|
||||
<LayoutContent></LayoutContent>
|
||||
<div>
|
||||
<el-card class="topCard">
|
||||
<el-radio-group v-model="active">
|
||||
<el-radio-button class="topButton" size="large" @click="routerTo('/databases')" label="mysql">
|
||||
Mysql
|
||||
</el-radio-button>
|
||||
<el-radio-button class="topButton" size="large" @click="routerTo('/databases/redis')" label="redis">
|
||||
Redis
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import LayoutContent from '@/layout/layout-content.vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
const router = useRouter();
|
||||
interface MenuProps {
|
||||
activeName: string;
|
||||
}
|
||||
const props = withDefaults(defineProps<MenuProps>(), {
|
||||
activeName: 'mysql',
|
||||
});
|
||||
|
||||
const active = ref('mysql');
|
||||
|
||||
onMounted(() => {
|
||||
if (props.activeName) {
|
||||
active.value = props.activeName;
|
||||
}
|
||||
});
|
||||
|
||||
const routerTo = (path: string) => {
|
||||
router.push({ path: path });
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.topCard {
|
||||
--el-card-border-color: var(--el-border-color-light);
|
||||
--el-card-border-radius: 4px;
|
||||
--el-card-padding: 0px;
|
||||
--el-card-bg-color: var(--el-fill-color-blank);
|
||||
}
|
||||
.topButton .el-radio-button__inner {
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
background: var(--el-button-bg-color, var(--el-fill-color-blank));
|
||||
border: 0;
|
||||
font-weight: 350;
|
||||
border-left: 0;
|
||||
color: var(--el-button-text-color, var(--el-text-color-regular));
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
outline: 0;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
transition: var(--el-transition-all);
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
padding: 8px 15px;
|
||||
font-size: var(--el-font-size-base);
|
||||
border-radius: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
107
frontend/src/views/database/mysql/create/index.vue
Normal file
107
frontend/src/views/database/mysql/create/index.vue
Normal file
|
@ -0,0 +1,107 @@
|
|||
<template>
|
||||
<el-dialog v-model="createVisiable" :destroy-on-close="true" :close-on-click-modal="false" width="30%">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>创建数据库</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item :label="$t('commons.table.name')" prop="name">
|
||||
<el-input clearable v-model="form.name">
|
||||
<template #append>
|
||||
<el-select v-model="form.format" style="width: 125px">
|
||||
<el-option label="utf8mb4" value="utf8mb4" />
|
||||
<el-option label="utf-8" value="utf-8" />
|
||||
<el-option label="gbk" value="gbk" />
|
||||
<el-option label="big5" value="big5" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('auth.username')" prop="username">
|
||||
<el-input clearable v-model="form.username" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('auth.password')" prop="password">
|
||||
<el-input type="password" clearable show-password v-model="form.password" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="$t('database.permission')" prop="permission">
|
||||
<el-select style="width: 100%" v-model="form.permission">
|
||||
<el-option value="local" :label="$t('database.permissionLocal')" />
|
||||
<el-option value="all" :label="$t('database.permissionAll')" />
|
||||
<el-option value="ip" :label="$t('database.permissionForIP')" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.permission === 'ip'" prop="permissionIPs">
|
||||
<el-input type="password" clearable v-model="form.permissionIPs" />
|
||||
</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-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="createVisiable = false">{{ $t('commons.button.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="onSubmit(formRef)">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import i18n from '@/lang';
|
||||
import { ElForm, ElMessage } from 'element-plus';
|
||||
import { addMysqlDB } from '@/api/modules/database';
|
||||
|
||||
const createVisiable = ref(false);
|
||||
const form = reactive({
|
||||
name: '',
|
||||
format: '',
|
||||
username: '',
|
||||
password: '',
|
||||
permission: '',
|
||||
permissionIPs: '',
|
||||
description: '',
|
||||
});
|
||||
const rules = reactive({
|
||||
name: [Rules.requiredInput, Rules.name],
|
||||
username: [Rules.requiredInput, Rules.name],
|
||||
password: [Rules.requiredInput],
|
||||
permission: [Rules.requiredSelect],
|
||||
permissionIPs: [Rules.requiredInput],
|
||||
});
|
||||
type FormInstance = InstanceType<typeof ElForm>;
|
||||
const formRef = ref<FormInstance>();
|
||||
|
||||
const acceptParams = (): void => {
|
||||
form.name = '';
|
||||
form.format = 'utf8mb4';
|
||||
form.username = '';
|
||||
form.password = '';
|
||||
form.permission = 'local';
|
||||
form.permissionIPs = '';
|
||||
form.description = '';
|
||||
createVisiable.value = true;
|
||||
};
|
||||
|
||||
const emit = defineEmits<{ (e: 'search'): void }>();
|
||||
const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
await addMysqlDB(form);
|
||||
|
||||
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
createVisiable.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
133
frontend/src/views/database/mysql/index.vue
Normal file
133
frontend/src/views/database/mysql/index.vue
Normal file
|
@ -0,0 +1,133 @@
|
|||
<template>
|
||||
<div>
|
||||
<Submenu activeName="mysql" />
|
||||
<el-dropdown size="large" split-button style="margin-top: 20px; margin-bottom: 5px">
|
||||
Mysql 版本 {{ version }}
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu v-model="version">
|
||||
<el-dropdown-item @click="version = '5.7.39'">5.7.39</el-dropdown-item>
|
||||
<el-dropdown-item @click="version = '8.0.30'">8.0.30</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<el-button style="margin-top: 20px; margin-left: 10px" size="large" icon="Setting" @click="onOpenDialog()">
|
||||
{{ $t('database.setting') }}
|
||||
</el-button>
|
||||
<el-card>
|
||||
<ComplexTable :pagination-config="paginationConfig" v-model:selects="selects" @search="search" :data="data">
|
||||
<template #toolbar>
|
||||
<el-button type="primary" @click="onOpenDialog()">{{ $t('commons.button.create') }}</el-button>
|
||||
<el-button @click="onOpenDialog()">{{ $t('database.rootPassword') }}</el-button>
|
||||
<el-button @click="onOpenDialog()">phpMyAdmin</el-button>
|
||||
<el-button 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')" prop="name" />
|
||||
<el-table-column :label="$t('auth.username')" prop="username" />
|
||||
<el-table-column :label="$t('auth.password')" prop="password" />
|
||||
<el-table-column :label="$t('commons.table.description')" prop="description" />
|
||||
<el-table-column
|
||||
prop="createdAt"
|
||||
:label="$t('commons.table.date')"
|
||||
:formatter="dateFromat"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<fu-table-operations
|
||||
width="300px"
|
||||
:buttons="buttons"
|
||||
:ellipsis="10"
|
||||
:label="$t('commons.table.operate')"
|
||||
fix
|
||||
/>
|
||||
</ComplexTable>
|
||||
</el-card>
|
||||
|
||||
<OperatrDialog @search="search" ref="dialogRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import ComplexTable from '@/components/complex-table/index.vue';
|
||||
import OperatrDialog from '@/views/database/mysql/create/index.vue';
|
||||
import Submenu from '@/views/database/index.vue';
|
||||
import { dateFromat } from '@/utils/util';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { deleteMysqlDB, searchMysqlDBs } from '@/api/modules/database';
|
||||
import i18n from '@/lang';
|
||||
import { Cronjob } from '@/api/interface/cronjob';
|
||||
import { useDeleteData } from '@/hooks/use-delete-data';
|
||||
|
||||
const selects = ref<any>([]);
|
||||
const version = ref<string>('5.7.39');
|
||||
|
||||
const data = ref();
|
||||
const paginationConfig = reactive({
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
const dialogRef = ref();
|
||||
const onOpenDialog = async () => {
|
||||
dialogRef.value!.acceptParams();
|
||||
};
|
||||
|
||||
const search = async () => {
|
||||
let params = {
|
||||
page: paginationConfig.currentPage,
|
||||
pageSize: paginationConfig.pageSize,
|
||||
};
|
||||
const res = await searchMysqlDBs(params);
|
||||
data.value = res.data.items || [];
|
||||
paginationConfig.total = res.data.total;
|
||||
};
|
||||
|
||||
const onBatchDelete = async (row: Cronjob.CronjobInfo | null) => {
|
||||
let ids: Array<number> = [];
|
||||
if (row) {
|
||||
ids.push(row.id);
|
||||
} else {
|
||||
selects.value.forEach((item: Cronjob.CronjobInfo) => {
|
||||
ids.push(item.id);
|
||||
});
|
||||
}
|
||||
await useDeleteData(deleteMysqlDB, { ids: ids }, 'commons.msg.delete', true);
|
||||
search();
|
||||
};
|
||||
const buttons = [
|
||||
{
|
||||
label: i18n.global.t('commons.button.edit'),
|
||||
icon: 'Delete',
|
||||
click: (row: Cronjob.CronjobInfo) => {
|
||||
onBatchDelete(row);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('database.backupList') + '(1)',
|
||||
icon: 'Delete',
|
||||
click: (row: Cronjob.CronjobInfo) => {
|
||||
onBatchDelete(row);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('database.loadBackup'),
|
||||
icon: 'Delete',
|
||||
click: (row: Cronjob.CronjobInfo) => {
|
||||
onBatchDelete(row);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('commons.button.delete'),
|
||||
icon: 'Delete',
|
||||
click: (row: Cronjob.CronjobInfo) => {
|
||||
onBatchDelete(row);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
onMounted(() => {
|
||||
search();
|
||||
});
|
||||
</script>
|
96
frontend/src/views/database/redis/index.vue
Normal file
96
frontend/src/views/database/redis/index.vue
Normal file
|
@ -0,0 +1,96 @@
|
|||
<template>
|
||||
<div>
|
||||
<Submenu activeName="redis" />
|
||||
<ComplexTable
|
||||
:pagination-config="paginationConfig"
|
||||
v-model:selects="selects"
|
||||
@search="search"
|
||||
style="margin-top: 20px"
|
||||
:data="data"
|
||||
>
|
||||
<template #toolbar>
|
||||
<el-button type="primary" @click="onOpenDialog()">{{ $t('commons.button.create') }}</el-button>
|
||||
<el-button 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')" prop="name" />
|
||||
<el-table-column :label="$t('auth.username')" prop="username" />
|
||||
<el-table-column :label="$t('auth.password')" prop="password" />
|
||||
<el-table-column :label="$t('commons.table.description')" prop="description" />
|
||||
<el-table-column
|
||||
prop="createdAt"
|
||||
:label="$t('commons.table.date')"
|
||||
:formatter="dateFromat"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<fu-table-operations type="icon" :buttons="buttons" :label="$t('commons.table.operate')" fix />
|
||||
</ComplexTable>
|
||||
|
||||
<OperatrDialog @search="search" ref="dialogRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import ComplexTable from '@/components/complex-table/index.vue';
|
||||
import OperatrDialog from '@/views/database/create/index.vue';
|
||||
import Submenu from '@/views/database/index.vue';
|
||||
import { dateFromat } from '@/utils/util';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { deleteMysqlDB, searchMysqlDBs } from '@/api/modules/database';
|
||||
import i18n from '@/lang';
|
||||
import { Cronjob } from '@/api/interface/cronjob';
|
||||
import { useDeleteData } from '@/hooks/use-delete-data';
|
||||
|
||||
const selects = ref<any>([]);
|
||||
|
||||
const data = ref();
|
||||
const paginationConfig = reactive({
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
const dialogRef = ref();
|
||||
const onOpenDialog = async () => {
|
||||
dialogRef.value!.acceptParams();
|
||||
};
|
||||
|
||||
const search = async () => {
|
||||
let params = {
|
||||
page: paginationConfig.currentPage,
|
||||
pageSize: paginationConfig.pageSize,
|
||||
};
|
||||
const res = await searchMysqlDBs(params);
|
||||
data.value = res.data.items || [];
|
||||
paginationConfig.total = res.data.total;
|
||||
};
|
||||
|
||||
const onBatchDelete = async (row: Cronjob.CronjobInfo | null) => {
|
||||
let ids: Array<number> = [];
|
||||
if (row) {
|
||||
ids.push(row.id);
|
||||
} else {
|
||||
selects.value.forEach((item: Cronjob.CronjobInfo) => {
|
||||
ids.push(item.id);
|
||||
});
|
||||
}
|
||||
await useDeleteData(deleteMysqlDB, { ids: ids }, 'commons.msg.delete', true);
|
||||
search();
|
||||
};
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
label: i18n.global.t('commons.button.delete'),
|
||||
icon: 'Delete',
|
||||
click: (row: Cronjob.CronjobInfo) => {
|
||||
onBatchDelete(row);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
onMounted(() => {
|
||||
search();
|
||||
});
|
||||
</script>
|
Loading…
Add table
Reference in a new issue