From 33484a94364d5f5c511db172c79318945d58ad98 Mon Sep 17 00:00:00 2001 From: ssongliu <73214554+ssongliu@users.noreply.github.com> Date: Mon, 25 Dec 2023 17:08:09 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=90=8C=E6=AD=A5=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E7=A7=BB=E9=99=A4=E5=88=9B=E5=BB=BA=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E9=80=BB=E8=BE=91=20(#3442)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/v1/database_mysql.go | 31 ++++ backend/app/dto/database.go | 8 + backend/app/service/database_mysql.go | 37 +++++ backend/router/ro_database.go | 1 + backend/utils/mysql/client.go | 1 + backend/utils/mysql/client/info.go | 24 --- backend/utils/mysql/client/local.go | 13 -- backend/utils/mysql/client/remote.go | 13 -- cmd/server/docs/docs.go | 72 ++++++++- cmd/server/docs/swagger.json | 72 ++++++++- cmd/server/docs/swagger.yaml | 49 +++++- frontend/src/api/interface/database.ts | 7 + frontend/src/api/modules/database.ts | 7 + frontend/src/lang/modules/en.ts | 1 + frontend/src/lang/modules/tw.ts | 1 + frontend/src/lang/modules/zh.ts | 1 + .../src/views/database/mysql/bind/index.vue | 139 ++++++++++++++++++ frontend/src/views/database/mysql/index.vue | 40 ++++- 18 files changed, 458 insertions(+), 59 deletions(-) create mode 100644 frontend/src/views/database/mysql/bind/index.vue diff --git a/backend/app/api/v1/database_mysql.go b/backend/app/api/v1/database_mysql.go index a3aec9b16..b6c5f9282 100644 --- a/backend/app/api/v1/database_mysql.go +++ b/backend/app/api/v1/database_mysql.go @@ -41,6 +41,37 @@ func (b *BaseApi) CreateMysql(c *gin.Context) { helper.SuccessWithData(c, nil) } +// @Tags Database Mysql +// @Summary Bind user of mysql database +// @Description 绑定 mysql 数据库用户 +// @Accept json +// @Param request body dto.BindUser true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Router /databases/bind [post] +// @x-panel-log {"bodyKeys":["database", "username"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"绑定 mysql 数据库名 [database] [username]","formatEN":"bind mysql database [database] [username]"} +func (b *BaseApi) BindUser(c *gin.Context) { + var req dto.BindUser + if err := helper.CheckBindAndValidate(&req, c); err != nil { + return + } + + if len(req.Password) != 0 { + password, err := base64.StdEncoding.DecodeString(req.Password) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + req.Password = string(password) + } + + if err := mysqlService.BindUser(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, nil) +} + // @Tags Database Mysql // @Summary Update mysql database description // @Description 更新 mysql 数据库库描述信息 diff --git a/backend/app/dto/database.go b/backend/app/dto/database.go index cdf1966df..65aaa0ab4 100644 --- a/backend/app/dto/database.go +++ b/backend/app/dto/database.go @@ -43,6 +43,14 @@ type MysqlDBCreate struct { Description string `json:"description"` } +type BindUser struct { + Database string `json:"database" validate:"required"` + DB string `json:"db" validate:"required"` + Username string `json:"username" validate:"required"` + Password string `json:"password" validate:"required"` + Permission string `json:"permission" validate:"required"` +} + type MysqlLoadDB struct { From string `json:"from" validate:"required,oneof=local remote"` Type string `json:"type" validate:"required,oneof=mysql mariadb"` diff --git a/backend/app/service/database_mysql.go b/backend/app/service/database_mysql.go index cf61f1241..fe293bc9e 100644 --- a/backend/app/service/database_mysql.go +++ b/backend/app/service/database_mysql.go @@ -35,6 +35,7 @@ type IMysqlService interface { SearchWithPage(search dto.MysqlDBSearch) (int64, interface{}, error) ListDBOption() ([]dto.MysqlOption, error) Create(ctx context.Context, req dto.MysqlDBCreate) (*model.DatabaseMysql, error) + BindUser(req dto.BindUser) error LoadFromRemote(req dto.MysqlLoadDB) error ChangeAccess(info dto.ChangeDBInfo) error ChangePassword(info dto.ChangeDBInfo) error @@ -144,6 +145,42 @@ func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*mode return &createItem, nil } +func (u *MysqlService) BindUser(req dto.BindUser) error { + dbItem, err := mysqlRepo.Get(mysqlRepo.WithByMysqlName(req.Database), commonRepo.WithByName(req.DB)) + if err != nil { + return err + } + cli, version, err := LoadMysqlClientByFrom(req.Database) + if err != nil { + return err + } + defer cli.Close() + + if err := cli.CreateUser(client.CreateInfo{ + Name: dbItem.Name, + Format: dbItem.Format, + Username: req.Username, + Password: req.Password, + Permission: req.Permission, + Version: version, + Timeout: 300, + }, false); err != nil { + return err + } + pass, err := encrypt.StringEncrypt(req.Password) + if err != nil { + return fmt.Errorf("decrypt database db password failed, err: %v", err) + } + if err := mysqlRepo.Update(dbItem.ID, map[string]interface{}{ + "username": req.Username, + "password": pass, + "permission": req.Permission, + }); err != nil { + return err + } + return nil +} + func (u *MysqlService) LoadFromRemote(req dto.MysqlLoadDB) error { client, version, err := LoadMysqlClientByFrom(req.Database) if err != nil { diff --git a/backend/router/ro_database.go b/backend/router/ro_database.go index d62e4f283..88fa214f4 100644 --- a/backend/router/ro_database.go +++ b/backend/router/ro_database.go @@ -17,6 +17,7 @@ func (s *DatabaseRouter) InitRouter(Router *gin.RouterGroup) { baseApi := v1.ApiGroupApp.BaseApi { cmdRouter.POST("", baseApi.CreateMysql) + cmdRouter.POST("/bind", baseApi.BindUser) cmdRouter.POST("load", baseApi.LoadDBFromRemote) cmdRouter.POST("/change/access", baseApi.ChangeMysqlAccess) cmdRouter.POST("/change/password", baseApi.ChangeMysqlPassword) diff --git a/backend/utils/mysql/client.go b/backend/utils/mysql/client.go index 7af24ff06..14225adf9 100644 --- a/backend/utils/mysql/client.go +++ b/backend/utils/mysql/client.go @@ -14,6 +14,7 @@ import ( type MysqlClient interface { Create(info client.CreateInfo) error + CreateUser(info client.CreateInfo, withDeleteDB bool) error Delete(info client.DeleteInfo) error ChangePassword(info client.PasswordChangeInfo) error diff --git a/backend/utils/mysql/client/info.go b/backend/utils/mysql/client/info.go index 58455adcc..0c05951b6 100644 --- a/backend/utils/mysql/client/info.go +++ b/backend/utils/mysql/client/info.go @@ -4,9 +4,7 @@ import ( "crypto/tls" "crypto/x509" "errors" - "strings" - "github.com/1Panel-dev/1Panel/backend/utils/common" "github.com/go-sql-driver/mysql" ) @@ -103,28 +101,6 @@ var formatMap = map[string]string{ "big5": "big5_chinese_ci", } -func loadNameByDB(name, version string) string { - nameItem := common.ConvertToPinyin(name) - if strings.HasPrefix(version, "5.6") { - if len(nameItem) <= 16 { - return nameItem - } - return strings.TrimSuffix(nameItem[:10], "_") + "_" + common.RandStr(5) - } - if len(nameItem) <= 32 { - return nameItem - } - return strings.TrimSuffix(nameItem[:25], "_") + "_" + common.RandStr(5) -} - -func randomPassword(user string) string { - passwdItem := user - if len(user) > 6 { - passwdItem = user[:6] - } - return passwdItem + "@" + common.RandStrAndNum(8) -} - func VerifyPeerCertFunc(pool *x509.CertPool) func([][]byte, [][]*x509.Certificate) error { return func(rawCerts [][]byte, _ [][]*x509.Certificate) error { if len(rawCerts) == 0 { diff --git a/backend/utils/mysql/client/local.go b/backend/utils/mysql/client/local.go index 8c0b7a52c..96711b382 100644 --- a/backend/utils/mysql/client/local.go +++ b/backend/utils/mysql/client/local.go @@ -307,19 +307,6 @@ func (r *Local) SyncDB(version string) ([]SyncDBInfo, error) { } } if len(dataItem.Username) == 0 { - dataItem.Username = loadNameByDB(parts[0], version) - dataItem.Password = randomPassword(dataItem.Username) - if err := r.CreateUser(CreateInfo{ - Name: parts[0], - Format: parts[1], - Version: version, - Username: dataItem.Username, - Password: dataItem.Password, - Permission: "%", - Timeout: 300, - }, false); err != nil { - global.LOG.Errorf("sync from remote server failed, err: create user failed %v", err) - } dataItem.Permission = "%" } else { if isLocal { diff --git a/backend/utils/mysql/client/remote.go b/backend/utils/mysql/client/remote.go index 18a0b01f7..d385b2b47 100644 --- a/backend/utils/mysql/client/remote.go +++ b/backend/utils/mysql/client/remote.go @@ -333,19 +333,6 @@ func (r *Remote) SyncDB(version string) ([]SyncDBInfo, error) { i++ } if len(dataItem.Username) == 0 { - dataItem.Username = loadNameByDB(dbName, version) - dataItem.Password = randomPassword(dataItem.Username) - if err := r.CreateUser(CreateInfo{ - Name: dbName, - Format: charsetName, - Version: version, - Username: dataItem.Username, - Password: dataItem.Password, - Permission: "%", - Timeout: 300, - }, false); err != nil { - return datas, fmt.Errorf("sync db from remote server failed, err: create user failed %v", err) - } dataItem.Permission = "%" } else { if isLocal { diff --git a/cmd/server/docs/docs.go b/cmd/server/docs/docs.go index 67f05d522..d288e5828 100644 --- a/cmd/server/docs/docs.go +++ b/cmd/server/docs/docs.go @@ -3952,6 +3952,49 @@ const docTemplate = `{ } } }, + "/databases/bind": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "绑定 mysql 数据库用户", + "consumes": [ + "application/json" + ], + "tags": [ + "Database Mysql" + ], + "summary": "Bind user of mysql database", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.BindUser" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFunctions": [], + "bodyKeys": [ + "database", + "username" + ], + "formatEN": "bind mysql database [database] [username]", + "formatZH": "绑定 mysql 数据库名 [database] [username]", + "paramKeys": [] + } + } + }, "/databases/change/access": { "post": { "security": [ @@ -10013,7 +10056,7 @@ const docTemplate = `{ "bodyKeys": [ "version" ], - "formatEN": "upgrade service =\u003e [version]", + "formatEN": "upgrade system =\u003e [version]", "formatZH": "更新系统 =\u003e [version]", "paramKeys": [] } @@ -13601,6 +13644,33 @@ const docTemplate = `{ } } }, + "dto.BindUser": { + "type": "object", + "required": [ + "database", + "db", + "password", + "permission", + "username" + ], + "properties": { + "database": { + "type": "string" + }, + "db": { + "type": "string" + }, + "password": { + "type": "string" + }, + "permission": { + "type": "string" + }, + "username": { + "type": "string" + } + } + }, "dto.CaptchaResponse": { "type": "object", "properties": { diff --git a/cmd/server/docs/swagger.json b/cmd/server/docs/swagger.json index 0e5aebd82..5ef899b02 100644 --- a/cmd/server/docs/swagger.json +++ b/cmd/server/docs/swagger.json @@ -3945,6 +3945,49 @@ } } }, + "/databases/bind": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "绑定 mysql 数据库用户", + "consumes": [ + "application/json" + ], + "tags": [ + "Database Mysql" + ], + "summary": "Bind user of mysql database", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.BindUser" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFunctions": [], + "bodyKeys": [ + "database", + "username" + ], + "formatEN": "bind mysql database [database] [username]", + "formatZH": "绑定 mysql 数据库名 [database] [username]", + "paramKeys": [] + } + } + }, "/databases/change/access": { "post": { "security": [ @@ -10006,7 +10049,7 @@ "bodyKeys": [ "version" ], - "formatEN": "upgrade service =\u003e [version]", + "formatEN": "upgrade system =\u003e [version]", "formatZH": "更新系统 =\u003e [version]", "paramKeys": [] } @@ -13594,6 +13637,33 @@ } } }, + "dto.BindUser": { + "type": "object", + "required": [ + "database", + "db", + "password", + "permission", + "username" + ], + "properties": { + "database": { + "type": "string" + }, + "db": { + "type": "string" + }, + "password": { + "type": "string" + }, + "permission": { + "type": "string" + }, + "username": { + "type": "string" + } + } + }, "dto.CaptchaResponse": { "type": "object", "properties": { diff --git a/cmd/server/docs/swagger.yaml b/cmd/server/docs/swagger.yaml index 26c908338..f0d01437b 100644 --- a/cmd/server/docs/swagger.yaml +++ b/cmd/server/docs/swagger.yaml @@ -137,6 +137,25 @@ definitions: - bindAddress - ipv6 type: object + dto.BindUser: + properties: + database: + type: string + db: + type: string + password: + type: string + permission: + type: string + username: + type: string + required: + - database + - db + - password + - permission + - username + type: object dto.CaptchaResponse: properties: captchaID: @@ -7268,6 +7287,34 @@ paths: summary: Load mysql base info tags: - Database Mysql + /databases/bind: + post: + consumes: + - application/json + description: 绑定 mysql 数据库用户 + parameters: + - description: request + in: body + name: request + required: true + schema: + $ref: '#/definitions/dto.BindUser' + responses: + "200": + description: OK + security: + - ApiKeyAuth: [] + summary: Bind user of mysql database + tags: + - Database Mysql + x-panel-log: + BeforeFunctions: [] + bodyKeys: + - database + - username + formatEN: bind mysql database [database] [username] + formatZH: 绑定 mysql 数据库名 [database] [username] + paramKeys: [] /databases/change/access: post: consumes: @@ -11106,7 +11153,7 @@ paths: BeforeFunctions: [] bodyKeys: - version - formatEN: upgrade service => [version] + formatEN: upgrade system => [version] formatZH: 更新系统 => [version] paramKeys: [] /toolbox/clean: diff --git a/frontend/src/api/interface/database.ts b/frontend/src/api/interface/database.ts index 6e3a77e19..c0899ccce 100644 --- a/frontend/src/api/interface/database.ts +++ b/frontend/src/api/interface/database.ts @@ -48,6 +48,13 @@ export namespace Database { permission: string; description: string; } + export interface BindUser { + database: string; + db: string; + username: string; + password: string; + permission: string; + } export interface MysqlLoadDB { from: string; type: string; diff --git a/frontend/src/api/modules/database.ts b/frontend/src/api/modules/database.ts index c92590c16..1186a3042 100644 --- a/frontend/src/api/modules/database.ts +++ b/frontend/src/api/modules/database.ts @@ -19,6 +19,13 @@ export const addMysqlDB = (params: Database.MysqlDBCreate) => { } return http.post(`/databases`, request); }; +export const bindUser = (params: Database.BindUser) => { + let request = deepCopy(params) as Database.BindUser; + if (request.password) { + request.password = Base64.encode(request.password); + } + return http.post(`/databases/bind`, request); +}; export const loadDBFromRemote = (params: Database.MysqlLoadDB) => { return http.post(`/databases/load`, params); }; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 1a35f171e..b25236353 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -380,6 +380,7 @@ const message = { 'This port is the exposed port of the container. You need to save the modification separately and restart the container!', loadFromRemote: 'Load from server', + userBind: 'Bind User', loadFromRemoteHelper: 'This action will synchronize the database info on the server to 1Panel, do you want to continue?', passwordHelper: 'Unable to retrieve, please modify', diff --git a/frontend/src/lang/modules/tw.ts b/frontend/src/lang/modules/tw.ts index 8004bc179..e147f9cb3 100644 --- a/frontend/src/lang/modules/tw.ts +++ b/frontend/src/lang/modules/tw.ts @@ -373,6 +373,7 @@ const message = { confNotFound: '未能找到該應用配置文件,請在應用商店升級該應用至最新版本後重試!', loadFromRemote: '從服務器獲取', + userBind: '綁定使用者', loadFromRemoteHelper: '此操作將同步服務器上數據庫信息到 1Panel,是否繼續?', passwordHelper: '無法獲取密碼,請修改', local: '本地', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 83b710808..2a86c1d04 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -373,6 +373,7 @@ const message = { confNotFound: '未能找到该应用配置文件,请在应用商店升级该应用至最新版本后重试!', loadFromRemote: '从服务器获取', + userBind: '绑定用户', loadFromRemoteHelper: '此操作将同步服务器上数据库信息到 1Panel,是否继续?', passwordHelper: '无法获取密码,请修改', local: '本地', diff --git a/frontend/src/views/database/mysql/bind/index.vue b/frontend/src/views/database/mysql/bind/index.vue new file mode 100644 index 000000000..d3ad0e5fb --- /dev/null +++ b/frontend/src/views/database/mysql/bind/index.vue @@ -0,0 +1,139 @@ +<template> + <div> + <el-drawer v-model="bindVisible" :destroy-on-close="true" :close-on-click-modal="false" width="30%"> + <template #header> + <DrawerHeader :header="$t('database.userBind')" :resource="form.mysqlName" :back="handleClose" /> + </template> + <el-form v-loading="loading" ref="changeFormRef" :model="form" :rules="rules" label-position="top"> + <el-row type="flex" justify="center"> + <el-col :span="22"> + <el-form-item :label="$t('commons.login.username')" prop="username"> + <el-input v-model="form.username"></el-input> + </el-form-item> + <el-form-item :label="$t('commons.login.password')" prop="password"> + <el-input type="password" clearable show-password v-model="form.password"></el-input> + </el-form-item> + <el-form-item :label="$t('database.permission')" prop="permission"> + <el-select v-model="form.permission"> + <el-option value="%" :label="$t('database.permissionAll')" /> + <el-option + v-if="form.from !== 'local'" + value="localhost" + :label="$t('terminal.localhost')" + /> + <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 + clearable + :autosize="{ minRows: 2, maxRows: 5 }" + type="textarea" + v-model="form.permissionIPs" + /> + <span class="input-help">{{ $t('database.remoteHelper') }}</span> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <span class="dialog-footer"> + <el-button :disabled="loading" @click="bindVisible = false"> + {{ $t('commons.button.cancel') }} + </el-button> + <el-button :disabled="loading" type="primary" @click="onSubmit(changeFormRef)"> + {{ $t('commons.button.confirm') }} + </el-button> + </span> + </template> + </el-drawer> + + <ConfirmDialog ref="confirmDialogRef" @confirm="onSubmit"></ConfirmDialog> + </div> +</template> +<script lang="ts" setup> +import { reactive, ref } from 'vue'; +import i18n from '@/lang'; +import { ElForm } from 'element-plus'; +import { bindUser } from '@/api/modules/database'; +import DrawerHeader from '@/components/drawer-header/index.vue'; +import { Rules } from '@/global/form-rules'; +import { MsgSuccess } from '@/utils/message'; +import { checkIp } from '@/utils/util'; + +const loading = ref(); +const bindVisible = ref(false); +type FormInstance = InstanceType<typeof ElForm>; +const changeFormRef = ref<FormInstance>(); +const form = reactive({ + database: '', + mysqlName: '', + username: '', + password: '', + permission: '', + permissionIPs: '', +}); +const confirmDialogRef = ref(); + +const rules = reactive({ + username: [Rules.requiredInput, Rules.name], + password: [Rules.paramComplexity], + permission: [Rules.requiredSelect], + permissionIPs: [{ validator: checkIPs, trigger: 'blur', required: true }], +}); + +function checkIPs(rule: any, value: any, callback: any) { + let ips = form.permissionIPs.split(','); + for (const item of ips) { + if (checkIp(item)) { + return callback(new Error(i18n.global.t('commons.rule.ip'))); + } + } + callback(); +} + +interface DialogProps { + database: string; + mysqlName: string; +} +const acceptParams = (params: DialogProps): void => { + form.id = params.id; + form.database = params.database; + form.mysqlName = params.mysqlName; + bindVisible.value = true; +}; +const emit = defineEmits<{ (e: 'search'): void }>(); + +const handleClose = () => { + bindVisible.value = false; +}; + +const onSubmit = async (formEl: FormInstance | undefined) => { + if (!formEl) return; + formEl.validate(async (valid) => { + if (!valid) return; + let param = { + database: form.database, + db: form.mysqlName, + username: form.username, + password: form.password, + permission: form.permission === 'ip' ? form.permissionIPs : form.permission, + }; + loading.value = true; + await bindUser(param) + .then(() => { + loading.value = false; + emit('search'); + bindVisible.value = false; + MsgSuccess(i18n.global.t('commons.msg.operationSuccess')); + }) + .catch(() => { + loading.value = false; + }); + }); +}; + +defineExpose({ + acceptParams, +}); +</script> diff --git a/frontend/src/views/database/mysql/index.vue b/frontend/src/views/database/mysql/index.vue index 88bc48b8c..61532f0a5 100644 --- a/frontend/src/views/database/mysql/index.vue +++ b/frontend/src/views/database/mysql/index.vue @@ -124,10 +124,24 @@ <template #main v-if="currentDB"> <ComplexTable :pagination-config="paginationConfig" @sort-change="search" @search="search" :data="data"> <el-table-column :label="$t('commons.table.name')" prop="name" sortable /> - <el-table-column :label="$t('commons.login.username')" prop="username" /> + <el-table-column :label="$t('commons.login.username')" prop="username"> + <template #default="{ row }"> + <div class="flex items-center" v-if="row.username"> + <span> + {{ row.username }} + </span> + </div> + <div v-else> + <el-button style="margin-left: -3px" type="primary" link @click="onBind(row)"> + {{ $t('database.userBind') }} + </el-button> + </div> + </template> + </el-table-column> <el-table-column :label="$t('commons.login.password')" prop="password"> <template #default="{ row }"> - <div class="flex items-center" v-if="row.password"> + <span v-if="row.username === ''">-</span> + <div class="flex items-center" v-if="row.password && row.username"> <div class="star-center" v-if="!row.showPassword"> <span>**********</span> </div> @@ -154,10 +168,10 @@ <CopyButton :content="row.password" type="icon" /> </div> </div> - <div v-else> - <el-link @click="onChangePassword(row)"> - <span style="font-size: 12px">{{ $t('database.passwordHelper') }}</span> - </el-link> + <div v-if="row.password === '' && row.username"> + <el-button style="margin-left: -3px" link type="primary" @click="onChangePassword(row)"> + {{ $t('database.passwordHelper') }} + </el-button> </div> </template> </el-table-column> @@ -221,6 +235,7 @@ </template> </el-dialog> + <BindDialog ref="bindRef" @search="search" /> <PasswordDialog ref="passwordRef" @search="search" /> <RootPasswordDialog ref="connRef" /> <UploadDialog ref="uploadRef" /> @@ -235,6 +250,7 @@ </template> <script lang="ts" setup> +import BindDialog from '@/views/database/mysql/bind/index.vue'; import OperateDialog from '@/views/database/mysql/create/index.vue'; import DeleteDialog from '@/views/database/mysql/delete/index.vue'; import PasswordDialog from '@/views/database/mysql/password/index.vue'; @@ -274,6 +290,7 @@ const dbOptionsRemote = ref<Array<Database.DatabaseOption>>([]); const currentDB = ref<Database.DatabaseOption>(); const currentDBName = ref(); +const bindRef = ref(); const checkRef = ref(); const deleteRef = ref(); @@ -508,6 +525,14 @@ const onDelete = async (row: Database.MysqlDBInfo) => { } }; +const onBind = async (row: Database.MysqlDBInfo) => { + let param = { + database: currentDBName.value, + mysqlName: row.name, + }; + bindRef.value.acceptParams(param); +}; + const onChangePassword = async (row: Database.MysqlDBInfo) => { let param = { id: row.id, @@ -525,6 +550,9 @@ const onChangePassword = async (row: Database.MysqlDBInfo) => { const buttons = [ { label: i18n.global.t('database.changePassword'), + disabled: (row: Database.MysqlDBInfo) => { + return !row.username; + }, click: (row: Database.MysqlDBInfo) => { onChangePassword(row); },