feat: 完成数据库前端页面

This commit is contained in:
ssongliu 2022-10-20 18:45:47 +08:00 committed by ssongliu
parent b2653c2aef
commit 2c529e8fa3
22 changed files with 790 additions and 52 deletions

View 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)
}

View file

@ -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
)

View 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"`
}

View 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);"`
}

View 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
}

View file

@ -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)

View 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))
}

View file

@ -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
)

View file

@ -17,6 +17,7 @@ func Init() {
migrations.AddTableCronjob,
migrations.AddTableApp,
migrations.AddTableImageRepo,
migrations.AddTableDatabaseMysql,
})
if err := m.Migrate(); err != nil {
global.LOG.Error(err)

View file

@ -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{})
},
}

View file

@ -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

View file

@ -14,6 +14,7 @@ type RouterGroup struct {
CronjobRouter
SettingRouter
AppRouter
DatabaseRouter
}
var RouterGroupApp = new(RouterGroup)

View 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)
}
}

View 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;
}
}

View 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);
};

View file

@ -150,6 +150,16 @@ export default {
header: {
logout: '退出登录',
},
database: {
permission: '权限',
permissionLocal: '本地服务器',
permissionForIP: '指定 IP',
permissionAll: '所有人不安全',
rootPassword: 'root 密码',
backupList: '备份列表',
loadBackup: '导入备份',
setting: '数据库设置',
},
container: {
operatorHelper: '将对选中容器进行 {0} 操作是否继续',
start: '启动',

View file

@ -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',
},
},
],
};

View file

@ -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>

View 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>

View 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>

View 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>